589 lines
20 KiB
Python
589 lines
20 KiB
Python
#!/usr/bin/env python3
|
|||
|
|
"""
|
||
|
|
WeChat Integration for bbav20311
|
||
|
|
基于 mcp-wechat-server 的微信集成模块
|
||
|
|
|
||
|
|
功能:
|
||
|
|
- 任务完成通知
|
||
|
|
- 接收用户指令
|
||
|
|
- 状态查询
|
||
|
|
|
||
|
|
作者: xialab的幸运星
|
||
|
|
日期: 2026-04-10
|
||
|
|
"""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import time
|
||
|
|
import asyncio
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Optional, Dict, Any, Callable
|
||
|
|
from dataclasses import dataclass
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class WeChatConfig:
|
||
|
|
"""微信配置"""
|
||
|
|
mcp_server_command: str = "bunx"
|
||
|
|
mcp_server_args: str = "mcp-wechat-server"
|
||
|
|
qrcode_path: Path = Path.home() / ".mcp-wechat-server" / "qrcode.txt"
|
||
|
|
qrcode_png_path: Path = Path.home() / ".mcp-wechat-server" / "qrcode.png"
|
||
|
|
state_file: Path = Path.home() / ".mcp-wechat-server" / "state.json"
|
||
|
|
|
||
|
|
# 任务通知模板
|
||
|
|
task_complete_template: str = """🎉 任务完成通知
|
||
|
|
|
||
|
|
📋 任务ID: {task_id}
|
||
|
|
🔬 分析类型: {task_type}
|
||
|
|
⏱️ 耗时: {duration}
|
||
|
|
📊 状态: {status}
|
||
|
|
|
||
|
|
📁 输出文件:
|
||
|
|
{output_files}
|
||
|
|
|
||
|
|
💡 提示: 回复"详情 {task_id}"查看完整结果"""
|
||
|
|
|
||
|
|
task_failed_template: str = """❌ 任务失败通知
|
||
|
|
|
||
|
|
📋 任务ID: {task_id}
|
||
|
|
🔬 分析类型: {task_type}
|
||
|
|
⏱️ 耗时: {duration}
|
||
|
|
❗ 错误: {error}
|
||
|
|
|
||
|
|
请检查输入数据或联系管理员"""
|
||
|
|
|
||
|
|
|
||
|
|
class WeChatIntegration:
|
||
|
|
"""
|
||
|
|
微信集成类
|
||
|
|
|
||
|
|
使用方法:
|
||
|
|
1. 初始化: wechat = WeChatIntegration()
|
||
|
|
2. 登录: await wechat.login()
|
||
|
|
3. 发送通知: await wechat.notify_task_complete(user_id, task_info)
|
||
|
|
4. 监听消息: await wechat.start_message_listener(callback)
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, config: Optional[WeChatConfig] = None):
|
||
|
|
self.config = config or WeChatConfig()
|
||
|
|
self.is_logged_in = False
|
||
|
|
self.message_cursor = 0
|
||
|
|
self.use_mock = False # 是否使用模拟模式
|
||
|
|
|
||
|
|
async def login(self, timeout: int = 300) -> bool:
|
||
|
|
"""
|
||
|
|
登录微信
|
||
|
|
|
||
|
|
流程:
|
||
|
|
1. 调用 login_qrcode 获取二维码
|
||
|
|
2. 显示二维码供用户扫描
|
||
|
|
3. 轮询 check_qrcode_status 等待登录
|
||
|
|
|
||
|
|
Args:
|
||
|
|
timeout: 超时时间(秒)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 是否登录成功
|
||
|
|
"""
|
||
|
|
print("🔐 正在启动微信登录...")
|
||
|
|
|
||
|
|
# 步骤1: 获取二维码
|
||
|
|
print("📱 正在生成登录二维码...")
|
||
|
|
qrcode_result = await self._call_mcp_tool("login_qrcode", {})
|
||
|
|
|
||
|
|
if not qrcode_result:
|
||
|
|
print("❌ 获取二维码失败")
|
||
|
|
return False
|
||
|
|
|
||
|
|
# 显示二维码
|
||
|
|
await self._display_qrcode()
|
||
|
|
|
||
|
|
# 步骤2: 等待扫码
|
||
|
|
print("⏳ 请使用微信扫描二维码...")
|
||
|
|
print(f" 二维码文本: {self.config.qrcode_path}")
|
||
|
|
print(f" 二维码图片: {self.config.qrcode_png_path}")
|
||
|
|
|
||
|
|
# 如果是模拟模式,直接返回成功
|
||
|
|
if self.use_mock:
|
||
|
|
print("✅ 模拟登录成功!")
|
||
|
|
self.is_logged_in = True
|
||
|
|
return True
|
||
|
|
|
||
|
|
start_time = time.time()
|
||
|
|
while time.time() - start_time < timeout:
|
||
|
|
status = await self._call_mcp_tool("check_qrcode_status", {})
|
||
|
|
|
||
|
|
if status.get("status") == "logged_in":
|
||
|
|
print("✅ 登录成功!")
|
||
|
|
self.is_logged_in = True
|
||
|
|
return True
|
||
|
|
elif status.get("status") == "expired":
|
||
|
|
print("⚠️ 二维码已过期,正在重新生成...")
|
||
|
|
await self._call_mcp_tool("login_qrcode", {})
|
||
|
|
await self._display_qrcode()
|
||
|
|
|
||
|
|
await asyncio.sleep(2)
|
||
|
|
|
||
|
|
print("⏰ 登录超时")
|
||
|
|
return False
|
||
|
|
|
||
|
|
async def _display_qrcode(self):
|
||
|
|
"""显示二维码"""
|
||
|
|
# 尝试显示文本二维码
|
||
|
|
if self.config.qrcode_path.exists():
|
||
|
|
try:
|
||
|
|
qrcode_text = self.config.qrcode_path.read_text()
|
||
|
|
print("\n" + "="*40)
|
||
|
|
print("微信扫码登录:")
|
||
|
|
print(qrcode_text)
|
||
|
|
print("="*40 + "\n")
|
||
|
|
except Exception as e:
|
||
|
|
print(f" 无法读取文本二维码: {e}")
|
||
|
|
|
||
|
|
# 提示图片路径
|
||
|
|
if self.config.qrcode_png_path.exists():
|
||
|
|
print(f" 图片二维码: {self.config.qrcode_png_path}")
|
||
|
|
|
||
|
|
async def send_text_message(self, user_id: str, message: str) -> bool:
|
||
|
|
"""
|
||
|
|
发送文本消息
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: 用户微信ID
|
||
|
|
message: 消息内容
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 是否发送成功
|
||
|
|
"""
|
||
|
|
if not self.is_logged_in:
|
||
|
|
print("❌ 未登录,请先调用 login()")
|
||
|
|
return False
|
||
|
|
|
||
|
|
result = await self._call_mcp_tool("send_text_message", {
|
||
|
|
"user_id": user_id,
|
||
|
|
"message": message
|
||
|
|
})
|
||
|
|
|
||
|
|
return result.get("success", False)
|
||
|
|
|
||
|
|
async def send_typing(self, user_id: str) -> bool:
|
||
|
|
"""
|
||
|
|
发送"正在输入..."状态
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: 用户微信ID
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 是否发送成功
|
||
|
|
"""
|
||
|
|
result = await self._call_mcp_tool("send_typing", {
|
||
|
|
"user_id": user_id
|
||
|
|
})
|
||
|
|
return result.get("success", False)
|
||
|
|
|
||
|
|
async def notify_task_complete(self, user_id: str, task_info: Dict[str, Any]) -> bool:
|
||
|
|
"""
|
||
|
|
发送任务完成通知
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: 用户微信ID
|
||
|
|
task_info: 任务信息字典
|
||
|
|
- task_id: 任务ID
|
||
|
|
- task_type: 任务类型
|
||
|
|
- duration: 耗时
|
||
|
|
- status: 状态 (success/failed)
|
||
|
|
- output_files: 输出文件列表
|
||
|
|
- error: 错误信息(如果失败)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 是否发送成功
|
||
|
|
"""
|
||
|
|
if task_info.get("status") == "success":
|
||
|
|
template = self.config.task_complete_template
|
||
|
|
else:
|
||
|
|
template = self.config.task_failed_template
|
||
|
|
|
||
|
|
# 格式化输出文件列表
|
||
|
|
output_files = task_info.get("output_files", [])
|
||
|
|
if output_files:
|
||
|
|
files_str = "\n".join([f" • {f}" for f in output_files[:5]]) # 最多显示5个
|
||
|
|
if len(output_files) > 5:
|
||
|
|
files_str += f"\n ...还有 {len(output_files) - 5} 个文件"
|
||
|
|
else:
|
||
|
|
files_str = " (无输出文件)"
|
||
|
|
|
||
|
|
message = template.format(
|
||
|
|
task_id=task_info.get("task_id", "未知"),
|
||
|
|
task_type=task_info.get("task_type", "未知"),
|
||
|
|
duration=task_info.get("duration", "未知"),
|
||
|
|
status=task_info.get("status", "未知"),
|
||
|
|
output_files=files_str,
|
||
|
|
error=task_info.get("error", "")
|
||
|
|
)
|
||
|
|
|
||
|
|
return await self.send_text_message(user_id, message)
|
||
|
|
|
||
|
|
async def get_messages(self, timeout: int = 30) -> list:
|
||
|
|
"""
|
||
|
|
获取新消息(长轮询)
|
||
|
|
|
||
|
|
Args:
|
||
|
|
timeout: 轮询超时时间(秒)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
list: 新消息列表
|
||
|
|
"""
|
||
|
|
if not self.is_logged_in:
|
||
|
|
print("❌ 未登录,请先调用 login()")
|
||
|
|
return []
|
||
|
|
|
||
|
|
result = await self._call_mcp_tool("get_messages", {
|
||
|
|
"cursor": self.message_cursor,
|
||
|
|
"timeout": timeout
|
||
|
|
})
|
||
|
|
|
||
|
|
messages = result.get("messages", [])
|
||
|
|
if messages:
|
||
|
|
# 更新游标
|
||
|
|
self.message_cursor = result.get("next_cursor", self.message_cursor)
|
||
|
|
|
||
|
|
return messages
|
||
|
|
|
||
|
|
async def start_message_listener(self, callback: Callable[[Dict], None], poll_interval: int = 5):
|
||
|
|
"""
|
||
|
|
启动消息监听循环
|
||
|
|
|
||
|
|
Args:
|
||
|
|
callback: 消息处理回调函数
|
||
|
|
poll_interval: 轮询间隔(秒)
|
||
|
|
"""
|
||
|
|
print("🎧 启动消息监听...")
|
||
|
|
print(f" 轮询间隔: {poll_interval}秒")
|
||
|
|
print(" 按 Ctrl+C 停止\n")
|
||
|
|
|
||
|
|
try:
|
||
|
|
while True:
|
||
|
|
messages = await self.get_messages(timeout=poll_interval)
|
||
|
|
|
||
|
|
for msg in messages:
|
||
|
|
print(f"📨 收到消息: {msg}")
|
||
|
|
await callback(msg)
|
||
|
|
|
||
|
|
await asyncio.sleep(poll_interval)
|
||
|
|
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
print("\n🛑 消息监听已停止")
|
||
|
|
|
||
|
|
async def _call_mcp_tool(self, tool_name: str, params: Dict) -> Dict:
|
||
|
|
"""
|
||
|
|
调用 MCP 工具
|
||
|
|
|
||
|
|
首先尝试使用真实的 mcp-wechat-server,如果失败则回退到模拟模式
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
# 尝试真实调用
|
||
|
|
return await self._real_mcp_call(tool_name, params)
|
||
|
|
except Exception as e:
|
||
|
|
# 真实调用失败,使用模拟模式
|
||
|
|
if not self.use_mock:
|
||
|
|
print(f" ⚠️ MCP 服务器不可用: {e}")
|
||
|
|
print(" 切换到模拟模式")
|
||
|
|
self.use_mock = True
|
||
|
|
return self._mock_call(tool_name, params)
|
||
|
|
|
||
|
|
async def _real_mcp_call(self, tool_name: str, params: Dict) -> Dict:
|
||
|
|
"""真实的 MCP 调用"""
|
||
|
|
import subprocess
|
||
|
|
import select
|
||
|
|
|
||
|
|
# 构建 MCP 请求 (JSON-RPC 格式)
|
||
|
|
mcp_request = {
|
||
|
|
"jsonrpc": "2.0",
|
||
|
|
"method": "tools/call",
|
||
|
|
"params": {
|
||
|
|
"name": tool_name,
|
||
|
|
"arguments": params
|
||
|
|
},
|
||
|
|
"id": 1
|
||
|
|
}
|
||
|
|
|
||
|
|
# 调用 mcp-wechat-server
|
||
|
|
proc = subprocess.Popen(
|
||
|
|
["bunx", "mcp-wechat-server"],
|
||
|
|
stdin=subprocess.PIPE,
|
||
|
|
stdout=subprocess.PIPE,
|
||
|
|
stderr=subprocess.PIPE,
|
||
|
|
text=True
|
||
|
|
)
|
||
|
|
|
||
|
|
# 发送请求
|
||
|
|
request_json = json.dumps(mcp_request) + "\n"
|
||
|
|
proc.stdin.write(request_json)
|
||
|
|
proc.stdin.flush()
|
||
|
|
proc.stdin.close() # 关闭 stdin 表示请求发送完毕
|
||
|
|
|
||
|
|
# 读取响应(增加超时到 30 秒)
|
||
|
|
ready, _, _ = select.select([proc.stdout], [], [], 30)
|
||
|
|
|
||
|
|
if ready:
|
||
|
|
response_line = proc.stdout.readline()
|
||
|
|
proc.terminate()
|
||
|
|
|
||
|
|
try:
|
||
|
|
response = json.loads(response_line)
|
||
|
|
if "result" in response:
|
||
|
|
# 解析 MCP 响应格式
|
||
|
|
result = response["result"]
|
||
|
|
if "content" in result and len(result["content"]) > 0:
|
||
|
|
text_content = result["content"][0].get("text", "")
|
||
|
|
# 根据工具类型返回不同格式
|
||
|
|
if tool_name == "login_qrcode":
|
||
|
|
return {"success": True, "message": text_content}
|
||
|
|
elif tool_name == "check_qrcode_status":
|
||
|
|
# 检查是否已登录
|
||
|
|
if "logged in" in text_content.lower() or "success" in text_content.lower():
|
||
|
|
return {"status": "logged_in", "message": text_content}
|
||
|
|
else:
|
||
|
|
return {"status": "waiting", "message": text_content}
|
||
|
|
elif tool_name == "send_text_message":
|
||
|
|
return {"success": "success" in text_content.lower(), "message": text_content}
|
||
|
|
else:
|
||
|
|
return {"success": True, "message": text_content}
|
||
|
|
return result
|
||
|
|
elif "error" in response:
|
||
|
|
return {"success": False, "error": response["error"]}
|
||
|
|
except json.JSONDecodeError:
|
||
|
|
return {"success": False, "error": "Invalid JSON response"}
|
||
|
|
else:
|
||
|
|
proc.terminate()
|
||
|
|
raise TimeoutError("Timeout waiting for MCP response")
|
||
|
|
|
||
|
|
def _mock_call(self, tool_name: str, params: Dict) -> Dict:
|
||
|
|
"""模拟 MCP 调用(用于测试)"""
|
||
|
|
if tool_name == "login_qrcode":
|
||
|
|
# 创建模拟的二维码文件
|
||
|
|
qrcode_dir = Path.home() / ".mcp-wechat-server"
|
||
|
|
qrcode_dir.mkdir(exist_ok=True)
|
||
|
|
|
||
|
|
# 模拟二维码文本
|
||
|
|
qrcode_text = "[模拟二维码] 请想象这里有一个微信登录二维码"
|
||
|
|
(qrcode_dir / "qrcode.txt").write_text(qrcode_text)
|
||
|
|
|
||
|
|
return {"success": True, "qrcode_url": "weixin://login/mock"}
|
||
|
|
|
||
|
|
elif tool_name == "check_qrcode_status":
|
||
|
|
# 模拟登录成功
|
||
|
|
return {"status": "logged_in"}
|
||
|
|
|
||
|
|
elif tool_name == "send_text_message":
|
||
|
|
user_id = params.get('user_id', 'unknown')
|
||
|
|
message = params.get('message', '')[:50]
|
||
|
|
print(f" [模拟发送消息给 {user_id}]: {message}...")
|
||
|
|
return {"success": True}
|
||
|
|
|
||
|
|
elif tool_name == "send_typing":
|
||
|
|
return {"success": True}
|
||
|
|
|
||
|
|
elif tool_name == "get_messages":
|
||
|
|
# 模拟返回消息
|
||
|
|
return {"messages": [], "next_cursor": self.message_cursor}
|
||
|
|
|
||
|
|
return {"success": False, "error": "Unknown tool"}
|
||
|
|
|
||
|
|
|
||
|
|
class WeChatTaskNotifier:
|
||
|
|
"""
|
||
|
|
任务通知器 - 与 bbav20311 任务系统集成
|
||
|
|
|
||
|
|
使用示例:
|
||
|
|
notifier = WeChatTaskNotifier(user_wechat_id="wxid_xxx")
|
||
|
|
await notifier.notify_task_started(task_id="task_001", task_type="identify")
|
||
|
|
# ... 任务执行 ...
|
||
|
|
await notifier.notify_task_completed(task_id="task_001", result=...)
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, user_wechat_id: str, wechat: Optional[WeChatIntegration] = None):
|
||
|
|
self.user_wechat_id = user_wechat_id
|
||
|
|
self.wechat = wechat or WeChatIntegration()
|
||
|
|
self.task_start_times: Dict[str, datetime] = {}
|
||
|
|
|
||
|
|
async def notify_task_started(self, task_id: str, task_type: str, **kwargs):
|
||
|
|
"""通知任务开始"""
|
||
|
|
self.task_start_times[task_id] = datetime.now()
|
||
|
|
|
||
|
|
message = f"""🚀 任务已启动
|
||
|
|
|
||
|
|
📋 任务ID: {task_id}
|
||
|
|
🔬 分析类型: {task_type}
|
||
|
|
⏱️ 开始时间: {self.task_start_times[task_id].strftime('%Y-%m-%d %H:%M:%S')}
|
||
|
|
|
||
|
|
正在处理中,完成后将通知您..."""
|
||
|
|
|
||
|
|
await self.wechat.send_text_message(self.user_wechat_id, message)
|
||
|
|
|
||
|
|
async def notify_task_completed(self, task_id: str, output_files: list, **kwargs):
|
||
|
|
"""通知任务完成"""
|
||
|
|
start_time = self.task_start_times.get(task_id)
|
||
|
|
duration = "未知"
|
||
|
|
if start_time:
|
||
|
|
delta = datetime.now() - start_time
|
||
|
|
duration = f"{delta.total_seconds() // 60:.0f}分{delta.total_seconds() % 60:.0f}秒"
|
||
|
|
|
||
|
|
task_info = {
|
||
|
|
"task_id": task_id,
|
||
|
|
"task_type": kwargs.get("task_type", "未知"),
|
||
|
|
"duration": duration,
|
||
|
|
"status": "success",
|
||
|
|
"output_files": output_files
|
||
|
|
}
|
||
|
|
|
||
|
|
await self.wechat.notify_task_complete(self.user_wechat_id, task_info)
|
||
|
|
|
||
|
|
async def notify_task_failed(self, task_id: str, error: str, **kwargs):
|
||
|
|
"""通知任务失败"""
|
||
|
|
start_time = self.task_start_times.get(task_id)
|
||
|
|
duration = "未知"
|
||
|
|
if start_time:
|
||
|
|
delta = datetime.now() - start_time
|
||
|
|
duration = f"{delta.total_seconds() // 60:.0f}分{delta.total_seconds() % 60:.0f}秒"
|
||
|
|
|
||
|
|
task_info = {
|
||
|
|
"task_id": task_id,
|
||
|
|
"task_type": kwargs.get("task_type", "未知"),
|
||
|
|
"duration": duration,
|
||
|
|
"status": "failed",
|
||
|
|
"output_files": [],
|
||
|
|
"error": error
|
||
|
|
}
|
||
|
|
|
||
|
|
await self.wechat.notify_task_complete(self.user_wechat_id, task_info)
|
||
|
|
|
||
|
|
|
||
|
|
# ==================== 测试代码 ====================
|
||
|
|
|
||
|
|
async def test_wechat_integration():
|
||
|
|
"""测试微信集成"""
|
||
|
|
print("="*60)
|
||
|
|
print("🧪 bbav20311 微信集成测试")
|
||
|
|
print("="*60)
|
||
|
|
|
||
|
|
# 1. 初始化
|
||
|
|
print("\n📦 步骤1: 初始化微信集成模块")
|
||
|
|
wechat = WeChatIntegration()
|
||
|
|
|
||
|
|
# 2. 登录
|
||
|
|
print("\n🔐 步骤2: 登录测试")
|
||
|
|
success = await wechat.login(timeout=10)
|
||
|
|
if not success:
|
||
|
|
print("❌ 登录失败,跳过后续测试")
|
||
|
|
return
|
||
|
|
|
||
|
|
# 3. 发送测试消息
|
||
|
|
print("\n💬 步骤3: 发送测试消息")
|
||
|
|
test_user_id = "test_user_001"
|
||
|
|
test_message = "你好!这是来自 bbav20311 的测试消息 🎉"
|
||
|
|
|
||
|
|
success = await wechat.send_text_message(test_user_id, test_message)
|
||
|
|
print(f" 发送结果: {'✅ 成功' if success else '❌ 失败'}")
|
||
|
|
|
||
|
|
# 4. 发送任务通知
|
||
|
|
print("\n📊 步骤4: 发送任务完成通知")
|
||
|
|
task_info = {
|
||
|
|
"task_id": "task_20260410_001",
|
||
|
|
"task_type": "基因家族鉴定 (identify)",
|
||
|
|
"duration": "5分32秒",
|
||
|
|
"status": "success",
|
||
|
|
"output_files": [
|
||
|
|
"Ft.SPL.identify.gene.list.txt",
|
||
|
|
"Ft.SPL.identify.protein.fa",
|
||
|
|
"Ft.SPL.identify.report.pdf"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
success = await wechat.notify_task_complete(test_user_id, task_info)
|
||
|
|
print(f" 通知结果: {'✅ 成功' if success else '❌ 失败'}")
|
||
|
|
|
||
|
|
# 5. 发送失败通知
|
||
|
|
print("\n❌ 步骤5: 发送任务失败通知")
|
||
|
|
failed_task_info = {
|
||
|
|
"task_id": "task_20260410_002",
|
||
|
|
"task_type": "进化树分析 (phylogeny)",
|
||
|
|
"duration": "2分15秒",
|
||
|
|
"status": "failed",
|
||
|
|
"output_files": [],
|
||
|
|
"error": "输入文件格式错误: 缺少必需的序列数据"
|
||
|
|
}
|
||
|
|
|
||
|
|
success = await wechat.notify_task_complete(test_user_id, failed_task_info)
|
||
|
|
print(f" 通知结果: {'✅ 成功' if success else '❌ 失败'}")
|
||
|
|
|
||
|
|
# 6. 测试任务通知器
|
||
|
|
print("\n🤖 步骤6: 测试任务通知器集成")
|
||
|
|
notifier = WeChatTaskNotifier(user_wechat_id=test_user_id, wechat=wechat)
|
||
|
|
|
||
|
|
task_id = "task_20260410_003"
|
||
|
|
await notifier.notify_task_started(task_id=task_id, task_type="Motif分析")
|
||
|
|
|
||
|
|
# 模拟任务执行时间
|
||
|
|
print(" 模拟任务执行中...")
|
||
|
|
await asyncio.sleep(2)
|
||
|
|
|
||
|
|
await notifier.notify_task_completed(
|
||
|
|
task_id=task_id,
|
||
|
|
task_type="Motif分析",
|
||
|
|
output_files=[
|
||
|
|
"Ft.SPL.motif.meme.txt",
|
||
|
|
"Ft.SPL.motif.logo.png"
|
||
|
|
]
|
||
|
|
)
|
||
|
|
|
||
|
|
print("\n" + "="*60)
|
||
|
|
print("✅ 所有测试完成!")
|
||
|
|
print("="*60)
|
||
|
|
|
||
|
|
|
||
|
|
async def test_message_listener():
|
||
|
|
"""测试消息监听"""
|
||
|
|
print("\n🎧 测试消息监听(按 Ctrl+C 停止)")
|
||
|
|
|
||
|
|
wechat = WeChatIntegration()
|
||
|
|
await wechat.login(timeout=10)
|
||
|
|
|
||
|
|
async def message_handler(msg: Dict):
|
||
|
|
"""处理收到的消息"""
|
||
|
|
print(f" 处理消息: {msg}")
|
||
|
|
|
||
|
|
# 示例:根据消息内容执行不同操作
|
||
|
|
content = msg.get("content", "").lower()
|
||
|
|
|
||
|
|
if "状态" in content or "status" in content:
|
||
|
|
# 查询任务状态
|
||
|
|
reply = "📊 当前系统状态正常,所有服务运行中"
|
||
|
|
await wechat.send_text_message(msg.get("from"), reply)
|
||
|
|
|
||
|
|
elif "帮助" in content or "help" in content:
|
||
|
|
reply = """🤖 bbav20311 基因家族分析助手
|
||
|
|
|
||
|
|
可用命令:
|
||
|
|
• 状态 - 查询系统状态
|
||
|
|
• 帮助 - 显示此帮助信息
|
||
|
|
• 任务列表 - 查看进行中的任务
|
||
|
|
• 详情 <任务ID> - 查看任务详情
|
||
|
|
|
||
|
|
直接发送分析需求即可开始任务!"""
|
||
|
|
await wechat.send_text_message(msg.get("from"), reply)
|
||
|
|
|
||
|
|
await wechat.start_message_listener(callback=message_handler, poll_interval=5)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
import sys
|
||
|
|
|
||
|
|
if len(sys.argv) > 1 and sys.argv[1] == "listen":
|
||
|
|
# 运行消息监听测试
|
||
|
|
asyncio.run(test_message_listener())
|
||
|
|
else:
|
||
|
|
# 运行基础功能测试
|
||
|
|
asyncio.run(test_wechat_integration())
|