Files
nanocode/weixin-nanobot-bridge/src/nanobot_adapter.py
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

183 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Nanobot 调用适配器
负责将微信消息转换为 nanobot 调用
"""
import os
import subprocess
import tempfile
import logging
from typing import List, Dict
logger = logging.getLogger(__name__)
class NanobotAdapter:
"""nanobot 适配器"""
def __init__(self, config: Dict):
self.config = config
self.command = config.get('command', 'nanobot')
self.timeout = config.get('timeout', 60)
def chat(self, message: str, history: List[Dict], conversation_id: str) -> str:
"""
调用 nanobot 处理消息
Args:
message: 当前消息
history: 历史消息
conversation_id: 会话ID
Returns:
nanobot 的回复
"""
# 构建上下文提示
context = self._build_context(history, conversation_id)
# 构建完整提示
prompt = self._build_prompt(context, message)
logger.info(f"调用 nanobot,prompt长度: {len(prompt)}")
try:
# 调用 nanobot
result = self._call_nanobot(prompt)
return result
except Exception as e:
logger.error(f"调用 nanobot 失败: {e}")
return f"处理消息时出错: {str(e)}"
def _build_context(self, history: List[Dict], conversation_id: str) -> str:
"""构建上下文"""
if not history:
return ""
lines = ["历史对话:"]
for msg in history[-5:]: # 最近5条
role = "用户" if msg['role'] == 'user' else "助手"
content = msg['content'][:100] # 截断过长内容
lines.append(f"{role}: {content}")
return "\n".join(lines)
def _build_prompt(self, context: str, message: str) -> str:
"""构建提示"""
lines = [
"你是一个 AI 助手,正在通过微信公众号为用户提供服务。",
"",
"规则:",
"1. 保持回答简洁明了,适合微信聊天场景",
"2. 如果需要执行复杂操作,先告知用户",
"3. 不要执行危险命令(删除文件、格式化等)",
"4. 回复长度控制在 4000 字符以内",
"",
]
if context:
lines.extend([context, ""])
lines.extend([
"用户消息:",
message,
"",
"请回复:"
])
return "\n".join(lines)
def _call_nanobot(self, prompt: str) -> str:
"""
调用 nanobot agent 命令
使用: nanobot agent -m "message" --session "id"
"""
try:
# 构建命令
cmd = [
self.command,
"agent",
"-m", prompt,
"--session", f"wechat:{hash(prompt) % 10000}",
"--no-markdown",
"--no-logs"
]
logger.info(f"执行命令: {' '.join(cmd[:5])}...")
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=self.timeout
)
if result.returncode == 0:
return result.stdout.strip() or "处理完成"
else:
error_msg = result.stderr.strip() if result.stderr else "未知错误"
return f"调用失败: {error_msg}"
except subprocess.TimeoutExpired:
return "处理超时,请稍后再试"
except Exception as e:
logger.error(f"调用异常: {e}")
return f"系统错误: {str(e)}"
def _parse_output(self, output: str) -> str:
"""解析 nanobot 输出"""
lines = output.strip().split('\n')
# 过滤掉日志和系统信息
filtered = []
for line in lines:
# 跳过日志行
if any(x in line for x in ['DEBUG', 'INFO', 'WARNING', 'ERROR']):
continue
# 跳过工具调用提示
if line.startswith('>'):
continue
filtered.append(line)
return '\n'.join(filtered).strip() or "处理完成,无返回内容"
class SimpleNanobotAdapter:
"""
简化版适配器(用于测试)
不依赖 nanobot 命令,直接返回模拟响应
"""
def __init__(self, config: Dict):
self.config = config
self.response_templates = [
"收到你的消息: {message}",
"我理解你在问: {message}\n这是一个很有趣的问题!",
"正在为你处理: {message}\n请稍候...",
]
def chat(self, message: str, history: List[Dict], conversation_id: str) -> str:
"""模拟回复"""
import random
template = random.choice(self.response_templates)
return template.format(message=message[:50])
# 兼容不同环境的适配器选择
try:
# 检查 nanobot 是否可用
result = subprocess.run(
['nanobot', '--version'],
capture_output=True,
timeout=5
)
NANOBOT_AVAILABLE = result.returncode == 0
except:
NANOBOT_AVAILABLE = False
if not NANOBOT_AVAILABLE:
logger.warning("nanobot 命令不可用,将使用模拟适配器")
NanobotAdapter = SimpleNanobotAdapter