From e2f1362a1fcdafda5a95c1e7e78e42042942fa7c Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Tue, 9 Jan 2024 22:25:52 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dmyid=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=E5=9C=A8gocq=E5=B9=B3=E5=8F=B0=E4=B8=8A=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E7=94=A8=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cores/qqbot/core.py | 6 +++--- model/command/command.py | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cores/qqbot/core.py b/cores/qqbot/core.py index 797944754..3cc161721 100644 --- a/cores/qqbot/core.py +++ b/cores/qqbot/core.py @@ -347,16 +347,16 @@ def run_qqchan_bot(cfg: dict, global_object: GlobalObject): def run_gocq_bot(cfg: dict, _global_object: GlobalObject): from model.platform.qq_gocq import QQGOCQ - gu.log("正在检查本地GO-CQHTTP连接...端口5700, 6700", tag="QQ") + gu.log("正在检查与 go-cqhttp 的连接...端口5700, 6700", tag="QQ") noticed = False while True: if not gu.port_checker(5700, cc.get("gocq_host", "127.0.0.1")) or not gu.port_checker(6700, cc.get("gocq_host", "127.0.0.1")): if not noticed: noticed = True - gu.log("与GO-CQHTTP通信失败, 请检查GO-CQHTTP是否启动并正确配置。程序会每隔 5s 自动重试。", gu.LEVEL_CRITICAL, tag="QQ") + gu.log("与 go-cqhttp 通信失败, 请检查 go-cqhttp 是否启动并正确配置。程序会每隔 5s 自动重试。", gu.LEVEL_CRITICAL, tag="QQ") time.sleep(5) else: - gu.log("检查完毕,未发现问题。", tag="QQ") + gu.log("成功连接到 go-cqhttp。", tag="QQ") break try: qq_gocq = QQGOCQ(cfg=cfg, message_handler=oper_msg) diff --git a/model/command/command.py b/model/command/command.py index 3a1abd1a6..2100206e5 100644 --- a/model/command/command.py +++ b/model/command/command.py @@ -82,7 +82,7 @@ class Command: if self.command_start_with(message, "plugin"): return True, self.plugin_oper(message, role, cached_plugins, platform) if self.command_start_with(message, "myid") or self.command_start_with(message, "!myid"): - return True, self.get_my_id(message_obj) + return True, self.get_my_id(message_obj, platform) if self.command_start_with(message, "nconf") or self.command_start_with(message, "newconf"): return True, self.get_new_conf(message, role) if self.command_start_with(message, "web"): # 网页搜索 @@ -105,8 +105,14 @@ class Command: return True, "已关闭网页搜索", "web" return True, f"网页搜索功能当前状态: {self.global_object.web_search}", "web" - def get_my_id(self, message_obj): - return True, f"你的ID:{str(message_obj.sender.tiny_id)}", "plugin" + def get_my_id(self, message_obj, platform): + user_id = "Unknown" + if platform == PLATFORM_QQCHAN: + user_id = str(message_obj.sender.tiny_id) + elif platform == PLATFORM_GOCQ: + user_id = str(message_obj.user_id) + + return True, f"你的ID:{user_id}", "plugin" def get_new_conf(self, message, role): if role != "admin": From 570ff4e8b6e584951d8777678582e5540d135aeb Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Wed, 10 Jan 2024 16:48:46 +0800 Subject: [PATCH 2/3] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96bing=E7=BD=91?= =?UTF-8?q?=E9=A1=B5=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/platform/qq_gocq.py | 47 ++++++++------- model/provider/openai_official.py | 4 +- util/function_calling/gplugin.py | 96 ++++++++++++++----------------- 3 files changed, 68 insertions(+), 79 deletions(-) diff --git a/model/platform/qq_gocq.py b/model/platform/qq_gocq.py index 01b76106d..57b9bf301 100644 --- a/model/platform/qq_gocq.py +++ b/model/platform/qq_gocq.py @@ -8,7 +8,8 @@ from nakuru import ( GroupMessage, FriendMessage, GroupMemberIncrease, - Notify + Notify, + Member ) from typing import Union import time @@ -37,12 +38,10 @@ class QQGOCQ(Platform): try: self.nick_qq = cfg['nick_qq'] except: - self.nick_qq = ("ai","!","!") + self.nick_qq = ["ai","!","!"] nick_qq = self.nick_qq if isinstance(nick_qq, str): - nick_qq = (nick_qq,) - if isinstance(nick_qq, list): - nick_qq = tuple(nick_qq) + nick_qq = [nick_qq] self.unique_session = cfg['uniqueSessionMode'] self.pic_mode = cfg['qq_pic_mode'] @@ -60,11 +59,9 @@ class QQGOCQ(Platform): async def _(app: CQHTTP, source: GroupMessage): if self.cc.get("gocq_react_group", True): if isinstance(source.message[0], Plain): - # await self.handle_msg(source, True) self.new_sub_thread(self.handle_msg, (source, True)) elif isinstance(source.message[0], At): if source.message[0].qq == source.self_id: - # await self.handle_msg(source, True) self.new_sub_thread(self.handle_msg, (source, True)) else: return @@ -73,7 +70,6 @@ class QQGOCQ(Platform): async def _(app: CQHTTP, source: FriendMessage): if self.cc.get("gocq_react_friend", True): if isinstance(source.message[0], Plain): - # await self.handle_msg(source, False) self.new_sub_thread(self.handle_msg, (source, False)) else: return @@ -112,22 +108,25 @@ class QQGOCQ(Platform): async def handle_msg(self, message: Union[GroupMessage, FriendMessage, GuildMessage, Notify], is_group: bool): # 判断是否响应消息 resp = False - for i in message.message: - if isinstance(i, At): - if message.type == "GuildMessage": - if i.qq == message.user_id or i.qq == message.self_tiny_id: - resp = True - if message.type == "FriendMessage": - if i.qq == message.self_id: - resp = True - if message.type == "GroupMessage": - if i.qq == message.self_id: - resp = True - elif isinstance(i, Plain): - for nick in self.nick_qq: - if nick != '' and i.text.strip().startswith(nick): - resp = True - break + if not is_group: + resp = True + else: + for i in message.message: + if isinstance(i, At): + if message.type == "GuildMessage": + if i.qq == message.user_id or i.qq == message.self_tiny_id: + resp = True + if message.type == "FriendMessage": + if i.qq == message.self_id: + resp = True + if message.type == "GroupMessage": + if i.qq == message.self_id: + resp = True + elif isinstance(i, Plain): + for nick in self.nick_qq: + if nick != '' and i.text.strip().startswith(nick): + resp = True + break if not resp: return diff --git a/model/provider/openai_official.py b/model/provider/openai_official.py index d24611eb4..41a8df5ff 100644 --- a/model/provider/openai_official.py +++ b/model/provider/openai_official.py @@ -29,7 +29,7 @@ class ProviderOpenAIOfficial(Provider): if cfg['key'] != '' and cfg['key'] != None: self.key_list = cfg['key'] else: - input("[System] 请先去完善ChatGPT的Key。详情请前往https://beta.openai.com/account/api-keys") + input("[System] 请先填写 Key。详情请前往 https://beta.openai.com/account/api-keys 或使用中转 Key 方案。") if len(self.key_list) == 0: raise Exception("您打开了 OpenAI 模型服务,但是未填写 key。请前往填写。") @@ -239,7 +239,7 @@ class ProviderOpenAIOfficial(Provider): err = str(e) retry += 1 if retry >= 10: - gu.log(r"如果报错, 且您的机器在中国大陆内, 请确保您的电脑已经设置好代理软件(梯子), 并在配置文件设置了系统代理地址。详见 https://github.com/Soulter/QQChannelChatGPT/wiki", max_len=999) + gu.log(r"如果报错, 且您的机器在中国大陆内且未使用国内中转Key服务, 请确保您的电脑已经设置好代理软件(梯子), 并在配置文件设置了系统代理地址。", max_len=999) raise BaseException("连接出错: "+str(err)) assert isinstance(response, ChatCompletion) gu.log(f"OPENAI RESPONSE: {response.usage}", level=gu.LEVEL_DEBUG, max_len=9999) diff --git a/util/function_calling/gplugin.py b/util/function_calling/gplugin.py index d6a4f4f14..8cba715aa 100644 --- a/util/function_calling/gplugin.py +++ b/util/function_calling/gplugin.py @@ -53,6 +53,7 @@ def google_web_search(keyword) -> str: for i in ls: desc = i.description try: + gu.log(f"搜索网页: {i.url}", tag="网页搜索", level=gu.LEVEL_INFO) desc = fetch_website_content(i.url) except BaseException as e: print(f"(google) fetch_website_content err: {str(e)}") @@ -74,51 +75,54 @@ def web_keyword_search_via_bing(keyword) -> str: } url = "https://www.bing.com/search?q="+keyword _cnt = 0 - _detail_store = [] + # _detail_store = [] while _cnt < 5: try: response = requests.get(url, headers=headers) response.encoding = "utf-8" gu.log(f"bing response: {response.text}", tag="bing", level=gu.LEVEL_DEBUG, max_len=9999) soup = BeautifulSoup(response.text, "html.parser") - res = [] + res = "" + result_cnt = 0 ols = soup.find(id="b_results") for i in ols.find_all("li", class_="b_algo"): try: title = i.find("h2").text desc = i.find("p").text link = i.find("h2").find("a").get("href") - res.append({ - "title": title, - "desc": desc, - "link": link, - }) - if len(res) >= 5: # 限制5条 - break - if len(_detail_store) >= 3: - continue + # res.append({ + # "title": title, + # "desc": desc, + # "link": link, + # }) + try: + gu.log(f"搜索网页: {link}", tag="网页搜索", level=gu.LEVEL_INFO) + desc = fetch_website_content(link) + except BaseException as e: + print(f"(bing) fetch_website_content err: {str(e)}") - # 爬取前两条的网页内容 - if "zhihu.com" in link: - try: - _detail_store.append(special_fetch_zhihu(link)) - except BaseException as e: - print(f"zhihu parse err: {str(e)}") - else: - try: - _detail_store.append(fetch_website_content(link)) - except BaseException as e: - print(f"fetch_website_content err: {str(e)}") + res += f"# No.{str(result_cnt + 1)}\ntitle: {title}\nurl: {link}\ncontent: {desc}\n\n" + result_cnt += 1 + if result_cnt > 5: break + + # if len(_detail_store) >= 3: + # continue + # # 爬取前两条的网页内容 + # if "zhihu.com" in link: + # try: + # _detail_store.append(special_fetch_zhihu(link)) + # except BaseException as e: + # print(f"zhihu parse err: {str(e)}") + # else: + # try: + # _detail_store.append(fetch_website_content(link)) + # except BaseException as e: + # print(f"fetch_website_content err: {str(e)}") except Exception as e: print(f"bing parse err: {str(e)}") - if len(res) == 0: - break - if len(_detail_store) > 0: - ret = f"{str(res)} \n具体网页内容: {str(_detail_store)}" - else: - ret = f"{str(res)}" - return str(ret) + if result_cnt == 0: break + return res except Exception as e: gu.log(f"bing fetch err: {str(e)}") _cnt += 1 @@ -175,26 +179,6 @@ def fetch_website_content(url): } response = requests.get(url, headers=headers, timeout=3) response.encoding = "utf-8" - # soup = BeautifulSoup(response.text, "html.parser") - # # 如果有container / content / main等的话,就只取这些部分 - # has = False - # beleive_ls = ["container", "content", "main"] - # res = "" - # for cls in beleive_ls: - # for i in soup.find_all(class_=cls): - # has = True - # res += i.text - # if not has: - # res = soup.text - # res = res.replace("\n", "").replace(" ", " ").replace("\r", "").replace("\t", "") - # if not has: - # res = res[300:1100] - # else: - # res = res[100:800] - # # with open(f"temp_{time.time()}.html", "w", encoding="utf-8") as f: - # # f.write(res) - # gu.log(f"fetch_website_content: end", tag="fetch_website_content", level=gu.LEVEL_DEBUG) - # return res doc = Document(response.content) # print('title:', doc.title()) ret = doc.summary(html_partial=True) @@ -213,7 +197,7 @@ def web_search(question, provider: Provider, session_id, official_fc=False): "description": "google search query (分词,尽量保留所有信息)" }], "通过搜索引擎搜索。如果问题需要在网页上搜索(如天气、新闻或任何需要通过网页获取信息的问题),则调用此函数;如果没有,不要调用此函数。", - google_web_search + web_keyword_search_via_bing ) new_func_call.add_func("fetch_website_content", [{ "type": "string", @@ -259,13 +243,20 @@ def web_search(question, provider: Provider, session_id, official_fc=False): if has_func: provider.forget(session_id) - question3 = f"""请你用活泼的语气回答`{question}`问题。\n以下是相关材料,请直接拿此材料针对问题进行总结回答。在文章末尾加上各参考链接,如`[1] <url>`;不要提到任何函数调用的信息;在总结的末尾加上1或2个相关的emoji。```\n{function_invoked_ret}\n```\n""" + question3 = f""" +以下是相关材料,你的任务是: +1. 根据材料对问题`{question}`做切题的总结回答; +2. 发表你对这个问题的看法. +你的总结末尾应当有对材料的引用, 如果有链接, 请在末尾附上引用网页链接。引用格式严格按照 `\n[1] title url \n`。 +不要提到任何函数调用的信息。以下是相关材料: +""" + gu.log(f"web_search: {question3}", tag="web_search", level=gu.LEVEL_DEBUG, max_len=99999) _c = 0 while _c < 3: try: print('text chat') - final_ret = provider.text_chat(question3) + final_ret = provider.text_chat(question3 + "```" + function_invoked_ret + "```", session_id) return final_ret except Exception as e: print(e) @@ -275,5 +266,4 @@ def web_search(question, provider: Provider, session_id, official_fc=False): provider.forget(session_id) function_invoked_ret = function_invoked_ret[:int(len(function_invoked_ret) / 2)] time.sleep(3) - question3 = f"""请回答`{question}`问题。\n以下是相关材料,请直接拿此材料针对问题进行回答,再给参考链接, 参考链接首末有空格。```\n{function_invoked_ret}\n```\n""" return function_invoked_ret From 5e8c5067b10f77ecc97c93aa224a040abd0c9a20 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Tue, 16 Jan 2024 00:32:07 +0800 Subject: [PATCH 3/3] Update README.md --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2b62e687c..75fd6c4d3 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ # AstrBot -*✨ 2024 - 希望成为一个跨平台、极易上手、稳定安全的机器人项目。✨* - [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Soulter/AstrBot)](https://github.com/Soulter/AstrBot/releases/latest) <img src="https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/34412545-2e37-400f-bedc-42348713ac1f.svg" alt="wakatime"> <img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python"> @@ -17,10 +15,9 @@ </a> <img alt="Static Badge" src="https://img.shields.io/badge/频道-x42d56aki2-purple"> -<a href="https://astrbot.soulter.top/center">项目主页(开发中)</a> | -<a href="https://astrbot.soulter.top/center/docs/%E9%83%A8%E7%BD%B2/%E9%80%9A%E8%BF%87Docker%E9%83%A8%E7%BD%B2">部署文档</a> | +<a href="https://astrbot.soulter.top/center">项目部署</a> | <a href="https://github.com/Soulter/QQChannelChatGPT/issues">问题提交</a> | -<a href="https://astrbot.soulter.top/center/docs/%E5%BC%80%E5%8F%91/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91">插件开发(最少只需 25 行,真不难!)</a> +<a href="https://astrbot.soulter.top/center/docs/%E5%BC%80%E5%8F%91/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91">插件开发(最少只需 25 行)</a> </div> ## 🤔您可能想了解的