ForcePilot/backend/package/yuxi/channels/adapters/qqbot/reply_dispatcher.py
Kris 552aef767c feat(qqbot): 实现QQ机器人适配器完整功能模块
新增QQ Bot适配器完整代码栈,包含:
1. 基础适配器入口与工具类封装
2. 会话管理、重试队列与流量控制
3. 命令系统与内置指令(ping/help/status等)
4. 富媒体消息处理与格式转换
5. 引用存储与审批管理
6. 凭证备份与会话持久化
7. 健康检查与交互回调系统
2026-05-12 00:48:04 +08:00

85 lines
2.9 KiB
Python

from __future__ import annotations
import logging
from enum import Enum, auto
from typing import Any
from yuxi.channels.adapters.qqbot.send import render_reply_payload
from yuxi.channels.pipeline.context import PipelineContext
logger = logging.getLogger(__name__)
class ReplyMode(Enum):
DIRECT = auto()
STREAMING = auto()
MARKDOWN = auto()
FALLBACK = auto()
class ReplyDispatcher:
def __init__(self, adapter: Any) -> None:
self._adapter = adapter
async def reply(self, ctx: PipelineContext, text: str) -> Any:
if ctx.chat_type == "interaction":
return await self._reply_interaction(ctx, text)
streaming_ready = self._check_streaming_ready(ctx)
if streaming_ready:
return await self._reply_streaming(ctx)
if len(text) > 2000:
return await self._reply_markdown(ctx, text)
return await self._reply_direct(ctx, text)
def _check_streaming_ready(self, ctx: PipelineContext) -> bool:
if ctx.chat_type != "dm":
return False
adapter = self._adapter
c2c_ctrl = getattr(adapter, "_c2c_streaming", None)
return c2c_ctrl is not None
async def _reply_direct(self, ctx: PipelineContext, text: str) -> Any:
if ctx.chat_type == "group":
return await self._adapter.send_group_message(ctx.chat_id, text, msg_id=ctx.msg_id)
return await self._adapter.send_dm_message(ctx.chat_id, text, msg_id=ctx.msg_id)
async def _reply_streaming(self, ctx: PipelineContext) -> Any:
c2c_ctrl = self._adapter._c2c_streaming
if c2c_ctrl is None:
return None
msg_id = ctx.metadata.get("stream_msg_id", "")
if not msg_id:
msg_id = ctx.msg_id
return await c2c_ctrl.stream(
chat_id=ctx.chat_id,
msg_id=msg_id,
content_generator=self._adapter._stream_content(ctx),
event_id=ctx.metadata.get("event_id", ""),
)
async def _reply_markdown(self, ctx: PipelineContext, text: str) -> Any:
chunks = self._adapter._markdown_chunker.chunk(text)
results = []
for i, chunk in enumerate(chunks):
payload = render_reply_payload(
chunk, msg_type=2, msg_id=ctx.msg_id, chunk_index=i, total_chunks=len(chunks)
)
if ctx.chat_type == "group":
result = await self._adapter.send_group_message(
ctx.chat_id, content="", payload=payload, msg_id=ctx.msg_id
)
else:
result = await self._adapter.send_dm_message(
ctx.chat_id, content="", payload=payload, msg_id=ctx.msg_id
)
results.append(result)
return results
async def _reply_interaction(self, ctx: PipelineContext, text: str) -> Any:
return await self._adapter._put_interaction(ctx.metadata.get("interaction_id", ""), ctx.content)