From afca560305f51629a8b6c26bb4cbf7fe2cbe947a Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Tue, 12 Aug 2025 16:23:16 +0800 Subject: [PATCH] =?UTF-8?q?fix;=E4=BC=98=E5=8C=96Web=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=92=8CURL=E8=A7=A3=E6=9E=90=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=9A=84API=20Key=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9DAPI=20Key=E4=B8=BA=E6=9C=89=E6=95=88?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=B9=B6=E6=B7=BB=E5=8A=A0=E7=9B=B8?= =?UTF-8?q?=E5=BA=94=E7=9A=84=E8=AD=A6=E5=91=8A=E6=97=A5=E5=BF=97=E3=80=82?= =?UTF-8?q?=E5=90=8C=E6=97=B6=EF=BC=8C=E5=A2=9E=E5=BC=BAURL=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E5=A4=84=E7=90=86=EF=BC=8C=E6=94=AF=E6=8C=81=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=92=8C=E5=88=97=E8=A1=A8=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E6=9C=89=E6=95=88URL=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=92=8C=E9=AA=8C=E8=AF=81=E3=80=82(?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=94=B9=E4=BA=86=E4=B8=80=E7=82=B9reply?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/replyer/default_generator.py | 32 +++---------- src/llm_models/model_client/__init__.py | 2 + .../built_in/WEB_SEARCH_TOOL/plugin.py | 48 +++++++++++++++++-- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index f3be85a9a..76be87c5e 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -86,32 +86,12 @@ def init_prompt(): {keywords_reaction_prompt} 请注意不要输出多余内容(包括前后缀,冒号和引号,at或 @等 )。只输出回复内容。 {moderation_prompt} -不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。只输出一条回复就好 -现在,你说: -""", - "replyer_prompt", - ) - - Prompt( - """ -{expression_habits_block}{tool_info_block} -{knowledge_prompt}{memory_block}{relation_info_block} -{extra_info_block} -{identity} -{action_descriptions} -{time_block} -你现在正在一个QQ群里聊天,以下是正在进行的聊天内容: -{background_dialogue_prompt} - -你现在想补充说明你刚刚自己的发言内容:{target},原因是{reason} -请你根据聊天内容,组织一条新回复。注意,{target} 是刚刚你自己的发言,你要在这基础上进一步发言,请按照你自己的角度来继续进行回复。 -注意保持上下文的连贯性。 -你现在的心情是:{mood_state} -{reply_style} -{keywords_reaction_prompt} -请注意不要输出多余内容(包括前后缀,冒号和引号,at或 @等 )。只输出回复内容。 -{moderation_prompt} -不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。只输出一条回复就好 +你的核心任务是针对 {reply_target_block} 中提到的内容,生成一段紧密相关且能推动对话的回复。你的回复应该: +1. 明确回应目标消息,而不是宽泛地评论。 +2. 可以分享你的看法、提出相关问题,或者开个合适的玩笑。 +3. 目的是让对话更有趣、更深入。 +4. 不要浮夸,不要夸张修辞,不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。 +最终请输出一条简短、完整且口语化的回复。 现在,你说: """, "replyer_self_prompt", diff --git a/src/llm_models/model_client/__init__.py b/src/llm_models/model_client/__init__.py index 80f7e115e..99abc6c0e 100644 --- a/src/llm_models/model_client/__init__.py +++ b/src/llm_models/model_client/__init__.py @@ -6,3 +6,5 @@ if "openai" in used_client_types: from . import openai_client # noqa: F401 if "gemini" in used_client_types: from . import gemini_client # noqa: F401 +if "aiohttp_gemini" in used_client_types: + from . import aiohttp_gemini_client # noqa: F401 diff --git a/src/plugins/built_in/WEB_SEARCH_TOOL/plugin.py b/src/plugins/built_in/WEB_SEARCH_TOOL/plugin.py index c12415f80..ac4cd8cb1 100644 --- a/src/plugins/built_in/WEB_SEARCH_TOOL/plugin.py +++ b/src/plugins/built_in/WEB_SEARCH_TOOL/plugin.py @@ -44,7 +44,11 @@ class WebSurfingTool(BaseTool): def __init__(self, plugin_config=None): super().__init__(plugin_config) EXA_API_KEY = self.get_config("exa.api_key", None) - self.exa = Exa(api_key=EXA_API_KEY) if EXA_API_KEY else None + # 确保API key是字符串类型 + if EXA_API_KEY and isinstance(EXA_API_KEY, str) and EXA_API_KEY.strip() != "None": + self.exa = Exa(api_key=str(EXA_API_KEY).strip()) + else: + self.exa = None if not self.exa: logger.warning("Exa API Key 未配置,Exa 搜索功能将不可用。") @@ -177,11 +181,14 @@ class URLParserTool(BaseTool): def __init__(self, plugin_config=None): super().__init__(plugin_config) EXA_API_KEY = self.get_config("exa.api_key", None) - if not EXA_API_KEY or EXA_API_KEY == "YOUR_API_KEY_HERE": + # 确保API key是字符串类型 + if (not EXA_API_KEY or + not isinstance(EXA_API_KEY, str) or + EXA_API_KEY.strip() in ("YOUR_API_KEY_HERE", "None", "")): self.exa = None logger.error("Exa API Key 未配置,URL解析功能将受限。") else: - self.exa = Exa(api_key=EXA_API_KEY) + self.exa = Exa(api_key=str(EXA_API_KEY).strip()) async def _local_parse_and_summarize(self, url: str) -> Dict[str, Any]: """ 使用本地库(httpx, BeautifulSoup)解析URL,并调用LLM进行总结。 @@ -243,10 +250,41 @@ class URLParserTool(BaseTool): """ 执行URL内容提取和总结。优先使用Exa,失败后尝试本地解析。 """ - urls = function_args.get("urls") - if not urls: + urls_input = function_args.get("urls") + if not urls_input: return {"error": "URL列表不能为空。"} + # 处理URL输入,确保是列表格式 + if isinstance(urls_input, str): + # 如果是字符串,尝试解析为URL列表 + import re + # 提取所有HTTP/HTTPS URL + url_pattern = r'https?://[^\s\],]+' + urls = re.findall(url_pattern, urls_input) + if not urls: + # 如果没有找到标准URL,将整个字符串作为单个URL + if urls_input.strip().startswith(('http://', 'https://')): + urls = [urls_input.strip()] + else: + return {"error": "提供的字符串中未找到有效的URL。"} + elif isinstance(urls_input, list): + urls = [url.strip() for url in urls_input if isinstance(url, str) and url.strip()] + else: + return {"error": "URL格式不正确,应为字符串或列表。"} + + # 验证URL格式 + valid_urls = [] + for url in urls: + if url.startswith(('http://', 'https://')): + valid_urls.append(url) + else: + logger.warning(f"跳过无效URL: {url}") + + if not valid_urls: + return {"error": "未找到有效的URL。"} + + urls = valid_urls + logger.info(f"准备解析 {len(urls)} 个URL: {urls}") successful_results = [] error_messages = []