From 98427345cf7bf268520e28908fb1ec0bb7d9bad0 Mon Sep 17 00:00:00 2001 From: kkjz <253839323@sohu.com> Date: Sun, 20 Apr 2025 12:04:02 +0800 Subject: [PATCH 1/4] =?UTF-8?q?bug:=20=E4=BF=AE=E5=A4=8Daiocqhttp=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E4=BD=BF=E7=94=A8=E6=8C=87=E4=BB=A4=E7=BB=84=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=A6=82=E6=9E=9C=E4=BD=BF=E7=94=A8=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E4=B8=AD=E6=90=BA=E5=B8=A6=E7=BD=91=E5=9D=80=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiocqhttp/aiocqhttp_platform_adapter.py | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py index 198946b1a..b06f537d4 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py @@ -3,6 +3,7 @@ import time import asyncio import logging import uuid +import re from typing import Awaitable, Any from aiocqhttp import CQHttp, Event from astrbot.api.platform import ( @@ -159,6 +160,14 @@ class AiocqhttpAdapter(Platform): return abm + def _is_url_or_ip(self,text: str) -> bool: + """ + 判断一个字符串是否为网址(http/https 开头)或 IP 地址。 + """ + url_pattern = r"^(?:http|https)://.+$" + ip_pattern = r"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" + return bool(re.match(url_pattern, text) or re.match(ip_pattern, text)) + async def _convert_handle_message_event( self, event: Event, get_reply=True ) -> AstrBotMessage: @@ -202,13 +211,30 @@ class AiocqhttpAdapter(Platform): return # 按消息段类型类型适配 - for m in event.message: + for idx, m in enumerate(event.message): t = m["type"] a = None if t == "text": - message_str += m["data"]["text"].strip() - a = ComponentTypes[t](**m["data"]) # noqa: F405 - abm.message.append(a) + should_append_new = True # 是否需要正常处理的标签 + # 合并相邻文本段的情况 + if idx > 0 and event.message[idx - 1]["type"] == "text": + prev_text = event.message[idx - 1]["data"]["text"] + curr_text = m["data"]["text"].strip() + + # 处理网址或IP地址的特殊情况,处理两端文本中间为url时的情况 + if (prev_text.endswith(" ") and self._is_url_or_ip(curr_text)) or \ + (idx > 1 and m["data"]["text"].startswith(" ") and self._is_url_or_ip(prev_text.strip())): + # 合并到前一个文本段 + message_str += " " + curr_text + event.message[idx - 1]["data"]["text"] = message_str + a = ComponentTypes[t](**event.message[idx - 1]["data"]) + abm.message[-1] = a + should_append_new = False + # 如果不需要合并,添加为新的消息段 + if should_append_new: + message_str += m["data"]["text"].strip() + a = ComponentTypes[t](**m["data"]) + abm.message.append(a) elif t == "file": if m["data"].get("url") and m["data"].get("url").startswith("http"): From d3bd775a79c18cd8d834d67b3859e295047d248d Mon Sep 17 00:00:00 2001 From: kkjz <253839323@sohu.com> Date: Sun, 20 Apr 2025 18:09:04 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8groupby=E6=9D=A5?= =?UTF-8?q?=E5=90=88=E5=B9=B6aiocqhttp=E8=BF=9E=E7=BB=AD=E7=9A=84=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiocqhttp/aiocqhttp_platform_adapter.py | 156 ++++++++---------- 1 file changed, 68 insertions(+), 88 deletions(-) diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py index b06f537d4..b7beff156 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py @@ -3,7 +3,7 @@ import time import asyncio import logging import uuid -import re +import itertools from typing import Awaitable, Any from aiocqhttp import CQHttp, Event from astrbot.api.platform import ( @@ -160,14 +160,6 @@ class AiocqhttpAdapter(Platform): return abm - def _is_url_or_ip(self,text: str) -> bool: - """ - 判断一个字符串是否为网址(http/https 开头)或 IP 地址。 - """ - url_pattern = r"^(?:http|https)://.+$" - ip_pattern = r"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" - return bool(re.match(url_pattern, text) or re.match(ip_pattern, text)) - async def _convert_handle_message_event( self, event: Event, get_reply=True ) -> AstrBotMessage: @@ -211,99 +203,87 @@ class AiocqhttpAdapter(Platform): return # 按消息段类型类型适配 - for idx, m in enumerate(event.message): - t = m["type"] + for t, m_group in itertools.groupby(event.message, key=lambda x: x["type"]): a = None if t == "text": - should_append_new = True # 是否需要正常处理的标签 # 合并相邻文本段的情况 - if idx > 0 and event.message[idx - 1]["type"] == "text": - prev_text = event.message[idx - 1]["data"]["text"] - curr_text = m["data"]["text"].strip() - - # 处理网址或IP地址的特殊情况,处理两端文本中间为url时的情况 - if (prev_text.endswith(" ") and self._is_url_or_ip(curr_text)) or \ - (idx > 1 and m["data"]["text"].startswith(" ") and self._is_url_or_ip(prev_text.strip())): - # 合并到前一个文本段 - message_str += " " + curr_text - event.message[idx - 1]["data"]["text"] = message_str - a = ComponentTypes[t](**event.message[idx - 1]["data"]) - abm.message[-1] = a - should_append_new = False - # 如果不需要合并,添加为新的消息段 - if should_append_new: - message_str += m["data"]["text"].strip() - a = ComponentTypes[t](**m["data"]) - abm.message.append(a) + for m in m_group: + message_str += m["data"]["text"] + message_str = message_str.strip() + a = ComponentTypes[t](**m["data"]) + abm.message.append(a) elif t == "file": - if m["data"].get("url") and m["data"].get("url").startswith("http"): - # Lagrange - logger.info("guessing lagrange") + for m in m_group: + if m["data"].get("url") and m["data"].get("url").startswith("http"): + # Lagrange + logger.info("guessing lagrange") - file_name = m["data"].get("file_name", "file") - path = os.path.join("data/temp", file_name) - await download_file(m["data"]["url"], path) + file_name = m["data"].get("file_name", "file") + path = os.path.join("data/temp", file_name) + await download_file(m["data"]["url"], path) - m["data"] = {"file": path, "name": file_name} - a = ComponentTypes[t](**m["data"]) # noqa: F405 - abm.message.append(a) - - else: - try: - # Napcat, LLBot - ret = await self.bot.call_action( - action="get_file", - file_id=event.message[0]["data"]["file_id"], - ) - if not ret.get("file", None): - raise ValueError(f"无法解析文件响应: {ret}") - if not os.path.exists(ret["file"]): - raise FileNotFoundError( - f"文件不存在或者权限问题: {ret['file']}。如果您使用 Docker 部署了 AstrBot 或者消息协议端(Napcat等),请先映射路径。如果路径在 /root 目录下,请用 sudo 打开 AstrBot" - ) - - m["data"] = {"file": ret["file"], "name": ret["file_name"]} + m["data"] = {"file": path, "name": file_name} a = ComponentTypes[t](**m["data"]) # noqa: F405 abm.message.append(a) - except ActionFailed as e: - logger.error(f"获取文件失败: {e},此消息段将被忽略。") - except BaseException as e: - logger.error(f"获取文件失败: {e},此消息段将被忽略。") + + else: + try: + # Napcat, LLBot + ret = await self.bot.call_action( + action="get_file", + file_id=event.message[0]["data"]["file_id"], + ) + if not ret.get("file", None): + raise ValueError(f"无法解析文件响应: {ret}") + if not os.path.exists(ret["file"]): + raise FileNotFoundError( + f"文件不存在或者权限问题: {ret['file']}。如果您使用 Docker 部署了 AstrBot 或者消息协议端(Napcat等),请先映射路径。如果路径在 /root 目录下,请用 sudo 打开 AstrBot" + ) + + m["data"] = {"file": ret["file"], "name": ret["file_name"]} + a = ComponentTypes[t](**m["data"]) # noqa: F405 + abm.message.append(a) + except ActionFailed as e: + logger.error(f"获取文件失败: {e},此消息段将被忽略。") + except BaseException as e: + logger.error(f"获取文件失败: {e},此消息段将被忽略。") elif t == "reply": - if not get_reply: - a = ComponentTypes[t](**m["data"]) # noqa: F405 - abm.message.append(a) - else: - try: - reply_event_data = await self.bot.call_action( - action="get_msg", - message_id=int(m["data"]["id"]), - ) - abm_reply = await self._convert_handle_message_event( - Event.from_payload(reply_event_data), get_reply=False - ) - - reply_seg = Reply( - id=abm_reply.message_id, - chain=abm_reply.message, - sender_id=abm_reply.sender.user_id, - sender_nickname=abm_reply.sender.nickname, - time=abm_reply.timestamp, - message_str=abm_reply.message_str, - text=abm_reply.message_str, # for compatibility - qq=abm_reply.sender.user_id, # for compatibility - ) - - abm.message.append(reply_seg) - except BaseException as e: - logger.error(f"获取引用消息失败: {e}。") + for m in m_group: + if not get_reply: a = ComponentTypes[t](**m["data"]) # noqa: F405 abm.message.append(a) + else: + try: + reply_event_data = await self.bot.call_action( + action="get_msg", + message_id=int(m["data"]["id"]), + ) + abm_reply = await self._convert_handle_message_event( + Event.from_payload(reply_event_data), get_reply=False + ) + + reply_seg = Reply( + id=abm_reply.message_id, + chain=abm_reply.message, + sender_id=abm_reply.sender.user_id, + sender_nickname=abm_reply.sender.nickname, + time=abm_reply.timestamp, + message_str=abm_reply.message_str, + text=abm_reply.message_str, # for compatibility + qq=abm_reply.sender.user_id, # for compatibility + ) + + abm.message.append(reply_seg) + except BaseException as e: + logger.error(f"获取引用消息失败: {e}。") + a = ComponentTypes[t](**m["data"]) # noqa: F405 + abm.message.append(a) else: - a = ComponentTypes[t](**m["data"]) # noqa: F405 - abm.message.append(a) + for m in m_group: + a = ComponentTypes[t](**m["data"]) # noqa: F405 + abm.message.append(a) abm.timestamp = int(time.time()) abm.message_str = message_str From 0ae61d586594849371137344972a09cb0ecd1031 Mon Sep 17 00:00:00 2001 From: kkjz <253839323@sohu.com> Date: Sun, 20 Apr 2025 22:11:24 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=9F=E6=88=90?= =?UTF-8?q?text=E7=9A=84Plain=E6=97=B6=E6=96=87=E6=9C=AC=E4=B8=BA=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=90=8E=E7=9A=84=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py index b7beff156..5eb1c09d1 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py @@ -210,7 +210,7 @@ class AiocqhttpAdapter(Platform): for m in m_group: message_str += m["data"]["text"] message_str = message_str.strip() - a = ComponentTypes[t](**m["data"]) + a = ComponentTypes[t](text = message_str) # noqa: F405 abm.message.append(a) elif t == "file": From 0e1eb3daf69bb240c1b2ebd2f87cbe7a13a21a02 Mon Sep 17 00:00:00 2001 From: kkjz <253839323@sohu.com> Date: Mon, 21 Apr 2025 20:56:18 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8join=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E4=BC=98=E5=8C=96=E7=9B=B8=E9=82=BB=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=AE=B5=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sources/aiocqhttp/aiocqhttp_platform_adapter.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py index 5eb1c09d1..0dd7912e2 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py @@ -206,11 +206,9 @@ class AiocqhttpAdapter(Platform): for t, m_group in itertools.groupby(event.message, key=lambda x: x["type"]): a = None if t == "text": - # 合并相邻文本段的情况 - for m in m_group: - message_str += m["data"]["text"] - message_str = message_str.strip() - a = ComponentTypes[t](text = message_str) # noqa: F405 + # 合并相邻文本段 + message_str = "".join(m["data"]["text"] for m in m_group).strip() + a = ComponentTypes[t](text=message_str) # noqa: F405 abm.message.append(a) elif t == "file":