Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

138 linhas
5.2KB

  1. import asyncio
  2. import json
  3. import threading
  4. from concurrent.futures import ThreadPoolExecutor
  5. import plugins
  6. from bridge.context import ContextType
  7. from bridge.reply import Reply, ReplyType
  8. from channel.chat_message import ChatMessage
  9. from common.log import logger
  10. from config import conf, global_config
  11. from plugins import *
  12. from .midjourney import MJBot, TaskType
  13. # 任务线程池
  14. task_thread_pool = ThreadPoolExecutor(max_workers=4)
  15. @plugins.register(
  16. name="linkai",
  17. desc="A plugin that supports knowledge base and midjourney drawing.",
  18. version="0.1.0",
  19. author="https://link-ai.tech",
  20. )
  21. class LinkAI(Plugin):
  22. def __init__(self):
  23. super().__init__()
  24. self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
  25. self.config = super().load_config()
  26. if self.config:
  27. self.mj_bot = MJBot(self.config.get("midjourney"))
  28. logger.info("[LinkAI] inited")
  29. def on_handle_context(self, e_context: EventContext):
  30. """
  31. 消息处理逻辑
  32. :param e_context: 消息上下文
  33. """
  34. if not self.config:
  35. return
  36. context = e_context['context']
  37. if context.type not in [ContextType.TEXT, ContextType.IMAGE, ContextType.IMAGE_CREATE]:
  38. # filter content no need solve
  39. return
  40. mj_type = self.mj_bot.judge_mj_task_type(e_context)
  41. if mj_type:
  42. # MJ作图任务处理
  43. self.mj_bot.process_mj_task(mj_type, e_context)
  44. return
  45. if context.content.startswith(f"{_get_trigger_prefix()}linkai"):
  46. # 应用管理功能
  47. self._process_admin_cmd(e_context)
  48. return
  49. if self._is_chat_task(e_context):
  50. # 文本对话任务处理
  51. self._process_chat_task(e_context)
  52. # 插件管理功能
  53. def _process_admin_cmd(self, e_context: EventContext):
  54. context = e_context['context']
  55. cmd = context.content.split()
  56. if len(cmd) == 1 or (len(cmd) == 2 and cmd[1] == "help"):
  57. _set_reply_text(self.get_help_text(verbose=True), e_context, level=ReplyType.INFO)
  58. return
  59. if len(cmd) == 3 and cmd[1] == "app":
  60. if not context.kwargs.get("isgroup"):
  61. _set_reply_text("该指令需在群聊中使用", e_context, level=ReplyType.ERROR)
  62. return
  63. if context.kwargs.get("msg").actual_user_id not in global_config["admin_users"]:
  64. _set_reply_text("需要管理员权限执行", e_context, level=ReplyType.ERROR)
  65. return
  66. app_code = cmd[2]
  67. group_name = context.kwargs.get("msg").from_user_nickname
  68. group_mapping = self.config.get("group_app_map")
  69. if group_mapping:
  70. group_mapping[group_name] = app_code
  71. else:
  72. self.config["group_app_map"] = {group_name: app_code}
  73. # 保存插件配置
  74. super().save_config(self.config)
  75. _set_reply_text(f"应用设置成功: {app_code}", e_context, level=ReplyType.INFO)
  76. else:
  77. _set_reply_text(f"指令错误,请输入{_get_trigger_prefix()}linkai help 获取帮助", e_context, level=ReplyType.INFO)
  78. return
  79. # LinkAI 对话任务处理
  80. def _is_chat_task(self, e_context: EventContext):
  81. context = e_context['context']
  82. # 群聊应用管理
  83. return self.config.get("group_app_map") and context.kwargs.get("isgroup")
  84. def _process_chat_task(self, e_context: EventContext):
  85. """
  86. 处理LinkAI对话任务
  87. :param e_context: 对话上下文
  88. """
  89. context = e_context['context']
  90. # 群聊应用管理
  91. group_name = context.kwargs.get("msg").from_user_nickname
  92. app_code = self._fetch_group_app_code(group_name)
  93. if app_code:
  94. context.kwargs['app_code'] = app_code
  95. def _fetch_group_app_code(self, group_name: str) -> str:
  96. """
  97. 根据群聊名称获取对应的应用code
  98. :param group_name: 群聊名称
  99. :return: 应用code
  100. """
  101. group_mapping = self.config.get("group_app_map")
  102. if group_mapping:
  103. app_code = group_mapping.get(group_name) or group_mapping.get("ALL_GROUP")
  104. return app_code
  105. def get_help_text(self, verbose=False, **kwargs):
  106. trigger_prefix = _get_trigger_prefix()
  107. help_text = "用于集成 LinkAI 提供的知识库、Midjourney绘画等能力。\n\n"
  108. if not verbose:
  109. return help_text
  110. help_text += f'📖 知识库\n - 群聊中指定应用: {trigger_prefix}linkai app 应用编码\n\n例如: \n"$linkai app Kv2fXJcH"\n\n'
  111. help_text += f"🎨 绘画\n - 生成: {trigger_prefix}mj 描述词1, 描述词2.. \n - 放大: {trigger_prefix}mju 图片ID 图片序号\n\n例如:\n\"{trigger_prefix}mj a little cat, white --ar 9:16\"\n\"{trigger_prefix}mju 1105592717188272288 2\""
  112. return help_text
  113. # 静态方法
  114. def _set_reply_text(content: str, e_context: EventContext, level: ReplyType = ReplyType.ERROR):
  115. reply = Reply(level, content)
  116. e_context["reply"] = reply
  117. e_context.action = EventAction.BREAK_PASS
  118. def _get_trigger_prefix():
  119. return conf().get("plugin_trigger_prefix", "$")