主要变更: 1. 修复速率限流器使用setdefault替代重复创建令牌桶 2. 重构交互注册表匹配逻辑,优化精确匹配查找 3. 重构去重缓存逻辑,移到适配器实例方法 4. 重构发送URL解析,增加合法性校验并拆分公共方法 5. 优化流式消息处理逻辑,简化flush_controller调用 6. 重构群聊类型判断代码,简化语法 7. 修复重连管理器对None类型关闭分类的处理 8. 新增消息缓存、线程模拟器、发送初始化模块 9. 重构凭证备份与会话存储逻辑,支持环境变量指定状态目录 10. 新增配置提示与向导二维码绑定功能 11. 优化媒体上传逻辑,增加重试机制与缓存 12. 新增审批键盘模板构建函数 13. 重构消息格式处理,修正媒体发送字段与长度限制 14. 修复令牌过期时间计算,使用time.time替代monotonic 15. 新增群组激活缓冲区与用户追踪器增强功能 16. 修复换行符问题,统一文件结尾格式
389 lines
11 KiB
Python
389 lines
11 KiB
Python
from __future__ import annotations
|
||
|
||
QQBOT_CONFIG_HINTS: list[dict] = [
|
||
{
|
||
"key": "app_id",
|
||
"label": "App ID",
|
||
"help": "QQ 开放平台应用 ID,从「应用管理」页面获取",
|
||
"required": True,
|
||
"sensitive": False,
|
||
"section": "credentials",
|
||
},
|
||
{
|
||
"key": "app_secret",
|
||
"label": "App Secret",
|
||
"help": "QQ 开放平台客户端密钥,从「开发设置」中生成",
|
||
"required": True,
|
||
"sensitive": True,
|
||
"section": "credentials",
|
||
},
|
||
{
|
||
"key": "client_secret_file",
|
||
"label": "密钥文件路径",
|
||
"help": "存放 App Secret 的文件路径,优先于环境变量",
|
||
"required": False,
|
||
"sensitive": False,
|
||
"section": "credentials",
|
||
},
|
||
{
|
||
"key": "sandbox",
|
||
"label": "沙箱模式",
|
||
"help": "启用沙箱 API 端点 (sandbox.api.sgroup.qq.com)",
|
||
"required": False,
|
||
"default": False,
|
||
"type": "boolean",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "bot_name",
|
||
"label": "Bot 名称",
|
||
"help": "机器人显示名称,用于 @提及匹配",
|
||
"required": False,
|
||
"section": "basic",
|
||
},
|
||
{
|
||
"key": "intents",
|
||
"label": "WebSocket Intents",
|
||
"help": "QQ Bot Gateway 意图位掩码,控制订阅的事件类型",
|
||
"required": False,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "dm_policy",
|
||
"label": "DM 策略",
|
||
"help": "私信访问策略: open(开放) / allowlist(白名单) / pairing(配对) / disabled(禁用)",
|
||
"required": False,
|
||
"default": "open",
|
||
"type": "enum",
|
||
"options": ["open", "allowlist", "pairing", "disabled"],
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "group_policy",
|
||
"label": "群组策略",
|
||
"help": "群组访问策略: open(开放) / allowlist(白名单) / disabled(禁用)",
|
||
"required": False,
|
||
"default": "open",
|
||
"type": "enum",
|
||
"options": ["open", "allowlist", "disabled"],
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "allow_from",
|
||
"label": "DM 白名单",
|
||
"help": "允许私信的用户 ID 列表,支持通配符 '*'",
|
||
"required": False,
|
||
"type": "list",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "group_allow_from",
|
||
"label": "群组白名单",
|
||
"help": "允许的群组 ID 列表,支持通配符 '*'",
|
||
"required": False,
|
||
"type": "list",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "group_require_mention",
|
||
"label": "群聊 @提及门控",
|
||
"help": "群聊中是否需要 @机器人 才响应",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "pairing_enabled",
|
||
"label": "配对模式",
|
||
"help": "启用配对模式,仅已配对用户可私信",
|
||
"required": False,
|
||
"default": False,
|
||
"type": "boolean",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "group_ignore_other_mentions",
|
||
"label": "忽略他人 @",
|
||
"help": "当消息 @了其他人但不包含机器人时忽略",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "group_command_bypass_mention",
|
||
"label": "命令跳过 @",
|
||
"help": "白名单命令可不需要 @机器人",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "security",
|
||
},
|
||
{
|
||
"key": "use_markdown",
|
||
"label": "使用 Markdown",
|
||
"help": "使用 Markdown 格式发送消息",
|
||
"required": False,
|
||
"default": False,
|
||
"type": "boolean",
|
||
"section": "format",
|
||
},
|
||
{
|
||
"key": "markdown_template_id",
|
||
"label": "Markdown 模板 ID",
|
||
"help": "QQ Bot Markdown 消息模板 ID",
|
||
"required": False,
|
||
"section": "format",
|
||
},
|
||
{
|
||
"key": "stream_flush_interval",
|
||
"label": "流式刷新间隔",
|
||
"help": "C2C 流式消息的刷新间隔 (秒)",
|
||
"required": False,
|
||
"default": 0.6,
|
||
"type": "number",
|
||
"section": "streaming",
|
||
},
|
||
{
|
||
"key": "streaming_mode",
|
||
"label": "流式模式",
|
||
"help": "C2C 流式模式: off(关闭) / block(块流式)",
|
||
"required": False,
|
||
"default": "block",
|
||
"type": "enum",
|
||
"options": ["off", "block"],
|
||
"section": "streaming",
|
||
},
|
||
{
|
||
"key": "silent",
|
||
"label": "静默发送",
|
||
"help": "发送消息时不通知用户 (no_notify)",
|
||
"required": False,
|
||
"default": False,
|
||
"type": "boolean",
|
||
"section": "format",
|
||
},
|
||
{
|
||
"key": "dedup_window_s",
|
||
"label": "去重窗口",
|
||
"help": "消息去重时间窗口 (秒)",
|
||
"required": False,
|
||
"default": 60,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "auto_download_attachments",
|
||
"label": "自动下载附件",
|
||
"help": "自动下载消息中的图片/文件附件",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "tts_default_voice",
|
||
"label": "TTS 默认语音",
|
||
"help": "文字转语音默认发音人",
|
||
"required": False,
|
||
"default": "zh-CN-XiaoxiaoNeural",
|
||
"section": "audio",
|
||
},
|
||
{
|
||
"key": "tts_default_format",
|
||
"label": "TTS 默认格式",
|
||
"help": "音频输出格式",
|
||
"required": False,
|
||
"default": "mp3",
|
||
"type": "enum",
|
||
"options": ["mp3", "wav", "opus"],
|
||
"section": "audio",
|
||
},
|
||
{
|
||
"key": "queue_global_limit",
|
||
"label": "消息队列全局上限",
|
||
"help": "消息队列最大容量",
|
||
"required": False,
|
||
"default": 1000,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "queue_per_user_limit",
|
||
"label": "每用户队列上限",
|
||
"help": "每个用户的消息队列最大容量",
|
||
"required": False,
|
||
"default": 20,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "queue_per_group_limit",
|
||
"label": "每群组队列上限",
|
||
"help": "每个群组的消息队列最大容量",
|
||
"required": False,
|
||
"default": 50,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "queue_max_concurrency",
|
||
"label": "队列最大并发",
|
||
"help": "消息队列最大并发处理数",
|
||
"required": False,
|
||
"default": 10,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "reconnect.max_retries",
|
||
"label": "重连次数",
|
||
"help": "WebSocket 最大重连次数",
|
||
"required": False,
|
||
"default": 10,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "reconnect.base_delay",
|
||
"label": "重连基础延迟",
|
||
"help": "重连指数退避基础延迟 (秒)",
|
||
"required": False,
|
||
"default": 1.0,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "reconnect.max_delay",
|
||
"label": "重连最大延迟",
|
||
"help": "重连指数退避最大延迟 (秒)",
|
||
"required": False,
|
||
"default": 60.0,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "reconnect.jitter",
|
||
"label": "重连抖动系数",
|
||
"help": "重连延迟随机抖动系数",
|
||
"required": False,
|
||
"default": 0.3,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "retry.attempts",
|
||
"label": "发送重试次数",
|
||
"help": "消息发送失败最大重试次数",
|
||
"required": False,
|
||
"default": 3,
|
||
"type": "number",
|
||
"section": "connection",
|
||
},
|
||
{
|
||
"key": "credential_backup_dir",
|
||
"label": "凭据备份目录",
|
||
"help": "凭据备份文件存储目录",
|
||
"required": False,
|
||
"section": "storage",
|
||
},
|
||
{
|
||
"key": "session_store_dir",
|
||
"label": "会话存储目录",
|
||
"help": "WebSocket 会话持久化目录",
|
||
"required": False,
|
||
"section": "storage",
|
||
},
|
||
{
|
||
"key": "known_users_max",
|
||
"label": "已知用户上限",
|
||
"help": "已知用户追踪器最大记录数",
|
||
"required": False,
|
||
"default": 10000,
|
||
"type": "number",
|
||
"section": "storage",
|
||
},
|
||
{
|
||
"key": "known_users_persist_dir",
|
||
"label": "已知用户存储目录",
|
||
"help": "已知用户持久化文件目录",
|
||
"required": False,
|
||
"section": "storage",
|
||
},
|
||
{
|
||
"key": "suppress_local_approval_prompt",
|
||
"label": "抑制本地审批提示",
|
||
"help": "防止 QQ Bot 本地二次审批提示去重",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "approval",
|
||
},
|
||
{
|
||
"key": "approval_native_routing",
|
||
"label": "审批原生路由",
|
||
"help": "审批请求通过 QQ Bot 内联键盘路由",
|
||
"required": False,
|
||
"default": True,
|
||
"type": "boolean",
|
||
"section": "approval",
|
||
},
|
||
{
|
||
"key": "plugin_version",
|
||
"label": "插件版本",
|
||
"help": "注入 HTTP User-Agent 的插件版本号",
|
||
"required": False,
|
||
"default": "1.0.0",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "openclaw_version",
|
||
"label": "OpenClaw 版本",
|
||
"help": "注入 HTTP User-Agent 的平台版本号",
|
||
"required": False,
|
||
"default": "1.0.0",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "message_cache_max",
|
||
"label": "消息缓存上限",
|
||
"help": "发送消息缓存最大记录数",
|
||
"required": False,
|
||
"default": 500,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
{
|
||
"key": "message_cache_ttl_s",
|
||
"label": "消息缓存 TTL",
|
||
"help": "发送消息缓存过期时间 (秒)",
|
||
"required": False,
|
||
"default": 3600,
|
||
"type": "number",
|
||
"section": "advanced",
|
||
},
|
||
]
|
||
|
||
|
||
def get_config_hints(section: str = "") -> list[dict]:
|
||
if section:
|
||
return [h for h in QQBOT_CONFIG_HINTS if h.get("section") == section]
|
||
return list(QQBOT_CONFIG_HINTS)
|
||
|
||
|
||
def get_config_sections() -> list[str]:
|
||
seen: set[str] = set()
|
||
result: list[str] = []
|
||
for hint in QQBOT_CONFIG_HINTS:
|
||
section = hint.get("section", "")
|
||
if section and section not in seen:
|
||
seen.add(section)
|
||
result.append(section)
|
||
return result
|
||
|
||
|
||
def get_required_config_keys() -> list[str]:
|
||
return [h["key"] for h in QQBOT_CONFIG_HINTS if h.get("required")]
|