fix(api): 统一错误日志时间戳并传递 request_datetime

- 统一 add_error_log 的 request_time:优先使用 request_datetime,
  否则使用 datetime.now(),去除 timezone.utc,避免与请求日志时区不一致
- 在 Gemini/OpenAI/Vertex/Embedding 等服务的异常处理处补充传入
  request_datetime,使错误日志与请求日志可一一对应
- stats: 移除失败记录的错误日志时间窗匹配与 error_log_id 附带,降低查询开销
  与误关联风险;建议通过统一时间戳(key + request_time)或独立错误日志
  查询接口完成关联
- 调整部分导入顺序与长行换行等代码风格,无功能改动

BREAKING CHANGE: 统计详情接口不再返回 error_log_id 字段。需要关联错误日志的
客户端请改为基于 key 与 request_time 在错误日志接口中检索。
This commit is contained in:
snaily
2025-08-18 17:26:53 +08:00
parent 669123f348
commit 2001bfdcd9
8 changed files with 187 additions and 150 deletions
@@ -1,4 +1,3 @@
import datetime
import json
import re
@@ -11,20 +10,21 @@ from app.database.services import (
add_request_log,
)
from app.domain.openai_models import ChatRequest, ImageGenerationRequest
from app.log.logger import get_openai_compatible_logger
from app.service.client.api_client import OpenaiApiClient
from app.service.key.key_manager import KeyManager
from app.utils.helpers import redact_key_for_logging
from app.log.logger import get_openai_compatible_logger
logger = get_openai_compatible_logger()
class OpenAICompatiableService:
def __init__(self, base_url: str, key_manager: KeyManager = None):
self.key_manager = key_manager
self.base_url = base_url
self.api_client = OpenaiApiClient(base_url, settings.TIME_OUT)
async def get_models(self, api_key: str) -> Dict[str, Any]:
return await self.api_client.get_models(api_key)
@@ -37,10 +37,12 @@ class OpenAICompatiableService:
request_dict = request.model_dump()
# 移除值为null的
request_dict = {k: v for k, v in request_dict.items() if v is not None}
del request_dict["top_k"] # 删除top_k参数,目前不支持该参数
del request_dict["top_k"] # 删除top_k参数,目前不支持该参数
if request.stream:
return self._handle_stream_completion(request.model, request_dict, api_key)
return await self._handle_normal_completion(request.model, request_dict, api_key)
return await self._handle_normal_completion(
request.model, request_dict, api_key
)
async def generate_images(
self,
@@ -153,6 +155,7 @@ class OpenAICompatiableService:
error_log=error_log_msg,
error_code=status_code,
request_msg=payload,
request_datetime=request_datetime,
)
if self.key_manager:
@@ -160,15 +163,17 @@ class OpenAICompatiableService:
current_attempt_key, retries
)
if api_key:
logger.info(f"Switched to new API key: {redact_key_for_logging(api_key)}")
logger.info(
f"Switched to new API key: {redact_key_for_logging(api_key)}"
)
else:
logger.error(
f"No valid API key available after {retries} retries."
)
break
break
else:
logger.error("KeyManager not available for retry logic.")
break
break
if retries >= max_retries:
logger.error(f"Max retries ({max_retries}) reached for streaming.")
@@ -187,5 +192,3 @@ class OpenAICompatiableService:
if not is_success and retries >= max_retries:
yield f"data: {json.dumps({'error': 'Streaming failed after retries'})}\n\n"
yield "data: [DONE]\n\n"