Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

147 rindas
6.4KB

  1. # encoding:utf-8
  2. import json
  3. import os
  4. from bridge.bridge import Bridge
  5. from bridge.context import ContextType
  6. from bridge.reply import Reply, ReplyType
  7. from common import const
  8. from config import conf
  9. import plugins
  10. from plugins import *
  11. from common.log import logger
  12. class RolePlay():
  13. def __init__(self, bot, sessionid, desc, wrapper=None):
  14. self.bot = bot
  15. self.sessionid = sessionid
  16. self.wrapper = wrapper or "%s" # 用于包装用户输入
  17. self.desc = desc
  18. self.bot.sessions.build_session(self.sessionid, system_prompt=self.desc)
  19. def reset(self):
  20. self.bot.sessions.clear_session(self.sessionid)
  21. def action(self, user_action):
  22. session = self.bot.sessions.build_session(self.sessionid)
  23. if session.system_prompt != self.desc: # 目前没有触发session过期事件,这里先简单判断,然后重置
  24. session.set_system_prompt(self.desc)
  25. prompt = self.wrapper % user_action
  26. return prompt
  27. @plugins.register(name="Role", desire_priority=0, namecn="角色扮演", desc="为你的Bot设置预设角色", version="1.0", author="lanvent")
  28. class Role(Plugin):
  29. def __init__(self):
  30. super().__init__()
  31. curdir = os.path.dirname(__file__)
  32. config_path = os.path.join(curdir, "roles.json")
  33. try:
  34. with open(config_path, "r", encoding="utf-8") as f:
  35. config = json.load(f)
  36. self.roles = {role["title"].lower(): role for role in config["roles"]}
  37. if len(self.roles) == 0:
  38. raise Exception("no role found")
  39. self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
  40. self.roleplays = {}
  41. logger.info("[Role] inited")
  42. except Exception as e:
  43. if isinstance(e, FileNotFoundError):
  44. logger.warn(f"[Role] init failed, {config_path} not found, ignore or see https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/role .")
  45. else:
  46. logger.warn("[Role] init failed, ignore or see https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/role .")
  47. raise e
  48. def get_role(self, name, find_closest=True, min_sim = 0.35):
  49. name = name.lower()
  50. found_role = None
  51. if name in self.roles:
  52. found_role = name
  53. elif find_closest:
  54. import difflib
  55. def str_simularity(a, b):
  56. return difflib.SequenceMatcher(None, a, b).ratio()
  57. max_sim = min_sim
  58. max_role = None
  59. for role in self.roles:
  60. sim = str_simularity(name, role)
  61. if sim >= max_sim:
  62. max_sim = sim
  63. max_role = role
  64. found_role = max_role
  65. return found_role
  66. def on_handle_context(self, e_context: EventContext):
  67. if e_context['context'].type != ContextType.TEXT:
  68. return
  69. bottype = Bridge().get_bot_type("chat")
  70. if bottype not in (const.CHATGPT, const.OPEN_AI):
  71. return
  72. bot = Bridge().get_bot("chat")
  73. content = e_context['context'].content[:]
  74. clist = e_context['context'].content.split(maxsplit=1)
  75. desckey = None
  76. customize = False
  77. sessionid = e_context['context']['session_id']
  78. trigger_prefix = conf().get('plugin_trigger_prefix', "$")
  79. if clist[0] == f"{trigger_prefix}停止扮演":
  80. if sessionid in self.roleplays:
  81. self.roleplays[sessionid].reset()
  82. del self.roleplays[sessionid]
  83. reply = Reply(ReplyType.INFO, "角色扮演结束!")
  84. e_context['reply'] = reply
  85. e_context.action = EventAction.BREAK_PASS
  86. return
  87. elif clist[0] == f"{trigger_prefix}角色":
  88. desckey = "descn"
  89. elif clist[0].lower() == f"{trigger_prefix}role":
  90. desckey = "description"
  91. elif clist[0] == f"{trigger_prefix}设定扮演":
  92. customize = True
  93. elif sessionid not in self.roleplays:
  94. return
  95. logger.debug("[Role] on_handle_context. content: %s" % content)
  96. if desckey is not None:
  97. if len(clist) == 1 or (len(clist) > 1 and clist[1].lower() in ["help", "帮助"]):
  98. reply = Reply(ReplyType.INFO, self.get_help_text(verbose=True))
  99. e_context['reply'] = reply
  100. e_context.action = EventAction.BREAK_PASS
  101. return
  102. role = self.get_role(clist[1])
  103. if role is None:
  104. reply = Reply(ReplyType.ERROR, "角色不存在")
  105. e_context['reply'] = reply
  106. e_context.action = EventAction.BREAK_PASS
  107. return
  108. else:
  109. self.roleplays[sessionid] = RolePlay(bot, sessionid, self.roles[role][desckey], self.roles[role].get("wrapper","%s"))
  110. reply = Reply(ReplyType.INFO, f"预设角色为 {role}:\n"+self.roles[role][desckey])
  111. e_context['reply'] = reply
  112. e_context.action = EventAction.BREAK_PASS
  113. elif customize == True:
  114. self.roleplays[sessionid] = RolePlay(bot, sessionid, clist[1], "%s")
  115. reply = Reply(ReplyType.INFO, f"角色设定为:\n{clist[1]}")
  116. e_context['reply'] = reply
  117. e_context.action = EventAction.BREAK_PASS
  118. else:
  119. prompt = self.roleplays[sessionid].action(content)
  120. e_context['context'].type = ContextType.TEXT
  121. e_context['context'].content = prompt
  122. e_context.action = EventAction.BREAK
  123. def get_help_text(self, verbose=False, **kwargs):
  124. help_text = "让机器人扮演不同的角色。\n"
  125. if not verbose:
  126. return help_text
  127. trigger_prefix = conf().get('plugin_trigger_prefix', "$")
  128. help_text = f"使用方法:\n{trigger_prefix}角色"+" 预设角色名: 设定角色为{预设角色名}。\n"+f"{trigger_prefix}role"+" 预设角色名: 同上,但使用英文设定。\n"
  129. help_text += f"{trigger_prefix}设定扮演"+" 角色设定: 设定自定义角色人设为{角色设定}。\n"
  130. help_text += f"{trigger_prefix}停止扮演: 清除设定的角色。\n"
  131. help_text += "\n目前可用的预设角色名列表: \n"
  132. for role in self.roles:
  133. help_text += f"{role}: {self.roles[role]['remark']}\n"
  134. help_text += f"\n命令例子: '{trigger_prefix}角色 写作助理'"
  135. return help_text