Merge pull request #50 from RockChinQ/response-rules

feat: 支持除@之外的群内其他响应机制 #28
This commit is contained in:
Rock Chin
2022-12-19 17:28:05 +08:00
committed by GitHub
4 changed files with 77 additions and 35 deletions

View File

@@ -17,7 +17,7 @@
<summary>✅回复符合上下文</summary>
- 程序向模型发送近几次对话内容,模型根据上下文生成回复
- 您可在`config.py`中修改`prompt_submit_round_amount``process_message_timeout`自定义联系上下文的范围
- 您可在`config.py`中修改`process_message_timeout`自定义联系上下文的范围
</details>

View File

@@ -28,21 +28,9 @@ openai_config = {
},
}
# 单个api-key的使用量警告阈值
# 当使用此api-key进行请求的文字量达到此阈值时会在控制台输出警告并通知管理员
# 若之后还有未使用超过此值的api-key则会切换到新的api-key进行请求
api_key_usage_threshold = 900000
# 管理员QQ号用于接收报错等通知为0时不发送通知
admin_qq = 0
# 回复消息时是否显示[GPT]前缀
show_prefix = False
# 敏感词过滤开关,以同样数量的*代替敏感词回复
# 请在sensitive.json中添加敏感词
sensitive_word_filter = True
# 每个会话的预设信息,影响所有会话,无视指令重置
# 可以通过这个字段指定某些情况的回复,可直接用自然语言描述指令
# 例如: 如果我之后想获取帮助,请你说“输入!help获取帮助”
@@ -50,30 +38,48 @@ sensitive_word_filter = True
# 可参考 https://github.com/PlexPt/awesome-chatgpt-prompts-zh
default_prompt = "如果我之后想获取帮助,请你说“输入!help获取帮助”"
# OpenAI的completion API的参数
# 具体请查看OpenAI的文档
completion_api_params = {
"model": "text-davinci-003",
"temperature": 0.6, # 数值越低得到的回答越理性,取值范围[0, 1]
"max_tokens": 512, # 每次向OpenAI请求的最大字符数, 不高于4096
"top_p": 1, # 生成的文本的文本与要求的符合度, 取值范围[0, 1]
"frequency_penalty": 0.2,
"presence_penalty": 0.4,
# 群内响应规则
# 符合此消息的群内消息即使不包含at机器人也会响应
# 支持消息前缀匹配及正则表达式匹配
# 注意:由消息前缀(prefix)匹配的消息中将会删除此前缀,正则表达式匹配的消息不会删除匹配的部分
# 前缀匹配优先级高于正则表达式匹配
# 正则表达式简明教程https://www.runoob.com/regexp/regexp-tutorial.html
response_rules = {
"prefix": ["/ai", "!ai", "ai", "ai"],
"regexp": ["为什么.*", "怎么?样.*", "如何.*", "[Hh]ow to.*", "[Ww]hy not.*", "[Ww]hat is.*", ]
}
# 单个api-key的使用量警告阈值
# 当使用此api-key进行请求的文字量达到此阈值时会在控制台输出警告并通知管理员
# 若之后还有未使用超过此值的api-key则会切换到新的api-key进行请求
api_key_usage_threshold = 900000
# 敏感词过滤开关,以同样数量的*代替敏感词回复
# 请在sensitive.json中添加敏感词
sensitive_word_filter = True
# 每次向OpenAI接口发送对话记录上下文的字符数
# 最大不超过(4096 - max_tokens)个字符max_tokens为上述completion_api_params中的max_tokens
# 注意较大的prompt_submit_length会导致OpenAI账户额度消耗更快
prompt_submit_length = 1536
# 每次向OpenAI接口发送对话记录上下文的聊天回合
# 不建议过大向OpenAI接口发送对话上下文时保证内容不超过prompt_submit_length个字符
# 不超过prompt_submit_round_amount个回合
prompt_submit_round_amount = 16
# OpenAI的completion API的参
# 具体请查看OpenAI的文档: https://beta.openai.com/docs/api-reference/completions/create
completion_api_params = {
"model": "text-davinci-003",
"temperature": 0.6, # 数值越低得到的回答越理性,取值范围[0, 1]
"max_tokens": 512, # 每次向OpenAI请求的最大字符数, 不高于4096
"top_p": 1, # 生成的文本的文本与要求的符合度, 取值范围[0, 1]
"frequency_penalty": 0.2,
"presence_penalty": 1.0,
}
# 消息处理的超时时间,单位为秒
process_message_timeout = 15
# 回复消息时是否显示[GPT]前缀
show_prefix = False
# 消息处理超时重试次数
retry_times = 3

View File

@@ -139,7 +139,8 @@ class Session:
def append(self, text: str) -> str:
self.last_interact_timestamp = int(time.time())
max_rounds = config.prompt_submit_round_amount if hasattr(config, 'prompt_submit_round_amount') else 7
# max_rounds = config.prompt_submit_round_amount if hasattr(config, 'prompt_submit_round_amount') else 7
max_rounds = 1000 # 不再限制回合数
max_length = config.prompt_submit_length if hasattr(config, "prompt_submit_length") else 1024
# 向API请求补全

View File

@@ -28,6 +28,29 @@ def go(func, args=()):
thread.start()
# 检查消息是否符合泛响应匹配机制
def check_response_rule(text: str) -> (bool, str):
if not hasattr(config, 'response_rules'):
return False, ''
rules = config.response_rules
# 检查前缀匹配
if 'prefix' in rules:
for rule in rules['prefix']:
if text.startswith(rule):
return True, text.replace(rule, "", 1)
# 检查正则表达式匹配
if 'regexp' in rules:
for rule in rules['regexp']:
import re
match = re.match(rule, text)
if match:
return True, text
return False, ""
# 控制QQ消息输入输出的类
class QQBotManager:
timeout = 60
@@ -265,12 +288,10 @@ class QQBotManager:
reply = ''
if Image in event.message_chain:
pass
elif At(self.bot.qq) not in event.message_chain:
pass
else:
event.message_chain.remove(At(self.bot.qq))
def process(text = None) -> str:
replys = ""
if At(self.bot.qq) in event.message_chain:
event.message_chain.remove(At(self.bot.qq))
processing.append("group_{}".format(event.sender.id))
@@ -278,7 +299,8 @@ class QQBotManager:
failed = 0
for i in range(self.retry):
try:
reply = self.process_message('group', event.group.id, str(event.message_chain).strip())
replys = self.process_message('group', event.group.id,
str(event.message_chain).strip() if text is None else text)
break
except FunctionTimedOut:
failed += 1
@@ -286,7 +308,20 @@ class QQBotManager:
if failed == self.retry:
self.notify_admin("{} 请求超时".format("group_{}".format(event.sender.id)))
reply = "[bot]err:请求超时"
replys = "[bot]err:请求超时"
return replys
if Image in event.message_chain:
pass
elif At(self.bot.qq) not in event.message_chain:
check, result = check_response_rule(str(event.message_chain).strip())
if check:
reply = process(result.strip())
else:
# 直接调用
reply = process()
if reply != '':
return self.send(event, reply)