chore: 恢复PR改动并适配官方最新版本

在官方更新到4936a6d后,选择性恢复PR中的功能改动:

Maizone插件修复(6个文件):
- 优化成功/失败反馈机制(直接反馈,不使用AI生成)
- 实现QQ空间Cookie失效自动重试机制
- 修复评论回复被分割导致标点符号丢失的问题
- 修复QQ空间转发内容提取错误
- 改进maizone图片识别模型配置,支持自动fallback
- 优化maizone说说生成规则

适配器响应处理(bot.py):
- 添加adapter_response消息处理逻辑
- 适配新的DatabaseMessages架构
- 在message_process早期阶段优先处理adapter_response

Web搜索引擎扩展:
- 添加Serper搜索引擎支持

LLM成本计算修复:
- 修复LLM使用统计中成本计算错误的bug
- 调整LLM相关日志级别为DEBUG

其他优化:
- 优化NapCat adapter响应处理
- 优化person_info关系推理逻辑

注:本次恢复已跳过与官方冲突的部分,保留官方的新架构改进

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SolenmeChiara
2025-10-31 22:09:25 -04:00
parent 26ae2c5b8e
commit 06ed1cbae6
13 changed files with 612 additions and 185 deletions

View File

@@ -15,11 +15,11 @@ from .payload_content.message import Message, MessageBuilder
logger = get_logger("消息压缩工具")
def compress_messages(messages: list[Message], img_target_size: int = 2 * 1024 * 1024) -> list[Message]:
def compress_messages(messages: list[Message], img_target_size: int = 1 * 1024 * 1024) -> list[Message]:
"""
压缩消息列表中的图片
:param messages: 消息列表
:param img_target_size: 图片目标大小,默认2MB
:param img_target_size: 图片目标大小,默认1MB
:return: 压缩后的消息列表
"""
@@ -30,7 +30,7 @@ def compress_messages(messages: list[Message], img_target_size: int = 2 * 1024 *
:return: 转换后的图片数据
"""
try:
image = Image.open(io.BytesIO(image_data))
image = Image.open(image_data)
if image.format and (image.format.upper() in ["JPEG", "JPG", "PNG", "WEBP"]):
# 静态图像转换为JPEG格式
@@ -51,7 +51,7 @@ def compress_messages(messages: list[Message], img_target_size: int = 2 * 1024 *
:return: 缩放后的图片数据
"""
try:
image = Image.open(io.BytesIO(image_data))
image = Image.open(image_data)
# 原始尺寸
original_size = (image.width, image.height)
@@ -156,13 +156,9 @@ class LLMUsageRecorder:
endpoint: str,
time_cost: float = 0.0,
):
prompt_tokens = getattr(model_usage, "prompt_tokens", 0)
completion_tokens = getattr(model_usage, "completion_tokens", 0)
total_tokens = getattr(model_usage, "total_tokens", 0)
input_cost = (prompt_tokens / 1000000) * model_info.price_in
output_cost = (completion_tokens / 1000000) * model_info.price_out
round(input_cost + output_cost, 6)
input_cost = (model_usage.prompt_tokens / 1000000) * model_info.price_in
output_cost = (model_usage.completion_tokens / 1000000) * model_info.price_out
total_cost = round(input_cost + output_cost, 6)
session = None
try:
@@ -175,10 +171,10 @@ class LLMUsageRecorder:
user_id=user_id,
request_type=request_type,
endpoint=endpoint,
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
total_tokens=total_tokens,
cost=1.0,
prompt_tokens=model_usage.prompt_tokens or 0,
completion_tokens=model_usage.completion_tokens or 0,
total_tokens=model_usage.total_tokens or 0,
cost=total_cost,
time_cost=round(time_cost or 0.0, 3),
status="success",
timestamp=datetime.now(), # SQLAlchemy 会处理 DateTime 字段
@@ -190,8 +186,8 @@ class LLMUsageRecorder:
logger.debug(
f"Token使用情况 - 模型: {model_usage.model_name}, "
f"用户: {user_id}, 类型: {request_type}, "
f"提示词: {prompt_tokens}, 完成: {completion_tokens}, "
f"总计: {total_tokens}"
f"提示词: {model_usage.prompt_tokens}, 完成: {model_usage.completion_tokens}, "
f"总计: {model_usage.total_tokens}"
)
except Exception as e:
logger.error(f"记录token使用情况失败: {e!s}")

View File

@@ -534,7 +534,7 @@ class _RequestExecutor:
model_name = model_info.name
retry_interval = api_provider.retry_interval
if isinstance(e, NetworkConnectionError | ReqAbortException):
if isinstance(e, (NetworkConnectionError, ReqAbortException)):
return await self._check_retry(remain_try, retry_interval, "连接异常", model_name)
elif isinstance(e, RespNotOkException):
return await self._handle_resp_not_ok(e, model_info, api_provider, remain_try, messages_info)
@@ -1009,15 +1009,12 @@ class LLMRequest:
# 步骤1: 更新内存中的统计数据,用于负载均衡
stats = self.model_usage[model_info.name]
# 安全地获取 token 使用量, embedding 模型可能不返回 completion_tokens
total_tokens = getattr(usage, "total_tokens", 0)
# 计算新的平均延迟
new_request_count = stats.request_count + 1
new_avg_latency = (stats.avg_latency * stats.request_count + time_cost) / new_request_count
self.model_usage[model_info.name] = stats._replace(
total_tokens=stats.total_tokens + total_tokens,
total_tokens=stats.total_tokens + usage.total_tokens,
avg_latency=new_avg_latency,
request_count=new_request_count,
)
@@ -1064,8 +1061,7 @@ class LLMRequest:
# 遍历工具的参数
for param in tool.get("parameters", []):
# 严格验证参数格式是否为包含5个元素的元组
assert isinstance(param, tuple), "参数必须是元组"
assert len(param) == 5, "参数必须包含5个元素"
assert isinstance(param, tuple) and len(param) == 5, "参数必须是包含5个元素的元组"
builder.add_param(
name=param[0],
param_type=param[1],