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