ForcePilot/backend/package/yuxi/channels/adapters/yuanbao/setup.py
Kris ba060ca9c5 refactor(yuanbao): 整理元宝适配器代码并新增功能支持
1. 调整导入顺序和导入项顺序优化代码结构
2. 新增位置消息类型映射支持
3. 新增频道帖子事件的消息分发处理
4. 重构WebSocket认证失败日志格式
5. 优化令牌刷新错误提示的换行格式
6. 简化事件队列满时的日志输出
7. 新增系统事件处理和打字状态上报支持
8. 实现打字指示器接口的实际调用逻辑
9. 更新通道能力配置,补充缺失的能力项
2026-05-13 16:17:49 +08:00

165 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from dataclasses import dataclass, field
from yuxi.utils.logging_config import logger
@dataclass
class SetupStepResult:
step: str
success: bool
message: str = ""
data: dict | None = None
@dataclass
class SetupWizardResult:
app_key: str
app_secret: str
bot_app_id: str
verified: bool = False
error: str | None = None
bot_info: dict | None = None
steps: list[SetupStepResult] = field(default_factory=list)
def add_step(self, step: str, success: bool, message: str = "", data: dict | None = None) -> None:
self.steps.append(SetupStepResult(step=step, success=success, message=message, data=data))
async def run_setup_wizard(
token_manager,
http_client,
app_key: str,
app_secret: str,
bot_app_id: str = "",
) -> SetupWizardResult:
result = SetupWizardResult(
app_key=app_key,
app_secret=app_secret,
bot_app_id=bot_app_id,
)
if not app_key.strip() or not app_secret.strip():
result.error = "app_key 和 app_secret 不能为空"
result.add_step("input_validation", False, result.error)
return result
result.add_step("input_validation", True, "输入参数校验通过")
try:
import hashlib
import hmac
import time
import aiohttp
timestamp = int(time.time())
message = f"{app_key}{timestamp}"
signature = hmac.new(
app_secret.encode("utf-8"),
message.encode("utf-8"),
hashlib.sha256,
).hexdigest()
api_base = "https://open-api.yuanbao.tencent.com"
async with aiohttp.ClientSession() as session:
async with session.post(
f"{api_base}/api/auth/token",
json={
"app_key": app_key,
"timestamp": timestamp,
"signature": signature,
},
timeout=aiohttp.ClientTimeout(total=10),
) as resp:
if resp.status != 200:
result.error = f"认证失败: HTTP {resp.status}"
result.add_step("auth", False, result.error)
return result
token_data = await resp.json()
token = token_data.get("access_token", "")
expires_in = token_data.get("expires_in", 7200)
result.add_step("auth", True, f"认证成功token 有效期 {expires_in}s")
headers = {"Authorization": f"Bearer {token}"}
async with session.get(
f"{api_base}/api/v1/bot/info",
headers=headers,
timeout=aiohttp.ClientTimeout(total=10),
) as resp:
if resp.status == 200:
bot_info = await resp.json()
result.verified = True
result.bot_info = bot_info
result.bot_app_id = bot_info.get("bot_app_id", bot_app_id)
result.add_step(
"bot_verify",
True,
f"Bot 验证成功: {result.bot_app_id}",
bot_info,
)
logger.info(f"[Yuanbao] Setup wizard verified: bot_app_id={result.bot_app_id}")
elif resp.status in (401, 403):
result.error = "凭据验证失败,请检查 app_key 和 app_secret"
result.add_step("bot_verify", False, result.error)
else:
result.error = f"Bot 信息获取失败: HTTP {resp.status}"
result.add_step("bot_verify", False, result.error)
except Exception as e:
result.error = f"设置向导出错: {e}"
result.add_step("unexpected_error", False, result.error)
logger.error(f"[Yuanbao] Setup wizard error: {e}")
return result
def generate_config_snippet(app_key: str, app_secret: str, bot_app_id: str) -> str:
return f"""```yaml
channels:
yuanbao:
enabled: true
app_key: "{app_key}"
app_secret: "{app_secret}"
bot_app_id: "{bot_app_id}"
dm_policy: pairing
# 群聊中需要 @机器人 才响应(仅群组生效)
requireMention: true
overflowPolicy: split
replyToMode: first
```"""
def generate_config_snippet_with_accounts(
app_key: str,
app_secret: str,
bot_app_id: str,
accounts: list[dict] | None = None,
) -> str:
accounts_config = ""
if accounts:
for acct in accounts:
accounts_config += f"""
accounts.{acct["id"]}:
appKey: "{acct.get("app_key", "")}"
appSecret: "{acct.get("app_secret", "")}"
name: "{acct.get("name", acct["id"])}"
enabled: true"""
return f"""```yaml
channels:
yuanbao:
enabled: true
app_key: "{app_key}"
app_secret: "{app_secret}"
bot_app_id: "{bot_app_id}"
dm_policy: pairing
# 群聊中需要 @机器人 才响应(仅群组生效)
requireMention: true
overflowPolicy: split
replyToMode: first
defaultAccount: "default"{accounts_config}
```"""