新增插件Python依赖管理系统,支持自动检查和安装依赖,优化依赖配置和错误处理,更新相关文档和示例代码。

This commit is contained in:
minecraft1024a
2025-08-13 12:32:07 +08:00
parent d6be518a77
commit 97351ce1ae
10 changed files with 730 additions and 36 deletions

View File

@@ -1,40 +1,192 @@
# 📦 插件依赖管理系统 # 插件Python依赖管理系统
现在的Python依赖包管理依然存在问题请保留你的`python_dependencies`属性,等待后续重构。 ## 概述
## 📚 详细教程 插件系统现在支持自动检查和安装Python包依赖。当插件初始化时系统会
### PythonDependency 类详解 1. 检查插件所需的Python包是否已安装
2. 验证包版本是否满足要求
3. 自动安装缺失的依赖包(可配置)
4. 提供详细的错误信息和日志
`PythonDependency`是依赖声明的核心类: ## 配置依赖
### 方式1: 简单字符串列表(向后兼容)
```python ```python
PythonDependency( from src.plugin_system import BasePlugin
package_name="PIL", # 导入时的包名
version=">=11.2.0", # 版本要求 @register_plugin
optional=False, # 是否为可选依赖 class MyPlugin(BasePlugin):
description="图像处理库", # 依赖描述 # 简单的字符串列表格式
install_name="pillow" # pip安装时的包名可选 python_dependencies: List[str] = [
"requests",
"beautifulsoup4>=4.9.0",
"httpx[socks]"
]
```
### 方式2: 详细的PythonDependency对象推荐
```python
from src.plugin_system import BasePlugin, PythonDependency
@register_plugin
class MyPlugin(BasePlugin):
python_dependencies: List[PythonDependency] = [
PythonDependency(
package_name="requests",
version=">=2.25.0",
description="HTTP请求库",
optional=False
),
PythonDependency(
package_name="beautifulsoup4",
version=">=4.9.0",
description="HTML解析库",
optional=False
),
PythonDependency(
package_name="httpx",
install_name="httpx[socks]", # 安装时使用的名称
description="支持SOCKS代理的HTTP客户端",
optional=True
)
]
```
## PythonDependency参数说明
- `package_name`: 包名称用于import检查
- `version`: 版本要求支持PEP 440格式如 ">=1.0.0", "==2.1.3"
- `install_name`: pip安装时使用的名称如果与package_name不同
- `description`: 依赖描述,用于日志和错误信息
- `optional`: 是否为可选依赖,可选依赖缺失不会阻止插件加载
## 全局配置
创建 `mmc/config/dependency_config.toml` 文件来配置依赖管理行为:
```toml
[dependency_management]
# 是否启用自动安装
auto_install = true
# 安装超时时间(秒)
auto_install_timeout = 300
# 是否使用代理
use_proxy = false
proxy_url = ""
# pip安装选项
pip_options = [
"--no-warn-script-location",
"--disable-pip-version-check"
]
# 是否允许自动安装(主开关)
allowed_auto_install = true
# 安装前是否提示用户
prompt_before_install = false
# 日志级别
install_log_level = "INFO"
```
## 代理配置
如果需要通过代理安装包,可以配置:
```toml
[dependency_management]
use_proxy = true
proxy_url = "http://proxy.example.com:8080"
# 或者 SOCKS5 代理
# proxy_url = "socks5://proxy.example.com:1080"
```
## 编程方式配置
也可以通过代码动态配置依赖管理:
```python
from src.plugin_system.utils.dependency_config import configure_dependency_settings
# 禁用自动安装
configure_dependency_settings(auto_install=False)
# 设置代理
configure_dependency_settings(
use_proxy=True,
proxy_url="http://proxy.example.com:8080"
) )
# 修改超时时间
configure_dependency_settings(auto_install_timeout=600)
``` ```
#### 参数说明 ## 工作流程
| 参数 | 类型 | 必需 | 说明 | 1. **插件初始化**: 当插件类被实例化时,系统自动检查依赖
|------|------|------|------| 2. **依赖标准化**: 将字符串格式的依赖转换为PythonDependency对象
| `package_name` | str | ✅ | Python导入时使用的包名`requests` | 3. **检查已安装**: 尝试导入每个依赖包并检查版本
| `version` | str | ❌ | 版本要求使用pip格式`>=1.0.0`, `==2.1.3` | 4. **自动安装**: 如果启用,自动安装缺失的依赖
| `optional` | bool | ❌ | 是否为可选依赖,默认`False` | 5. **错误处理**: 记录详细的错误信息和安装日志
| `description` | str | ❌ | 依赖的用途描述 |
| `install_name` | str | ❌ | pip安装时的包名默认与`package_name`相同,用于处理安装名称和导入名称不一致的情况 |
#### 版本格式示例 ## 日志输出示例
```python ```
# 常用版本格式 [Plugin:web_search_tool] 开始自动安装Python依赖: ['asyncddgs', 'httpx[socks]']
PythonDependency("requests", ">=2.25.0") # 最小版本 [Plugin:web_search_tool] ✅ 成功安装: asyncddgs
PythonDependency("numpy", ">=1.20.0,<2.0.0") # 版本范围 [Plugin:web_search_tool] ✅ 成功安装: httpx[socks]
PythonDependency("pillow", "==8.3.2") # 精确版本 [Plugin:web_search_tool] 🎉 所有依赖安装完成
PythonDependency("scipy", ">=1.7.0,!=1.8.0") # 排除特定版本 [Plugin:web_search_tool] Python依赖检查通过
``` ```
## 错误处理
当依赖检查失败时,系统会:
1. 记录详细的错误信息
2. 如果是可选依赖缺失,仅记录警告
3. 如果是必需依赖缺失且自动安装失败,阻止插件加载
4. 提供清晰的解决建议
## 最佳实践
1. **使用详细的PythonDependency对象** 以获得更好的控制和文档
2. **合理设置可选依赖** 避免非核心功能阻止插件加载
3. **指定版本要求** 确保兼容性
4. **添加描述信息** 帮助用户理解依赖的用途
5. **测试依赖配置** 在不同环境中验证依赖是否正确
## 安全考虑
- 自动安装功能默认启用,但可以通过配置禁用
- 所有安装操作都有详细的日志记录
- 支持设置安装超时以避免长时间挂起
- 可以通过`allowed_auto_install`全局禁用自动安装
## 故障排除
### 依赖安装失败
1. 检查网络连接
2. 验证代理设置
3. 检查pip配置
4. 查看详细的错误日志
### 版本冲突
1. 检查现有包的版本
2. 调整版本要求
3. 考虑使用虚拟环境
### 导入错误
1. 确认包名与导入名一致
2. 检查可选依赖配置
3. 验证安装是否成功

View File

@@ -38,6 +38,7 @@ from src.config.official_configs import (
CustomPromptConfig, CustomPromptConfig,
ScheduleConfig, ScheduleConfig,
VideoAnalysisConfig, VideoAnalysisConfig,
DependencyManagementConfig,
) )
from .api_ada_configs import ( from .api_ada_configs import (
@@ -354,6 +355,7 @@ class Config(ConfigBase):
voice: VoiceConfig voice: VoiceConfig
schedule: ScheduleConfig schedule: ScheduleConfig
utils_video: VideoAnalysisConfig = field(default_factory=lambda: VideoAnalysisConfig()) utils_video: VideoAnalysisConfig = field(default_factory=lambda: VideoAnalysisConfig())
dependency_management: DependencyManagementConfig = field(default_factory=lambda: DependencyManagementConfig())
@dataclass @dataclass

View File

@@ -451,7 +451,7 @@ class ExpressionConfig(ConfigBase):
# 如果都没有匹配,返回默认值 # 如果都没有匹配,返回默认值
return True, True, 300 return True, True, 300
def _get_stream_specific_config(self, chat_stream_id: str) -> Optional[tuple[bool, bool, int]]: def _get_stream_specific_config(self, chat_stream_id: str) -> Optional[tuple[bool, bool, float]]:
""" """
获取特定聊天流的表达配置 获取特定聊天流的表达配置
@@ -491,7 +491,7 @@ class ExpressionConfig(ConfigBase):
return None return None
def _get_global_config(self) -> Optional[tuple[bool, bool, int]]: def _get_global_config(self) -> Optional[tuple[bool, bool, float]]:
""" """
获取全局表达配置 获取全局表达配置
@@ -863,4 +863,36 @@ class VideoAnalysisConfig(ConfigBase):
"""批量分析时使用的提示词""" """批量分析时使用的提示词"""
enable_frame_timing: bool = True enable_frame_timing: bool = True
"""是否在分析中包含帧的时间信息""" """是否在分析中包含帧的时间信息"""
@dataclass
class DependencyManagementConfig(ConfigBase):
"""插件Python依赖管理配置类"""
auto_install: bool = True
"""是否启用自动安装Python依赖包"""
auto_install_timeout: int = 300
"""安装超时时间(秒)"""
use_proxy: bool = False
"""是否使用代理进行包安装"""
proxy_url: str = ""
"""代理URL如: "http://proxy.example.com:8080""socks5://proxy.example.com:1080" """
pip_options: list[str] = field(default_factory=lambda: [
"--no-warn-script-location",
"--disable-pip-version-check"
])
"""pip安装选项"""
allowed_auto_install: bool = True
"""是否允许自动安装(主开关),关闭后所有插件都不会自动安装依赖"""
prompt_before_install: bool = False
"""安装前是否提示用户(暂未实现)"""
install_log_level: str = "INFO"
"""依赖安装日志级别"""

View File

@@ -35,6 +35,10 @@ from .utils import (
# generate_plugin_manifest, # generate_plugin_manifest,
) )
# 导入依赖管理模块
from .utils.dependency_manager import get_dependency_manager, configure_dependency_manager
from .utils.dependency_config import get_dependency_config, configure_dependency_settings
from .apis import ( from .apis import (
chat_api, chat_api,
tool_api, tool_api,

View File

@@ -6,6 +6,7 @@ import toml
import json import json
import shutil import shutil
import datetime import datetime
from typing import Union
from src.common.logger import get_logger from src.common.logger import get_logger
from src.plugin_system.base.component_types import ( from src.plugin_system.base.component_types import (
@@ -42,8 +43,8 @@ class PluginBase(ABC):
@property @property
@abstractmethod @abstractmethod
def python_dependencies(self) -> List[PythonDependency]: def python_dependencies(self) -> List[Union[str, PythonDependency]]:
return [] # Python包依赖 return [] # Python包依赖支持字符串列表或PythonDependency对象列表
@property @property
@abstractmethod @abstractmethod
@@ -87,6 +88,12 @@ class PluginBase(ABC):
self.plugin_description = self.get_manifest_info("description", "") self.plugin_description = self.get_manifest_info("description", "")
self.plugin_author = self._get_author_name() self.plugin_author = self._get_author_name()
# 标准化Python依赖为PythonDependency对象
normalized_python_deps = self._normalize_python_dependencies(self.python_dependencies)
# 检查Python依赖
self._check_python_dependencies(normalized_python_deps)
# 创建插件信息对象 # 创建插件信息对象
self.plugin_info = PluginInfo( self.plugin_info = PluginInfo(
name=self.plugin_name, name=self.plugin_name,
@@ -98,7 +105,7 @@ class PluginBase(ABC):
is_built_in=False, is_built_in=False,
config_file=self.config_file_name or "", config_file=self.config_file_name or "",
dependencies=self.dependencies.copy(), dependencies=self.dependencies.copy(),
python_dependencies=self.python_dependencies.copy(), python_dependencies=normalized_python_deps,
# manifest相关信息 # manifest相关信息
manifest_data=self.manifest_data.copy(), manifest_data=self.manifest_data.copy(),
license=self.get_manifest_info("license", ""), license=self.get_manifest_info("license", ""),
@@ -564,6 +571,62 @@ class PluginBase(ABC):
return current return current
def _normalize_python_dependencies(self, dependencies: Any) -> List[PythonDependency]:
"""将依赖列表标准化为PythonDependency对象"""
from packaging.requirements import Requirement
normalized = []
for dep in dependencies:
if isinstance(dep, str):
try:
# 尝试解析为requirement格式 (如 "package>=1.0.0")
req = Requirement(dep)
version_spec = str(req.specifier) if req.specifier else ""
normalized.append(PythonDependency(
package_name=req.name,
version=version_spec,
install_name=dep # 保持原始的安装名称
))
except Exception:
# 如果解析失败,作为简单包名处理
normalized.append(PythonDependency(
package_name=dep,
install_name=dep
))
elif isinstance(dep, PythonDependency):
normalized.append(dep)
else:
logger.warning(f"{self.log_prefix} 未知的依赖格式: {dep}")
return normalized
def _check_python_dependencies(self, dependencies: List[PythonDependency]) -> bool:
"""检查Python依赖并尝试自动安装"""
if not dependencies:
logger.info(f"{self.log_prefix} 无Python依赖需要检查")
return True
try:
# 延迟导入以避免循环依赖
from src.plugin_system.utils.dependency_manager import get_dependency_manager
dependency_manager = get_dependency_manager()
success, errors = dependency_manager.check_and_install_dependencies(dependencies, self.plugin_name)
if success:
logger.info(f"{self.log_prefix} Python依赖检查通过")
return True
else:
logger.error(f"{self.log_prefix} Python依赖检查失败:")
for error in errors:
logger.error(f"{self.log_prefix} - {error}")
return False
except Exception as e:
logger.error(f"{self.log_prefix} Python依赖检查时发生异常: {e}", exc_info=True)
return False
@abstractmethod @abstractmethod
def register_plugin(self) -> bool: def register_plugin(self) -> bool:
""" """

View File

@@ -0,0 +1,102 @@
from typing import Optional
from src.common.logger import get_logger
logger = get_logger("dependency_config")
class DependencyConfig:
"""依赖管理配置类 - 现在使用全局配置"""
def __init__(self, global_config=None):
self._global_config = global_config
def _get_config(self):
"""获取全局配置对象"""
if self._global_config is not None:
return self._global_config
# 延迟导入以避免循环依赖
try:
from src.config.config import global_config
return global_config
except ImportError:
logger.warning("无法导入全局配置,使用默认设置")
return None
@property
def auto_install(self) -> bool:
"""是否启用自动安装"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.auto_install
return True
@property
def use_proxy(self) -> bool:
"""是否使用代理"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.use_proxy
return False
@property
def proxy_url(self) -> str:
"""代理URL"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.proxy_url
return ""
@property
def install_timeout(self) -> int:
"""安装超时时间(秒)"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.auto_install_timeout
return 300
@property
def pip_options(self) -> list:
"""pip安装选项"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.pip_options
return [
"--no-warn-script-location",
"--disable-pip-version-check"
]
@property
def allowed_auto_install(self) -> bool:
"""是否允许自动安装"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.allowed_auto_install
return True
@property
def prompt_before_install(self) -> bool:
"""安装前是否提示用户"""
config = self._get_config()
if config and hasattr(config, 'dependency_management'):
return config.dependency_management.prompt_before_install
return False
# 全局配置实例
_global_dependency_config: Optional[DependencyConfig] = None
def get_dependency_config() -> DependencyConfig:
"""获取全局依赖配置实例"""
global _global_dependency_config
if _global_dependency_config is None:
_global_dependency_config = DependencyConfig()
return _global_dependency_config
def configure_dependency_settings(**kwargs) -> None:
"""配置依赖管理设置 - 注意这个函数现在仅用于兼容性实际配置需要修改bot_config.toml"""
logger.info("依赖管理设置现在通过 bot_config.toml 的 [dependency_management] 节进行配置")
logger.info(f"请求的配置更改: {kwargs}")
logger.warning("configure_dependency_settings 函数仅用于兼容性,配置更改不会持久化")

View File

@@ -0,0 +1,289 @@
import subprocess
import sys
import importlib
import importlib.util
from typing import List, Dict, Tuple, Optional, Union, Any
from packaging import version
from packaging.requirements import Requirement
import re
from src.common.logger import get_logger
from src.plugin_system.base.component_types import PythonDependency
logger = get_logger("dependency_manager")
class DependencyManager:
"""Python包依赖管理器
负责检查和自动安装插件的Python包依赖
"""
def __init__(self, auto_install: bool = True, use_proxy: bool = False, proxy_url: Optional[str] = None):
"""初始化依赖管理器
Args:
auto_install: 是否自动安装缺失的依赖
use_proxy: 是否使用代理
proxy_url: 代理URL
"""
# 延迟导入配置以避免循环依赖
try:
from src.plugin_system.utils.dependency_config import get_dependency_config
config = get_dependency_config()
# 优先使用配置文件中的设置,参数作为覆盖
self.auto_install = config.auto_install if auto_install is True else auto_install
self.use_proxy = config.use_proxy if use_proxy is False else use_proxy
self.proxy_url = config.proxy_url if proxy_url is None else proxy_url
self.install_timeout = config.install_timeout
self.pip_options = config.pip_options.copy()
self.allowed_auto_install = config.allowed_auto_install
except Exception as e:
logger.warning(f"无法加载依赖配置,使用默认设置: {e}")
self.auto_install = auto_install
self.use_proxy = use_proxy
self.proxy_url = proxy_url
self.install_timeout = 300
self.pip_options = ["--no-warn-script-location", "--disable-pip-version-check"]
self.allowed_auto_install = True
def check_dependencies(self, dependencies: Any, plugin_name: str = "") -> Tuple[bool, List[str], List[str]]:
"""检查依赖包是否满足要求
Args:
dependencies: 依赖列表支持字符串或PythonDependency对象
plugin_name: 插件名称,用于日志记录
Returns:
Tuple[bool, List[str], List[str]]: (是否全部满足, 缺失的包, 错误信息)
"""
missing_packages = []
error_messages = []
log_prefix = f"[Plugin:{plugin_name}] " if plugin_name else ""
# 标准化依赖格式
normalized_deps = self._normalize_dependencies(dependencies)
for dep in normalized_deps:
try:
if not self._check_single_dependency(dep):
logger.info(f"{log_prefix}缺少依赖包: {dep.get_pip_requirement()}")
missing_packages.append(dep.get_pip_requirement())
except Exception as e:
error_msg = f"检查依赖 {dep.package_name} 时发生错误: {str(e)}"
error_messages.append(error_msg)
logger.error(f"{log_prefix}{error_msg}")
all_satisfied = len(missing_packages) == 0 and len(error_messages) == 0
if all_satisfied:
logger.debug(f"{log_prefix}所有Python依赖检查通过")
else:
logger.warning(f"{log_prefix}Python依赖检查失败: 缺失{len(missing_packages)}个包, {len(error_messages)}个错误")
return all_satisfied, missing_packages, error_messages
def install_dependencies(self, packages: List[str], plugin_name: str = "") -> Tuple[bool, List[str]]:
"""自动安装缺失的依赖包
Args:
packages: 要安装的包列表
plugin_name: 插件名称,用于日志记录
Returns:
Tuple[bool, List[str]]: (是否全部安装成功, 失败的包列表)
"""
if not packages:
return True, []
if not self.auto_install or not self.allowed_auto_install:
logger.info(f"[Plugin:{plugin_name}] 自动安装已禁用,跳过安装: {packages}")
return False, packages
log_prefix = f"[Plugin:{plugin_name}] " if plugin_name else ""
logger.info(f"{log_prefix}开始自动安装Python依赖: {packages}")
failed_packages = []
for package in packages:
try:
if self._install_single_package(package, plugin_name):
logger.info(f"{log_prefix}✅ 成功安装: {package}")
else:
failed_packages.append(package)
logger.error(f"{log_prefix}❌ 安装失败: {package}")
except Exception as e:
failed_packages.append(package)
logger.error(f"{log_prefix}❌ 安装 {package} 时发生异常: {str(e)}")
success = len(failed_packages) == 0
if success:
logger.info(f"{log_prefix}🎉 所有依赖安装完成")
else:
logger.error(f"{log_prefix}⚠️ 部分依赖安装失败: {failed_packages}")
return success, failed_packages
def check_and_install_dependencies(self, dependencies: Any, plugin_name: str = "") -> Tuple[bool, List[str]]:
"""检查并自动安装依赖(组合操作)
Args:
dependencies: 依赖列表
plugin_name: 插件名称
Returns:
Tuple[bool, List[str]]: (是否全部满足, 错误信息列表)
"""
# 第一步:检查依赖
all_satisfied, missing_packages, check_errors = self.check_dependencies(dependencies, plugin_name)
if all_satisfied:
return True, []
all_errors = check_errors.copy()
# 第二步:尝试安装缺失的包
if missing_packages and self.auto_install:
install_success, failed_packages = self.install_dependencies(missing_packages, plugin_name)
if not install_success:
all_errors.extend([f"安装失败: {pkg}" for pkg in failed_packages])
else:
# 安装成功后重新检查
recheck_satisfied, recheck_missing, recheck_errors = self.check_dependencies(dependencies, plugin_name)
if not recheck_satisfied:
all_errors.extend(recheck_errors)
all_errors.extend([f"安装后仍缺失: {pkg}" for pkg in recheck_missing])
else:
return True, []
else:
all_errors.extend([f"缺失依赖: {pkg}" for pkg in missing_packages])
return False, all_errors
def _normalize_dependencies(self, dependencies: Any) -> List[PythonDependency]:
"""将依赖列表标准化为PythonDependency对象"""
normalized = []
for dep in dependencies:
if isinstance(dep, str):
# 解析字符串格式的依赖
try:
# 尝试解析为requirement格式 (如 "package>=1.0.0")
req = Requirement(dep)
version_spec = str(req.specifier) if req.specifier else ""
normalized.append(PythonDependency(
package_name=req.name,
version=version_spec,
install_name=dep # 保持原始的安装名称
))
except Exception:
# 如果解析失败,作为简单包名处理
normalized.append(PythonDependency(
package_name=dep,
install_name=dep
))
elif isinstance(dep, PythonDependency):
normalized.append(dep)
else:
logger.warning(f"未知的依赖格式: {dep}")
return normalized
def _check_single_dependency(self, dep: PythonDependency) -> bool:
"""检查单个依赖是否满足要求"""
try:
# 尝试导入包
spec = importlib.util.find_spec(dep.package_name)
if spec is None:
return False
# 如果没有版本要求,导入成功就够了
if not dep.version:
return True
# 检查版本要求
try:
module = importlib.import_module(dep.package_name)
installed_version = getattr(module, '__version__', None)
if installed_version is None:
# 尝试其他常见的版本属性
installed_version = getattr(module, 'VERSION', None)
if installed_version is None:
logger.debug(f"无法获取包 {dep.package_name} 的版本信息,假设满足要求")
return True
# 解析版本要求
req = Requirement(f"{dep.package_name}{dep.version}")
return version.parse(str(installed_version)) in req.specifier
except Exception as e:
logger.debug(f"检查包 {dep.package_name} 版本时出错: {e}")
return True # 如果无法检查版本,假设满足要求
except ImportError:
return False
except Exception as e:
logger.error(f"检查依赖 {dep.package_name} 时发生未知错误: {e}")
return False
def _install_single_package(self, package: str, plugin_name: str = "") -> bool:
"""安装单个包"""
try:
cmd = [sys.executable, "-m", "pip", "install", package]
# 添加代理设置
if self.use_proxy and self.proxy_url:
cmd.extend(["--proxy", self.proxy_url])
# 添加配置的pip选项
cmd.extend(self.pip_options)
logger.debug(f"[Plugin:{plugin_name}] 执行安装命令: {' '.join(cmd)}")
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=self.install_timeout,
check=False
)
if result.returncode == 0:
return True
else:
logger.error(f"[Plugin:{plugin_name}] pip安装失败: {result.stderr}")
return False
except subprocess.TimeoutExpired:
logger.error(f"[Plugin:{plugin_name}] 安装 {package} 超时")
return False
except Exception as e:
logger.error(f"[Plugin:{plugin_name}] 安装 {package} 时发生异常: {e}")
return False
# 全局依赖管理器实例
_global_dependency_manager: Optional[DependencyManager] = None
def get_dependency_manager() -> DependencyManager:
"""获取全局依赖管理器实例"""
global _global_dependency_manager
if _global_dependency_manager is None:
_global_dependency_manager = DependencyManager()
return _global_dependency_manager
def configure_dependency_manager(auto_install: bool = True, use_proxy: bool = False, proxy_url: Optional[str] = None):
"""配置全局依赖管理器"""
global _global_dependency_manager
_global_dependency_manager = DependencyManager(
auto_install=auto_install,
use_proxy=use_proxy,
proxy_url=proxy_url
)

View File

@@ -694,7 +694,7 @@ class MaiZonePlugin(BasePlugin):
plugin_name: str = "MaiZonePlugin" plugin_name: str = "MaiZonePlugin"
enable_plugin: bool = True enable_plugin: bool = True
dependencies: List[str] = [] dependencies: List[str] = []
python_dependencies: List[str] = [] python_dependencies: List[str] = ["pytz"]
config_file_name: str = "config.toml" config_file_name: str = "config.toml"
# 配置节描述 # 配置节描述

View File

@@ -14,7 +14,8 @@ from src.plugin_system import (
ComponentInfo, ComponentInfo,
ConfigField, ConfigField,
llm_api, llm_api,
ToolParamType ToolParamType,
PythonDependency
) )
import httpx import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@@ -398,7 +399,30 @@ class WEBSEARCHPLUGIN(BasePlugin):
plugin_name: str = "web_search_tool" # 内部标识符 plugin_name: str = "web_search_tool" # 内部标识符
enable_plugin: bool = True enable_plugin: bool = True
dependencies: List[str] = [] # 插件依赖列表 dependencies: List[str] = [] # 插件依赖列表
python_dependencies: List[str] = ["asyncddgs","exa_py","httpx[socks]"] # Python包依赖列表 # Python包依赖列表 - 支持两种格式:
# 方式1: 简单字符串列表(向后兼容)
# python_dependencies: List[str] = ["asyncddgs", "exa_py", "httpx[socks]"]
# 方式2: 详细的PythonDependency对象推荐
python_dependencies: List[PythonDependency] = [
PythonDependency(
package_name="asyncddgs",
description="异步DuckDuckGo搜索库",
optional=False
),
PythonDependency(
package_name="exa_py",
description="Exa搜索API客户端库",
optional=True # 如果没有API密钥这个是可选的
),
PythonDependency(
package_name="httpx",
version=">=0.20.0",
install_name="httpx[socks]", # 安装时使用这个名称(包含可选依赖)
description="支持SOCKS代理的HTTP客户端库",
optional=False
)
]
config_file_name: str = "config.toml" # 配置文件名 config_file_name: str = "config.toml" # 配置文件名
# 配置节描述 # 配置节描述

View File

@@ -1,5 +1,5 @@
[inner] [inner]
version = "6.2.7" version = "6.2.8"
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
#如果你想要修改配置文件请递增version的值 #如果你想要修改配置文件请递增version的值
@@ -254,6 +254,32 @@ file_log_level = "DEBUG" # 文件日志级别,可选: DEBUG, INFO, WARNING, ER
suppress_libraries = ["faiss","httpx", "urllib3", "asyncio", "websockets", "httpcore", "requests", "peewee", "openai","uvicorn","jieba","maim_message"] # 完全屏蔽的库 suppress_libraries = ["faiss","httpx", "urllib3", "asyncio", "websockets", "httpcore", "requests", "peewee", "openai","uvicorn","jieba","maim_message"] # 完全屏蔽的库
library_log_levels = { "aiohttp" = "WARNING"} # 设置特定库的日志级别 library_log_levels = { "aiohttp" = "WARNING"} # 设置特定库的日志级别
[dependency_management] # 插件Python依赖管理配置
# 是否启用自动安装Python依赖包
auto_install = true
# 安装超时时间(秒)
auto_install_timeout = 300
# 是否使用代理进行包安装
use_proxy = false
proxy_url = "" # 代理URL如: "http://proxy.example.com:8080" 或 "socks5://proxy.example.com:1080"
# pip安装选项
pip_options = [
"--no-warn-script-location",
"--disable-pip-version-check"
]
# 是否允许自动安装(主开关),关闭后所有插件都不会自动安装依赖
allowed_auto_install = true
# 安装前是否提示用户(暂未实现)
prompt_before_install = false
# 依赖安装日志级别
install_log_level = "INFO"
[debug] [debug]
show_prompt = false # 是否显示prompt show_prompt = false # 是否显示prompt