diff --git a/.gitignore b/.gitignore index 5da6953..4203451 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,7 @@ cookies.json res/announcement_saved res/announcement_saved.json cmdpriv.json -tips.py \ No newline at end of file +tips.py +.venv +bin/ +.vscode \ No newline at end of file diff --git a/README.md b/README.md index f2cb90d..1fbdcd6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/RockChinQ/QChatGPT?style=flat-square)](https://github.com/RockChinQ/QChatGPT/releases/latest) +> 2023/4/24 支持使用go-cqhttp登录QQ,请查看[此文档](https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE) > 2023/3/18 现已支持GPT-4 API(内测),请查看`config-template.py`中的`completion_api_params` > 2023/3/15 逆向库已支持New Bing,使用方法查看[插件文档](https://github.com/RockChinQ/revLibs) @@ -192,12 +193,29 @@ - 请使用Python 3.9.x以上版本 -#### 配置Mirai +#### ① 配置QQ登录框架 -按照[此教程](https://yiri-mirai.wybxc.cc/tutorials/01/configuration)配置Mirai及YiriMirai -启动mirai-console后,使用`login`命令登录QQ账号,保持mirai-console运行状态 +目前支持mirai和go-cqhttp,配置任意一个即可 -#### 配置主程序 +
+mirai + +1. 按照[此教程](https://yiri-mirai.wybxc.cc/tutorials/01/configuration)配置Mirai及mirai-api-http +2. 启动mirai-console后,使用`login`命令登录QQ账号,保持mirai-console运行状态 +3. 在下一步配置主程序时请在config.py中将`msg_source_adapter`设为`yirimirai` + +
+ +
+go-cqhttp + +1. 按照[此文档](https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE)配置go-cqhttp +2. 启动go-cqhttp,确保登录成功,保持运行 +3. 在下一步配置主程序时请在config.py中将`msg_source_adapter`设为`nakuru` + +
+ +#### ② 配置主程序 1. 克隆此项目 @@ -209,7 +227,7 @@ cd QChatGPT 2. 安装依赖 ```bash -pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow +pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow nakuru-project-idk ``` 3. 运行一次主程序,生成配置文件 diff --git a/README_en.md b/README_en.md index 068eee4..92ca57b 100644 --- a/README_en.md +++ b/README_en.md @@ -107,11 +107,26 @@ Use [this installer](https://github.com/RockChinQ/qcg-installer) to deploy. - Python 3.9.x or higher -#### Configure Mirai +#### 配置QQ登录框架 + +Currently supports mirai and go-cqhttp, configure either one + +
+mirai Follow [this tutorial(cn)](https://yiri-mirai.wybxc.cc/tutorials/01/configuration) to configure Mirai and YiriMirai. After starting mirai-console, use the `login` command to log in to the QQ account, and keep the mirai-console running. +
+ +
+go-cqhttp + +1. Follow [this tutorial(cn)](https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE) to configure go-cqhttp. +2. Start go-cqhttp, make sure it is logged in and running. + +
+ #### Configure QChatGPT 1. Clone the repository @@ -124,7 +139,7 @@ cd QChatGPT 2. Install dependencies ```bash -pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow +pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow nakuru-project-idk ``` 3. Generate `config.py` diff --git a/config-template.py b/config-template.py index 7568f7d..3ade683 100644 --- a/config-template.py +++ b/config-template.py @@ -3,11 +3,11 @@ import logging # 消息处理协议适配器 # 目前支持以下适配器: -# - "yirimirai": YiriMirai框架适配器, 请填写mirai_http_api_config -# - "nonebot2": NoneBot2框架适配器, 请填写nonebot2_config +# - "yirimirai": mirai的通信框架,YiriMirai框架适配器, 请同时填写下方mirai_http_api_config +# - "nakuru": go-cqhttp通信框架,请同时填写下方nakuru_config msg_source_adapter = "yirimirai" -# [必需] Mirai的配置 +# [必需(与nakuru二选一,取决于msg_source_adapter)] Mirai的配置 # 请到配置mirai的步骤中的教程查看每个字段的信息 # adapter: 选择适配器,目前支持HTTPAdapter和WebSocketAdapter # host: 运行mirai的主机地址 @@ -24,8 +24,14 @@ mirai_http_api_config = { "qq": 1234567890 } -# NoneBot2的配置 -nonebot2_config = {} +# [必需(与mirai二选一,取决于msg_source_adapter)] +# 使用nakuru-project框架连接go-cqhttp的配置 +nakuru_config = { + "host": "localhost", # go-cqhttp的地址 + "port": 6700, # go-cqhttp的正向websocket端口 + "http_port": 5700, # go-cqhttp的正向http端口 + "token": "" # 若在go-cqhttp的config.yml设置了access_token, 则填写此处 +} # [必需] OpenAI的配置 # api_key: OpenAI的API Key diff --git a/main.py b/main.py index fbdd961..725e657 100644 --- a/main.py +++ b/main.py @@ -47,7 +47,7 @@ def init_db(): def ensure_dependencies(): import pkg.utils.pkgmgr as pkgmgr - pkgmgr.run_pip(["install", "openai", "Pillow", "--upgrade", + pkgmgr.run_pip(["install", "openai", "Pillow", "nakuru-project-idk", "--upgrade", "-i", "https://pypi.douban.com/simple/", "--trusted-host", "pypi.douban.com"]) @@ -243,6 +243,8 @@ def start(first_time_init=False): "mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format( e)) else: + import traceback + traceback.print_exc() logging.error( "捕捉到未知异常:{}, 请前往 https://github.com/RockChinQ/QChatGPT/issues 查找或提issue".format(e)) known_exception_caught = True @@ -262,9 +264,14 @@ def start(first_time_init=False): if first_time_init: if not known_exception_caught: - logging.info("QQ: {}, MAH: {}".format(config.mirai_http_api_config['qq'], config.mirai_http_api_config['host']+":"+str(config.mirai_http_api_config['port']))) - logging.info('程序启动完成,如长时间未显示 ”成功登录到账号xxxxx“ ,并且不回复消息,请查看 ' - 'https://github.com/RockChinQ/QChatGPT/issues/37') + import config + if config.msg_source_adapter == "yirimirai": + logging.info("QQ: {}, MAH: {}".format(config.mirai_http_api_config['qq'], config.mirai_http_api_config['host']+":"+str(config.mirai_http_api_config['port']))) + logging.critical('程序启动完成,如长时间未显示 "成功登录到账号xxxxx" ,并且不回复消息,请查看 ' + 'https://github.com/RockChinQ/QChatGPT/issues/37') + elif config.msg_source_adapter == 'nakuru': + logging.info("host: {}, port: {}, http_port: {}".format(config.nakuru_config['host'], config.nakuru_config['port'], config.nakuru_config['http_port'])) + logging.critical('程序启动完成,如长时间未显示 "Protocol: connected" ,并且不回复消息,请检查config.py中的nakuru_config是否正确') else: sys.exit(1) else: diff --git a/override-all.json b/override-all.json index c3f6f1c..737afb3 100644 --- a/override-all.json +++ b/override-all.json @@ -8,7 +8,12 @@ "verifyKey": "yirimirai", "qq": 1234567890 }, - "nonebot2_config": {}, + "nakuru_config": { + "host": "localhost", + "port": 6700, + "http_port": 5700, + "token": "" + }, "openai_config": { "api_key": { "default": "openai_api_key" diff --git a/pkg/qqbot/adapter.py b/pkg/qqbot/adapter.py index 5d4faa0..0d00915 100644 --- a/pkg/qqbot/adapter.py +++ b/pkg/qqbot/adapter.py @@ -79,4 +79,58 @@ class MessageSourceAdapter: bool: 是否成功关闭,热重载时若此函数返回False则不会重载MessageSource底层 """ raise NotImplementedError - \ No newline at end of file + + +class MessageConverter: + """消息链转换器基类""" + @staticmethod + def yiri2target(message_chain: mirai.MessageChain): + """将YiriMirai消息链转换为目标消息链 + + Args: + message_chain (mirai.MessageChain): YiriMirai消息链 + + Returns: + typing.Any: 目标消息链 + """ + raise NotImplementedError + + @staticmethod + def target2yiri(message_chain: typing.Any) -> mirai.MessageChain: + """将目标消息链转换为YiriMirai消息链 + + Args: + message_chain (typing.Any): 目标消息链 + + Returns: + mirai.MessageChain: YiriMirai消息链 + """ + raise NotImplementedError + + +class EventConverter: + """事件转换器基类""" + + @staticmethod + def yiri2target(event: typing.Type[mirai.Event]): + """将YiriMirai事件转换为目标事件 + + Args: + event (typing.Type[mirai.Event]): YiriMirai事件 + + Returns: + typing.Any: 目标事件 + """ + raise NotImplementedError + + @staticmethod + def target2yiri(event: typing.Any) -> mirai.Event: + """将目标事件的调用参数转换为YiriMirai的事件参数对象 + + Args: + event (typing.Any): 目标事件 + + Returns: + typing.Type[mirai.Event]: YiriMirai事件 + """ + raise NotImplementedError diff --git a/pkg/qqbot/manager.py b/pkg/qqbot/manager.py index 747854c..4a1b8c7 100644 --- a/pkg/qqbot/manager.py +++ b/pkg/qqbot/manager.py @@ -80,7 +80,6 @@ class QQBotManager: def __init__(self, first_time_init=True): import config - mirai_http_api_config = config.mirai_http_api_config self.timeout = config.process_message_timeout self.retry = config.retry_times @@ -88,12 +87,17 @@ class QQBotManager: # 故只在第一次初始化时创建bot对象,重载之后使用原bot对象 # 因此,bot的配置不支持热重载 if first_time_init: + logging.info("Use adapter:" + config.msg_source_adapter) if config.msg_source_adapter == 'yirimirai': from pkg.qqbot.sources.yirimirai import YiriMiraiAdapter + + mirai_http_api_config = config.mirai_http_api_config self.bot_account_id = config.mirai_http_api_config['qq'] self.adapter = YiriMiraiAdapter(mirai_http_api_config) - elif config.msg_source_adapter == 'nonebot2': - pass + elif config.msg_source_adapter == 'nakuru': + from pkg.qqbot.sources.nakuru import NakuruProjectAdapter + self.adapter = NakuruProjectAdapter(config.nakuru_config) + self.bot_account_id = self.adapter.bot_account_id else: self.adapter = pkg.utils.context.get_qqbot_manager().adapter @@ -146,10 +150,12 @@ class QQBotManager: pkg.utils.context.get_thread_ctl().submit_user_task( stranger_message_handler, ) - self.adapter.register_listener( - StrangerMessage, - on_stranger_message - ) + # nakuru不区分好友和陌生人,故仅为yirimirai注册陌生人事件 + if config.msg_source_adapter == 'yirimirai': + self.adapter.register_listener( + StrangerMessage, + on_stranger_message + ) def on_group_message(event: GroupMessage): @@ -182,14 +188,16 @@ class QQBotManager: 用于在热重载流程中卸载所有事件处理器 """ + import config self.adapter.unregister_listener( FriendMessage, on_friend_message ) - self.adapter.unregister_listener( - StrangerMessage, - on_stranger_message - ) + if config.msg_source_adapter == 'yirimirai': + self.adapter.unregister_listener( + StrangerMessage, + on_stranger_message + ) self.adapter.unregister_listener( GroupMessage, on_group_message @@ -272,7 +280,6 @@ class QQBotManager: def on_group_message(self, event: GroupMessage): import config reply = '' - def process(text=None) -> str: replys = "" if At(self.bot_account_id) in event.message_chain: diff --git a/pkg/qqbot/process.py b/pkg/qqbot/process.py index ff85126..545886d 100644 --- a/pkg/qqbot/process.py +++ b/pkg/qqbot/process.py @@ -66,7 +66,8 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes # 检查是否被禁言 if launcher_type == 'group': - if mgr.adapter.is_muted(launcher_id): + is_muted = mgr.adapter.is_muted(launcher_id) + if is_muted: logging.info("机器人被禁言,跳过消息处理(group_{})".format(launcher_id)) return reply diff --git a/pkg/qqbot/sources/nakuru.py b/pkg/qqbot/sources/nakuru.py new file mode 100644 index 0000000..6ce36c6 --- /dev/null +++ b/pkg/qqbot/sources/nakuru.py @@ -0,0 +1,319 @@ +import mirai + +from ..adapter import MessageSourceAdapter, MessageConverter, EventConverter +import nakuru +import nakuru.entities.components as nkc + +import asyncio +import typing +import traceback +import logging +import json + +from pkg.qqbot.blob import Forward, ForwardMessageNode, ForwardMessageDiaplay + + +class NakuruProjectMessageConverter(MessageConverter): + """消息转换器""" + @staticmethod + def yiri2target(message_chain: mirai.MessageChain) -> list: + msg_list = [] + if type(message_chain) is mirai.MessageChain: + msg_list = message_chain.__root__ + elif type(message_chain) is list: + msg_list = message_chain + else: + raise Exception("Unknown message type: " + str(message_chain) + type(message_chain)) + + nakuru_msg_list = [] + + # 遍历并转换 + for component in msg_list: + if type(component) is mirai.Plain: + nakuru_msg_list.append(nkc.Plain(component.text, False)) + elif type(component) is mirai.Image: + if component.url is not None: + nakuru_msg_list.append(nkc.Image.fromURL(component.url)) + elif component.base64 is not None: + nakuru_msg_list.append(nkc.Image.fromBase64(component.base64)) + elif component.path is not None: + nakuru_msg_list.append(nkc.Image.fromFileSystem(component.path)) + elif type(component) is mirai.Face: + nakuru_msg_list.append(nkc.Face(id=component.face_id)) + elif type(component) is mirai.At: + nakuru_msg_list.append(nkc.At(qq=component.target)) + elif type(component) is mirai.AtAll: + nakuru_msg_list.append(nkc.AtAll()) + elif type(component) is mirai.Voice: + if component.url is not None: + nakuru_msg_list.append(nkc.Record.fromURL(component.url)) + elif component.path is not None: + nakuru_msg_list.append(nkc.Record.fromFileSystem(component.path)) + elif type(component) is Forward: + # 转发消息 + yiri_forward_node_list = component.node_list + nakuru_forward_node_list = [] + + # 遍历并转换 + for yiri_forward_node in yiri_forward_node_list: + try: + content_list = NakuruProjectMessageConverter.yiri2target(yiri_forward_node.message_chain) + nakuru_forward_node = nkc.Node( + name=yiri_forward_node.sender_name, + uin=yiri_forward_node.sender_id, + time=int(yiri_forward_node.time.timestamp()) if yiri_forward_node.time is not None else None, + content=content_list + ) + nakuru_forward_node_list.append(nakuru_forward_node) + except Exception as e: + import traceback + traceback.print_exc() + + nakuru_msg_list.append(nakuru_forward_node_list) + else: + nakuru_msg_list.append(nkc.Plain(str(component))) + + return nakuru_msg_list + + @staticmethod + def target2yiri(message_chain: typing.Any, message_id: int = -1) -> mirai.MessageChain: + """将Yiri的消息链转换为YiriMirai的消息链""" + assert type(message_chain) is list + + yiri_msg_list = [] + import datetime + # 添加Source组件以标记message_id等信息 + yiri_msg_list.append(mirai.models.message.Source(id=message_id, time=datetime.datetime.now())) + for component in message_chain: + if type(component) is nkc.Plain: + yiri_msg_list.append(mirai.Plain(text=component.text)) + elif type(component) is nkc.Image: + yiri_msg_list.append(mirai.Image(url=component.url)) + elif type(component) is nkc.Face: + yiri_msg_list.append(mirai.Face(face_id=component.id)) + elif type(component) is nkc.At: + yiri_msg_list.append(mirai.At(target=component.qq)) + elif type(component) is nkc.AtAll: + yiri_msg_list.append(mirai.AtAll()) + else: + pass + logging.debug("转换后的消息链: " + str(yiri_msg_list)) + chain = mirai.MessageChain(yiri_msg_list) + return chain + + +class NakuruProjectEventConverter(EventConverter): + """事件转换器""" + @staticmethod + def yiri2target(event: typing.Type[mirai.Event]): + if event is mirai.GroupMessage: + return nakuru.GroupMessage + elif event is mirai.FriendMessage: + return nakuru.FriendMessage + else: + raise Exception("未支持转换的事件类型: " + str(event)) + + @staticmethod + def target2yiri(event: typing.Any) -> mirai.Event: + yiri_chain = NakuruProjectMessageConverter.target2yiri(event.message, event.message_id) + if type(event) is nakuru.FriendMessage: # 私聊消息事件 + return mirai.FriendMessage( + sender=mirai.models.entities.Friend( + id=event.sender.user_id, + nickname=event.sender.nickname, + remark=event.sender.nickname + ), + message_chain=yiri_chain, + time=event.time + ) + elif type(event) is nakuru.GroupMessage: # 群聊消息事件 + permission = "MEMBER" + + if event.sender.role == "admin": + permission = "ADMINISTRATOR" + elif event.sender.role == "owner": + permission = "OWNER" + + import mirai.models.entities as entities + return mirai.GroupMessage( + sender=mirai.models.entities.GroupMember( + id=event.sender.user_id, + member_name=event.sender.nickname, + permission=permission, + group=mirai.models.entities.Group( + id=event.group_id, + name=event.sender.nickname, + permission=entities.Permission.Member + ), + special_title=event.sender.title, + join_timestamp=0, + last_speak_timestamp=0, + mute_time_remaining=0, + ), + message_chain=yiri_chain, + time=event.time + ) + else: + raise Exception("未支持转换的事件类型: " + str(event)) + + + +class NakuruProjectAdapter(MessageSourceAdapter): + """nakuru-project适配器""" + bot: nakuru.CQHTTP + bot_account_id: int + + message_converter: NakuruProjectMessageConverter = NakuruProjectMessageConverter() + event_converter: NakuruProjectEventConverter = NakuruProjectEventConverter() + + listener_list: list[dict] + + def __init__(self, cfg: dict): + """初始化nakuru-project的对象""" + self.bot = nakuru.CQHTTP(**cfg) + self.listener_list = [] + # nakuru库有bug,这个接口没法带access_token,会失败 + # 所以目前自行发请求 + import config + import requests + resp = requests.get( + url="http://{}:{}/get_login_info".format(config.nakuru_config['host'], config.nakuru_config['http_port']), + headers={ + 'Authorization': "Bearer " + config.nakuru_config['token'] if 'token' in config.nakuru_config else "" + }, + timeout=5 + ) + self.bot_account_id = int(resp.json()['data']['user_id']) + + def send_message( + self, + target_type: str, + target_id: str, + message: typing.Union[mirai.MessageChain, list], + converted: bool = False + ): + task = None + + converted_msg = self.message_converter.yiri2target(message) if not converted else message + + # 检查是否有转发消息 + has_forward = False + for msg in converted_msg: + if type(msg) is list: # 转发消息,仅回复此消息组件 + has_forward = True + converted_msg = msg + break + if has_forward: + if target_type == "group": + task = self.bot.sendGroupForwardMessage(int(target_id), converted_msg) + elif target_type == "person": + task = self.bot.sendPrivateForwardMessage(int(target_id), converted_msg) + else: + raise Exception("Unknown target type: " + target_type) + else: + if target_type == "group": + task = self.bot.sendGroupMessage(int(target_id), converted_msg) + elif target_type == "person": + task = self.bot.sendFriendMessage(int(target_id), converted_msg) + else: + raise Exception("Unknown target type: " + target_type) + + asyncio.run(task) + + def reply_message( + self, + message_source: mirai.MessageEvent, + message: mirai.MessageChain, + quote_origin: bool = False + ): + message = self.message_converter.yiri2target(message) + if quote_origin: + # 在前方添加引用组件 + message.insert(0, nkc.Reply( + id=message_source.message_chain.message_id, + ) + ) + if type(message_source) is mirai.GroupMessage: + self.send_message( + "group", + message_source.sender.group.id, + message, + converted=True + ) + elif type(message_source) is mirai.FriendMessage: + self.send_message( + "person", + message_source.sender.id, + message, + converted=True + ) + else: + raise Exception("Unknown message source type: " + str(type(message_source))) + + def is_muted(self, group_id: int) -> bool: + import time + # 检查是否被禁言 + group_member_info = asyncio.run(self.bot.getGroupMemberInfo(group_id, self.bot_account_id)) + return group_member_info.shut_up_timestamp > int(time.time()) + + def register_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + try: + logging.debug("注册监听器: " + str(event_type) + " -> " + str(callback)) + + # 包装函数 + async def listener_wrapper(app: nakuru.CQHTTP, source: self.event_converter.yiri2target(event_type)): + callback(self.event_converter.target2yiri(source)) + + # 将包装函数和原函数的对应关系存入列表 + self.listener_list.append( + { + "event_type": event_type, + "callable": callback, + "wrapper": listener_wrapper, + } + ) + + # 注册监听器 + self.bot.receiver(self.event_converter.yiri2target(event_type).__name__)(listener_wrapper) + logging.debug("注册完成") + except Exception as e: + traceback.print_exc() + raise e + + def unregister_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + nakuru_event_name = self.event_converter.yiri2target(event_type).__name__ + + new_event_list = [] + + # 从本对象的监听器列表中查找并删除 + target_wrapper = None + for listener in self.listener_list: + if listener["event_type"] == event_type and listener["callable"] == callback: + target_wrapper = listener["wrapper"] + self.listener_list.remove(listener) + break + + if target_wrapper is None: + raise Exception("未找到对应的监听器") + + for func in self.bot.event[nakuru_event_name]: + if func.callable != target_wrapper: + new_event_list.append(func) + + self.bot.event[nakuru_event_name] = new_event_list + + def run_sync(self): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + self.bot.run() + + def kill(self) -> bool: + return False diff --git a/pkg/qqbot/sources/yirimirai.py b/pkg/qqbot/sources/yirimirai.py index 0026ba9..8aa14ba 100644 --- a/pkg/qqbot/sources/yirimirai.py +++ b/pkg/qqbot/sources/yirimirai.py @@ -68,6 +68,7 @@ class YiriMiraiAdapter(MessageSourceAdapter): Args: message_source (mirai.MessageEvent): YiriMirai消息源事件 message (mirai.MessageChain): YiriMirai库的消息链 + quote_origin (bool, optional): 是否引用原消息. Defaults to False. """ asyncio.run(self.bot.send(message_source, message, quote_origin)) diff --git a/pkg/utils/log.py b/pkg/utils/log.py index 2666616..b976583 100644 --- a/pkg/utils/log.py +++ b/pkg/utils/log.py @@ -48,7 +48,7 @@ def reset_logging(): logging.basicConfig(level=config.logging_level, # 设置日志输出格式 filename=log_file_name, # log日志输出的文件位置和文件名 - format="[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : %(message)s", + format="[%(asctime)s.%(msecs)03d] %(pathname)s (%(lineno)d) - [%(levelname)s] :\n%(message)s", # 日志输出的格式 # -8表示占位符,让输出左对齐,输出长度都为8位 datefmt="%Y-%m-%d %H:%M:%S" # 时间输出的格式 diff --git a/requirements.txt b/requirements.txt index ac56cf0..1c17a40 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ yiri-mirai~=0.2.6.1 websockets urllib3~=1.26.10 func_timeout~=4.3.5 -Pillow \ No newline at end of file +Pillow +nakuru-project-idk \ No newline at end of file diff --git a/res/announcement.json b/res/announcement.json index 0637a08..3c47586 100644 --- a/res/announcement.json +++ b/res/announcement.json @@ -1 +1,8 @@ -[] \ No newline at end of file +[ + { + "id": 0, + "time": "2023-04-24 16:05:20", + "timestamp": 1682323520, + "content": "现已支持使用go-cqhttp替换mirai作为QQ登录框架, 请更新并查看 https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE" + } +] \ No newline at end of file diff --git a/res/wiki/go-cqhttp配置.md b/res/wiki/go-cqhttp配置.md new file mode 100644 index 0000000..0868d64 --- /dev/null +++ b/res/wiki/go-cqhttp配置.md @@ -0,0 +1,67 @@ +# 配置go-cqhttp用于登录QQ + +> 若您是从旧版本升级到此版本以使用go-cqhttp的用户,请您按照`config-template.py`的内容修改`config.py`,添加`msg_source_adapter`配置项并将其设为`nakuru`,同时添加`nakuru_config`字段按照说明配置。 + +## 步骤 + +1. 从[go-cqhttp的Release](https://github.com/Mrs4s/go-cqhttp/releases/latest)下载最新的go-cqhttp可执行文件(建议直接下载可执行文件压缩包,而不是安装器) +2. 解压并运行,首次运行会询问需要开放的网络协议,请填入`02`并回车 + + ``` + C:\Softwares\go-cqhttp.old> .\go-cqhttp.exe + 未找到配置文件,正在为您生成配置文件中! + 请选择你需要的通信方式: + > 0: HTTP通信 + > 1: 云函数服务 + > 2: 正向 Websocket 通信 + > 3: 反向 Websocket 通信 + 请输入你需要的编号(0-9),可输入多个,同一编号也可输入多个(如: 233) + 您的选择是:02 + ``` + 提示已生成`config.yml`文件,关闭go-cqhttp。 + +3. 打开go-cqhttp同目录的`config.yml` + + 1. 编辑账号登录信息(可选) + + 只需要修改下方`uin`和`password`为你要登录的机器人账号的QQ号和密码即可。 + **若您不填写,将会在启动时请求扫码登录。** + + ```yaml + account: # 账号相关 + uin: 1233456 # QQ账号 + password: '' # 密码为空时使用扫码登录 + encrypt: false # 是否开启密码加密 + status: 0 # 在线状态 请参考 https://docs.go-cqhttp.org/guide/config.html#在线状态 + relogin: # 重连设置 + delay: 3 # 首次重连延迟, 单位秒 + interval: 3 # 重连间隔 + max-times: 0 # 最大重连次数, 0为无限制 + ``` + + 2. 修改websocket端口(必需) + + 在`config.yml`下方找到以下内容 + + ```yaml + - ws: + # 正向WS服务器监听地址 + address: 0.0.0.0:8080 + middlewares: + <<: *default # 引用默认中间件 + ``` + + **将`0.0.0.0:8080`改为`0.0.0.0:6700`**,保存并关闭`config.yml`。 + + 3. 若您的服务器位于公网,强烈建议您填写`access-token` (可选) + + ```yaml + # 默认中间件锚点 + default-middlewares: &default + # 访问密钥, 强烈推荐在公网的服务器设置 + access-token: '' + ``` + +4. 配置完成,重新启动go-cqhttp + +> 若启动后登录不成功,请尝试根据[此文档](https://docs.go-cqhttp.org/guide/config.html#%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF)修改`device.json`的协议编号。 \ No newline at end of file