feat:优化屎山
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -115,6 +115,19 @@ class AutoReply(PluginBase):
|
||||
logger.error(f"[AutoReply] 初始化失败: {e}")
|
||||
self.config = None
|
||||
|
||||
async def on_disable(self):
|
||||
"""插件禁用时调用,清理后台判断任务"""
|
||||
await super().on_disable()
|
||||
|
||||
if self.pending_tasks:
|
||||
for task in self.pending_tasks.values():
|
||||
task.cancel()
|
||||
await asyncio.gather(*self.pending_tasks.values(), return_exceptions=True)
|
||||
self.pending_tasks.clear()
|
||||
|
||||
self.judging.clear()
|
||||
logger.info("[AutoReply] 已清理后台判断任务")
|
||||
|
||||
def _load_bot_info(self):
|
||||
"""加载机器人信息"""
|
||||
try:
|
||||
@@ -294,6 +307,8 @@ class AutoReply(PluginBase):
|
||||
# 直接调用 AIChat 生成回复(基于最新上下文)
|
||||
await self._trigger_ai_reply(bot, pending.from_wxid)
|
||||
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[AutoReply] 后台判断异常: {e}")
|
||||
import traceback
|
||||
@@ -316,8 +331,7 @@ class AutoReply(PluginBase):
|
||||
return
|
||||
|
||||
# 获取最新的历史记录作为上下文
|
||||
chat_id = self._normalize_chat_id(from_wxid)
|
||||
recent_context = await self._get_recent_context_for_reply(chat_id)
|
||||
recent_context = await self._get_recent_context_for_reply(from_wxid)
|
||||
|
||||
if not recent_context:
|
||||
logger.warning("[AutoReply] 无法获取上下文")
|
||||
@@ -342,10 +356,10 @@ class AutoReply(PluginBase):
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
async def _get_recent_context_for_reply(self, chat_id: str) -> str:
|
||||
async def _get_recent_context_for_reply(self, group_id: str) -> str:
|
||||
"""获取最近的上下文用于生成回复"""
|
||||
try:
|
||||
history = await self._get_history(chat_id)
|
||||
history = await self._get_history(group_id)
|
||||
if not history:
|
||||
return ""
|
||||
|
||||
@@ -353,35 +367,10 @@ class AutoReply(PluginBase):
|
||||
count = self.config.get('context', {}).get('messages_count', 5)
|
||||
recent = history[-count:] if len(history) > count else history
|
||||
|
||||
# 构建上下文摘要
|
||||
context_lines = []
|
||||
for record in recent:
|
||||
nickname = record.get('nickname', '未知')
|
||||
content = record.get('content', '')
|
||||
if isinstance(content, list):
|
||||
# 多模态内容,提取文本
|
||||
for item in content:
|
||||
if item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = '[图片]'
|
||||
if len(content) > 50:
|
||||
content = content[:50] + "..."
|
||||
context_lines.append(f"{nickname}: {content}")
|
||||
|
||||
# 返回最后一条消息作为触发内容(AIChat 会读取完整历史)
|
||||
if recent:
|
||||
last = recent[-1]
|
||||
last_content = last.get('content', '')
|
||||
if isinstance(last_content, list):
|
||||
for item in last_content:
|
||||
if item.get('type') == 'text':
|
||||
return item.get('text', '')
|
||||
return '[图片]'
|
||||
return last_content
|
||||
|
||||
return ""
|
||||
# 自动回复触发不再把最后一条用户消息再次发给 AI,
|
||||
# 避免在上下文里出现“同一句话重复两遍”的错觉。
|
||||
# AIChat 会读取完整历史 recent_history。
|
||||
return "(自动回复触发)请基于最近群聊内容,自然地回复一句,不要复述提示本身。"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[AutoReply] 获取上下文失败: {e}")
|
||||
@@ -389,12 +378,13 @@ class AutoReply(PluginBase):
|
||||
|
||||
async def _judge_with_small_model(self, from_wxid: str, content: str) -> JudgeResult:
|
||||
"""使用小模型判断是否需要回复"""
|
||||
chat_id = self._normalize_chat_id(from_wxid)
|
||||
chat_state = self._get_chat_state(chat_id)
|
||||
group_id = from_wxid
|
||||
state_id = self._normalize_chat_id(group_id)
|
||||
chat_state = self._get_chat_state(state_id)
|
||||
|
||||
# 获取最近消息历史
|
||||
recent_messages = await self._get_recent_messages(chat_id)
|
||||
last_bot_reply = await self._get_last_bot_reply(chat_id)
|
||||
recent_messages = await self._get_recent_messages(group_id)
|
||||
last_bot_reply = await self._get_last_bot_reply(group_id)
|
||||
|
||||
# 构建判断提示词
|
||||
reasoning_part = ',\n "reasoning": "简短分析原因(20字内)"' if self.config["judge"]["include_reasoning"] else ""
|
||||
@@ -403,7 +393,7 @@ class AutoReply(PluginBase):
|
||||
|
||||
## 当前状态
|
||||
- 精力: {chat_state.energy:.1f}/1.0
|
||||
- 上次发言: {self._get_minutes_since_last_reply(chat_id)}分钟前
|
||||
- 上次发言: {self._get_minutes_since_last_reply(state_id)}分钟前
|
||||
|
||||
## 最近对话
|
||||
{recent_messages}
|
||||
@@ -531,6 +521,13 @@ class AutoReply(PluginBase):
|
||||
if not aichat_plugin:
|
||||
return []
|
||||
|
||||
# 优先使用 AIChat 的统一 ContextStore
|
||||
if hasattr(aichat_plugin, "store") and aichat_plugin.store:
|
||||
try:
|
||||
return await aichat_plugin.store.load_group_history(chat_id)
|
||||
except Exception as e:
|
||||
logger.debug(f"[AutoReply] ContextStore 获取历史失败: {e}")
|
||||
|
||||
# 优先使用 Redis(与 AIChat 保持一致)
|
||||
try:
|
||||
from utils.redis_cache import get_cache
|
||||
@@ -548,7 +545,8 @@ class AutoReply(PluginBase):
|
||||
|
||||
# 降级到文件存储
|
||||
if hasattr(aichat_plugin, 'history_dir') and aichat_plugin.history_dir:
|
||||
history_file = aichat_plugin.history_dir / f"{chat_id}.json"
|
||||
safe_id = (chat_id or "").replace("@", "_").replace(":", "_")
|
||||
history_file = aichat_plugin.history_dir / f"{safe_id}.json"
|
||||
if history_file.exists():
|
||||
with open(history_file, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
@@ -558,10 +556,10 @@ class AutoReply(PluginBase):
|
||||
|
||||
return []
|
||||
|
||||
async def _get_recent_messages(self, chat_id: str) -> str:
|
||||
"""获取最近消息历史"""
|
||||
async def _get_recent_messages(self, group_id: str) -> str:
|
||||
"""获取最近消息历史(群聊)"""
|
||||
try:
|
||||
history = await self._get_history(chat_id)
|
||||
history = await self._get_history(group_id)
|
||||
if not history:
|
||||
return "暂无对话历史"
|
||||
|
||||
@@ -572,6 +570,12 @@ class AutoReply(PluginBase):
|
||||
for record in recent:
|
||||
nickname = record.get('nickname', '未知')
|
||||
content = record.get('content', '')
|
||||
if isinstance(content, list):
|
||||
text_parts = []
|
||||
for item in content:
|
||||
if item.get("type") == "text":
|
||||
text_parts.append(item.get("text", ""))
|
||||
content = "".join(text_parts).strip() or "[图片]"
|
||||
# 限制单条消息长度
|
||||
if len(content) > 100:
|
||||
content = content[:100] + "..."
|
||||
@@ -584,17 +588,23 @@ class AutoReply(PluginBase):
|
||||
|
||||
return "暂无对话历史"
|
||||
|
||||
async def _get_last_bot_reply(self, chat_id: str) -> Optional[str]:
|
||||
"""获取上次机器人回复"""
|
||||
async def _get_last_bot_reply(self, group_id: str) -> Optional[str]:
|
||||
"""获取上次机器人回复(群聊)"""
|
||||
try:
|
||||
history = await self._get_history(chat_id)
|
||||
history = await self._get_history(group_id)
|
||||
if not history:
|
||||
return None
|
||||
|
||||
# 从后往前查找机器人回复
|
||||
for record in reversed(history):
|
||||
if record.get('nickname') == self.bot_nickname:
|
||||
if record.get('role') == 'assistant' or record.get('nickname') == self.bot_nickname:
|
||||
content = record.get('content', '')
|
||||
if isinstance(content, list):
|
||||
text_parts = []
|
||||
for item in content:
|
||||
if item.get("type") == "text":
|
||||
text_parts.append(item.get("text", ""))
|
||||
content = "".join(text_parts).strip() or "[图片]"
|
||||
if len(content) > 100:
|
||||
content = content[:100] + "..."
|
||||
return content
|
||||
|
||||
@@ -1606,9 +1606,8 @@ class SignInPlugin(PluginBase):
|
||||
return {"success": True, "message": f"城市注册请求已处理: {city}"}
|
||||
|
||||
else:
|
||||
return {"success": False, "message": "未知的工具名称"}
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"LLM工具执行失败: {e}")
|
||||
return {"success": False, "message": f"执行失败: {str(e)}"}
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ class WeatherPlugin(PluginBase):
|
||||
"""执行LLM工具调用,供AIChat插件调用"""
|
||||
try:
|
||||
if tool_name != "query_weather":
|
||||
return {"success": False, "message": "未知的工具名称"}
|
||||
return None
|
||||
|
||||
# 从 arguments 中获取用户信息
|
||||
user_wxid = arguments.get("user_wxid", from_wxid)
|
||||
|
||||
@@ -345,7 +345,7 @@ class ZImageTurbo(PluginBase):
|
||||
async def execute_llm_tool(self, tool_name: str, arguments: dict, bot: WechatHookClient, from_wxid: str) -> dict:
|
||||
"""执行LLM工具调用,供AIChat插件调用"""
|
||||
if tool_name != "generate_image":
|
||||
return {"success": False, "message": "未知的工具名称"}
|
||||
return None
|
||||
|
||||
try:
|
||||
prompt = arguments.get("prompt", "")
|
||||
|
||||
Reference in New Issue
Block a user