From 8f5ec48522b9f166d18535bf7d320b2db2a09324 Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Tue, 26 Aug 2025 16:00:48 +0800 Subject: [PATCH 1/5] doc: update shengsuanyun comment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9341668..6e677369 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ docker compose up -d | [Anthropic](https://www.anthropic.com/) | ✅ | | | [xAI](https://x.ai/) | ✅ | | | [智谱AI](https://open.bigmodel.cn/) | ✅ | | +| [胜算云](https://www.shengsuanyun.com/?from=CH_KYIPP758) | ✅ | 全球大模型都可调用(友情推荐) | | [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | ✅ | 大模型和 GPU 资源平台 | | [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | ✅ | 大模型和 GPU 资源平台 | -| [胜算云](https://www.shengsuanyun.com/?from=CH_KYIPP758) | ✅ | 大模型和 GPU 资源平台 | | [302.AI](https://share.302.ai/SuTG99) | ✅ | 大模型聚合平台 | | [Google Gemini](https://aistudio.google.com/prompts/new_chat) | ✅ | | | [Dify](https://dify.ai) | ✅ | LLMOps 平台 | From 8858f432b506478d821c3ad30e956aeb9e824e77 Mon Sep 17 00:00:00 2001 From: Bruce Date: Wed, 27 Aug 2025 18:09:30 +0800 Subject: [PATCH 2/5] fix dingtalk message sender id & update dingtalk streaming card without content (#1630) --- pkg/platform/sources/dingtalk.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/platform/sources/dingtalk.py b/pkg/platform/sources/dingtalk.py index 71c7b0d0..77b467d5 100644 --- a/pkg/platform/sources/dingtalk.py +++ b/pkg/platform/sources/dingtalk.py @@ -23,6 +23,9 @@ class DingTalkMessageConverter(adapter.MessageConverter): at = True if type(msg) is platform_message.Plain: content += msg.text + if type(msg) is platform_message.Forward: + for node in msg.node_list: + content += (await DingTalkMessageConverter.yiri2target(node.message_chain))[0] return content, at @staticmethod @@ -61,7 +64,7 @@ class DingTalkEventConverter(adapter.EventConverter): if event.conversation == 'FriendMessage': return platform_events.FriendMessage( sender=platform_entities.Friend( - id=event.incoming_message.sender_id, + id=event.incoming_message.sender_staff_id, nickname=event.incoming_message.sender_nick, remark='', ), @@ -71,7 +74,7 @@ class DingTalkEventConverter(adapter.EventConverter): ) elif event.conversation == 'GroupMessage': sender = platform_entities.GroupMember( - id=event.incoming_message.sender_id, + id=event.incoming_message.sender_staff_id, member_name=event.incoming_message.sender_nick, permission='MEMBER', group=platform_entities.Group( @@ -166,8 +169,11 @@ class DingTalkAdapter(adapter.MessagePlatformAdapter): content, at = await DingTalkMessageConverter.yiri2target(message) card_instance, card_instance_id = self.card_instance_id_dict[message_id] + if not content and bot_message.content: + content = bot_message.content # 兼容直接传入content的情况 # print(card_instance_id) - await self.bot.send_card_message(card_instance, card_instance_id, content, is_final) + if content: + await self.bot.send_card_message(card_instance, card_instance_id, content, is_final) if is_final and bot_message.tool_calls is None: # self.seq = 1 # 消息回复结束之后重置seq self.card_instance_id_dict.pop(message_id) # 消息回复结束之后删除卡片实例id From d9fa1cbb0668f177769135dc1d5e26fa3bc0c301 Mon Sep 17 00:00:00 2001 From: Bruce Date: Thu, 28 Aug 2025 12:59:50 +0800 Subject: [PATCH 3/5] perf: add cmd enable config & fix announce request timeout & fix send card with disconnect ai platform (#1633) * add cmd config && fix bugs * perf: use `get` * update bansess fix block match rule * perf: comment for access-control session str --------- Co-authored-by: Junyan Qin --- .../migrations/dbm001_migrate_v3_config.py | 1 + pkg/pipeline/bansess/bansess.py | 4 +++ pkg/pipeline/process/handlers/chat.py | 9 ++++--- pkg/pipeline/process/process.py | 12 +++++---- pkg/utils/announce.py | 26 ++++++++++++------- pkg/utils/version.py | 22 +++++++++------- templates/config.yaml | 1 + templates/metadata/pipeline/trigger.yaml | 6 +++++ 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/pkg/persistence/migrations/dbm001_migrate_v3_config.py b/pkg/persistence/migrations/dbm001_migrate_v3_config.py index 58f05e04..6d53718d 100644 --- a/pkg/persistence/migrations/dbm001_migrate_v3_config.py +++ b/pkg/persistence/migrations/dbm001_migrate_v3_config.py @@ -212,6 +212,7 @@ class DBMigrateV3Config(migration.DBMigration): self.ap.instance_config.data['api']['port'] = self.ap.system_cfg.data['http-api']['port'] self.ap.instance_config.data['command'] = { 'prefix': self.ap.command_cfg.data['command-prefix'], + 'enable': self.ap.command_cfg.data['command-enable'], 'privilege': self.ap.command_cfg.data['privilege'], } self.ap.instance_config.data['concurrency']['pipeline'] = self.ap.system_cfg.data['pipeline-concurrency'] diff --git a/pkg/pipeline/bansess/bansess.py b/pkg/pipeline/bansess/bansess.py index c88a1aa2..ed6ddf74 100644 --- a/pkg/pipeline/bansess/bansess.py +++ b/pkg/pipeline/bansess/bansess.py @@ -30,6 +30,10 @@ class BanSessionCheckStage(stage.PipelineStage): if sess == f'{query.launcher_type.value}_{query.launcher_id}': found = True break + # 使用 *_id 来表示加白/拉黑某用户的私聊和群聊场景 + if sess.startswith('*_') and (sess[2:] == query.launcher_id or sess[2:] == query.sender_id): + found = True + break ctn = False diff --git a/pkg/pipeline/process/handlers/chat.py b/pkg/pipeline/process/handlers/chat.py index e913bbc2..fee54427 100644 --- a/pkg/pipeline/process/handlers/chat.py +++ b/pkg/pipeline/process/handlers/chat.py @@ -43,7 +43,7 @@ class ChatMessageHandler(handler.MessageHandler): query=query, ) ) - + is_create_card = False # 判断下是否需要创建流式卡片 if event_ctx.is_prevented_default(): if event_ctx.event.reply is not None: mc = platform_message.MessageChain(event_ctx.event.reply) @@ -72,14 +72,17 @@ class ChatMessageHandler(handler.MessageHandler): raise ValueError(f'未找到请求运行器: {query.pipeline_config["ai"]["runner"]["runner"]}') if is_stream: resp_message_id = uuid.uuid4() - await query.adapter.create_message_card(str(resp_message_id), query.message_event) + async for result in runner.run(query): result.resp_message_id = str(resp_message_id) if query.resp_messages: query.resp_messages.pop() if query.resp_message_chain: query.resp_message_chain.pop() - + # 此时连接外部 AI 服务正常,创建卡片 + if not is_create_card: # 只有不是第一次才创建卡片 + await query.adapter.create_message_card(str(resp_message_id), query.message_event) + is_create_card = True query.resp_messages.append(result) self.ap.logger.info(f'对话({query.query_id})流式响应: {self.cut_str(result.readable_str())}') diff --git a/pkg/pipeline/process/process.py b/pkg/pipeline/process/process.py index db66135c..a08b8c08 100644 --- a/pkg/pipeline/process/process.py +++ b/pkg/pipeline/process/process.py @@ -42,12 +42,14 @@ class Processor(stage.PipelineStage): async def generator(): cmd_prefix = self.ap.instance_config.data['command']['prefix'] + cmd_enable = self.ap.instance_config.data['command'].get('enable', True) - if any(message_text.startswith(prefix) for prefix in cmd_prefix): - async for result in self.cmd_handler.handle(query): - yield result + if cmd_enable and any(message_text.startswith(prefix) for prefix in cmd_prefix): + handler_to_use = self.cmd_handler else: - async for result in self.chat_handler.handle(query): - yield result + handler_to_use = self.chat_handler + + async for result in handler_to_use.handle(query): + yield result return generator() diff --git a/pkg/utils/announce.py b/pkg/utils/announce.py index a6b8539a..69d19368 100644 --- a/pkg/utils/announce.py +++ b/pkg/utils/announce.py @@ -45,17 +45,23 @@ class AnnouncementManager: async def fetch_all(self) -> list[Announcement]: """获取所有公告""" - resp = requests.get( - url='https://api.github.com/repos/langbot-app/LangBot/contents/res/announcement.json', - proxies=self.ap.proxy_mgr.get_forward_proxies(), - timeout=5, - ) - obj_json = resp.json() - b64_content = obj_json['content'] - # 解码 - content = base64.b64decode(b64_content).decode('utf-8') + try: + resp = requests.get( + url='https://api.github.com/repos/langbot-app/LangBot/contents/res/announcement.json', + proxies=self.ap.proxy_mgr.get_forward_proxies(), + timeout=5, + ) + resp.raise_for_status() # 检查请求是否成功 + obj_json = resp.json() + b64_content = obj_json['content'] + # 解码 + content = base64.b64decode(b64_content).decode('utf-8') - return [Announcement(**item) for item in json.loads(content)] + return [Announcement(**item) for item in json.loads(content)] + except (requests.RequestException, json.JSONDecodeError, KeyError) as e: + self.ap.logger.warning(f"获取公告失败: {e}") + pass + return [] # 请求失败时返回空列表 async def fetch_saved(self) -> list[Announcement]: if not os.path.exists('data/labels/announcement_saved.json'): diff --git a/pkg/utils/version.py b/pkg/utils/version.py index b26b1e33..3a2748fc 100644 --- a/pkg/utils/version.py +++ b/pkg/utils/version.py @@ -28,15 +28,19 @@ class VersionManager: async def get_release_list(self) -> list: """获取发行列表""" - rls_list_resp = requests.get( - url='https://api.github.com/repos/langbot-app/LangBot/releases', - proxies=self.ap.proxy_mgr.get_forward_proxies(), - timeout=5, - ) - - rls_list = rls_list_resp.json() - - return rls_list + try: + rls_list_resp = requests.get( + url='https://api.github.com/repos/langbot-app/LangBot/releases', + proxies=self.ap.proxy_mgr.get_forward_proxies(), + timeout=5, + ) + rls_list_resp.raise_for_status() # 检查请求是否成功 + rls_list = rls_list_resp.json() + return rls_list + except Exception as e: + self.ap.logger.warning(f"获取发行列表失败: {e}") + pass + return [] async def update_all(self): """检查更新并下载源码""" diff --git a/templates/config.yaml b/templates/config.yaml index d347af77..3faa2fd7 100644 --- a/templates/config.yaml +++ b/templates/config.yaml @@ -2,6 +2,7 @@ admins: [] api: port: 5300 command: + enable: true prefix: - '!' - ! diff --git a/templates/metadata/pipeline/trigger.yaml b/templates/metadata/pipeline/trigger.yaml index 949b2698..cecfc59d 100644 --- a/templates/metadata/pipeline/trigger.yaml +++ b/templates/metadata/pipeline/trigger.yaml @@ -79,6 +79,9 @@ stages: label: en_US: Blacklist zh_Hans: 黑名单 + description: + en_US: Sessions in the blacklist will be ignored, the format is `{launcher_type}_{launcher_id}`(remove quotes), for example `person_123` matches private chat, `group_456` matches group chat, `person_*` matches all private chats, `group_*` matches all group chats, `*_123` matches private and group chats with user ID 123 + zh_Hans: 黑名单中的会话将被忽略;会话格式:`{launcher_type}_{launcher_id}`(删除引号),例如 `person_123` 匹配私聊会话,`group_456` 匹配群聊会话;`person_*` 匹配所有私聊会话,`group_*` 匹配所有群聊会话;`*_123` 匹配用户 ID 为 123 的私聊和群聊消息 type: array[string] required: true default: [] @@ -86,6 +89,9 @@ stages: label: en_US: Whitelist zh_Hans: 白名单 + description: + en_US: Only respond to sessions in the whitelist, the format is `{launcher_type}_{launcher_id}`(remove quotes), for example `person_123` matches private chat, `group_456` matches group chat, `person_*` matches all private chats, `group_*` matches all group chats, `*_123` matches private and group chats with user ID 123 + zh_Hans: 仅响应白名单中的会话;会话格式:`{launcher_type}_{launcher_id}`(删除引号),例如 `person_123` 匹配私聊会话,`group_456` 匹配群聊会话;`person_*` 匹配所有私聊会话,`group_*` 匹配所有群聊会话;`*_123` 匹配用户 ID 为 123 的私聊和群聊消息 type: array[string] required: true default: [] From 46b4482a7d2f253ccb823665f349c2c1b9bc88b3 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:04:36 +0800 Subject: [PATCH 4/5] feat: add GitHub star count component to sidebar (#1636) * feat: add GitHub star count component to sidebar - Add GitHub star component to sidebar bottom section - Fetch star count from space.langbot.app API - Display star count with proper internationalization - Open GitHub repository in new tab when clicked - Follow existing sidebar styling patterns Co-Authored-By: Rock * perf: ui * chore: remove githubStars text --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Rock --- .../components/home-sidebar/HomeSidebar.tsx | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx index 25b3b58f..4009c77a 100644 --- a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx +++ b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx @@ -9,7 +9,7 @@ import { import { useRouter, usePathname } from 'next/navigation'; import { sidebarConfigList } from '@/app/home/components/home-sidebar/sidbarConfigList'; import langbotIcon from '@/app/assets/langbot-logo.webp'; -import { systemInfo } from '@/app/infra/http/HttpClient'; +import { systemInfo, spaceClient } from '@/app/infra/http/HttpClient'; import { useTranslation } from 'react-i18next'; import { Moon, Sun, Monitor } from 'lucide-react'; import { useTheme } from 'next-themes'; @@ -22,6 +22,7 @@ import { import { Button } from '@/components/ui/button'; import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'; import { LanguageSelector } from '@/components/ui/language-selector'; +import { Badge } from '@/components/ui/badge'; import PasswordChangeDialog from '@/app/home/components/password-change-dialog/PasswordChangeDialog'; // TODO 侧边导航栏要加动画 @@ -44,6 +45,7 @@ export default function HomeSidebar({ const [popoverOpen, setPopoverOpen] = useState(false); const [passwordChangeOpen, setPasswordChangeOpen] = useState(false); const [languageSelectorOpen, setLanguageSelectorOpen] = useState(false); + const [starCount, setStarCount] = useState(null); useEffect(() => { initSelect(); @@ -51,6 +53,16 @@ export default function HomeSidebar({ localStorage.setItem('token', 'test-token'); localStorage.setItem('userEmail', 'test@example.com'); } + + spaceClient + .get('/api/v1/dist/info/repo') + .then((response) => { + const data = response as { repo: { stargazers_count: number } }; + setStarCount(data.repo.stargazers_count); + }) + .catch((error) => { + console.error('Failed to fetch GitHub star count:', error); + }); return () => console.log('sidebar.unmounted'); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -150,6 +162,30 @@ export default function HomeSidebar({
+ {starCount !== null && ( +
{ + window.open('https://github.com/langbot-app/LangBot', '_blank'); + }} + className="flex justify-center cursor-pointer p-2 rounded-lg hover:bg-accent/30 transition-colors" + > + + + + +
+ {starCount.toLocaleString()} +
+
+ )} + { // open docs.langbot.app From 89b25b898562f6ccc9302dbf5c541ebe685fd7ab Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Fri, 29 Aug 2025 17:01:26 +0800 Subject: [PATCH 5/5] chore: release v4.2.2 --- pkg/utils/constants.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/utils/constants.py b/pkg/utils/constants.py index 8b620e41..74fe232b 100644 --- a/pkg/utils/constants.py +++ b/pkg/utils/constants.py @@ -1,4 +1,4 @@ -semantic_version = 'v4.2.1' +semantic_version = 'v4.2.2' required_database_version = 5 """Tag the version of the database schema, used to check if the database needs to be migrated""" diff --git a/pyproject.toml b/pyproject.toml index b12db3e1..ef1e174b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "langbot" -version = "4.1.0" +version = "4.2.2" description = "高稳定、支持扩展、多模态 - 大模型原生即时通信机器人平台" readme = "README.md" requires-python = ">=3.10.1"