diff --git a/astrbot/core/pipeline/result_decorate/stage.py b/astrbot/core/pipeline/result_decorate/stage.py index 53f2ec49d..afb8a6184 100644 --- a/astrbot/core/pipeline/result_decorate/stage.py +++ b/astrbot/core/pipeline/result_decorate/stage.py @@ -186,7 +186,6 @@ class ResultDecorateStage(Stage): # 流式输出不执行下面的逻辑 if is_stream: - logger.info("流式输出已启用,跳过结果装饰阶段") return # 需要再获取一次。插件可能直接对 chain 进行了替换。 diff --git a/astrbot/core/pipeline/scheduler.py b/astrbot/core/pipeline/scheduler.py index 243d03378..f62dc5d89 100644 --- a/astrbot/core/pipeline/scheduler.py +++ b/astrbot/core/pipeline/scheduler.py @@ -90,7 +90,7 @@ class PipelineScheduler: if isinstance(event, WebChatMessageEvent | WecomAIBotMessageEvent): await event.send(None) - logger.debug("pipeline 执行完毕。") + logger.debug("pipeline execution completed.") finally: event.cleanup_temporary_local_files() active_event_registry.unregister(event) diff --git a/astrbot/core/provider/sources/gemini_source.py b/astrbot/core/provider/sources/gemini_source.py index bd87391be..47998ff68 100644 --- a/astrbot/core/provider/sources/gemini_source.py +++ b/astrbot/core/provider/sources/gemini_source.py @@ -97,7 +97,6 @@ class ProviderGoogleGenAI(Provider): if proxy: async_client_kwargs["proxy"] = proxy async_client_kwargs["trust_env"] = False - logger.info("[Gemini] 使用代理") else: async_client_kwargs["trust_env"] = True @@ -137,15 +136,18 @@ class ProviderGoogleGenAI(Provider): keys.remove(self.chosen_api_key) if len(keys) > 0: self.set_key(random.choice(keys)) - logger.info( - f"检测到 Key 异常({e.message}),正在尝试更换 API Key 重试... 当前 Key: {self.chosen_api_key[:12]}...", + logger.warning( + "Retrying with a different API key due to detected key issue: %s. Current key: %s...", + e.message, + self.chosen_api_key[:12], ) await asyncio.sleep(1) return True logger.error( - f"检测到 Key 异常({e.message}),且已没有可用的 Key。 当前 Key: {self.chosen_api_key[:12]}...", + "No valid API keys remaining. Current key: %s...", + self.chosen_api_key[:12], ) - raise Exception("达到了 Gemini 速率限制, 请稍后再试...") + raise Exception("Gemini API rate limit reached or API key issue detected.") # 连接错误处理 if is_connection_error(e): @@ -172,7 +174,9 @@ class ProviderGoogleGenAI(Provider): self.provider_settings.get("streaming_response", False) and "IMAGE" in modalities ): - logger.warning("流式输出不支持图片模态,已自动降级为文本模态") + logger.warning( + "Streaming responses do not support IMAGE modality, falling back to TEXT modality." + ) modalities = ["TEXT"] tool_list: list[types.Tool] | None = [] @@ -181,60 +185,28 @@ class ProviderGoogleGenAI(Provider): native_search = self.provider_config.get("gm_native_search", False) url_context = self.provider_config.get("gm_url_context", False) - if "gemini-2.5" in model_name: - if native_coderunner: - tool_list.append(types.Tool(code_execution=types.ToolCodeExecution())) - if native_search: - logger.warning("代码执行工具与搜索工具互斥,已忽略搜索工具") - if url_context: - logger.warning( - "代码执行工具与URL上下文工具互斥,已忽略URL上下文工具", - ) - else: - if native_search: - tool_list.append(types.Tool(google_search=types.GoogleSearch())) - - if url_context: - if hasattr(types, "UrlContext"): - tool_list.append(types.Tool(url_context=types.UrlContext())) - else: - logger.warning( - "当前 SDK 版本不支持 URL 上下文工具,已忽略该设置,请升级 google-genai 包", - ) - - elif "gemini-2.0-lite" in model_name: + if "gemini-2.0-lite" in model_name: if native_coderunner or native_search or url_context: logger.warning( - "gemini-2.0-lite 不支持代码执行、搜索工具和URL上下文,将忽略这些设置", + "gemini-2.0-lite does not support native code execution, search, or URL context tools. These settings will be ignored.", ) - tool_list = None - else: if native_coderunner: tool_list.append(types.Tool(code_execution=types.ToolCodeExecution())) - if native_search: - logger.warning("代码执行工具与搜索工具互斥,已忽略搜索工具") - elif native_search: + if native_search: tool_list.append(types.Tool(google_search=types.GoogleSearch())) + if url_context: + tool_list.append(types.Tool(url_context=types.UrlContext())) - if url_context and not native_coderunner: - if hasattr(types, "UrlContext"): - tool_list.append(types.Tool(url_context=types.UrlContext())) - else: - logger.warning( - "当前 SDK 版本不支持 URL 上下文工具,已忽略该设置,请升级 google-genai 包", - ) + if tools: + func_desc = tools.get_func_desc_google_genai_style() + tool_list.append( + types.Tool(function_declarations=func_desc["function_declarations"]), + ) if not tool_list: tool_list = None - if tools and tool_list: - logger.warning("已启用原生工具,函数工具将被忽略") - elif tools and (func_desc := tools.get_func_desc_google_genai_style()): - tool_list = [ - types.Tool(function_declarations=func_desc["function_declarations"]), - ] - tool_config = None has_func_decl = tool_list and any(t.function_declarations for t in tool_list) if has_func_decl: @@ -322,7 +294,7 @@ class ProviderGoogleGenAI(Provider): def create_text_part(text: str) -> types.Part: content_a = text if text else " " if not text: - logger.warning("文本内容为空,已添加空格占位") + logger.warning("Text content is empty, added a space as placeholder.") return types.Part.from_text(text=content_a) def process_image_url(image_url_dict: dict) -> types.Part: @@ -394,11 +366,16 @@ class ProviderGoogleGenAI(Provider): ) thinking_signature = None - if not text and thinking_signature and "tool_calls" in message and any( - tool.get("extra_content", {}).get("google", {}).get( - "thought_signature" + if ( + not text + and thinking_signature + and "tool_calls" in message + and any( + tool.get("extra_content", {}) + .get("google", {}) + .get("thought_signature") + for tool in message["tool_calls"] ) - for tool in message["tool_calls"] ): # If the main content is empty but tool calls have thought signatures, # skip adding an empty text part to deduplicate the thinking signature in the main content and tool calls. @@ -499,7 +476,7 @@ class ProviderGoogleGenAI(Provider): ) -> MessageChain: """处理内容部分并构建消息链""" if not candidate.content: - logger.warning(f"收到的 candidate.content 为空: {candidate}") + logger.warning(f"Gemini candidate.content is empty: {candidate}") if validate_output: raise EmptyModelOutputError( "Gemini candidate content is empty. " @@ -512,22 +489,22 @@ class ProviderGoogleGenAI(Provider): result_parts: list[types.Part] | None = candidate.content.parts if finish_reason == types.FinishReason.SAFETY: - raise Exception("模型生成内容未通过 Gemini 平台的安全检查") + raise Exception("The model output failed Gemini platform safety checks.") if finish_reason in { types.FinishReason.PROHIBITED_CONTENT, types.FinishReason.SPII, types.FinishReason.BLOCKLIST, }: - raise Exception("模型生成内容违反 Gemini 平台政策") + raise Exception("The model output violates Gemini platform policy.") # 防止旧版本SDK不存在IMAGE_SAFETY if hasattr(types.FinishReason, "IMAGE_SAFETY"): if finish_reason == types.FinishReason.IMAGE_SAFETY: - raise Exception("模型生成内容违反 Gemini 平台政策") + raise Exception("The model output violates Gemini platform policy.") if not result_parts: - logger.warning(f"收到的 candidate.content.parts 为空: {candidate}") + logger.warning(f"Gemini candidate.content.parts is empty: {candidate}") if validate_output: raise EmptyModelOutputError( "Gemini candidate content parts are empty. " @@ -634,15 +611,19 @@ class ProviderGoogleGenAI(Provider): logger.debug(f"genai result: {result}") if not result.candidates: - logger.error(f"请求失败, 返回的 candidates 为空: {result}") - raise Exception("请求失败, 返回的 candidates 为空。") + logger.error( + f"Gemini request failed: candidates is empty: {result}" + ) + raise Exception("Gemini request failed: candidates is empty.") if result.candidates[0].finish_reason == types.FinishReason.RECITATION: if temperature > 2: - raise Exception("温度参数已超过最大值2,仍然发生recitation") + raise Exception( + "Temperature exceeded the maximum value of 2, but Gemini recitation still occurred." + ) temperature += 0.2 logger.warning( - f"发生了recitation,正在提高温度至{temperature:.1f}重试...", + f"Gemini recitation detected; increasing temperature to {temperature:.1f} and retrying...", ) continue @@ -653,11 +634,13 @@ class ProviderGoogleGenAI(Provider): e.message = "" if "Developer instruction is not enabled" in e.message: logger.warning( - f"{model} 不支持 system prompt,已自动去除(影响人格设置)", + f"{model} does not support system prompts; removing it automatically. This may affect persona settings.", ) system_instruction = None elif "Function calling is not enabled" in e.message: - logger.warning(f"{model} 不支持函数调用,已自动去除") + logger.warning( + f"{model} does not support function calling; removing tools automatically." + ) tools = None elif ( "Multi-modal output is not supported" in e.message @@ -666,7 +649,7 @@ class ProviderGoogleGenAI(Provider): or "only supports text output" in e.message ): logger.warning( - f"{model} 不支持多模态输出,降级为文本模态", + f"{model} does not support multimodal output; falling back to TEXT modality.", ) modalities = ["TEXT"] else: @@ -717,11 +700,13 @@ class ProviderGoogleGenAI(Provider): e.message = "" if "Developer instruction is not enabled" in e.message: logger.warning( - f"{model} 不支持 system prompt,已自动去除(影响人格设置)", + f"{model} does not support system prompts; removing it automatically. This may affect persona settings.", ) system_instruction = None elif "Function calling is not enabled" in e.message: - logger.warning(f"{model} 不支持函数调用,已自动去除") + logger.warning( + f"{model} does not support function calling; removing tools automatically." + ) tools = None else: raise @@ -736,10 +721,10 @@ class ProviderGoogleGenAI(Provider): llm_response = LLMResponse("assistant", is_chunk=True) if not chunk.candidates: - logger.warning(f"收到的 chunk 中 candidates 为空: {chunk}") + logger.warning(f"Gemini stream chunk has empty candidates: {chunk}") continue if not chunk.candidates[0].content: - logger.warning(f"收到的 chunk 中 content 为空: {chunk}") + logger.warning(f"Gemini stream chunk has empty content: {chunk}") continue if chunk.candidates[0].content.parts and any( @@ -870,7 +855,7 @@ class ProviderGoogleGenAI(Provider): continue break - raise Exception("请求失败。") + raise Exception("Gemini request failed.") async def text_chat_stream( self, @@ -945,7 +930,7 @@ class ProviderGoogleGenAI(Provider): and m.name ] except APIError as e: - raise Exception(f"获取模型列表失败: {e.message}") + raise Exception(f"Failed to fetch Gemini model list: {e.message}") def get_current_key(self) -> str: return self.chosen_api_key @@ -972,7 +957,7 @@ class ProviderGoogleGenAI(Provider): media_type="image", ) if not image_data: - logger.warning("图片预处理结果为空,将忽略。") + logger.warning("Image preprocessing returned no data; ignoring it.") return None return { "type": "image_url", @@ -987,11 +972,13 @@ class ProviderGoogleGenAI(Provider): strict=True, ) except Exception as exc: - logger.warning("音频预处理失败,将忽略。错误: %s", exc) + logger.warning( + "Audio preprocessing failed; ignoring it. Error: %s", exc + ) return None if not audio_data: - logger.warning("音频预处理结果为空,将忽略。") + logger.warning("Audio preprocessing returned no data; ignoring it.") return None return { "type": "audio_url", @@ -1027,7 +1014,9 @@ class ProviderGoogleGenAI(Provider): if audio_part: content_blocks.append(audio_part) else: - raise ValueError(f"不支持的额外内容块类型: {type(part)}") + raise ValueError( + f"Unsupported extra content part type: {type(part)}" + ) # 3. 图片内容 if image_urls: