From a0cf090f264c4dfc797f8b0d043eeed09ab3d590 Mon Sep 17 00:00:00 2001 From: Cassius0924 <2670226747@qq.com> Date: Thu, 29 Feb 2024 20:29:52 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20Discord=E6=B6=88=E6=81=AF=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++- atest.py | 0 config.yaml.example | 10 ++- wechatter/config/parsers/__init__.py | 4 + ...ord_message_forwarding_rule_list_parser.py | 30 +++++++ wechatter/config/validate.py | 2 + wechatter/message/message_forwarder.py | 85 ++++++++++++++++--- wechatter/message/message_handler.py | 35 ++++++-- wechatter/sender/sender.py | 23 ++++- 9 files changed, 181 insertions(+), 22 deletions(-) delete mode 100644 atest.py create mode 100644 wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py diff --git a/README.md b/README.md index 05808891..c8d43779 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ python3 -m wechatter ![official_account_reminder_show](docs/images/official_account_reminder_show.png) - [x] **定时任务**:大部分命令均支持定时任务。需进行[配置](#%EF%B8%8F-task-cron-配置)。 +- [x] **Discord 消息转发**:基于 Discord Webhook,将微信消息转发到 Discord 频道。需进行[配置](#%EF%B8%8F-discord-message-forwarding-配置)。 ## 支持的游戏 @@ -190,7 +191,7 @@ python3 -m wechatter | 配置项 | 子项 | 解释 | 备注 | | --- | --- | --- | --- | | `message_forwarding_enabled` | | 功能开关,是否开启消息转发 | 默认为 `False` | -| `message_forwarding_rule_list` | | 消息规则列表,每个规则包含三个字段:`from_list`、`to_person_list` 和 `to_group_list` | | +| `message_forwarding_rule_list` | | 消息规则列表,每个规则包含四个字段:`from_list`、`from_list_exclude`、`to_person_list` 和 `to_group_list` | | | | `from_list` | 消息转发来源列表,即消息发送者 | 可以填多个用户名称或群名称,若要转发所有消息则使用 `["%ALL"]` | | | `from_list_exclude` | 消息转发来源排除列表,不转发此列表的用户和群 | 只在 `from_list` 为 `["%ALL"]` 时生效 | | | `to_person_list` | 消息转发目标用户列表,即消息接收用户 | 可以填多个用户名称或为空列表 | @@ -223,6 +224,17 @@ python3 -m wechatter 关于命令名称可选值请参阅[自定义命令关键词配置详细](docs/custom_command_key_config_detail.md)。 +### ⚙️ Discord Message Forwarding 配置 + +| 配置项 | 解释 | 备注 | +| --- | --- | --- | +| `discord_message_forwarding_enabled` | 功能开关,是否开启 Discord 消息转发 | 默认为 `False` | +| `discord_message_forwarding_rule_list` | 消息规则列表,每个规则包含三个字段:`from_list`、`to_discord_webhook_url` 和 `to_discord_webhook_name` | | +| | `from_list` | 消息转发来源列表,即消息发送者 | 可以填多个用户名称或群名称,若要转发所有消息则使用 `["%ALL"]` | +| | `from_list_exclude` | 消息转发来源排除列表,不转发此列表的用户和群 | 只在 `from_list` 为 `["%ALL"]` 时生效 | +| | `discord_webhook_url` | 消息转发目标 Discord Webhook URL | | + + ## 日志文件 日志文件存放在项目根目录下的 `logs/` 文件夹中。 diff --git a/atest.py b/atest.py deleted file mode 100644 index e69de29b..00000000 diff --git a/config.yaml.example b/config.yaml.example index d8175d27..1536cf77 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -83,4 +83,12 @@ custom_command_key_dict: gpt4: [ ">" ] bili-hot: [ "bh" ] play: [ "p" ] - weather: [ "w", "温度" ] \ No newline at end of file + weather: [ "w", "温度" ] + + +# Discord Message Forwarding:Discord 消息转发 +discord_message_forwarding_enabled: True +discord_message_forwarding_rule_list: + - from_list: [ "%ALL" ] + from_list_exclude: [ "" ] + webhook_url: "your_discord_webhook_url" diff --git a/wechatter/config/parsers/__init__.py b/wechatter/config/parsers/__init__.py index d00973f9..087cb1fd 100644 --- a/wechatter/config/parsers/__init__.py +++ b/wechatter/config/parsers/__init__.py @@ -1,3 +1,6 @@ +from .discord_message_forwarding_rule_list_parser import ( + parse_discord_message_forwarding_rule_list, +) from .message_forwarding_rule_list_parser import parse_message_forwarding_rule_list from .official_account_reminder_rule_list_parser import ( parse_official_account_reminder_rule_list, @@ -8,4 +11,5 @@ "parse_task_cron_list", "parse_message_forwarding_rule_list", "parse_official_account_reminder_rule_list", + "parse_discord_message_forwarding_rule_list", ] diff --git a/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py new file mode 100644 index 00000000..1e9f2ec4 --- /dev/null +++ b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py @@ -0,0 +1,30 @@ +from typing import Dict, List, Tuple + + +def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, Dict]: + """ + 解析消息转发规则列表 + :param rule_list: 消息转发规则列表 + :return: 转发规则元组,第一个元素为全局转发规则,第二个元素为特定转发规则 + """ + all_message_rule = { + "from_list_exclude": [], + "webhook_url": "", + } + specific_message_rules = {} + for rule in rule_list: + if "%ALL" in rule["from_list"]: + all_message_rule["from_list_exclude"].extend( + rule.get("from_list_exclude", []) + ) + all_message_rule["webhook_url"] = rule.get("webhook_url", "") + else: + for from_name in rule["from_list"]: + if from_name not in specific_message_rules: + specific_message_rules[from_name] = { + "webhook_url": "", + } + specific_message_rules[from_name]["webhook_url"] = rule.get( + "webhook_url", "" + ) + return all_message_rule, specific_message_rules diff --git a/wechatter/config/validate.py b/wechatter/config/validate.py index e3d646ee..00169d83 100644 --- a/wechatter/config/validate.py +++ b/wechatter/config/validate.py @@ -18,6 +18,8 @@ "official_account_reminder_rule_list", "all_task_cron_enabled", "task_cron_list", + "discord_message_forwarding_enabled", + "discord_message_forwarding_rule_list", ] diff --git a/wechatter/message/message_forwarder.py b/wechatter/message/message_forwarder.py index 41b6747b..2ed9b0ed 100644 --- a/wechatter/message/message_forwarder.py +++ b/wechatter/message/message_forwarder.py @@ -3,6 +3,7 @@ from loguru import logger from wechatter.config.parsers import ( + parse_discord_message_forwarding_rule_list, parse_message_forwarding_rule_list, parse_official_account_reminder_rule_list, ) @@ -41,32 +42,61 @@ class MessageForwarder: 消息转发器类 """ - def __init__( - self, - message_forwarding_rule_list: List, - official_account_reminder_rule_list: List, - ): + def __init__(self): + self.all_message_rule = (None,) + self.specific_message_rules = (None,) + self.official_account_reminder_rule = None + self.official_account_reminder_type = "text" + self.discord_all_message_rule = None + self.discord_message_forwarding_rule = None + + def set_wechat_forwarding_rule(self, message_forwarding_rule_list: List): """ - 初始化 + 设置微信消息转发规则 :param message_forwarding_rule_list: 消息转发规则列表 - :param official_account_reminder_rule_list: 公众号文章提醒规则列表 """ ( self.all_message_rule, self.specific_message_rules, ) = parse_message_forwarding_rule_list(message_forwarding_rule_list) + + def set_official_account_reminder_rule( + self, official_account_reminder_rule_list: List + ): + """ + 设置公众号提醒规则 + :param official_account_reminder_rule_list: 公众号提醒规则列表 + """ self.official_account_reminder_rule = parse_official_account_reminder_rule_list( official_account_reminder_rule_list ) - self.official_account_reminder_type = "text" - def forwarding(self, message_obj: Message): + def set_discord_forwarding_rule(self, discord_message_forwarding_rule_list: List): + """ + 设置 Discord 消息转发规则 + :param discord_message_forwarding_rule_list: Discord 消息转发规则列表 + """ + ( + self.discord_all_message_rule, + self.discord_specific_message_rules, + ) = parse_discord_message_forwarding_rule_list( + discord_message_forwarding_rule_list + ) + + def forwarding_to_wechat(self, message_obj: Message): """ 消息转发 :param message_obj: 消息对象 """ # TODO: 转发文件 + # 判断是否设置了转发规则 + if not self.all_message_rule and not self.specific_message_rules: + logger.warning( + "消息转发器未设置转发规则,self.all_message_rule 和 self.specific_message_rules 均为空" + ) + return + # 判断消息来源是否符合转发规则 if self.all_message_rule: rule = self.all_message_rule @@ -77,7 +107,7 @@ def forwarding(self, message_obj: Message): _forwarding_by_rule(message_obj, rule) @staticmethod - def reply_forwarded_message(message_obj: Message): + def reply_wechat_forwarded_message(message_obj: Message): """ 回复转发消息 :param message_obj: 消息对象 @@ -98,6 +128,12 @@ def remind_official_account_article(self, message_obj: Message): """ if not message_obj.is_official_account: return + # 判断是否设置了提醒规则 + if not self.official_account_reminder_rule: + logger.warning( + "消息转发器未设置公众号提醒规则,self.official_account_reminder_rule 为空" + ) + return if message_obj.sender_name in self.official_account_reminder_rule: rule = self.official_account_reminder_rule[message_obj.sender_name] to_person_list = rule["to_person_list"] @@ -128,6 +164,34 @@ def remind_official_account_article(self, message_obj: Message): is_group=is_group, ) + def forwarding_to_discord(self, message_obj: Message): + """ + 转发消息到 Discord + :param message_obj: 消息对象 + """ + if ( + not self.discord_all_message_rule + and not self.discord_specific_message_rules + ): + logger.warning( + "消息转发器未设置 Discord 转发规则,self.discord_message_forwarding_rule 为空" + ) + return + + if self.discord_all_message_rule: + rule = self.discord_all_message_rule + webhook_url = rule["webhook_url"] + sender.send_to_discord( + webhook_url, message_obj.content, message_obj.person, message_obj.group + ) + + if message_obj.sender_name in self.discord_specific_message_rules: + rule = self.discord_specific_message_rules[message_obj.sender_name] + webhook_url = rule["webhook_url"] + sender.send_to_discord( + webhook_url, message_obj.content, message_obj.person, message_obj.group + ) + def _construct_official_account_reminder_message(message_obj: Message) -> str: """ @@ -145,6 +209,7 @@ def _construct_official_account_reminder_image(message_obj: Message) -> str: """ 构造公众号文章提醒图片 """ + # TODO: 构造公众号文章提醒图片 # title = message_obj.urllink.title return "开发中..." pass diff --git a/wechatter/message/message_handler.py b/wechatter/message/message_handler.py index d855a256..871863c7 100644 --- a/wechatter/message/message_handler.py +++ b/wechatter/message/message_handler.py @@ -9,12 +9,18 @@ from wechatter.message.message_forwarder import MessageForwarder from wechatter.models.wechat import Message, SendTo -message_forwarding_enabled = False +message_forwarder = MessageForwarder() if config["message_forwarding_enabled"]: - message_forwarding_enabled = True - message_forwarder = MessageForwarder( - config["message_forwarding_rule_list"], - config["official_account_reminder_rule_list"], + message_forwarder.set_wechat_forwarding_rule(config["message_forwarding_rule_list"]) + +if config["official_account_reminder_enabled"]: + message_forwarder.set_official_account_reminder_rule( + config["official_account_reminder_rule_list"] + ) + +if config["discord_message_forwarding_enabled"]: + message_forwarder.set_discord_forwarding_rule( + config["discord_message_forwarding_rule_list"] ) @@ -43,20 +49,31 @@ def handle_message(self, message_obj: Message): :param message_obj: 消息对象 """ # 公众号文章提醒 - if message_obj.is_official_account and message_obj.type.value == "urlLink": + if ( + config["official_account_reminder_enabled"] + and message_obj.is_official_account + and message_obj.type.value == "urlLink" + ): # 尝试提醒 message_forwarder.remind_official_account_article(message_obj) return # 消息转发 - if message_forwarding_enabled and not message_obj.is_official_account: + if config["message_forwarding_enabled"] and not message_obj.is_official_account: # 尝试进行消息转发 - message_forwarder.forwarding(message_obj) + message_forwarder.forwarding_to_wechat(message_obj) # 尝试进行转发消息的回复 if message_obj.forwarded_source: - message_forwarder.reply_forwarded_message(message_obj) + message_forwarder.reply_wechat_forwarded_message(message_obj) return + # Discord消息转发 + if ( + config["discord_message_forwarding_enabled"] + and not message_obj.is_official_account + ): + message_forwarder.forwarding_to_discord(message_obj) + to = SendTo(person=message_obj.person, group=message_obj.group) # 解析命令 diff --git a/wechatter/sender/sender.py b/wechatter/sender/sender.py index 87ec6508..322518fa 100644 --- a/wechatter/sender/sender.py +++ b/wechatter/sender/sender.py @@ -45,7 +45,11 @@ def _logging(func): def logging_wrapper(*args, **kwargs): response = func(*args, **kwargs) - r_json = response.json() + try: + r_json = response.json() + except requests.exceptions.JSONDecodeError: + logger.debug("请求返回值 JSON 解析失败") + return # https://github.com/danni-cool/wechatbot-webhook?tab=readme-ov-file#%E8%BF%94%E5%9B%9E%E5%80%BC-response-%E7%BB%93%E6%9E%84 if r_json["message"].startswith("Message"): pass @@ -425,3 +429,20 @@ def mass_send_msg_to_github_webhook_receivers( is_group=True, type=type, ) + + +def send_to_discord(webhook_url: str, message: str, person, group=None): + """ + 发送消息到 Discord + :param webhook_url: Discord 频道 Webhook URL + :param message: 消息内容 + :param person: 用户 + :param group: 群组 + """ + data = {"username": "", "content": message} + if group: + data["username"] = f"WeChatter [{group.name}]-[{person.name}]" + else: + data["username"] = f"WeChatter [{person.name}]" + + _post_request(webhook_url, json=data) From a5812abca13fe20921d8cbf99675a9b6f2f6a4c3 Mon Sep 17 00:00:00 2001 From: Cassius0924 <2670226747@qq.com> Date: Mon, 4 Mar 2024 10:37:47 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20discord=E6=B6=88=E6=81=AF=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 35 +++++++++---------- ...ord_message_forwarding_rule_list_parser.py | 11 +++--- wechatter/config/validate.py | 13 +++++-- wechatter/message/message_handler.py | 9 ----- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2cf44dd5..6dfc7e73 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,20 +1,19 @@ default_language_version: - python: python3.8 - + python: python3.8 repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.14 - hooks: - - id: ruff - - id: ruff-format -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - name: isort (python) -- repo: https://github.com/PyCQA/bandit - rev: 1.7.7 - hooks: - - id: bandit - args: ['-c', 'pyproject.toml'] - + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.14 + hooks: + - id: ruff + - id: ruff-format + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + name: isort (python) + - repo: https://github.com/PyCQA/bandit + rev: 1.7.7 + hooks: + - id: bandit + args: ['-c', 'pyproject.toml'] + additional_dependencies: ["bandit[toml]"] diff --git a/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py index 1e9f2ec4..080a8800 100644 --- a/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py +++ b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py @@ -7,7 +7,9 @@ def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, D :param rule_list: 消息转发规则列表 :return: 转发规则元组,第一个元素为全局转发规则,第二个元素为特定转发规则 """ + # TODO:用is_none来判断 all_message_rule = { + "is_none": True, "from_list_exclude": [], "webhook_url": "", } @@ -17,14 +19,13 @@ def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, D all_message_rule["from_list_exclude"].extend( rule.get("from_list_exclude", []) ) - all_message_rule["webhook_url"] = rule.get("webhook_url", "") + all_message_rule["webhook_url"] = rule["webhook_url"] else: for from_name in rule["from_list"]: if from_name not in specific_message_rules: specific_message_rules[from_name] = { - "webhook_url": "", + "from_list_exclude": [], + "webhook_url": [], } - specific_message_rules[from_name]["webhook_url"] = rule.get( - "webhook_url", "" - ) + specific_message_rules[from_name]["webhook_url"] = rule["webhook_url"] return all_message_rule, specific_message_rules diff --git a/wechatter/config/validate.py b/wechatter/config/validate.py index 00169d83..88d39b5e 100644 --- a/wechatter/config/validate.py +++ b/wechatter/config/validate.py @@ -47,10 +47,10 @@ def validate_config(config): # raise ValueError(error_msg) # 定时任务配置 - task_cron_ess_fields = ["task", "cron", "commands"] + ess_fields = ["task", "cron", "commands"] for i, task_cron in enumerate(config["task_cron_list"]): # task_cron_list 字段验证 - for field in task_cron_ess_fields: + for field in ess_fields: if field not in task_cron: error_msg = f"配置参数错误:task_cron_list[{i}] 缺少必要字段 {field}" logger.critical(error_msg) @@ -75,4 +75,13 @@ def validate_config(config): logger.critical(error_msg) raise ValueError(error_msg) + # Discord 消息转发配置 + ess_fields = ["from_list", "webhook_url"] + for i, rule in enumerate(config["discord_message_forwarding_rule_list"]): + for field in ess_fields: + if field not in rule: + error_msg = f"配置参数错误:discord_message_forwarding_rule_list[{i}] 缺少必要字段 {field}" + logger.critical(error_msg) + raise ValueError(error_msg) + logger.info("配置文件验证通过!") diff --git a/wechatter/message/message_handler.py b/wechatter/message/message_handler.py index 871863c7..1d51005b 100644 --- a/wechatter/message/message_handler.py +++ b/wechatter/message/message_handler.py @@ -107,15 +107,6 @@ def handle_message(self, message_obj: Message): else: logger.debug("该消息不是命令类型") - # game_name = self.__get_game(content, message_obj.is_mentioned, message_obj.is_group) - # # 是游戏命令 - # if game_name: - # game_class = self.games[game_name]["class"] - # logger.info(self.games[game_name]["desc"]) - # _execute_game(game, game_class, to, content, message_obj) - # else: - # logger.debug("该消息不是游戏类型") - def __parse_command(self, content: str, is_mentioned: bool, is_group: bool) -> Dict: """ 解析命令 From c0404fda37085cba423029d5edd140c467d440b8 Mon Sep 17 00:00:00 2001 From: Cassius0924 <2670226747@qq.com> Date: Mon, 4 Mar 2024 11:01:49 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20discord=E6=B6=88=E6=81=AF=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E6=89=80=E6=9C=89=E4=BA=BA=E5=88=A4=E6=96=AD=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../discord_message_forwarding_rule_list_parser.py | 3 +-- .../config/parsers/message_forwarding_rule_list_parser.py | 2 ++ wechatter/message/message_forwarder.py | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py index 080a8800..24d8e399 100644 --- a/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py +++ b/wechatter/config/parsers/discord_message_forwarding_rule_list_parser.py @@ -7,7 +7,6 @@ def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, D :param rule_list: 消息转发规则列表 :return: 转发规则元组,第一个元素为全局转发规则,第二个元素为特定转发规则 """ - # TODO:用is_none来判断 all_message_rule = { "is_none": True, "from_list_exclude": [], @@ -16,6 +15,7 @@ def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, D specific_message_rules = {} for rule in rule_list: if "%ALL" in rule["from_list"]: + all_message_rule["is_none"] = False all_message_rule["from_list_exclude"].extend( rule.get("from_list_exclude", []) ) @@ -24,7 +24,6 @@ def parse_discord_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, D for from_name in rule["from_list"]: if from_name not in specific_message_rules: specific_message_rules[from_name] = { - "from_list_exclude": [], "webhook_url": [], } specific_message_rules[from_name]["webhook_url"] = rule["webhook_url"] diff --git a/wechatter/config/parsers/message_forwarding_rule_list_parser.py b/wechatter/config/parsers/message_forwarding_rule_list_parser.py index dc62c826..27ad1336 100644 --- a/wechatter/config/parsers/message_forwarding_rule_list_parser.py +++ b/wechatter/config/parsers/message_forwarding_rule_list_parser.py @@ -8,6 +8,7 @@ def parse_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, Dict]: :return: 转发规则元组,第一个元素为全局转发规则,第二个元素为特定转发规则 """ all_message_rule = { + "is_none": True, "from_list_exclude": [], "to_group_list": [], "to_person_list": [], @@ -15,6 +16,7 @@ def parse_message_forwarding_rule_list(rule_list: List) -> Tuple[Dict, Dict]: specific_message_rules = {} for rule in rule_list: if "%ALL" in rule["from_list"]: + all_message_rule["is_none"] = False all_message_rule["from_list_exclude"].extend( rule.get("from_list_exclude", []) ) diff --git a/wechatter/message/message_forwarder.py b/wechatter/message/message_forwarder.py index 2ed9b0ed..b9c57744 100644 --- a/wechatter/message/message_forwarder.py +++ b/wechatter/message/message_forwarder.py @@ -43,8 +43,8 @@ class MessageForwarder: """ def __init__(self): - self.all_message_rule = (None,) - self.specific_message_rules = (None,) + self.all_message_rule = None + self.specific_message_rules = None self.official_account_reminder_rule = None self.official_account_reminder_type = "text" self.discord_all_message_rule = None @@ -98,7 +98,7 @@ def forwarding_to_wechat(self, message_obj: Message): return # 判断消息来源是否符合转发规则 - if self.all_message_rule: + if not self.all_message_rule["is_none"]: rule = self.all_message_rule _forwarding_by_rule(message_obj, rule) @@ -178,7 +178,7 @@ def forwarding_to_discord(self, message_obj: Message): ) return - if self.discord_all_message_rule: + if not self.discord_all_message_rule["is_none"]: rule = self.discord_all_message_rule webhook_url = rule["webhook_url"] sender.send_to_discord( From 4fc0eec7646bb6ff0a99b1f4c682222715ea9acc Mon Sep 17 00:00:00 2001 From: Cassius0924 <2670226747@qq.com> Date: Mon, 4 Mar 2024 11:33:11 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81OpenAI=E5=AE=98?= =?UTF-8?q?=E6=96=B9API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- config.yaml.example | 6 +++--- wechatter/commands/_commands/copilot_gpt4.py | 12 +++++------- wechatter/config/validate.py | 4 ++-- wechatter/utils/url_joiner.py | 16 ++++++++++++++++ 5 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 wechatter/utils/url_joiner.py diff --git a/README.md b/README.md index c8d43779..ccb49bfd 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ python3 -m wechatter ## 支持的命令 -- [x] GPT 问答,基于 [Copilot-GPT4-Service](https://github.com/aaamoon/copilot-gpt4-service)(不支持定时任务) +- [x] GPT 问答(不支持定时任务) - [x] Bilibili 热搜 - [x] 知乎热搜 - [x] 微博热搜 @@ -170,12 +170,12 @@ python3 -m wechatter | `command_prefix` | 机器人命令前缀 | 默认为 `/` ,可以设置为`>>`、`!` 等任意字符 | | `need_mentioned` | 群聊中的命令是否需要@机器人 | 默认为 `True` | -### ⚙️ Copilot GPT4 配置 +### ⚙️ LLM 配置 | 配置项 | 解释 | 备注 | | --- | --- | --- | -| `cp_gpt4_base_api` | CopilotGPT4 服务的 BaseAPI | 默认为 `http://localhost:8080` | -| `cp_token` | GitHub Copilot 的 Token | 以 `ghu_` 开头的字符串 | +| `openai_base_api` | OpenAI 服务的 BaseAPI | 默认为 `https://api.openai.com` | +| `openai_token` | OpenAI Token(Key) | 以 `sk_` 开头的字符串密钥 | ### ⚙️ GitHub Webhook 配置 diff --git a/config.yaml.example b/config.yaml.example index 1536cf77..521b66f9 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -26,9 +26,9 @@ command_prefix: / need_mentioned: False -# Copilot GPT4 -cp_gpt4_base_api: http://localhost:999 -cp_token: ghu_your_token +# LLM +openai_base_api: https://api.openai.com +openai_token: sk_your_openai_token # GitHub Webhook diff --git a/wechatter/commands/_commands/copilot_gpt4.py b/wechatter/commands/_commands/copilot_gpt4.py index 7eb6d05e..b3be78cb 100644 --- a/wechatter/commands/_commands/copilot_gpt4.py +++ b/wechatter/commands/_commands/copilot_gpt4.py @@ -3,7 +3,6 @@ from loguru import logger -import wechatter.utils.path_manager as pm from wechatter.commands.handlers import command from wechatter.config import config from wechatter.database import ( @@ -16,9 +15,9 @@ from wechatter.sender import sender from wechatter.utils import post_request_json from wechatter.utils.time import get_current_date, get_current_time, get_current_week +from wechatter.utils.url_joiner import join_urls DEFAULT_TOPIC = "(对话进行中*)" -# DEFAULT_MODEL = "gpt-4" # TODO: 初始化对话,Prompt选择 DEFAULT_CONVERSATION = [ { @@ -197,9 +196,8 @@ def _gptx_continue(model: str, to: SendTo, message: str = "") -> None: class CopilotGPT4: - api = f"{config['cp_gpt4_base_api']}/v1/chat/completions" - bearer_token = "Bearer " + config["cp_token"] - save_path = pm.get_abs_path("data/copilot_gpt4/chats/") + chat_api = join_urls(config["openai_base_api"], "v1/chat/completions") + token = "Bearer " + config["openai_token"] @staticmethod def create_chat(person: Person, model: str) -> GptChatInfo: @@ -428,7 +426,7 @@ def _chat(chat_info: GptChatInfo, message: str, message_obj, is_save: bool) -> s newconv = [{"role": "user", "content": message}] # 发送请求 headers = { - "Authorization": CopilotGPT4.bearer_token, + "Authorization": CopilotGPT4.token, "Content-Type": "application/json", } json = { @@ -436,7 +434,7 @@ def _chat(chat_info: GptChatInfo, message: str, message_obj, is_save: bool) -> s "messages": DEFAULT_CONVERSATION + chat_info.get_conversation() + newconv, } r_json = post_request_json( - url=CopilotGPT4.api, headers=headers, json=json, timeout=60 + url=CopilotGPT4.chat_api, headers=headers, json=json, timeout=60 ) # 判断是否有 error 或 code 字段 diff --git a/wechatter/config/validate.py b/wechatter/config/validate.py index 88d39b5e..43739512 100644 --- a/wechatter/config/validate.py +++ b/wechatter/config/validate.py @@ -8,8 +8,8 @@ "bot_name", "command_prefix", "need_mentioned", - "cp_gpt4_base_api", - "cp_token", + "openai_base_api", + "openai_token", "github_webhook_enabled", "github_webhook_api_path", "message_forwarding_enabled", diff --git a/wechatter/utils/url_joiner.py b/wechatter/utils/url_joiner.py new file mode 100644 index 00000000..b6d718da --- /dev/null +++ b/wechatter/utils/url_joiner.py @@ -0,0 +1,16 @@ +from urllib.parse import urljoin + +from loguru import logger + + +def join_urls(base_url, relative_url) -> str: + """ + 拼接 URL + :param base_url: 基础 URL + :param relative_url: 相对 URL + """ + try: + return urljoin(base_url, relative_url) + except TypeError as e: + logger.error(f"拼接 URL 时出错:{e}") + raise TypeError(f"拼接 URL 时出错:{e}")