From 7f94bce360d9d3e517fec354f9e94c5b261abff0 Mon Sep 17 00:00:00 2001 From: Weilong Liao <37870767+Soulter@users.noreply.github.com> Date: Wed, 27 May 2026 21:59:47 +0800 Subject: [PATCH] feat(qqofficial): split message chain by media and update sending logic (#8376) * feat(qqofficial): split message chain by media and update sending logic * Delete tests/test_qqofficial_adapter.py --- .../qqofficial/qqofficial_message_event.py | 62 +++++++++++++++++-- .../qqofficial/qqofficial_platform_adapter.py | 8 +++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py b/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py index fa10d2876..313b00e68 100644 --- a/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +++ b/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py @@ -183,10 +183,62 @@ class QQOfficialMessageEvent(AstrMessageEvent): ret_id = getattr(ret, "id", None) return str(ret_id) if ret_id is not None else None + @staticmethod + def _split_message_chain_by_media(message: MessageChain) -> list[MessageChain]: + chunks: list[MessageChain] = [] + current_chain = [] + current_has_media = False + + for component in message.chain: + is_media = isinstance(component, Image | Record | Video | File) + if is_media and current_has_media: + chunks.append( + MessageChain( + chain=current_chain, + use_t2i_=message.use_t2i_, + type=message.type, + ) + ) + current_chain = [] + current_has_media = False + + current_chain.append(component) + current_has_media = current_has_media or is_media + + if current_chain or not message.chain: + chunks.append( + MessageChain( + chain=current_chain, + use_t2i_=message.use_t2i_, + type=message.type, + ) + ) + + return chunks + async def _post_send(self, stream: dict | None = None): if not self.send_buffer: return None + message_chains = self._split_message_chain_by_media(self.send_buffer) + stream_for_chain = stream if len(message_chains) == 1 else None + + ret = None + for message_chain in message_chains: + ret = await self._post_send_one(message_chain, stream_for_chain) + + self.send_buffer = None + + return ret + + async def _post_send_one( + self, + message_to_send: MessageChain, + stream: dict | None = None, + ): + if not message_to_send: + return None + source = self.message_obj.raw_message if not isinstance( @@ -207,10 +259,12 @@ class QQOfficialMessageEvent(AstrMessageEvent): video_file_source, file_source, file_name, - ) = await QQOfficialMessageEvent._parse_to_qqofficial(self.send_buffer) + ) = await QQOfficialMessageEvent._parse_to_qqofficial(message_to_send) # C2C 流式仅用于文本分片,富媒体时降级为普通发送,避免平台侧流式校验报错。 - if stream and (image_base64 or record_file_path): + if stream and ( + image_base64 or record_file_path or video_file_source or file_source + ): logger.debug("[QQOfficial] 检测到富媒体,降级为非流式发送。") stream = None @@ -416,9 +470,7 @@ class QQOfficialMessageEvent(AstrMessageEvent): case _: pass - await super().send(self.send_buffer) - - self.send_buffer = None + await super().send(message_to_send) return ret diff --git a/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py b/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py index 27880e548..c693c546e 100644 --- a/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +++ b/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py @@ -203,6 +203,14 @@ class QQOfficialPlatformAdapter(Platform): session: MessageSesion, message_chain: MessageChain, ) -> None: + message_chains = QQOfficialMessageEvent._split_message_chain_by_media( + message_chain + ) + if len(message_chains) > 1: + for split_message_chain in message_chains: + await self._send_by_session_common(session, split_message_chain) + return + ( plain_text, image_base64,