钉钉与飞书 Stream 长连接客户端,接收用户消息,分发到命令处理器。所有跨层数据类(BotMessage / ChatType)来自 stocklens.contracts,本目录仅作 re-export。
| 文件 | 职责 |
|---|---|
__init__.py |
导出 |
dispatcher.py |
命令分发入口(被 platforms 调用);RateLimiter 现已包装 limits.MovingWindowRateLimiter(slowapi 间接依赖),自动回收离线用户 key |
models.py |
BotResponse / WebhookResponse + re-export BotMessage / ChatType |
BotMessage和ChatType的真实定义在stocklens/contracts/bot_message.py,本文件保留 re-export 是为了向后兼容旧代码from bot.models import BotMessage。详见 contracts.md。
| 文件 | 职责 |
|---|---|
base.py |
Bot 平台抽象 |
dingtalk.py |
钉钉客户端(HTTP webhook) |
dingtalk_stream.py |
钉钉 Stream 长连接 |
feishu_stream.py |
飞书 Stream 长连接 |
| 文件 | 职责 |
|---|---|
base.py |
Command 基类 |
help.py |
/help 帮助 |
status.py |
/status 系统状态 |
analyze.py |
/analyze <代码> 单股分析 |
batch.py |
/batch 批量分析 |
ask.py |
/ask <代码> [策略] Agent 分析 |
chat.py |
/chat <消息> AI 对话 |
跨平台统一消息模型。字段:platform / message_id / user_id / user_name / chat_id / chat_type / content / raw_content / mentioned / mentions / timestamp / raw_data。
提供 get_command_and_args(prefix='/') 解析命令;中文别名(分析 / 大盘 / 批量 / 帮助 / 状态)也支持。
只在 bot 包内部使用,不入核心层:
BotResponse(text, markdown, at_user, reply_to_message, extra)
BotResponse.text_response(text)
BotResponse.markdown_response(text)
BotResponse.error_response(message)
WebhookResponse(status_code, body, headers)
WebhookResponse.success(body)
WebhookResponse.challenge(challenge)
WebhookResponse.error(message)start()— 启动长连接on_message(...)— 消息回调;归一化为BotMessage→dispatcher.dispatch()send_reply(...)— 平台原生回复
# bot/dispatcher.py 接收 BotMessage
# 解析命令前缀 → 路由到 commands/<name>.py 处理器支持的命令:
| 命令 | 处理器 | 说明 |
|---|---|---|
/help |
help.py | 显示帮助 |
/status |
status.py | 系统状态(数据源/LLM/任务队列) |
/analyze <代码> |
analyze.py | 单股分析(调用 Pipeline.analyze_stock) |
/batch |
batch.py | 批量分析(STOCK_LIST 中所有股票) |
/ask <代码> [策略] |
ask.py | Agent 分析 |
/chat <消息> |
chat.py | AI 自由对话 |
- 依赖:
dingtalk-stream(可选)、lark-oapi(可选)、stocklens.contracts、stocklens.config、stocklens.pipeline、stocklens.agent、stocklens.services、stocklens.notification(formatting 工具) - 被依赖:
main.py(start_bot_stream_clients)
| 变量 | 默认 | 说明 |
|---|---|---|
DINGTALK_APP_KEY |
None | 钉钉应用 Key |
DINGTALK_APP_SECRET |
None | 钉钉应用 Secret |
DINGTALK_STREAM_ENABLED |
false | 启用钉钉 Stream |
FEISHU_APP_ID |
None | 飞书应用 ID |
FEISHU_APP_SECRET |
None | 飞书应用 Secret |
FEISHU_STREAM_ENABLED |
false | 启用飞书 Stream |
AGENT_NL_ROUTING |
false | 自然语言路由(用 LLM 判断意图) |
-
dingtalk-stream与lark-oapi是可选依赖,未装时 Bot 不可用 -
Stream 模式是长连接,不需要公网 IP / Webhook
-
自然语言路由会用 LLM 判断意图,消耗 token
-
长消息会按平台限制截断
-
/chat会话独立维护,进程重启后会话丢失 -
不要在
stocklens/核心层直接from bot.models import BotMessage;改用from stocklens.contracts import BotMessage -
2026-05 修复:
bot/models.py之前BotResponse/WebhookResponse各被定义了两次(第二份覆盖第一份),统一为单一定义;同时把error_response里f"❌ 错误:{message}"(中文+emoji)改为f"[ERROR] {message}",符合 CLAUDE.md 第 2 铁律(源代码全英文) -
2026-05 G9 — 股票代码校验抽到
contracts/stock_code.py:AnalyzeCommand.validate_args之前内联了 3 条正则(A 股 6 位数字 / 港股HK+ 5 位 / 美股 1-5 字母可带.X后缀)+ 中文错误模板字符串。现在用stocklens.contracts.validate_user_stock_code(code) → Optional[error_msg]—— bot 层不再持有验证规则,跨层 contract 单一来源。is_valid_user_stock_code(code)同样导出,可被 API/CLI 复用。回归测试tests/unit/test_contracts_stock_code.py(26 用例:A 股 / HK / US / 大小写混入 / 非法字符 / 边界长度)。