Files
DanDingNoneBot/danding_bot/plugins/danding_qqpush/api.py
XiaM-Admin dedc872f1b 功能:通过 HTTP API 实现 Danding_QqPush 插件,用于 QQ 群通知
- 增加了通过外部 HTTP API 向 QQ 群组发送消息的核心功能。
- 实现了对长文本消息的图片渲染,以避免被认定为垃圾信息。
- 支持在消息中提及特定的 QQ 用户。
- 创建了用于 API 令牌和图片渲染设置的配置选项。
- 开发了一个测试脚本以验证 API 功能。
- 对现有代码进行了重构,以提高组织性和可维护性。
2026-01-20 21:19:05 +08:00

143 lines
4.3 KiB
Python

"""API 接口模块 - FastAPI 路由定义"""
from fastapi import APIRouter, Request, HTTPException
from pydantic import BaseModel
from typing import Optional
from nonebot import get_driver, logger
from .config import Config
from .text_parser import TextParser
from .image_render import ImageRenderer
from .sender import sender
# 请求体模型
class PushRequest(BaseModel):
"""推送请求模型"""
group_id: int
"""接收消息的 QQ 群号"""
qq: int
"""被 @ 的 QQ 号"""
text: str
"""通知文本(# 表示换行)"""
# 响应模型
class PushResponse(BaseModel):
"""推送响应模型"""
success: bool
"""是否成功"""
message: str
"""响应消息"""
data: Optional[dict] = None
"""返回数据(如有)"""
# 创建路由器
router = APIRouter()
def create_routes(token: str, config: Config):
"""
创建 API 路由
Args:
token: 鉴权 Token
config: 配置对象
"""
@router.post(f"/danding/qqpush/{token}", response_model=PushResponse)
async def qqpush(request: Request, data: PushRequest):
"""
QQ 消息推送接口
Args:
request: FastAPI 请求对象
data: 推送请求数据
Returns:
推送结果
"""
try:
# 1. 验证参数
if not data.group_id:
raise HTTPException(status_code=400, detail="group_id 不能为空")
if not data.qq:
raise HTTPException(status_code=400, detail="qq 不能为空")
if not data.text or not isinstance(data.text, str):
raise HTTPException(status_code=400, detail="text 不能为空且必须是字符串")
# 2. 检查 Bot 是否在线
bot = sender.get_bot()
if not bot:
logger.error("Bot 实例未设置,无法发送消息")
raise HTTPException(
status_code=500,
detail="Bot 未连接,请检查机器人状态"
)
# 3. 文本处理
text_parser = TextParser(max_length=config.MaxTextLength)
if not text_parser.validate_text(data.text):
raise HTTPException(status_code=400, detail="文本内容无效")
parsed_text = text_parser.parse(data.text)
logger.info(f"解析文本: {parsed_text[:50]}..." if len(parsed_text) > 50 else parsed_text)
# 4. 生成图片
image_renderer = ImageRenderer(
width=config.ImageWidth,
font_size=config.ImageFontSize,
padding=config.ImagePadding,
line_spacing=config.ImageLineSpacing,
bg_color=config.ImageBgColor,
text_color=config.ImageTextColor,
font_paths=config.FontPaths
)
image_base64 = image_renderer.render_to_base64(parsed_text)
logger.info("图片生成成功")
# 5. 发送消息
send_result = await sender.send_to_group(
group_id=data.group_id,
qq=data.qq,
image_base64=image_base64
)
if not send_result["success"]:
logger.error(f"消息发送失败: {send_result['error']}")
raise HTTPException(
status_code=500,
detail=send_result["message"]
)
logger.info(f"消息发送成功 - 群: {data.group_id}, @: {data.qq}")
return PushResponse(
success=True,
message="推送成功",
data={
"group_id": data.group_id,
"qq": data.qq,
"message_id": send_result["data"].get("message_id")
}
)
except HTTPException:
raise
except Exception as e:
logger.exception(f"推送接口异常: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"服务器内部错误: {str(e)}"
)
return router