From 31516c309051fc60f1ec2a00bc5d8efd0b554144 Mon Sep 17 00:00:00 2001 From: liuwei Date: Wed, 19 Mar 2025 17:37:02 +0800 Subject: [PATCH] =?UTF-8?q?dify=20=E6=8F=92=E4=BB=B6=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/dify/__init__.py | 7 + {dify => plugins/dify}/config.toml | 7 +- dify/dify_chat.py => plugins/dify/main.py | 160 ++++++++++++++-------- robot.py | 8 -- 4 files changed, 119 insertions(+), 63 deletions(-) create mode 100644 plugins/dify/__init__.py rename {dify => plugins/dify}/config.toml (77%) rename dify/dify_chat.py => plugins/dify/main.py (65%) diff --git a/plugins/dify/__init__.py b/plugins/dify/__init__.py new file mode 100644 index 0000000..251a8dc --- /dev/null +++ b/plugins/dify/__init__.py @@ -0,0 +1,7 @@ +# 从当前包的main模块导入DifyPlugin类 +from .main import DifyPlugin + +# 提供get_plugin函数,返回插件实例 +def get_plugin(): + """获取插件实例""" + return DifyPlugin() \ No newline at end of file diff --git a/dify/config.toml b/plugins/dify/config.toml similarity index 77% rename from dify/config.toml rename to plugins/dify/config.toml index 59d887c..2f98f22 100644 --- a/dify/config.toml +++ b/plugins/dify/config.toml @@ -6,6 +6,7 @@ base-url = "http://192.168.2.240/v1" #Dify API接口base url commands = ["ai", "dify", "聊天", "AI"] command-tip = """ +-----Bot----- 💬AI聊天指令: 聊天 请求内容 """ @@ -15,4 +16,8 @@ price = 0 # 用一次扣积分,如果0则不扣 # Http代理设置 # 格式: http://用户名:密码@代理地址:代理端口 # 例如:http://127.0.0.1:7890 -http-proxy = "" \ No newline at end of file +http-proxy = "" + +# 管理员和白名单用户是否免费使用 +admin_ignore = true +whitelist_ignore = true \ No newline at end of file diff --git a/dify/dify_chat.py b/plugins/dify/main.py similarity index 65% rename from dify/dify_chat.py rename to plugins/dify/main.py index b630e0e..6c7ab6e 100644 --- a/dify/dify_chat.py +++ b/plugins/dify/main.py @@ -1,85 +1,135 @@ import logging -import tomllib import os import requests import json import time -from typing import Dict, List, Optional -from wcferry import WxMsg, Wcf +from typing import Dict, Any, List, Optional, Tuple +from wcferry import Wcf + +from plugin_common.message_plugin_interface import MessagePluginInterface +from plugin_common.plugin_interface import PluginStatus +from plugins.stats_collector.decorators import plugin_stats_decorator from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager -class DifyChat: - def __init__(self, wcf: Wcf, gbm: GroupBotManager): - self.LOG = logging.getLogger(__name__) - self.wcf = wcf - self.gbm = gbm # 权限功能 +class DifyPlugin(MessagePluginInterface): + """Dify AI聊天插件""" - # 加载配置文件 - with open("dify/config.toml", "rb") as f: - plugin_config = tomllib.load(f) + @property + def name(self) -> str: + return "Dify聊天" - config = plugin_config["Dify"] + @property + def version(self) -> str: + return "1.0.0" - # 基本配置 - self.enable = config["enable"] - self.api_key = config["api-key"] - self.base_url = config["base-url"] - self.commands = config["commands"] - self.command_tip = config["command-tip"] - self.price = config["price"] - self.admin_ignore = config.get("admin_ignore", False) - self.whitelist_ignore = config.get("whitelist_ignore", False) - self.http_proxy = config.get("http-proxy", "") + @property + def description(self) -> str: + return "提供基于Dify的AI聊天功能" + @property + def author(self) -> str: + return "Trae AI" + + @property + def command_prefix(self) -> Optional[str]: + return "" # 不需要前缀,直接匹配命令 + + @property + def commands(self) -> List[str]: + return self._commands + + def __init__(self): + super().__init__() # 会话上下文管理,格式: {group_id/wxid: [conversation_history]} self.conversations: Dict[str, List[Dict]] = {} - # tokens 消耗统计,格式: {wxid: total_tokens} self.token_usage: Dict[str, int] = {} - # 最大上下文长度 self.max_history_length = 10 - # 会话过期时间(秒) self.conversation_timeout = 3600 # 1小时 self.last_activity: Dict[str, float] = {} - self.LOG.info(f"[Dify聊天] 组件初始化完成,指令:{self.commands}") + def initialize(self, context: Dict[str, Any]) -> bool: + """初始化插件""" + self.LOG = logging.getLogger(f"Plugin.{self.name}") + self.LOG.info(f"正在初始化 {self.name} 插件...") - def handle_message(self, message: WxMsg) -> None: - """处理微信消息""" + # 保存上下文对象 + self.wcf = context.get("wcf") + self.event_system = context.get("event_system") + self.message_util = context.get("message_util") + self.gbm = context.get("gbm") + + # 从配置中获取参数 + dify_config = self._config.get("Dify", {}) + self._commands = dify_config.get("commands", ["ai", "dify", "聊天", "AI"]) + self.command_format = dify_config.get("command-tip", "聊天 请求内容") + self.enable = dify_config.get("enable", True) + self.api_key = dify_config.get("api-key", "") + self.base_url = dify_config.get("base-url", "") + self.price = dify_config.get("price", 0) + self.admin_ignore = dify_config.get("admin_ignore", False) + self.whitelist_ignore = dify_config.get("whitelist_ignore", False) + self.http_proxy = dify_config.get("http-proxy", "") + + self.LOG.info(f"[{self.name}] 插件初始化完成,指令:{self._commands}") + return True + + def start(self) -> bool: + """启动插件""" + self.LOG.info(f"[{self.name}] 插件已启动") + self.status = PluginStatus.RUNNING + return True + + def stop(self) -> bool: + """停止插件""" + self.LOG.info(f"[{self.name}] 插件已停止") + self.status = PluginStatus.STOPPED + return True + + def can_process(self, message: Dict[str, Any]) -> bool: + """检查是否可以处理该消息""" if not self.enable: - return + return False - content = str(message.content).strip() + content = str(message.get("content", "")).strip() + command = content.split(" ")[0] + + return command in self._commands + + @plugin_stats_decorator(plugin_name="Dify聊天") + def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]: + """处理消息""" + content = str(message.get("content", "")).strip() + self.LOG.info(f"插件执行: {self.name}:{content}") parts = content.split(" ", 1) command = parts[0] + sender = message.get("sender") + roomid = message.get("roomid", "") + wcf: Wcf = message.get("wcf") + gbm: GroupBotManager = message.get("gbm") - # 检查是否是触发命令 - if command not in self.commands: - return - - # 如果没有查询内容,返回使用提示 + # 检查命令格式 if len(parts) < 2 or not parts[1].strip(): - self.wcf.send_text(self.command_tip, - (message.roomid if message.from_group() else message.sender)) - return + wcf.send_text(f"{self.command_format}", + (roomid if roomid else sender), sender) + return True, "命令格式错误" # 检查权限 - if message.from_group() and self.gbm.get_group_permission(message.roomid, - Feature.AI_CAPABILITY) == PermissionStatus.DISABLED: - return + if roomid and gbm.get_group_permission(roomid, Feature.AI_CAPABILITY) == PermissionStatus.DISABLED: + return False, "没有权限" # 获取查询内容 query = parts[1].strip() # 获取会话ID(群聊使用群ID,私聊使用个人wxid) - session_id = message.roomid if message.from_group() else message.sender + session_id = roomid if roomid else sender # 获取用户ID - user_id = message.sender + user_id = sender # 检查是否需要扣除积分 if self.price > 0: @@ -98,20 +148,22 @@ class DifyChat: try: # 调用Dify API获取回复 - response = self.chat_with_dify(session_id, user_id, query) + response = self._chat_with_dify(session_id, user_id, query) # 发送回复 if response: - self.wcf.send_text(response, - (message.roomid if message.from_group() else message.sender), - message.sender if message.from_group() else "") - except Exception as e: - self.LOG.error(f"Dify聊天出错:{e}") - self.wcf.send_text(f"❌请求出错:{str(e)}", - (message.roomid if message.from_group() else message.sender), - message.sender if message.from_group() else "") + wcf.send_text(response, (roomid if roomid else sender), sender if roomid else "") + return True, "发送成功" + else: + wcf.send_text("❌未能获取到回复,请稍后再试", (roomid if roomid else sender), sender if roomid else "") + return True, "未获取到回复" - def chat_with_dify(self, session_id: str, user_id: str, query: str) -> Optional[str]: + except Exception as e: + self.LOG.error(f"处理Dify聊天请求出错: {e}") + wcf.send_text(f"❌请求出错:{str(e)}", (roomid if roomid else sender), sender if roomid else "") + return True, f"处理出错: {e}" + + def _chat_with_dify(self, session_id: str, user_id: str, query: str) -> Optional[str]: """ 与Dify API交互获取回复 @@ -290,4 +342,4 @@ class DifyChat: def reset_all_conversations(self) -> None: """重置所有会话上下文""" self.conversations.clear() - self.last_activity.clear() + self.last_activity.clear() \ No newline at end of file diff --git a/robot.py b/robot.py index b19c689..dae2c7b 100644 --- a/robot.py +++ b/robot.py @@ -22,7 +22,6 @@ from base.func_xinghuo_web import XinghuoWeb from base.func_claude import Claude from configuration import Config from constants import ChatType -from dify.dify_chat import DifyChat from douyin_parser.main import DouyinParser from game_task.game_task_encyclopedia import game_process_message, get_group_ids,run_random_task_assignment from group_add.main import GroupAdd @@ -125,8 +124,6 @@ class Robot(Job): self.group_add = GroupAdd(wcf, self.gbm) # 抖音转视频 self.douyin = DouyinParser(wcf, self.gbm) - # DIFY 插件 - self.dify = DifyChat(wcf, self.gbm) if ChatType.is_in_chat_types(chat_type): if chat_type == ChatType.TIGER_BOT.value and TigerBot.value_check(self.config.TIGERBOT): @@ -341,11 +338,6 @@ class Robot(Job): self.douyin.handle_douyin_links(message=msg) except Exception as e: self.LOG.error(f"douyin.handle_douyin_links error: {e}") - # dify AI聊天 - try: - self.dify.handle_message(message=msg) - except Exception as e: - self.LOG.error(f"douyin.handle_douyin_links error: {e}") if msg.is_at(self.wxid): # 被@ self.toAt(msg)