From d9ec43469993052dd416a2fbce00bccf254749a8 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Tue, 11 Mar 2025 17:08:33 +0800 Subject: [PATCH 01/28] =?UTF-8?q?feat:gewe=E7=9A=84client=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20=E6=B7=BB=E5=8A=A0=E5=A5=BD=E5=8F=8B=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20feat:gewe=E7=9A=84client=E6=B7=BB=E5=8A=A0=20?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E7=BE=A4=E4=BF=A1=E6=81=AF/=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98=E6=8E=A5=E5=8F=A3=20feat:gewe=E7=9A=84client?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E6=B7=BB=E5=8A=A0=E7=BE=A4=E6=88=90?= =?UTF-8?q?=E5=91=98=E4=B8=BA=E5=A5=BD=E5=8F=8B=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/platform/sources/gewechat/client.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 7268efded..de7762b2d 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -487,3 +487,75 @@ class SimpleGewechatClient: ) as resp: json_blob = await resp.json() logger.debug(f"发送文件结果: {json_blob}") + + async def add_friend(self, v3: str, v4: str, content: str): + """申请添加好友""" + payload = { + "appId": self.appid, + "scene": 3, + "content": content, + "v4": v4, + "v3": v3, + "option": 2, + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/contacts/addContacts", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"申请添加好友结果: {json_blob}") + return json_blob + + async def get_group(self, group_id: str): + payload = { + "appId": self.appid, + "chatroomId": group_id, + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/group/getChatroomInfo", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + return json_blob + + async def get_group_member(self, group_id: str): + payload = { + "appId": self.appid, + "chatroomId": group_id, + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/group/getChatroomMemberList", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + return json_blob + + + async def add_group_member_to_friend(self, group_id: str,to_wxid: str,content: str): + payload = { + "appId": self.appid, + "chatroomId": group_id, + "content": content, + "memberWxid": to_wxid + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/group/addGroupMemberAsFriend", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + return json_blob \ No newline at end of file From 76cfc31a1d992f6bf9dea23f2f1a71d9fbb7124d Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Tue, 11 Mar 2025 17:10:04 +0800 Subject: [PATCH 02/28] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=20Group=20?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/astrbot_message.py | 48 +++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/astrbot/core/platform/astrbot_message.py b/astrbot/core/platform/astrbot_message.py index ea55eaf4b..cb399bacf 100644 --- a/astrbot/core/platform/astrbot_message.py +++ b/astrbot/core/platform/astrbot_message.py @@ -1,5 +1,5 @@ import time -from typing import List +from typing import List, Dict, Any from dataclasses import dataclass from astrbot.core.message.components import BaseMessageComponent from .message_type import MessageType @@ -10,6 +10,52 @@ class MessageMember: user_id: str # 发送者id nickname: str = None + def __str__(self): + # 使用 f-string 来构建返回的字符串表示形式 + return (f"User ID: {self.user_id}\n" + f"Nickname: {self.nickname if self.nickname else 'N/A'}") + +@dataclass +class Group: + group_id: str + group_name: str = None + + # 群头像 + group_avatar: str = None + + # 群主id + group_owner: str = None + + # 群管理员id + group_admin: str = None + + # 群成员 + members: List[MessageMember] = None + + def __str__(self): + # 使用 f-string 来构建返回的字符串表示形式 + return (f"Group ID: {self.group_id}\n" + f"Name: {self.group_name if self.group_name else 'N/A'}\n" + f"Avatar: {self.group_avatar if self.group_avatar else 'N/A'}\n" + f"Owner ID: {self.group_owner if self.group_owner else 'N/A'}\n" + f"Admin ID: {self.group_admin if self.group_admin else 'N/A'}") + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "Group": + # 提取members信息并转换为MessageMember对象 + members = [ + MessageMember(user_id=member["wxid"], nickname=member["nickName"]) + for member in data.get("memberList", []) + ] + + return cls( + group_id=data["chatroomId"], + group_name=data.get("nickName"), + group_avatar=data.get("smallHeadImgUrl"), + group_owner=data.get("chatRoomOwner"), + members=members, + ) + class AstrBotMessage: """ From 4a8309ed1f77e6921be5bd81a63806ca0ea7ba60 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Tue, 11 Mar 2025 17:10:55 +0800 Subject: [PATCH 03/28] =?UTF-8?q?style:idea=E9=BB=98=E8=AE=A4=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BA=86=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=20feat:=E6=B7=BB=E5=8A=A0=E6=A0=B9=E6=8D=AE=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E8=8E=B7=E5=8F=96=E7=BE=A4=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/astr_message_event.py | 75 +++++++++++++++------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/astrbot/core/platform/astr_message_event.py b/astrbot/core/platform/astr_message_event.py index 72e4414b6..a85ec0b9b 100644 --- a/astrbot/core/platform/astr_message_event.py +++ b/astrbot/core/platform/astr_message_event.py @@ -1,11 +1,9 @@ import abc import asyncio from dataclasses import dataclass -from .astrbot_message import AstrBotMessage -from .platform_metadata import PlatformMetadata -from astrbot.core.message.message_event_result import MessageEventResult, MessageChain -from astrbot.core.platform.message_type import MessageType -from typing import List, Union +from typing import List, Union, Optional + +from astrbot.core.db.po import Conversation from astrbot.core.message.components import ( Plain, Image, @@ -15,9 +13,12 @@ from astrbot.core.message.components import ( AtAll, Forward, ) -from astrbot.core.utils.metrics import Metric +from astrbot.core.message.message_event_result import MessageEventResult, MessageChain +from astrbot.core.platform.message_type import MessageType from astrbot.core.provider.entites import ProviderRequest -from astrbot.core.db.po import Conversation +from astrbot.core.utils.metrics import Metric +from .astrbot_message import AstrBotMessage, Group +from .platform_metadata import PlatformMetadata @dataclass @@ -37,11 +38,11 @@ class MessageSesion: class AstrMessageEvent(abc.ABC): def __init__( - self, - message_str: str, - message_obj: AstrBotMessage, - platform_meta: PlatformMetadata, - session_id: str, + self, + message_str: str, + message_obj: AstrBotMessage, + platform_meta: PlatformMetadata, + session_id: str, ): self.message_str = message_str """纯文本的消息""" @@ -320,14 +321,14 @@ class AstrMessageEvent(abc.ABC): """LLM 请求相关""" def request_llm( - self, - prompt: str, - func_tool_manager=None, - session_id: str = None, - image_urls: List[str] = [], - contexts: List = [], - system_prompt: str = "", - conversation: Conversation = None, + self, + prompt: str, + func_tool_manager=None, + session_id: str = None, + image_urls: List[str] = [], + contexts: List = [], + system_prompt: str = "", + conversation: Conversation = None, ) -> ProviderRequest: """ 创建一个 LLM 请求。 @@ -363,3 +364,37 @@ class AstrMessageEvent(abc.ABC): system_prompt=system_prompt, conversation=conversation, ) + + async def get_group(self, group_id: str = None) -> Optional[Group]: + """ + 获取群聊,如果不填写group_id,且消息是私聊消息,则返回 None + 目前只实现了 GeweChat 协议 + """ + # 确定有效的 group_id + if group_id is None: + group_id = self.message_obj.group_id + + if group_id is None: + return None + + # 检查平台是否为 gewechat + if self.platform_meta.name != "gewechat": + return None + + from astrbot.core.platform.sources.gewechat.gewechat_event import ( + GewechatPlatformEvent, + ) + + assert isinstance(self, GewechatPlatformEvent) + client = self.client + + # 从客户端获取群信息 + res = await client.get_group(group_id) + + data = res["data"] + + # 检查 chatroomId 是否为空 + if data["chatroomId"] == "": + return None + + return Group.from_dict(data) From 00f5189f58cab395512ec670f21d7d395d3fc1ad Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 09:16:43 +0000 Subject: [PATCH 04/28] :balloon: auto fixes by pre-commit hooks --- astrbot/core/platform/astr_message_event.py | 26 +++++++++---------- astrbot/core/platform/astrbot_message.py | 19 +++++++++----- .../core/platform/sources/gewechat/client.py | 9 ++++--- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/astrbot/core/platform/astr_message_event.py b/astrbot/core/platform/astr_message_event.py index a85ec0b9b..02d600768 100644 --- a/astrbot/core/platform/astr_message_event.py +++ b/astrbot/core/platform/astr_message_event.py @@ -38,11 +38,11 @@ class MessageSesion: class AstrMessageEvent(abc.ABC): def __init__( - self, - message_str: str, - message_obj: AstrBotMessage, - platform_meta: PlatformMetadata, - session_id: str, + self, + message_str: str, + message_obj: AstrBotMessage, + platform_meta: PlatformMetadata, + session_id: str, ): self.message_str = message_str """纯文本的消息""" @@ -321,14 +321,14 @@ class AstrMessageEvent(abc.ABC): """LLM 请求相关""" def request_llm( - self, - prompt: str, - func_tool_manager=None, - session_id: str = None, - image_urls: List[str] = [], - contexts: List = [], - system_prompt: str = "", - conversation: Conversation = None, + self, + prompt: str, + func_tool_manager=None, + session_id: str = None, + image_urls: List[str] = [], + contexts: List = [], + system_prompt: str = "", + conversation: Conversation = None, ) -> ProviderRequest: """ 创建一个 LLM 请求。 diff --git a/astrbot/core/platform/astrbot_message.py b/astrbot/core/platform/astrbot_message.py index cb399bacf..be49ba18e 100644 --- a/astrbot/core/platform/astrbot_message.py +++ b/astrbot/core/platform/astrbot_message.py @@ -12,8 +12,11 @@ class MessageMember: def __str__(self): # 使用 f-string 来构建返回的字符串表示形式 - return (f"User ID: {self.user_id}\n" - f"Nickname: {self.nickname if self.nickname else 'N/A'}") + return ( + f"User ID: {self.user_id}\n" + f"Nickname: {self.nickname if self.nickname else 'N/A'}" + ) + @dataclass class Group: @@ -34,11 +37,13 @@ class Group: def __str__(self): # 使用 f-string 来构建返回的字符串表示形式 - return (f"Group ID: {self.group_id}\n" - f"Name: {self.group_name if self.group_name else 'N/A'}\n" - f"Avatar: {self.group_avatar if self.group_avatar else 'N/A'}\n" - f"Owner ID: {self.group_owner if self.group_owner else 'N/A'}\n" - f"Admin ID: {self.group_admin if self.group_admin else 'N/A'}") + return ( + f"Group ID: {self.group_id}\n" + f"Name: {self.group_name if self.group_name else 'N/A'}\n" + f"Avatar: {self.group_avatar if self.group_avatar else 'N/A'}\n" + f"Owner ID: {self.group_owner if self.group_owner else 'N/A'}\n" + f"Admin ID: {self.group_admin if self.group_admin else 'N/A'}" + ) @classmethod def from_dict(cls, data: Dict[str, Any]) -> "Group": diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index de7762b2d..6c7bd0a23 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -541,13 +541,14 @@ class SimpleGewechatClient: logger.debug(f"获取群信息结果: {json_blob}") return json_blob - - async def add_group_member_to_friend(self, group_id: str,to_wxid: str,content: str): + async def add_group_member_to_friend( + self, group_id: str, to_wxid: str, content: str + ): payload = { "appId": self.appid, "chatroomId": group_id, "content": content, - "memberWxid": to_wxid + "memberWxid": to_wxid, } async with aiohttp.ClientSession() as session: @@ -558,4 +559,4 @@ class SimpleGewechatClient: ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") - return json_blob \ No newline at end of file + return json_blob From d177b9f7fab89678d479888603034ec8f6591816 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Fri, 14 Mar 2025 17:11:10 +0800 Subject: [PATCH 05/28] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E4=B8=BB=E5=8A=A8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A5=BD=E5=8F=8B=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../core/platform/sources/gewechat/client.py | 155 +++++++++++------- requirements.txt | 44 ++--- 3 files changed, 124 insertions(+), 76 deletions(-) diff --git a/.gitignore b/.gitignore index a863e36ec..4b683ee8b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ venv/* packages/python_interpreter/workplace .venv/* .conda/ +.idea \ No newline at end of file diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 6c7bd0a23..985185b12 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -1,17 +1,19 @@ -import threading import asyncio -import aiohttp -import quart import base64 import datetime -import re import os +import re +import threading + +import aiohttp import anyio -from astrbot.api.platform import AstrBotMessage, MessageMember, MessageType -from astrbot.api.message_components import Plain, Image, At, Record +import quart + from astrbot.api import logger, sp -from .downloader import GeweDownloader +from astrbot.api.message_components import Plain, Image, At, Record +from astrbot.api.platform import AstrBotMessage, MessageMember, MessageType from astrbot.core.utils.io import download_image_by_url +from .downloader import GeweDownloader class SimpleGewechatClient: @@ -22,12 +24,12 @@ class SimpleGewechatClient: """ def __init__( - self, - base_url: str, - nickname: str, - host: str, - port: int, - event_queue: asyncio.Queue, + self, + base_url: str, + nickname: str, + host: str, + port: int, + event_queue: asyncio.Queue, ): self.base_url = base_url if self.base_url.endswith("/"): @@ -137,8 +139,8 @@ class SimpleGewechatClient: # at msg_source = d["MsgSource"] if ( - f"" in msg_source - or f"" in msg_source + f"" in msg_source + or f"" in msg_source ): at_me = True if "在群聊中@了你" in d.get("PushContent", ""): @@ -155,8 +157,8 @@ class SimpleGewechatClient: user_real_name = "unknown" if abm.group_id: if ( - abm.group_id not in self.userrealnames - or user_id not in self.userrealnames[abm.group_id] + abm.group_id not in self.userrealnames + or user_id not in self.userrealnames[abm.group_id] ): # 获取群成员列表,并且缓存 if abm.group_id not in self.userrealnames: @@ -250,9 +252,9 @@ class SimpleGewechatClient: await asyncio.sleep(3) async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/tools/setCallback", - headers=self.headers, - json={"token": self.token, "callbackUrl": self.callback_url}, + f"{self.base_url}/tools/setCallback", + headers=self.headers, + json={"token": self.token, "callbackUrl": self.callback_url}, ) as resp: json_blob = await resp.json() logger.info(f"设置回调结果: {json_blob}") @@ -280,9 +282,9 @@ class SimpleGewechatClient: # /login/checkOnline async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/checkOnline", - headers=self.headers, - json={"appId": appid}, + f"{self.base_url}/login/checkOnline", + headers=self.headers, + json={"appId": appid}, ) as resp: json_blob = await resp.json() return json_blob["data"] @@ -293,9 +295,9 @@ class SimpleGewechatClient: if online: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/logout", - headers=self.headers, - json={"appId": self.appid}, + f"{self.base_url}/login/logout", + headers=self.headers, + json={"appId": self.appid}, ) as resp: json_blob = await resp.json() logger.info(f"登出结果: {json_blob}") @@ -327,9 +329,9 @@ class SimpleGewechatClient: try: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/getLoginQrCode", - headers=self.headers, - json=payload, + f"{self.base_url}/login/getLoginQrCode", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() if json_blob["ret"] != 200: @@ -378,9 +380,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/checkLogin", - headers=self.headers, - json=payload, + f"{self.base_url}/login/checkLogin", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.info(f"检查登录状态: {json_blob}") @@ -419,9 +421,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomMemberList", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomMemberList", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() return json_blob["data"] @@ -437,7 +439,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postText", headers=self.headers, json=payload + f"{self.base_url}/message/postText", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送消息结果: {json_blob}") @@ -451,7 +453,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postImage", headers=self.headers, json=payload + f"{self.base_url}/message/postImage", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送图片结果: {json_blob}") @@ -468,7 +470,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postVoice", headers=self.headers, json=payload + f"{self.base_url}/message/postVoice", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送语音结果: {json_blob}") @@ -483,7 +485,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postFile", headers=self.headers, json=payload + f"{self.base_url}/message/postFile", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送文件结果: {json_blob}") @@ -501,9 +503,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/contacts/addContacts", - headers=self.headers, - json=payload, + f"{self.base_url}/contacts/addContacts", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"申请添加好友结果: {json_blob}") @@ -517,9 +519,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomInfo", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomInfo", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") @@ -533,29 +535,68 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomMemberList", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomMemberList", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") return json_blob - async def add_group_member_to_friend( - self, group_id: str, to_wxid: str, content: str - ): + async def accept_group_invite(self, url: str): + """同意进群""" payload = { "appId": self.appid, - "chatroomId": group_id, - "content": content, - "memberWxid": to_wxid, + "url": url } async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/addGroupMemberAsFriend", - headers=self.headers, - json=payload, + f"{self.base_url}/group/agreeJoinRoom", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + return json_blob + + async def add_group_member_to_friend(self, group_id: str, to_wxid: str, content: str): + payload = { + "appId": self.appid, + "chatroomId": group_id, + "content": content, + "memberWxid": to_wxid + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/group/addGroupMemberAsFriend", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + return json_blob + + async def get_user_or_group_info(self, *ids): + """ + 获取用户或群组信息。 + + :param ids: 可变数量的 wxid 参数 + """ + + wxids_str = list(ids) + + payload = { + "appId": self.appid, + "wxids": wxids_str # 使用逗号分隔的字符串 + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/contacts/getDetailInfo", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") diff --git a/requirements.txt b/requirements.txt index 07b168cc1..ac56e3db4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,27 +1,33 @@ pydantic~=2.10.3 -aiohttp -openai -anthropic +aiohttp~=3.11.13 +openai~=1.65.5 +anthropic~=0.49.0 qq-botpy chardet~=5.1.0 -Pillow -beautifulsoup4 +Pillow~=11.1.0 +beautifulsoup4~=4.13.3 googlesearch-python -readability-lxml -quart +readability-lxml~=0.8.1 +quart~=0.20.0 lxml_html_clean -colorlog -aiocqhttp -pyjwt -apscheduler -docstring_parser -aiodocker +colorlog~=6.9.0 +aiocqhttp~=1.4.4 +pyjwt~=2.10.1 +apscheduler~=3.11.0 +docstring_parser~=0.16 +aiodocker~=0.24.0 silk-python psutil>=5.8.0 lark-oapi -ormsgpack -cryptography -dashscope -python-telegram-bot -wechatpy -dingtalk-stream \ No newline at end of file +ormsgpack~=1.8.0 +cryptography~=44.0.2 +dashscope~=1.22.2 +python-telegram-bot~=21.11.1 +wechatpy~=1.8.18 +dingtalk-stream +PyYAML~=6.0.2 +pip~=23.2.1 +typing_extensions~=4.12.2 +requests~=2.32.3 +anyio~=4.8.0 +httpx~=0.28.1 \ No newline at end of file From c95682a0c7f5a8e5d3802d0ebc56edb8b19739dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:11:21 +0000 Subject: [PATCH 06/28] :balloon: auto fixes by pre-commit hooks --- .../core/platform/sources/gewechat/client.py | 119 +++++++++--------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 985185b12..abaf1a877 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -24,12 +24,12 @@ class SimpleGewechatClient: """ def __init__( - self, - base_url: str, - nickname: str, - host: str, - port: int, - event_queue: asyncio.Queue, + self, + base_url: str, + nickname: str, + host: str, + port: int, + event_queue: asyncio.Queue, ): self.base_url = base_url if self.base_url.endswith("/"): @@ -139,8 +139,8 @@ class SimpleGewechatClient: # at msg_source = d["MsgSource"] if ( - f"" in msg_source - or f"" in msg_source + f"" in msg_source + or f"" in msg_source ): at_me = True if "在群聊中@了你" in d.get("PushContent", ""): @@ -157,8 +157,8 @@ class SimpleGewechatClient: user_real_name = "unknown" if abm.group_id: if ( - abm.group_id not in self.userrealnames - or user_id not in self.userrealnames[abm.group_id] + abm.group_id not in self.userrealnames + or user_id not in self.userrealnames[abm.group_id] ): # 获取群成员列表,并且缓存 if abm.group_id not in self.userrealnames: @@ -252,9 +252,9 @@ class SimpleGewechatClient: await asyncio.sleep(3) async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/tools/setCallback", - headers=self.headers, - json={"token": self.token, "callbackUrl": self.callback_url}, + f"{self.base_url}/tools/setCallback", + headers=self.headers, + json={"token": self.token, "callbackUrl": self.callback_url}, ) as resp: json_blob = await resp.json() logger.info(f"设置回调结果: {json_blob}") @@ -282,9 +282,9 @@ class SimpleGewechatClient: # /login/checkOnline async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/checkOnline", - headers=self.headers, - json={"appId": appid}, + f"{self.base_url}/login/checkOnline", + headers=self.headers, + json={"appId": appid}, ) as resp: json_blob = await resp.json() return json_blob["data"] @@ -295,9 +295,9 @@ class SimpleGewechatClient: if online: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/logout", - headers=self.headers, - json={"appId": self.appid}, + f"{self.base_url}/login/logout", + headers=self.headers, + json={"appId": self.appid}, ) as resp: json_blob = await resp.json() logger.info(f"登出结果: {json_blob}") @@ -329,9 +329,9 @@ class SimpleGewechatClient: try: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/getLoginQrCode", - headers=self.headers, - json=payload, + f"{self.base_url}/login/getLoginQrCode", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() if json_blob["ret"] != 200: @@ -380,9 +380,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/login/checkLogin", - headers=self.headers, - json=payload, + f"{self.base_url}/login/checkLogin", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.info(f"检查登录状态: {json_blob}") @@ -421,9 +421,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomMemberList", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomMemberList", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() return json_blob["data"] @@ -439,7 +439,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postText", headers=self.headers, json=payload + f"{self.base_url}/message/postText", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送消息结果: {json_blob}") @@ -453,7 +453,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postImage", headers=self.headers, json=payload + f"{self.base_url}/message/postImage", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送图片结果: {json_blob}") @@ -470,7 +470,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postVoice", headers=self.headers, json=payload + f"{self.base_url}/message/postVoice", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送语音结果: {json_blob}") @@ -485,7 +485,7 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/message/postFile", headers=self.headers, json=payload + f"{self.base_url}/message/postFile", headers=self.headers, json=payload ) as resp: json_blob = await resp.json() logger.debug(f"发送文件结果: {json_blob}") @@ -503,9 +503,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/contacts/addContacts", - headers=self.headers, - json=payload, + f"{self.base_url}/contacts/addContacts", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"申请添加好友结果: {json_blob}") @@ -519,9 +519,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomInfo", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomInfo", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") @@ -535,9 +535,9 @@ class SimpleGewechatClient: async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/getChatroomMemberList", - headers=self.headers, - json=payload, + f"{self.base_url}/group/getChatroomMemberList", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") @@ -545,34 +545,33 @@ class SimpleGewechatClient: async def accept_group_invite(self, url: str): """同意进群""" - payload = { - "appId": self.appid, - "url": url - } + payload = {"appId": self.appid, "url": url} async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/agreeJoinRoom", - headers=self.headers, - json=payload, + f"{self.base_url}/group/agreeJoinRoom", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") return json_blob - async def add_group_member_to_friend(self, group_id: str, to_wxid: str, content: str): + async def add_group_member_to_friend( + self, group_id: str, to_wxid: str, content: str + ): payload = { "appId": self.appid, "chatroomId": group_id, "content": content, - "memberWxid": to_wxid + "memberWxid": to_wxid, } async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/group/addGroupMemberAsFriend", - headers=self.headers, - json=payload, + f"{self.base_url}/group/addGroupMemberAsFriend", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") @@ -580,23 +579,23 @@ class SimpleGewechatClient: async def get_user_or_group_info(self, *ids): """ - 获取用户或群组信息。 + 获取用户或群组信息。 - :param ids: 可变数量的 wxid 参数 - """ + :param ids: 可变数量的 wxid 参数 + """ wxids_str = list(ids) payload = { "appId": self.appid, - "wxids": wxids_str # 使用逗号分隔的字符串 + "wxids": wxids_str, # 使用逗号分隔的字符串 } async with aiohttp.ClientSession() as session: async with session.post( - f"{self.base_url}/contacts/getDetailInfo", - headers=self.headers, - json=payload, + f"{self.base_url}/contacts/getDetailInfo", + headers=self.headers, + json=payload, ) as resp: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") From 44601c8954c25b60f568f49652af3dd27337d04d Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Fri, 14 Mar 2025 18:30:27 +0800 Subject: [PATCH 07/28] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Dgewe=E7=9A=84ModCon?= =?UTF-8?q?tacts=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/sources/gewechat/client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 985185b12..d7550490b 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -115,6 +115,12 @@ class SimpleGewechatClient: abm = AstrBotMessage() + if type_name == "ModContacts": + abm.type = MessageType.OTHER_MESSAGE + abm.raw_message = data + logger.debug(f"abm: {abm}") + return abm + from_user_name = d["FromUserName"]["string"] # 消息来源 d["to_wxid"] = from_user_name # 用于发信息 From 2e4fef6c6613309789de8e56fd6dee20d51fa138 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Mon, 17 Mar 2025 16:02:55 +0800 Subject: [PATCH 08/28] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/platform/sources/gewechat/client.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 026195fc8..7a07afe9c 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -115,11 +115,8 @@ class SimpleGewechatClient: abm = AstrBotMessage() - if type_name == "ModContacts": - abm.type = MessageType.OTHER_MESSAGE - abm.raw_message = data - logger.debug(f"abm: {abm}") - return abm + # if type_name == "ModContacts": + # self from_user_name = d["FromUserName"]["string"] # 消息来源 d["to_wxid"] = from_user_name # 用于发信息 @@ -606,3 +603,19 @@ class SimpleGewechatClient: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") return json_blob + async def send_message(self, to_wxid, content): + payload = { + "appId": self.appid, + "toWxid": to_wxid, + "content":content + } + + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.base_url}/message/postText", + headers=self.headers, + json=payload, + ) as resp: + json_blob = await resp.json() + logger.debug(f"获取群信息结果: {json_blob}") + # return json_blob From 13a95e1f2b454b66303c24e538ec559a3ada91b4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 08:42:40 +0000 Subject: [PATCH 09/28] :balloon: auto fixes by pre-commit hooks --- astrbot/core/message/message_event_result.py | 1 + .../sources/aiocqhttp/aiocqhttp_message_event.py | 1 + astrbot/core/platform/sources/gewechat/client.py | 9 +++------ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/astrbot/core/message/message_event_result.py b/astrbot/core/message/message_event_result.py index 48d0b18c9..4cc7fb842 100644 --- a/astrbot/core/message/message_event_result.py +++ b/astrbot/core/message/message_event_result.py @@ -151,4 +151,5 @@ class MessageEventResult(MessageChain): """是否为 LLM 结果。""" return self.result_content_type == ResultContentType.LLM_RESULT + CommandResult = MessageEventResult diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py index 08990015e..0dfe41a4e 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py @@ -4,6 +4,7 @@ from astrbot.api.event import AstrMessageEvent, MessageChain from astrbot.api.message_components import Plain, Image, Record, At, Node, Nodes from aiocqhttp import CQHttp + class AiocqhttpMessageEvent(AstrMessageEvent): def __init__( self, message_str, message_obj, platform_meta, session_id, bot: CQHttp diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 90e60a255..c7fd52e19 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -125,7 +125,7 @@ class SimpleGewechatClient: abm = AstrBotMessage() # if type_name == "ModContacts": - # self + # self from_user_name = d["FromUserName"]["string"] # 消息来源 d["to_wxid"] = from_user_name # 用于发信息 @@ -642,12 +642,9 @@ class SimpleGewechatClient: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") return json_blob + async def send_message(self, to_wxid, content): - payload = { - "appId": self.appid, - "toWxid": to_wxid, - "content":content - } + payload = {"appId": self.appid, "toWxid": to_wxid, "content": content} async with aiohttp.ClientSession() as session: async with session.post( From 8838dbd003fcdadec3de5304af16ec23381fa966 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 20 Mar 2025 16:52:48 +0800 Subject: [PATCH 10/28] =?UTF-8?q?=F0=9F=8E=A8=20style:=20format=20codes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/sources/gewechat/client.py | 3 --- astrbot/core/platform/sources/gewechat/gewechat_event.py | 2 +- astrbot/core/platform/sources/wecom/wecom_event.py | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index c7fd52e19..5140e499d 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -124,9 +124,6 @@ class SimpleGewechatClient: abm = AstrBotMessage() - # if type_name == "ModContacts": - # self - from_user_name = d["FromUserName"]["string"] # 消息来源 d["to_wxid"] = from_user_name # 用于发信息 diff --git a/astrbot/core/platform/sources/gewechat/gewechat_event.py b/astrbot/core/platform/sources/gewechat/gewechat_event.py index 247a2a6a4..15f0badd7 100644 --- a/astrbot/core/platform/sources/gewechat/gewechat_event.py +++ b/astrbot/core/platform/sources/gewechat/gewechat_event.py @@ -2,7 +2,7 @@ import wave import uuid import traceback import os -from astrbot.core.utils.io import save_temp_img, download_image_by_url, download_file +from astrbot.core.utils.io import save_temp_img, download_file from astrbot.core.utils.tencent_record_helper import wav_to_tencent_silk from astrbot.api import logger from astrbot.api.event import AstrMessageEvent, MessageChain diff --git a/astrbot/core/platform/sources/wecom/wecom_event.py b/astrbot/core/platform/sources/wecom/wecom_event.py index c6f8d6ef6..470b7b1f8 100644 --- a/astrbot/core/platform/sources/wecom/wecom_event.py +++ b/astrbot/core/platform/sources/wecom/wecom_event.py @@ -3,7 +3,6 @@ from astrbot.api.event import AstrMessageEvent, MessageChain from astrbot.api.platform import AstrBotMessage, PlatformMetadata from astrbot.api.message_components import Plain, Image, Record from wechatpy.enterprise import WeChatClient -from astrbot.core.utils.io import download_image_by_url, download_file from astrbot.api import logger From 361256e0162b8762c01f5a5b474e3f49caa35467 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 20 Mar 2025 17:20:32 +0800 Subject: [PATCH 11/28] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=20gewechat=20client=20=E7=9A=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/platform/sources/gewechat/client.py | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index 5140e499d..bc5e65c8d 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -53,11 +53,11 @@ class SimpleGewechatClient: self.server = quart.Quart(__name__) self.server.add_url_rule( - "/astrbot-gewechat/callback", view_func=self.callback, methods=["POST"] + "/astrbot-gewechat/callback", view_func=self._callback, methods=["POST"] ) self.server.add_url_rule( "/astrbot-gewechat/file/", - view_func=self.handle_file, + view_func=self._handle_file, methods=["GET"], ) @@ -75,6 +75,8 @@ class SimpleGewechatClient: self.stop = False async def get_token_id(self): + """获取 Gewechat Token。 + """ async with aiohttp.ClientSession() as session: async with session.post(f"{self.base_url}/tools/getTokenId") as resp: json_blob = await resp.json() @@ -260,7 +262,7 @@ class SimpleGewechatClient: logger.debug(f"abm: {abm}") return abm - async def callback(self): + async def _callback(self): data = await quart.request.json logger.debug(f"收到 gewechat 回调: {data}") @@ -282,7 +284,7 @@ class SimpleGewechatClient: return quart.jsonify({"r": "AstrBot ACK"}) - async def handle_file(self, file_id): + async def _handle_file(self, file_id): file_path = f"data/temp/{file_id}" return await quart.send_file(file_path) @@ -308,17 +310,18 @@ class SimpleGewechatClient: await self.server.run_task( host="0.0.0.0", port=self.port, - shutdown_trigger=self.shutdown_trigger_placeholder, + shutdown_trigger=self._shutdown_trigger_placeholder, ) - async def shutdown_trigger_placeholder(self): + async def _shutdown_trigger_placeholder(self): # TODO: use asyncio.Event while not self.event_queue.closed and not self.stop: # noqa: ASYNC110 await asyncio.sleep(1) logger.info("gewechat 适配器已关闭。") async def check_online(self, appid: str): - # /login/checkOnline + """检查 APPID 对应的设备是否在线。 + """ async with aiohttp.ClientSession() as session: async with session.post( f"{self.base_url}/login/checkOnline", @@ -329,6 +332,8 @@ class SimpleGewechatClient: return json_blob["data"] async def logout(self): + """登出 gewechat。 + """ if self.appid: online = await self.check_online(self.appid) if online: @@ -342,6 +347,8 @@ class SimpleGewechatClient: logger.info(f"登出结果: {json_blob}") async def login(self): + """登录 gewechat。一般来说插件用不到这个方法。 + """ if self.token is None: await self.get_token_id() @@ -453,9 +460,18 @@ class SimpleGewechatClient: self.appid = appid logger.info(f"已保存 APPID: {appid}") - """API""" + """API 部分。Gewechat 的 API 文档请参考: https://apifox.com/apidoc/shared/69ba62ca-cb7d-437e-85e4-6f3d3df271b1 + """ - async def get_chatroom_member_list(self, chatroom_wxid: str): + async def get_chatroom_member_list(self, chatroom_wxid: str) -> dict: + """获取群成员列表。 + + Args: + chatroom_wxid (str): 微信群聊的id。可以通过 event.get_group_id() 获取。 + + Returns: + dict: 返回群成员列表字典。其中键为 memberList 的值为群成员列表。 + """ payload = {"appId": self.appid, "chatroomId": chatroom_wxid} async with aiohttp.ClientSession() as session: @@ -468,6 +484,7 @@ class SimpleGewechatClient: return json_blob["data"] async def post_text(self, to_wxid, content: str, ats: str = ""): + """发送纯文本消息""" payload = { "appId": self.appid, "toWxid": to_wxid, @@ -484,6 +501,7 @@ class SimpleGewechatClient: logger.debug(f"发送消息结果: {json_blob}") async def post_image(self, to_wxid, image_url: str): + """发送图片消息""" payload = { "appId": self.appid, "toWxid": to_wxid, @@ -498,6 +516,12 @@ class SimpleGewechatClient: logger.debug(f"发送图片结果: {json_blob}") async def post_voice(self, to_wxid, voice_url: str, voice_duration: int): + """发送语音信息 + + Args: + voice_url (str): 语音文件的网络链接 + voice_duration (int): 语音时长,毫秒 + """ payload = { "appId": self.appid, "toWxid": to_wxid, @@ -515,6 +539,13 @@ class SimpleGewechatClient: logger.debug(f"发送语音结果: {json_blob}") async def post_file(self, to_wxid, file_url: str, file_name: str): + """发送文件 + + Args: + to_wxid (string): 微信ID + file_url (str): 文件的网络链接 + file_name (str): 文件名 + """ payload = { "appId": self.appid, "toWxid": to_wxid, From 1e7eb2cf1c468f153a79961b45f996d8d658e637 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:21:31 +0000 Subject: [PATCH 12/28] :balloon: auto fixes by pre-commit hooks --- astrbot/core/platform/sources/gewechat/client.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index bc5e65c8d..edc7afb55 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -75,8 +75,7 @@ class SimpleGewechatClient: self.stop = False async def get_token_id(self): - """获取 Gewechat Token。 - """ + """获取 Gewechat Token。""" async with aiohttp.ClientSession() as session: async with session.post(f"{self.base_url}/tools/getTokenId") as resp: json_blob = await resp.json() @@ -320,8 +319,7 @@ class SimpleGewechatClient: logger.info("gewechat 适配器已关闭。") async def check_online(self, appid: str): - """检查 APPID 对应的设备是否在线。 - """ + """检查 APPID 对应的设备是否在线。""" async with aiohttp.ClientSession() as session: async with session.post( f"{self.base_url}/login/checkOnline", @@ -332,8 +330,7 @@ class SimpleGewechatClient: return json_blob["data"] async def logout(self): - """登出 gewechat。 - """ + """登出 gewechat。""" if self.appid: online = await self.check_online(self.appid) if online: @@ -347,8 +344,7 @@ class SimpleGewechatClient: logger.info(f"登出结果: {json_blob}") async def login(self): - """登录 gewechat。一般来说插件用不到这个方法。 - """ + """登录 gewechat。一般来说插件用不到这个方法。""" if self.token is None: await self.get_token_id() From 7a24cbff1c8ad0ba1825e5830f19b992b480ca2f Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 20 Mar 2025 18:04:58 +0800 Subject: [PATCH 13/28] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=94=AF=E6=8C=81=20?= =?UTF-8?q?aiocqhttp=20=E9=80=82=E9=85=8D=E5=99=A8=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E7=BE=A4=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/api/platform/__init__.py | 2 + astrbot/core/platform/__init__.py | 2 +- astrbot/core/platform/astr_message_event.py | 54 ++++++------------- astrbot/core/platform/astrbot_message.py | 38 ++++--------- .../aiocqhttp/aiocqhttp_message_event.py | 46 +++++++++++++++- .../sources/gewechat/gewechat_event.py | 29 +++++++++- 6 files changed, 104 insertions(+), 67 deletions(-) diff --git a/astrbot/api/platform/__init__.py b/astrbot/api/platform/__init__.py index dcc02bb49..5a98c5903 100644 --- a/astrbot/api/platform/__init__.py +++ b/astrbot/api/platform/__init__.py @@ -5,6 +5,7 @@ from astrbot.core.platform import ( MessageMember, MessageType, PlatformMetadata, + Group, ) from astrbot.core.platform.register import register_platform_adapter @@ -18,4 +19,5 @@ __all__ = [ "MessageType", "PlatformMetadata", "register_platform_adapter", + "Group", ] diff --git a/astrbot/core/platform/__init__.py b/astrbot/core/platform/__init__.py index 48ea57b8a..69a173396 100644 --- a/astrbot/core/platform/__init__.py +++ b/astrbot/core/platform/__init__.py @@ -1,7 +1,7 @@ from .platform import Platform from .astr_message_event import AstrMessageEvent from .platform_metadata import PlatformMetadata -from .astrbot_message import AstrBotMessage, MessageMember, MessageType +from .astrbot_message import AstrBotMessage, MessageMember, MessageType, Group __all__ = [ "Platform", diff --git a/astrbot/core/platform/astr_message_event.py b/astrbot/core/platform/astr_message_event.py index 35a2c4179..3e1b14ee6 100644 --- a/astrbot/core/platform/astr_message_event.py +++ b/astrbot/core/platform/astr_message_event.py @@ -202,15 +202,6 @@ class AstrMessageEvent(abc.ABC): """ return self.role == "admin" - async def send(self, message: MessageChain): - """ - 发送消息到消息平台。 - """ - asyncio.create_task( - Metric.upload(msg_event_tick=1, adapter_name=self.platform_meta.name) - ) - self._has_send_oper = True - async def _pre_send(self): """调度器会在执行 send() 前调用该方法""" @@ -373,36 +364,25 @@ class AstrMessageEvent(abc.ABC): conversation=conversation, ) - async def get_group(self, group_id: str = None) -> Optional[Group]: + """平台适配器""" + + async def send(self, message: MessageChain): + """发送消息到消息平台。 + + Args: + message (MessageChain): 消息链,具体使用方式请参考文档。 """ - 获取群聊,如果不填写group_id,且消息是私聊消息,则返回 None - 目前只实现了 GeweChat 协议 - """ - # 确定有效的 group_id - if group_id is None: - group_id = self.message_obj.group_id - - if group_id is None: - return None - - # 检查平台是否为 gewechat - if self.platform_meta.name != "gewechat": - return None - - from astrbot.core.platform.sources.gewechat.gewechat_event import ( - GewechatPlatformEvent, + asyncio.create_task( + Metric.upload(msg_event_tick=1, adapter_name=self.platform_meta.name) ) + self._has_send_oper = True - assert isinstance(self, GewechatPlatformEvent) - client = self.client + async def get_group(self, group_id: str = None, **kwargs) -> Optional[Group]: + """获取一个群聊的数据, 如果不填写 group_id: 如果是私聊消息,返回 None。如果是群聊消息,返回当前群聊的数据。 - # 从客户端获取群信息 - res = await client.get_group(group_id) + 适配情况: - data = res["data"] - - # 检查 chatroomId 是否为空 - if data["chatroomId"] == "": - return None - - return Group.from_dict(data) + - gewechat + - aiocqhttp(OneBotv11) + """ + ... diff --git a/astrbot/core/platform/astrbot_message.py b/astrbot/core/platform/astrbot_message.py index be49ba18e..def638e96 100644 --- a/astrbot/core/platform/astrbot_message.py +++ b/astrbot/core/platform/astrbot_message.py @@ -13,7 +13,7 @@ class MessageMember: def __str__(self): # 使用 f-string 来构建返回的字符串表示形式 return ( - f"User ID: {self.user_id}\n" + f"User ID: {self.user_id}," f"Nickname: {self.nickname if self.nickname else 'N/A'}" ) @@ -21,19 +21,17 @@ class MessageMember: @dataclass class Group: group_id: str + """群号""" group_name: str = None - - # 群头像 + """群名称""" group_avatar: str = None - - # 群主id + """群头像""" group_owner: str = None - - # 群管理员id - group_admin: str = None - - # 群成员 + """群主 id""" + group_admins: List[str] = None + """群管理员 id""" members: List[MessageMember] = None + """所有群成员""" def __str__(self): # 使用 f-string 来构建返回的字符串表示形式 @@ -42,23 +40,9 @@ class Group: f"Name: {self.group_name if self.group_name else 'N/A'}\n" f"Avatar: {self.group_avatar if self.group_avatar else 'N/A'}\n" f"Owner ID: {self.group_owner if self.group_owner else 'N/A'}\n" - f"Admin ID: {self.group_admin if self.group_admin else 'N/A'}" - ) - - @classmethod - def from_dict(cls, data: Dict[str, Any]) -> "Group": - # 提取members信息并转换为MessageMember对象 - members = [ - MessageMember(user_id=member["wxid"], nickname=member["nickName"]) - for member in data.get("memberList", []) - ] - - return cls( - group_id=data["chatroomId"], - group_name=data.get("nickName"), - group_avatar=data.get("smallHeadImgUrl"), - group_owner=data.get("chatRoomOwner"), - members=members, + f"Admin IDs: {self.group_admins if self.group_admins else 'N/A'}\n" + f"Members Len: {len(self.members) if self.members else 0}\n" + f"First Member: {self.members[0] if self.members else 'N/A'}\n" ) diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py index 0dfe41a4e..c7aede7d1 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py @@ -1,6 +1,7 @@ import asyncio - +import typing from astrbot.api.event import AstrMessageEvent, MessageChain +from astrbot.api.platform import Group, MessageMember from astrbot.api.message_components import Plain, Image, Record, At, Node, Nodes from aiocqhttp import CQHttp @@ -74,3 +75,46 @@ class AiocqhttpMessageEvent(AstrMessageEvent): await self.bot.send(self.message_obj.raw_message, ret) await super().send(message) + + async def get_group(self, group_id=None, **kwargs): + if isinstance(group_id, str) and group_id.isdigit(): + group_id = int(group_id) + elif self.get_group_id(): + group_id = int(self.get_group_id()) + else: + return None + + info: dict = await self.bot.call_action( + "get_group_info", + group_id=group_id, + ) + + members: typing.List[typing.Dict] = await self.bot.call_action( + "get_group_member_list", + group_id=group_id, + ) + + owner_id = None + admin_ids = [] + for member in members: + if member["role"] == "owner": + owner_id = member["user_id"] + if member["role"] == "admin": + admin_ids.append(member["user_id"]) + + group = Group( + group_id=str(group_id), + group_name=info.get("group_name"), + group_avatar="", + group_admins=admin_ids, + group_owner=str(owner_id), + members=[ + MessageMember( + user_id=member["user_id"], + nickname=member.get("nickname") or member.get("card"), + ) + for member in members + ], + ) + + return group diff --git a/astrbot/core/platform/sources/gewechat/gewechat_event.py b/astrbot/core/platform/sources/gewechat/gewechat_event.py index 15f0badd7..26633f622 100644 --- a/astrbot/core/platform/sources/gewechat/gewechat_event.py +++ b/astrbot/core/platform/sources/gewechat/gewechat_event.py @@ -6,7 +6,7 @@ from astrbot.core.utils.io import save_temp_img, download_file from astrbot.core.utils.tencent_record_helper import wav_to_tencent_silk from astrbot.api import logger from astrbot.api.event import AstrMessageEvent, MessageChain -from astrbot.api.platform import AstrBotMessage, PlatformMetadata +from astrbot.api.platform import AstrBotMessage, PlatformMetadata, Group, MessageMember from astrbot.api.message_components import Plain, Image, Record, At, File from .client import SimpleGewechatClient @@ -123,3 +123,30 @@ class GewechatPlatformEvent(AstrMessageEvent): to_wxid = self.message_obj.raw_message.get("to_wxid", None) await GewechatPlatformEvent.send_with_client(message, to_wxid, self.client) await super().send(message) + + async def get_group(self, group_id = None, **kwargs): + # 确定有效的 group_id + if group_id is None: + group_id = self.message_obj.group_id + + if group_id is None: + return None + + res = await self.client.get_group(group_id) + data: dict = res["data"] + + if not data["chatroomId"]: + return None + + members = [ + MessageMember(user_id=member["wxid"], nickname=member["nickName"]) + for member in data.get("memberList", []) + ] + + return Group( + group_id=data["chatroomId"], + group_name=data.get("nickName"), + group_avatar=data.get("smallHeadImgUrl"), + group_owner=data.get("chatRoomOwner"), + members=members, + ) From 2d6d7f31e87e12584d6e0a1370ca569f6adb0e4c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:06:08 +0000 Subject: [PATCH 14/28] :balloon: auto fixes by pre-commit hooks --- astrbot/core/platform/sources/gewechat/gewechat_event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/platform/sources/gewechat/gewechat_event.py b/astrbot/core/platform/sources/gewechat/gewechat_event.py index 26633f622..535922303 100644 --- a/astrbot/core/platform/sources/gewechat/gewechat_event.py +++ b/astrbot/core/platform/sources/gewechat/gewechat_event.py @@ -124,7 +124,7 @@ class GewechatPlatformEvent(AstrMessageEvent): await GewechatPlatformEvent.send_with_client(message, to_wxid, self.client) await super().send(message) - async def get_group(self, group_id = None, **kwargs): + async def get_group(self, group_id=None, **kwargs): # 确定有效的 group_id if group_id is None: group_id = self.message_obj.group_id From 34843eea905c479fd380b5b17493991a9b1e9187 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 20 Mar 2025 18:07:15 +0800 Subject: [PATCH 15/28] =?UTF-8?q?=F0=9F=8E=A8=20style:=20format=20codes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/__init__.py | 1 + astrbot/core/platform/astrbot_message.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/astrbot/core/platform/__init__.py b/astrbot/core/platform/__init__.py index 69a173396..4007b2d90 100644 --- a/astrbot/core/platform/__init__.py +++ b/astrbot/core/platform/__init__.py @@ -10,4 +10,5 @@ __all__ = [ "AstrBotMessage", "MessageMember", "MessageType", + "Group", ] diff --git a/astrbot/core/platform/astrbot_message.py b/astrbot/core/platform/astrbot_message.py index def638e96..e7bd4bd9c 100644 --- a/astrbot/core/platform/astrbot_message.py +++ b/astrbot/core/platform/astrbot_message.py @@ -1,5 +1,5 @@ import time -from typing import List, Dict, Any +from typing import List from dataclasses import dataclass from astrbot.core.message.components import BaseMessageComponent from .message_type import MessageType From b49c11004a65b5c593b2983a6580f4de77cec216 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Thu, 20 Mar 2025 19:57:35 +0800 Subject: [PATCH 16/28] =?UTF-8?q?fix:=E8=BF=98=E5=8E=9F=E5=9B=9E=E5=8E=9F?= =?UTF-8?q?=E6=9D=A5=E7=9A=84=E4=BE=9D=E8=B5=96=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/requirements.txt b/requirements.txt index ac56e3db4..07b168cc1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,33 +1,27 @@ pydantic~=2.10.3 -aiohttp~=3.11.13 -openai~=1.65.5 -anthropic~=0.49.0 +aiohttp +openai +anthropic qq-botpy chardet~=5.1.0 -Pillow~=11.1.0 -beautifulsoup4~=4.13.3 +Pillow +beautifulsoup4 googlesearch-python -readability-lxml~=0.8.1 -quart~=0.20.0 +readability-lxml +quart lxml_html_clean -colorlog~=6.9.0 -aiocqhttp~=1.4.4 -pyjwt~=2.10.1 -apscheduler~=3.11.0 -docstring_parser~=0.16 -aiodocker~=0.24.0 +colorlog +aiocqhttp +pyjwt +apscheduler +docstring_parser +aiodocker silk-python psutil>=5.8.0 lark-oapi -ormsgpack~=1.8.0 -cryptography~=44.0.2 -dashscope~=1.22.2 -python-telegram-bot~=21.11.1 -wechatpy~=1.8.18 -dingtalk-stream -PyYAML~=6.0.2 -pip~=23.2.1 -typing_extensions~=4.12.2 -requests~=2.32.3 -anyio~=4.8.0 -httpx~=0.28.1 \ No newline at end of file +ormsgpack +cryptography +dashscope +python-telegram-bot +wechatpy +dingtalk-stream \ No newline at end of file From 70d9b193acd71b5a2033c6017805dce752c2b348 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 20 Mar 2025 20:18:14 +0800 Subject: [PATCH 17/28] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=A7=81=E8=81=8A=E4=B8=8B=20get=5Fgroup=20=E7=9A=84=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/sources/gewechat/gewechat_event.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/gewechat_event.py b/astrbot/core/platform/sources/gewechat/gewechat_event.py index 535922303..3aca64bab 100644 --- a/astrbot/core/platform/sources/gewechat/gewechat_event.py +++ b/astrbot/core/platform/sources/gewechat/gewechat_event.py @@ -127,9 +127,9 @@ class GewechatPlatformEvent(AstrMessageEvent): async def get_group(self, group_id=None, **kwargs): # 确定有效的 group_id if group_id is None: - group_id = self.message_obj.group_id + group_id = self.get_group_id() - if group_id is None: + if not group_id: return None res = await self.client.get_group(group_id) From 98b841190589e32370f71c6ecb44a68d7ff7c15d Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:53:09 +0800 Subject: [PATCH 18/28] Update compose.yml --- compose.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compose.yml b/compose.yml index 805d30c11..c6a608f8c 100644 --- a/compose.yml +++ b/compose.yml @@ -1,16 +1,21 @@ version: '3.8' +# 当接入 QQ NapCat 时,请使用这个 compose 文件一件部署: https://github.com/NapNeko/NapCat-Docker/blob/main/compose/astrbot.yml + services: astrbot: image: soulter/astrbot:latest container_name: astrbot + restart: always ports: # mappings description: https://github.com/Soulter/AstrBot/issues/497 - "6185:6185" - "6195:6195" # optional, wecom default port - "6199:6199" # optional, aiocqhttp default port - "6196:6196" # optional, qq official webhook default port - "11451:11451" # optional, gewechat default port + environment: + - TZ=Asia/Shanghai volumes: - ./data:/AstrBot/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro + # - /etc/timezone:/etc/timezone:ro + # - /etc/localtime:/etc/localtime:ro From 6390d796ac3b4138191a3d38b6deb9bb789b0cfd Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:05:44 +0800 Subject: [PATCH 19/28] Update compose.yml --- compose.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compose.yml b/compose.yml index c6a608f8c..3db6f1dd1 100644 --- a/compose.yml +++ b/compose.yml @@ -8,11 +8,11 @@ services: container_name: astrbot restart: always ports: # mappings description: https://github.com/Soulter/AstrBot/issues/497 - - "6185:6185" - - "6195:6195" # optional, wecom default port - - "6199:6199" # optional, aiocqhttp default port - - "6196:6196" # optional, qq official webhook default port - - "11451:11451" # optional, gewechat default port + - "6185:6185" # 必选,AstrBot WebUI 端口 + - "6195:6195" # 可选, 企业微信 Webhook 端口 + - "6199:6199" # 可选, QQ 个人号(aiocqhttp) WebSocket 端口 + - "6196:6196" # 可选, QQ 官方接口 Webhook 端口 + - "11451:11451" # 可选, 微信个人号 Webhook 端口 environment: - TZ=Asia/Shanghai volumes: From 6cf032a164684efc2d9da57c2dacb79362f991af Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:06:22 +0800 Subject: [PATCH 20/28] Update compose.yml --- compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index 3db6f1dd1..3bab93fc3 100644 --- a/compose.yml +++ b/compose.yml @@ -10,7 +10,7 @@ services: ports: # mappings description: https://github.com/Soulter/AstrBot/issues/497 - "6185:6185" # 必选,AstrBot WebUI 端口 - "6195:6195" # 可选, 企业微信 Webhook 端口 - - "6199:6199" # 可选, QQ 个人号(aiocqhttp) WebSocket 端口 + - "6199:6199" # 可选, QQ 个人号 WebSocket 端口 - "6196:6196" # 可选, QQ 官方接口 Webhook 端口 - "11451:11451" # 可选, 微信个人号 Webhook 端口 environment: From ad54549b514052ade8542099a90fd0f354100934 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:58:40 +0800 Subject: [PATCH 21/28] Update README.md --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b4d97fbbb..ae5189a4c 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,13 @@ _✨ 易上手的多平台 LLM 聊天机器人及开发框架 ✨_ Soulter%2FAstrBot | Trendshift -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot)](https://github.com/Soulter/AstrBot/releases/latest) -python -Docker pull -Static Badge -[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e) -![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B6%88%E6%81%AF%E4%B8%8A%E8%A1%8C%E9%87%8F&cacheSeconds=60) -[![codecov](https://codecov.io/gh/Soulter/AstrBot/graph/badge.svg?token=FF3P5967B8)](https://codecov.io/gh/Soulter/AstrBot) -[![star](https://gitcode.com/Soulter/AstrBot/star/badge.svg)](https://gitcode.com/Soulter/AstrBot) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot?style=for-the-badge)](https://github.com/Soulter/AstrBot/releases/latest) +python +Docker pull +Static Badge +[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg?style=for-the-badge)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e) +![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B4%BB%E8%B7%83%E9%87%8F&cacheSeconds=60&style=for-the-badge) +[![codecov](https://img.shields.io/codecov/c/github/soulter/astrbot?style=for-the-badge)](https://codecov.io/gh/Soulter/AstrBot) English日本語 | @@ -27,6 +26,8 @@ _✨ 易上手的多平台 LLM 聊天机器人及开发框架 ✨_ AstrBot 是一个松耦合、异步、支持多消息平台部署、具有易用的插件系统和完善的大语言模型(LLM)接入功能的聊天机器人及开发框架。 +[![star](https://gitcode.com/Soulter/AstrBot/star/badge.svg?style=for-the-badge)](https://gitcode.com/Soulter/AstrBot) + ## ✨ 主要功能 1. **大语言模型对话**。支持各种大语言模型,包括 OpenAI API、Google Gemini、Llama、Deepseek、ChatGLM 等,支持接入本地部署的大模型,通过 Ollama、LLMTuner。具有多轮对话、人格情境、多模态能力,支持图片理解、语音转文字(Whisper)。 From 7d71015e8c3f46b5387147eaf10440f25459a29b Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:12:25 +0800 Subject: [PATCH 22/28] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ae5189a4c..d2cedd6e2 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ _✨ 易上手的多平台 LLM 聊天机器人及开发框架 ✨_ Soulter%2FAstrBot | Trendshift -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot?style=for-the-badge)](https://github.com/Soulter/AstrBot/releases/latest) -python -Docker pull -Static Badge -[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg?style=for-the-badge)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e) -![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B4%BB%E8%B7%83%E9%87%8F&cacheSeconds=60&style=for-the-badge) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot?style=for-the-badge&color=76bad9)](https://github.com/Soulter/AstrBot/releases/latest) +python +Docker pull +Static Badge +[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg?style=for-the-badge&color=76bad9)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e) +![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B4%BB%E8%B7%83%E9%87%8F&cacheSeconds=60&style=for-the-badge&color=3b618e) [![codecov](https://img.shields.io/codecov/c/github/soulter/astrbot?style=for-the-badge)](https://codecov.io/gh/Soulter/AstrBot) English | From be79ddc9a30598b0e66cf1158bc14daa086fd1c8 Mon Sep 17 00:00:00 2001 From: Moyuyanli <572490972@qq.com> Date: Fri, 21 Mar 2025 16:24:31 +0800 Subject: [PATCH 23/28] =?UTF-8?q?fix:=E5=8E=BB=E6=8E=89=E8=B7=9Fpost=5Ftex?= =?UTF-8?q?t=E5=8A=9F=E8=83=BD=E7=9B=B8=E5=90=8C=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/platform/sources/gewechat/client.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/astrbot/core/platform/sources/gewechat/client.py b/astrbot/core/platform/sources/gewechat/client.py index edc7afb55..d2f28f09d 100644 --- a/astrbot/core/platform/sources/gewechat/client.py +++ b/astrbot/core/platform/sources/gewechat/client.py @@ -666,16 +666,3 @@ class SimpleGewechatClient: json_blob = await resp.json() logger.debug(f"获取群信息结果: {json_blob}") return json_blob - - async def send_message(self, to_wxid, content): - payload = {"appId": self.appid, "toWxid": to_wxid, "content": content} - - async with aiohttp.ClientSession() as session: - async with session.post( - f"{self.base_url}/message/postText", - headers=self.headers, - json=payload, - ) as resp: - json_blob = await resp.json() - logger.debug(f"获取群信息结果: {json_blob}") - # return json_blob From f242144dcfdb134801541f2e68007c7fbba7dff0 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 21 Mar 2025 19:21:35 +0800 Subject: [PATCH 24/28] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2cedd6e2..d924191f8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ _✨ 易上手的多平台 LLM 聊天机器人及开发框架 ✨_ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot?style=for-the-badge&color=76bad9)](https://github.com/Soulter/AstrBot/releases/latest) python Docker pull -Static Badge +Static Badge [![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg?style=for-the-badge&color=76bad9)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e) ![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B4%BB%E8%B7%83%E9%87%8F&cacheSeconds=60&style=for-the-badge&color=3b618e) [![codecov](https://img.shields.io/codecov/c/github/soulter/astrbot?style=for-the-badge)](https://codecov.io/gh/Soulter/AstrBot) From e4d486fec5364f2f5a91c79e09bad6b0bd084187 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Sat, 22 Mar 2025 00:42:04 +0800 Subject: [PATCH 25/28] =?UTF-8?q?docs:=20=E5=AE=9D=E5=A1=94=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E9=83=A8=E7=BD=B2=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d924191f8..b94123962 100644 --- a/README.md +++ b/README.md @@ -52,15 +52,19 @@ AstrBot 是一个松耦合、异步、支持多消息平台部署、具有易用 需要电脑上安装有 Python(>3.10)。请参阅官方文档 [使用 Windows 一键安装器部署 AstrBot](https://astrbot.app/deploy/astrbot/windows.html) 。 -#### Replit 部署 +#### 宝塔面板部署 -[![Run on Repl.it](https://repl.it/badge/github/Soulter/AstrBot)](https://repl.it/github/Soulter/AstrBot) +请参阅官方文档 [宝塔面板部署](https://astrbot.app/deploy/astrbot/btpanel.html) 。 #### CasaOS 部署 社区贡献的部署方式。 -请参阅官方文档 [通过源码部署 AstrBot](https://astrbot.app/deploy/astrbot/casaos.html) 。 +请参阅官方文档 [CasaOS 部署](https://astrbot.app/deploy/astrbot/casaos.html) 。 + +#### Replit 部署 + +[![Run on Repl.it](https://repl.it/badge/github/Soulter/AstrBot)](https://repl.it/github/Soulter/AstrBot) #### 手动部署 From 69ba75abf4d082cb88e559961d3c0bb7b0116f13 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Sat, 22 Mar 2025 01:26:03 +0800 Subject: [PATCH 26/28] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b94123962..9d9589384 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ AstrBot 是一个松耦合、异步、支持多消息平台部署、具有易用 | Whisper | ✔ | 语音转文本 | 支持 API、本地部署 | | SenseVoice | ✔ | 语音转文本 | 本地部署 | | OpenAI TTS API | ✔ | 文本转语音 | | +| GSVI | ✔ | 文本转语音 | GPT-Sovits-Inference | | Fishaudio | ✔ | 文本转语音 | GPT-Sovits 作者参与的项目 | | Edge-TTS | ✔ | 文本转语音 | Edge 浏览器的免费 TTS | From 30d3062944f953cc4076044081bdc1b704bc9fd4 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 22 Mar 2025 15:44:42 +0800 Subject: [PATCH 27/28] =?UTF-8?q?=F0=9F=8E=88=20perf:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=92=89=E9=92=89=E5=9C=A8=E9=85=8D=E7=BD=AE=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E5=A0=B5=E5=A1=9E=E6=95=B4=E4=B8=AA=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E7=9A=84=E9=97=AE=E9=A2=98=20#885?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a.k.a 帮钉钉擦屁股 --- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py b/astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py index 507b3bb50..b38c7d5c8 100644 --- a/astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +++ b/astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py @@ -196,7 +196,10 @@ class DingtalkPlatformAdapter(Platform): self._event_queue.put_nowait(event) async def run(self): - await self.client_.start() + # await self.client_.start() + loop = asyncio.get_event_loop() + # 钉钉的 SDK 并没有实现真正的异步,start() 里面有堵塞方法。 + await loop.run_in_executor(None, lambda: asyncio.run(self.client_.start())) def get_client(self): return self.client From c29f22c39e6d511f0b66ef2bd8425e672818d627 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Sat, 22 Mar 2025 15:51:35 +0800 Subject: [PATCH 28/28] Update PLUGIN_PUBLISH.yml --- .github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml b/.github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml index e5aaaaf78..7eb5ae15c 100644 --- a/.github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml +++ b/.github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - 欢迎发布插件到插件市场! + 欢迎发布插件到插件市场!请确保您的插件经过**完整的**测试。 - type: textarea attributes: @@ -22,9 +22,10 @@ body: 插件名: 插件作者: 插件简介: - 标签: (可选) - 社交链接: (可选, 将会在插件市场作者名称上作为可点击的链接) - description: 必填。请以列表的字段按顺序将插件名、插件作者、插件简介放在这里。 + 支持的消息平台:(必填,如 QQ、微信、飞书) + 标签:(可选) + 社交链接:(可选, 将会在插件市场作者名称上作为可点击的链接) + description: 必填。请以列表的字段按顺序将插件名、插件作者、插件简介放在这里。如果您不知道支持哪些消息平台,请填写测试过的消息平台。 - type: checkboxes attributes: