diff --git a/config.py b/config.py index a1d5e1ec..6e5134fb 100644 --- a/config.py +++ b/config.py @@ -269,6 +269,10 @@ GROBID_URLS = [ ] +# Searxng互联网检索服务 +SEARXNG_URL = "https://cloud-1.agent-matrix.com/" + + # 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭 ALLOW_RESET_CONFIG = False @@ -386,6 +390,9 @@ NUM_CUSTOM_BASIC_BTN = 4 插件在线服务配置依赖关系示意图 │ +├── 互联网检索 +│ └── SEARXNG_URL +│ ├── 语音功能 │ ├── ENABLE_AUDIO │ ├── ALIYUN_TOKEN diff --git a/crazy_functional.py b/crazy_functional.py index 317bdce0..0e874f71 100644 --- a/crazy_functional.py +++ b/crazy_functional.py @@ -43,7 +43,8 @@ def get_crazy_functions(): from crazy_functions.Latex_Function import PDF翻译中文并重新编译PDF from crazy_functions.Latex_Function_Wrap import Arxiv_Localize from crazy_functions.Latex_Function_Wrap import PDF_Localize - + from crazy_functions.Internet_GPT import 连接网络回答问题 + from crazy_functions.Internet_GPT_Wrap import NetworkGPT_Wrap function_plugins = { "虚空终端": { @@ -196,6 +197,7 @@ def get_crazy_functions(): }, "保存当前的对话": { "Group": "对话", + "Color": "stop", "AsButton": True, "Info": "保存当前的对话 | 不需要输入参数", "Function": HotReload(对话历史存档), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用 @@ -203,13 +205,23 @@ def get_crazy_functions(): }, "[多线程Demo]解析此项目本身(源码自译解)": { "Group": "对话|编程", + "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "多线程解析并翻译此项目的源码 | 不需要输入参数", "Function": HotReload(解析项目本身), }, + "查互联网后回答": { + "Group": "对话", + "Color": "stop", + "AsButton": True, # 加入下拉菜单中 + # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题", + "Function": HotReload(连接网络回答问题), + "Class": NetworkGPT_Wrap # 新一代插件需要注册Class + }, "历史上的今天": { "Group": "对话", - "AsButton": True, + "Color": "stop", + "AsButton": False, "Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数", "Function": None, "Class": Demo_Wrap, # 新一代插件需要注册Class @@ -360,36 +372,36 @@ def get_crazy_functions(): print(trimmed_format_exc()) print("Load function plugin failed") - try: - from crazy_functions.联网的ChatGPT import 连接网络回答问题 + # try: + # from crazy_functions.联网的ChatGPT import 连接网络回答问题 - function_plugins.update( - { - "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题", - "Function": HotReload(连接网络回答问题), - } - } - ) - from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题 + # function_plugins.update( + # { + # "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": { + # "Group": "对话", + # "Color": "stop", + # "AsButton": False, # 加入下拉菜单中 + # # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题", + # "Function": HotReload(连接网络回答问题), + # } + # } + # ) + # from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题 - function_plugins.update( - { - "连接网络回答问题(中文Bing版,输入问题后点击该插件)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题", - "Function": HotReload(连接bing搜索回答问题), - } - } - ) - except: - print(trimmed_format_exc()) - print("Load function plugin failed") + # function_plugins.update( + # { + # "连接网络回答问题(中文Bing版,输入问题后点击该插件)": { + # "Group": "对话", + # "Color": "stop", + # "AsButton": False, # 加入下拉菜单中 + # "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题", + # "Function": HotReload(连接bing搜索回答问题), + # } + # } + # ) + # except: + # print(trimmed_format_exc()) + # print("Load function plugin failed") try: from crazy_functions.解析项目源代码 import 解析任意code项目 diff --git a/crazy_functions/Internet_GPT.py b/crazy_functions/Internet_GPT.py index 25a651f8..34ea0a5b 100644 --- a/crazy_functions/Internet_GPT.py +++ b/crazy_functions/Internet_GPT.py @@ -1,4 +1,4 @@ -from toolbox import CatchException, update_ui +from toolbox import CatchException, update_ui, get_conf from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping import requests from bs4 import BeautifulSoup @@ -6,7 +6,6 @@ from request_llms.bridge_all import model_info import urllib.request from functools import lru_cache - @lru_cache def get_auth_ip(): try: @@ -15,12 +14,16 @@ def get_auth_ip(): except: return '114.114.114.114' -def searxng_request(query, proxies): - url = 'https://cloud-1.agent-matrix.com/' # 请替换为实际的API URL +def searxng_request(query, proxies, categories='general', searxng_url=None): + if searxng_url is None: + url = get_conf("SEARXNG_URL") + else: + url = searxng_url params = { 'q': query, # 搜索查询 'format': 'json', # 输出格式为JSON 'language': 'zh', # 搜索语言 + 'categories': categories } headers = { 'Accept-Language': 'zh-CN,zh;q=0.9', @@ -41,7 +44,10 @@ def searxng_request(query, proxies): results.append(item) return results else: - raise ValueError("搜索失败,状态码: " + str(response.status_code) + '\t' + response.content.decode('utf-8')) + if response.status_code == 429: + raise ValueError("Searxng(在线搜索服务)当前使用人数太多,请稍后。") + else: + raise ValueError("在线搜索失败,状态码: " + str(response.status_code) + '\t' + response.content.decode('utf-8')) def scrape_text(url, proxies) -> str: """Scrape text from a webpage @@ -72,29 +78,23 @@ def scrape_text(url, proxies) -> str: @CatchException def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数,暂时没有用武之地 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) - """ + history = [] # 清空历史,以免输入溢出 chatbot.append((f"请结合互联网信息回答以下问题:{txt}", "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该模板可以实现ChatGPT联网信息综合。该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板。您若希望分享新的功能模组,请不吝PR!")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # ------------- < 第1步:爬取搜索引擎的结果 > ------------- from toolbox import get_conf proxies = get_conf('proxies') - urls = searxng_request(txt, proxies) + categories = plugin_kwargs.get('categories', 'general') + searxng_url = plugin_kwargs.get('searxng_url', None) + urls = searxng_request(txt, proxies, categories, searxng_url) history = [] if len(urls) == 0: chatbot.append((f"结论:{txt}", "[Local Message] 受到google限制,无法从google获取信息!")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return # ------------- < 第2步:依次访问网页 > ------------- max_search_result = 5 # 最多收纳多少个网页的结果 @@ -102,14 +102,14 @@ def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, s res = scrape_text(url['link'], proxies) history.extend([f"第{index}份搜索结果:", res]) chatbot.append([f"第{index}份搜索结果:", res[:500]+"......"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # ------------- < 第3步:ChatGPT综合 > ------------- i_say = f"从以上搜索结果中抽取信息,然后回答问题:{txt}" i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token inputs=i_say, history=history, - max_token_limit=model_info[llm_kwargs['llm_model']]['max_token']*3//4 + max_token_limit=min(model_info[llm_kwargs['llm_model']]['max_token']*3//4, 8192) ) gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( inputs=i_say, inputs_show_user=i_say, diff --git a/crazy_functions/Internet_GPT_Wrap.py b/crazy_functions/Internet_GPT_Wrap.py new file mode 100644 index 00000000..c05f44c0 --- /dev/null +++ b/crazy_functions/Internet_GPT_Wrap.py @@ -0,0 +1,42 @@ + +from toolbox import get_conf +from crazy_functions.Internet_GPT import 连接网络回答问题 +from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty + + +class NetworkGPT_Wrap(GptAcademicPluginTemplate): + def __init__(self): + """ + 请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎! + """ + pass + + def define_arg_selection_menu(self): + """ + 定义插件的二级选项菜单 + + 第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值; + 第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值; + 第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值; + + """ + gui_definition = { + "main_input": + ArgProperty(title="输入问题", description="待通过互联网检索的问题", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步 + "categories": + ArgProperty(title="搜索分类", options=["网页", "学术论文"], default_value="网页", description="无", type="dropdown").model_dump_json(), + "searxng_url": + ArgProperty(title="Searxng服务地址", description="输入Searxng的地址", default_value=get_conf("SEARXNG_URL"), type="string").model_dump_json(), # 主输入,自动从输入框同步 + + } + return gui_definition + + def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): + """ + 执行插件 + """ + if plugin_kwargs["categories"] == "网页": plugin_kwargs["categories"] = "general" + if plugin_kwargs["categories"] == "学术论文": plugin_kwargs["categories"] = "science" + + yield from 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request) +