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"]
command-tip = """
-----Bot-----
💬AI
"""
@@ -15,4 +16,8 @@ price = 0 # 用一次扣积分如果0则不扣
# Http代理设置
# 格式: http://用户名:密码@代理地址:代理端口
# 例如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 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()

View File

@@ -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)