项目初始化
This commit is contained in:
156
bot/main.py
Normal file
156
bot/main.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""企业微信智能机器人 · Skills 助手(skills 快查 + 截图预览 + Cursor 执行任务)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import env_config
|
||||
from bridge_manager import shutdown_cursor_bridge, warm_cursor_bridge
|
||||
from router import route_message, routing_mode
|
||||
from skills_service import handle_command, warm_feed_cache
|
||||
from wecom_media import reply_image, upload_image
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
)
|
||||
logger = logging.getLogger("skills-bot")
|
||||
|
||||
BOT_ID = env_config.env("WECOM_BOT_ID") or env_config.env("WECHAT_BOT_ID")
|
||||
BOT_SECRET = env_config.env("WECOM_BOT_SECRET") or env_config.env("WECHAT_BOT_SECRET")
|
||||
|
||||
|
||||
def _require_credentials() -> None:
|
||||
if not BOT_ID or not BOT_SECRET:
|
||||
print(
|
||||
"请设置环境变量 WECOM_BOT_ID 和 WECOM_BOT_SECRET\n"
|
||||
"(企业微信 → 智能机器人 → API 模式 → 长连接)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_client():
|
||||
from aibot import WSClient, WSClientOptions, generate_req_id
|
||||
|
||||
ws_client = WSClient(
|
||||
WSClientOptions(
|
||||
bot_id=BOT_ID,
|
||||
secret=BOT_SECRET,
|
||||
)
|
||||
)
|
||||
|
||||
@ws_client.on("authenticated")
|
||||
def on_authenticated():
|
||||
logger.info("企业微信长连接认证成功,路由模式=%s", routing_mode())
|
||||
cursor_key = env_config.env("CURSOR_API_KEY")
|
||||
if cursor_key:
|
||||
logger.info("CURSOR_API_KEY 已加载(%s…)", cursor_key[:8])
|
||||
try:
|
||||
warm_cursor_bridge()
|
||||
logger.info("Cursor bridge 预启动完成")
|
||||
except Exception as exc:
|
||||
logger.warning("Cursor bridge 预启动失败(Cursor 任务时会重试): %s", exc)
|
||||
else:
|
||||
logger.warning("CURSOR_API_KEY 未配置,Cursor 任务将失败")
|
||||
try:
|
||||
warm_feed_cache()
|
||||
logger.info("skills 数据预加载完成")
|
||||
except Exception as exc:
|
||||
logger.warning("skills 数据预加载失败: %s", exc)
|
||||
|
||||
@ws_client.on("event.enter_chat")
|
||||
async def on_enter_chat(frame):
|
||||
help_text = handle_command("help")
|
||||
extra = (
|
||||
"\n\n---\n"
|
||||
"**单页截图**:`preview` / `截图` / `预览 [路径或URL]`\n"
|
||||
"**网页操作**:自然语言多步操作,或 `browser 场景名`\n"
|
||||
"例:`访问登录页,输入账号密码,点击登录,点击智能体管理,截图`\n"
|
||||
"场景文件:`bot/scenarios/*.yaml`(可用 `browser xiaobao-agent-manage`)"
|
||||
)
|
||||
await ws_client.reply_welcome(
|
||||
frame,
|
||||
{
|
||||
"msgtype": "markdown",
|
||||
"markdown": {"content": help_text + extra},
|
||||
},
|
||||
)
|
||||
|
||||
@ws_client.on("message.text")
|
||||
async def on_text(frame):
|
||||
body = frame.get("body", {})
|
||||
content = body.get("text", {}).get("content", "")
|
||||
logger.info("收到消息: %s", content)
|
||||
|
||||
stream_id = generate_req_id("stream")
|
||||
last_progress = ""
|
||||
|
||||
async def on_progress(message: str) -> None:
|
||||
nonlocal last_progress
|
||||
if message != last_progress:
|
||||
last_progress = message
|
||||
await ws_client.reply_stream(frame, stream_id, message, False)
|
||||
|
||||
await ws_client.reply_stream(frame, stream_id, "收到,正在处理…", False)
|
||||
|
||||
try:
|
||||
result = await route_message(content, on_progress=on_progress)
|
||||
reply = result.text
|
||||
logger.info(
|
||||
"回复来源: %s, 文本长度=%d, 图片=%s",
|
||||
result.source,
|
||||
len(reply),
|
||||
result.image_path or "-",
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.exception("处理失败")
|
||||
reply = f"处理失败:{exc}"
|
||||
result = None
|
||||
|
||||
if len(reply) > 3800:
|
||||
reply = reply[:3800] + "\n\n> …内容已截断"
|
||||
|
||||
await ws_client.reply_stream(frame, stream_id, reply, True)
|
||||
|
||||
if result and result.image_path:
|
||||
try:
|
||||
media_id = await upload_image(ws_client, result.image_path)
|
||||
await reply_image(ws_client, frame, media_id)
|
||||
logger.info("图片已发送到企微: %s", result.image_path)
|
||||
except Exception as exc:
|
||||
logger.exception("发送图片失败")
|
||||
await ws_client.reply(
|
||||
frame,
|
||||
{
|
||||
"msgtype": "markdown",
|
||||
"markdown": {
|
||||
"content": f"截图文件:`{result.image_path}`\n发图失败:{exc}\n\n请确认 bot 已重启,或发送 `截图` 重试。",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@ws_client.on("error")
|
||||
def on_error(error):
|
||||
logger.error("连接错误: %s", error)
|
||||
|
||||
@ws_client.on("disconnected")
|
||||
def on_disconnected(reason):
|
||||
logger.warning("连接断开: %s", reason)
|
||||
|
||||
return ws_client
|
||||
|
||||
|
||||
def main() -> None:
|
||||
import atexit
|
||||
|
||||
atexit.register(shutdown_cursor_bridge)
|
||||
_require_credentials()
|
||||
client = create_client()
|
||||
logger.info("启动 Skills 助手,Bot ID=%s…", BOT_ID[:8] if BOT_ID else "?")
|
||||
client.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user