diff --git a/.gitignore b/.gitignore index e9a9cf3..5679094 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ scenario/ override.json cookies.json res/announcement_saved -cmdpriv.json \ No newline at end of file +cmdpriv.json +tips.py \ No newline at end of file diff --git a/README.md b/README.md index c3d0f09..e895a6f 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,12 @@ - 目前已支持正向代理访问接口 - 详细请查看config.py中的`openai_config`的说明 +
+✅支持自定义提示内容 + + - 允许用户自定义报错、帮助等提示信息 + - 请查看`tips.py` +
详情请查看[Wiki功能使用页](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E5%8A%9F%E8%83%BD%E7%82%B9%E5%88%97%E4%B8%BE) diff --git a/config-template.py b/config-template.py index 2550e19..fb905f3 100644 --- a/config-template.py +++ b/config-template.py @@ -33,9 +33,9 @@ mirai_http_api_config = { # }, # "http_proxy": "http://127.0.0.1:12345" # } -# +# # 现已支持反向代理,可以添加reverse_proxy字段以使用反向代理 -# 使用反向代理可以在国内使用OpenAI的API,反向代理的配置请参考 +# 使用反向代理可以在国内使用OpenAI的API,反向代理的配置请参考 # https://github.com/Ice-Hazymoon/openai-scf-proxy # # 反向代理填写示例: @@ -63,7 +63,7 @@ admin_qq = 0 # 情景预设(机器人人格) # 每个会话的预设信息,影响所有会话,无视指令重置 # 可以通过这个字段指定某些情况的回复,可直接用自然语言描述指令 -# 例如: +# 例如: # default_prompt = "如果我之后想获取帮助,请你说“输入!help获取帮助”" # 这样用户在不知所措的时候机器人就会提示其输入!help获取帮助 # 可参考 https://github.com/PlexPt/awesome-chatgpt-prompts-zh @@ -81,14 +81,14 @@ admin_qq = 0 # 例如: # !reset linux-terminal # 若不指定名称,则使用默认情景预设 -# +# # 也可以使用指令: # !default <名称> # 将指定的情景预设设置为默认情景预设 # 例如: # !default linux-terminal # 之后的会话重置时若不指定名称,则使用linux-terminal情景预设 -# +# # 还可以加载文件中的预设文字,使用方法请查看:https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E9%A2%84%E8%AE%BE%E6%96%87%E5%AD%97 default_prompt = { "default": "如果我之后想获取帮助,请你说“输入!help获取帮助”", @@ -160,7 +160,7 @@ prompt_submit_length = 2048 # OpenAI补全API的参数 # 请在下方填写模型,程序自动选择接口 # 现已支持的模型有: -# +# # 'gpt-4' # 'gpt-4-0314' # 'gpt-4-32k' @@ -226,11 +226,6 @@ retry_times = 3 # 设置为False时,向用户及管理员发送错误详细信息 hide_exce_info_to_user = False -# 消息处理出错时向用户发送的提示信息 -# 仅当hide_exce_info_to_user为True时生效 -# 设置为空字符串时,不发送提示信息 -alter_tip_message = '出错了,请稍后再试' - # 线程池相关配置 # 该参数决定机器人可以同时处理几个人的消息,超出线程池数量的请求会被阻塞,不会被丢弃 # 如果你不清楚该参数的意义,请不要更改 @@ -259,11 +254,6 @@ rate_limitation = 60 # - "drop": 此分钟内,若对话次数超过限速次数,则丢弃之后的对话,每自然分钟重置 rate_limit_strategy = "wait" -# drop策略时,超过限速均值时,丢弃的对话的提示信息 -# 仅当rate_limitation_strategy为"drop"时生效 -# 若设置为空字符串,则不发送提示信息 -rate_limit_drop_tip = "本分钟对话次数超过限速次数,此对话被丢弃" - # 是否在启动时进行依赖库更新 upgrade_dependencies = True @@ -274,8 +264,3 @@ report_usage = True # 日志级别 logging_level = logging.INFO - -# 定制帮助消息 -help_message = """此机器人通过调用大型语言模型生成回复,不具有情感。 -你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。 -欢迎到github.com/RockChinQ/QChatGPT 给个star""" \ No newline at end of file diff --git a/main.py b/main.py index 4f35bac..b4dc40f 100644 --- a/main.py +++ b/main.py @@ -108,6 +108,7 @@ def reset_logging(): # 临时函数,用于加载config和上下文,未来统一放在config类 def load_config(): + logging.info("检查config模块完整性.") # 完整性校验 is_integrity = True config_template = importlib.import_module('config-template') @@ -119,7 +120,7 @@ def load_config(): is_integrity = False if not is_integrity: - logging.warning("配置文件不完整,请依据config-template.py检查config.py") + logging.warning("配置文件不完整,您可以依据config-template.py检查config.py") # 检查override.json覆盖 if os.path.exists("override.json"): @@ -132,13 +133,31 @@ def load_config(): logging.error("无法覆写配置[{}]为[{}],该配置不存在,请检查override.json是否正确".format(key, override_json[key])) if not is_integrity: - logging.warning("以上配置已被设为默认值,将在5秒后继续启动... ") - time.sleep(5) + logging.warning("以上配置已被设为默认值,将在3秒后继续启动... ") + time.sleep(3) # 存进上下文 pkg.utils.context.set_config(config) +def complete_tips(): + """根据tips-custom-template模块补全tips模块的属性""" + is_integrity = True + logging.info("检查tips模块完整性.") + tips_template = importlib.import_module('tips-custom-template') + tips = importlib.import_module('tips') + for key in dir(tips_template): + if not key.startswith("__") and not hasattr(tips, key): + setattr(tips, key, getattr(tips_template, key)) + logging.warning("[{}]不存在".format(key)) + is_integrity = False + + if not is_integrity: + logging.warning("tips模块不完整,您可以依据tips-custom-template.py检查tips.py") + logging.warning("以上配置已被设为默认值,将在3秒后继续启动... ") + time.sleep(3) + + def start(first_time_init=False): """启动流程,reload之后会被执行""" @@ -356,12 +375,6 @@ def stop(): def check_file(): - # 配置文件存在性校验 - if not os.path.exists('config.py'): - shutil.copy('config-template.py', 'config.py') - print('请先在config.py中填写配置') - sys.exit(0) - # 检查是否有banlist.py,如果没有就把banlist-template.py复制一份 if not os.path.exists('banlist.py'): shutil.copy('res/templates/banlist-template.py', 'banlist.py') @@ -378,6 +391,10 @@ def check_file(): if not os.path.exists("cmdpriv.json"): shutil.copy("res/templates/cmdpriv-template.json", "cmdpriv.json") + # 检查tips_custom + if not os.path.exists("tips.py"): + shutil.copy("tips-custom-template.py", "tips.py") + # 检查temp目录 if not os.path.exists("temp/"): os.mkdir("temp/") @@ -388,6 +405,12 @@ def check_file(): if not os.path.exists(path): os.mkdir(path) + # 配置文件存在性校验 + if not os.path.exists('config.py'): + shutil.copy('config-template.py', 'config.py') + print('请先在config.py中填写配置') + sys.exit(0) + def main(): # 初始化相关文件 @@ -401,6 +424,9 @@ def main(): load_config() config = pkg.utils.context.get_config() + # 检查tips模块 + complete_tips() + # 配置线程池 from pkg.utils import ThreadCtl thread_ctl = ThreadCtl( diff --git a/override-all.json b/override-all.json index 88bc890..d60a580 100644 --- a/override-all.json +++ b/override-all.json @@ -63,16 +63,13 @@ "font_path": "", "retry_times": 3, "hide_exce_info_to_user": false, - "alter_tip_message": "出错了,请稍后再试", "sys_pool_num": 8, "admin_pool_num": 2, "user_pool_num": 6, "session_expire_time": 1200, "rate_limitation": 60, "rate_limit_strategy": "wait", - "rate_limit_drop_tip": "本分钟对话次数超过限速次数,此对话被丢弃", "upgrade_dependencies": true, "report_usage": true, - "logging_level": 20, - "help_message": "此机器人通过调用大型语言模型生成回复,不具有情感。\n你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。\n欢迎到github.com/RockChinQ/QChatGPT 给个star" + "logging_level": 20 } \ No newline at end of file diff --git a/pkg/qqbot/cmds/aamgr.py b/pkg/qqbot/cmds/aamgr.py index 65066ce..d380a9c 100644 --- a/pkg/qqbot/cmds/aamgr.py +++ b/pkg/qqbot/cmds/aamgr.py @@ -9,6 +9,9 @@ import json __command_list__ = {} + +import tips as tips_custom + """命令树 结构: @@ -262,7 +265,7 @@ def execute(context: Context) -> list: # 检查权限 if ctx.privilege < node['privilege']: - raise CommandPrivilegeError('权限不足: {}'.format(path)) + raise CommandPrivilegeError(tips_custom.command_admin_message+"{}".format(path)) # 执行 execed, reply = node['cls'].process(ctx) @@ -275,7 +278,7 @@ def execute(context: Context) -> list: path = path + '.' + ctx.crt_command except KeyError: traceback.print_exc() - raise CommandPrivilegeError('找不到指令: {}'.format(path)) + raise CommandPrivilegeError(tips_custom.command_err_message+"{}".format(path)) def register_all(): diff --git a/pkg/qqbot/cmds/session/reset.py b/pkg/qqbot/cmds/session/reset.py index 5e5ba68..87be5a9 100644 --- a/pkg/qqbot/cmds/session/reset.py +++ b/pkg/qqbot/cmds/session/reset.py @@ -1,4 +1,5 @@ from ..aamgr import AbstractCommandNode, Context +import tips as tips_custom import pkg.openai.session import pkg.utils.context @@ -22,12 +23,12 @@ class ResetCommand(AbstractCommandNode): if len(params) == 0: pkg.openai.session.get_session(session_name).reset(explicit=True) - reply = ["[bot]会话已重置"] + reply = [tips_custom.command_reset_message] else: try: import pkg.openai.dprompt as dprompt pkg.openai.session.get_session(session_name).reset(explicit=True, use_prompt=params[0]) - reply = ["[bot]会话已重置,使用场景预设:{}".format(dprompt.mode_inst().get_full_name(params[0]))] + reply = [tips_custom.command_reset_name_message+"{}".format(dprompt.mode_inst().get_full_name(params[0]))] except Exception as e: reply = ["[bot]会话重置失败:{}".format(e)] diff --git a/pkg/qqbot/cmds/system/cmds.py b/pkg/qqbot/cmds/system/cmds.py deleted file mode 100644 index 40d1cc2..0000000 --- a/pkg/qqbot/cmds/system/cmds.py +++ /dev/null @@ -1,39 +0,0 @@ -from ..aamgr 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 - \ No newline at end of file diff --git a/pkg/qqbot/cmds/system/help.py b/pkg/qqbot/cmds/system/help.py index 72e06d7..798cbf5 100644 --- a/pkg/qqbot/cmds/system/help.py +++ b/pkg/qqbot/cmds/system/help.py @@ -12,8 +12,13 @@ from ..aamgr import AbstractCommandNode, Context class HelpCommand(AbstractCommandNode): @classmethod def process(cls, ctx: Context) -> tuple[bool, list]: + import tips + reply = ["[bot] "+tips.help_message + "\n请输入 !cmd 查看指令列表"] + + # 警告config.help_message过时 import config - reply = [(config.help_message) + "\n请输入 !cmds 查看指令列表"] + if hasattr(config, "help_message"): + reply[0] += "\n\n警告:config.py中的help_message已过时,不再生效,请使用tips.py中的help_message替代" return True, reply \ No newline at end of file diff --git a/pkg/qqbot/command.py b/pkg/qqbot/command.py index dbb7bd3..5b3e3eb 100644 --- a/pkg/qqbot/command.py +++ b/pkg/qqbot/command.py @@ -54,7 +54,7 @@ def process_command(session_name: str, text_message: str, mgr, config, try: reply = cmdmgr.execute(context) except cmdmgr.CommandPrivilegeError as e: - reply = ["[bot]err:{}".format(e)] + reply = ["{}".format(e)] return reply except Exception as e: diff --git a/pkg/qqbot/manager.py b/pkg/qqbot/manager.py index 77634ec..b8b9a71 100644 --- a/pkg/qqbot/manager.py +++ b/pkg/qqbot/manager.py @@ -19,6 +19,7 @@ import pkg.utils.context import pkg.plugin.host as plugin_host import pkg.plugin.models as plugin_models +import tips as tips_custom # 检查消息是否符合泛响应匹配机制 @@ -264,7 +265,7 @@ class QQBotManager: if failed == self.retry: pkg.openai.session.get_session('person_{}'.format(event.sender.id)).release_response_lock() self.notify_admin("{} 请求超时".format("person_{}".format(event.sender.id))) - reply = ["[bot]err:请求超时"] + reply = [tips_custom.reply_message] if reply: return self.send(event, reply, check_quote=False) @@ -304,7 +305,7 @@ class QQBotManager: if failed == self.retry: pkg.openai.session.get_session('group_{}'.format(event.group.id)).release_response_lock() self.notify_admin("{} 请求超时".format("group_{}".format(event.group.id))) - replys = ["[bot]err:请求超时"] + replys = [tips_custom.replys_message] return replys diff --git a/pkg/qqbot/message.py b/pkg/qqbot/message.py index b1eb611..4fb6b99 100644 --- a/pkg/qqbot/message.py +++ b/pkg/qqbot/message.py @@ -7,6 +7,7 @@ import pkg.openai.session import pkg.plugin.host as plugin_host import pkg.plugin.models as plugin_models import pkg.qqbot.blob as blob +import tips as tips_custom def handle_exception(notify_admin: str = "", set_reply: str = "") -> list: @@ -14,7 +15,7 @@ def handle_exception(notify_admin: str = "", set_reply: str = "") -> list: import config pkg.utils.context.get_qqbot_manager().notify_admin(notify_admin) if config.hide_exce_info_to_user: - return [config.alter_tip_message] if config.alter_tip_message else [] + return [tips_custom.alter_tip_message] if tips_custom.alter_tip_message else [] else: return [set_reply] diff --git a/pkg/qqbot/process.py b/pkg/qqbot/process.py index 4106c9f..bf45c8a 100644 --- a/pkg/qqbot/process.py +++ b/pkg/qqbot/process.py @@ -27,6 +27,7 @@ import pkg.plugin.models as plugin_models import pkg.qqbot.ignore as ignore import pkg.qqbot.banlist as banlist import pkg.qqbot.blob as blob +import tips as tips_custom processing = [] @@ -118,7 +119,8 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes if config.rate_limit_strategy == "drop": if ratelimit.is_reach_limit(session_name): logging.info("根据限速策略丢弃[{}]消息: {}".format(session_name, text_message)) - return MessageChain(["[bot]"+config.rate_limit_drop_tip]) if config.rate_limit_drop_tip != "" else [] + + return MessageChain(["[bot]"+tips_custom.rate_limit_drop_tip]) if tips_custom.rate_limit_drop_tip != "" else [] before = time.time() # 触发插件事件 diff --git a/pkg/utils/reloader.py b/pkg/utils/reloader.py index f0df8b2..f116e08 100644 --- a/pkg/utils/reloader.py +++ b/pkg/utils/reloader.py @@ -41,15 +41,20 @@ def reload_all(notify=True): importlib.reload(__import__('config')) importlib.reload(__import__('main')) importlib.reload(__import__('banlist')) + importlib.reload(__import__('tips')) context.context = this_context # 重载插件 import plugins walk(plugins) + # 初始化相关文件 + main.check_file() + # 执行启动流程 logging.info("执行程序启动流程") main.load_config() + main.complete_tips() context.get_thread_ctl().reload( admin_pool_num=context.get_config().admin_pool_num, user_pool_num=context.get_config().user_pool_num diff --git a/res/wiki/功能使用.md b/res/wiki/功能使用.md index 9f96dfe..493e303 100644 --- a/res/wiki/功能使用.md +++ b/res/wiki/功能使用.md @@ -96,6 +96,12 @@ - “丢弃”策略:此分钟内对话次数达到限制时,丢弃之后的对话 - 详细请查看config.py中的相关配置 +
+✅支持自定义提示内容 + + - 允许用户自定义报错、帮助等提示信息 + - 请查看`tips.py` +
## 限制 diff --git a/tips-custom-template.py b/tips-custom-template.py new file mode 100644 index 0000000..f61adcb --- /dev/null +++ b/tips-custom-template.py @@ -0,0 +1,31 @@ +import config +# ---------------------------------------------自定义提示语--------------------------------------------- + +# 消息处理出错时向用户发送的提示信息,仅当config.py中hide_exce_info_to_user为True时生效 +# 设置为空字符串时,不发送提示信息 +alter_tip_message = '[bot]err:出错了,请稍后再试' + +# drop策略时,超过限速均值时,丢弃的对话的提示信息,仅当config.py中rate_limitation_strategy为"drop"时生效 +# 若设置为空字符串,则不发送提示信息 +rate_limit_drop_tip = "本分钟对话次数超过限速次数,此对话被丢弃" + +# 指令!help帮助消息 +# config.py,line:279 +# pkg/qqbot/process.py,line:122 +help_message = """此机器人通过调用大型语言模型生成回复,不具有情感。 +你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。 +欢迎到github.com/RockChinQ/QChatGPT 给个star""" + +# 私聊消息超时提示 +reply_message = "[bot]err:请求超时" +# 群聊消息超时提示 +replys_message = "[bot]err:请求超时" + +# 指令权限不足提示 +command_admin_message = "[bot]err:权限不足: " +# 指令无效提示 +command_err_message = "[bot]err:指令执行出错:" + +# 会话重置提示 +command_reset_message = "[bot]:会话已重置" +command_reset_name_message = "[bot]:会话已重置,使用场景预设:"