Files

433 lines
14 KiB
Python
Raw Permalink Normal View History

2026-08-03 18:42:47 +08:00
#!/usr/bin/env python3
"""
WeChat Task Bridge - 微信与 bbav20311 任务系统的桥接
功能:
1. 用户从微信发送分析请求
2. 自动创建并执行任务
3. 任务完成后微信通知用户
使用:
python wechat_task_bridge.py
作者: xialab的幸运星
日期: 2026-04-10
"""
import asyncio
import json
import re
import sys
from pathlib import Path
from typing import Dict, Optional
from datetime import datetime
# 添加项目路径
PROJECT_ROOT = Path(__file__).parent
sys.path.insert(0, str(PROJECT_ROOT))
from wechat_integration import WeChatIntegration, WeChatTaskNotifier
# 导入 bbav20311 的任务模块
try:
from apps.web.pipeline_backend import new_job, run_stage
from gfa_core.agents.router import route, is_analysis_task
BACKEND_AVAILABLE = True
except ImportError as e:
print(f"⚠️ 无法导入后端模块: {e}")
print(" 将以模拟模式运行")
BACKEND_AVAILABLE = False
class WeChatTaskBridge:
"""
微信任务桥接器
将微信消息转换为 bbav20311 分析任务
"""
def __init__(self):
self.wechat = WeChatIntegration()
self.active_tasks: Dict[str, dict] = {} # 存储活跃任务
self.user_sessions: Dict[str, dict] = {} # 用户会话状态
async def start(self):
"""启动桥接服务"""
print("🚀 启动 WeChat Task Bridge")
print("="*60)
# 1. 登录微信
print("\n🔐 正在登录微信...")
success = await self.wechat.login(timeout=300)
if not success:
print("❌ 微信登录失败,服务无法启动")
return
print("✅ 微信登录成功")
# 2. 启动消息监听
print("\n🎧 启动消息监听...")
print(" 用户现在可以通过微信发送分析请求")
print(" 按 Ctrl+C 停止服务\n")
await self.wechat.start_message_listener(
callback=self._handle_message,
poll_interval=5
)
async def _handle_message(self, msg: dict):
"""处理收到的微信消息"""
user_id = msg.get("from")
content = msg.get("content", "").strip()
print(f"\n📨 收到消息 [{user_id}]: {content}")
# 显示正在输入状态
await self.wechat.send_typing(user_id)
# 解析命令
response = await self._parse_command(user_id, content)
# 发送回复
if response:
await self.wechat.send_text_message(user_id, response)
async def _parse_command(self, user_id: str, content: str) -> str:
"""解析用户命令并返回回复"""
content_lower = content.lower()
# 1. 帮助命令
if content in ["帮助", "help", "?", "菜单"]:
return self._get_help_message()
# 2. 状态查询
if content in ["状态", "status", "系统状态"]:
return await self._get_system_status()
# 3. 任务列表
if content in ["任务", "任务列表", "tasks"]:
return self._get_task_list(user_id)
# 4. 任务详情
detail_match = re.match(r"详情\s+(\w+)", content)
if detail_match:
task_id = detail_match.group(1)
return self._get_task_detail(task_id)
# 5. 取消任务
cancel_match = re.match(r"取消\s+(\w+)", content)
if cancel_match:
task_id = cancel_match.group(1)
return await self._cancel_task(user_id, task_id)
# 6. 分析请求 - 尝试解析为基因家族分析任务
if BACKEND_AVAILABLE:
analysis_response = await self._handle_analysis_request(user_id, content)
if analysis_response:
return analysis_response
# 7. 未知命令
return f"""❓ 无法理解的命令: "{content}"
请使用以下格式:
• 帮助 - 显示帮助信息
• 状态 - 查询系统状态
• 任务列表 - 查看任务
• 详情 <任务ID> - 查看详情
• 或直接发送分析需求,如:"Ft.SPL 基因家族鉴定"
发送"帮助"查看完整命令列表。"""
def _get_help_message(self) -> str:
"""获取帮助信息"""
return """🤖 bbav20311 基因家族分析助手
📋 可用命令:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• 帮助 / help - 显示此帮助
• 状态 / status - 查询系统状态
• 任务 / 任务列表 - 查看进行中的任务
• 详情 <任务ID> - 查看任务详情
• 取消 <任务ID> - 取消任务
🧬 分析任务:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
直接发送分析需求,例如:
• "Ft.SPL 基因家族鉴定"
• "分析 Ft.WRKY 的进化树"
• "Ft.MYB motif分析"
📊 支持的 stage:
• identify - 基因家族鉴定
• phylogeny - 进化树构建
• motif - Motif分析
• domain - 结构域分析
• promoter - 启动子分析
• synteny - 共线性分析
• expression - 表达分析
• combo - 综合分析
💡 提示:
• 任务完成后会自动通知您
• 大任务可能需要几分钟到几小时
• 可随时查询任务状态"""
async def _get_system_status(self) -> str:
"""获取系统状态"""
if not BACKEND_AVAILABLE:
return "⚠️ 后端服务未连接(模拟模式)"
# 检查后端服务状态
active_count = len(self.active_tasks)
return f"""📊 系统状态
✅ 微信服务: 在线
✅ 后端服务: 运行中
📋 活跃任务: {active_count} 个
系统运行正常,可以接收分析请求。"""
def _get_task_list(self, user_id: str) -> str:
"""获取用户的任务列表"""
user_tasks = [
tid for tid, task in self.active_tasks.items()
if task.get("user_id") == user_id
]
if not user_tasks:
return "📭 您当前没有进行中的任务"
lines = [f"📋 您的任务列表 ({len(user_tasks)}个):"]
for tid in user_tasks[-5:]: # 只显示最近5个
task = self.active_tasks[tid]
status_emoji = {
"pending": "⏳",
"running": "🔄",
"completed": "✅",
"failed": "❌"
}.get(task.get("status"), "❓")
lines.append(f"{status_emoji} {tid} - {task.get('task_type', '未知')}")
lines.append("\n发送'详情 <任务ID>'查看详细信息")
return "\n".join(lines)
def _get_task_detail(self, task_id: str) -> str:
"""获取任务详情"""
task = self.active_tasks.get(task_id)
if not task:
return f"❌ 未找到任务: {task_id}"
status_emoji = {
"pending": "⏳",
"running": "🔄",
"completed": "✅",
"failed": "❌"
}.get(task.get("status"), "❓")
lines = [
f"📋 任务详情: {task_id}",
f"状态: {status_emoji} {task.get('status', '未知')}",
f"类型: {task.get('task_type', '未知')}",
f"创建时间: {task.get('created_at', '未知')}",
]
if task.get("started_at"):
lines.append(f"开始时间: {task['started_at']}")
if task.get("completed_at"):
lines.append(f"完成时间: {task['completed_at']}")
if task.get("error"):
lines.append(f"错误信息: {task['error']}")
if task.get("output_files"):
lines.append(f"\n输出文件:")
for f in task["output_files"][:5]:
lines.append(f" • {f}")
return "\n".join(lines)
async def _cancel_task(self, user_id: str, task_id: str) -> str:
"""取消任务"""
task = self.active_tasks.get(task_id)
if not task:
return f"❌ 未找到任务: {task_id}"
if task.get("user_id") != user_id:
return "❌ 您无权取消此任务"
if task.get("status") in ["completed", "failed"]:
return "❌ 任务已完成或已失败,无法取消"
# 取消任务逻辑
task["status"] = "cancelled"
return f"✅ 任务 {task_id} 已取消"
async def _handle_analysis_request(self, user_id: str, content: str) -> Optional[str]:
"""
处理分析请求
使用 bbav20311 的意图识别和任务系统
"""
try:
# 使用 router 进行意图识别
intent = route(content)
if not is_analysis_task(intent):
return None # 不是分析任务
# 提取参数
prefix = intent.prefix
stage = intent.task_type if intent.task_type != "pipeline" else "full"
if not prefix:
return "❌ 无法识别基因家族前缀,请使用格式如:Ft.SPL 基因家族"
# 创建任务
task_id = f"wx_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{user_id[:8]}"
task_info = {
"task_id": task_id,
"user_id": user_id,
"task_type": stage,
"prefix": prefix,
"status": "pending",
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"parameters": intent.parameters
}
self.active_tasks[task_id] = task_info
# 启动异步任务执行
asyncio.create_task(self._execute_task(task_info))
return f"""✅ 分析任务已创建
📋 任务ID: {task_id}
🧬 基因家族: {prefix}
🔬 分析类型: {stage}
⏳ 状态: 排队中
任务完成后将通过微信通知您。
发送"详情 {task_id}"查看进度。"""
except Exception as e:
print(f"处理分析请求失败: {e}")
return None
async def _execute_task(self, task_info: dict):
"""执行任务"""
task_id = task_info["task_id"]
user_id = task_info["user_id"]
# 创建通知器
notifier = WeChatTaskNotifier(user_wechat_id=user_id, wechat=self.wechat)
try:
# 更新状态
task_info["status"] = "running"
task_info["started_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 通知开始
await notifier.notify_task_started(
task_id=task_id,
task_type=task_info["task_type"]
)
if BACKEND_AVAILABLE:
# 创建 bbav20311 job
job = new_job()
# 运行任务
# 这里需要根据 task_type 调用相应的 stage
stage = task_info["task_type"]
prefix = task_info["prefix"]
print(f"执行任务: {task_id}, stage={stage}, prefix={prefix}")
# 模拟任务执行(实际实现需要调用 pipeline_backend)
await asyncio.sleep(5) # 模拟执行时间
# 更新任务信息
task_info["status"] = "completed"
task_info["completed_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
task_info["output_files"] = [
f"{prefix}.{stage}.result.txt",
f"{prefix}.{stage}.report.pdf"
]
# 通知完成
await notifier.notify_task_completed(
task_id=task_id,
task_type=task_info["task_type"],
output_files=task_info["output_files"]
)
else:
# 模拟模式
await asyncio.sleep(3)
task_info["status"] = "completed"
task_info["completed_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
task_info["output_files"] = ["simulated_result.txt"]
await notifier.notify_task_completed(
task_id=task_id,
task_type=task_info["task_type"],
output_files=task_info["output_files"]
)
except Exception as e:
task_info["status"] = "failed"
task_info["error"] = str(e)
task_info["completed_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
await notifier.notify_task_failed(
task_id=task_id,
task_type=task_info["task_type"],
error=str(e)
)
# ==================== 测试 ====================
async def test_bridge():
"""测试桥接器"""
print("="*60)
print("🧪 WeChat Task Bridge 测试")
print("="*60)
bridge = WeChatTaskBridge()
# 模拟消息处理
test_cases = [
("user_001", "帮助"),
("user_001", "状态"),
("user_001", "Ft.SPL 基因家族鉴定"),
("user_001", "任务列表"),
]
for user_id, content in test_cases:
print(f"\n[Test] 用户: {user_id}, 消息: {content}")
response = await bridge._parse_command(user_id, content)
print(f"[Response] {response[:200]}...")
await asyncio.sleep(1)
print("\n" + "="*60)
print("✅ 测试完成")
print("="*60)
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "test":
# 运行测试模式
asyncio.run(test_bridge())
else:
# 运行服务
bridge = WeChatTaskBridge()
try:
asyncio.run(bridge.start())
except KeyboardInterrupt:
print("\n\n🛑 服务已停止")