dify 插件化

This commit is contained in:
liuwei
2025-03-19 17:37:02 +08:00
parent 1fa18848c0
commit 31516c3090
4 changed files with 119 additions and 63 deletions

7
plugins/dify/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# 从当前包的main模块导入DifyPlugin类
from .main import DifyPlugin
# 提供get_plugin函数返回插件实例
def get_plugin():
"""获取插件实例"""
return DifyPlugin()

View File

@@ -6,6 +6,7 @@ base-url = "http://192.168.2.240/v1" #Dify API接口base url
commands = ["ai", "dify", "聊天", "AI"] commands = ["ai", "dify", "聊天", "AI"]
command-tip = """ command-tip = """
-----Bot-----
💬AI 💬AI
""" """
@@ -16,3 +17,7 @@ price = 0 # 用一次扣积分如果0则不扣
# 格式: http://用户名:密码@代理地址:代理端口 # 格式: http://用户名:密码@代理地址:代理端口
# 例如http://127.0.0.1:7890 # 例如http://127.0.0.1:7890
http-proxy = "" http-proxy = ""
# 管理员和白名单用户是否免费使用
admin_ignore = true
whitelist_ignore = true

View File

@@ -1,85 +1,135 @@
import logging import logging
import tomllib
import os import os
import requests import requests
import json import json
import time import time
from typing import Dict, List, Optional from typing import Dict, Any, List, Optional, Tuple
from wcferry import WxMsg, Wcf
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 from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
class DifyChat: class DifyPlugin(MessagePluginInterface):
def __init__(self, wcf: Wcf, gbm: GroupBotManager): """Dify AI聊天插件"""
self.LOG = logging.getLogger(__name__)
self.wcf = wcf
self.gbm = gbm # 权限功能
# 加载配置文件 @property
with open("dify/config.toml", "rb") as f: def name(self) -> str:
plugin_config = tomllib.load(f) return "Dify聊天"
config = plugin_config["Dify"] @property
def version(self) -> str:
return "1.0.0"
# 基本配置 @property
self.enable = config["enable"] def description(self) -> str:
self.api_key = config["api-key"] return "提供基于Dify的AI聊天功能"
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 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]} # 会话上下文管理,格式: {group_id/wxid: [conversation_history]}
self.conversations: Dict[str, List[Dict]] = {} self.conversations: Dict[str, List[Dict]] = {}
# tokens 消耗统计,格式: {wxid: total_tokens} # tokens 消耗统计,格式: {wxid: total_tokens}
self.token_usage: Dict[str, int] = {} self.token_usage: Dict[str, int] = {}
# 最大上下文长度 # 最大上下文长度
self.max_history_length = 10 self.max_history_length = 10
# 会话过期时间(秒) # 会话过期时间(秒)
self.conversation_timeout = 3600 # 1小时 self.conversation_timeout = 3600 # 1小时
self.last_activity: Dict[str, float] = {} 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: 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) parts = content.split(" ", 1)
command = parts[0] 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(): if len(parts) < 2 or not parts[1].strip():
self.wcf.send_text(self.command_tip, wcf.send_text(f"{self.command_format}",
(message.roomid if message.from_group() else message.sender)) (roomid if roomid else sender), sender)
return return True, "命令格式错误"
# 检查权限 # 检查权限
if message.from_group() and self.gbm.get_group_permission(message.roomid, if roomid and gbm.get_group_permission(roomid, Feature.AI_CAPABILITY) == PermissionStatus.DISABLED:
Feature.AI_CAPABILITY) == PermissionStatus.DISABLED: return False, "没有权限"
return
# 获取查询内容 # 获取查询内容
query = parts[1].strip() query = parts[1].strip()
# 获取会话ID群聊使用群ID私聊使用个人wxid # 获取会话ID群聊使用群ID私聊使用个人wxid
session_id = message.roomid if message.from_group() else message.sender session_id = roomid if roomid else sender
# 获取用户ID # 获取用户ID
user_id = message.sender user_id = sender
# 检查是否需要扣除积分 # 检查是否需要扣除积分
if self.price > 0: if self.price > 0:
@@ -98,20 +148,22 @@ class DifyChat:
try: try:
# 调用Dify API获取回复 # 调用Dify API获取回复
response = self.chat_with_dify(session_id, user_id, query) response = self._chat_with_dify(session_id, user_id, query)
# 发送回复 # 发送回复
if response: if response:
self.wcf.send_text(response, wcf.send_text(response, (roomid if roomid else sender), sender if roomid else "")
(message.roomid if message.from_group() else message.sender), return True, "发送成功"
message.sender if message.from_group() else "") else:
except Exception as e: wcf.send_text("❌未能获取到回复,请稍后再试", (roomid if roomid else sender), sender if roomid else "")
self.LOG.error(f"Dify聊天出错{e}") return True, "未获取到回复"
self.wcf.send_text(f"❌请求出错:{str(e)}",
(message.roomid if message.from_group() else message.sender),
message.sender if message.from_group() else "")
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交互获取回复 与Dify API交互获取回复

View File

@@ -22,7 +22,6 @@ from base.func_xinghuo_web import XinghuoWeb
from base.func_claude import Claude from base.func_claude import Claude
from configuration import Config from configuration import Config
from constants import ChatType from constants import ChatType
from dify.dify_chat import DifyChat
from douyin_parser.main import DouyinParser from douyin_parser.main import DouyinParser
from game_task.game_task_encyclopedia import game_process_message, get_group_ids,run_random_task_assignment from game_task.game_task_encyclopedia import game_process_message, get_group_ids,run_random_task_assignment
from group_add.main import GroupAdd from group_add.main import GroupAdd
@@ -125,8 +124,6 @@ class Robot(Job):
self.group_add = GroupAdd(wcf, self.gbm) self.group_add = GroupAdd(wcf, self.gbm)
# 抖音转视频 # 抖音转视频
self.douyin = DouyinParser(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 ChatType.is_in_chat_types(chat_type):
if chat_type == ChatType.TIGER_BOT.value and TigerBot.value_check(self.config.TIGERBOT): 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) self.douyin.handle_douyin_links(message=msg)
except Exception as e: except Exception as e:
self.LOG.error(f"douyin.handle_douyin_links error: {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): # 被@ if msg.is_at(self.wxid): # 被@
self.toAt(msg) self.toAt(msg)