feat: optimize logging and fix timeout calculation issues

This commit is contained in:
Chenyme committed 2025-10-28 20:41:28 +08:00
1 parent b9c67f972a
commit b5b817ebcd
8 files changed
+52 -118

No files matched your search

+1 -1
View File
@@ -41,7 +41,7 @@ async def chat_completions(
HTTPException: 当请求处理失败时
"""
try:
logger.info(f"[Chat] 聊天请求 - 模型: {request.model}")
logger.info(f"[Chat] 收到聊天请求")
# 调用Grok客户端处理请求
result = await GrokClient.openai_to_grok(request.model_dump())
+1 -1
View File
@@ -46,7 +46,7 @@ class AuthManager:
}
)
logger.debug("[Auth] 令牌认证成功。")
logger.debug("[Auth] 令牌认证成功")
return credentials.credentials
+7 -7
View File
@@ -29,7 +29,7 @@ class CacheService:
"""下载并缓存文件"""
cache_path = self._cache_path(file_path)
if cache_path.exists():
logger.debug(f"[{self.cache_type.upper()}Cache] 文件已缓存: {cache_path}")
logger.debug(f"[{self.cache_type.upper()}Cache] 文件缓存成功")
return cache_path
try:
@@ -54,7 +54,7 @@ class CacheService:
logger.debug(f"[{self.cache_type.upper()}Cache] 使用缓存代理: {proxy_url.split('@')[-1] if '@' in proxy_url else proxy_url}")
async with AsyncSession() as session:
logger.debug(f"[{self.cache_type.upper()}Cache] 开始下载: https://assets.grok.com{file_path}")
logger.debug(f"[{self.cache_type.upper()}Cache] 缓存生成视频文件: https://assets.grok.com{file_path}")
response = await session.get(
f"https://assets.grok.com{file_path}",
headers=headers,
@@ -65,7 +65,7 @@ class CacheService:
)
response.raise_for_status()
cache_path.write_bytes(response.content)
logger.debug(f"[{self.cache_type.upper()}Cache] 文件已缓存: {cache_path} ({len(response.content)} bytes)")
logger.debug(f"[{self.cache_type.upper()}Cache] 文件缓存成功")
asyncio.create_task(self.cleanup_cache())
return cache_path
except Exception as e:
@@ -88,10 +88,10 @@ class CacheService:
total_size = sum(size for _, size, _ in files)
if total_size <= max_size_bytes:
logger.debug(f"[{self.cache_type.upper()}Cache] 缓存大小 {total_size / 1024 / 1024:.2f}MB,未超限")
logger.debug(f"[{self.cache_type.upper()}Cache] 缓存大小统计: {total_size / 1024 / 1024:.2f}MB,未达到限制")
return
logger.info(f"[{self.cache_type.upper()}Cache] 缓存大小 {total_size / 1024 / 1024:.2f}MB 超过限制 {max_size_mb}MB,开始清理")
logger.info(f"[{self.cache_type.upper()}Cache] 清理缓存,当前大小 {total_size / 1024 / 1024:.2f}MB 超过限制 {max_size_mb}MB")
files.sort(key=lambda x: x[2])
for file_path, size, _ in files:
@@ -99,9 +99,9 @@ class CacheService:
break
file_path.unlink()
total_size -= size
logger.debug(f"[{self.cache_type.upper()}Cache] 已删除缓存文件: {file_path}")
logger.debug(f"[{self.cache_type.upper()}Cache] 清理缓存文件: {file_path}")
logger.info(f"[{self.cache_type.upper()}Cache] 缓存清理完成,当前大小 {total_size / 1024 / 1024:.2f}MB")
logger.info(f"[{self.cache_type.upper()}Cache] 清理缓存完成,当前大小 {total_size / 1024 / 1024:.2f}MB")
except Exception as e:
logger.error(f"[{self.cache_type.upper()}Cache] 清理缓存失败: {e}")
+7 -24
View File
@@ -33,8 +33,6 @@ class GrokClient:
messages = openai_request["messages"]
stream = openai_request.get("stream", False)
logger.debug(f"[Client] 处理请求 - 模型:{model}, 消息数:{len(messages)}, 流式:{stream}")
# 提取消息内容和图片URL
content, image_urls = GrokClient._extract_content(messages)
model_name, model_mode = Models.to_grok(model)
@@ -45,7 +43,6 @@ class GrokClient:
if len(image_urls) > 1:
logger.warning(f"[Client] 视频模型只允许一张图片,当前有{len(image_urls)}张,只使用第一张")
image_urls = image_urls[:1]
logger.debug(f"[Client] 视频模型文本处理: {content}")
# 重试逻辑
return await GrokClient._try(model, content, image_urls, model_name, model_mode, is_video_model, stream)
@@ -63,23 +60,20 @@ class GrokClient:
# 上传图片
imgs, uris = await GrokClient._upload_imgs(image_urls, auth_token)
# 视频模型需要额外的create操作
# 视频模型 - 创建会话
post_id = None
if is_video and imgs and uris:
logger.debug(f"[Client] 检测到视频模型,执行post create操作")
try:
create_result = await PostCreateManager.create(imgs[0], uris[0], auth_token)
if create_result and create_result.get("success"):
post_id = create_result.get("post_id")
logger.debug(f"[Client] Post创建成功: {post_id}")
else:
logger.warning(f"[Client] Post创建失败,继续使用原有流程")
logger.warning(f"[Client] 创建会话失败,继续使用原有流程")
except Exception as e:
logger.warning(f"[Client] Post创建异常: {e},继续使用原有流程")
logger.warning(f"[Client] 创建会话异常: {e},继续使用原有流程")
# 构建并发送请求
payload = GrokClient._build_payload(content, model_name, model_mode, imgs, uris, is_video, post_id)
logger.debug(f"[Client] 请求载荷配置: {payload}")
return await GrokClient._send_request(payload, auth_token, model, stream, post_id)
except GrokApiException as e:
@@ -110,7 +104,7 @@ class GrokClient:
for msg in messages:
msg_content = msg.get("content", "")
# 处理复杂消息格式(包含文本和图片)
# 处理复杂消息格式
if isinstance(msg_content, list):
for item in msg_content:
item_type = item.get("type")
@@ -173,17 +167,14 @@ class GrokClient:
"isAsyncChat": False
}
# 视频模型特殊配置
# 视频模型配置
if is_video_model and image_uris:
image_url = image_uris[0]
logger.debug(f"[Client] 视频模型图片URL: {image_url}")
# 根据是否有post_id选择不同的URL格式
# 构建 URL 消息
if post_id:
logger.debug(f"[Client] 使用PostID构建URL: {post_id}")
image_message = f"https://grok.com/imagine/{post_id} {content} --mode=custom"
else:
logger.debug(f"[Client] 使用文件URI构建URL: {image_url}")
image_message = f"https://assets.grok.com/post/{image_url} {content} --mode=custom"
payload = {
@@ -193,8 +184,6 @@ class GrokClient:
"fileAttachments": image_attachments,
"toolOverrides": {"videoGen": True}
}
logger.debug(f"[Client] 视频模型载荷配置: {payload}")
logger.debug("[Client] 视频模型载荷配置: toolOverrides.videoGen = True")
return payload
@@ -209,19 +198,15 @@ class GrokClient:
# 构建请求头
headers = GrokClient._build_headers(auth_token)
if model == "grok-imagine-0.9":
# 优先使用传入的post_id,否则使用fileAttachments中的第一个
# 传入会话ID
referer_id = post_id if post_id else payload.get("fileAttachments", [""])[0]
if referer_id:
headers["Referer"] = f"https://grok.com/imagine/{referer_id}"
logger.debug(f"[Client] 设置Referer: {headers['Referer']}")
# 使用服务代理
proxy_url = setting.get_service_proxy()
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
if proxy_url:
logger.debug(f"[Client] 使用服务代理: {proxy_url.split('@')[-1] if '@' in proxy_url else proxy_url}")
# 构建请求参数
request_kwargs = {
"headers": headers,
@@ -239,8 +224,6 @@ class GrokClient:
**request_kwargs
)
logger.debug(f"[Client] API响应状态码: {response.status_code}")
# 处理非成功响应
if response.status_code != 200:
GrokClient._handle_error(response, auth_token)
+11 -46
View File
@@ -17,15 +17,15 @@ IMPERSONATE_BROWSER = "chrome133a"
class PostCreateManager:
"""
Grok Post创建管理器
Grok 会话创建管理器
提供图片post创建功能,用于视频生成前的准备工作
提供图片会话创建功能,用于视频生成前的准备工作
"""
@staticmethod
async def create(file_id: str, file_uri: str, auth_token: str) -> Optional[Dict[str, Any]]:
"""
创建post记录
创建会话记录
Args:
file_id: 上传后的文件ID
@@ -33,18 +33,17 @@ class PostCreateManager:
auth_token: 认证令牌
Returns:
创建的post信息,包含post_id等
创建的会话信息,包含会话ID等
"""
try:
# 验证参数
if not file_id or not file_uri:
raise GrokApiException("文件ID或URI缺失", "INVALID_PARAMS")
raise GrokApiException("会话ID或URI缺失", "INVALID_PARAMS")
if not auth_token:
raise GrokApiException("认证令牌缺失", "NO_AUTH_TOKEN")
# 构建创建数据
# 构建完整的 media_url
media_url = f"https://assets.grok.com/{file_uri}"
create_data = {
@@ -52,17 +51,12 @@ class PostCreateManager:
"media_type": "MEDIA_POST_TYPE_IMAGE"
}
logger.debug(f"[PostCreate] 创建post请求: fileId={file_id}, uri={file_uri}, media_url={media_url}")
# 获取认证令牌和cookie
cf_clearance = setting.grok_config.get("cf_clearance", "")
cookie = f"{auth_token};{cf_clearance}" if cf_clearance else auth_token
# 获取代理配置
proxy_url = setting.grok_config.get("proxy_url", "")
if proxy_url:
logger.debug(f"[PostCreate] 使用代理: {proxy_url.split('@')[-1] if '@' in proxy_url else proxy_url}")
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
# 发送异步请求
@@ -82,8 +76,8 @@ class PostCreateManager:
# 检查响应
if response.status_code == 200:
result = response.json()
post_id = result.get("postId", "")
logger.debug(f"[PostCreate] Post创建成功,PostID: {post_id}")
post_id = result.get("post", {}).get("id", "")
logger.debug(f"[PostCreate] 创建会话成功,会话ID: {post_id}")
return {
"post_id": post_id,
"file_id": file_id,
@@ -99,40 +93,11 @@ class PostCreateManager:
except:
error_msg = f"{error_msg}, 详情: {response.text[:200]}"
logger.error(f"[PostCreate] Post创建失败: {error_msg}")
raise GrokApiException(f"Post创建失败: {error_msg}", "CREATE_ERROR")
logger.error(f"[PostCreate] 创建会话失败: {error_msg}")
raise GrokApiException(f"创建会话失败: {error_msg}", "CREATE_ERROR")
except GrokApiException:
raise
except Exception as e:
logger.error(f"[PostCreate] Post创建异常: {e}")
raise GrokApiException(f"Post创建异常: {e}", "CREATE_ERROR") from e
@staticmethod
async def batch_create(file_list: list, auth_token: str) -> list:
"""
批量创建post记录
Args:
file_list: 文件列表,每个元素包含 (file_id, file_uri)
auth_token: 认证令牌
Returns:
创建结果列表
"""
results = []
for file_id, file_uri in file_list:
try:
result = await PostCreateManager.create(file_id, file_uri, auth_token)
results.append(result)
except Exception as e:
logger.warning(f"[PostCreate] 批量创建失败: fileId={file_id}, 错误={e}")
results.append({
"file_id": file_id,
"file_uri": file_uri,
"success": False,
"error": str(e)
})
return results
logger.error(f"[PostCreate] 创建会话异常: {e}")
raise GrokApiException(f"创建会话异常: {e}", "CREATE_ERROR") from e
+22 -28
View File
@@ -269,7 +269,7 @@ class GrokResponseProcessor:
yield "data: [DONE]\n\n"
return
logger.debug(f"[Processor] 接收到数据块: {chunk} \n\n")
logger.debug(f"[Processor] 接收到数据块, 长度: {len(chunk)} bytes")
if not chunk:
continue
@@ -286,9 +286,12 @@ class GrokResponseProcessor:
# 提取响应数据
grok_resp = data.get("result", {}).get("response", {})
logger.debug(f"[Processor] 解析响应数据: {grok_resp} \n\n")
logger.debug(f"[Processor] 解析响应数据, 长度: {len(grok_resp)} bytes")
if not grok_resp:
continue
# 更新超时计时器
timeout_manager.mark_chunk_received()
# 更新模型名称
if user_resp := grok_resp.get("userResponse"):
@@ -300,27 +303,28 @@ class GrokResponseProcessor:
progress = video_resp.get("progress", 0)
v_url = video_resp.get("videoUrl")
# 处理进度更新(仅当进度增加时)
# 处理进度更新
if progress > last_video_progress:
last_video_progress = progress
# 添加 <think> 标签
if not video_progress_started:
content = f"<think>视频已生成{progress}%\n"
video_progress_started = True
elif progress < 100:
content = f"视频已生成{progress}%\n"
else:
# 进度100%时关闭 <think> 标签
content = f"视频已生成{progress}%</think>\n"
# 思考状态
if show_thinking:
# 添加 <think> 标签
if not video_progress_started:
content = f"<think>视频已生成{progress}%\n"
video_progress_started = True
elif progress < 100:
content = f"视频已生成{progress}%\n"
else:
# 关闭 <think> 标签
content = f"视频已生成{progress}%</think>\n"
yield make_chunk(content)
timeout_manager.mark_chunk_received()
chunk_index += 1
yield make_chunk(content)
chunk_index += 1
# 处理视频URL(单独判断,不依赖进度)
# 处理视频URL
if v_url:
logger.debug(f"[Processor] 视频生成完成: {v_url}")
logger.debug(f"[Processor] 视频生成完成")
full_video_url = f"https://assets.grok.com/{v_url}"
try:
@@ -337,7 +341,6 @@ class GrokResponseProcessor:
video_content = f'<video src="{full_video_url}" controls="controls"></video>\n'
yield make_chunk(video_content)
timeout_manager.mark_chunk_received()
chunk_index += 1
continue
@@ -378,7 +381,6 @@ class GrokResponseProcessor:
# 发送前缀
yield make_chunk(markdown_prefix + mime_part)
timeout_manager.mark_chunk_received()
chunk_index += 1
# 分块发送 base64 数据
@@ -386,24 +388,19 @@ class GrokResponseProcessor:
for i in range(0, len(b64_data), chunk_size):
chunk_data = b64_data[i:i + chunk_size]
yield make_chunk(chunk_data)
timeout_manager.mark_chunk_received()
chunk_index += 1
# 发送后缀
yield make_chunk(markdown_suffix)
timeout_manager.mark_chunk_received()
chunk_index += 1
else:
yield make_chunk(f"![Generated Image]({base64_str})\n")
timeout_manager.mark_chunk_received()
chunk_index += 1
else:
yield make_chunk(f"![Generated Image]({base64_str})\n")
timeout_manager.mark_chunk_received()
chunk_index += 1
else:
yield make_chunk(f"![Generated Image](https://assets.grok.com/{img})\n")
timeout_manager.mark_chunk_received()
chunk_index += 1
else:
# url 模式:缓存并返回链接
@@ -419,11 +416,9 @@ class GrokResponseProcessor:
# 发送内容
yield make_chunk(content.strip(), "stop")
timeout_manager.mark_chunk_received()
return
elif token:
yield make_chunk(token)
timeout_manager.mark_chunk_received()
chunk_index += 1
# 提取对话数据
@@ -495,7 +490,6 @@ class GrokResponseProcessor:
# 只在不需要跳过时才发送
if not should_skip:
yield make_chunk(content)
timeout_manager.mark_chunk_received()
chunk_index += 1
is_thinking = current_is_thinking
@@ -517,7 +511,7 @@ class GrokResponseProcessor:
logger.info(f"[Processor] 流式响应完成,总耗时: {timeout_manager.get_total_duration():.2f}秒")
except Exception as e:
logger.error(f"[Processor] 流式处理严重错误: {e}")
logger.error(f"[Processor] 流式处理发生严重错误: {e}")
yield make_chunk(f"处理错误: {e}", "error")
# 发送流结束标记
yield "data: [DONE]\n\n"
+3 -8
View File
@@ -272,14 +272,13 @@ class GrokTokenManager:
)
status_text = "未使用" if max_remaining == -1 else f"剩余{max_remaining}次"
logger.debug(f"[Token] 为模型 {model} 选择Token ({status_text})")
logger.debug(f"[Token] 正在为模型 {model} 分配Token ({status_text})")
return max_token_key
async def check_limits(self, auth_token: str, model: str) -> Optional[Dict[str, Any]]:
"""检查并更新模型速率限制"""
try:
rate_limit_model_name = Models.to_rate_limit(model)
logger.debug(f"[Token] 检查模型 {model} (接口模型: {rate_limit_model_name}) 的速率限制")
# 准备请求
payload = {"requestKind": "DEFAULT", "modelName": rate_limit_model_name}
@@ -293,9 +292,6 @@ class GrokTokenManager:
proxy_url = setting.grok_config.get("proxy_url", "")
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
if proxy_url:
logger.debug(f"[Token] 使用代理: {proxy_url.split('@')[-1] if '@' in proxy_url else proxy_url}")
# 发送异步请求
async with AsyncSession() as session:
response = await session.post(
@@ -309,17 +305,16 @@ class GrokTokenManager:
if response.status_code == 200:
rate_limit_data = response.json()
logger.debug(f"[Token] 成功获取速率限制信息")
# 保存速率限制信息
sso_value = self._extract_sso(auth_token)
if sso_value:
if model == "grok-4-heavy":
await self.update_limits(sso_value, normal=None, heavy=rate_limit_data.get("remainingQueries", -1))
logger.info(f"[Token] 已更新限制: sso={sso_value[:10]}..., heavy={rate_limit_data.get('remainingQueries', -1)}")
logger.info(f"[Token] 更新 Token 限制: sso={sso_value[:10]}..., heavy={rate_limit_data.get('remainingQueries', -1)}")
else:
await self.update_limits(sso_value, normal=rate_limit_data.get("remainingTokens", -1), heavy=None)
logger.info(f"[Token] 已更新限制: sso={sso_value[:10]}..., 通用={rate_limit_data.get('remainingTokens', -1)}")
logger.info(f"[Token] 更新 Token 限制: sso={sso_value[:10]}..., basic={rate_limit_data.get('remainingTokens', -1)}")
return rate_limit_data
else:
-3
View File
@@ -63,9 +63,6 @@ class ImageUploadManager:
cookie = f"{auth_token};{cf_clearance}" if cf_clearance else auth_token
proxy_url = setting.grok_config.get("proxy_url", "")
if proxy_url:
logger.debug(f"[Upload] 使用代理: {proxy_url.split('@')[-1] if '@' in proxy_url else proxy_url}")
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
# 发送异步请求