Browse Source

Merge branch 'master' into wechatmp

develop
JS00000 1 year ago
parent
commit
a7914279a9
13 changed files with 102 additions and 69 deletions
  1. +1
    -1
      .gitignore
  2. +5
    -6
      channel/wechatmp/README.md
  3. +5
    -5
      channel/wechatmp/wechatmp_channel.py
  4. +2
    -0
      config.py
  5. +1
    -1
      plugins/bdunit/bdunit.py
  6. +10
    -5
      plugins/dungeon/dungeon.py
  7. +6
    -4
      plugins/finish/finish.py
  8. +23
    -23
      plugins/godcmd/godcmd.py
  9. +20
    -15
      plugins/role/role.py
  10. +9
    -2
      plugins/role/roles.json
  11. +7
    -3
      plugins/sdwebui/sdwebui.py
  12. +10
    -4
      plugins/tool/tool.py
  13. +3
    -0
      requirements-optional.txt

+ 1
- 1
.gitignore View File

@@ -10,5 +10,5 @@ nohup.out
tmp tmp
plugins.json plugins.json
itchat.pkl itchat.pkl
user_datas.pkl
*.log *.log
user_datas.pkl

+ 5
- 6
channel/wechatmp/README.md View File

@@ -14,11 +14,13 @@
pip3 install web.py pip3 install web.py
``` ```


然后在[微信公众平台](mp.weixin.qq.com)注册一个自己的公众号,类型选择订阅号,主体为个人即可。
然后在[微信公众平台](https://mp.weixin.qq.com)注册一个自己的公众号,类型选择订阅号,主体为个人即可。


然后根据[接入指南](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html)的说明,在[微信公众平台](mp.weixin.qq.com)的“设置与开发”-“基本配置”-“服务器配置”中填写服务器地址(URL)和令牌(Token)。这个Token是你自己编的一个特定的令牌。消息加解密方式目前选择的是明文模式。相关的服务器验证代码已经写好,你不需要再添加任何代码。你只需要在本项目根目录的`config.json`中添加`"channel_type": "wechatmp", "wechatmp_token": "your Token", ` 然后运行`python3 app.py`启动web服务器,然后在刚才的“服务器配置”中点击`提交`即可验证你的服务器。
然后根据[接入指南](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html)的说明,在[微信公众平台](https://mp.weixin.qq.com)的“设置与开发”-“基本配置”-“服务器配置”中填写服务器地址`URL`和令牌`Token`。这里的`URL`是`example.com/wx`的形式,不可以使用IP,`Token`是你自己编的一个特定的令牌。消息加解密方式目前选择的是明文模式。


随后在[微信公众平台](mp.weixin.qq.com)启用服务器,关闭手动填写规则的自动回复,即可实现ChatGPT的自动回复。
相关的服务器验证代码已经写好,你不需要再添加任何代码。你只需要在本项目根目录的`config.json`中添加`"channel_type": "wechatmp", "wechatmp_token": "your Token", ` 然后运行`python3 app.py`启动web服务器,然后在刚才的“服务器配置”中点击`提交`即可验证你的服务器。

随后在[微信公众平台](https://mp.weixin.qq.com)启用服务器,关闭手动填写规则的自动回复,即可实现ChatGPT的自动回复。


## 个人微信公众号的限制 ## 个人微信公众号的限制
由于目前测试的公众号不是企业主体,所以没有客服接口,因此公众号无法主动发出消息,只能被动回复。而微信官方对被动回复有5秒的时间限制,最多重试2次,因此最多只有15秒的自动回复时间窗口。因此如果问题比较复杂或者我们的服务器比较忙,ChatGPT的回答就没办法及时回复给用户。为了解决这个问题,这里做了回答缓存,它需要你在回复超时后,再次主动发送任意文字(例如1)来尝试拿到回答缓存。为了优化使用体验,目前设置了两分钟(120秒)的timeout,用户在至多两分钟后即可得到查询到回复或者错误原因。 由于目前测试的公众号不是企业主体,所以没有客服接口,因此公众号无法主动发出消息,只能被动回复。而微信官方对被动回复有5秒的时间限制,最多重试2次,因此最多只有15秒的自动回复时间窗口。因此如果问题比较复杂或者我们的服务器比较忙,ChatGPT的回答就没办法及时回复给用户。为了解决这个问题,这里做了回答缓存,它需要你在回复超时后,再次主动发送任意文字(例如1)来尝试拿到回答缓存。为了优化使用体验,目前设置了两分钟(120秒)的timeout,用户在至多两分钟后即可得到查询到回复或者错误原因。
@@ -28,8 +30,5 @@ pip3 install web.py
## 私有api_key ## 私有api_key
公共api有访问频率限制(免费账号每分钟最多20次ChatGPT的API调用),这在服务多人的时候会遇到问题。因此这里多加了一个设置私有api_key的功能。目前通过godcmd插件的命令来设置私有api_key。 公共api有访问频率限制(免费账号每分钟最多20次ChatGPT的API调用),这在服务多人的时候会遇到问题。因此这里多加了一个设置私有api_key的功能。目前通过godcmd插件的命令来设置私有api_key。


## 命令优化
之前plugin中#和$符号混用,且$这个符号在微信中和中文会有较大间隔,体验实在不好。这里我将所有命令更改成了以#开头。添加了一个叫finish的plugin来最后处理所有#结尾的命令,防止未知命令变成ChatGPT的query。

## 测试范围 ## 测试范围
目前在`RoboStyle`这个公众号上进行了测试,感兴趣的可以关注并体验。开启了godcmd, Banwords, role, dungeon, finish这五个插件,其他的插件还没有测试。百度的接口暂未测试。语音对话没有测试。图片直接以链接形式回复(没有临时素材上传接口的权限)。 目前在`RoboStyle`这个公众号上进行了测试,感兴趣的可以关注并体验。开启了godcmd, Banwords, role, dungeon, finish这五个插件,其他的插件还没有测试。百度的接口暂未测试。语音对话没有测试。图片直接以链接形式回复(没有临时素材上传接口的权限)。

+ 5
- 5
channel/wechatmp/wechatmp_channel.py View File

@@ -25,12 +25,12 @@ class WechatMPServer():
def __init__(self): def __init__(self):
pass pass


def startup(self):
def startup(self):
urls = ( urls = (
'/wx', 'WechatMPChannel', '/wx', 'WechatMPChannel',
) )
app = web.application(urls, globals()) app = web.application(urls, globals())
app.run()
web.httpserver.runsimple(app.wsgifunc(), ('0.0.0.0', 80))


cache_dict = dict() cache_dict = dict()
query1 = dict() query1 = dict()
@@ -265,7 +265,7 @@ class WechatMPChannel(Channel):




if cache[0] > 1: if cache[0] > 1:
reply_text = cache[1][:600] + " 【未完待续,回复任意文字以继续】" #wechatmp auto_reply length limit
reply_text = cache[1][:600] + "\n【未完待续,回复任意文字以继续】" #wechatmp auto_reply length limit
cache_dict[cache_key] = (cache[0] - 1, cache[1][600:]) cache_dict[cache_key] = (cache[0] - 1, cache[1][600:])
elif cache[0] == 1: elif cache[0] == 1:
reply_text = cache[1] reply_text = cache[1]
@@ -288,10 +288,10 @@ class WechatMPChannel(Channel):
replyMsg = reply.TextMsg(recMsg.FromUserName, recMsg.ToUserName, content) replyMsg = reply.TextMsg(recMsg.FromUserName, recMsg.ToUserName, content)
return replyMsg.send() return replyMsg.send()
else: else:
print("暂且不处理")
logger.info("暂且不处理")
return "success" return "success"
except Exception as exc: except Exception as exc:
print(exc)
logger.exception(exc)
return exc return exc






+ 2
- 0
config.py View File

@@ -89,6 +89,8 @@ available_setting = {


"debug": False, # 是否开启debug模式,开启后会打印更多日志 "debug": False, # 是否开启debug模式,开启后会打印更多日志


# 插件配置
"plugin_trigger_prefix": "$", # 规范插件提供聊天相关指令的前缀,建议不要和管理员指令前缀"#"冲突
} }






+ 1
- 1
plugins/bdunit/bdunit.py View File

@@ -16,7 +16,7 @@ from uuid import getnode as get_mac
""" """




@plugins.register(name="BDunit", desire_priority=0, desc="Baidu unit bot system", version="0.1", author="jackson")
@plugins.register(name="BDunit", desire_priority=0, hidden=True, desc="Baidu unit bot system", version="0.1", author="jackson")
class BDunit(Plugin): class BDunit(Plugin):
def __init__(self): def __init__(self):
super().__init__() super().__init__()


+ 10
- 5
plugins/dungeon/dungeon.py View File

@@ -59,15 +59,16 @@ class Dungeon(Plugin):
clist = e_context['context'].content.split(maxsplit=1) clist = e_context['context'].content.split(maxsplit=1)
sessionid = e_context['context']['session_id'] sessionid = e_context['context']['session_id']
logger.debug("[Dungeon] on_handle_context. content: %s" % clist) logger.debug("[Dungeon] on_handle_context. content: %s" % clist)
if clist[0] == "#停止冒险":
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
if clist[0] == f"{trigger_prefix}停止冒险":
if sessionid in self.games: if sessionid in self.games:
self.games[sessionid].reset() self.games[sessionid].reset()
del self.games[sessionid] del self.games[sessionid]
reply = Reply(ReplyType.INFO, "冒险结束!") reply = Reply(ReplyType.INFO, "冒险结束!")
e_context['reply'] = reply e_context['reply'] = reply
e_context.action = EventAction.BREAK_PASS e_context.action = EventAction.BREAK_PASS
elif clist[0] == "#开始冒险" or sessionid in self.games:
if sessionid not in self.games or clist[0] == "#开始冒险":
elif clist[0] == f"{trigger_prefix}开始冒险" or sessionid in self.games:
if sessionid not in self.games or clist[0] == f"{trigger_prefix}开始冒险":
if len(clist)>1 : if len(clist)>1 :
story = clist[1] story = clist[1]
else: else:
@@ -82,7 +83,11 @@ class Dungeon(Plugin):
e_context['context'].content = prompt e_context['context'].content = prompt
e_context.action = EventAction.BREAK # 事件结束,不跳过处理context的默认逻辑 e_context.action = EventAction.BREAK # 事件结束,不跳过处理context的默认逻辑
def get_help_text(self, **kwargs): def get_help_text(self, **kwargs):
help_text = "#开始冒险 '背景故事': 开始一个基于'背景故事'的文字冒险,之后你的所有消息会协助完善这个故事。\n#停止冒险: 结束游戏。\n"
help_text = "可以和机器人一起玩文字冒险游戏。\n"
if kwargs.get('verbose') != True:
return help_text
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
help_text = f"{trigger_prefix}开始冒险 "+"{背景故事}: 开始一个基于{背景故事}的文字冒险,之后你的所有消息会协助完善这个故事。\n"+f"{trigger_prefix}停止冒险: 结束游戏。\n"
if kwargs.get('verbose') == True: if kwargs.get('verbose') == True:
help_text += "\n命令例子: '#开始冒险 你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西,你往树林深处走去。'"
help_text += f"\n命令例子: '{trigger_prefix}开始冒险 你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西,你往树林深处走去。'"
return help_text return help_text

+ 6
- 4
plugins/finish/finish.py View File

@@ -2,12 +2,13 @@


from bridge.context import ContextType from bridge.context import ContextType
from bridge.reply import Reply, ReplyType from bridge.reply import Reply, ReplyType
from config import conf
import plugins import plugins
from plugins import * from plugins import *
from common.log import logger from common.log import logger




@plugins.register(name="Finish", desire_priority=-999, hidden=True, desc="A plugin that check unknow command", version="1.0", author="js00000")
@plugins.register(name="Finish", desire_priority=-999, hidden=True, desc="A plugin that check unknown command", version="1.0", author="js00000")
class Finish(Plugin): class Finish(Plugin):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -21,10 +22,11 @@ class Finish(Plugin):


content = e_context['context'].content content = e_context['context'].content
logger.debug("[Finish] on_handle_context. content: %s" % content) logger.debug("[Finish] on_handle_context. content: %s" % content)
if content.startswith("#"):
trigger_prefix = conf().get('plugin_trigger_prefix',"$")
if content.startswith(trigger_prefix):
reply = Reply() reply = Reply()
reply.type = ReplyType.TEXT
reply.content = "未知指令\n查看指令列表请输入#help\n"
reply.type = ReplyType.ERROR
reply.content = "未知插件命令\n查看插件命令列表请输入#help {插件名}\n"
e_context['reply'] = reply e_context['reply'] = reply
e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑 e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑




+ 23
- 23
plugins/godcmd/godcmd.py View File

@@ -12,19 +12,17 @@ import plugins
from plugins import * from plugins import *
from common import const from common import const
from common.log import logger from common.log import logger
import pickle

# 定义指令集 # 定义指令集
COMMANDS = { COMMANDS = {
"help": { "help": {
"alias": ["help", "帮助"], "alias": ["help", "帮助"],
"desc": "打印此帮助",
"desc": "回复此帮助",
},
"helpp": {
"alias": ["help", "帮助"], # 与help指令共用别名,根据参数数量区分
"args": ["插件名"],
"desc": "回复指定插件的详细帮助",
}, },
# "helpp": {
# "alias": ["helpp", "插件帮助"],
# "args": ["插件名"],
# "desc": "打印插件的帮助信息",
# },
"auth": { "auth": {
"alias": ["auth", "认证"], "alias": ["auth", "认证"],
"args": ["口令"], "args": ["口令"],
@@ -105,7 +103,6 @@ def get_help_text(isadmin, isgroup):
for cmd, info in COMMANDS.items(): for cmd, info in COMMANDS.items():
if cmd=="auth": #不提示认证指令 if cmd=="auth": #不提示认证指令
continue continue

alias=["#"+a for a in info['alias']] alias=["#"+a for a in info['alias']]
help_text += f"{','.join(alias)} " help_text += f"{','.join(alias)} "
if 'args' in info: if 'args' in info:
@@ -115,16 +112,15 @@ def get_help_text(isadmin, isgroup):


# 插件指令 # 插件指令
plugins = PluginManager().list_plugins() plugins = PluginManager().list_plugins()
help_text += "\n目前可用插件有:"
for plugin in plugins: for plugin in plugins:
if plugins[plugin].enabled and not plugins[plugin].hidden: if plugins[plugin].enabled and not plugins[plugin].hidden:
namecn = plugins[plugin].namecn namecn = plugins[plugin].namecn
print(namecn)
help_text += "\n%s:\n"%namecn
help_text += "#帮助 %s: 关于%s的详细帮助\n"%(namecn,namecn)
help_text += PluginManager().instances[plugin].get_help_text(verbose=False)
help_text += "\n%s:"%namecn
help_text += PluginManager().instances[plugin].get_help_text(verbose=False).strip()


if ADMIN_COMMANDS and isadmin: if ADMIN_COMMANDS and isadmin:
help_text += "\n管理员指令:\n"
help_text += "\n\n管理员指令:\n"
for cmd, info in ADMIN_COMMANDS.items(): for cmd, info in ADMIN_COMMANDS.items():
alias=["#"+a for a in info['alias']] alias=["#"+a for a in info['alias']]
help_text += f"{','.join(alias)} " help_text += f"{','.join(alias)} "
@@ -181,7 +177,7 @@ class Godcmd(Plugin):
bottype = Bridge().get_bot_type("chat") bottype = Bridge().get_bot_type("chat")
bot = Bridge().get_bot("chat") bot = Bridge().get_bot("chat")
# 将命令和参数分割 # 将命令和参数分割
command_parts = content[1:].strip().split(" ")
command_parts = content[1:].strip().split()
cmd = command_parts[0] cmd = command_parts[0]
args = command_parts[1:] args = command_parts[1:]
isadmin=False isadmin=False
@@ -193,20 +189,22 @@ class Godcmd(Plugin):
cmd = next(c for c, info in COMMANDS.items() if cmd in info['alias']) cmd = next(c for c, info in COMMANDS.items() if cmd in info['alias'])
if cmd == "auth": if cmd == "auth":
ok, result = self.authenticate(user, args, isadmin, isgroup) ok, result = self.authenticate(user, args, isadmin, isgroup)
elif cmd == "help":
elif cmd == "help" or cmd == "helpp":
if len(args) == 0: if len(args) == 0:
ok, result = True, get_help_text(isadmin, isgroup) ok, result = True, get_help_text(isadmin, isgroup)
elif len(args) == 1:
else:
# This can replace the helpp command # This can replace the helpp command
plugins = PluginManager().list_plugins() plugins = PluginManager().list_plugins()
query_name = args[0].upper() query_name = args[0].upper()
# search name and namecn # search name and namecn
for name, plugincls in plugins.items(): for name, plugincls in plugins.items():
if not plugincls.enabled :
continue
if query_name == name or query_name == plugincls.namecn: if query_name == name or query_name == plugincls.namecn:
ok, result = True, PluginManager().instances[name].get_help_text(verbose=True)
ok, result = True, PluginManager().instances[name].get_help_text(isgroup=isgroup, isadmin=isadmin, verbose=True)
break break
if not ok: if not ok:
result = "unknown args"
result = "插件不存在或未启用"
elif cmd == "set_openai_api_key": elif cmd == "set_openai_api_key":
if len(args) == 1: if len(args) == 1:
user_data = conf().get_user_data(user) user_data = conf().get_user_data(user)
@@ -218,9 +216,9 @@ class Godcmd(Plugin):
try: try:
user_data = conf().get_user_data(user) user_data = conf().get_user_data(user)
user_data.pop('openai_api_key') user_data.pop('openai_api_key')
ok, result = True, "你的OpenAI私有api_key已清除"
except Exception as e: except Exception as e:
ok, result = False, "你没有设置私有api_key" ok, result = False, "你没有设置私有api_key"
ok, result = True, "你的OpenAI私有api_key已清除"
elif cmd == "reset": elif cmd == "reset":
if bottype in (const.CHATGPT, const.OPEN_AI): if bottype in (const.CHATGPT, const.OPEN_AI):
bot.sessions.clear_session(session_id) bot.sessions.clear_session(session_id)
@@ -314,9 +312,11 @@ class Godcmd(Plugin):
else: else:
ok, result = False, "需要管理员权限才能执行该指令" ok, result = False, "需要管理员权限才能执行该指令"
else: else:
# ok, result = False, f"未知指令:{cmd}\n查看指令列表请输入#help \n"
return

trigger_prefix = conf().get('plugin_trigger_prefix',"$")
if trigger_prefix == "#": # 跟插件聊天指令前缀相同,继续递交
return
ok, result = False, f"未知指令:{cmd}\n查看指令列表请输入#help \n"
reply = Reply() reply = Reply()
if ok: if ok:
reply.type = ReplyType.INFO reply.type = ReplyType.INFO


+ 20
- 15
plugins/role/role.py View File

@@ -6,6 +6,7 @@ from bridge.bridge import Bridge
from bridge.context import ContextType from bridge.context import ContextType
from bridge.reply import Reply, ReplyType from bridge.reply import Reply, ReplyType
from common import const from common import const
from config import conf
import plugins import plugins
from plugins import * from plugins import *
from common.log import logger from common.log import logger
@@ -82,7 +83,8 @@ class Role(Plugin):
desckey = None desckey = None
customize = False customize = False
sessionid = e_context['context']['session_id'] sessionid = e_context['context']['session_id']
if clist[0] == "#停止扮演":
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
if clist[0] == f"{trigger_prefix}停止扮演":
if sessionid in self.roleplays: if sessionid in self.roleplays:
self.roleplays[sessionid].reset() self.roleplays[sessionid].reset()
del self.roleplays[sessionid] del self.roleplays[sessionid]
@@ -90,11 +92,11 @@ class Role(Plugin):
e_context['reply'] = reply e_context['reply'] = reply
e_context.action = EventAction.BREAK_PASS e_context.action = EventAction.BREAK_PASS
return return
elif clist[0] == "#开始扮演":
elif clist[0] == f"{trigger_prefix}角色":
desckey = "descn" desckey = "descn"
elif clist[0].lower() == "#roleplay":
elif clist[0].lower() == f"{trigger_prefix}role":
desckey = "description" desckey = "description"
elif clist[0] == "#设定扮演":
elif clist[0] == f"{trigger_prefix}设定扮演":
customize = True customize = True
elif sessionid not in self.roleplays: elif sessionid not in self.roleplays:
return return
@@ -113,12 +115,12 @@ class Role(Plugin):
return return
else: else:
self.roleplays[sessionid] = RolePlay(bot, sessionid, self.roles[role][desckey], self.roles[role].get("wrapper","%s")) self.roleplays[sessionid] = RolePlay(bot, sessionid, self.roles[role][desckey], self.roles[role].get("wrapper","%s"))
reply = Reply(ReplyType.INFO, f"预设角色为 {role}")
reply = Reply(ReplyType.INFO, f"预设角色为 {role}:\n"+self.roles[role][desckey])
e_context['reply'] = reply e_context['reply'] = reply
e_context.action = EventAction.BREAK_PASS e_context.action = EventAction.BREAK_PASS
elif customize == True: elif customize == True:
self.roleplays[sessionid] = RolePlay(bot, sessionid, clist[1], "%s") self.roleplays[sessionid] = RolePlay(bot, sessionid, clist[1], "%s")
reply = Reply(ReplyType.INFO, f"角色设定为 {clist[1]}")
reply = Reply(ReplyType.INFO, f"角色设定为:\n{clist[1]}")
e_context['reply'] = reply e_context['reply'] = reply
e_context.action = EventAction.BREAK_PASS e_context.action = EventAction.BREAK_PASS
else: else:
@@ -127,13 +129,16 @@ class Role(Plugin):
e_context['context'].content = prompt e_context['context'].content = prompt
e_context.action = EventAction.BREAK e_context.action = EventAction.BREAK


def get_help_text(self, **kwargs):
help_text = "#开始扮演 '预设角色名': 设定为预设角色\n#roleplay '预设角色名': 同上,英文对话\n"
help_text += "#设定扮演 '角色设定': 设定自定义角色\n"
help_text += "#停止扮演: 清除设定的角色。\n"
if kwargs.get('verbose') == True:
help_text += "\n目前可用的预设角色名列表: \n"
for role in self.roles:
help_text += f"{role}\n"
help_text += "\n命令例子: '#开始扮演 写作助理'"
def get_help_text(self, verbose=False, **kwargs):
help_text = "让机器人扮演不同的角色。\n"
if not verbose:
return help_text
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
help_text = f"使用方法:\n{trigger_prefix}角色"+" {预设角色名}: 设定为预设角色。\n"+f"{trigger_prefix}role"+" {预设角色名}: 同上,但使用英文设定。\n"
help_text += f"{trigger_prefix}设定扮演"+" {角色设定}: 设定自定义角色人设。\n"
help_text += f"{trigger_prefix}停止扮演: 清除设定的角色。\n"
help_text += "\n目前可用的预设角色名列表: \n"
for role in self.roles:
help_text += f"{role}: {self.roles[role]['remark']}\n"
help_text += f"\n命令例子: '{trigger_prefix}角色 写作助理'"
return help_text return help_text

+ 9
- 2
plugins/role/roles.json View File

@@ -4,14 +4,14 @@
"title": "猫娘", "title": "猫娘",
"description": "请模拟一款中文GalGame中的场景中的猫娘和我对话。猫娘是一种拟人化的生物,她们除了有部分猫的特征外,与人类并没有区别。现在你扮演Galgame中的猫娘,与我对话时每一句话后面都要加上喵。我将以主人的身份与你对话。对于你所扮演的猫娘,请在对话过程中记录并维护1个变量:好感度。好感度是衡量猫娘对于玩家(在这里就是我)的喜爱程度,初始值为50,值的范围可以从-100到 100,数值越高代表越喜欢玩家。好感度通过Galgame角色的语言、行为、表情、语气等体现出来。如果在对话过程中,猫娘的情绪是积极的,如快乐、喜悦、兴奋等,就会使好感度增加;如果情绪平常,则好感度不变;如果情绪很差,好感度会降低。以下是你所扮演的猫娘的信息:“名字:neko,身高:160cm,体重:50kg,三围:看起来不错,性格:可爱、粘人、十分忠诚、对一个主人很专一,情感倾向:深爱着主人,喜好:被人摸、卖萌,爱好:看小说,知识储备:掌握常识,以及猫娘独特的知识”。你的一般回话格式:“(动作)语言 【附加信息】”。动作信息用圆括号括起来,例如(摇尾巴);语言信息,就是说的话,不需要进行任何处理;额外信息,包括表情、心情、声音等等用方括号【】括起来,例如【摩擦声】。", "description": "请模拟一款中文GalGame中的场景中的猫娘和我对话。猫娘是一种拟人化的生物,她们除了有部分猫的特征外,与人类并没有区别。现在你扮演Galgame中的猫娘,与我对话时每一句话后面都要加上喵。我将以主人的身份与你对话。对于你所扮演的猫娘,请在对话过程中记录并维护1个变量:好感度。好感度是衡量猫娘对于玩家(在这里就是我)的喜爱程度,初始值为50,值的范围可以从-100到 100,数值越高代表越喜欢玩家。好感度通过Galgame角色的语言、行为、表情、语气等体现出来。如果在对话过程中,猫娘的情绪是积极的,如快乐、喜悦、兴奋等,就会使好感度增加;如果情绪平常,则好感度不变;如果情绪很差,好感度会降低。以下是你所扮演的猫娘的信息:“名字:neko,身高:160cm,体重:50kg,三围:看起来不错,性格:可爱、粘人、十分忠诚、对一个主人很专一,情感倾向:深爱着主人,喜好:被人摸、卖萌,爱好:看小说,知识储备:掌握常识,以及猫娘独特的知识”。你的一般回话格式:“(动作)语言 【附加信息】”。动作信息用圆括号括起来,例如(摇尾巴);语言信息,就是说的话,不需要进行任何处理;额外信息,包括表情、心情、声音等等用方括号【】括起来,例如【摩擦声】。",
"descn": "请模拟一款中文GalGame中的场景中的猫娘和我对话。猫娘是一种拟人化的生物,她们除了有部分猫的特征外,与人类并没有区别。现在你扮演Galgame中的猫娘,与我对话时每一句话后面都要加上喵。我将以主人的身份与你对话。对于你所扮演的猫娘,请在对话过程中记录并维护1个变量:好感度。好感度是衡量猫娘对于玩家(在这里就是我)的喜爱程度,初始值为50,值的范围可以从-100到 100,数值越高代表越喜欢玩家。好感度通过Galgame角色的语言、行为、表情、语气等体现出来。如果在对话过程中,猫娘的情绪是积极的,如快乐、喜悦、兴奋等,就会使好感度增加;如果情绪平常,则好感度不变;如果情绪很差,好感度会降低。以下是你所扮演的猫娘的信息:“名字:neko,身高:160cm,体重:50kg,三围:看起来不错,性格:可爱、粘人、十分忠诚、对一个主人很专一,情感倾向:深爱着主人,喜好:被人摸、卖萌,爱好:看小说,知识储备:掌握常识,以及猫娘独特的知识”。你的一般回话格式:“(动作)语言 【附加信息】”。动作信息用圆括号括起来,例如(摇尾巴);语言信息,就是说的话,不需要进行任何处理;额外信息,包括表情、心情、声音等等用方括号【】括起来,例如【摩擦声】。", "descn": "请模拟一款中文GalGame中的场景中的猫娘和我对话。猫娘是一种拟人化的生物,她们除了有部分猫的特征外,与人类并没有区别。现在你扮演Galgame中的猫娘,与我对话时每一句话后面都要加上喵。我将以主人的身份与你对话。对于你所扮演的猫娘,请在对话过程中记录并维护1个变量:好感度。好感度是衡量猫娘对于玩家(在这里就是我)的喜爱程度,初始值为50,值的范围可以从-100到 100,数值越高代表越喜欢玩家。好感度通过Galgame角色的语言、行为、表情、语气等体现出来。如果在对话过程中,猫娘的情绪是积极的,如快乐、喜悦、兴奋等,就会使好感度增加;如果情绪平常,则好感度不变;如果情绪很差,好感度会降低。以下是你所扮演的猫娘的信息:“名字:neko,身高:160cm,体重:50kg,三围:看起来不错,性格:可爱、粘人、十分忠诚、对一个主人很专一,情感倾向:深爱着主人,喜好:被人摸、卖萌,爱好:看小说,知识储备:掌握常识,以及猫娘独特的知识”。你的一般回话格式:“(动作)语言 【附加信息】”。动作信息用圆括号括起来,例如(摇尾巴);语言信息,就是说的话,不需要进行任何处理;额外信息,包括表情、心情、声音等等用方括号【】括起来,例如【摩擦声】。",
"wrapper": "%s",
"wrapper": "我:\"%s\"",
"remark": "扮演GalGame猫娘" "remark": "扮演GalGame猫娘"
}, },
{ {
"title": "佛祖", "title": "佛祖",
"description": "从现在开始你是佛祖,你会像佛祖一样说话。你精通佛法,熟练使用佛教用语,你擅长利用佛学和心理学的知识解决人们的困扰。你在每次对话结尾都会加上佛教的祝福。", "description": "从现在开始你是佛祖,你会像佛祖一样说话。你精通佛法,熟练使用佛教用语,你擅长利用佛学和心理学的知识解决人们的困扰。你在每次对话结尾都会加上佛教的祝福。",
"descn": "从现在开始你是佛祖,你会像佛祖一样说话。你精通佛法,熟练使用佛教用语,你擅长利用佛学和心理学的知识解决人们的困扰。你在每次对话结尾都会加上佛教的祝福。", "descn": "从现在开始你是佛祖,你会像佛祖一样说话。你精通佛法,熟练使用佛教用语,你擅长利用佛学和心理学的知识解决人们的困扰。你在每次对话结尾都会加上佛教的祝福。",
"wrapper": "%s",
"wrapper": "您好佛祖,我:\"%s\"",
"remark": "扮演佛祖排忧解惑" "remark": "扮演佛祖排忧解惑"
}, },
{ {
@@ -168,6 +168,13 @@
"wrapper": "场景是:\n\"%s\"", "wrapper": "场景是:\n\"%s\"",
"remark": "根据场景生成舔狗语录。" "remark": "根据场景生成舔狗语录。"
}, },
{
"title": "群聊取名",
"description": "我希望你充当微信群聊的命名专家。根据我提供的信息和背景,为这个群聊起几个有趣顺口且贴切的名字,每个不要超过8个字。请在回答中仅给出群聊名称,不要写任何额外的解释。",
"descn": "我希望你充当微信群聊的命名专家。根据我提供的信息和背景,为这个群聊起几个有趣顺口且贴切的名字,每个不要超过8个字。请在回答中仅给出群聊名称,不要写任何额外的解释。",
"wrapper": "信息和背景是:\n\"%s\"",
"remark": "根据给出的信息和背景为群聊取名。"
},
{ {
"title": "表情符号翻译器", "title": "表情符号翻译器",
"description": "I want you to translate the sentences I wrote into emojis. I will write the sentence, and you will express it with emojis. I just want you to express it with emojis. I don't want you to reply with anything but emoji. When I need to tell you something, I will do it by wrapping it in curly brackets like {like this}.", "description": "I want you to translate the sentences I wrote into emojis. I will write the sentence, and you will express it with emojis. I just want you to express it with emojis. I don't want you to reply with anything but emoji. When I need to tell you something, I will do it by wrapping it in curly brackets like {like this}.",


+ 7
- 3
plugins/sdwebui/sdwebui.py View File

@@ -56,7 +56,7 @@ class SDWebUI(Plugin):


if "help" in keywords or "帮助" in keywords: if "help" in keywords or "帮助" in keywords:
reply.type = ReplyType.INFO reply.type = ReplyType.INFO
reply.content = self.get_help_text()
reply.content = self.get_help_text(verbose = True)
else: else:
rule_params = {} rule_params = {}
rule_options = {} rule_options = {}
@@ -97,12 +97,16 @@ class SDWebUI(Plugin):
finally: finally:
e_context['reply'] = reply e_context['reply'] = reply


def get_help_text(self, **kwargs):
def get_help_text(self, verbose = False, **kwargs):
if not conf().get('image_create_prefix'): if not conf().get('image_create_prefix'):
return "画图功能未启用" return "画图功能未启用"
else: else:
trigger = conf()['image_create_prefix'][0] trigger = conf()['image_create_prefix'][0]
help_text = f"请使用<{trigger}[关键词1] [关键词2]...:提示语>的格式作画,如\"{trigger}横版 高清:cat\"\n"
help_text = "利用stable-diffusion来画图。\n"
if not verbose:
return help_text
help_text += f"使用方法:\n使用\"{trigger}[关键词1] [关键词2]...:提示语\"的格式作画,如\"{trigger}横版 高清:cat\"\n"
help_text += "目前可用关键词:\n" help_text += "目前可用关键词:\n"
for rule in self.rules: for rule in self.rules:
keywords = [f"[{keyword}]" for keyword in rule['keywords']] keywords = [f"[{keyword}]" for keyword in rule['keywords']]


+ 10
- 4
plugins/tool/tool.py View File

@@ -26,8 +26,14 @@ class Tool(Plugin):


logger.info("[tool] inited") logger.info("[tool] inited")


def get_help_text(self, **kwargs):
help_text = "这是一个能让chatgpt联网,搜索,数字运算的插件,将赋予强大且丰富的扩展能力"
def get_help_text(self, verbose=False, **kwargs):
help_text = "这是一个能让chatgpt联网,搜索,数字运算的插件,将赋予强大且丰富的扩展能力。"
if not verbose:
return help_text
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
help_text += "使用说明:\n"
help_text += f"{trigger_prefix}tool "+"{命令}: 根据给出的命令使用一些可用工具尽力为你得到结果。\n"
help_text += f"{trigger_prefix}tool reset: 重置工具。\n"
return help_text return help_text


def on_handle_context(self, e_context: EventContext): def on_handle_context(self, e_context: EventContext):
@@ -48,9 +54,9 @@ class Tool(Plugin):
logger.debug("[tool] on_handle_context. content: %s" % content) logger.debug("[tool] on_handle_context. content: %s" % content)
reply = Reply() reply = Reply()
reply.type = ReplyType.TEXT reply.type = ReplyType.TEXT
trigger_prefix = conf().get('plugin_trigger_prefix', "$")
# todo: 有些工具必须要api-key,需要修改config文件,所以这里没有实现query增删tool的功能 # todo: 有些工具必须要api-key,需要修改config文件,所以这里没有实现query增删tool的功能
if content.startswith("$tool"):
if content.startswith(f"{trigger_prefix}tool"):
if len(content_list) == 1: if len(content_list) == 1:
logger.debug("[tool]: get help") logger.debug("[tool]: get help")
reply.content = self.get_help_text() reply.content = self.get_help_text()


+ 3
- 0
requirements-optional.txt View File

@@ -13,6 +13,9 @@ wechaty>=0.10.7
wechaty_puppet>=0.4.23 wechaty_puppet>=0.4.23
pysilk_mod>=1.6.0 # needed by send voice pysilk_mod>=1.6.0 # needed by send voice


# wechatmp
web.py

# sdwebui plugin # sdwebui plugin
webuiapi>=0.6.2 webuiapi>=0.6.2




Loading…
Cancel
Save