diff --git a/main.py b/main.py index d9a1249..2552663 100644 --- a/main.py +++ b/main.py @@ -459,6 +459,7 @@ class GroupDailyAnalysis(Star): 分析群聊日常活动(跨平台支持) 用法: /群分析 [天数] """ + event.should_call_llm(True) # 阻止默认 LLM 解析 group_id = self._get_group_id_from_event(event) platform_id = self._get_platform_id_from_event(event) @@ -499,7 +500,11 @@ class GroupDailyAnalysis(Star): ) TraceContext.set(trace_id) - yield event.plain_result("🔍 正在启动跨平台分析引擎,正在拉取最近消息...") + # 使用表情回应代替文本回复 + adapter = self.bot_manager.get_adapter(platform_id) + orig_msg_id = getattr(event.message_obj, "message_id", None) + if adapter and orig_msg_id: + await adapter.set_reaction(event.get_group_id(), orig_msg_id, "🔍") # 🔍 try: # 调用 DDD 应用级服务 @@ -515,9 +520,8 @@ class GroupDailyAnalysis(Star): yield event.plain_result("❌ 分析失败,原因未知") return - yield event.plain_result( - f"📊 已获取{result['messages_count']}条消息,正在生成渲染报告..." - ) + if adapter and orig_msg_id: + await adapter.set_reaction(event.get_group_id(), orig_msg_id, "📊") # 📊 async for res in self._send_analysis_report(event, result): yield res diff --git a/src/infrastructure/platform/adapters/discord_adapter.py b/src/infrastructure/platform/adapters/discord_adapter.py index b20388a..039d5c0 100644 --- a/src/infrastructure/platform/adapters/discord_adapter.py +++ b/src/infrastructure/platform/adapters/discord_adapter.py @@ -749,3 +749,39 @@ class DiscordAdapter(PlatformAdapter): ) -> dict[str, str | None]: """批量获取头像的最佳实践。""" return {uid: await self.get_user_avatar_url(uid, size) for uid in user_ids} + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + Discord 实现消息回应。 + """ + if not discord: + return False + + try: + # 映射常见的表情 ID 为文字表情,使分析状态在跨平台保持一致 + mapping = {289: "🔍", 424: "📊", 124: "✅"} + emoji_to_use = emoji + if isinstance(emoji, int) or (isinstance(emoji, str) and emoji.isdigit()): + emoji_to_use = mapping.get(int(emoji), emoji) + + channel_id = int(group_id) + channel = self._discord_client.get_channel(channel_id) + if not channel: + channel = await self._discord_client.fetch_channel(channel_id) + + if not hasattr(channel, "get_partial_message"): + # 如果较低版本的 SDK 没这个方法,则直接 fetch + msg = await channel.fetch_message(int(message_id)) + else: + msg = channel.get_partial_message(int(message_id)) + + if is_add: + await msg.add_reaction(emoji_to_use) + else: + await msg.remove_reaction(emoji_to_use, self._discord_client.user) + return True + except Exception as e: + logger.debug(f"Discord set_reaction 失败: {e}") + return False diff --git a/src/infrastructure/platform/adapters/onebot_adapter.py b/src/infrastructure/platform/adapters/onebot_adapter.py index 0f61a7d..f010b59 100644 --- a/src/infrastructure/platform/adapters/onebot_adapter.py +++ b/src/infrastructure/platform/adapters/onebot_adapter.py @@ -1346,3 +1346,30 @@ class OneBotAdapter(PlatformAdapter): logger.info(f"[群分析相册] 未能找到名为 '{album_name}' 的相册 (群 {group_id})") return None + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + OneBot 实现消息回应 (set_msg_emoji_like)。 + 支持 Go-CQHTTP, NapCat, Lagrange 等 OneBot 实现。 + """ + try: + # 语义化映射:根据用户喜好精细化 OneBot 端的降级 + emoji_id = str(emoji) + if str(emoji) == "🔍": + emoji_id = "289" # 🫣 表情 (表示任务已接收) + elif str(emoji) == "📊": + emoji_id = "124" # 👌 表情 (表示任务处理完成) + + await self.bot.call_action( + "set_msg_emoji_like", + message_id=int(message_id), + emoji_id=emoji_id, + emoji_type="1", # 还原为最稳定的系统表情类型 + set=is_add, + ) + return True + except Exception as e: + logger.debug(f"OneBot set_reaction 失败 (API 可能不支持): {e}") + return False diff --git a/src/infrastructure/platform/adapters/telegram_adapter.py b/src/infrastructure/platform/adapters/telegram_adapter.py index 4e8e39c..13a00e6 100644 --- a/src/infrastructure/platform/adapters/telegram_adapter.py +++ b/src/infrastructure/platform/adapters/telegram_adapter.py @@ -890,6 +890,50 @@ class TelegramAdapter(PlatformAdapter): pairs = await asyncio.gather(*(_fetch_avatar(uid) for uid in user_ids)) return dict(pairs) + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + Telegram 实现消息回应。 + """ + client = self._telegram_client + if not client: + return False + + try: + # 映射常见的表情 ID 为文字表情 + mapping = {289: "🔍", 424: "📊", 124: "✅"} + emoji_to_use = emoji + if isinstance(emoji, int) or (isinstance(emoji, str) and emoji.isdigit()): + emoji_to_use = mapping.get(int(emoji), emoji) + + chat_id, _ = self._parse_group_id(group_id) + + # 只有开启了库支持且版本符合时才尝试。set_message_reaction 是 Bot API 7.0 (PTB 20.8+) 特性。 + if hasattr(client, "set_message_reaction"): + try: + from telegram import ReactionTypeEmoji + + reaction = [ReactionTypeEmoji(emoji=emoji_to_use)] if is_add else [] + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=reaction, + ) + return True + except ImportError: + # 如果版本太低没有 ReactionTypeEmoji,尝试直接传字符串 (有些实现支持) + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=emoji_to_use if is_add else None, + ) + return True + return False + except Exception as e: + logger.debug(f"[Telegram] set_reaction 失败: {e}") + return False + # ==================== 辅助方法 ==================== def _parse_group_id(self, group_id: str) -> tuple[str, str | None]: diff --git a/src/infrastructure/platform/base.py b/src/infrastructure/platform/base.py index e8d5685..4def32f 100644 --- a/src/infrastructure/platform/base.py +++ b/src/infrastructure/platform/base.py @@ -89,3 +89,20 @@ class PlatformAdapter( list[dict]: 转换后的平台原生消息字典列表 """ raise NotImplementedError + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + 对消息添加/移除表情回应。 + + Args: + group_id (str): 群组/频道 ID + message_id (str): 消息 ID + emoji (str | int): 表情代码或字符 + is_add (bool): True 为添加,False 为移除 + + Returns: + bool: 平台是否支持并成功执行 + """ + return False