From b5b817ebcd07bff9e167f0972db4588eea75aaec Mon Sep 17 00:00:00 2001 From: Chenyme <118253778+chenyme@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:41:28 +0800 Subject: [PATCH] feat: optimize logging and fix timeout calculation issues --- app/api/v1/chat.py | 2 +- app/core/auth.py | 2 +- app/services/grok/cache.py | 14 ++++----- app/services/grok/client.py | 31 +++++------------- app/services/grok/create.py | 57 +++++++--------------------------- app/services/grok/processer.py | 50 +++++++++++++---------------- app/services/grok/token.py | 11 ++----- app/services/grok/upload.py | 3 -- 8 files changed, 52 insertions(+), 118 deletions(-) diff --git a/app/api/v1/chat.py b/app/api/v1/chat.py index 87460e5..72dddeb 100644 --- a/app/api/v1/chat.py +++ b/app/api/v1/chat.py @@ -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()) diff --git a/app/core/auth.py b/app/core/auth.py index fffaa9e..d497e4d 100644 --- a/app/core/auth.py +++ b/app/core/auth.py @@ -46,7 +46,7 @@ class AuthManager: } ) - logger.debug("[Auth] 令牌认证成功。") + logger.debug("[Auth] 令牌认证成功") return credentials.credentials diff --git a/app/services/grok/cache.py b/app/services/grok/cache.py index 05f8a52..21d8631 100644 --- a/app/services/grok/cache.py +++ b/app/services/grok/cache.py @@ -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}") diff --git a/app/services/grok/client.py b/app/services/grok/client.py index 05b3dea..718ff98 100644 --- a/app/services/grok/client.py +++ b/app/services/grok/client.py @@ -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) diff --git a/app/services/grok/create.py b/app/services/grok/create.py index 1aeddfa..29621d4 100644 --- a/app/services/grok/create.py +++ b/app/services/grok/create.py @@ -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 diff --git a/app/services/grok/processer.py b/app/services/grok/processer.py index 1c29564..9de2dc2 100644 --- a/app/services/grok/processer.py +++ b/app/services/grok/processer.py @@ -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 - # 添加 标签 - if not video_progress_started: - content = f"视频已生成{progress}%\n" - video_progress_started = True - elif progress < 100: - content = f"视频已生成{progress}%\n" - else: - # 进度100%时关闭 标签 - content = f"视频已生成{progress}%\n" + # 思考状态 + if show_thinking: + # 添加 标签 + if not video_progress_started: + content = f"视频已生成{progress}%\n" + video_progress_started = True + elif progress < 100: + content = f"视频已生成{progress}%\n" + else: + # 关闭 标签 + content = f"视频已生成{progress}%\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'\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" diff --git a/app/services/grok/token.py b/app/services/grok/token.py index f93f714..5cc5159 100644 --- a/app/services/grok/token.py +++ b/app/services/grok/token.py @@ -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: diff --git a/app/services/grok/upload.py b/app/services/grok/upload.py index 973a508..8738b2e 100644 --- a/app/services/grok/upload.py +++ b/app/services/grok/upload.py @@ -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 # 发送异步请求