From c818a2ac8d73ce262c984bbb816603d3ed52c098 Mon Sep 17 00:00:00 2001 From: fujie Date: Sun, 15 Mar 2026 18:14:23 +0800 Subject: [PATCH] fix(batch-install-plugins): support CRLF community plugin metadata - support CRLF docstrings and folded YAML metadata blocks - detect community repo plugins such as iChristGit/OpenWebui-Tools correctly - align README, mirrored docs, and announcement wording with actual behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../tools/batch-install-plugins-tool.md | 97 +++++++----- .../tools/batch-install-plugins-tool.zh.md | 141 ++++++++++-------- .../batch-install-plugins/ANNOUNCEMENT.md | 132 ++++++++++++++++ .../batch-install-plugins/ANNOUNCEMENT_CN.md | 132 ++++++++++++++++ plugins/tools/batch-install-plugins/README.md | 93 +++++++----- .../tools/batch-install-plugins/README_CN.md | 95 +++++++----- .../batch_install_plugins.py | 111 ++++++++++++-- .../tools/test_batch_install_plugins.py | 102 +++++++++++++ 8 files changed, 725 insertions(+), 178 deletions(-) create mode 100644 plugins/tools/batch-install-plugins/ANNOUNCEMENT.md create mode 100644 plugins/tools/batch-install-plugins/ANNOUNCEMENT_CN.md diff --git a/docs/plugins/tools/batch-install-plugins-tool.md b/docs/plugins/tools/batch-install-plugins-tool.md index 2442006..ffb18b9 100644 --- a/docs/plugins/tools/batch-install-plugins-tool.md +++ b/docs/plugins/tools/batch-install-plugins-tool.md @@ -1,8 +1,6 @@ # Batch Install Plugins from GitHub -**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.0.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT - ---- +**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.0.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) One-click batch install plugins from GitHub repositories to your OpenWebUI instance. @@ -10,7 +8,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta - **One-Click Install**: Install all plugins with a single command - **Auto-Update**: Automatically updates previously installed plugins -- **GitHub Support**: Install plugins from any GitHub repository +- **Public GitHub Support**: Install plugins from any public GitHub repository - **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins - **Confirmation**: Shows plugin list before installing, allows selective installation - **i18n**: Supports 11 languages @@ -53,68 +51,91 @@ User Input ## How to Use 1. Open OpenWebUI and go to **Workspace > Tools** -2. Install **Batch Install Plugins from GitHub** from the official marketplace +2. Install **Batch Install Plugins from GitHub** from the marketplace 3. Enable this tool for your model/chat 4. Ask the model to install plugins +## Interactive Installation Workflow + +Each request handles one repository. To mix repositories, send another request after the previous installation completes. + +### Example Installation Sequence + +1. **Start with My Collection** + ``` + "Install all plugins from Fu-Jie/openwebui-extensions" + ``` + Review the confirmation dialog, approve, and the plugins are installed. + +2. **Add a Community Collection** + ``` + "Install all plugins from iChristGit/OpenWebui-Tools" + ``` + Add more plugins from a different repository. Already installed plugins are updated seamlessly. + +3. **Install a Specific Type** + ``` + "Install only pipe plugins from Haervwe/open-webui-tools" + ``` + Pick specific plugin types from another repository, or exclude certain keywords. + +4. **Use Your Own Repository** + ``` + "Install all plugins from your-username/your-collection" + ``` + Works with any public GitHub repository in `owner/repo` format. + ## Usage Examples +Each line below is a separate request: + ``` +# Install from my default collection "Install all plugins" -"Install all plugins from github.com/username/repo" -"Install only pipe plugins" -"Install action and filter plugins" -"Install all plugins, exclude_keywords=copilot" -``` -## Popular Plugin Repositories - -Here are some popular repositories with many plugins you can install: - -### Community Collections - -``` -# Install all plugins from iChristGit's collection +# Add another repository in a new request "Install all plugins from iChristGit/OpenWebui-Tools" -# Install all tools from Haervwe's tools collection -"Install all plugins from Haervwe/open-webui-tools" +# Add only tools from a different repository +"Install only tool plugins from Haervwe/open-webui-tools" -# Install all plugins from Classic298's repository -"Install all plugins from Classic298/open-webui-plugins" +# Continue building your setup with another request +"Install only action plugins from Classic298/open-webui-plugins" -# Install all functions from suurt8ll's collection -"Install all plugins from suurt8ll/open_webui_functions" - -# Install only specific types (e.g., only tools) -"Install only tool plugins from iChristGit/OpenWebui-Tools" - -# Exclude certain keywords while installing +# Filter out unwanted plugins "Install all plugins from Haervwe/open-webui-tools, exclude_keywords=test,deprecated" + +# Install from your own public repository +"Install all plugins from your-username/my-plugin-collection" ``` -### Supported Repositories +## Popular Public Repositories -- `Fu-Jie/openwebui-extensions` - Default, official plugin collection -- `iChristGit/OpenWebui-Tools` - Comprehensive tool and plugin collection -- `Haervwe/open-webui-tools` - Specialized tools and utilities -- `Classic298/open-webui-plugins` - Various plugin implementations +The tool works with any public GitHub repository in `owner/repo` format. Popular starting points include: + +- `Fu-Jie/openwebui-extensions` - My personal collection and the default source +- `iChristGit/OpenWebui-Tools` - Comprehensive tools and plugins +- `Haervwe/open-webui-tools` - Utility-focused extensions +- `Classic298/open-webui-plugins` - Mixed community plugins - `suurt8ll/open_webui_functions` - Function-based plugins +- `rbb-dev/Open-WebUI-OpenRouter-pipe` - OpenRouter pipe integration + +To combine repositories, run the tool again with a different `repo` after the previous installation completes. ## Default Repository -When no repository is specified, defaults to `Fu-Jie/openwebui-extensions`. +When no repository is specified, the tool uses `Fu-Jie/openwebui-extensions` (my personal collection). ## Plugin Detection Rules ### Fu-Jie/openwebui-extensions (Strict) -For the default repository, plugins must have: +For the default repository, the tool applies stricter filtering: 1. A `.py` file containing `class Tools:`, `class Filter:`, `class Pipe:`, or `class Action:` -2. A docstring with `title:`, `description:`, and **`openwebui_id:`** fields +2. A docstring with `title:`, `description:`, and **`openwebui_id:`** metadata 3. Filename must not end with `_cn` -### Other GitHub Repositories +### Other Public GitHub Repositories For other repositories: 1. A `.py` file containing `class Tools:`, `class Filter:`, `class Pipe:`, or `class Action:` diff --git a/docs/plugins/tools/batch-install-plugins-tool.zh.md b/docs/plugins/tools/batch-install-plugins-tool.zh.md index 4386ff0..4b359e8 100644 --- a/docs/plugins/tools/batch-install-plugins-tool.zh.md +++ b/docs/plugins/tools/batch-install-plugins-tool.zh.md @@ -1,21 +1,19 @@ -# Batch Install Plugins from GitHub - 从 GitHub 批量安装插件 +# Batch Install Plugins from GitHub -**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 1.0.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可:** MIT +**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 1.0.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) ---- +一键将 GitHub 仓库中的插件批量安装到你的 OpenWebUI 实例。 -一键从 GitHub 仓库批量安装插件到你的 OpenWebUI 实例。 +## 主要功能 -## ✨ 主要特性 +- 一键安装:单个命令安装所有插件 +- 自动更新:自动更新之前安装过的插件 +- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件 +- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件 +- 安装确认:安装前显示插件列表,支持选择性安装 +- 国际化:支持 11 种语言 -- **一键安装**: 一条命令安装所有插件 -- **自动更新**: 自动更新之前已安装的插件 -- **GitHub 支持**: 支持从任何 GitHub 仓库安装插件 -- **多类型支持**: 支持 Pipe、Action、Filter 和 Tool 插件 -- **确认机制**: 安装前显示插件列表,允许选择性安装 -- **国际化**: 支持 11 种语言 - -## 工作流 +## 流程 ``` 用户输入 @@ -23,13 +21,13 @@ ▼ ┌─────────────────────────────────────┐ │ 从 GitHub 发现插件 │ -│ (获取文件树 + 解析 .py) │ +│ (获取文件树 + 解析 .py 文件) │ └─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 按类型和关键词过滤 │ -│ (tool/filter/pipe/action) │ +│ (tool/filter/pipe/action) │ └─────────────────────────────────────┘ │ ▼ @@ -42,90 +40,113 @@ │ ▼ ┌─────────────────────────────────────┐ -│ 安装到 OpenWebUI │ -│ (更新或创建每个插件) │ +│ 安装到 OpenWebUI │ +│ (更新或创建每个插件) │ └─────────────────────────────────────┘ │ ▼ 完成 ``` -## 🚀 使用方法 +## 使用方法 -1. 打开 OpenWebUI,进入 **工作区 > 工具** -2. 从官方市场安装 **Batch Install Plugins from GitHub** -3. 为你的模型/聊天启用此工具 -4. 让模型安装插件 +1. 打开 OpenWebUI,进入 **Workspace > Tools** +2. 从市场安装 **Batch Install Plugins from GitHub** +3. 为你的模型/对话启用此工具 +4. 让模型调用工具来安装插件 + +## 交互式安装工作流 + +每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。 + +### 安装序列示例 + +1. **先从我的合集开始** + ``` + "安装 Fu-Jie/openwebui-extensions 中的所有插件" + ``` + 查看确认对话框,批准后插件开始安装。 + +2. **再添加社区合集** + ``` + "从 iChristGit/OpenWebui-Tools 安装所有插件" + ``` + 从不同仓库添加更多插件。已安装的插件会无缝更新。 + +3. **按类型继续安装** + ``` + "从 Haervwe/open-webui-tools 仅安装 pipe 插件" + ``` + 从另一个仓库选择特定类型的插件,或排除某些关键词。 + +4. **使用你自己的仓库** + ``` + "从 your-username/your-collection 安装所有插件" + ``` + 支持任何公开的 GitHub 仓库,格式为 `owner/repo`。 ## 使用示例 +下面每一行都是一次独立请求: + ``` +# 从默认合集安装 "安装所有插件" -"从 github.com/username/repo 安装所有插件" -"仅安装 pipe 插件" -"安装 action 和 filter 插件" -"安装所有插件,exclude_keywords=copilot" -``` -## 热门插件仓库 - -这些是包含大量插件的热门仓库,你可以从中安装插件: - -### 社区合集 - -``` -# 从 iChristGit 的集合安装所有插件 +# 在下一次请求中加入其他仓库 "从 iChristGit/OpenWebui-Tools 安装所有插件" -# 从 Haervwe 的工具集合只安装工具 -"从 Haervwe/open-webui-tools 安装所有插件" +# 从其他仓库只安装工具 +"从 Haervwe/open-webui-tools 仅安装 tool 插件" -# 从 Classic298 的仓库安装所有插件 -"从 Classic298/open-webui-plugins 安装所有插件" +# 再继续补充另一类插件 +"从 Classic298/open-webui-plugins 安装仅 action 插件" -# 从 suurt8ll 的集合安装所有函数 -"从 suurt8ll/open_webui_functions 安装所有插件" +# 过滤不想安装的插件 +"从 Haervwe/open-webui-tools 安装所有插件, exclude_keywords=test,deprecated" -# 仅安装特定类型的插件(比如只安装工具) -"从 iChristGit/OpenWebui-Tools 仅安装 tool 插件" - -# 安装时排除特定关键词 -"从 Haervwe/open-webui-tools 安装所有插件,exclude_keywords=test,deprecated" +# 从你自己的公开仓库安装 +"从 your-username/my-plugin-collection 安装所有插件" ``` -### 支持的仓库 +## 热门公开仓库 -- `Fu-Jie/openwebui-extensions` - 默认的官方插件集合 +该工具支持任何公开 GitHub 仓库,格式为 `owner/repo`。这些都是不错的起点: + +- `Fu-Jie/openwebui-extensions` - 我的个人合集,也是默认来源 - `iChristGit/OpenWebui-Tools` - 全面的工具和插件集合 -- `Haervwe/open-webui-tools` - 专业的工具和实用程序 -- `Classic298/open-webui-plugins` - 各种插件实现 -- `suurt8ll/open_webui_functions` - 基于函数的插件 +- `Haervwe/open-webui-tools` - 偏工具型的扩展集合 +- `Classic298/open-webui-plugins` - 混合型社区插件集合 +- `suurt8ll/open_webui_functions` - 基于函数的插件集合 +- `rbb-dev/Open-WebUI-OpenRouter-pipe` - OpenRouter pipe 集成 + +如需混合多个来源,请在上一次安装完成后,换一个 `repo` 再调用一次工具。 ## 默认仓库 -未指定仓库时,默认使用 `Fu-Jie/openwebui-extensions`。 +未指定仓库时,工具会使用 `Fu-Jie/openwebui-extensions`(我的个人合集)。 ## 插件检测规则 ### Fu-Jie/openwebui-extensions(严格模式) -对于默认仓库,插件必须有: +对于默认仓库,工具会采用更严格的筛选规则: 1. 包含 `class Tools:`、`class Filter:`、`class Pipe:` 或 `class Action:` 的 `.py` 文件 -2. 包含 `title:`、`description:` 和 **`openwebui_id:`** 字段的文档字符串 +2. Docstring 中包含 `title:`、`description:` 和 **`openwebui_id:`** 元数据 3. 文件名不能以 `_cn` 结尾 -### 其他 GitHub 仓库 +### 其他公开 GitHub 仓库 -对于其他仓库: +其他仓库的插件必须满足: 1. 包含 `class Tools:`、`class Filter:`、`class Pipe:` 或 `class Action:` 的 `.py` 文件 -2. 包含 `title:` 和 `description:` 字段的文档字符串 +2. Docstring 中包含 `title:` 和 `description:` 字段 -## 配置 (Valves) +## 配置(Valves) | 参数 | 默认值 | 描述 | | --- | --- | --- | -| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 要跳过的关键词,用逗号分隔 | -| `TIMEOUT` | `20` | 请求超时时间(秒) | +| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 | +| `TIMEOUT` | `20` | 请求超时时间(秒)| ## 确认超时时间 diff --git a/plugins/tools/batch-install-plugins/ANNOUNCEMENT.md b/plugins/tools/batch-install-plugins/ANNOUNCEMENT.md new file mode 100644 index 0000000..c23dcb1 --- /dev/null +++ b/plugins/tools/batch-install-plugins/ANNOUNCEMENT.md @@ -0,0 +1,132 @@ +# 🎉 Introducing Batch Install Plugins v1.0.0 + +## Headline +**One-Click Batch Installation of OpenWebUI Plugins - Solving the Plugin Setup Headache** + +## Introduction +Installing plugins in OpenWebUI used to be tedious: searching for plugins, downloading them one by one, and hoping everything works in your environment. Today, we're excited to announce **Batch Install Plugins from GitHub** v1.0.0 — a powerful new tool that transforms plugin installation from a chore into a single command. + +## Key Highlights + +### 🚀 One-Click Bulk Installation +- Install multiple plugins from any public GitHub repository with a single command +- Automatically discovers plugins and validates them +- Updates previously installed plugins seamlessly + +### ✅ Smart Safety Features +- Shows a confirmation dialog with the plugin list before installation +- Users can review and approve before proceeding +- Automatically excludes the tool itself from installation + +### 🌍 Multi-Repository Support +Install plugins from **any public GitHub repository**, including your own community collections: +- Use one request per repository, then call the tool again to combine multiple sources +- **Default**: Fu-Jie/openwebui-extensions (my personal collection) +- Works with public repositories in `owner/repo` format +- Mix and match plugins: install from my collection first, then add community collections in subsequent calls + +### 🔧 Container-Friendly +- Automatically handles port mapping issues in containerized deployments +- Smart fallback: retries with localhost:8080 if the primary connection fails +- Rich debugging logs for troubleshooting + +### 🌐 Global Support +- Complete i18n support for 11 languages +- All error messages localized and user-friendly +- Works seamlessly across different deployment scenarios + +## How It Works: Interactive Installation Workflow + +Each request handles one repository. To combine multiple repositories, send another request after the previous installation completes. + +1. **Start with My Collection** + ``` + "Install all plugins from Fu-Jie/openwebui-extensions" + ``` + Review the confirmation dialog, approve, and the plugins are installed. + +2. **Add a Community Collection** + ``` + "Install all plugins from iChristGit/OpenWebui-Tools" + ``` + Add more plugins from a different repository. Already installed plugins are updated seamlessly. + +3. **Install a Specific Type** + ``` + "Install only pipe plugins from Haervwe/open-webui-tools" + ``` + Pick specific plugin types from another repository, or exclude certain keywords. + +4. **Use Your Own Public Repository** + ``` + "Install all plugins from your-username/your-collection" + ``` + Works with any public GitHub repository in `owner/repo` format. + +## Popular Community Collections + +Ready-to-install from these community favorites: + +#### **iChristGit/OpenWebui-Tools** +Comprehensive tools and plugins for various use cases. + +#### **Haervwe/open-webui-tools** +Specialized utilities for extending OpenWebUI functionality. + +#### **Classic298/open-webui-plugins** +Diverse plugin implementations for different scenarios. + +#### **suurt8ll/open_webui_functions** +Function-based plugins for custom integrations. + +#### **rbb-dev/Open-WebUI-OpenRouter-pipe** +OpenRouter API pipe integration for advanced model access. + +## Usage Examples + +Each line below is a separate request: + +``` +# Start with my collection +"Install all plugins" + +# Add community plugins in a new request +"Install all plugins from iChristGit/OpenWebui-Tools" + +# Add only one plugin type from another repository +"Install only tool plugins from Haervwe/open-webui-tools" + +# Continue building your setup +"Install only action plugins from Classic298/open-webui-plugins" + +# Filter out unwanted plugins +"Install all plugins from Haervwe/open-webui-tools, exclude_keywords=test,deprecated" + +# Install from your own public repository +"Install all plugins from your-username/my-plugin-collection" +``` + +## Technical Excellence + +- **Async Architecture**: Non-blocking I/O for better performance +- **httpx Integration**: Modern async HTTP client with timeout protection +- **Comprehensive Tests**: 8 regression tests with 100% pass rate +- **Full Event Support**: Proper OpenWebUI event injection with fallback handling + +## Installation + +1. Open OpenWebUI → Workspace > Tools +2. Install **Batch Install Plugins from GitHub** from the marketplace +3. Enable it for your model/chat +4. Start using it with commands like "Install all plugins" + +## Links + +- **GitHub Repository**: https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins +- **Release Notes**: https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.0.0.md + +## Community Love + +If this tool has been helpful to you, please give us a ⭐ on [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) — it truly motivates us to keep improving! + +**Thank you for supporting the OpenWebUI community! 🙏** diff --git a/plugins/tools/batch-install-plugins/ANNOUNCEMENT_CN.md b/plugins/tools/batch-install-plugins/ANNOUNCEMENT_CN.md new file mode 100644 index 0000000..7b06596 --- /dev/null +++ b/plugins/tools/batch-install-plugins/ANNOUNCEMENT_CN.md @@ -0,0 +1,132 @@ +# 🎉 Batch Install Plugins 首发 v1.0.0 + +## 标题 +**一键批量安装 OpenWebUI 插件 - 解决装机烦恼** + +## 前言 +在 OpenWebUI 中安装插件曾经很麻烦:逐个搜索、逐个下载、祈祷一切顺利。今天,我们欣然宣布 **Batch Install Plugins from GitHub** v1.0.0 的问世 — 一款强大的新工具,让插件安装从苦差事变成一条简单命令。 + +## 核心特性 + +### 🚀 一键批量安装 +- 从任意公开 GitHub 仓库用一条命令安装多个插件 +- 自动发现插件并进行验证 +- 无缝更新已安装的插件 + +### ✅ 智能安全保障 +- 安装前显示插件列表确认对话框 +- 用户可在安装前查看和审批 +- 自动排除工具自身,避免重复安装 + +### 🌍 多仓库支持 +支持从**任意公开 GitHub 仓库**安装插件,包括你自己的社区合集: +- 每次请求处理一个仓库,需要时可再次调用工具来组合多个来源 +- **默认**:Fu-Jie/openwebui-extensions(我的个人合集) +- 支持公开仓库,格式为 `owner/repo` +- 混合搭配:先从我的合集安装,再通过后续调用添加社区合集 + +### 🔧 容器友好 +- 自动处理容器部署中的端口映射问题 +- 智能降级:主连接失败时自动重试 localhost:8080 +- 丰富的调试日志便于故障排除 + +### 🌐 全球化支持 +- 完整支持 11 种语言 +- 所有错误提示本地化且用户友好 +- 跨不同部署场景无缝运行 + +## 工作流程:交互式安装 + +每次请求处理一个仓库。如需组合多个仓库,请在上一次安装完成后再发起下一次请求。 + +1. **先从我的合集开始** + ``` + "安装 Fu-Jie/openwebui-extensions 中的所有插件" + ``` + 查看确认对话框,批准后开始安装。 + +2. **再添加社区合集** + ``` + "从 iChristGit/OpenWebui-Tools 安装所有插件" + ``` + 从不同仓库添加更多插件。已安装的插件会无缝更新。 + +3. **按类型继续安装** + ``` + "从 Haervwe/open-webui-tools 仅安装 pipe 插件" + ``` + 从另一个仓库选择特定类型的插件,或排除某些关键词。 + +4. **使用你自己的公开仓库** + ``` + "从 your-username/your-collection 安装所有插件" + ``` + 支持任何公开 GitHub 仓库,格式为 `owner/repo`。 + +## 热门社区合集 + +这些社区精选都已准备好安装: + +#### **iChristGit/OpenWebui-Tools** +包含各种工具和插件的综合集合。 + +#### **Haervwe/open-webui-tools** +专业工具和实用程序,扩展 OpenWebUI 功能。 + +#### **Classic298/open-webui-plugins** +多样化的插件实现,满足不同场景。 + +#### **suurt8ll/open_webui_functions** +基于函数的插件,用于自定义集成。 + +#### **rbb-dev/Open-WebUI-OpenRouter-pipe** +OpenRouter API pipe 集成,提供高级模型访问。 + +## 使用示例 + +下面每一行都是一次独立请求: + +``` +# 先从我的合集开始 +"安装所有插件" + +# 在下一次请求中加入社区插件 +"从 iChristGit/OpenWebui-Tools 安装所有插件" + +# 从其他仓库只安装某一种类型 +"从 Haervwe/open-webui-tools 仅安装 tool 插件" + +# 继续补充你的插件组合 +"从 Classic298/open-webui-plugins 安装仅 action 插件" + +# 过滤不想安装的插件 +"从 Haervwe/open-webui-tools 安装所有插件,exclude_keywords=test,deprecated" + +# 从你自己的公开仓库安装 +"从 your-username/my-plugin-collection 安装所有插件" +``` + +## 技术亮点 + +- **异步架构**:非阻塞 I/O,性能更优 +- **httpx 集成**:现代化异步 HTTP 客户端,包含超时保护 +- **完整测试**:8 个回归测试,100% 通过率 +- **完整事件支持**:正确处理 OpenWebUI 事件注入,提供回退机制 + +## 安装方法 + +1. 打开 OpenWebUI → 工作区 > 工具 +2. 从市场安装 **Batch Install Plugins from GitHub** +3. 为你的模型/对话启用此工具 +4. 开始使用,比如说"安装所有插件" + +## 相关链接 + +- **GitHub 仓库**:https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins +- **发布说明**:https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.0.0_CN.md + +## 社区支持 + +如果这个工具对你有帮助,欢迎到 [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) 点个 ⭐ — 这将是我们持续改进的动力! + +**感谢你支持 OpenWebUI 社区!🙏** diff --git a/plugins/tools/batch-install-plugins/README.md b/plugins/tools/batch-install-plugins/README.md index f70e08e..ffb18b9 100644 --- a/plugins/tools/batch-install-plugins/README.md +++ b/plugins/tools/batch-install-plugins/README.md @@ -8,7 +8,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta - **One-Click Install**: Install all plugins with a single command - **Auto-Update**: Automatically updates previously installed plugins -- **GitHub Support**: Install plugins from any GitHub repository +- **Public GitHub Support**: Install plugins from any public GitHub repository - **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins - **Confirmation**: Shows plugin list before installing, allows selective installation - **i18n**: Supports 11 languages @@ -51,68 +51,91 @@ User Input ## How to Use 1. Open OpenWebUI and go to **Workspace > Tools** -2. Install **Batch Install Plugins from GitHub** from the official marketplace +2. Install **Batch Install Plugins from GitHub** from the marketplace 3. Enable this tool for your model/chat 4. Ask the model to install plugins +## Interactive Installation Workflow + +Each request handles one repository. To mix repositories, send another request after the previous installation completes. + +### Example Installation Sequence + +1. **Start with My Collection** + ``` + "Install all plugins from Fu-Jie/openwebui-extensions" + ``` + Review the confirmation dialog, approve, and the plugins are installed. + +2. **Add a Community Collection** + ``` + "Install all plugins from iChristGit/OpenWebui-Tools" + ``` + Add more plugins from a different repository. Already installed plugins are updated seamlessly. + +3. **Install a Specific Type** + ``` + "Install only pipe plugins from Haervwe/open-webui-tools" + ``` + Pick specific plugin types from another repository, or exclude certain keywords. + +4. **Use Your Own Repository** + ``` + "Install all plugins from your-username/your-collection" + ``` + Works with any public GitHub repository in `owner/repo` format. + ## Usage Examples +Each line below is a separate request: + ``` +# Install from my default collection "Install all plugins" -"Install all plugins from github.com/username/repo" -"Install only pipe plugins" -"Install action and filter plugins" -"Install all plugins, exclude_keywords=copilot" -``` -## Popular Plugin Repositories - -Here are some popular repositories with many plugins you can install: - -### Community Collections - -``` -# Install all plugins from iChristGit's collection +# Add another repository in a new request "Install all plugins from iChristGit/OpenWebui-Tools" -# Install all tools from Haervwe's tools collection -"Install all plugins from Haervwe/open-webui-tools" +# Add only tools from a different repository +"Install only tool plugins from Haervwe/open-webui-tools" -# Install all plugins from Classic298's repository -"Install all plugins from Classic298/open-webui-plugins" +# Continue building your setup with another request +"Install only action plugins from Classic298/open-webui-plugins" -# Install all functions from suurt8ll's collection -"Install all plugins from suurt8ll/open_webui_functions" - -# Install only specific types (e.g., only tools) -"Install only tool plugins from iChristGit/OpenWebui-Tools" - -# Exclude certain keywords while installing +# Filter out unwanted plugins "Install all plugins from Haervwe/open-webui-tools, exclude_keywords=test,deprecated" + +# Install from your own public repository +"Install all plugins from your-username/my-plugin-collection" ``` -### Supported Repositories +## Popular Public Repositories -- `Fu-Jie/openwebui-extensions` - Default, official plugin collection -- `iChristGit/OpenWebui-Tools` - Comprehensive tool and plugin collection -- `Haervwe/open-webui-tools` - Specialized tools and utilities -- `Classic298/open-webui-plugins` - Various plugin implementations +The tool works with any public GitHub repository in `owner/repo` format. Popular starting points include: + +- `Fu-Jie/openwebui-extensions` - My personal collection and the default source +- `iChristGit/OpenWebui-Tools` - Comprehensive tools and plugins +- `Haervwe/open-webui-tools` - Utility-focused extensions +- `Classic298/open-webui-plugins` - Mixed community plugins - `suurt8ll/open_webui_functions` - Function-based plugins +- `rbb-dev/Open-WebUI-OpenRouter-pipe` - OpenRouter pipe integration + +To combine repositories, run the tool again with a different `repo` after the previous installation completes. ## Default Repository -When no repository is specified, defaults to `Fu-Jie/openwebui-extensions`. +When no repository is specified, the tool uses `Fu-Jie/openwebui-extensions` (my personal collection). ## Plugin Detection Rules ### Fu-Jie/openwebui-extensions (Strict) -For the default repository, plugins must have: +For the default repository, the tool applies stricter filtering: 1. A `.py` file containing `class Tools:`, `class Filter:`, `class Pipe:`, or `class Action:` -2. A docstring with `title:`, `description:`, and **`openwebui_id:`** fields +2. A docstring with `title:`, `description:`, and **`openwebui_id:`** metadata 3. Filename must not end with `_cn` -### Other GitHub Repositories +### Other Public GitHub Repositories For other repositories: 1. A `.py` file containing `class Tools:`, `class Filter:`, `class Pipe:`, or `class Action:` diff --git a/plugins/tools/batch-install-plugins/README_CN.md b/plugins/tools/batch-install-plugins/README_CN.md index d988e74..4b359e8 100644 --- a/plugins/tools/batch-install-plugins/README_CN.md +++ b/plugins/tools/batch-install-plugins/README_CN.md @@ -8,7 +8,7 @@ - 一键安装:单个命令安装所有插件 - 自动更新:自动更新之前安装过的插件 -- GitHub 支持:从任意 GitHub 仓库安装插件 +- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件 - 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件 - 安装确认:安装前显示插件列表,支持选择性安装 - 国际化:支持 11 种语言 @@ -51,68 +51,91 @@ ## 使用方法 1. 打开 OpenWebUI,进入 **Workspace > Tools** -2. 从官方市场安装 **Batch Install Plugins from GitHub** +2. 从市场安装 **Batch Install Plugins from GitHub** 3. 为你的模型/对话启用此工具 -4. 让模型调用工具方法 +4. 让模型调用工具来安装插件 + +## 交互式安装工作流 + +每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。 + +### 安装序列示例 + +1. **先从我的合集开始** + ``` + "安装 Fu-Jie/openwebui-extensions 中的所有插件" + ``` + 查看确认对话框,批准后插件开始安装。 + +2. **再添加社区合集** + ``` + "从 iChristGit/OpenWebui-Tools 安装所有插件" + ``` + 从不同仓库添加更多插件。已安装的插件会无缝更新。 + +3. **按类型继续安装** + ``` + "从 Haervwe/open-webui-tools 仅安装 pipe 插件" + ``` + 从另一个仓库选择特定类型的插件,或排除某些关键词。 + +4. **使用你自己的仓库** + ``` + "从 your-username/your-collection 安装所有插件" + ``` + 支持任何公开的 GitHub 仓库,格式为 `owner/repo`。 ## 使用示例 +下面每一行都是一次独立请求: + ``` +# 从默认合集安装 "安装所有插件" -"从 github.com/username/repo 安装所有插件" -"只安装 pipe 插件" -"安装 action 和 filter 插件" -"安装所有插件, exclude_keywords=copilot" -``` -## 热门插件仓库 - -这些是包含大量插件的热门仓库,你可以从中安装插件: - -### 社区合集 - -``` -# 从 iChristGit 的集合安装所有插件 +# 在下一次请求中加入其他仓库 "从 iChristGit/OpenWebui-Tools 安装所有插件" -# 从 Haervwe 的工具集合只安装工具 -"从 Haervwe/open-webui-tools 安装所有插件" +# 从其他仓库只安装工具 +"从 Haervwe/open-webui-tools 仅安装 tool 插件" -# 从 Classic298 的仓库安装所有插件 -"从 Classic298/open-webui-plugins 安装所有插件" +# 再继续补充另一类插件 +"从 Classic298/open-webui-plugins 安装仅 action 插件" -# 从 suurt8ll 的集合安装所有函数 -"从 suurt8ll/open_webui_functions 安装所有插件" - -# 只安装特定类型的插件(比如只安装工具) -"从 iChristGit/OpenWebui-Tools 只安装 tool 插件" - -# 安装时排除特定关键词 +# 过滤不想安装的插件 "从 Haervwe/open-webui-tools 安装所有插件, exclude_keywords=test,deprecated" + +# 从你自己的公开仓库安装 +"从 your-username/my-plugin-collection 安装所有插件" ``` -### 支持的仓库 +## 热门公开仓库 -- `Fu-Jie/openwebui-extensions` - 默认的官方插件集合 +该工具支持任何公开 GitHub 仓库,格式为 `owner/repo`。这些都是不错的起点: + +- `Fu-Jie/openwebui-extensions` - 我的个人合集,也是默认来源 - `iChristGit/OpenWebui-Tools` - 全面的工具和插件集合 -- `Haervwe/open-webui-tools` - 专业的工具和实用程序 -- `Classic298/open-webui-plugins` - 各种插件实现 -- `suurt8ll/open_webui_functions` - 基于函数的插件 +- `Haervwe/open-webui-tools` - 偏工具型的扩展集合 +- `Classic298/open-webui-plugins` - 混合型社区插件集合 +- `suurt8ll/open_webui_functions` - 基于函数的插件集合 +- `rbb-dev/Open-WebUI-OpenRouter-pipe` - OpenRouter pipe 集成 + +如需混合多个来源,请在上一次安装完成后,换一个 `repo` 再调用一次工具。 ## 默认仓库 -未指定仓库时,默认为 `Fu-Jie/openwebui-extensions`。 +未指定仓库时,工具会使用 `Fu-Jie/openwebui-extensions`(我的个人合集)。 ## 插件检测规则 ### Fu-Jie/openwebui-extensions(严格模式) -默认仓库的插件必须满足: +对于默认仓库,工具会采用更严格的筛选规则: 1. 包含 `class Tools:`、`class Filter:`、`class Pipe:` 或 `class Action:` 的 `.py` 文件 -2. Docstring 中包含 `title:`、`description:` 和 **`openwebui_id:`** 字段 +2. Docstring 中包含 `title:`、`description:` 和 **`openwebui_id:`** 元数据 3. 文件名不能以 `_cn` 结尾 -### 其他 GitHub 仓库 +### 其他公开 GitHub 仓库 其他仓库的插件必须满足: 1. 包含 `class Tools:`、`class Filter:`、`class Pipe:` 或 `class Action:` 的 `.py` 文件 diff --git a/plugins/tools/batch-install-plugins/batch_install_plugins.py b/plugins/tools/batch-install-plugins/batch_install_plugins.py index be9d07d..d3ed217 100644 --- a/plugins/tools/batch-install-plugins/batch_install_plugins.py +++ b/plugins/tools/batch-install-plugins/batch_install_plugins.py @@ -7,11 +7,13 @@ version: 1.0.0 description: One-click batch install plugins from GitHub repositories to your OpenWebUI instance. """ +import ast import asyncio import json import logging import os import re +import textwrap from pathlib import Path from typing import Any, Dict, List, Optional, Tuple @@ -33,9 +35,10 @@ SELF_EXCLUDE_TERMS = ( SELF_EXCLUDE_HINT, "batch install plugins from github", ) -DOCSTRING_PATTERN = re.compile(r'^\s*"""\n(.*?)\n"""', re.DOTALL) +DOCSTRING_PATTERN = re.compile(r'^\s*(?P"""|\'\'\')\s*(.*?)\s*(?P=quote)', re.DOTALL) CLASS_PATTERN = re.compile(r'^class (Tools|Filter|Pipe|Action)\s*[\(:]', re.MULTILINE) EMOJI_PATTERN = re.compile(r'[\U00010000-\U0010ffff]', re.UNICODE) +METADATA_KEY_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_-]*$") TRANSLATIONS = { "en-US": { @@ -476,19 +479,109 @@ class PluginCandidate: def extract_metadata(content: str) -> Dict[str, str]: - match = DOCSTRING_PATTERN.search(content) - if not match: + docstring = _extract_module_docstring(content) + if not docstring: return {} + metadata: Dict[str, str] = {} - for raw_line in match.group(1).splitlines(): - line = raw_line.strip() - if not line or line.startswith("#") or ":" not in line: + lines = docstring.splitlines() + index = 0 + + while index < len(lines): + raw_line = lines[index] + stripped = raw_line.strip() + + if not stripped or stripped.startswith("#"): + index += 1 continue - key, value = line.split(":", 1) - metadata[key.strip().lower()] = value.strip() + + if raw_line[:1].isspace() or ":" not in raw_line: + index += 1 + continue + + key, value = raw_line.split(":", 1) + key = key.strip().lower() + if not METADATA_KEY_PATTERN.match(key): + index += 1 + continue + + value = value.strip() + if value and value[0] in {">", "|"}: + block_lines, index = _consume_indented_block(lines, index + 1) + metadata[key] = ( + _fold_yaml_block(block_lines) + if value[0] == ">" + else _preserve_yaml_block(block_lines) + ) + continue + + metadata[key] = value + index += 1 + return metadata +def _extract_module_docstring(content: str) -> str: + normalized = content.lstrip("\ufeff") + + try: + module = ast.parse(normalized) + except SyntaxError: + module = None + + if module is not None: + docstring = ast.get_docstring(module, clean=False) + if isinstance(docstring, str): + return docstring + + fallback = normalized.replace("\r\n", "\n").replace("\r", "\n") + match = DOCSTRING_PATTERN.search(fallback) + return match.group(2) if match else "" + + +def _consume_indented_block(lines: List[str], start_index: int) -> Tuple[List[str], int]: + block: List[str] = [] + index = start_index + + while index < len(lines): + line = lines[index] + if not line.strip(): + block.append("") + index += 1 + continue + if line[:1].isspace(): + block.append(line) + index += 1 + continue + break + + dedented = textwrap.dedent("\n".join(block)).splitlines() + return dedented, index + + +def _fold_yaml_block(lines: List[str]) -> str: + paragraphs: List[str] = [] + current: List[str] = [] + + for line in lines: + stripped = line.strip() + if not stripped: + if current: + paragraphs.append(" ".join(current)) + current = [] + continue + current.append(stripped) + + if current: + paragraphs.append(" ".join(current)) + + return "\n\n".join(paragraphs).strip() + + +def _preserve_yaml_block(lines: List[str]) -> str: + return "\n".join(line.rstrip() for line in lines).strip() + + def detect_plugin_type(content: str) -> Optional[str]: if "\nclass Tools:" in content or "\nclass Tools (" in content: return "tool" @@ -767,7 +860,7 @@ async def discover_plugins( skipped.append((item_path, "missing title/description")) continue - if has_emoji(metadata.get("title", "")): + if is_default_repo and has_emoji(metadata.get("title", "")): skipped.append((item_path, "title contains emoji")) continue diff --git a/tests/plugins/tools/test_batch_install_plugins.py b/tests/plugins/tools/test_batch_install_plugins.py index a3f9134..ed8ac9a 100644 --- a/tests/plugins/tools/test_batch_install_plugins.py +++ b/tests/plugins/tools/test_batch_install_plugins.py @@ -74,6 +74,17 @@ class FakeAsyncClient: return response +class FakeGithubAsyncClient: + def __init__(self, *args, **kwargs): + pass + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + @pytest.mark.asyncio async def test_install_all_plugins_only_installs_filtered_candidates(monkeypatch): keep = make_candidate("Keep Plugin", "plugins/tools/keep/keep.py", "keep_plugin") @@ -300,3 +311,94 @@ async def test_install_all_plugins_emits_frontend_debug_logs_on_connect_error( assert any("http://localhost:3000" in code for code in execute_codes) assert events[-1]["type"] == "notification" assert events[-1]["data"]["type"] == "error" + + +def test_extract_metadata_supports_crlf_and_folded_yaml_docstrings(): + content = ( + '"""\r\n' + "title: Persona Selector\r\n" + "author: ichrist\r\n" + "description: >\r\n" + " Two-step persona picker. Step 1: numbered category list (16 categories).\r\n" + " Step 2: numbered persona list (10 per category). 160 personas + Custom.\r\n" + "version: 6.0.2\r\n" + '"""\r\n\r\n' + "class Tools:\r\n" + " pass\r\n" + ) + + metadata = batch_install_plugins.extract_metadata(content) + + assert metadata["title"] == "Persona Selector" + assert metadata["author"] == "ichrist" + assert metadata["version"] == "6.0.2" + assert metadata["description"] == ( + "Two-step persona picker. Step 1: numbered category list (16 categories). " + "Step 2: numbered persona list (10 per category). 160 personas + Custom." + ) + + +@pytest.mark.asyncio +async def test_discover_plugins_supports_community_repo_crlf_docstrings(monkeypatch): + tree = [ + {"type": "blob", "path": "Tools/ask-user.py"}, + {"type": "blob", "path": "Tools/persona.py"}, + {"type": "blob", "path": "Tools/orchestrator.py"}, + ] + contents = { + "Tools/ask-user.py": ( + '"""\r\n' + "title: Ask User\r\n" + "author: ichrist\r\n" + "version: 1.0\r\n" + "description: Allows the LLM to autonomously trigger 1-5 interactive pop-up questions.\r\n" + '"""\r\n\r\n' + "class Tools:\r\n" + " pass\r\n" + ), + "Tools/persona.py": ( + '"""\r\n' + "title: Persona Selector\r\n" + "author: ichrist\r\n" + "description: >\r\n" + " Two-step persona picker. Step 1: numbered category list (16 categories).\r\n" + " Step 2: numbered persona list (10 per category). 160 personas + Custom.\r\n" + "version: 6.0.2\r\n" + '"""\r\n\r\n' + "class Tools:\r\n" + " pass\r\n" + ), + "Tools/orchestrator.py": ( + '"""\r\n' + "title: 🌌 The Omniscient Orchestrator\r\n" + "author: ichrist\r\n" + "version: 2.0\r\n" + "description: A high-polish, multi-stage workflow engine.\r\n" + '"""\r\n\r\n' + "class Tools:\r\n" + " pass\r\n" + ), + } + + async def fake_fetch_tree(client, owner, repo, branch): + assert (owner, repo, branch) == ("iChristGit", "OpenWebui-Tools", "main") + return tree + + async def fake_fetch_file(client, owner, repo, branch, path): + return contents[path] + + monkeypatch.setattr(batch_install_plugins.httpx, "AsyncClient", FakeGithubAsyncClient) + monkeypatch.setattr(batch_install_plugins, "fetch_github_tree", fake_fetch_tree) + monkeypatch.setattr(batch_install_plugins, "fetch_github_file", fake_fetch_file) + + candidates, skipped = await batch_install_plugins.discover_plugins( + "https://github.com/iChristGit/OpenWebui-Tools/", + batch_install_plugins.DEFAULT_SKIP_KEYWORDS, + ) + + assert sorted(candidate.title for candidate in candidates) == [ + "Ask User", + "Persona Selector", + "🌌 The Omniscient Orchestrator", + ] + assert skipped == []