Compare commits

...

14 Commits

Author SHA1 Message Date
Rock Chin
414910719c Release v2.3.3 2023-04-05 09:57:21 +08:00
Rock Chin
10a1e8faa6 fix: 回复内容不完整问题 (#208) 2023-04-05 09:56:27 +08:00
Rock Chin
4eea21927e doc: 补充手动部署中缺失的requests库 (#375) 2023-04-04 16:49:59 +08:00
Rock Chin
48c7f659f9 Release v2.3.2 2023-04-04 03:22:19 +00:00
Rock Chin
b33333f4aa Merge pull request #372 from RockChinQ/363-bug-helpmessage-creditapi
[Fix] help_message问题、额度检测接口问题
2023-04-04 11:20:34 +08:00
Rock Chin
9edb32b081 feat: usage命令不再显示额度 2023-04-04 03:15:07 +00:00
Rock Chin
c9b25fe806 doc: cmds指令的说明 2023-04-03 14:55:01 +00:00
GitHub Actions Bot
b6ee3939be Update cmdpriv-template.json 2023-04-03 14:41:25 +00:00
Rock Chin
e5485cddd0 feat: 更改使用!cmd指令查看指令列表 2023-04-03 14:40:27 +00:00
Rock Chin
ac81597236 feat: 插件更新异常处理 2023-04-03 14:09:30 +00:00
Rock Chin
58d991df0a Merge pull request #368 from zyckk4/docstring-improvements
[Chore] 统一docstring格式
2023-04-03 22:02:11 +08:00
Rock Chin
3f8e380da4 Merge pull request #369 from zyckk4/fix-type-hint
[Fix] 修复一处类型注解的错误
2023-04-03 13:39:56 +08:00
zyckk4
ae831a2654 [Fix] 修复一处类型注解的错误 2023-04-03 10:13:20 +08:00
zyckk4
ae72cf2283 chore: 统一docstring格式 2023-04-03 00:19:28 +08:00
15 changed files with 140 additions and 95 deletions

View File

@@ -188,7 +188,7 @@ cd QChatGPT
2. 安装依赖
```bash
pip3 install yiri-mirai openai colorlog func_timeout dulwich Pillow
pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow
```
3. 运行一次主程序,生成配置文件

View File

@@ -19,6 +19,7 @@
"prompt": 1,
"resend": 1,
"reset": 1,
"cmd": 1,
"help": 1,
"reload": 2,
"update": 2,

View File

@@ -1,2 +1 @@
"""OpenAI 接口处理及会话管理相关
"""
"""OpenAI 接口处理及会话管理相关"""

View File

@@ -11,8 +11,7 @@ class KeysManager:
"""所有api-key"""
using_key = ""
"""当前使用的api-key
"""
"""当前使用的api-key"""
alerted = []
"""已提示过超额的key
@@ -48,7 +47,7 @@ class KeysManager:
self.auto_switch()
def auto_switch(self) -> (bool, str):
def auto_switch(self) -> tuple[bool, str]:
"""尝试切换api-key
Returns:
@@ -79,8 +78,7 @@ class KeysManager:
self.api_key[key_name] = key
def set_current_exceeded(self):
"""设置当前使用的api-key使用量超限
"""
"""设置当前使用的api-key使用量超限"""
self.exceeded.append(self.using_key)
def get_key_name(self, api_key):

View File

@@ -229,13 +229,7 @@ class Session:
# 成功获取,处理回复
res_test = message
res_ans = res_test
# 去除开头可能的提示
res_ans_spt = res_test.split("\n\n")
if len(res_ans_spt) > 1:
del (res_ans_spt[0])
res_ans = '\n\n'.join(res_ans_spt)
res_ans = res_test.strip()
# 将此次对话的双方内容加入到prompt中
self.prompt.append({'role': 'user', 'content': text})

View File

@@ -15,8 +15,7 @@ import pkg.plugin.settings as settings
from mirai import Mirai
__plugins__ = {}
"""
插件列表
"""插件列表
示例:
{
@@ -35,14 +34,15 @@ __plugins__ = {}
},
"instance": None
}
}"""
}
"""
__plugins_order__ = []
"""插件顺序"""
def generate_plugin_order():
""" 根据__plugin__生成插件初始顺序无视是否启用 """
"""根据__plugin__生成插件初始顺序无视是否启用"""
global __plugins_order__
__plugins_order__ = []
for plugin_name in __plugins__:
@@ -50,13 +50,13 @@ def generate_plugin_order():
def iter_plugins():
""" 按照顺序迭代插件 """
"""按照顺序迭代插件"""
for plugin_name in __plugins_order__:
yield __plugins__[plugin_name]
def iter_plugins_name():
""" 迭代插件名 """
"""迭代插件名"""
for plugin_name in __plugins_order__:
yield plugin_name
@@ -85,7 +85,7 @@ def walk_plugin_path(module, prefix='', path_prefix=''):
def load_plugins():
""" 加载插件 """
"""加载插件"""
logging.info("加载插件")
PluginHost()
walk_plugin_path(__import__('plugins'))
@@ -102,7 +102,7 @@ def load_plugins():
def initialize_plugins():
""" 初始化插件 """
"""初始化插件"""
logging.info("初始化插件")
import pkg.plugin.models as models
for plugin in iter_plugins():
@@ -117,8 +117,7 @@ def initialize_plugins():
def unload_plugins():
""" 卸载插件
"""
"""卸载插件"""
# 不再显式卸载插件,因为当程序结束时,插件的析构函数会被系统执行
# for plugin in __plugins__.values():
# if plugin['enabled'] and plugin['instance'] is not None:
@@ -134,7 +133,7 @@ def unload_plugins():
def install_plugin(repo_url: str):
""" 安装插件从git储存库获取并解决依赖 """
"""安装插件从git储存库获取并解决依赖"""
try:
import pkg.utils.pkgmgr
pkg.utils.pkgmgr.ensure_dulwich()
@@ -162,7 +161,7 @@ def install_plugin(repo_url: str):
def uninstall_plugin(plugin_name: str) -> str:
""" 卸载插件 """
"""卸载插件"""
if plugin_name not in __plugins__:
raise Exception("插件不存在")
@@ -178,17 +177,17 @@ def uninstall_plugin(plugin_name: str) -> str:
class EventContext:
""" 事件上下文 """
"""事件上下文"""
eid = 0
"""事件编号"""
name = ""
__prevent_default__ = False
""" 是否阻止默认行为 """
"""是否阻止默认行为"""
__prevent_postorder__ = False
""" 是否阻止后续插件的执行 """
"""是否阻止后续插件的执行"""
__return_value__ = {}
""" 返回值
@@ -251,7 +250,7 @@ class EventContext:
def emit(event_name: str, **kwargs) -> EventContext:
""" 触发事件 """
"""触发事件"""
import pkg.utils.context as context
if context.get_plugin_host() is None:
return None
@@ -290,7 +289,7 @@ class PluginHost:
context.get_qqbot_manager().notify_admin(message)
def emit(self, event_name: str, **kwargs) -> EventContext:
""" 触发事件 """
"""触发事件"""
import json
event_context = EventContext(event_name)

View File

@@ -7,7 +7,7 @@ import pkg.plugin.host as host
def wrapper_dict_from_plugin_list() -> dict:
""" 将插件列表转换为开关json """
"""将插件列表转换为开关json"""
switch = {}
for plugin_name in host.__plugins__:
@@ -30,7 +30,7 @@ def apply_switch(switch: dict):
def dump_switch():
""" 保存开关数据 """
"""保存开关数据"""
logging.debug("保存开关数据")
# 将开关数据写入plugins/switch.json
@@ -41,7 +41,7 @@ def dump_switch():
def load_switch():
""" 加载开关数据 """
"""加载开关数据"""
logging.debug("加载开关数据")
# 读取plugins/switch.json

View File

@@ -98,28 +98,33 @@ class PluginUpdateCommand(AbstractCommandNode):
reply = []
def closure():
import pkg.utils.context
updated = []
for key in plugin_list:
plugin = plugin_list[key]
if updater.is_repo("/".join(plugin['path'].split('/')[:-1])):
success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1]))
if success:
updated.append(plugin['name'])
try:
import pkg.utils.context
updated = []
for key in plugin_list:
plugin = plugin_list[key]
if updater.is_repo("/".join(plugin['path'].split('/')[:-1])):
success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1]))
if success:
updated.append(plugin['name'])
# 检查是否有requirements.txt
pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...")
for key in plugin_list:
plugin = plugin_list[key]
if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"):
logging.info("{}检测到requirements.txt安装依赖".format(plugin['name']))
import pkg.utils.pkgmgr
pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt")
# 检查是否有requirements.txt
pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...")
for key in plugin_list:
plugin = plugin_list[key]
if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"):
logging.info("{}检测到requirements.txt安装依赖".format(plugin['name']))
import pkg.utils.pkgmgr
pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt")
import main
main.reset_logging()
import main
main.reset_logging()
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated)))
except Exception as e:
logging.error("插件更新失败:{}".format(e))
pkg.utils.context.get_qqbot_manager().notify_admin("插件更新失败:{} 请尝试手动更新插件".format(e))
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated)))
threading.Thread(target=closure).start()
reply = ["[bot]正在更新所有插件,请勿重复发起..."]

View File

@@ -0,0 +1,39 @@
from ..mgr import AbstractCommandNode, Context, __command_list__
@AbstractCommandNode.register(
parent=None,
name="cmd",
description="显示指令列表",
usage="!cmd\n!cmd <指令名称>",
aliases=[],
privilege=1
)
class CmdCommand(AbstractCommandNode):
@classmethod
def process(cls, ctx: Context) -> tuple[bool, list]:
command_list = __command_list__
reply = []
if len(ctx.params) == 0:
reply_str = "[bot]当前所有指令:\n\n"
# 遍历顶级指令
for key in command_list:
command = command_list[key]
if command['parent'] is None:
reply_str += "!{} - {}\n".format(key, command['description'])
reply_str += "\n请使用 !cmd <指令名称> 来查看指令的详细信息"
reply = [reply_str]
else:
command_name = ctx.params[0]
if command_name in command_list:
reply = [command_list[command_name]['cls'].help()]
else:
reply = ["[bot]指令 {} 不存在".format(command_name)]
return True, reply

View File

@@ -0,0 +1,39 @@
from ..mgr import AbstractCommandNode, Context, __command_list__
@AbstractCommandNode.register(
parent=None,
name="cmd",
description="显示指令列表",
usage="!help\n!help <指令名称>",
aliases=[],
privilege=1
)
class CmdCommand(AbstractCommandNode):
@classmethod
def process(cls, ctx: Context) -> tuple[bool, list]:
command_list = __command_list__
reply = []
if len(ctx.params) == 0:
reply_str = "[bot]当前所有指令:\n\n"
# 遍历顶级指令
for key in command_list:
command = command_list[key]
if command['parent'] is None:
reply_str += "!{} - {}\n".format(key, command['description'])
reply_str += "\n请使用 !cmd <指令名称> 来查看指令的详细信息"
reply = [reply_str]
else:
command_name = ctx.params[0]
if command_name in command_list:
reply = [command_list[command_name]['cls'].help()]
else:
reply = ["[bot]指令 {} 不存在".format(command_name)]
return True, reply

View File

@@ -1,38 +1,19 @@
from ..mgr import AbstractCommandNode, Context, __command_list__
from ..mgr import AbstractCommandNode, Context
@AbstractCommandNode.register(
parent=None,
name="help",
description="显示帮助信息",
usage="!help\n!help <指令名称>",
description="显示自定义的帮助信息",
usage="!help",
aliases=[],
privilege=1
)
class HelpCommand(AbstractCommandNode):
@classmethod
def process(cls, ctx: Context) -> tuple[bool, list]:
command_list = __command_list__
import config
reply = [(config.help_message if hasattr(config, 'help_message') else "") + "\n请输入 !cmds 查看指令列表"]
reply = []
if len(ctx.params) == 0:
reply_str = "[bot]当前所有指令:\n\n"
# 遍历顶级指令
for key in command_list:
command = command_list[key]
if command['parent'] is None:
reply_str += "!{} - {}\n".format(key, command['description'])
reply_str += "\n请使用 !help <指令名称> 来查看指令的详细信息"
reply = [reply_str]
else:
command_name = ctx.params[0]
if command_name in command_list:
reply = [command_list[command_name]['cls'].help()]
else:
reply = ["[bot]指令 {} 不存在".format(command_name)]
return True, reply
return True, reply

View File

@@ -29,13 +29,6 @@ class UsageCommand(AbstractCommandNode):
.get_image_count_of_key(api_keys[key_name])
reply_str += "{}:\n - 文本长度:{}\n - 图片数量:{}\n".format(key_name, int(text_length),
int(image_count))
# 获取此key的额度
try:
http_proxy = config.openai_config["http_proxy"] if "http_proxy" in config.openai_config else None
credit_data = credit.fetch_credit_data(api_keys[key_name], http_proxy)
reply_str += " - 使用额度:{:.2f}/{:.2f}\n".format(credit_data['total_used'],credit_data['total_granted'])
except Exception as e:
logging.warning("获取额度失败:{}".format(e))
reply = [reply_str]

File diff suppressed because one or more lines are too long

View File

@@ -4,9 +4,7 @@ from concurrent.futures import ThreadPoolExecutor
class Pool:
'''
线程池结构
'''
"""线程池结构"""
pool_num:int = None
ctl:ThreadPoolExecutor = None
task_list:list = None
@@ -33,12 +31,11 @@ class Pool:
class ThreadCtl:
def __init__(self, sys_pool_num, admin_pool_num, user_pool_num):
'''
线程池控制类
"""线程池控制类
sys_pool_num分配系统使用的线程池数量(>=8)
admin_pool_num用于处理管理员消息的线程池数量(>=1)
user_pool_num分配用于处理用户消息的线程池的数量(>=1)
'''
"""
if sys_pool_num < 5:
raise Exception("Too few system threads(sys_pool_num needs >= 8, but received {})".format(sys_pool_num))
if admin_pool_num < 1: