Compare commits
61 Commits
v2026.01.2
...
v2026.02.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f882997337 | ||
|
|
8e2c1b467e | ||
|
|
db2433afa1 | ||
|
|
fd125c9dea | ||
|
|
0a726aacb6 | ||
|
|
bf82e093d4 | ||
|
|
53ae7ef003 | ||
|
|
c2c7e3b2d3 | ||
|
|
26df5f5144 | ||
|
|
aebeb3677c | ||
|
|
076c1d62c6 | ||
|
|
21cf6ecc1d | ||
|
|
e6bdab54c9 | ||
|
|
2232e5adb3 | ||
|
|
d17089972a | ||
|
|
a7991147be | ||
|
|
be6eb35567 | ||
|
|
90bc295871 | ||
|
|
310ad5d1d3 | ||
|
|
00ce724430 | ||
|
|
43b68b3ff0 | ||
|
|
b6c1335335 | ||
|
|
8b0b33015f | ||
|
|
11ee9086b2 | ||
|
|
3578ffc543 | ||
|
|
b8531f1979 | ||
|
|
8607afd4c3 | ||
|
|
41d9963d35 | ||
|
|
bd5f3d3f7c | ||
|
|
dda8262bc0 | ||
|
|
0271013ec2 | ||
|
|
e1f210d600 | ||
|
|
eac8f6f355 | ||
|
|
3998b93034 | ||
|
|
ae04e95e13 | ||
|
|
12d638e134 | ||
|
|
4a9eb8ed3d | ||
|
|
af127bbfd5 | ||
|
|
db7bb6250a | ||
|
|
24b029e617 | ||
|
|
ff63ab3118 | ||
|
|
07e7e74fe1 | ||
|
|
55456775c1 | ||
|
|
05bb2e4644 | ||
|
|
83fa20ed08 | ||
|
|
ec69524357 | ||
|
|
829361da63 | ||
|
|
af05ecec6a | ||
|
|
1e08ae7d10 | ||
|
|
b24233ee07 | ||
|
|
e5d1550986 | ||
|
|
7f5deb603e | ||
|
|
55b2a28f79 | ||
|
|
db9bcb2c31 | ||
|
|
ad2773e8f1 | ||
|
|
7d4da3be8a | ||
|
|
28166728a4 | ||
|
|
4dfca903c4 | ||
|
|
b619d3f402 | ||
|
|
1e68f985fb | ||
|
|
596b571887 |
8
.github/copilot-instructions.md
vendored
8
.github/copilot-instructions.md
vendored
@@ -42,11 +42,15 @@ plugins/actions/export_to_docx/
|
||||
- 格式: `**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** x.x.x | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)`
|
||||
- **注意**: Author 和 Project 为固定值,仅需更新 Version 版本号
|
||||
3. **描述 (Description)**: 一句话功能介绍
|
||||
4. **最新更新 (What's New)**: **必须**放在描述之后,显著展示最新版本的变更点 (仅展示最近 3 次更新)
|
||||
4. **最新更新 (What's New)**: **必须**放在描述之后,仅展示**最近 1 次**更新
|
||||
5. **核心特性 (Key Features)**: 使用 Emoji + 粗体标题 + 描述格式
|
||||
6. **使用方法 (How to Use)**: 按步骤说明
|
||||
7. **配置参数 (Configuration/Valves)**: 使用表格格式,包含参数名、默认值、描述
|
||||
8. **其他 (Others)**: 支持的模板类型、语法示例、故障排除等
|
||||
8. **支持 (Support)**: **必须**包含,放在配置参数之后、故障排除之前
|
||||
- English: `If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.`
|
||||
- 中文: `如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。`
|
||||
9. **其他 (Others)**: 支持的模板类型、语法示例、故障排除等
|
||||
- **Changelog**: 统一指向 GitHub 项目历史,不在 README 中列出具体变更
|
||||
|
||||
### 2. 插件目录结构 (Plugin Directory Structure)
|
||||
|
||||
|
||||
26
README.md
26
README.md
@@ -10,28 +10,28 @@ A collection of enhancements, plugins, and prompts for [OpenWebUI](https://githu
|
||||
<!-- STATS_START -->
|
||||
## 📊 Community Stats
|
||||
|
||||
> 🕐 Auto-updated: 2026-01-28 09:37
|
||||
> 🕐 Auto-updated: 2026-02-07 09:38
|
||||
|
||||
| 👤 Author | 👥 Followers | ⭐ Points | 🏆 Contributions |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **165** | **167** | **35** |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **203** | **246** | **40** |
|
||||
|
||||
| 📝 Posts | ⬇️ Downloads | 👁️ Views | 👍 Upvotes | 💾 Saves |
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
| **19** | **2553** | **29974** | **150** | **198** |
|
||||
| **20** | **3675** | **43326** | **213** | **253** |
|
||||
|
||||
### 🔥 Top 6 Popular Plugins
|
||||
|
||||
> 🕐 Auto-updated: 2026-01-28 09:37
|
||||
> 🕐 Auto-updated: 2026-02-07 09:38
|
||||
|
||||
| Rank | Plugin | Version | Downloads | Views | Updated |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.1 | 670 | 5919 | 2026-01-17 |
|
||||
| 🥈 | [📊 Smart Infographic (AntV)](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 441 | 4010 | 2026-01-27 |
|
||||
| 🥉 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 265 | 1099 | 2026-01-07 |
|
||||
| 4️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 240 | 2593 | 2026-01-21 |
|
||||
| 5️⃣ | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.3 | 240 | 1951 | 2026-01-17 |
|
||||
| 6️⃣ | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | 0.2.4 | 179 | 2805 | 2026-01-17 |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 877 | 7765 | 2026-01-28 |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 631 | 5825 | 2026-01-30 |
|
||||
| 🥉 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.3 | 343 | 2659 | 2026-01-28 |
|
||||
| 4️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 327 | 1519 | 2026-01-29 |
|
||||
| 5️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 327 | 3412 | 2026-01-28 |
|
||||
| 6️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 293 | 4243 | 2026-01-29 |
|
||||
|
||||
*See full stats in [Community Stats Report](./docs/community-stats.md)*
|
||||
<!-- STATS_END -->
|
||||
@@ -73,6 +73,12 @@ Located in the `prompts/` directory, containing fine-tuned System Prompts:
|
||||
- **Coding**: Programming assistance prompts.
|
||||
- **Marketing**: Marketing and copywriting prompts.
|
||||
|
||||
## 🛠️ Extensions
|
||||
|
||||
Standalone frontend extensions to supercharge your Open WebUI:
|
||||
|
||||
- **[Open WebUI Prompt Plus](https://github.com/Fu-Jie/open-webui-prompt-plus)**: An all-in-one prompt management suite featuring AI-powered prompt generation, spotlight-style quick search, and advanced category organization.
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
Located in the `docs/en/` directory:
|
||||
|
||||
26
README_CN.md
26
README_CN.md
@@ -7,28 +7,28 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
<!-- STATS_START -->
|
||||
## 📊 社区统计
|
||||
|
||||
> 🕐 自动更新于 2026-01-28 09:37
|
||||
> 🕐 自动更新于 2026-02-07 09:38
|
||||
|
||||
| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🏆 贡献 |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **165** | **167** | **35** |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **203** | **246** | **40** |
|
||||
|
||||
| 📝 发布 | ⬇️ 下载 | 👁️ 浏览 | 👍 点赞 | 💾 收藏 |
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
| **19** | **2553** | **29974** | **150** | **198** |
|
||||
| **20** | **3675** | **43326** | **213** | **253** |
|
||||
|
||||
### 🔥 热门插件 Top 6
|
||||
|
||||
> 🕐 自动更新于 2026-01-28 09:37
|
||||
> 🕐 自动更新于 2026-02-07 09:38
|
||||
|
||||
| 排名 | 插件 | 版本 | 下载 | 浏览 | 更新日期 |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.1 | 670 | 5919 | 2026-01-17 |
|
||||
| 🥈 | [📊 Smart Infographic (AntV)](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 441 | 4010 | 2026-01-27 |
|
||||
| 🥉 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 265 | 1099 | 2026-01-07 |
|
||||
| 4️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 240 | 2593 | 2026-01-21 |
|
||||
| 5️⃣ | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.3 | 240 | 1951 | 2026-01-17 |
|
||||
| 6️⃣ | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | 0.2.4 | 179 | 2805 | 2026-01-17 |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 877 | 7765 | 2026-01-28 |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 631 | 5825 | 2026-01-30 |
|
||||
| 🥉 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.3 | 343 | 2659 | 2026-01-28 |
|
||||
| 4️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 327 | 1519 | 2026-01-29 |
|
||||
| 5️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 327 | 3412 | 2026-01-28 |
|
||||
| 6️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 293 | 4243 | 2026-01-29 |
|
||||
|
||||
*完整统计请查看 [社区统计报告](./docs/community-stats.zh.md)*
|
||||
<!-- STATS_END -->
|
||||
@@ -76,6 +76,12 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
每个提示词都独立保存为 Markdown 文件,可直接在 OpenWebUI 中使用。
|
||||
|
||||
## 🛠️ 扩展 (Extensions)
|
||||
|
||||
Open WebUI 的前端增强扩展:
|
||||
|
||||
- **[Open WebUI Prompt Plus](https://github.com/Fu-Jie/open-webui-prompt-plus)**: 一站式提示词管理套件,支持 AI 提示词生成、Spotlight 风格快速搜索及高级分类管理。
|
||||
|
||||
## 📖 开发文档
|
||||
|
||||
位于 `docs/zh/` 目录:
|
||||
|
||||
@@ -10,9 +10,10 @@ The Chinese version (README_CN.md) MUST be translated based on this English vers
|
||||
|
||||
## What's New
|
||||
|
||||
<!-- Keep the changelog for the last 3 versions here. Remove this section for the initial release. -->
|
||||
<!-- Keep only the latest update here. Remove this section for the initial release. -->
|
||||
|
||||
### v1.0.0
|
||||
|
||||
- **Initial Release**: Released the first version of the plugin.
|
||||
- **[Feature Name]**: [Brief description of the feature].
|
||||
|
||||
@@ -36,9 +37,17 @@ The Chinese version (README_CN.md) MUST be translated based on this English vers
|
||||
| `VALVE_NAME` | `Default Value` | Description of what this setting does. |
|
||||
| `ANOTHER_VALVE` | `True` | Another setting description. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the filter/action is enabled in the model settings.
|
||||
- **Debug Logs**: Enable `SHOW_DEBUG_LOG` in Valves and check the browser console (F12) for detailed logs.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "downloads",
|
||||
"message": "2.6k",
|
||||
"message": "3.7k",
|
||||
"color": "blue",
|
||||
"namedLogo": "openwebui"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "followers",
|
||||
"message": "165",
|
||||
"message": "203",
|
||||
"color": "blue"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "plugins",
|
||||
"message": "19",
|
||||
"message": "20",
|
||||
"color": "green"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "points",
|
||||
"message": "167",
|
||||
"message": "246",
|
||||
"color": "orange"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "upvotes",
|
||||
"message": "150",
|
||||
"message": "213",
|
||||
"color": "brightgreen"
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
{
|
||||
"total_posts": 19,
|
||||
"total_downloads": 2553,
|
||||
"total_views": 29974,
|
||||
"total_upvotes": 150,
|
||||
"total_posts": 20,
|
||||
"total_downloads": 3675,
|
||||
"total_views": 43326,
|
||||
"total_upvotes": 213,
|
||||
"total_downvotes": 2,
|
||||
"total_saves": 198,
|
||||
"total_comments": 40,
|
||||
"total_saves": 253,
|
||||
"total_comments": 46,
|
||||
"by_type": {
|
||||
"action": 14,
|
||||
"pipe": 1,
|
||||
"unknown": 3,
|
||||
"action": 15,
|
||||
"unknown": 4,
|
||||
"filter": 1
|
||||
},
|
||||
"posts": [
|
||||
@@ -17,34 +16,50 @@
|
||||
"title": "Smart Mind Map",
|
||||
"slug": "turn_any_text_into_beautiful_mind_maps_3094c59a",
|
||||
"type": "action",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
|
||||
"downloads": 670,
|
||||
"views": 5919,
|
||||
"upvotes": 17,
|
||||
"saves": 38,
|
||||
"comments": 11,
|
||||
"downloads": 877,
|
||||
"views": 7765,
|
||||
"upvotes": 21,
|
||||
"saves": 47,
|
||||
"comments": 13,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-01-17",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a"
|
||||
},
|
||||
{
|
||||
"title": "📊 Smart Infographic (AntV)",
|
||||
"title": "Smart Infographic",
|
||||
"slug": "smart_infographic_ad6f0c7f",
|
||||
"type": "action",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "AI-powered infographic generator based on AntV Infographic. Supports professional templates, auto-icon matching, and SVG/PNG downloads.",
|
||||
"downloads": 441,
|
||||
"views": 4010,
|
||||
"upvotes": 19,
|
||||
"saves": 28,
|
||||
"downloads": 631,
|
||||
"views": 5825,
|
||||
"upvotes": 23,
|
||||
"saves": 33,
|
||||
"comments": 10,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-01-27",
|
||||
"updated_at": "2026-01-30",
|
||||
"url": "https://openwebui.com/posts/smart_infographic_ad6f0c7f"
|
||||
},
|
||||
{
|
||||
"title": "Export to Word (Enhanced)",
|
||||
"slug": "export_to_word_enhanced_formatting_fca6a315",
|
||||
"type": "action",
|
||||
"version": "0.4.3",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Export current conversation from Markdown to Word (.docx) with Mermaid diagrams rendered client-side (Mermaid.js, SVG+PNG), LaTeX math, real hyperlinks, improved tables, syntax highlighting, and blockquote support.",
|
||||
"downloads": 343,
|
||||
"views": 2659,
|
||||
"upvotes": 12,
|
||||
"saves": 26,
|
||||
"comments": 2,
|
||||
"created_at": "2026-01-03",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315"
|
||||
},
|
||||
{
|
||||
"title": "Export to Excel",
|
||||
"slug": "export_mulit_table_to_excel_244b8f9d",
|
||||
@@ -52,13 +67,13 @@
|
||||
"version": "0.3.7",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
|
||||
"downloads": 265,
|
||||
"views": 1099,
|
||||
"upvotes": 4,
|
||||
"downloads": 327,
|
||||
"views": 1519,
|
||||
"upvotes": 7,
|
||||
"saves": 6,
|
||||
"comments": 0,
|
||||
"created_at": "2025-05-30",
|
||||
"updated_at": "2026-01-07",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
|
||||
},
|
||||
{
|
||||
@@ -68,47 +83,15 @@
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
|
||||
"downloads": 240,
|
||||
"views": 2593,
|
||||
"upvotes": 9,
|
||||
"saves": 27,
|
||||
"downloads": 327,
|
||||
"views": 3412,
|
||||
"upvotes": 13,
|
||||
"saves": 33,
|
||||
"comments": 0,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-01-21",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/async_context_compression_b1655bc8"
|
||||
},
|
||||
{
|
||||
"title": "Export to Word (Enhanced)",
|
||||
"slug": "export_to_word_enhanced_formatting_fca6a315",
|
||||
"type": "action",
|
||||
"version": "0.4.3",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Export current conversation from Markdown to Word (.docx) with Mermaid diagrams rendered client-side (Mermaid.js, SVG+PNG), LaTeX math, real hyperlinks, improved tables, syntax highlighting, and blockquote support.",
|
||||
"downloads": 240,
|
||||
"views": 1951,
|
||||
"upvotes": 8,
|
||||
"saves": 21,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-03",
|
||||
"updated_at": "2026-01-17",
|
||||
"url": "https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315"
|
||||
},
|
||||
{
|
||||
"title": "Flash Card",
|
||||
"slug": "flash_card_65a2ea8f",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
|
||||
"downloads": 179,
|
||||
"views": 2805,
|
||||
"upvotes": 11,
|
||||
"saves": 13,
|
||||
"comments": 2,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-01-17",
|
||||
"url": "https://openwebui.com/posts/flash_card_65a2ea8f"
|
||||
},
|
||||
{
|
||||
"title": "Markdown Normalizer",
|
||||
"slug": "markdown_normalizer_baaa8732",
|
||||
@@ -116,15 +99,47 @@
|
||||
"version": "1.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "A content normalizer filter that fixes common Markdown formatting issues in LLM outputs, such as broken code blocks, LaTeX formulas, and list formatting.",
|
||||
"downloads": 164,
|
||||
"views": 2910,
|
||||
"upvotes": 10,
|
||||
"saves": 22,
|
||||
"downloads": 293,
|
||||
"views": 4243,
|
||||
"upvotes": 17,
|
||||
"saves": 27,
|
||||
"comments": 5,
|
||||
"created_at": "2026-01-12",
|
||||
"updated_at": "2026-01-19",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/markdown_normalizer_baaa8732"
|
||||
},
|
||||
{
|
||||
"title": "Flash Card",
|
||||
"slug": "flash_card_65a2ea8f",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
|
||||
"downloads": 213,
|
||||
"views": 3239,
|
||||
"upvotes": 13,
|
||||
"saves": 14,
|
||||
"comments": 2,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/flash_card_65a2ea8f"
|
||||
},
|
||||
{
|
||||
"title": "AI Task Instruction Generator",
|
||||
"slug": "ai_task_instruction_generator_9bab8b37",
|
||||
"type": "unknown",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 141,
|
||||
"views": 2180,
|
||||
"upvotes": 8,
|
||||
"saves": 3,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-28",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37"
|
||||
},
|
||||
{
|
||||
"title": "Deep Dive",
|
||||
"slug": "deep_dive_c0b846e4",
|
||||
@@ -132,10 +147,10 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "A comprehensive thinking lens that dives deep into any content - from context to logic, insights, and action paths.",
|
||||
"downloads": 96,
|
||||
"views": 880,
|
||||
"upvotes": 4,
|
||||
"saves": 8,
|
||||
"downloads": 132,
|
||||
"views": 1155,
|
||||
"upvotes": 6,
|
||||
"saves": 11,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
@@ -148,29 +163,29 @@
|
||||
"version": "0.4.3",
|
||||
"author": "Fu-Jie",
|
||||
"description": "将对话导出为 Word (.docx),支持 Mermaid 图表 (客户端渲染 SVG+PNG)、LaTeX 数学公式、真实超链接、增强表格格式、代码高亮和引用块。",
|
||||
"downloads": 90,
|
||||
"views": 1710,
|
||||
"upvotes": 11,
|
||||
"saves": 4,
|
||||
"downloads": 119,
|
||||
"views": 2104,
|
||||
"upvotes": 13,
|
||||
"saves": 6,
|
||||
"comments": 4,
|
||||
"created_at": "2026-01-04",
|
||||
"updated_at": "2026-01-17",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0"
|
||||
},
|
||||
{
|
||||
"title": "📊 智能信息图 (AntV Infographic)",
|
||||
"title": "智能信息图",
|
||||
"slug": "智能信息图_e04a48ff",
|
||||
"type": "action",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
|
||||
"downloads": 48,
|
||||
"views": 811,
|
||||
"upvotes": 7,
|
||||
"saves": 0,
|
||||
"downloads": 56,
|
||||
"views": 1003,
|
||||
"upvotes": 10,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-01-27",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/智能信息图_e04a48ff"
|
||||
},
|
||||
{
|
||||
@@ -180,29 +195,45 @@
|
||||
"version": "0.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Automatically extracts project rules from conversations and injects them into the folder's system prompt.",
|
||||
"downloads": 29,
|
||||
"views": 834,
|
||||
"upvotes": 4,
|
||||
"saves": 7,
|
||||
"downloads": 55,
|
||||
"views": 1195,
|
||||
"upvotes": 6,
|
||||
"saves": 8,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-20",
|
||||
"updated_at": "2026-01-20",
|
||||
"url": "https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "action",
|
||||
"version": "0.2.3",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.",
|
||||
"downloads": 49,
|
||||
"views": 1835,
|
||||
"upvotes": 11,
|
||||
"saves": 5,
|
||||
"comments": 1,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "思维导图",
|
||||
"slug": "智能生成交互式思维导图帮助用户可视化知识_8d4b097b",
|
||||
"type": "action",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "智能分析文本内容,生成交互式思维导图,帮助用户结构化和可视化知识。",
|
||||
"downloads": 28,
|
||||
"views": 468,
|
||||
"upvotes": 4,
|
||||
"saves": 1,
|
||||
"downloads": 37,
|
||||
"views": 563,
|
||||
"upvotes": 6,
|
||||
"saves": 2,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-31",
|
||||
"updated_at": "2026-01-17",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b"
|
||||
},
|
||||
{
|
||||
@@ -212,13 +243,13 @@
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "通过智能摘要和消息压缩,降低长对话的 token 消耗,同时保持对话连贯性。",
|
||||
"downloads": 23,
|
||||
"views": 518,
|
||||
"upvotes": 5,
|
||||
"saves": 2,
|
||||
"downloads": 31,
|
||||
"views": 624,
|
||||
"upvotes": 7,
|
||||
"saves": 4,
|
||||
"comments": 0,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-01-21",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/异步上下文压缩_5c0617cb"
|
||||
},
|
||||
{
|
||||
@@ -228,31 +259,15 @@
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
|
||||
"downloads": 20,
|
||||
"views": 531,
|
||||
"upvotes": 6,
|
||||
"downloads": 27,
|
||||
"views": 659,
|
||||
"upvotes": 8,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-01-17",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/闪记卡生成插件_4a31eac3"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "pipe",
|
||||
"version": "0.2.3",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.",
|
||||
"downloads": 10,
|
||||
"views": 517,
|
||||
"upvotes": 8,
|
||||
"saves": 2,
|
||||
"comments": 1,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-01-26",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "精读",
|
||||
"slug": "精读_99830b0f",
|
||||
@@ -260,9 +275,9 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "全方位的思维透镜 —— 从背景全景到逻辑脉络,从深度洞察到行动路径。",
|
||||
"downloads": 10,
|
||||
"views": 321,
|
||||
"upvotes": 3,
|
||||
"downloads": 17,
|
||||
"views": 400,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-08",
|
||||
@@ -277,12 +292,12 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 705,
|
||||
"upvotes": 7,
|
||||
"saves": 9,
|
||||
"comments": 5,
|
||||
"views": 1421,
|
||||
"upvotes": 11,
|
||||
"saves": 16,
|
||||
"comments": 7,
|
||||
"created_at": "2026-01-25",
|
||||
"updated_at": "2026-01-25",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e"
|
||||
},
|
||||
{
|
||||
@@ -293,8 +308,8 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 101,
|
||||
"upvotes": 1,
|
||||
"views": 134,
|
||||
"upvotes": 2,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-14",
|
||||
@@ -309,9 +324,9 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1291,
|
||||
"upvotes": 12,
|
||||
"saves": 8,
|
||||
"views": 1391,
|
||||
"upvotes": 14,
|
||||
"saves": 9,
|
||||
"comments": 2,
|
||||
"created_at": "2026-01-10",
|
||||
"updated_at": "2026-01-10",
|
||||
@@ -323,11 +338,11 @@
|
||||
"name": "Fu-Jie",
|
||||
"profile_url": "https://openwebui.com/u/Fu-Jie",
|
||||
"profile_image": "https://community.s3.openwebui.com/uploads/users/b15d1348-4347-42b4-b815-e053342d6cb0/profile_d9510745-4bd4-4f8f-a997-4a21847d9300.webp",
|
||||
"followers": 165,
|
||||
"following": 3,
|
||||
"total_points": 167,
|
||||
"post_points": 148,
|
||||
"comment_points": 19,
|
||||
"contributions": 35
|
||||
"followers": 203,
|
||||
"following": 4,
|
||||
"total_points": 246,
|
||||
"post_points": 211,
|
||||
"comment_points": 35,
|
||||
"contributions": 40
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,45 @@
|
||||
# 📊 OpenWebUI Community Stats Report
|
||||
|
||||
> 📅 Updated: 2026-01-28 09:37
|
||||
> 📅 Updated: 2026-02-07 09:38
|
||||
|
||||
## 📈 Overview
|
||||
|
||||
| Metric | Value |
|
||||
|------|------|
|
||||
| 📝 Total Posts | 19 |
|
||||
| ⬇️ Total Downloads | 2553 |
|
||||
| 👁️ Total Views | 29974 |
|
||||
| 👍 Total Upvotes | 150 |
|
||||
| 💾 Total Saves | 198 |
|
||||
| 💬 Total Comments | 40 |
|
||||
| 📝 Total Posts | 20 |
|
||||
| ⬇️ Total Downloads | 3675 |
|
||||
| 👁️ Total Views | 43326 |
|
||||
| 👍 Total Upvotes | 213 |
|
||||
| 💾 Total Saves | 253 |
|
||||
| 💬 Total Comments | 46 |
|
||||
|
||||
## 📂 By Type
|
||||
|
||||
- **action**: 14
|
||||
- **pipe**: 1
|
||||
- **unknown**: 3
|
||||
- **action**: 15
|
||||
- **unknown**: 4
|
||||
- **filter**: 1
|
||||
|
||||
## 📋 Posts List
|
||||
|
||||
| Rank | Title | Type | Version | Downloads | Views | Upvotes | Saves | Updated |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.1 | 670 | 5919 | 17 | 38 | 2026-01-17 |
|
||||
| 2 | [📊 Smart Infographic (AntV)](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 441 | 4010 | 19 | 28 | 2026-01-27 |
|
||||
| 3 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 265 | 1099 | 4 | 6 | 2026-01-07 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 240 | 2593 | 9 | 27 | 2026-01-21 |
|
||||
| 5 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.3 | 240 | 1951 | 8 | 21 | 2026-01-17 |
|
||||
| 6 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 179 | 2805 | 11 | 13 | 2026-01-17 |
|
||||
| 7 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 164 | 2910 | 10 | 22 | 2026-01-19 |
|
||||
| 8 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 96 | 880 | 4 | 8 | 2026-01-08 |
|
||||
| 9 | [导出为 Word (增强版)](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.3 | 90 | 1710 | 11 | 4 | 2026-01-17 |
|
||||
| 10 | [📊 智能信息图 (AntV Infographic)](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 48 | 811 | 7 | 0 | 2026-01-27 |
|
||||
| 11 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 29 | 834 | 4 | 7 | 2026-01-20 |
|
||||
| 12 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.1 | 28 | 468 | 4 | 1 | 2026-01-17 |
|
||||
| 13 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 23 | 518 | 5 | 2 | 2026-01-21 |
|
||||
| 14 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 20 | 531 | 6 | 1 | 2026-01-17 |
|
||||
| 15 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe | 0.2.3 | 10 | 517 | 8 | 2 | 2026-01-26 |
|
||||
| 16 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 10 | 321 | 3 | 1 | 2026-01-08 |
|
||||
| 17 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 705 | 7 | 9 | 2026-01-25 |
|
||||
| 18 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 101 | 1 | 0 | 2026-01-14 |
|
||||
| 19 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1291 | 12 | 8 | 2026-01-10 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 877 | 7765 | 21 | 47 | 2026-01-28 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 631 | 5825 | 23 | 33 | 2026-01-30 |
|
||||
| 3 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.3 | 343 | 2659 | 12 | 26 | 2026-01-28 |
|
||||
| 4 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 327 | 1519 | 7 | 6 | 2026-01-29 |
|
||||
| 5 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 327 | 3412 | 13 | 33 | 2026-01-28 |
|
||||
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 293 | 4243 | 17 | 27 | 2026-01-29 |
|
||||
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 213 | 3239 | 13 | 14 | 2026-01-28 |
|
||||
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 141 | 2180 | 8 | 3 | 2026-01-28 |
|
||||
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 132 | 1155 | 6 | 11 | 2026-01-08 |
|
||||
| 10 | [导出为 Word (增强版)](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.3 | 119 | 2104 | 13 | 6 | 2026-01-28 |
|
||||
| 11 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 56 | 1003 | 10 | 1 | 2026-01-29 |
|
||||
| 12 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 55 | 1195 | 6 | 8 | 2026-01-20 |
|
||||
| 13 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.2.3 | 49 | 1835 | 11 | 5 | 2026-01-29 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 563 | 6 | 2 | 2026-01-28 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 31 | 624 | 7 | 4 | 2026-01-28 |
|
||||
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 659 | 8 | 1 | 2026-01-28 |
|
||||
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 17 | 400 | 5 | 1 | 2026-01-08 |
|
||||
| 18 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1421 | 11 | 16 | 2026-01-28 |
|
||||
| 19 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 134 | 2 | 0 | 2026-01-14 |
|
||||
| 20 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1391 | 14 | 9 | 2026-01-10 |
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
# 📊 OpenWebUI 社区统计报告
|
||||
|
||||
> 📅 更新时间: 2026-01-28 09:37
|
||||
> 📅 更新时间: 2026-02-07 09:38
|
||||
|
||||
## 📈 总览
|
||||
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| 📝 发布数量 | 19 |
|
||||
| ⬇️ 总下载量 | 2553 |
|
||||
| 👁️ 总浏览量 | 29974 |
|
||||
| 👍 总点赞数 | 150 |
|
||||
| 💾 总收藏数 | 198 |
|
||||
| 💬 总评论数 | 40 |
|
||||
| 📝 发布数量 | 20 |
|
||||
| ⬇️ 总下载量 | 3675 |
|
||||
| 👁️ 总浏览量 | 43326 |
|
||||
| 👍 总点赞数 | 213 |
|
||||
| 💾 总收藏数 | 253 |
|
||||
| 💬 总评论数 | 46 |
|
||||
|
||||
## 📂 按类型分类
|
||||
|
||||
- **action**: 14
|
||||
- **pipe**: 1
|
||||
- **unknown**: 3
|
||||
- **action**: 15
|
||||
- **unknown**: 4
|
||||
- **filter**: 1
|
||||
|
||||
## 📋 发布列表
|
||||
|
||||
| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.1 | 670 | 5919 | 17 | 38 | 2026-01-17 |
|
||||
| 2 | [📊 Smart Infographic (AntV)](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 441 | 4010 | 19 | 28 | 2026-01-27 |
|
||||
| 3 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 265 | 1099 | 4 | 6 | 2026-01-07 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 240 | 2593 | 9 | 27 | 2026-01-21 |
|
||||
| 5 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.3 | 240 | 1951 | 8 | 21 | 2026-01-17 |
|
||||
| 6 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 179 | 2805 | 11 | 13 | 2026-01-17 |
|
||||
| 7 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 164 | 2910 | 10 | 22 | 2026-01-19 |
|
||||
| 8 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 96 | 880 | 4 | 8 | 2026-01-08 |
|
||||
| 9 | [导出为 Word (增强版)](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.3 | 90 | 1710 | 11 | 4 | 2026-01-17 |
|
||||
| 10 | [📊 智能信息图 (AntV Infographic)](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 48 | 811 | 7 | 0 | 2026-01-27 |
|
||||
| 11 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 29 | 834 | 4 | 7 | 2026-01-20 |
|
||||
| 12 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.1 | 28 | 468 | 4 | 1 | 2026-01-17 |
|
||||
| 13 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 23 | 518 | 5 | 2 | 2026-01-21 |
|
||||
| 14 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 20 | 531 | 6 | 1 | 2026-01-17 |
|
||||
| 15 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe | 0.2.3 | 10 | 517 | 8 | 2 | 2026-01-26 |
|
||||
| 16 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 10 | 321 | 3 | 1 | 2026-01-08 |
|
||||
| 17 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 705 | 7 | 9 | 2026-01-25 |
|
||||
| 18 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 101 | 1 | 0 | 2026-01-14 |
|
||||
| 19 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1291 | 12 | 8 | 2026-01-10 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 877 | 7765 | 21 | 47 | 2026-01-28 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 631 | 5825 | 23 | 33 | 2026-01-30 |
|
||||
| 3 | [Export to Word (Enhanced)](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.3 | 343 | 2659 | 12 | 26 | 2026-01-28 |
|
||||
| 4 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 327 | 1519 | 7 | 6 | 2026-01-29 |
|
||||
| 5 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 327 | 3412 | 13 | 33 | 2026-01-28 |
|
||||
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 293 | 4243 | 17 | 27 | 2026-01-29 |
|
||||
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 213 | 3239 | 13 | 14 | 2026-01-28 |
|
||||
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 141 | 2180 | 8 | 3 | 2026-01-28 |
|
||||
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 132 | 1155 | 6 | 11 | 2026-01-08 |
|
||||
| 10 | [导出为 Word (增强版)](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.3 | 119 | 2104 | 13 | 6 | 2026-01-28 |
|
||||
| 11 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 56 | 1003 | 10 | 1 | 2026-01-29 |
|
||||
| 12 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 55 | 1195 | 6 | 8 | 2026-01-20 |
|
||||
| 13 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.2.3 | 49 | 1835 | 11 | 5 | 2026-01-29 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 563 | 6 | 2 | 2026-01-28 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 31 | 624 | 7 | 4 | 2026-01-28 |
|
||||
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 659 | 8 | 1 | 2026-01-28 |
|
||||
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 17 | 400 | 5 | 1 | 2026-01-08 |
|
||||
| 18 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1421 | 11 | 16 | 2026-01-28 |
|
||||
| 19 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 134 | 2 | 0 | 2026-01-14 |
|
||||
| 20 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1391 | 14 | 9 | 2026-01-10 |
|
||||
|
||||
22
docs/extensions/index.md
Normal file
22
docs/extensions/index.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Extensions
|
||||
---
|
||||
|
||||
# Extensions
|
||||
|
||||
Standalone frontend extensions to supercharge your Open WebUI.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Open WebUI Prompt Plus
|
||||
|
||||
**An all-in-one prompt management suite for power users.**
|
||||
|
||||
[Open WebUI Prompt Plus](https://github.com/Fu-Jie/open-webui-prompt-plus) elevates your experience with:
|
||||
|
||||
- **🤖 AI-Powered Prompt Generator**: Turn natural language into structured prompts.
|
||||
- **⚡ Quick Insert Panel**: Spotlight-style search (`Cmd/Ctrl + Shift + P`).
|
||||
- **📂 Advanced Management**: Dynamic categories, favorites, and usage stats.
|
||||
- **📝 Native Variable Support**: Visual form rendering for template variables.
|
||||
|
||||
[:fontawesome-brands-github: View on GitHub](https://github.com/Fu-Jie/open-webui-prompt-plus){ .md-button .md-button--primary }
|
||||
22
docs/extensions/index.zh.md
Normal file
22
docs/extensions/index.zh.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: 扩展 (Extensions)
|
||||
---
|
||||
|
||||
# 扩展 (Extensions)
|
||||
|
||||
Open WebUI 的独立前端增强扩展。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Open WebUI Prompt Plus
|
||||
|
||||
**专为高级用户打造的一站式提示词管理套件。**
|
||||
|
||||
[Open WebUI Prompt Plus](https://github.com/Fu-Jie/open-webui-prompt-plus) 通过以下功能提升您的体验:
|
||||
|
||||
- **🤖 AI 提示词生成器**: 将自然语言转化为结构化提示词。
|
||||
- **⚡ 快速插入面板**: Spotlight 风格的快速搜索 (`Cmd/Ctrl + Shift + P`)。
|
||||
- **📂 高级管理**: 动态分类、收藏夹及使用统计。
|
||||
- **📝 原生变量支持**: 模板变量的可视化表单渲染。
|
||||
|
||||
[:fontawesome-brands-github: 查看 GitHub](https://github.com/Fu-Jie/open-webui-prompt-plus){ .md-button .md-button--primary }
|
||||
@@ -25,7 +25,7 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-puzzle:{ .lg .middle } **Plugin Center**
|
||||
- :material-puzzle:{ .lg .middle } **Plugin Center**
|
||||
|
||||
---
|
||||
|
||||
@@ -33,7 +33,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: Explore Plugins](plugins/index.md)
|
||||
|
||||
- :material-message-text:{ .lg .middle } **Prompt Library**
|
||||
- :material-message-text:{ .lg .middle } **Prompt Library**
|
||||
|
||||
---
|
||||
|
||||
@@ -41,7 +41,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: Browse Prompts](prompts/index.md)
|
||||
|
||||
- :material-tools:{ .lg .middle } **Enhancements**
|
||||
- :material-tools:{ .lg .middle } **Enhancements**
|
||||
|
||||
---
|
||||
|
||||
@@ -49,7 +49,15 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: View Guides](enhancements/index.md)
|
||||
|
||||
- :material-book-open-page-variant:{ .lg .middle } **Development**
|
||||
- :material-rocket-launch:{ .lg .middle } **Extensions**
|
||||
|
||||
---
|
||||
|
||||
Standalone frontend extensions to supercharge your Open WebUI interface.
|
||||
|
||||
[:octicons-arrow-right-24: Browse Extensions](extensions/index.md)
|
||||
|
||||
- :material-book-open-page-variant:{ .lg .middle } **Development**
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +73,7 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-brain:{ .lg .middle } **Smart Mind Map**
|
||||
- :material-brain:{ .lg .middle } **Smart Mind Map**
|
||||
|
||||
---
|
||||
|
||||
@@ -73,7 +81,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: Learn More](plugins/actions/smart-mind-map.md)
|
||||
|
||||
- :material-card-text:{ .lg .middle } **Flash Card**
|
||||
- :material-card-text:{ .lg .middle } **Flash Card**
|
||||
|
||||
---
|
||||
|
||||
@@ -81,7 +89,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: Learn More](plugins/actions/flash-card.md)
|
||||
|
||||
- :material-arrow-collapse-vertical:{ .lg .middle } **Async Context Compression**
|
||||
- :material-arrow-collapse-vertical:{ .lg .middle } **Async Context Compression**
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-puzzle:{ .lg .middle } **插件中心**
|
||||
- :material-puzzle:{ .lg .middle } **插件中心**
|
||||
|
||||
---
|
||||
|
||||
@@ -33,7 +33,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: 探索插件](plugins/index.md)
|
||||
|
||||
- :material-message-text:{ .lg .middle } **提示词库**
|
||||
- :material-message-text:{ .lg .middle } **提示词库**
|
||||
|
||||
---
|
||||
|
||||
@@ -41,7 +41,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: 浏览提示词](prompts/index.md)
|
||||
|
||||
- :material-tools:{ .lg .middle } **增强功能**
|
||||
- :material-tools:{ .lg .middle } **增强功能**
|
||||
|
||||
---
|
||||
|
||||
@@ -49,7 +49,15 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: 查看指南](enhancements/index.md)
|
||||
|
||||
- :material-book-open-page-variant:{ .lg .middle } **开发指南**
|
||||
- :material-rocket-launch:{ .lg .middle } **扩展 (Extensions)**
|
||||
|
||||
---
|
||||
|
||||
独立的 OpenWebUI 前端增强扩展,全面提升交互体验。
|
||||
|
||||
[:octicons-arrow-right-24: 浏览扩展](extensions/index.md)
|
||||
|
||||
- :material-book-open-page-variant:{ .lg .middle } **开发指南**
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +73,7 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-brain:{ .lg .middle } **智能思维导图**
|
||||
- :material-brain:{ .lg .middle } **智能思维导图**
|
||||
|
||||
---
|
||||
|
||||
@@ -73,7 +81,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: 了解更多](plugins/actions/smart-mind-map.md)
|
||||
|
||||
- :material-card-text:{ .lg .middle } **Flash Card(闪记卡)**
|
||||
- :material-card-text:{ .lg .middle } **Flash Card(闪记卡)**
|
||||
|
||||
---
|
||||
|
||||
@@ -81,7 +89,7 @@ hide:
|
||||
|
||||
[:octicons-arrow-right-24: 了解更多](plugins/actions/flash-card.md)
|
||||
|
||||
- :material-arrow-collapse-vertical:{ .lg .middle } **异步上下文压缩**
|
||||
- :material-arrow-collapse-vertical:{ .lg .middle } **异步上下文压缩**
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
# GitHub Copilot SDK Pipe for OpenWebUI
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.2.3 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.3.0 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/open-webui) that allows you to use GitHub Copilot models (such as `gpt-5`, `gpt-5-mini`, `claude-sonnet-4.5`) directly within OpenWebUI. It is built upon the official [GitHub Copilot SDK for Python](https://github.com/github/copilot-sdk), providing a native integration experience.
|
||||
|
||||
## 🚀 What's New (v0.2.3)
|
||||
## 🚀 What's New (v0.3.0) - The Power of "Unified Ecosystem"
|
||||
|
||||
* **🧩 Per-user Overrides**: Added user-level overrides for `REASONING_EFFORT`, `CLI_PATH`, `DEBUG`, `SHOW_THINKING`, and `MODEL_ID`.
|
||||
* **🧠 Thinking Output Reliability**: Thinking visibility now respects the user setting and is correctly passed into streaming.
|
||||
* **📝 Formatting Enforcement**: Added automatic formatting hints to ensure outputs are well-structured (paragraphs, lists).
|
||||
* **🔌 Zero-Config Tool Bridge**: Automatically transforms your existing OpenWebUI Functions (Tools) into Copilot-compatible tools. **Copilot now has total access to your entire WebUI toolset!**
|
||||
* **🔗 Dynamic MCP Discovery**: Seamlessly connects to MCP servers defined in **Admin Settings -> Connections**. No configuration files required—it just works.
|
||||
* **⚡ High-Performance Async Engine**: Background CLI updates and optimized event-driven streaming ensure lightning-fast responses without UI lag.
|
||||
* **🛡️ Robust Interoperability**: Advanced sanitization and dynamic Pydantic model generation ensure smooth integration even with complex third-party tools.
|
||||
|
||||
## ✨ Core Features
|
||||
## ✨ Key Capabilities
|
||||
|
||||
* **🚀 Official SDK Integration**: Built on the official SDK for stability and reliability.
|
||||
* **🛠️ Custom Tools Support**: Example tools included (random number). Easy to extend with your own tools.
|
||||
* **💬 Multi-turn Conversation**: Automatically concatenates history context so Copilot understands your previous messages.
|
||||
* **🌊 Streaming Output**: Supports typewriter effect for fast responses.
|
||||
* **🖼️ Multimodal Support**: Supports image uploads, automatically converting them to attachments for Copilot (requires model support).
|
||||
* **🛠️ Zero-config Installation**: Automatically detects and downloads the GitHub Copilot CLI, ready to use out of the box.
|
||||
* **🔑 Secure Authentication**: Supports Fine-grained Personal Access Tokens for minimized permissions.
|
||||
* **🐛 Debug Mode**: Built-in detailed log output (browser console) for easy troubleshooting.
|
||||
* **⚠️ Single Node Only**: Due to local session storage, this plugin currently supports single-node OpenWebUI deployment or multi-node with sticky sessions enabled.
|
||||
* **🌉 The Ultimate Bridge**: The first and only plugin that creates a seamless bridge between **OpenWebUI Tools** and **GitHub Copilot SDK**.
|
||||
* **🚀 Official & Native**: Built directly on the official Python SDK, providing the most stable and authentic Copilot experience.
|
||||
* **🌊 Advanced Streaming (Thought Process)**: Supports full model reasoning/thinking display with typewriter effects.
|
||||
* **🖼️ Intelligent Multimodal**: Full support for images and attachments, enabling Copilot to "see" your workspace.
|
||||
* **🛠️ Effortless Setup**: Automatic CLI detection, version enforcement, and dependency management.
|
||||
* **🔑 Dual-Layer Security**: Supports secure OAuth flow for Chat and standard PAT for extended MCP capabilities.
|
||||
|
||||
## 📦 Installation & Usage
|
||||
|
||||
@@ -38,13 +36,11 @@ Find "GitHub Copilot" in the function list and click the **⚙️ (Valves)** ico
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | **(Required)** Your GitHub Token. | - |
|
||||
| **MODEL_ID** | The model name to use. Recommended `gpt-5-mini` or `gpt-5`. | `gpt-5-mini` |
|
||||
| **CLI_PATH** | Path to the Copilot CLI. Will download automatically if not found. | `/usr/local/bin/copilot` |
|
||||
| **GH_TOKEN** | **(Required)** GitHub Access Token (PAT or OAuth Token). Access to Chat. | - |
|
||||
| **DEBUG** | Whether to enable debug logs (output to browser console). | `False` |
|
||||
| **LOG_LEVEL** | Copilot CLI log level: none, error, warning, info, debug, all. | `error` |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process (requires streaming + model support). | `True` |
|
||||
| **SHOW_WORKSPACE_INFO** | Show session workspace path and summary in debug mode. | `True` |
|
||||
| **COPILOT_CLI_VERSION** | Specific Copilot CLI version to install/enforce. | `0.0.405` |
|
||||
| **EXCLUDE_KEYWORDS** | Exclude models containing these keywords (comma separated). | - |
|
||||
| **WORKSPACE_DIR** | Restricted workspace directory for file operations. | - |
|
||||
| **INFINITE_SESSION** | Enable Infinite Sessions (automatic context compaction). | `True` |
|
||||
@@ -52,10 +48,10 @@ Find "GitHub Copilot" in the function list and click the **⚙️ (Valves)** ico
|
||||
| **BUFFER_THRESHOLD** | Buffer exhaustion threshold (0.0-1.0). | `0.95` |
|
||||
| **TIMEOUT** | Timeout for each stream chunk (seconds). | `300` |
|
||||
| **CUSTOM_ENV_VARS** | Custom environment variables (JSON format). | - |
|
||||
| **REASONING_EFFORT** | Reasoning effort level: low, medium, high. `xhigh` is supported for gpt-5.2-codex. | `medium` |
|
||||
| **REASONING_EFFORT** | Reasoning effort level: low, medium, high. `xhigh` is supported for some models. | `medium` |
|
||||
| **ENFORCE_FORMATTING** | Add formatting instructions to system prompt for better readability. | `True` |
|
||||
| **ENABLE_TOOLS** | Enable custom tools (example: random number). | `False` |
|
||||
| **AVAILABLE_TOOLS** | Available tools: 'all' or comma-separated list. | `all` |
|
||||
| **ENABLE_MCP_SERVER** | Enable Direct MCP Client connection (Recommended). | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | Enable OpenWebUI Tools (includes defined and server tools). | `True` |
|
||||
|
||||
#### User Valves (per-user overrides)
|
||||
|
||||
@@ -63,37 +59,26 @@ These optional settings can be set per user (overrides global Valves):
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | Personal GitHub Token (overrides global setting). | - |
|
||||
| **REASONING_EFFORT** | Reasoning effort level (low/medium/high/xhigh). | - |
|
||||
| **CLI_PATH** | Custom path to Copilot CLI. | - |
|
||||
| **DEBUG** | Enable technical debug logs. | `False` |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process (requires streaming + model support). | `True` |
|
||||
| **MODEL_ID** | Custom model ID. | - |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process. | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | Enable OpenWebUI Tools (overrides global). | `True` |
|
||||
| **ENABLE_MCP_SERVER** | Enable MCP server loading (overrides global). | `True` |
|
||||
| **ENFORCE_FORMATTING** | Enforce formatting guidelines (overrides global). | `True` |
|
||||
|
||||
### 3. Using Custom Tools (🆕 Optional)
|
||||
### 3. Get Token
|
||||
|
||||
This pipe includes **1 example tool** to demonstrate tool calling:
|
||||
To use GitHub Copilot, you need a GitHub Personal Access Token (PAT) with appropriate permissions.
|
||||
|
||||
* **🎲 generate_random_number**: Generate random integers
|
||||
|
||||
**To enable:**
|
||||
|
||||
1. Set `ENABLE_TOOLS: true` in Valves
|
||||
2. Try: "Give me a random number"
|
||||
|
||||
**📚 For detailed usage and creating your own tools, see [TOOLS_USAGE.md](https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/debug/github-copilot-sdk/guides/TOOLS_USAGE.md)**
|
||||
|
||||
### 4. Get GH_TOKEN
|
||||
|
||||
For security, it is recommended to use a **Fine-grained Personal Access Token**:
|
||||
**Steps to generate your token:**
|
||||
|
||||
1. Visit [GitHub Token Settings](https://github.com/settings/tokens?type=beta).
|
||||
2. Click **Generate new token**.
|
||||
3. **Repository access**: Select **Public repositories** (Required to access Copilot permissions).
|
||||
2. Click **Generate new token (fine-grained)**.
|
||||
3. **Repository access**: Select **Public Repositories** (simplest) or **All repositories**.
|
||||
4. **Permissions**:
|
||||
|
||||
* Click **Account permissions**.
|
||||
* Find **Copilot Requests** (It defaults to **Read-only**, no selection needed).
|
||||
|
||||
* If you chose **All repositories**, you must click **Account permissions**.
|
||||
* Find **Copilot Requests**, and select **Access**.
|
||||
5. Generate and copy the Token.
|
||||
|
||||
## 📋 Dependencies
|
||||
@@ -103,17 +88,12 @@ This Pipe will automatically attempt to install the following dependencies:
|
||||
* `github-copilot-sdk` (Python package)
|
||||
* `github-copilot-cli` (Binary file, installed via official script)
|
||||
|
||||
## ⚠️ FAQ
|
||||
## Troubleshooting ❓
|
||||
|
||||
* **Stuck on "Waiting..."**:
|
||||
* Check if `GH_TOKEN` is correct and has `Copilot Requests` permission.
|
||||
* **Images not recognized**:
|
||||
* **Images and Multimodal Usage**:
|
||||
* Ensure `MODEL_ID` is a model that supports multimodal input.
|
||||
* **Thinking not shown**:
|
||||
* Ensure **streaming is enabled** and the selected model supports reasoning output.
|
||||
* **CLI Installation Failed**:
|
||||
* Ensure the OpenWebUI container has internet access.
|
||||
* You can manually download the CLI and specify `CLI_PATH` in Valves.
|
||||
|
||||
## 📄 License
|
||||
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
# GitHub Copilot SDK 官方管道
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.2.3 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.3.0 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
这是一个用于 [OpenWebUI](https://github.com/open-webui/open-webui) 的高级 Pipe 函数,允许你直接在 OpenWebUI 中使用 GitHub Copilot 模型(如 `gpt-5`, `gpt-5-mini`, `claude-sonnet-4.5`)。它基于官方 [GitHub Copilot SDK for Python](https://github.com/github/copilot-sdk) 构建,提供了原生级的集成体验。
|
||||
|
||||
## 🚀 最新特性 (v0.2.3)
|
||||
## 🚀 最新特性 (v0.3.0) - “统一生态”的力量
|
||||
|
||||
* **🧩 用户级覆盖**:新增 `REASONING_EFFORT`、`CLI_PATH`、`DEBUG`、`SHOW_THINKING`、`MODEL_ID` 的用户级覆盖。
|
||||
* **🧠 思考输出可靠性**:思考显示会遵循用户设置,并正确传递到流式输出中。
|
||||
* **📝 格式化输出增强**:自动优化输出格式(段落、列表),并解决了在某些界面下显示过于紧凑的问题。
|
||||
* **🔌 零配置工具桥接 (Unified Tool Bridge)**: 自动将您现有的 OpenWebUI Functions (工具) 转换为 Copilot 兼容工具。**Copilot 现在可以无缝调用您手头所有的 WebUI 工具!**
|
||||
* **🔗 动态 MCP 自动发现**: 直接联动 OpenWebUI **管理面板 -> 连接**。无需编写任何配置文件,即插即用,瞬间扩展 Copilot 能力边界。
|
||||
* **⚡ 高性能异步引擎**: 异步 CLI 更新检查与高度优化的事件驱动流式处理,确保对话毫秒级响应。
|
||||
* **🛡️ 卓越的兼容性**: 独创的动态 Pydantic 模型生成技术,确保复杂工具参数在 Copilot 端也能得到精准验证。
|
||||
|
||||
## ✨ 核心特性
|
||||
## ✨ 核心能力
|
||||
|
||||
* **🚀 官方 SDK 集成**:基于官方 SDK,稳定可靠。
|
||||
* **🛠️ 自定义工具支持**:内置示例工具(随机数)。易于扩展自定义工具。
|
||||
* **💬 多轮对话支持**:自动拼接历史上下文,Copilot 能理解你的前文。
|
||||
* **🌊 流式输出 (Streaming)**:支持打字机效果,响应迅速。
|
||||
* **🖼️ 多模态支持**:支持上传图片,自动转换为附件发送给 Copilot(需模型支持)。
|
||||
* **🛠️ 零配置安装**:自动检测并下载 GitHub Copilot CLI,开箱即用。
|
||||
* **🔑 安全认证**:支持 Fine-grained Personal Access Tokens,权限最小化。
|
||||
* **🐛 调试模式**:内置详细的日志输出(浏览器控制台),方便排查问题。
|
||||
* **⚠️ 仅支持单节点**:由于会话状态存储在本地,本插件目前仅支持 OpenWebUI 单节点部署,或开启了会话粘性 (Sticky Session) 的多节点集群。
|
||||
* **🌉 强大的生态桥接**: 首个且唯一完美打通 **OpenWebUI Tools** 与 **GitHub Copilot SDK** 的插件。
|
||||
* **🚀 官方原生产体验**: 基于官方 Python SDK 构建,提供最稳定、最纯正的 Copilot 交互体验。
|
||||
* **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染。
|
||||
* **🖼️ 智能多模态**: 支持图像识别与附件上传,让 Copilot 拥有视觉能力。
|
||||
* **🛠️ 极简部署流程**: 自动检测环境、自动下载 CLI、自动管理依赖,全自动化开箱即用。
|
||||
* **🔑 安全认证体系**: 完美支持 OAuth 授权与 PAT 模式,兼顾便捷与安全性。
|
||||
|
||||
## 📦 安装与使用
|
||||
|
||||
@@ -38,24 +36,22 @@
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | **(必填)** 你的 GitHub Token。 | - |
|
||||
| **MODEL_ID** | 使用的模型名称。推荐 `gpt-5-mini` 或 `gpt-5`。 | `gpt-5-mini` |
|
||||
| **CLI_PATH** | Copilot CLI 的路径。如果未找到会自动下载。 | `/usr/local/bin/copilot` |
|
||||
| **GH_TOKEN** | **(必填)** GitHub 访问令牌 (PAT 或 OAuth Token)。用于聊天。 | - |
|
||||
| **DEBUG** | 是否开启调试日志(输出到浏览器控制台)。 | `False` |
|
||||
| **LOG_LEVEL** | Copilot CLI 日志级别: none, error, warning, info, debug, all。 | `error` |
|
||||
| **SHOW_THINKING** | 是否显示模型推理/思考过程(需开启流式 + 模型支持)。 | `True` |
|
||||
| **SHOW_WORKSPACE_INFO** | 在调试模式下显示会话工作空间路径和摘要。 | `True` |
|
||||
| **EXCLUDE_KEYWORDS** | 排除包含这些关键词的模型 (逗号分隔)。 | - |
|
||||
| **WORKSPACE_DIR** | 文件操作的受限工作目录。 | - |
|
||||
| **INFINITE_SESSION** | 启用无限会话 (自动上下文压缩)。 | `True` |
|
||||
| **COPILOT_CLI_VERSION** | 指定安装/强制使用的 Copilot CLI 版本。 | `0.0.405` |
|
||||
| **EXCLUDE_KEYWORDS** | 排除包含这些关键词的模型(逗号分隔)。 | - |
|
||||
| **WORKSPACE_DIR** | 文件操作的受限工作区目录。 | - |
|
||||
| **INFINITE_SESSION** | 启用无限会话(自动上下文压缩)。 | `True` |
|
||||
| **COMPACTION_THRESHOLD** | 后台压缩阈值 (0.0-1.0)。 | `0.8` |
|
||||
| **BUFFER_THRESHOLD** | 缓冲耗尽阈值 (0.0-1.0)。 | `0.95` |
|
||||
| **TIMEOUT** | 流式数据块超时时间 (秒)。 | `300` |
|
||||
| **BUFFER_THRESHOLD** | 缓冲区耗尽阈值 (0.0-1.0)。 | `0.95` |
|
||||
| **TIMEOUT** | 每个流式分块超时(秒)。 | `300` |
|
||||
| **CUSTOM_ENV_VARS** | 自定义环境变量 (JSON 格式)。 | - |
|
||||
| **ENABLE_TOOLS** | 启用自定义工具 (示例:随机数)。 | `False` |
|
||||
| **AVAILABLE_TOOLS** | 可用工具: 'all' 或逗号分隔列表。 | `all` |
|
||||
| **REASONING_EFFORT** | 推理强度级别:low, medium, high。`gpt-5.2-codex`额外支持`xhigh`。 | `medium` |
|
||||
| **ENFORCE_FORMATTING** | 是否强制添加格式化指导,以提高输出可读性。 | `True` |
|
||||
| **REASONING_EFFORT** | 推理强度级别: low, medium, high. `xhigh` 仅部分模型支持。 | `medium` |
|
||||
| **ENFORCE_FORMATTING** | 在系统提示词中添加格式化指导。 | `True` |
|
||||
| **ENABLE_MCP_SERVER** | 启用直接 MCP 客户端连接 (建议)。 | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | 启用 OpenWebUI 工具 (包括自定义和服务器工具)。 | `True` |
|
||||
|
||||
#### 用户 Valves(按用户覆盖)
|
||||
|
||||
@@ -63,38 +59,27 @@
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | 个人 GitHub Token(覆盖全局设置)。 | - |
|
||||
| **REASONING_EFFORT** | 推理强度级别(low/medium/high/xhigh)。 | - |
|
||||
| **CLI_PATH** | 自定义 Copilot CLI 路径。 | - |
|
||||
| **DEBUG** | 是否启用技术调试日志。 | `False` |
|
||||
| **SHOW_THINKING** | 是否显示思考过程(需开启流式 + 模型支持)。 | `True` |
|
||||
| **MODEL_ID** | 自定义模型 ID。 | - |
|
||||
| **SHOW_THINKING** | 是否显示思考过程。 | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | 启用 OpenWebUI 工具(覆盖全局设置)。 | `True` |
|
||||
| **ENABLE_MCP_SERVER** | 启用动态 MCP 服务器加载(覆盖全局设置)。 | `True` |
|
||||
| **ENFORCE_FORMATTING** | 强制启用格式化指导(覆盖全局设置)。 | `True` |
|
||||
|
||||
### 3. 使用自定义工具 (🆕 可选)
|
||||
### 3. 获取 Token
|
||||
|
||||
本 Pipe 内置了 **1 个示例工具**来展示工具调用功能:
|
||||
要使用 GitHub Copilot,您需要一个具有适当权限的 GitHub 个人访问令牌 (PAT)。
|
||||
|
||||
* **🎲 generate_random_number**:生成随机整数
|
||||
**获取步骤:**
|
||||
|
||||
**启用方法:**
|
||||
|
||||
1. 在 Valves 中设置 `ENABLE_TOOLS: true`
|
||||
2. 尝试问:“给我一个随机数”
|
||||
|
||||
**📚 详细使用说明和创建自定义工具,请参阅 [TOOLS_USAGE.md](https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/debug/github-copilot-sdk/guides/TOOLS_USAGE.md)**
|
||||
|
||||
### 4. 获取 GH_TOKEN
|
||||
|
||||
为了安全起见,推荐使用 **Fine-grained Personal Access Token**:
|
||||
|
||||
1. 访问 [GitHub Token Settings](https://github.com/settings/tokens?type=beta)。
|
||||
2. 点击 **Generate new token**。
|
||||
3. **Repository access**: 选择 **Public repositories** (必须选择此项才能看到 Copilot 权限)。
|
||||
1. 访问 [GitHub 令牌设置](https://github.com/settings/tokens?type=beta)。
|
||||
2. 点击 **Generate new token (fine-grained)**。
|
||||
3. **Repository access**: 选择 **Public Repositories** (最简单) 或 **All repositories**。
|
||||
4. **Permissions**:
|
||||
|
||||
* 点击 **Account permissions**。
|
||||
* 找到 **Copilot Requests** (默认即为 **Read-only**,无需手动修改)。
|
||||
|
||||
5. 生成并复制 Token。
|
||||
* 如果您选择了 **All repositories**,则必须点击 **Account permissions**。
|
||||
* 找到 **Copilot Requests**,选择 **Access**。
|
||||
5. 生成并复制令牌。
|
||||
|
||||
## 📋 依赖说明
|
||||
|
||||
@@ -103,17 +88,12 @@
|
||||
* `github-copilot-sdk` (Python 包)
|
||||
* `github-copilot-cli` (二进制文件,通过官方脚本安装)
|
||||
|
||||
## ⚠️ 常见问题
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
* **一直显示 "Waiting..."**:
|
||||
* 检查 `GH_TOKEN` 是否正确且拥有 `Copilot Requests` 权限。
|
||||
* **图片无法识别**:
|
||||
* **图片及多模态使用说明**:
|
||||
* 确保 `MODEL_ID` 是支持多模态的模型。
|
||||
* **看不到思考过程**:
|
||||
* 确认已开启**流式输出**,且所选模型支持推理输出。
|
||||
* **CLI 安装失败**:
|
||||
* 确保 OpenWebUI 容器有外网访问权限。
|
||||
* 你可以手动下载 CLI 并挂载到容器中,然后在 Valves 中指定 `CLI_PATH`。
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Pipes allow you to:
|
||||
|
||||
## Available Pipe Plugins
|
||||
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.md) (v0.1.1) - Official GitHub Copilot SDK integration. Supports dynamic models, multi-turn conversation, streaming, multimodal input, and infinite sessions.
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.md) (v0.3.0) - Official GitHub Copilot SDK integration. Features **zero-config OpenWebUI Tool Bridge** and **dynamic MCP discovery**. Supports streaming, multimodal, and infinite sessions.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Pipes 可以用于:
|
||||
|
||||
## 可用的 Pipe 插件
|
||||
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.zh.md) (v0.1.1) - GitHub Copilot SDK 官方集成。支持动态模型、多轮对话、流式输出、图片输入及无限会话。
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.zh.md) (v0.3.0) - GitHub Copilot SDK 官方集成。**零配置工具桥接**与**动态 MCP 发现**。支持流式输出、多模态及无限会话。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ A comprehensive thinking lens that dives deep into any content - from context to
|
||||
| **Clear Previous HTML (CLEAR_PREVIOUS_HTML)** | `True` | Whether to clear previous plugin results. |
|
||||
| **Message Count (MESSAGE_COUNT)** | `1` | Number of recent messages to analyze. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🌗 Theme Support
|
||||
|
||||
The plugin automatically detects and adapts to OpenWebUI's theme settings:
|
||||
@@ -48,7 +52,7 @@ The plugin automatically detects and adapts to OpenWebUI's theme settings:
|
||||
2. Parent document `html/body` class or `data-theme` attribute
|
||||
3. System preference via `prefers-color-scheme: dark`
|
||||
|
||||
- **Requirements**: For best results, enable **iframe Sandbox Allow Same Origin** in OpenWebUI:
|
||||
- **Requirements**: For best results, enable **iframe Sandbox Allow Same Origin** in OpenWebUI:
|
||||
- Go to **Settings** → **Interface** → **Artifacts** → Check **iframe Sandbox Allow Same Origin**
|
||||
|
||||
## 🎨 Visual Preview
|
||||
@@ -88,3 +92,7 @@ The plugin generates a structured thinking timeline:
|
||||
- **Debug Logs**: Enable `SHOW_STATUS` in Valves to see progress updates.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
| **清除旧 HTML (CLEAR_PREVIOUS_HTML)** | `True` | 是否清除之前的插件结果。 |
|
||||
| **消息数量 (MESSAGE_COUNT)** | `1` | 要分析的最近消息数量。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 🌗 主题支持
|
||||
|
||||
插件会自动检测并适配 OpenWebUI 的主题设置:
|
||||
@@ -88,3 +92,7 @@
|
||||
- **调试日志**: 在 Valves 中启用 `SHOW_STATUS` 以查看进度更新。
|
||||
- **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -44,6 +44,10 @@ Export conversation to Word (.docx) with **syntax highlighting**, **native math
|
||||
| **Mermaid PNG Scale** | `3.0` | Resolution multiplier for Mermaid images |
|
||||
| **Math Enable** | `True` | Enable LaTeX math conversion |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🛠️ Supported Markdown Syntax
|
||||
|
||||
| Syntax | Word Result |
|
||||
@@ -71,25 +75,13 @@ Export conversation to Word (.docx) with **syntax highlighting**, **native math
|
||||
- `latex2mathml` - LaTeX to MathML conversion
|
||||
- `mathml2omml` - MathML to Office Math (OMML) conversion
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
### v0.4.3
|
||||
- **S3 Object Storage**: Direct S3/MinIO access via boto3 for faster image retrieval.
|
||||
- **6-Level Fallback**: Robust file retrieval: DB → S3 → Local → URL → API → Attributes.
|
||||
- **Better Logging**: Improved error messages for debugging file access issues.
|
||||
|
||||
### v0.4.1
|
||||
- **Chinese Parameter Names**: Localized configuration names for Chinese version.
|
||||
|
||||
### v0.4.0
|
||||
- **Multi-language Support**: UI language switching (English/Chinese).
|
||||
- **Font & Style Configuration**: Customizable fonts and table colors.
|
||||
- **Mermaid Enhancements**: Hybrid SVG+PNG rendering, background color config.
|
||||
- **Performance**: Real-time progress updates for large exports.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the filter/action is enabled in the model settings.
|
||||
- **Debug Logs**: Check the browser console (F12) for detailed logs if available.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
| **Mermaid_PNG缩放比例** | `3.0` | Mermaid 图片分辨率倍数 |
|
||||
| **启用数学公式** | `True` | 启用 LaTeX 公式转换 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 🛠️ 支持的 Markdown 语法
|
||||
|
||||
| 语法 | Word 效果 |
|
||||
@@ -71,25 +75,13 @@
|
||||
- `latex2mathml` - LaTeX 转 MathML
|
||||
- `mathml2omml` - MathML 转 Office Math (OMML)
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### v0.4.3
|
||||
- **S3 对象存储**: 通过 boto3 直连 S3/MinIO,图片获取速度更快。
|
||||
- **6 级回退机制**: 稳健的文件获取:数据库 → S3 → 本地 → URL → API → 属性。
|
||||
- **日志优化**: 改进错误提示,便于调试文件访问问题。
|
||||
|
||||
### v0.4.1
|
||||
- **中文参数名**: 配置项名称和描述全部汉化。
|
||||
|
||||
### v0.4.0
|
||||
- **多语言支持**: 界面语言切换(中文/英文)。
|
||||
- **字体与样式配置**: 支持自定义中英文字体、代码字体以及表格颜色。
|
||||
- **Mermaid 增强**: 混合 SVG+PNG 渲染,支持背景色配置。
|
||||
- **性能优化**: 导出大型文档时提供实时进度反馈。
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
- **插件不工作?**: 请检查是否在模型设置中启用了该过滤器/动作。
|
||||
- **调试日志**: 请查看浏览器控制台 (F12) 获取详细日志(如果可用)。
|
||||
- **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -1,4 +1,59 @@
|
||||
# Export to Excel
|
||||
# 📊 Export to Excel
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.3.6 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
Export chat history to an Excel (.xlsx) file directly from the chat interface.
|
||||
|
||||
## 🔥 What's New in v0.3.6
|
||||
|
||||
- **OpenWebUI-Style Theme**: Modern dark header (#1f2937) with light gray zebra striping for better readability.
|
||||
- **Zebra Striping**: Alternating row colors (#ffffff / #f3f4f6) for improved visual scanning.
|
||||
- **Smart Data Type Conversion**: Automatically converts columns to numeric or datetime types with fallback to string.
|
||||
- **Full Cell Bold/Italic**: Supports full cell Markdown bold (`**text**`) and italic (`*text*`) formatting in Excel.
|
||||
- **Partial Markdown Cleanup**: Removes partial Markdown formatting symbols for cleaner Excel output.
|
||||
- **Export Scope**: Added `EXPORT_SCOPE` to choose between the last message or all messages.
|
||||
- **Smart Sheet Naming**: Names sheets based on Markdown headers, AI titles, or message index.
|
||||
- **Multiple Tables Support**: Improved handling of multiple tables across messages.
|
||||
- **Smart Filename Generation**: Supports filenames based on chat title, AI summary, or Markdown headers.
|
||||
- **Configuration Options**: Added `TITLE_SOURCE` to control filename strategy.
|
||||
- **AI Title Generation**: Added `MODEL_ID` to use AI for filename generation with progress notifications.
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
- 🚀 **One-Click Export**: Adds an “Export to Excel” action button to the chat.
|
||||
- 🧠 **Automatic Header Extraction**: Intelligently identifies table headers from chat content.
|
||||
- 📊 **Multi-Table Support**: Handles multiple tables within a single chat session.
|
||||
|
||||
## 🚀 How to Use
|
||||
|
||||
1. **Install**: Search for “Export to Excel” in the Open WebUI Community and install.
|
||||
2. **Trigger**: In any chat, click the “Export to Excel” action button.
|
||||
3. **Download**: The .xlsx file will be automatically downloaded.
|
||||
|
||||
## ⚙️ Configuration (Valves)
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `TITLE_SOURCE` | `chat_title` | Filename source: `chat_title`, `ai_generated`, or `markdown_title`. |
|
||||
| `EXPORT_SCOPE` | `last_message` | Export scope: `last_message` or `all_messages`. |
|
||||
| `MODEL_ID` | `""` | Model ID for AI title generation. Empty uses current chat model. |
|
||||
| `SHOW_STATUS` | `True` | Show operation status updates. |
|
||||
| `SHOW_DEBUG_LOG` | `False` | Print debug logs in the browser console (F12). |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the filter/action is enabled in the model settings.
|
||||
- **Debug Logs**: Enable `SHOW_STATUS` and check the browser console (F12) if needed.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)# Export to Excel
|
||||
|
||||
This plugin allows you to export your chat history to an Excel (.xlsx) file directly from the chat interface.
|
||||
|
||||
|
||||
@@ -1,4 +1,59 @@
|
||||
# 导出为 Excel
|
||||
# 📊 导出为 Excel
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.3.6 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
将对话历史直接导出为 Excel (.xlsx) 文件。
|
||||
|
||||
## 🔥 最新更新 v0.3.6
|
||||
|
||||
- **OpenWebUI 风格主题**:现代深灰表头(#1f2937)与浅灰斑马纹,提升可读性。
|
||||
- **斑马纹效果**:隔行变色(#ffffff / #f3f4f6),方便视觉扫描。
|
||||
- **智能数据类型转换**:自动将列转换为数字或日期类型,无法转换时保持字符串。
|
||||
- **全单元格粗体/斜体**:支持全单元格 Markdown 粗体与斜体格式。
|
||||
- **部分 Markdown 清理**:移除部分 Markdown 格式符号,输出更整洁。
|
||||
- **导出范围**:新增 `EXPORT_SCOPE`,可选择导出最后一条或所有消息。
|
||||
- **智能 Sheet 命名**:按 Markdown 标题、AI 标题或消息索引命名。
|
||||
- **多表格支持**:优化了多表格处理能力。
|
||||
- **智能文件名生成**:支持对话标题 / AI 总结 / Markdown 标题命名。
|
||||
- **配置选项**:新增 `TITLE_SOURCE` 控制文件名策略。
|
||||
- **AI 标题生成**:新增 `MODEL_ID`,支持 AI 标题生成与进度提示。
|
||||
|
||||
## ✨ 核心特性
|
||||
|
||||
- 🚀 **一键导出**:在聊天界面添加“导出为 Excel”按钮。
|
||||
- 🧠 **自动表头提取**:智能识别聊天内容中的表格标题。
|
||||
- 📊 **多表支持**:支持单次对话中的多个表格。
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
1. **安装**:在 Open WebUI 社区搜索“导出为 Excel”并安装。
|
||||
2. **触发**:在任意对话中,点击“导出为 Excel”动作按钮。
|
||||
3. **下载**:.xlsx 文件将自动下载到你的设备。
|
||||
|
||||
## ⚙️ 配置参数 (Valves)
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- |
|
||||
| `TITLE_SOURCE` | `chat_title` | 文件名来源:`chat_title`、`ai_generated`、`markdown_title`。 |
|
||||
| `EXPORT_SCOPE` | `last_message` | 导出范围:`last_message` 或 `all_messages`。 |
|
||||
| `MODEL_ID` | `""` | AI 标题生成的模型 ID。为空则使用当前对话模型。 |
|
||||
| `SHOW_STATUS` | `True` | 是否显示操作状态更新。 |
|
||||
| `SHOW_DEBUG_LOG` | `False` | 是否在浏览器控制台输出调试日志 (F12)。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
- **插件不工作?**: 请检查是否在模型设置中启用了该过滤器/动作。
|
||||
- **调试日志**: 如需排查,启用 `SHOW_STATUS` 并查看浏览器控制台 (F12)。
|
||||
- **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)# 导出为 Excel
|
||||
|
||||
此插件允许你直接从聊天界面将对话历史导出为 Excel (.xlsx) 文件。
|
||||
|
||||
|
||||
@@ -4,13 +4,10 @@ Generate polished learning flashcards from any text—title, summary, key points
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.2.4 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
## Preview 📸
|
||||
|
||||

|
||||
|
||||
## What's New
|
||||
|
||||
### v0.2.4
|
||||
|
||||
- **Clean Output**: Removed debug messages from output.
|
||||
|
||||
## Key Features 🔑
|
||||
@@ -39,9 +36,21 @@ Generate polished learning flashcards from any text—title, summary, key points
|
||||
| CLEAR_PREVIOUS_HTML | Whether to clear previous card HTML (otherwise append/merge) | false |
|
||||
| MESSAGE_COUNT | Use the latest N messages to build the card | 1 |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the filter/action is enabled in the model settings.
|
||||
- **Debug Logs**: Enable `SHOW_STATUS` in Valves to see progress updates.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Preview 📸
|
||||
|
||||

|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -4,22 +4,17 @@
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.2.4 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
## 预览 📸
|
||||
## 🔥 最新更新 v0.2.4
|
||||
|
||||

|
||||
|
||||
## 更新日志
|
||||
|
||||
### v0.2.4
|
||||
- **输出优化**: 移除输出中的调试信息。
|
||||
* **输出优化**: 移除输出中的调试信息。
|
||||
|
||||
## 核心特性 🔑
|
||||
|
||||
- **一键生成**:输入任意文本,直接产出结构化卡片。
|
||||
- **要点聚合**:自动提取 3-5 个记忆要点与 2-4 个标签。
|
||||
- **多语言支持**:可设定目标语言(默认中文)。
|
||||
- **渐进合并**:多次调用会将新卡片合并到同一 HTML 容器中;如需重置可启用清空选项。
|
||||
- **状态提示**:实时推送“生成中/完成/错误”等状态与通知。
|
||||
* **一键生成**:输入任意文本,直接产出结构化卡片。
|
||||
* **要点聚合**:自动提取 3-5 个记忆要点与 2-4 个标签。
|
||||
* **多语言支持**:可设定目标语言(默认中文)。
|
||||
* **渐进合并**:多次调用会将新卡片合并到同一 HTML 容器中;如需重置可启用清空选项。
|
||||
* **状态提示**:实时推送“生成中/完成/错误”等状态与通知。
|
||||
|
||||
## 使用方法 🛠️
|
||||
|
||||
@@ -39,9 +34,21 @@
|
||||
| CLEAR_PREVIOUS_HTML | 是否清空旧的卡片 HTML(否则合并追加) | false |
|
||||
| MESSAGE_COUNT | 取最近 N 条消息生成卡片 | 1 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
- **插件不工作?**: 请检查是否在模型设置中启用了该过滤器/动作。
|
||||
- **调试日志**: 在 Valves 中启用 `SHOW_STATUS` 以查看进度更新。
|
||||
- **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
* **插件不工作?**: 请检查是否在模型设置中启用了该过滤器/动作。
|
||||
* **调试日志**: 在 Valves 中启用 `SHOW_STATUS` 以查看进度更新。
|
||||
* **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
* **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 预览 📸
|
||||
|
||||

|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 📊 Smart Infographic (AntV)
|
||||
# Smart Infographic
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 1.5.0 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
@@ -10,19 +10,6 @@ An Open WebUI plugin powered by the AntV Infographic engine. It transforms long
|
||||
- 🗣️ **Context-Aware Generation**: Generated infographics now strictly follow the language of your input content (e.g., input Japanese -> output Japanese infographic).
|
||||
- 🐛 **Bug Fixes**: Fixed issues with language synchronization between the UI and generated content.
|
||||
|
||||
### Previous: v1.4.9
|
||||
|
||||
- 🎨 **70+ Official Templates**: Integrated comprehensive AntV infographic template library.
|
||||
- 🖼️ **Iconify & unDraw Support**: Richer visuals with official icons and illustrations.
|
||||
- 📏 **Visual Optimization**: Improved text wrapping, adaptive sizing, and layout refinement.
|
||||
- ✨ **PNG Upload**: Infographics now upload as PNG format for better Word export compatibility.
|
||||
- 🔧 **Canvas Conversion**: Uses browser canvas for high-quality SVG to PNG conversion (2x scale).
|
||||
|
||||
### Previous: v1.4.0
|
||||
|
||||
- ✨ **Default Mode Change**: Default output mode is now `image` (static image) for better compatibility.
|
||||
- 📱 **Responsive Sizing**: Images now auto-adapt to the chat container width.
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
- 🚀 **AI-Powered Transformation**: Automatically analyzes text logic, extracts key points, and generates structured charts.
|
||||
@@ -52,6 +39,10 @@ You can adjust the following parameters in the plugin settings to optimize the g
|
||||
| **Message Count (MESSAGE_COUNT)** | `1` | Number of recent messages to use for analysis. Increase this for more context. |
|
||||
| **Output Mode (OUTPUT_MODE)** | `image` | `image` for static image embedding (default, better compatibility), `html` for interactive chart. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🛠️ Supported Template Types
|
||||
|
||||
| Category | Template Name | Use Case |
|
||||
@@ -69,6 +60,10 @@ You can adjust the following parameters in the plugin settings to optimize the g
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
## 📝 Syntax Example (For Advanced Users)
|
||||
|
||||
You can also input this syntax directly for AI to render:
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
# 📊 智能信息图 (AntV Infographic)
|
||||
# 智能信息图
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 1.5.0 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
基于 AntV Infographic 引擎的 Open WebUI 插件,能够将长文本内容一键转换为专业、美观的信息图表。
|
||||
|
||||
## 🔥 v1.5.0 更新日志
|
||||
## 🔥 最新更新 v1.5.0
|
||||
|
||||
- 🌐 **智能语言检测**:自动从浏览器准确识别当前界面语言设置。
|
||||
- 🗣️ **上下文感知生成**:生成的信息图内容现在严格跟随用户输入内容的语言(例如:输入日语 -> 生成日语信息图)。
|
||||
- 🐛 **问题修复**:修复了界面语言与生成内容语言不同步的问题。
|
||||
|
||||
### 此前: v1.4.9
|
||||
|
||||
- 🎨 **70+ 官方模板**:全面集成 AntV 官方信息图模板库。
|
||||
- 🖼️ **图标与插图支持**:支持 Iconify 图标库与 unDraw 插图库,视觉效果更丰富。
|
||||
- 📏 **视觉优化**:改进文本换行逻辑,优化自适应尺寸,提升卡片布局精细度。
|
||||
- ✨ **PNG 上传**:信息图现在以 PNG 格式上传,与 Word 导出完美兼容。
|
||||
- 🔧 **Canvas 转换**:使用浏览器 Canvas 高质量转换 SVG 为 PNG(2倍缩放)。
|
||||
|
||||
### 此前: v1.4.0
|
||||
|
||||
- ✨ **默认模式变更**:默认输出模式调整为 `image`(静态图片)。
|
||||
- 📱 **响应式尺寸**:图片模式下自动适应聊天容器宽度。
|
||||
|
||||
## ✨ 核心特性
|
||||
|
||||
- 🚀 **智能转换**:自动分析文本核心逻辑,提取关键点并生成结构化图表。
|
||||
@@ -52,6 +39,10 @@
|
||||
| **上下文消息数 (MESSAGE_COUNT)** | `1` | 用于分析的最近消息条数。增加此值可让 AI 参考更多对话背景。 |
|
||||
| **输出模式 (OUTPUT_MODE)** | `image` | `image` 为静态图片嵌入(默认,兼容性好),`html` 为交互式图表。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 🛠️ 支持的模板类型
|
||||
|
||||
| 分类 | 模板名称 | 适用场景 |
|
||||
@@ -69,6 +60,10 @@
|
||||
- **错误信息**: 如果看到错误,请复制完整的错误信息并报告。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
## 📝 语法示例 (高级用户)
|
||||
|
||||
你也可以直接输入以下语法让 AI 渲染:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
title: 📊 Smart Infographic (AntV)
|
||||
title: Smart Infographic
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/awesome-openwebui
|
||||
funding_url: https://github.com/open-webui
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
title: 📊 智能信息图 (AntV Infographic)
|
||||
title: 智能信息图
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/awesome-openwebui
|
||||
funding_url: https://github.com/open-webui
|
||||
|
||||
@@ -38,6 +38,10 @@ Smart Mind Map is a powerful OpenWebUI action plugin that intelligently analyzes
|
||||
| `MESSAGE_COUNT` | `1` | Number of recent messages to use for generation (1-5). |
|
||||
| `OUTPUT_MODE` | `html` | Output mode: `html` (interactive) or `image` (static). |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the action is enabled in the chat settings.
|
||||
@@ -59,3 +63,7 @@ Smart Mind Map is a powerful OpenWebUI action plugin that intelligently analyzes
|
||||
1. **Text Preparation**: Provide text with clear structure and distinct hierarchies.
|
||||
2. **Model Selection**: Use fast models like `gemini-2.5-flash` for daily use.
|
||||
3. **Export Quality**: Use PNG for presentations and SVG for further editing.
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
| `MESSAGE_COUNT` | `1` | 用于生成思维导图的最近消息数量(1-5)。 |
|
||||
| `OUTPUT_MODE` | `html` | 输出模式:`html`(交互式)或 `image`(静态图片)。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
- **插件无法启动**:检查 OpenWebUI 日志,确认插件已正确上传并启用。
|
||||
@@ -59,3 +63,7 @@
|
||||
1. **文本准备**:提供结构清晰、层次分明的文本内容。
|
||||
2. **模型选择**:日常使用推荐 `gemini-2.5-flash` 等快速模型。
|
||||
3. **导出质量**:PNG 适合演示分享,SVG 适合进一步矢量编辑。
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
359
plugins/debug/common_tools/update_readmes_to_market.py
Normal file
359
plugins/debug/common_tools/update_readmes_to_market.py
Normal file
@@ -0,0 +1,359 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
======================================================================
|
||||
Staged README Synchronizer to OpenWebUI Community
|
||||
暂存 README 文件同步到 OpenWebUI 社区工具
|
||||
======================================================================
|
||||
|
||||
PURPOSE / 用途:
|
||||
--------------
|
||||
This script synchronizes staged README.md/README_CN.md files to their
|
||||
corresponding OpenWebUI Community posts automatically. It's designed for
|
||||
batch updating documentation content without modifying plugin versions
|
||||
or media attachments.
|
||||
|
||||
本脚本自动将暂存的 README.md/README_CN.md 文件同步到对应的 OpenWebUI
|
||||
社区帖子。专为批量更新文档内容设计,不修改插件版本或媒体附件。
|
||||
|
||||
USAGE / 使用方法:
|
||||
----------------
|
||||
1. Set up environment:
|
||||
配置环境:
|
||||
|
||||
Create a .env file in the repository root with:
|
||||
在仓库根目录创建 .env 文件,包含:
|
||||
|
||||
OPENWEBUI_API_KEY=your_api_key_here
|
||||
|
||||
2. Stage README files to sync:
|
||||
暂存需要同步的 README 文件:
|
||||
|
||||
git add plugins/actions/my_plugin/README.md
|
||||
git add plugins/actions/my_plugin/README_CN.md
|
||||
|
||||
3. Run the script:
|
||||
运行脚本:
|
||||
|
||||
python plugins/debug/common_tools/update_readmes_to_market.py
|
||||
|
||||
WORKFLOW / 工作流程:
|
||||
-------------------
|
||||
1. Load OPENWEBUI_API_KEY from .env file
|
||||
从 .env 文件加载 OPENWEBUI_API_KEY
|
||||
|
||||
2. Get list of staged README.md/README_CN.md files via git
|
||||
通过 git 获取暂存的 README.md/README_CN.md 文件列表
|
||||
|
||||
3. For each staged README:
|
||||
对于每个暂存的 README:
|
||||
|
||||
a. Locate the corresponding plugin .py file
|
||||
定位对应的插件 .py 文件
|
||||
|
||||
b. Extract openwebui_id/post_id from plugin frontmatter
|
||||
从插件前置信息中提取 openwebui_id/post_id
|
||||
|
||||
c. Fetch existing post data from OpenWebUI Community API
|
||||
从 OpenWebUI 社区 API 获取现有帖子数据
|
||||
|
||||
d. Update post content with new README content
|
||||
用新的 README 内容更新帖子内容
|
||||
|
||||
e. Push changes via API (preserves version & media)
|
||||
通过 API 推送更改(保留版本和媒体)
|
||||
|
||||
REQUIREMENTS / 依赖要求:
|
||||
-----------------------
|
||||
- python-dotenv: For loading .env configuration
|
||||
用于加载 .env 配置文件
|
||||
- Git repository: Must be run from a git-tracked workspace
|
||||
必须在 git 跟踪的工作区中运行
|
||||
|
||||
KEY FEATURES / 关键特性:
|
||||
-----------------------
|
||||
✅ Only updates content field (不仅更新内容字段)
|
||||
✅ Skips files without openwebui_id (跳过没有 openwebui_id 的文件)
|
||||
✅ Automatically matches CN/EN plugin files (自动匹配中英文插件文件)
|
||||
✅ Supports staged plugin source code updates (支持暂存插件源码更新)
|
||||
✅ Safe: Won't modify version or media fields (安全:不会修改版本或媒体字段)
|
||||
|
||||
NOTES / 注意事项:
|
||||
---------------
|
||||
- This is a DEBUG/DEVELOPMENT tool, not for production workflows
|
||||
这是一个调试/开发工具,不用于生产工作流
|
||||
|
||||
- Always verify changes in OpenWebUI Community after sync
|
||||
同步后务必在 OpenWebUI 社区中验证更改
|
||||
|
||||
- Requires valid API key with update permissions
|
||||
需要具有更新权限的有效 API 密钥
|
||||
|
||||
AUTHOR / 作者:
|
||||
-------------
|
||||
Fu-Jie
|
||||
GitHub: https://github.com/Fu-Jie/awesome-openwebui
|
||||
|
||||
======================================================================
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, List
|
||||
|
||||
|
||||
def _load_dotenv(repo_root: Path) -> None:
|
||||
try:
|
||||
from dotenv import load_dotenv # type: ignore
|
||||
except Exception as exc: # pragma: no cover
|
||||
print("Missing dependency: python-dotenv. Please install it and retry.")
|
||||
raise SystemExit(1) from exc
|
||||
|
||||
env_path = repo_root / ".env"
|
||||
load_dotenv(env_path)
|
||||
|
||||
|
||||
def _get_repo_root() -> Path:
|
||||
return Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
def _get_staged_readmes(repo_root: Path) -> List[Path]:
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"-C",
|
||||
str(repo_root),
|
||||
"diff",
|
||||
"--cached",
|
||||
"--name-only",
|
||||
"--",
|
||||
"*.md",
|
||||
],
|
||||
text=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
print(f"Failed to read staged files: {exc}")
|
||||
return []
|
||||
|
||||
paths = []
|
||||
for line in output.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line.endswith("README.md") or line.endswith("README_CN.md"):
|
||||
paths.append(repo_root / line)
|
||||
return paths
|
||||
|
||||
|
||||
def _get_staged_plugin_files(repo_root: Path) -> List[Path]:
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"-C",
|
||||
str(repo_root),
|
||||
"diff",
|
||||
"--cached",
|
||||
"--name-only",
|
||||
"--",
|
||||
"*.py",
|
||||
],
|
||||
text=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
print(f"Failed to read staged files: {exc}")
|
||||
return []
|
||||
|
||||
paths = []
|
||||
for line in output.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if "/plugins/" not in line:
|
||||
continue
|
||||
if line.endswith("__init__.py") or os.path.basename(line).startswith("test_"):
|
||||
continue
|
||||
paths.append(repo_root / line)
|
||||
return paths
|
||||
|
||||
|
||||
def _parse_frontmatter(content: str) -> Dict[str, str]:
|
||||
match = re.search(r'^\s*"""\n(.*?)\n"""', content, re.DOTALL)
|
||||
if not match:
|
||||
match = re.search(r'"""\n(.*?)\n"""', content, re.DOTALL)
|
||||
if not match:
|
||||
return {}
|
||||
|
||||
frontmatter = match.group(1)
|
||||
meta: Dict[str, str] = {}
|
||||
for line in frontmatter.split("\n"):
|
||||
if ":" in line:
|
||||
key, value = line.split(":", 1)
|
||||
meta[key.strip()] = value.strip()
|
||||
return meta
|
||||
|
||||
|
||||
def _find_plugin_file(readme_path: Path) -> Optional[Path]:
|
||||
plugin_dir = readme_path.parent
|
||||
is_cn = readme_path.name.lower().endswith("readme_cn.md")
|
||||
|
||||
py_files = [
|
||||
p
|
||||
for p in plugin_dir.glob("*.py")
|
||||
if p.name != "__init__.py" and not p.name.startswith("test_")
|
||||
]
|
||||
if not py_files:
|
||||
return None
|
||||
|
||||
cn_files = [p for p in py_files if p.stem.endswith("_cn")]
|
||||
en_files = [p for p in py_files if not p.stem.endswith("_cn")]
|
||||
|
||||
candidates = cn_files + en_files if is_cn else en_files + cn_files
|
||||
|
||||
# Prefer files that contain openwebui_id/post_id in frontmatter
|
||||
for candidate in candidates:
|
||||
post_id = _get_post_id(candidate)
|
||||
if post_id:
|
||||
return candidate
|
||||
|
||||
return candidates[0] if candidates else None
|
||||
|
||||
|
||||
def _get_post_id(plugin_file: Path) -> Optional[str]:
|
||||
try:
|
||||
content = plugin_file.read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
meta = _parse_frontmatter(content)
|
||||
return meta.get("openwebui_id") or meta.get("post_id")
|
||||
|
||||
|
||||
def _get_plugin_metadata(plugin_file: Path) -> Dict[str, str]:
|
||||
try:
|
||||
content = plugin_file.read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
return {}
|
||||
return _parse_frontmatter(content)
|
||||
|
||||
|
||||
def _find_readme_for_plugin(plugin_file: Path) -> Optional[str]:
|
||||
plugin_dir = plugin_file.parent
|
||||
is_cn = plugin_file.stem.endswith("_cn")
|
||||
readme_candidates = ["README_CN.md", "README.md"] if is_cn else ["README.md", "README_CN.md"]
|
||||
for name in readme_candidates:
|
||||
readme_path = plugin_dir / name
|
||||
if readme_path.exists():
|
||||
return readme_path.read_text(encoding="utf-8")
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
repo_root = _get_repo_root()
|
||||
_load_dotenv(repo_root)
|
||||
|
||||
api_key = os.environ.get("OPENWEBUI_API_KEY")
|
||||
if not api_key:
|
||||
print("OPENWEBUI_API_KEY is not set in environment.")
|
||||
return 1
|
||||
|
||||
client_module_path = repo_root / "scripts" / "openwebui_community_client.py"
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"openwebui_community_client", client_module_path
|
||||
)
|
||||
if not spec or not spec.loader:
|
||||
print("Failed to load openwebui_community_client module.")
|
||||
return 1
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
client = module.get_client(api_key)
|
||||
|
||||
staged_plugins = _get_staged_plugin_files(repo_root)
|
||||
staged_readmes = _get_staged_readmes(repo_root)
|
||||
if not staged_plugins and not staged_readmes:
|
||||
print("No staged README or plugin files found.")
|
||||
return 0
|
||||
|
||||
updated_post_ids: set[str] = set()
|
||||
|
||||
for plugin_file in staged_plugins:
|
||||
if not plugin_file.exists():
|
||||
print(f"Skipped (missing): {plugin_file}")
|
||||
continue
|
||||
|
||||
post_id = _get_post_id(plugin_file)
|
||||
if not post_id:
|
||||
print(f"Skipped (no openwebui_id): {plugin_file}")
|
||||
continue
|
||||
|
||||
try:
|
||||
post_data = client.get_post(post_id)
|
||||
if not post_data:
|
||||
print(f"Skipped (post not found): {plugin_file}")
|
||||
continue
|
||||
|
||||
source_code = plugin_file.read_text(encoding="utf-8")
|
||||
metadata = _get_plugin_metadata(plugin_file)
|
||||
readme_content = _find_readme_for_plugin(plugin_file)
|
||||
|
||||
ok = client.update_plugin(
|
||||
post_id=post_id,
|
||||
source_code=source_code,
|
||||
readme_content=readme_content or metadata.get("description", ""),
|
||||
metadata=metadata,
|
||||
media_urls=None,
|
||||
)
|
||||
if ok:
|
||||
updated_post_ids.add(post_id)
|
||||
print(f"Updated plugin -> {plugin_file} (post_id: {post_id})")
|
||||
except Exception as exc:
|
||||
print(f"Failed: {plugin_file} ({exc})")
|
||||
|
||||
for readme_path in staged_readmes:
|
||||
if not readme_path.exists():
|
||||
print(f"Skipped (missing): {readme_path}")
|
||||
continue
|
||||
|
||||
plugin_file = _find_plugin_file(readme_path)
|
||||
if not plugin_file:
|
||||
print(f"Skipped (no plugin file): {readme_path}")
|
||||
continue
|
||||
|
||||
post_id = _get_post_id(plugin_file)
|
||||
if not post_id:
|
||||
print(f"Skipped (no openwebui_id): {readme_path}")
|
||||
continue
|
||||
|
||||
try:
|
||||
if post_id in updated_post_ids:
|
||||
print(f"Skipped (already updated via plugin): {readme_path}")
|
||||
continue
|
||||
|
||||
post_data = client.get_post(post_id)
|
||||
if not post_data:
|
||||
print(f"Skipped (post not found): {readme_path}")
|
||||
continue
|
||||
|
||||
readme_content = readme_path.read_text(encoding="utf-8")
|
||||
|
||||
# Update README content only, keep other fields unchanged.
|
||||
post_data["content"] = readme_content
|
||||
|
||||
ok = client.update_post(post_id, post_data)
|
||||
if ok:
|
||||
print(f"Updated README -> {readme_path} (post_id: {post_id})")
|
||||
except Exception as exc:
|
||||
print(f"Failed: {readme_path} ({exc})")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -5,31 +5,10 @@
|
||||
This filter reduces token consumption in long conversations through intelligent summarization and message compression while keeping conversations coherent.
|
||||
|
||||
## What's new in 1.2.2
|
||||
|
||||
- **Critical Fix**: Resolved `TypeError: 'str' object is not callable` caused by variable name conflict in logging function.
|
||||
- **Compatibility**: Enhanced `params` handling to support Pydantic objects, improving compatibility with different OpenWebUI versions.
|
||||
|
||||
## What's new in 1.2.1
|
||||
|
||||
- **Smart Configuration**: Automatically detects base model settings for custom models and adds `summary_model_max_context` for independent summary limits.
|
||||
- **Performance & Refactoring**: Optimized threshold parsing with caching, removed redundant code, and improved LLM response handling (JSONResponse support).
|
||||
- **Bug Fixes & Modernization**: Fixed `datetime` deprecation warnings, corrected type annotations, and replaced print statements with proper logging.
|
||||
|
||||
## What's new in 1.2.0
|
||||
|
||||
- **Preflight Context Check**: Before sending to the model, validates that total tokens fit within the context window. Automatically trims or drops oldest messages if exceeded.
|
||||
- **Structure-Aware Assistant Trimming**: When context exceeds the limit, long AI responses are intelligently collapsed while preserving their structure (headers H1-H6, first line, last line).
|
||||
- **Native Tool Output Trimming**: Detects and trims native tool outputs (`function_calling: "native"`), extracting only the final answer. Enable via `enable_tool_output_trimming`. **Note**: Non-native tool outputs are not fully injected into context.
|
||||
- **Consolidated Status Notifications**: Unified "Context Usage" and "Context Summary Updated" notifications with appended warnings (e.g., `| ⚠️ High Usage`) for clearer feedback.
|
||||
- **Context Usage Warning**: Emits a warning notification when context usage exceeds 90%.
|
||||
- **Enhanced Header Detection**: Optimized regex (`^#{1,6}\s+`) to avoid false positives like `#hashtag`.
|
||||
- **Detailed Token Logging**: Logs now show token breakdown for System, Head, Summary, and Tail sections with total.
|
||||
|
||||
## What's new in 1.1.3
|
||||
- **Improved Compatibility**: Changed summary injection role from `user` to `assistant` for better compatibility across different LLMs.
|
||||
- **Enhanced Stability**: Fixed a race condition in state management that could cause "inlet state not found" warnings in high-concurrency scenarios.
|
||||
- **Bug Fixes**: Corrected default model handling to prevent misleading logs when no model is specified.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Core Features
|
||||
@@ -57,11 +36,7 @@ This filter reduces token consumption in long conversations through intelligent
|
||||
|
||||
### 2) Filter order
|
||||
|
||||
It is recommended to keep this filter early in the chain so it runs before filters that mutate messages:
|
||||
|
||||
1. Pre-filters (priority < 10) — e.g., system prompt injectors.
|
||||
2. This compression filter (priority = 10).
|
||||
3. Post-filters (priority > 10) — e.g., output formatting.
|
||||
- Recommended order: pre-filters (<10) → this filter (10) → post-filters (>10).
|
||||
|
||||
---
|
||||
|
||||
@@ -85,6 +60,16 @@ It is recommended to keep this filter early in the chain so it runs before filte
|
||||
|
||||
---
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Initial system prompt is lost**: Keep `keep_first` greater than 0 to protect the initial message.
|
||||
- **Compression effect is weak**: Raise `compression_threshold_tokens` or lower `keep_first` / `keep_last` to allow more aggressive compression.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -7,31 +7,10 @@
|
||||
本过滤器通过智能摘要和消息压缩技术,在保持对话连贯性的同时,显著降低长对话的 Token 消耗。
|
||||
|
||||
## 1.2.2 版本更新
|
||||
|
||||
- **严重错误修复**: 解决了因日志函数变量名冲突导致的 `TypeError: 'str' object is not callable` 错误。
|
||||
- **兼容性增强**: 改进了 `params` 处理逻辑以支持 Pydantic 对象,提高了对不同 OpenWebUI 版本的兼容性。
|
||||
|
||||
## 1.2.1 版本更新
|
||||
|
||||
- **智能配置增强**: 自动检测自定义模型的基础模型配置,并新增 `summary_model_max_context` 参数以独立控制摘要模型的上下文限制。
|
||||
- **性能优化与重构**: 重构了阈值解析逻辑并增加缓存,移除了冗余的处理代码,并增强了 LLM 响应处理(支持 JSONResponse)。
|
||||
- **稳定性改进**: 修复了 `datetime` 弃用警告,修正了类型注解,并将 print 语句替换为标准日志记录。
|
||||
|
||||
## 1.2.0 版本更新
|
||||
|
||||
- **预检上下文检查 (Preflight Context Check)**: 在发送给模型之前,验证总 Token 是否符合上下文窗口。如果超出,自动裁剪或丢弃最旧的消息。
|
||||
- **结构感知助手裁剪 (Structure-Aware Assistant Trimming)**: 当上下文超出限制时,智能折叠过长的 AI 回复,同时保留其结构(标题 H1-H6、首行、尾行)。
|
||||
- **原生工具输出裁剪 (Native Tool Output Trimming)**: 检测并裁剪原生工具输出 (`function_calling: "native"`),仅提取最终答案。通过 `enable_tool_output_trimming` 启用。**注意**:非原生工具调用输出不会完整注入上下文。
|
||||
- **统一状态通知**: 统一了“上下文使用情况”和“上下文摘要更新”的通知,并附加警告(例如 `| ⚠️ 高负载`),反馈更清晰。
|
||||
- **上下文使用警告**: 当上下文使用率超过 90% 时发出警告通知。
|
||||
- **增强的标题检测**: 优化了正则表达式 (`^#{1,6}\s+`) 以避免误判(如 `#hashtag`)。
|
||||
- **详细 Token 日志**: 日志现在显示 System、Head、Summary 和 Tail 部分的 Token 细分及总计。
|
||||
|
||||
## 1.1.3 版本更新
|
||||
- **兼容性提升**: 将摘要注入角色从 `user` 改为 `assistant`,以提高在不同 LLM 之间的兼容性。
|
||||
- **稳定性增强**: 修复了状态管理中的竞态条件,解决了高并发场景下可能出现的“无法获取 inlet 状态”警告。
|
||||
- **Bug 修复**: 修正了默认模型处理逻辑,防止在未指定模型时产生误导性日志。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 核心特性
|
||||
@@ -61,11 +40,7 @@
|
||||
|
||||
### 2. 过滤器顺序
|
||||
|
||||
建议将此过滤器的优先级设置得相对较高(数值较小),以确保它在其他可能修改消息内容的过滤器之前运行。一个典型的顺序可能是:
|
||||
|
||||
1. 前置过滤器 (priority < 10) —— 例如系统提示注入。
|
||||
2. 本压缩过滤器 (priority = 10)。
|
||||
3. 后置过滤器 (priority > 10) —— 例如最终输出格式化。
|
||||
- 建议顺序:前置过滤器(<10)→ 本过滤器(10)→ 后置过滤器(>10)。
|
||||
|
||||
---
|
||||
|
||||
@@ -124,6 +99,16 @@
|
||||
|
||||
---
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
- **初始系统提示丢失**:将 `keep_first` 设置为大于 0。
|
||||
- **压缩效果不明显**:提高 `compression_threshold_tokens`,或降低 `keep_first` / `keep_last` 以增强压缩力度。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -2,35 +2,30 @@
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.1.0 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
---
|
||||
**Folder Memory** is an intelligent context filter plugin for OpenWebUI. It automatically extracts consistent "Project Rules" from ongoing conversations within a folder and injects them back into the folder's system prompt.
|
||||
|
||||
## 🔥 What's New in v0.1.0
|
||||
|
||||
### 📌 What's new in 0.1.0
|
||||
- **Initial Release**: Automated "Project Rules" management for OpenWebUI folders.
|
||||
- **Folder-Level Persistence**: Automatically updates folder system prompts with extracted rules.
|
||||
- **Optimized Performance**: Runs asynchronously and supports `PRIORITY` configuration for seamless integration with other filters.
|
||||
|
||||
---
|
||||
|
||||
**Folder Memory** is an intelligent context filter plugin for OpenWebUI. It automatically extracts consistent "Project Rules" from ongoing conversations within a folder and injects them back into the folder's system prompt.
|
||||
|
||||
## ✨ Features
|
||||
## ✨ Core Features
|
||||
|
||||
- **Automatic Extraction**: Analyzes chat history every N messages to extract project rules.
|
||||
- **Non-destructive Injection**: Updates only the specific "Project Rules" block in the system prompt, preserving other instructions.
|
||||
- **Async Processing**: Runs in the background without blocking the user's chat experience.
|
||||
- **ORM Integration**: Directly updates folder data using OpenWebUI's internal models for reliability.
|
||||
|
||||
## ⚠️ Prerequisites
|
||||
## Installation & Configuration
|
||||
|
||||
- **Conversations must occur inside a folder.** This plugin only triggers when a chat belongs to a folder (i.e., you need to create a folder in OpenWebUI and start a conversation within it).
|
||||
|
||||
## 📦 Installation
|
||||
### 1) Installation
|
||||
|
||||
1. Copy `folder_memory.py` to your OpenWebUI `plugins/filters/` directory (or upload via Admin UI).
|
||||
2. Enable the filter in your **Settings** -> **Filters**.
|
||||
3. (Optional) Configure the triggering threshold (default: every 10 messages).
|
||||
3. **Prerequisite**: Conversations must occur inside a folder (create a folder and start a chat within it).
|
||||
|
||||
## ⚙️ Configuration (Valves)
|
||||
### 2) Configuration (Valves)
|
||||
|
||||
| Valve | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
@@ -41,6 +36,10 @@
|
||||
| `SHOW_DEBUG_LOG` | `False` | Show detailed debug logs in the browser console. |
|
||||
| `UPDATE_ROOT_FOLDER` | `False` | If enabled, finds and updates the root folder rules instead of the current subfolder. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🛠️ How It Works
|
||||
|
||||

|
||||
@@ -58,3 +57,7 @@
|
||||
## 🗺️ Roadmap
|
||||
|
||||
See [ROADMAP.md](./ROADMAP.md) for future plans, including "Project Knowledge" collection.
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -2,37 +2,32 @@
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.1.0 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
---
|
||||
|
||||
### 📌 0.1.0 版本特性
|
||||
- **首个版本发布**:专注于自动化的“项目规则”管理。
|
||||
- **文件夹级持久化**:自动将提取的规则回写到文件夹系统提示词中。
|
||||
- **性能优化**:采用异步处理机制,并支持 `PRIORITY` 配置,确保与其他过滤器(如上下文压缩)完美协作。
|
||||
|
||||
---
|
||||
|
||||
**文件夹记忆 (Folder Memory)** 是一个 OpenWebUI 的智能上下文过滤器插件。它能自动从文件夹内的对话中提取一致性的“项目规则”,并将其回写到文件夹的系统提示词中。
|
||||
|
||||
这确保了该文件夹内的所有未来对话都能共享相同的进化上下文和规则,无需手动更新。
|
||||
|
||||
## ✨ 功能特性
|
||||
## 🔥 最新更新 v0.1.0
|
||||
|
||||
- **首个版本发布**:专注于自动化的“项目规则”管理。
|
||||
- **文件夹级持久化**:自动将提取的规则回写到文件夹系统提示词中。
|
||||
- **性能优化**:采用异步处理机制,并支持 `PRIORITY` 配置,确保与其他过滤器(如上下文压缩)完美协作。
|
||||
|
||||
## ✨ 核心特性
|
||||
|
||||
- **自动提取**:每隔 N 条消息分析一次聊天记录,提取项目规则。
|
||||
- **无损注入**:仅更新系统提示词中的特定“项目规则”块,保留其他指令。
|
||||
- **异步处理**:在后台运行,不阻塞用户的聊天体验。
|
||||
- **ORM 集成**:直接使用 OpenWebUI 的内部模型更新文件夹数据,确保可靠性。
|
||||
|
||||
## ⚠️ 前置条件
|
||||
## 安装与配置
|
||||
|
||||
- **对话必须在文件夹内进行。** 此插件仅在聊天属于某个文件夹时触发(即您需要先在 OpenWebUI 中创建一个文件夹,并在其内部开始对话)。
|
||||
### 1. 安装
|
||||
|
||||
## 📦 安装指南
|
||||
|
||||
1. 将 `folder_memory.py` (或中文版 `folder_memory_cn.py`) 复制到 OpenWebUI 的 `plugins/filters/` 目录(或通过管理员 UI 上传)。
|
||||
1. 将 `folder_memory.py`(或中文版 `folder_memory_cn.py`)复制到 OpenWebUI 的 `plugins/filters/` 目录(或通过管理员 UI 上传)。
|
||||
2. 在 **设置** -> **过滤器** 中启用该插件。
|
||||
3. (可选)配置触发阈值(默认:每 10 条消息)。
|
||||
3. **前置条件**:对话必须在文件夹内进行(先创建文件夹并在其中开始对话)。
|
||||
|
||||
## ⚙️ 配置 (Valves)
|
||||
### 2. 配置 (Valves)
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
@@ -43,6 +38,10 @@
|
||||
| `SHOW_DEBUG_LOG` | `False` | 在浏览器控制台显示详细调试日志。 |
|
||||
| `UPDATE_ROOT_FOLDER` | `False` | 如果启用,将向上查找并更新根文件夹的规则,而不是当前子文件夹。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 🛠️ 工作原理
|
||||
|
||||

|
||||
@@ -60,3 +59,7 @@
|
||||
## 🗺️ 路线图
|
||||
|
||||
查看 [ROADMAP.md](./ROADMAP.md) 了解未来计划,包括“项目知识”收集功能。
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
A content normalizer filter for Open WebUI that fixes common Markdown formatting issues in LLM outputs. It ensures that code blocks, LaTeX formulas, Mermaid diagrams, and other Markdown elements are rendered correctly.
|
||||
|
||||
## Features
|
||||
## 🔥 What's New in v1.2.4
|
||||
|
||||
* **Documentation Sync**: Synchronized version numbers across all documentation and code files.
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
* **Details Tag Normalization**: Ensures proper spacing for `<details>` tags (used for thought chains). Adds a blank line after `</details>` and ensures a newline after self-closing `<details />` tags to prevent rendering issues.
|
||||
* **Emphasis Spacing Fix**: Fixes extra spaces inside emphasis markers (e.g., `** text **` -> `**text**`) which can cause rendering failures. Includes safeguards to protect math expressions (e.g., `2 * 3 * 4`) and list variables.
|
||||
@@ -19,7 +23,7 @@ A content normalizer filter for Open WebUI that fixes common Markdown formatting
|
||||
* **Table Fix**: Adds missing closing pipes in tables.
|
||||
* **XML Cleanup**: Removes leftover XML artifacts.
|
||||
|
||||
## Usage
|
||||
## How to Use 🛠️
|
||||
|
||||
1. Install the plugin in Open WebUI.
|
||||
2. Enable the filter globally or for specific models.
|
||||
@@ -28,69 +32,38 @@ A content normalizer filter for Open WebUI that fixes common Markdown formatting
|
||||
> [!WARNING]
|
||||
> As this is an initial version, some "negative fixes" might occur (e.g., breaking valid Markdown). If you encounter issues, please check the console logs, copy the "Original" vs "Normalized" content, and submit an issue.
|
||||
|
||||
## Configuration (Valves)
|
||||
## Configuration (Valves) ⚙️
|
||||
|
||||
* `priority`: Filter priority (default: 50).
|
||||
* `enable_escape_fix`: Fix excessive escape characters.
|
||||
* `enable_thought_tag_fix`: Normalize thought tags.
|
||||
* `enable_details_tag_fix`: Normalize details tags (default: True).
|
||||
* `enable_code_block_fix`: Fix code block formatting.
|
||||
* `enable_latex_fix`: Normalize LaTeX formulas.
|
||||
* `enable_list_fix`: Fix list item newlines (Experimental).
|
||||
* `enable_unclosed_block_fix`: Auto-close unclosed code blocks.
|
||||
* `enable_fullwidth_symbol_fix`: Fix full-width symbols in code blocks.
|
||||
* `enable_mermaid_fix`: Fix Mermaid syntax errors.
|
||||
* `enable_heading_fix`: Fix missing space in headings.
|
||||
* `enable_table_fix`: Fix missing closing pipe in tables.
|
||||
* `enable_xml_tag_cleanup`: Cleanup leftover XML tags.
|
||||
* `enable_emphasis_spacing_fix`: Fix extra spaces in emphasis (default: False).
|
||||
* `show_status`: Show status notification when fixes are applied.
|
||||
* `show_debug_log`: Print debug logs to browser console.
|
||||
| Parameter | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | Filter priority. Higher runs later (recommended after other filters). |
|
||||
| `enable_escape_fix` | `True` | Fix excessive escape characters (`\n`, `\t`, etc.). |
|
||||
| `enable_escape_fix_in_code_blocks` | `False` | Apply escape fix inside code blocks (may affect valid code). |
|
||||
| `enable_thought_tag_fix` | `True` | Normalize thought tags (`</thought>`). |
|
||||
| `enable_details_tag_fix` | `True` | Normalize `<details>` tags and add safe spacing. |
|
||||
| `enable_code_block_fix` | `True` | Fix code block formatting (indentation/newlines). |
|
||||
| `enable_latex_fix` | `True` | Normalize LaTeX delimiters (`\[` -> `$$`, `\(` -> `$`). |
|
||||
| `enable_list_fix` | `False` | Fix list item newlines (experimental). |
|
||||
| `enable_unclosed_block_fix` | `True` | Auto-close unclosed code blocks. |
|
||||
| `enable_fullwidth_symbol_fix` | `False` | Fix full-width symbols in code blocks. |
|
||||
| `enable_mermaid_fix` | `True` | Fix common Mermaid syntax errors. |
|
||||
| `enable_heading_fix` | `True` | Fix missing space in headings. |
|
||||
| `enable_table_fix` | `True` | Fix missing closing pipe in tables. |
|
||||
| `enable_xml_tag_cleanup` | `True` | Cleanup leftover XML tags. |
|
||||
| `enable_emphasis_spacing_fix` | `False` | Fix extra spaces in emphasis. |
|
||||
| `show_status` | `True` | Show status notification when fixes are applied. |
|
||||
| `show_debug_log` | `True` | Print debug logs to browser console (F12). |
|
||||
|
||||
## Troubleshooting ❓
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🧩 Others
|
||||
|
||||
### Troubleshooting ❓
|
||||
|
||||
* **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## Changelog
|
||||
### Changelog
|
||||
|
||||
### v1.2.4
|
||||
|
||||
* **Documentation Updates**: Synchronized version numbers across all documentation and code files.
|
||||
|
||||
### v1.2.3
|
||||
|
||||
* **List Marker Protection Enhancement**: Fixed a bug where list markers (`*`) followed by plain text and emphasis were having their spaces incorrectly stripped (e.g., `* U16 forward` became `*U16 forward`).
|
||||
* **Placeholder Support**: Confirmed that 4 or more underscores (e.g., `____`) are correctly treated as placeholders and not modified by the emphasis fix.
|
||||
|
||||
### v1.2.2
|
||||
|
||||
* **Code Block Indentation Fix**: Fixed an issue where code blocks nested inside lists were having their indentation incorrectly stripped. Now preserves proper indentation for nested code blocks.
|
||||
* **Underscore Emphasis Support**: Extended emphasis spacing fix to support `__` (double underscore for bold) and `___` (triple underscore for bold+italic) syntax.
|
||||
* **List Marker Protection**: Fixed a bug where list markers (`*`) followed by emphasis markers (`**`) were incorrectly merged (e.g., `* **Yes**` became `***Yes**`). Added safeguard to prevent this.
|
||||
* **Test Suite**: Added comprehensive pytest test suite with 56 test cases covering all major features.
|
||||
|
||||
### v1.2.1
|
||||
|
||||
* **Emphasis Spacing Fix**: Added a new fix for extra spaces inside emphasis markers (e.g., `** text **` -> `**text**`).
|
||||
* Uses a recursive approach to handle nested emphasis (e.g., `**bold _italic _**`).
|
||||
* Includes safeguards to prevent modifying math expressions (e.g., `2 * 3 * 4`) or list variables.
|
||||
* Controlled by the `enable_emphasis_spacing_fix` valve (default: True).
|
||||
|
||||
### v1.2.0
|
||||
|
||||
* **Details Tag Support**: Added normalization for `<details>` tags.
|
||||
* Ensures a blank line is added after `</details>` closing tags to separate thought content from the main response.
|
||||
* Ensures a newline is added after self-closing `<details ... />` tags to prevent them from interfering with subsequent Markdown headings (e.g., fixing `<details/>#Heading`).
|
||||
* Includes safeguard to prevent modification of `<details>` tags inside code blocks.
|
||||
|
||||
### v1.1.2
|
||||
|
||||
* **Mermaid Edge Label Protection**: Implemented comprehensive protection for edge labels (text on connecting lines) to prevent them from being incorrectly modified. Now supports all Mermaid link types including solid (`--`), dotted (`-.`), and thick (`==`) lines with or without arrows.
|
||||
* **Bug Fixes**: Fixed an issue where lines without arrows (e.g., `A -- text --- B`) were not correctly protected.
|
||||
|
||||
### v1.1.0
|
||||
|
||||
* **Mermaid Fix Refinement**: Improved regex to handle nested parentheses in node labels (e.g., `ID("Label (text)")`) and avoided matching connection labels.
|
||||
* **HTML Safeguard Optimization**: Refined `_contains_html` to allow common tags like `<br/>`, `<b>`, `<i>`, etc., ensuring Mermaid diagrams with these tags are still normalized.
|
||||
* **Full-width Symbol Cleanup**: Fixed duplicate keys and incorrect quote mapping in `FULLWIDTH_MAP`.
|
||||
* **Bug Fixes**: Fixed missing `Dict` import in Python files.
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
这是一个用于 Open WebUI 的内容格式化过滤器,旨在修复 LLM 输出中常见的 Markdown 格式问题。它能确保代码块、LaTeX 公式、Mermaid 图表和其他 Markdown 元素被正确渲染。
|
||||
|
||||
## 功能特性
|
||||
## 🔥 最新更新 v1.2.4
|
||||
|
||||
* **文档更新**: 同步了所有文档和代码文件的版本号。
|
||||
|
||||
## ✨ 核心特性
|
||||
|
||||
* **Details 标签规范化**: 确保 `<details>` 标签(常用于思维链)有正确的间距。在 `</details>` 后添加空行,并在自闭合 `<details />` 标签后添加换行,防止渲染问题。
|
||||
* **强调空格修复**: 修复强调标记内部的多余空格(例如 `** 文本 **` -> `**文本**`),这会导致 Markdown 渲染失败。包含保护机制,防止误修改数学表达式(如 `2 * 3 * 4`)或列表变量。
|
||||
@@ -28,69 +32,38 @@
|
||||
> [!WARNING]
|
||||
> 由于这是初版,可能会出现“负向修复”的情况(例如破坏了原本正确的格式)。如果您遇到问题,请务必查看控制台日志,复制“原始 (Original)”与“规范化 (Normalized)”的内容对比,并提交 Issue 反馈。
|
||||
|
||||
## 配置项 (Valves)
|
||||
## 配置参数 (Valves) ⚙️
|
||||
|
||||
* `priority`: 过滤器优先级 (默认: 50)。
|
||||
* `enable_escape_fix`: 修复过度的转义字符。
|
||||
* `enable_thought_tag_fix`: 规范化思维标签。
|
||||
* `enable_details_tag_fix`: 规范化 Details 标签 (默认: True)。
|
||||
* `enable_code_block_fix`: 修复代码块格式。
|
||||
* `enable_latex_fix`: 规范化 LaTeX 公式。
|
||||
* `enable_list_fix`: 修复列表项换行 (实验性)。
|
||||
* `enable_unclosed_block_fix`: 自动闭合未闭合的代码块。
|
||||
* `enable_fullwidth_symbol_fix`: 修复代码块中的全角符号。
|
||||
* `enable_mermaid_fix`: 修复 Mermaid 语法错误。
|
||||
* `enable_heading_fix`: 修复标题中缺失的空格。
|
||||
* `enable_table_fix`: 修复表格中缺失的闭合管道符。
|
||||
* `enable_xml_tag_cleanup`: 清理残留的 XML 标签。
|
||||
* `enable_emphasis_spacing_fix`: 修复强调语法中的多余空格 (默认: True)。
|
||||
* `show_status`: 应用修复时显示状态通知。
|
||||
* `show_debug_log`: 在浏览器控制台打印调试日志。
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | 过滤器优先级。数值越大越靠后(建议在其他过滤器之后运行)。 |
|
||||
| `enable_escape_fix` | `True` | 修复过度的转义字符(`\n`, `\t` 等)。 |
|
||||
| `enable_escape_fix_in_code_blocks` | `False` | 在代码块内应用转义修复(可能影响有效代码)。 |
|
||||
| `enable_thought_tag_fix` | `True` | 规范化思维标签(`</thought>`)。 |
|
||||
| `enable_details_tag_fix` | `True` | 规范化 `<details>` 标签并添加安全间距。 |
|
||||
| `enable_code_block_fix` | `True` | 修复代码块格式(缩进/换行)。 |
|
||||
| `enable_latex_fix` | `True` | 规范化 LaTeX 定界符(`\[` -> `$$`, `\(` -> `$`)。 |
|
||||
| `enable_list_fix` | `False` | 修复列表项换行(实验性)。 |
|
||||
| `enable_unclosed_block_fix` | `True` | 自动闭合未闭合的代码块。 |
|
||||
| `enable_fullwidth_symbol_fix` | `False` | 修复代码块中的全角符号。 |
|
||||
| `enable_mermaid_fix` | `True` | 修复常见 Mermaid 语法错误。 |
|
||||
| `enable_heading_fix` | `True` | 修复标题中缺失的空格。 |
|
||||
| `enable_table_fix` | `True` | 修复表格中缺失的闭合管道符。 |
|
||||
| `enable_xml_tag_cleanup` | `True` | 清理残留的 XML 标签。 |
|
||||
| `enable_emphasis_spacing_fix` | `False` | 修复强调语法中的多余空格。 |
|
||||
| `show_status` | `True` | 应用修复时显示状态通知。 |
|
||||
| `show_debug_log` | `True` | 在浏览器控制台打印调试日志。 |
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 其他
|
||||
|
||||
### 故障排除 (Troubleshooting) ❓
|
||||
|
||||
* **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[Awesome OpenWebUI Issues](https://github.com/Fu-Jie/awesome-openwebui/issues)
|
||||
|
||||
## 更新日志
|
||||
### 更新日志
|
||||
|
||||
### v1.2.4
|
||||
|
||||
* **文档更新**: 同步了所有文档和代码文件的版本号。
|
||||
|
||||
### v1.2.3
|
||||
|
||||
* **列表标记保护增强**: 修复了列表标记 (`*`) 后跟普通文本和强调标记时,空格被错误剥离的问题(例如 `* U16 前锋` 变成 `*U16 前锋`)。
|
||||
* **占位符支持**: 确认 4 个或更多下划线(如 `____`)会被正确视为占位符,不会被强调修复逻辑修改。
|
||||
|
||||
### v1.2.2
|
||||
|
||||
* **代码块缩进修复**: 修复了列表中嵌套代码块的缩进被错误剥离的问题。现在会正确保留嵌套代码块的缩进。
|
||||
* **下划线强调语法支持**: 扩展强调空格修复以支持 `__` (双下划线加粗) 和 `___` (三下划线加粗斜体) 语法。
|
||||
* **列表标记保护**: 修复了列表标记 (`*`) 后跟强调标记 (`**`) 被错误合并的 Bug(例如 `* **是**` 变成 `***是**`)。添加了保护逻辑防止此问题。
|
||||
* **测试套件**: 新增完整的 pytest 测试套件,包含 56 个测试用例,覆盖所有主要功能。
|
||||
|
||||
### v1.2.1
|
||||
|
||||
* **强调空格修复**: 新增了对强调标记内部多余空格的修复(例如 `** 文本 **` -> `**文本**`)。
|
||||
* 采用递归方法处理嵌套强调(例如 `**加粗 _斜体 _**`)。
|
||||
* 包含保护机制,防止误修改数学表达式(如 `2 * 3 * 4`)或列表变量。
|
||||
* 通过 `enable_emphasis_spacing_fix` 开关控制(默认:开启)。
|
||||
|
||||
### v1.2.0
|
||||
|
||||
* **Details 标签支持**: 新增了对 `<details>` 标签的规范化支持。
|
||||
* 确保在 `</details>` 闭合标签后添加空行,将思维内容与正文分隔开。
|
||||
* 确保在自闭合 `<details ... />` 标签后添加换行,防止其干扰后续的 Markdown 标题(例如修复 `<details/>#标题`)。
|
||||
* 包含保护机制,防止修改代码块内部的 `<details>` 标签。
|
||||
|
||||
### v1.1.2
|
||||
|
||||
* **Mermaid 连线标签保护**: 实现了全面的连线标签保护机制,防止连接线上的文字被误修改。现在支持所有 Mermaid 连线类型,包括实线 (`--`)、虚线 (`-.`) 和粗线 (`==`),无论是否带有箭头。
|
||||
* **Bug 修复**: 修复了无箭头连线(如 `A -- text --- B`)未被正确保护的问题。
|
||||
|
||||
### v1.1.0
|
||||
|
||||
* **Mermaid 修复优化**: 改进了正则表达式以处理节点标签中的嵌套括号(如 `ID("标签 (文本)")`),并避免误匹配连接线上的文字。
|
||||
* **HTML 保护机制优化**: 优化了 `_contains_html` 检测,允许 `<br/>`, `<b>`, `<i>` 等常见标签,确保包含这些标签的 Mermaid 图表能被正常规范化。
|
||||
* **全角符号清理**: 修复了 `FULLWIDTH_MAP` 中的重复键名和错误的引号映射。
|
||||
* **Bug 修复**: 修复了 Python 文件中缺失的 `Dict` 类型导入。
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
# GitHub Copilot SDK Pipe for OpenWebUI
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.2.3 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.3.0 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
|
||||
|
||||
This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/open-webui) that allows you to use GitHub Copilot models (such as `gpt-5`, `gpt-5-mini`, `claude-sonnet-4.5`) directly within OpenWebUI. It is built upon the official [GitHub Copilot SDK for Python](https://github.com/github/copilot-sdk), providing a native integration experience.
|
||||
|
||||
## 🚀 What's New (v0.2.3)
|
||||
## 🚀 What's New (v0.3.0) - The Power of "Unified Ecosystem"
|
||||
|
||||
* **🧩 Per-user Overrides**: Added user-level overrides for `REASONING_EFFORT`, `CLI_PATH`, `DEBUG`, `SHOW_THINKING`, and `MODEL_ID`.
|
||||
* **🧠 Thinking Output Reliability**: Thinking visibility now respects the user setting and is correctly passed into streaming.
|
||||
* **📝 Formatting Enforcement**: Added automatic formatting hints to ensure outputs are well-structured (paragraphs, lists) and addressed "tight output" issues.
|
||||
* **🔌 Zero-Config Tool Bridge**: Automatically transforms your existing OpenWebUI Functions (Tools) into Copilot-compatible tools. **Copilot now has total access to your entire WebUI toolset!**
|
||||
* **🔗 Dynamic MCP Discovery**: Seamlessly connects to MCP servers defined in **Admin Settings -> Connections**. No configuration files required—it just works.
|
||||
* **⚡ High-Performance Async Engine**: Background CLI updates and optimized event-driven streaming ensure lightning-fast responses without UI lag.
|
||||
* **🛡️ Robust Interoperability**: Advanced sanitization and dynamic Pydantic model generation ensure smooth integration even with complex third-party tools.
|
||||
|
||||
## ✨ Core Features
|
||||
## ✨ Key Capabilities
|
||||
|
||||
* **🚀 Official SDK Integration**: Built on the official SDK for stability and reliability.
|
||||
* **🛠️ Custom Tools Support**: Example tools included (random number). Easy to extend with your own tools.
|
||||
* **💬 Multi-turn Conversation**: Automatically concatenates history context so Copilot understands your previous messages.
|
||||
* **🌊 Streaming Output**: Supports typewriter effect for fast responses.
|
||||
* **🖼️ Multimodal Support**: Supports image uploads, automatically converting them to attachments for Copilot (requires model support).
|
||||
* **🛠️ Zero-config Installation**: Automatically detects and downloads the GitHub Copilot CLI, ready to use out of the box.
|
||||
* **🔑 Secure Authentication**: Supports Fine-grained Personal Access Tokens for minimized permissions.
|
||||
* **🐛 Debug Mode**: Built-in detailed log output (browser console) for easy troubleshooting.
|
||||
* **⚠️ Single Node Only**: Due to local session storage, this plugin currently supports single-node OpenWebUI deployment or multi-node with sticky sessions enabled.
|
||||
* **🌉 The Ultimate Bridge**: The first and only plugin that creates a seamless bridge between **OpenWebUI Tools** and **GitHub Copilot SDK**.
|
||||
* **🚀 Official & Native**: Built directly on the official Python SDK, providing the most stable and authentic Copilot experience.
|
||||
* **🌊 Advanced Streaming (Thought Process)**: Supports full model reasoning/thinking display with typewriter effects.
|
||||
* **🖼️ Intelligent Multimodal**: Full support for images and attachments, enabling Copilot to "see" your workspace.
|
||||
* **🛠️ Effortless Setup**: Automatic CLI detection, version enforcement, and dependency management.
|
||||
* **🔑 Dual-Layer Security**: Supports secure OAuth flow for Chat and standard PAT for extended MCP capabilities.
|
||||
|
||||
## 📦 Installation & Usage
|
||||
## Installation & Configuration
|
||||
|
||||
### 1. Import Function
|
||||
### 1) Import Function
|
||||
|
||||
1. Open OpenWebUI.
|
||||
2. Go to **Workspace** -> **Functions**.
|
||||
@@ -32,19 +30,17 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
|
||||
4. Paste the content of `github_copilot_sdk.py` (or `github_copilot_sdk_cn.py` for Chinese) completely.
|
||||
5. Save.
|
||||
|
||||
### 2. Configure Valves (Settings)
|
||||
### 2) Configure Valves (Settings)
|
||||
|
||||
Find "GitHub Copilot" in the function list and click the **⚙️ (Valves)** icon to configure:
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | **(Required)** Your GitHub Token. | - |
|
||||
| **MODEL_ID** | The model name to use. | `gpt-5-mini` |
|
||||
| **CLI_PATH** | Path to the Copilot CLI. Will download automatically if not found. | `/usr/local/bin/copilot` |
|
||||
| **GH_TOKEN** | **(Required)** GitHub Access Token (PAT or OAuth Token). Access to Chat. | - |
|
||||
| **DEBUG** | Whether to enable debug logs (output to browser console). | `False` |
|
||||
| **LOG_LEVEL** | Copilot CLI log level: none, error, warning, info, debug, all. | `error` |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process (requires streaming + model support). | `True` |
|
||||
| **SHOW_WORKSPACE_INFO** | Show session workspace path and summary in debug mode. | `True` |
|
||||
| **COPILOT_CLI_VERSION** | Specific Copilot CLI version to install/enforce. | `0.0.405` |
|
||||
| **EXCLUDE_KEYWORDS** | Exclude models containing these keywords (comma separated). | - |
|
||||
| **WORKSPACE_DIR** | Restricted workspace directory for file operations. | - |
|
||||
| **INFINITE_SESSION** | Enable Infinite Sessions (automatic context compaction). | `True` |
|
||||
@@ -52,10 +48,10 @@ Find "GitHub Copilot" in the function list and click the **⚙️ (Valves)** ico
|
||||
| **BUFFER_THRESHOLD** | Buffer exhaustion threshold (0.0-1.0). | `0.95` |
|
||||
| **TIMEOUT** | Timeout for each stream chunk (seconds). | `300` |
|
||||
| **CUSTOM_ENV_VARS** | Custom environment variables (JSON format). | - |
|
||||
| **REASONING_EFFORT** | Reasoning effort level: low, medium, high. `xhigh` is supported for gpt-5.2-codex. | `medium` |
|
||||
| **REASONING_EFFORT** | Reasoning effort level: low, medium, high. `xhigh` is supported for some models. | `medium` |
|
||||
| **ENFORCE_FORMATTING** | Add formatting instructions to system prompt for better readability. | `True` |
|
||||
| **ENABLE_TOOLS** | Enable custom tools (example: random number). | `False` |
|
||||
| **AVAILABLE_TOOLS** | Available tools: 'all' or comma-separated list. | `all` |
|
||||
| **ENABLE_MCP_SERVER** | Enable Direct MCP Client connection (Recommended). | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | Enable OpenWebUI Tools (includes defined and server tools). | `True` |
|
||||
|
||||
#### User Valves (per-user overrides)
|
||||
|
||||
@@ -63,35 +59,30 @@ These optional settings can be set per user (overrides global Valves):
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | Personal GitHub Token (overrides global setting). | - |
|
||||
| **REASONING_EFFORT** | Reasoning effort level (low/medium/high/xhigh). | - |
|
||||
| **CLI_PATH** | Custom path to Copilot CLI. | - |
|
||||
| **DEBUG** | Enable technical debug logs. | `False` |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process (requires streaming + model support). | `True` |
|
||||
| **MODEL_ID** | Custom model ID. | - |
|
||||
| **SHOW_THINKING** | Show model reasoning/thinking process. | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | Enable OpenWebUI Tools (overrides global). | `True` |
|
||||
| **ENABLE_MCP_SERVER** | Enable MCP server loading (overrides global). | `True` |
|
||||
| **ENFORCE_FORMATTING** | Enforce formatting guidelines (overrides global). | `True` |
|
||||
|
||||
### 3. Using Custom Tools (🆕 Optional)
|
||||
## ⭐ Support
|
||||
|
||||
This pipe includes **1 example tool** to demonstrate tool calling:
|
||||
If this plugin has been useful, a star on [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) is a big motivation for me. Thank you for the support.
|
||||
|
||||
* **🎲 generate_random_number**: Generate random integers
|
||||
### Get Token
|
||||
|
||||
**To enable:**
|
||||
To use GitHub Copilot, you need a GitHub Personal Access Token (PAT) with appropriate permissions.
|
||||
|
||||
1. Set `ENABLE_TOOLS: true` in Valves
|
||||
2. Try: "Give me a random number"
|
||||
|
||||
**📚 For detailed usage and creating your own tools, see [TOOLS_USAGE.md](TOOLS_USAGE.md)**
|
||||
|
||||
### 4. Get GH_TOKEN
|
||||
|
||||
For security, it is recommended to use a **Fine-grained Personal Access Token**:
|
||||
**Steps to generate your token:**
|
||||
|
||||
1. Visit [GitHub Token Settings](https://github.com/settings/tokens?type=beta).
|
||||
2. Click **Generate new token**.
|
||||
3. **Repository access**: Select **Public repositories** (Required to access Copilot permissions).
|
||||
2. Click **Generate new token (fine-grained)**.
|
||||
3. **Repository access**: Select **Public Repositories** (simplest) or **All repositories**.
|
||||
4. **Permissions**:
|
||||
* Click **Account permissions**.
|
||||
* Find **Copilot Requests** (It defaults to **Read-only**, no selection needed).
|
||||
* If you chose **All repositories**, you must click **Account permissions**.
|
||||
* Find **Copilot Requests**, and select **Access**.
|
||||
5. Generate and copy the Token.
|
||||
|
||||
## 📋 Dependencies
|
||||
@@ -101,14 +92,13 @@ This Pipe will automatically attempt to install the following dependencies:
|
||||
* `github-copilot-sdk` (Python package)
|
||||
* `github-copilot-cli` (Binary file, installed via official script)
|
||||
|
||||
## ⚠️ FAQ
|
||||
## Troubleshooting ❓
|
||||
|
||||
* **Stuck on "Waiting..."**:
|
||||
* Check if `GH_TOKEN` is correct and has `Copilot Requests` permission.
|
||||
* **Images not recognized**:
|
||||
* Ensure `MODEL_ID` is a model that supports multimodal input.
|
||||
* **Thinking not shown**:
|
||||
* Ensure **streaming is enabled** and the selected model supports reasoning output.
|
||||
* **CLI Installation Failed**:
|
||||
* Ensure the OpenWebUI container has internet access.
|
||||
* You can manually download the CLI and specify `CLI_PATH` in Valves.
|
||||
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
# GitHub Copilot SDK 官方管道
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.2.3 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.3.0 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
|
||||
|
||||
这是一个用于 [OpenWebUI](https://github.com/open-webui/open-webui) 的高级 Pipe 函数,允许你直接在 OpenWebUI 中使用 GitHub Copilot 模型(如 `gpt-5`, `gpt-5-mini`, `claude-sonnet-4.5`)。它基于官方 [GitHub Copilot SDK for Python](https://github.com/github/copilot-sdk) 构建,提供了原生级的集成体验。
|
||||
|
||||
## 🚀 最新特性 (v0.2.3)
|
||||
## 🚀 最新特性 (v0.3.0) - “统一生态”的力量
|
||||
|
||||
* **🧩 用户级覆盖**:新增 `REASONING_EFFORT`、`CLI_PATH`、`DEBUG`、`SHOW_THINKING`、`MODEL_ID` 的用户级覆盖。
|
||||
* **🧠 思考输出可靠性**:思考显示会遵循用户设置,并正确传递到流式输出中。
|
||||
* **📝 格式化输出增强**:自动优化输出格式(短句、段落、列表),并解决了在某些界面下显示过于紧凑的问题。
|
||||
* **🔌 零配置工具桥接 (Unified Tool Bridge)**: 自动将您现有的 OpenWebUI Functions (工具) 转换为 Copilot 兼容工具。**Copilot 现在可以无缝调用您手头所有的 WebUI 工具!**
|
||||
* **🔗 动态 MCP 自动发现**: 直接联动 OpenWebUI **管理面板 -> 连接**。无需编写任何配置文件,即插即用,瞬间扩展 Copilot 能力边界。
|
||||
* **⚡ 高性能异步引擎**: 异步 CLI 更新检查与高度优化的事件驱动流式处理,确保对话毫秒级响应。
|
||||
* **🛡️ 卓越的兼容性**: 独创的动态 Pydantic 模型生成技术,确保复杂工具参数在 Copilot 端也能得到精准验证。
|
||||
|
||||
## ✨ 核心特性
|
||||
## ✨ 核心能力
|
||||
|
||||
* **🚀 官方 SDK 集成**:基于官方 SDK,稳定可靠。
|
||||
* **🛠️ 自定义工具支持**:内置示例工具(随机数)。易于扩展自定义工具。
|
||||
* **💬 多轮对话支持**:自动拼接历史上下文,Copilot 能理解你的前文。
|
||||
* **🌊 流式输出 (Streaming)**:支持打字机效果,响应迅速。
|
||||
* **🖼️ 多模态支持**:支持上传图片,自动转换为附件发送给 Copilot(需模型支持)。
|
||||
* **🛠️ 零配置安装**:自动检测并下载 GitHub Copilot CLI,开箱即用。
|
||||
* **🔑 安全认证**:支持 Fine-grained Personal Access Tokens,权限最小化。
|
||||
* **🐛 调试模式**:内置详细的日志输出(浏览器控制台),方便排查问题。
|
||||
* **⚠️ 仅支持单节点**:由于会话状态存储在本地,本插件目前仅支持 OpenWebUI 单节点部署,或开启了会话粘性 (Sticky Session) 的多节点集群。
|
||||
* **🌉 强大的生态桥接**: 首个且唯一完美打通 **OpenWebUI Tools** 与 **GitHub Copilot SDK** 的插件。
|
||||
* **🚀 官方原生产体验**: 基于官方 Python SDK 构建,提供最稳定、最纯正的 Copilot 交互体验。
|
||||
* **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染。
|
||||
* **🖼️ 智能多模态**: 支持图像识别与附件上传,让 Copilot 拥有视觉能力。
|
||||
* **🛠️ 极简部署流程**: 自动检测环境、自动下载 CLI、自动管理依赖,全自动化开箱即用。
|
||||
* **🔑 安全认证体系**: 完美支持 OAuth 授权与 PAT 模式,兼顾便捷与安全性。
|
||||
|
||||
## 📦 安装与使用
|
||||
## 安装与配置
|
||||
|
||||
### 1. 导入函数
|
||||
|
||||
@@ -38,24 +36,22 @@
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | **(必填)** 你的 GitHub Token。 | - |
|
||||
| **MODEL_ID** | 使用的模型名称。 | `gpt-5-mini` |
|
||||
| **CLI_PATH** | Copilot CLI 的路径。如果未找到会自动下载。 | `/usr/local/bin/copilot` |
|
||||
| **GH_TOKEN** | **(必填)** GitHub 访问令牌 (PAT 或 OAuth Token)。用于聊天。 | - |
|
||||
| **DEBUG** | 是否开启调试日志(输出到浏览器控制台)。 | `False` |
|
||||
| **LOG_LEVEL** | Copilot CLI 日志级别: none, error, warning, info, debug, all。 | `error` |
|
||||
| **SHOW_THINKING** | 是否显示模型推理/思考过程(需开启流式 + 模型支持)。 | `True` |
|
||||
| **SHOW_WORKSPACE_INFO** | 在调试模式下显示会话工作空间路径和摘要。 | `True` |
|
||||
| **EXCLUDE_KEYWORDS** | 排除包含这些关键词的模型 (逗号分隔)。 | - |
|
||||
| **WORKSPACE_DIR** | 文件操作的受限工作目录。 | - |
|
||||
| **INFINITE_SESSION** | 启用无限会话 (自动上下文压缩)。 | `True` |
|
||||
| **COPILOT_CLI_VERSION** | 指定安装/强制使用的 Copilot CLI 版本。 | `0.0.405` |
|
||||
| **EXCLUDE_KEYWORDS** | 排除包含这些关键词的模型(逗号分隔)。 | - |
|
||||
| **WORKSPACE_DIR** | 文件操作的受限工作区目录。 | - |
|
||||
| **INFINITE_SESSION** | 启用无限会话(自动上下文压缩)。 | `True` |
|
||||
| **COMPACTION_THRESHOLD** | 后台压缩阈值 (0.0-1.0)。 | `0.8` |
|
||||
| **BUFFER_THRESHOLD** | 缓冲耗尽阈值 (0.0-1.0)。 | `0.95` |
|
||||
| **TIMEOUT** | 流式数据块超时时间 (秒)。 | `300` |
|
||||
| **BUFFER_THRESHOLD** | 缓冲区耗尽阈值 (0.0-1.0)。 | `0.95` |
|
||||
| **TIMEOUT** | 每个流式分块超时(秒)。 | `300` |
|
||||
| **CUSTOM_ENV_VARS** | 自定义环境变量 (JSON 格式)。 | - |
|
||||
| **ENABLE_TOOLS** | 启用自定义工具 (示例:随机数)。 | `False` |
|
||||
| **AVAILABLE_TOOLS** | 可用工具: 'all' 或逗号分隔列表。 | `all` |
|
||||
| **REASONING_EFFORT** | 推理强度级别:low, medium, high。`gpt-5.2-codex`额外支持`xhigh`。 | `medium` |
|
||||
| **ENFORCE_FORMATTING** | 是否强制添加格式化指导,以提高输出可读性。 | `True` |
|
||||
| **REASONING_EFFORT** | 推理强度级别: low, medium, high. `xhigh` 仅部分模型支持。 | `medium` |
|
||||
| **ENFORCE_FORMATTING** | 在系统提示词中添加格式化指导。 | `True` |
|
||||
| **ENABLE_MCP_SERVER** | 启用直接 MCP 客户端连接 (建议)。 | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | 启用 OpenWebUI 工具 (包括自定义和服务器工具)。 | `True` |
|
||||
|
||||
#### 用户 Valves(按用户覆盖)
|
||||
|
||||
@@ -63,36 +59,31 @@
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GH_TOKEN** | 个人 GitHub Token(覆盖全局设置)。 | - |
|
||||
| **REASONING_EFFORT** | 推理强度级别(low/medium/high/xhigh)。 | - |
|
||||
| **CLI_PATH** | 自定义 Copilot CLI 路径。 | - |
|
||||
| **DEBUG** | 是否启用技术调试日志。 | `False` |
|
||||
| **SHOW_THINKING** | 是否显示思考过程(需开启流式 + 模型支持)。 | `True` |
|
||||
| **MODEL_ID** | 自定义模型 ID。 | - |
|
||||
| **SHOW_THINKING** | 是否显示思考过程。 | `True` |
|
||||
| **ENABLE_OPENWEBUI_TOOLS** | 启用 OpenWebUI 工具(覆盖全局设置)。 | `True` |
|
||||
| **ENABLE_MCP_SERVER** | 启用动态 MCP 服务器加载(覆盖全局设置)。 | `True` |
|
||||
| **ENFORCE_FORMATTING** | 强制启用格式化指导(覆盖全局设置)。 | `True` |
|
||||
|
||||
### 3. 使用自定义工具 (🆕 可选)
|
||||
## ⭐ 支持
|
||||
|
||||
本 Pipe 内置了 **1 个示例工具**来展示工具调用功能:
|
||||
如果这个插件对你有帮助,欢迎到 [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
* **🎲 generate_random_number**:生成随机整数
|
||||
### 获取 Token
|
||||
|
||||
**启用方法:**
|
||||
要使用 GitHub Copilot,您需要一个具有适当权限的 GitHub 个人访问令牌 (PAT)。
|
||||
|
||||
1. 在 Valves 中设置 `ENABLE_TOOLS: true`
|
||||
2. 尝试问:“给我一个随机数”
|
||||
**获取步骤:**
|
||||
|
||||
**📚 详细使用说明和创建自定义工具,请参阅 [TOOLS_USAGE.md](TOOLS_USAGE.md)**
|
||||
|
||||
### 4. 获取 GH_TOKEN
|
||||
|
||||
为了安全起见,推荐使用 **Fine-grained Personal Access Token**:
|
||||
|
||||
1. 访问 [GitHub Token Settings](https://github.com/settings/tokens?type=beta)。
|
||||
2. 点击 **Generate new token**。
|
||||
3. **Repository access**: 选择 **Public repositories** (必须选择此项才能看到 Copilot 权限)。
|
||||
1. 访问 [GitHub 令牌设置](https://github.com/settings/tokens?type=beta)。
|
||||
2. 点击 **Generate new token (fine-grained)**。
|
||||
3. **Repository access**: 选择 **Public Repositories** (最简单) 或 **All repositories**。
|
||||
4. **Permissions**:
|
||||
* 点击 **Account permissions**。
|
||||
* 找到 **Copilot Requests** (默认即为 **Read-only**,无需手动修改)。
|
||||
5. 生成并复制 Token。
|
||||
* 如果您选择了 **All repositories**,则必须点击 **Account permissions**。
|
||||
* 找到 **Copilot Requests**,选择 **Access**。
|
||||
5. 生成并复制令牌。
|
||||
|
||||
## 📋 依赖说明
|
||||
|
||||
@@ -101,14 +92,13 @@
|
||||
* `github-copilot-sdk` (Python 包)
|
||||
* `github-copilot-cli` (二进制文件,通过官方脚本安装)
|
||||
|
||||
## ⚠️ 常见问题
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
* **一直显示 "Waiting..."**:
|
||||
* 检查 `GH_TOKEN` 是否正确且拥有 `Copilot Requests` 权限。
|
||||
* **图片无法识别**:
|
||||
* **图片及多模态使用说明**:
|
||||
* 确保 `MODEL_ID` 是支持多模态的模型。
|
||||
* **CLI 安装失败**:
|
||||
* 确保 OpenWebUI 容器有外网访问权限。
|
||||
* 你可以手动下载 CLI 并挂载到容器中,然后在 Valves 中指定 `CLI_PATH`。
|
||||
* **看不到思考过程**:
|
||||
* 确认已开启**流式输出**,且所选模型支持推理输出。
|
||||
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)
|
||||
|
||||
187
plugins/pipes/github-copilot-sdk/TOOLS_USAGE.md
Normal file
187
plugins/pipes/github-copilot-sdk/TOOLS_USAGE.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 🛠️ Custom Tools Usage / 自定义工具使用指南
|
||||
|
||||
## Overview / 概览
|
||||
|
||||
This pipe supports **OpenWebUI Native Tools** (Functions) and **Custom Python Tools**.
|
||||
本 Pipe 支持 **OpenWebUI 原生工具** (Functions) 和 **自定义 Python 工具**。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 OpenWebUI Native Tools / OpenWebUI 原生工具 (v0.3.0)
|
||||
|
||||
**New in v0.3.0**: You can use any tool defined in OpenWebUI directly with Copilot.
|
||||
**v0.3.0 新增**: 您可以直接在 Copilot 中使用 OpenWebUI 中定义的任何工具。
|
||||
|
||||
**How to use / 如何使用:**
|
||||
|
||||
1. Go to **Workspace** -> **Tools**.
|
||||
2. Create a tool (e.g. `get_weather`).
|
||||
3. In Copilot Chat settings (Valves), ensure `ENABLE_OPENWEBUI_TOOLS` is `True` (default).
|
||||
4. Ask Copilot: "Search for the latest news" or "Check weather".
|
||||
|
||||
**Note / 注意:**
|
||||
|
||||
- Tool names are automatically sanitized to match Copilot SDK requirements (e.g. `my.tool` -> `my_tool`).
|
||||
- 工具名称会自动净化以符合 Copilot SDK 要求(例如 `my.tool` 变为 `my_tool`)。
|
||||
|
||||
---
|
||||
|
||||
## 📦 Python Custom Tools / Python 自定义工具
|
||||
|
||||
This pipe includes **1 example custom tool** that demonstrates how to use GitHub Copilot SDK's tool calling feature directly in Python code.
|
||||
本 Pipe 包含 **1 个示例自定义工具**,展示如何使用 GitHub Copilot SDK 的工具调用功能。
|
||||
|
||||
### 1. `generate_random_number` / 生成随机数
|
||||
|
||||
**Description:** Generate a random integer
|
||||
**描述:** 生成随机整数
|
||||
|
||||
**Parameters / 参数:**
|
||||
|
||||
- `min` (optional): Minimum value (default: 1)
|
||||
- `max` (optional): Maximum value (default: 100)
|
||||
- `min` (可选): 最小值 (默认: 1)
|
||||
- `max` (可选): 最大值 (默认: 100)
|
||||
|
||||
**Example / 示例:**
|
||||
|
||||
```
|
||||
User: "Give me a random number between 1 and 10"
|
||||
Copilot: [calls generate_random_number with min=1, max=10] "Generated random number: 7"
|
||||
|
||||
用户: "给我一个 1 到 10 之间的随机数"
|
||||
Copilot: [调用 generate_random_number,参数 min=1, max=10] "生成的随机数: 7"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuration / 配置
|
||||
|
||||
### Enable Tools / 启用工具
|
||||
|
||||
In Valves configuration:
|
||||
在 Valves 配置中:
|
||||
|
||||
```
|
||||
ENABLE_TOOLS: true
|
||||
AVAILABLE_TOOLS: all
|
||||
```
|
||||
|
||||
### Select Specific Tools / 选择特定工具
|
||||
|
||||
Instead of enabling all tools, specify which ones to use:
|
||||
不启用所有工具,而是指定要使用的工具:
|
||||
|
||||
```
|
||||
ENABLE_TOOLS: true
|
||||
AVAILABLE_TOOLS: generate_random_number
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 How Tool Calling Works / 工具调用的工作原理
|
||||
|
||||
```
|
||||
1. User asks a question / 用户提问
|
||||
↓
|
||||
2. Copilot decides if it needs a tool / Copilot 决定是否需要工具
|
||||
↓
|
||||
3. If yes, Copilot calls the appropriate tool / 如果需要,调用相应工具
|
||||
↓
|
||||
4. Tool executes and returns result / 工具执行并返回结果
|
||||
↓
|
||||
5. Copilot uses the result to answer / Copilot 使用结果回答
|
||||
```
|
||||
|
||||
### Visual Feedback / 可视化反馈
|
||||
|
||||
When tools are called, you'll see:
|
||||
当工具被调用时,你会看到:
|
||||
|
||||
```
|
||||
🔧 **Calling tool**: `generate_random_number`
|
||||
✅ **Tool `generate_random_number` completed**
|
||||
|
||||
Generated random number: 7
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Creating Your Own Tools / 创建自定义工具
|
||||
|
||||
Want to add your own Python tools? Follow this pattern (module-level tools):
|
||||
想要添加自己的 Python 工具?遵循这个模式(模块级工具):
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from copilot import define_tool
|
||||
|
||||
class MyToolParams(BaseModel):
|
||||
param_name: str = Field(description="Parameter description")
|
||||
|
||||
|
||||
@define_tool(description="Clear description of what the tool does and when to use it")
|
||||
async def my_tool(params: MyToolParams) -> str:
|
||||
# Do something
|
||||
result = do_something(params.param_name)
|
||||
return f"Result: {result}"
|
||||
```
|
||||
|
||||
Then register it in `_initialize_custom_tools()`:
|
||||
然后将它添加到 `_initialize_custom_tools()`:
|
||||
|
||||
```python
|
||||
def _initialize_custom_tools(self):
|
||||
if not self.valves.ENABLE_TOOLS:
|
||||
return []
|
||||
|
||||
all_tools = {
|
||||
"generate_random_number": generate_random_number,
|
||||
"my_tool": my_tool, # ✅ Add here
|
||||
}
|
||||
|
||||
if self.valves.AVAILABLE_TOOLS == "all":
|
||||
return list(all_tools.values())
|
||||
|
||||
enabled = [t.strip() for t in self.valves.AVAILABLE_TOOLS.split(",")]
|
||||
return [all_tools[name] for name in enabled if name in all_tools]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes / 重要说明
|
||||
|
||||
### Security / 安全性
|
||||
|
||||
- Tools run in the same process as the pipe
|
||||
- Be careful with tools that execute code or access files
|
||||
- Always validate input parameters
|
||||
|
||||
- 工具在与 Pipe 相同的进程中运行
|
||||
- 谨慎处理执行代码或访问文件的工具
|
||||
- 始终验证输入参数
|
||||
|
||||
### Performance / 性能
|
||||
|
||||
- Tool execution is synchronous during streaming
|
||||
- Long-running tools may cause delays
|
||||
- Consider adding timeouts for external API calls
|
||||
|
||||
- 工具执行在流式传输期间是同步的
|
||||
- 长时间运行的工具可能导致延迟
|
||||
- 考虑为外部 API 调用添加超时
|
||||
|
||||
### Debugging / 调试
|
||||
|
||||
- Enable `DEBUG: true` to see tool events in the browser console
|
||||
- Check tool calls in `🔧 Calling tool` messages
|
||||
- Tool errors are displayed in the response
|
||||
|
||||
- 启用 `DEBUG: true` 在浏览器控制台查看工具事件
|
||||
- 在 `🔧 Calling tool` 消息中检查工具调用
|
||||
- 工具错误会显示在响应中
|
||||
|
||||
---
|
||||
|
||||
**Version:** 0.3.0
|
||||
**Last Updated:** 2026-02-05
|
||||
@@ -5,11 +5,12 @@ author_url: https://github.com/Fu-Jie/awesome-openwebui
|
||||
funding_url: https://github.com/open-webui
|
||||
openwebui_id: ce96f7b4-12fc-4ac3-9a01-875713e69359
|
||||
description: Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.
|
||||
version: 0.2.3
|
||||
requirements: github-copilot-sdk
|
||||
version: 0.3.0
|
||||
requirements: github-copilot-sdk==0.1.22
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import base64
|
||||
import tempfile
|
||||
@@ -17,44 +18,34 @@ import asyncio
|
||||
import logging
|
||||
import shutil
|
||||
import subprocess
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union, AsyncGenerator, List, Any, Dict
|
||||
from pydantic import BaseModel, Field
|
||||
from types import SimpleNamespace
|
||||
from pydantic import BaseModel, Field, create_model
|
||||
|
||||
# Import copilot SDK modules
|
||||
from copilot import CopilotClient, define_tool
|
||||
|
||||
# Import Tool Server Connections and Tool System from OpenWebUI Config
|
||||
from open_webui.config import TOOL_SERVER_CONNECTIONS
|
||||
from open_webui.utils.tools import get_tools as get_openwebui_tools
|
||||
from open_webui.models.tools import Tools
|
||||
from open_webui.models.users import Users
|
||||
|
||||
# Setup logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RandomNumberParams(BaseModel):
|
||||
min: int = Field(description="Minimum value (inclusive)")
|
||||
max: int = Field(description="Maximum value (inclusive)")
|
||||
|
||||
|
||||
@define_tool(description="Generate a random integer within a specified range.")
|
||||
async def generate_random_number(params: RandomNumberParams) -> str:
|
||||
import random
|
||||
|
||||
if params.min >= params.max:
|
||||
raise ValueError("min must be less than max")
|
||||
number = random.randint(params.min, params.max)
|
||||
return f"Generated random number: {number}"
|
||||
|
||||
|
||||
class Pipe:
|
||||
class Valves(BaseModel):
|
||||
GH_TOKEN: str = Field(
|
||||
default="",
|
||||
description="GitHub Fine-grained Token (Requires 'Copilot Requests' permission)",
|
||||
)
|
||||
MODEL_ID: str = Field(
|
||||
default="gpt-5-mini",
|
||||
description="Default Copilot model name (used when dynamic fetching fails)",
|
||||
)
|
||||
CLI_PATH: str = Field(
|
||||
default="/usr/local/bin/copilot",
|
||||
description="Path to Copilot CLI",
|
||||
COPILOT_CLI_VERSION: str = Field(
|
||||
default="0.0.405",
|
||||
description="Specific Copilot CLI version to install/enforce (e.g. '0.0.405'). Leave empty for latest.",
|
||||
)
|
||||
DEBUG: bool = Field(
|
||||
default=False,
|
||||
@@ -68,10 +59,6 @@ class Pipe:
|
||||
default=True,
|
||||
description="Show model reasoning/thinking process",
|
||||
)
|
||||
SHOW_WORKSPACE_INFO: bool = Field(
|
||||
default=True,
|
||||
description="Show session workspace path and summary in debug mode",
|
||||
)
|
||||
EXCLUDE_KEYWORDS: str = Field(
|
||||
default="",
|
||||
description="Exclude models containing these keywords (comma separated, e.g.: codex, haiku)",
|
||||
@@ -100,13 +87,14 @@ class Pipe:
|
||||
default="",
|
||||
description='Custom environment variables (JSON format, e.g., {"VAR": "value"})',
|
||||
)
|
||||
ENABLE_TOOLS: bool = Field(
|
||||
default=False,
|
||||
description="Enable custom tools (example: random number)",
|
||||
|
||||
ENABLE_OPENWEBUI_TOOLS: bool = Field(
|
||||
default=True,
|
||||
description="Enable OpenWebUI Tools (includes defined Tools and Tool Server Tools).",
|
||||
)
|
||||
AVAILABLE_TOOLS: str = Field(
|
||||
default="all",
|
||||
description="Available tools: 'all' or comma-separated list (e.g., 'generate_random_number')",
|
||||
ENABLE_MCP_SERVER: bool = Field(
|
||||
default=True,
|
||||
description="Enable Direct MCP Client connection (Recommended).",
|
||||
)
|
||||
REASONING_EFFORT: str = Field(
|
||||
default="medium",
|
||||
@@ -118,14 +106,14 @@ class Pipe:
|
||||
)
|
||||
|
||||
class UserValves(BaseModel):
|
||||
GH_TOKEN: str = Field(
|
||||
default="",
|
||||
description="Personal GitHub Fine-grained Token (overrides global setting)",
|
||||
)
|
||||
REASONING_EFFORT: str = Field(
|
||||
default="",
|
||||
description="Reasoning effort level (low, medium, high, xhigh). Leave empty to use global setting.",
|
||||
)
|
||||
CLI_PATH: str = Field(
|
||||
default="",
|
||||
description="Custom path to Copilot CLI. Leave empty to use global setting.",
|
||||
)
|
||||
DEBUG: bool = Field(
|
||||
default=False,
|
||||
description="Enable technical debug logs (connection info, etc.)",
|
||||
@@ -134,9 +122,18 @@ class Pipe:
|
||||
default=True,
|
||||
description="Show model reasoning/thinking process",
|
||||
)
|
||||
MODEL_ID: str = Field(
|
||||
default="",
|
||||
description="Custom model ID (e.g. gpt-4o). Leave empty to use global default.",
|
||||
ENABLE_OPENWEBUI_TOOLS: bool = Field(
|
||||
default=True,
|
||||
description="Enable OpenWebUI Tools (includes defined Tools and Tool Server Tools).",
|
||||
)
|
||||
ENABLE_MCP_SERVER: bool = Field(
|
||||
default=True,
|
||||
description="Enable dynamic MCP server loading (overrides global).",
|
||||
)
|
||||
|
||||
ENFORCE_FORMATTING: bool = Field(
|
||||
default=True,
|
||||
description="Enforce formatting guidelines (overrides global)",
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
@@ -147,6 +144,7 @@ class Pipe:
|
||||
self.temp_dir = tempfile.mkdtemp(prefix="copilot_images_")
|
||||
self.thinking_started = False
|
||||
self._model_cache = [] # Model list cache
|
||||
self._last_update_check = 0 # Timestamp of last CLI update check
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
@@ -183,23 +181,269 @@ class Pipe:
|
||||
# ==================== Custom Tool Examples ====================
|
||||
# Tool registration: Add @define_tool decorated functions at module level,
|
||||
# then register them in _initialize_custom_tools() -> all_tools dict.
|
||||
def _initialize_custom_tools(self):
|
||||
async def _initialize_custom_tools(self, __user__=None, __event_call__=None):
|
||||
"""Initialize custom tools based on configuration"""
|
||||
if not self.valves.ENABLE_TOOLS:
|
||||
if not self.valves.ENABLE_OPENWEBUI_TOOLS:
|
||||
return []
|
||||
|
||||
# Define all available tools (register new tools here)
|
||||
all_tools = {
|
||||
"generate_random_number": generate_random_number,
|
||||
# Load OpenWebUI tools dynamically
|
||||
openwebui_tools = await self._load_openwebui_tools(
|
||||
__user__=__user__, __event_call__=__event_call__
|
||||
)
|
||||
|
||||
return openwebui_tools
|
||||
|
||||
def _json_schema_to_python_type(self, schema: dict) -> Any:
|
||||
"""Convert JSON Schema type to Python type for Pydantic models."""
|
||||
if not isinstance(schema, dict):
|
||||
return Any
|
||||
|
||||
schema_type = schema.get("type")
|
||||
if isinstance(schema_type, list):
|
||||
schema_type = next((t for t in schema_type if t != "null"), schema_type[0])
|
||||
|
||||
if schema_type == "string":
|
||||
return str
|
||||
if schema_type == "integer":
|
||||
return int
|
||||
if schema_type == "number":
|
||||
return float
|
||||
if schema_type == "boolean":
|
||||
return bool
|
||||
if schema_type == "object":
|
||||
return Dict[str, Any]
|
||||
if schema_type == "array":
|
||||
items_schema = schema.get("items", {})
|
||||
item_type = self._json_schema_to_python_type(items_schema)
|
||||
return List[item_type]
|
||||
|
||||
return Any
|
||||
|
||||
def _convert_openwebui_tool(self, tool_name: str, tool_dict: dict):
|
||||
"""Convert OpenWebUI tool definition to Copilot SDK tool."""
|
||||
# Sanitize tool name to match pattern ^[a-zA-Z0-9_-]+$
|
||||
sanitized_tool_name = re.sub(r"[^a-zA-Z0-9_-]", "_", tool_name)
|
||||
|
||||
# If sanitized name is empty or consists only of separators (e.g. pure Chinese name), generate a fallback name
|
||||
if not sanitized_tool_name or re.match(r"^[_.-]+$", sanitized_tool_name):
|
||||
hash_suffix = hashlib.md5(tool_name.encode("utf-8")).hexdigest()[:8]
|
||||
sanitized_tool_name = f"tool_{hash_suffix}"
|
||||
|
||||
if sanitized_tool_name != tool_name:
|
||||
logger.debug(
|
||||
f"Sanitized tool name '{tool_name}' to '{sanitized_tool_name}'"
|
||||
)
|
||||
|
||||
spec = tool_dict.get("spec", {}) if isinstance(tool_dict, dict) else {}
|
||||
params_schema = spec.get("parameters", {}) if isinstance(spec, dict) else {}
|
||||
properties = params_schema.get("properties", {})
|
||||
required = params_schema.get("required", [])
|
||||
|
||||
if not isinstance(properties, dict):
|
||||
properties = {}
|
||||
if not isinstance(required, list):
|
||||
required = []
|
||||
|
||||
required_set = set(required)
|
||||
fields = {}
|
||||
for param_name, param_schema in properties.items():
|
||||
param_type = self._json_schema_to_python_type(param_schema)
|
||||
description = ""
|
||||
if isinstance(param_schema, dict):
|
||||
description = param_schema.get("description", "")
|
||||
|
||||
if param_name in required_set:
|
||||
if description:
|
||||
fields[param_name] = (
|
||||
param_type,
|
||||
Field(..., description=description),
|
||||
)
|
||||
else:
|
||||
fields[param_name] = (param_type, ...)
|
||||
else:
|
||||
optional_type = Optional[param_type]
|
||||
if description:
|
||||
fields[param_name] = (
|
||||
optional_type,
|
||||
Field(default=None, description=description),
|
||||
)
|
||||
else:
|
||||
fields[param_name] = (optional_type, None)
|
||||
|
||||
if fields:
|
||||
ParamsModel = create_model(f"{sanitized_tool_name}_Params", **fields)
|
||||
else:
|
||||
ParamsModel = create_model(f"{sanitized_tool_name}_Params")
|
||||
|
||||
tool_callable = tool_dict.get("callable")
|
||||
tool_description = spec.get("description", "") if isinstance(spec, dict) else ""
|
||||
if not tool_description and isinstance(spec, dict):
|
||||
tool_description = spec.get("summary", "")
|
||||
|
||||
# Critical: If the tool name was sanitized (e.g. Chinese -> Hash), instructions are lost.
|
||||
# We must inject the original name into the description so the model knows what it is.
|
||||
if sanitized_tool_name != tool_name:
|
||||
tool_description = f"Function '{tool_name}': {tool_description}"
|
||||
|
||||
async def _tool(params):
|
||||
payload = params.model_dump() if hasattr(params, "model_dump") else {}
|
||||
return await tool_callable(**payload)
|
||||
|
||||
_tool.__name__ = sanitized_tool_name
|
||||
_tool.__doc__ = tool_description
|
||||
|
||||
# Debug log for tool conversion
|
||||
logger.debug(
|
||||
f"Converting tool '{sanitized_tool_name}': {tool_description[:50]}..."
|
||||
)
|
||||
|
||||
# Core Fix: Explicitly pass params_type and name
|
||||
return define_tool(
|
||||
name=sanitized_tool_name,
|
||||
description=tool_description,
|
||||
params_type=ParamsModel,
|
||||
)(_tool)
|
||||
|
||||
def _build_openwebui_request(self):
|
||||
"""Build a minimal request-like object for OpenWebUI tool loading."""
|
||||
app_state = SimpleNamespace(
|
||||
config=SimpleNamespace(
|
||||
TOOL_SERVER_CONNECTIONS=TOOL_SERVER_CONNECTIONS.value
|
||||
),
|
||||
TOOLS={},
|
||||
)
|
||||
app = SimpleNamespace(state=app_state)
|
||||
request = SimpleNamespace(
|
||||
app=app,
|
||||
cookies={},
|
||||
state=SimpleNamespace(token=SimpleNamespace(credentials="")),
|
||||
)
|
||||
return request
|
||||
|
||||
async def _load_openwebui_tools(self, __user__=None, __event_call__=None):
|
||||
"""Load OpenWebUI tools and convert them to Copilot SDK tools."""
|
||||
if isinstance(__user__, (list, tuple)):
|
||||
user_data = __user__[0] if __user__ else {}
|
||||
elif isinstance(__user__, dict):
|
||||
user_data = __user__
|
||||
else:
|
||||
user_data = {}
|
||||
|
||||
if not user_data:
|
||||
return []
|
||||
|
||||
user_id = user_data.get("id") or user_data.get("user_id")
|
||||
if not user_id:
|
||||
return []
|
||||
|
||||
user = Users.get_user_by_id(user_id)
|
||||
if not user:
|
||||
return []
|
||||
|
||||
# 1. Get User defined tools (Python scripts)
|
||||
tool_items = Tools.get_tools_by_user_id(user_id, permission="read")
|
||||
tool_ids = [tool.id for tool in tool_items] if tool_items else []
|
||||
|
||||
# 2. Get OpenAPI Tool Server tools
|
||||
# We manually add enabled OpenAPI servers to the list because Tools.get_tools_by_user_id only checks the DB.
|
||||
# open_webui.utils.tools.get_tools handles the actual loading and access control.
|
||||
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
|
||||
for server in TOOL_SERVER_CONNECTIONS.value:
|
||||
# We only add 'openapi' servers here because get_tools currently only supports 'openapi' (or defaults to it).
|
||||
# MCP tools are handled separately via ENABLE_MCP_SERVER.
|
||||
if server.get("type") == "openapi":
|
||||
# Format expected by get_tools: "server:<id>" implies types="openapi"
|
||||
server_id = server.get("id")
|
||||
if server_id:
|
||||
tool_ids.append(f"server:{server_id}")
|
||||
|
||||
if not tool_ids:
|
||||
return []
|
||||
|
||||
request = self._build_openwebui_request()
|
||||
extra_params = {
|
||||
"__request__": request,
|
||||
"__user__": user_data,
|
||||
"__event_emitter__": None,
|
||||
"__event_call__": __event_call__,
|
||||
"__chat_id__": None,
|
||||
"__message_id__": None,
|
||||
"__model_knowledge__": [],
|
||||
}
|
||||
|
||||
# Filter based on configuration
|
||||
if self.valves.AVAILABLE_TOOLS == "all":
|
||||
return list(all_tools.values())
|
||||
tools_dict = await get_openwebui_tools(request, tool_ids, user, extra_params)
|
||||
if not tools_dict:
|
||||
return []
|
||||
|
||||
# Only enable specified tools
|
||||
enabled = [t.strip() for t in self.valves.AVAILABLE_TOOLS.split(",")]
|
||||
return [all_tools[name] for name in enabled if name in all_tools]
|
||||
converted_tools = []
|
||||
for tool_name, tool_def in tools_dict.items():
|
||||
try:
|
||||
converted_tools.append(
|
||||
self._convert_openwebui_tool(tool_name, tool_def)
|
||||
)
|
||||
except Exception as e:
|
||||
await self._emit_debug_log(
|
||||
f"Failed to load OpenWebUI tool '{tool_name}': {e}",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
return converted_tools
|
||||
|
||||
def _parse_mcp_servers(self) -> Optional[dict]:
|
||||
"""
|
||||
Dynamically load MCP servers from OpenWebUI TOOL_SERVER_CONNECTIONS.
|
||||
Returns a dict of mcp_servers compatible with CopilotClient.
|
||||
"""
|
||||
if not self.valves.ENABLE_MCP_SERVER:
|
||||
return None
|
||||
|
||||
mcp_servers = {}
|
||||
|
||||
# Iterate over OpenWebUI Tool Server Connections
|
||||
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
|
||||
connections = TOOL_SERVER_CONNECTIONS.value
|
||||
else:
|
||||
connections = []
|
||||
|
||||
for conn in connections:
|
||||
if conn.get("type") == "mcp":
|
||||
info = conn.get("info", {})
|
||||
# Use ID from info or generate one
|
||||
raw_id = info.get("id", f"mcp-server-{len(mcp_servers)}")
|
||||
|
||||
# Sanitize server_id (using same logic as tools)
|
||||
server_id = re.sub(r"[^a-zA-Z0-9_-]", "_", raw_id)
|
||||
if not server_id or re.match(r"^[_.-]+$", server_id):
|
||||
hash_suffix = hashlib.md5(raw_id.encode("utf-8")).hexdigest()[:8]
|
||||
server_id = f"server_{hash_suffix}"
|
||||
|
||||
url = conn.get("url")
|
||||
if not url:
|
||||
continue
|
||||
|
||||
# Build Headers (Handle Auth)
|
||||
headers = {}
|
||||
auth_type = conn.get("auth_type", "bearer")
|
||||
key = conn.get("key", "")
|
||||
|
||||
if auth_type == "bearer" and key:
|
||||
headers["Authorization"] = f"Bearer {key}"
|
||||
elif auth_type == "basic" and key:
|
||||
headers["Authorization"] = f"Basic {key}"
|
||||
|
||||
# Merge custom headers if any
|
||||
custom_headers = conn.get("headers", {})
|
||||
if isinstance(custom_headers, dict):
|
||||
headers.update(custom_headers)
|
||||
|
||||
mcp_servers[server_id] = {
|
||||
"type": "http",
|
||||
"url": url,
|
||||
"headers": headers,
|
||||
"tools": ["*"], # Enable all tools by default
|
||||
}
|
||||
|
||||
return mcp_servers if mcp_servers else None
|
||||
|
||||
async def _emit_debug_log(self, message: str, __event_call__=None):
|
||||
"""Emit debug log to frontend (console) when DEBUG is enabled."""
|
||||
@@ -390,9 +634,31 @@ class Pipe:
|
||||
|
||||
return system_prompt_content, system_prompt_source
|
||||
|
||||
def _get_workspace_dir(self) -> str:
|
||||
"""Get the effective workspace directory with smart defaults."""
|
||||
if self.valves.WORKSPACE_DIR:
|
||||
return self.valves.WORKSPACE_DIR
|
||||
|
||||
# Smart default for OpenWebUI container
|
||||
if os.path.exists("/app/backend/data"):
|
||||
cwd = "/app/backend/data/copilot_workspace"
|
||||
else:
|
||||
# Local fallback: subdirectory in current working directory
|
||||
cwd = os.path.join(os.getcwd(), "copilot_workspace")
|
||||
|
||||
# Ensure directory exists
|
||||
if not os.path.exists(cwd):
|
||||
try:
|
||||
os.makedirs(cwd, exist_ok=True)
|
||||
except Exception as e:
|
||||
print(f"Error creating workspace {cwd}: {e}")
|
||||
return os.getcwd() # Fallback to CWD if creation fails
|
||||
|
||||
return cwd
|
||||
|
||||
def _build_client_config(self, body: dict) -> dict:
|
||||
"""Build CopilotClient config from valves and request body."""
|
||||
cwd = self.valves.WORKSPACE_DIR if self.valves.WORKSPACE_DIR else os.getcwd()
|
||||
cwd = self._get_workspace_dir()
|
||||
client_config = {}
|
||||
if os.environ.get("COPILOT_CLI_PATH"):
|
||||
client_config["cli_path"] = os.environ["COPILOT_CLI_PATH"]
|
||||
@@ -418,7 +684,6 @@ class Pipe:
|
||||
custom_tools: List[Any],
|
||||
system_prompt_content: Optional[str],
|
||||
is_streaming: bool,
|
||||
reasoning_effort: str = "",
|
||||
):
|
||||
"""Build SessionConfig for Copilot SDK."""
|
||||
from copilot.types import SessionConfig, InfiniteSessionConfig
|
||||
@@ -470,9 +735,9 @@ class Pipe:
|
||||
"infinite_sessions": infinite_session_config,
|
||||
}
|
||||
|
||||
# Add reasoning_effort if not default (medium)
|
||||
if reasoning_effort and reasoning_effort.lower() != "medium":
|
||||
session_params["reasoning_effort"] = reasoning_effort.lower()
|
||||
mcp_servers = self._parse_mcp_servers()
|
||||
if mcp_servers:
|
||||
session_params["mcp_servers"] = mcp_servers
|
||||
|
||||
return SessionConfig(**session_params)
|
||||
|
||||
@@ -628,8 +893,8 @@ class Pipe:
|
||||
# Return default model on failure
|
||||
return [
|
||||
{
|
||||
"id": f"{self.id}-{self.valves.MODEL_ID}",
|
||||
"name": f"GitHub Copilot ({self.valves.MODEL_ID})",
|
||||
"id": f"{self.id}-gpt-5-mini",
|
||||
"name": f"GitHub Copilot (gpt-5-mini)",
|
||||
}
|
||||
]
|
||||
finally:
|
||||
@@ -638,8 +903,8 @@ class Pipe:
|
||||
await self._emit_debug_log(f"Pipes Error: {e}")
|
||||
return [
|
||||
{
|
||||
"id": f"{self.id}-{self.valves.MODEL_ID}",
|
||||
"name": f"GitHub Copilot ({self.valves.MODEL_ID})",
|
||||
"id": f"{self.id}-gpt-5-mini",
|
||||
"name": f"GitHub Copilot (gpt-5-mini)",
|
||||
}
|
||||
]
|
||||
|
||||
@@ -654,30 +919,93 @@ class Pipe:
|
||||
return client
|
||||
|
||||
def _setup_env(self, __event_call__=None):
|
||||
cli_path = self.valves.CLI_PATH
|
||||
found = False
|
||||
# Default CLI path logic
|
||||
cli_path = "/usr/local/bin/copilot"
|
||||
if os.environ.get("COPILOT_CLI_PATH"):
|
||||
cli_path = os.environ["COPILOT_CLI_PATH"]
|
||||
|
||||
target_version = self.valves.COPILOT_CLI_VERSION.strip()
|
||||
found = False
|
||||
current_version = None
|
||||
|
||||
# internal helper to get version
|
||||
def get_cli_version(path):
|
||||
try:
|
||||
output = (
|
||||
subprocess.check_output(
|
||||
[path, "--version"], stderr=subprocess.STDOUT
|
||||
)
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
# Copilot CLI version output format is usually just the version number or "copilot version X.Y.Z"
|
||||
# We try to extract X.Y.Z
|
||||
match = re.search(r"(\d+\.\d+\.\d+)", output)
|
||||
return match.group(1) if match else output
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# Check default path
|
||||
if os.path.exists(cli_path):
|
||||
found = True
|
||||
current_version = get_cli_version(cli_path)
|
||||
|
||||
# Check system path if not found
|
||||
if not found:
|
||||
sys_path = shutil.which("copilot")
|
||||
if sys_path:
|
||||
cli_path = sys_path
|
||||
found = True
|
||||
current_version = get_cli_version(cli_path)
|
||||
|
||||
# Determine if we need to install or update
|
||||
should_install = False
|
||||
install_reason = ""
|
||||
|
||||
if not found:
|
||||
should_install = True
|
||||
install_reason = "CLI not found"
|
||||
elif target_version:
|
||||
# Normalize versions for comparison (remove 'v' prefix)
|
||||
norm_target = target_version.lstrip("v")
|
||||
norm_current = current_version.lstrip("v") if current_version else ""
|
||||
|
||||
if norm_target != norm_current:
|
||||
should_install = True
|
||||
install_reason = f"Version mismatch (Current: {current_version}, Target: {target_version})"
|
||||
|
||||
if should_install:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Installing Copilot CLI: {install_reason}...", __event_call__
|
||||
)
|
||||
try:
|
||||
env = os.environ.copy()
|
||||
if target_version:
|
||||
env["VERSION"] = target_version
|
||||
|
||||
subprocess.run(
|
||||
"curl -fsSL https://gh.io/copilot-install | bash",
|
||||
shell=True,
|
||||
check=True,
|
||||
env=env,
|
||||
)
|
||||
if os.path.exists(self.valves.CLI_PATH):
|
||||
cli_path = self.valves.CLI_PATH
|
||||
|
||||
# Check default install location first, then system path
|
||||
if os.path.exists("/usr/local/bin/copilot"):
|
||||
cli_path = "/usr/local/bin/copilot"
|
||||
found = True
|
||||
except:
|
||||
pass
|
||||
elif shutil.which("copilot"):
|
||||
cli_path = shutil.which("copilot")
|
||||
found = True
|
||||
|
||||
if found:
|
||||
current_version = get_cli_version(cli_path)
|
||||
except Exception as e:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Failed to install Copilot CLI: {e}", __event_call__
|
||||
)
|
||||
|
||||
if found:
|
||||
os.environ["COPILOT_CLI_PATH"] = cli_path
|
||||
@@ -687,25 +1015,9 @@ class Pipe:
|
||||
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Copilot CLI found at: {cli_path}", __event_call__
|
||||
f"Copilot CLI found at: {cli_path} (Version: {current_version})",
|
||||
__event_call__,
|
||||
)
|
||||
try:
|
||||
# Try to get version to confirm it's executable
|
||||
ver = (
|
||||
subprocess.check_output(
|
||||
[cli_path, "--version"], stderr=subprocess.STDOUT
|
||||
)
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
self._emit_debug_log_sync(
|
||||
f"Copilot CLI Version: {ver}", __event_call__
|
||||
)
|
||||
except Exception as e:
|
||||
self._emit_debug_log_sync(
|
||||
f"Warning: Copilot CLI found but failed to run: {e}",
|
||||
__event_call__,
|
||||
)
|
||||
else:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
@@ -722,6 +1034,8 @@ class Pipe:
|
||||
"Warning: GH_TOKEN is not set.", __event_call__
|
||||
)
|
||||
|
||||
self._sync_mcp_config(__event_call__)
|
||||
|
||||
def _process_images(self, messages, __event_call__=None):
|
||||
attachments = []
|
||||
text_content = ""
|
||||
@@ -779,8 +1093,8 @@ class Pipe:
|
||||
"gpt-5.2-codex"
|
||||
not in self._collect_model_ids(
|
||||
body={},
|
||||
request_model=self.valves.MODEL_ID,
|
||||
real_model_id=self.valves.MODEL_ID,
|
||||
request_model=self.id,
|
||||
real_model_id=None,
|
||||
)[0].lower()
|
||||
):
|
||||
# Fallback to high if not supported
|
||||
@@ -823,6 +1137,53 @@ class Pipe:
|
||||
except Exception as e:
|
||||
self._emit_debug_log_sync(f"Config sync check failed: {e}", __event_call__)
|
||||
|
||||
async def _update_copilot_cli(self, cli_path: str, __event_call__=None):
|
||||
"""Async task to update Copilot CLI if needed."""
|
||||
import time
|
||||
|
||||
try:
|
||||
# Check frequency (e.g., once every hour)
|
||||
now = time.time()
|
||||
if now - self._last_update_check < 3600:
|
||||
return
|
||||
|
||||
self._last_update_check = now
|
||||
|
||||
# Simple check if "update" command is available or if we should just run it
|
||||
# The user requested "async attempt to update copilot cli"
|
||||
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
"Triggering async Copilot CLI update check...", __event_call__
|
||||
)
|
||||
|
||||
# We create a subprocess to run the update
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
cli_path,
|
||||
"update",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
|
||||
stdout, stderr = await process.communicate()
|
||||
|
||||
if self.valves.DEBUG:
|
||||
output = stdout.decode().strip() or stderr.decode().strip()
|
||||
if output:
|
||||
self._emit_debug_log_sync(
|
||||
f"Async CLI Update result: {output}", __event_call__
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Async CLI Update failed: {e}", __event_call__
|
||||
)
|
||||
|
||||
def _sync_mcp_config(self, __event_call__=None):
|
||||
"""Deprecated: MCP config is now handled dynamically via session config."""
|
||||
pass
|
||||
|
||||
# ==================== Internal Implementation ====================
|
||||
# _pipe_impl() contains the main request handling logic.
|
||||
# ================================================================
|
||||
@@ -835,12 +1196,22 @@ class Pipe:
|
||||
__event_call__=None,
|
||||
) -> Union[str, AsyncGenerator]:
|
||||
self._setup_env(__event_call__)
|
||||
|
||||
cwd = self._get_workspace_dir()
|
||||
if self.valves.DEBUG:
|
||||
await self._emit_debug_log(f"Agent working in: {cwd}", __event_call__)
|
||||
|
||||
if not self.valves.GH_TOKEN:
|
||||
return "Error: Please configure GH_TOKEN in Valves."
|
||||
|
||||
# Trigger async CLI update if configured
|
||||
cli_path = os.environ.get("COPILOT_CLI_PATH")
|
||||
if cli_path:
|
||||
asyncio.create_task(self._update_copilot_cli(cli_path, __event_call__))
|
||||
|
||||
# Parse user selected model
|
||||
request_model = body.get("model", "")
|
||||
real_model_id = self.valves.MODEL_ID # Default value
|
||||
real_model_id = request_model
|
||||
|
||||
# Determine effective reasoning effort and debug setting
|
||||
if __user__:
|
||||
@@ -877,6 +1248,14 @@ class Pipe:
|
||||
await self._emit_debug_log(
|
||||
f"Using selected model: {real_model_id}", __event_call__
|
||||
)
|
||||
elif __metadata__ and __metadata__.get("base_model_id"):
|
||||
base_model_id = __metadata__.get("base_model_id", "")
|
||||
if base_model_id.startswith(f"{self.id}-"):
|
||||
real_model_id = base_model_id[len(f"{self.id}-") :]
|
||||
await self._emit_debug_log(
|
||||
f"Using base model: {real_model_id} (derived from custom model {request_model})",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
messages = body.get("messages", [])
|
||||
if not messages:
|
||||
@@ -918,26 +1297,58 @@ class Pipe:
|
||||
await client.start()
|
||||
|
||||
# Initialize custom tools
|
||||
custom_tools = self._initialize_custom_tools()
|
||||
custom_tools = await self._initialize_custom_tools(
|
||||
__user__=__user__, __event_call__=__event_call__
|
||||
)
|
||||
if custom_tools:
|
||||
tool_names = [t.name for t in custom_tools]
|
||||
await self._emit_debug_log(
|
||||
f"Enabled {len(custom_tools)} custom tools: {tool_names}",
|
||||
__event_call__,
|
||||
)
|
||||
if self.valves.DEBUG:
|
||||
for t in custom_tools:
|
||||
await self._emit_debug_log(
|
||||
f"📋 Tool Detail: {t.name} - {t.description[:100]}...",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
# Check MCP Servers
|
||||
mcp_servers = self._parse_mcp_servers()
|
||||
mcp_server_names = list(mcp_servers.keys()) if mcp_servers else []
|
||||
if mcp_server_names:
|
||||
await self._emit_debug_log(
|
||||
f"🔌 MCP Servers Configured: {mcp_server_names}",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
else:
|
||||
await self._emit_debug_log(
|
||||
"ℹ️ No MCP tool servers found in OpenWebUI Connections.",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
# Create or Resume Session
|
||||
session = None
|
||||
if chat_id:
|
||||
try:
|
||||
session = await client.resume_session(chat_id)
|
||||
# Prepare resume config
|
||||
resume_params = {}
|
||||
if mcp_servers:
|
||||
resume_params["mcp_servers"] = mcp_servers
|
||||
|
||||
session = (
|
||||
await client.resume_session(chat_id, resume_params)
|
||||
if resume_params
|
||||
else await client.resume_session(chat_id)
|
||||
)
|
||||
await self._emit_debug_log(
|
||||
f"Resumed session: {chat_id} (Note: Formatting guidelines only apply to NEW sessions. Create a new chat to use updated formatting.)",
|
||||
f"Resumed session: {chat_id} (Reasoning: {effective_reasoning_effort or 'default'})",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
# Show workspace info if available
|
||||
if self.valves.DEBUG and self.valves.SHOW_WORKSPACE_INFO:
|
||||
# Show workspace info of available
|
||||
if self.valves.DEBUG:
|
||||
if session.workspace_path:
|
||||
await self._emit_debug_log(
|
||||
f"Session workspace: {session.workspace_path}",
|
||||
@@ -990,7 +1401,7 @@ class Pipe:
|
||||
)
|
||||
|
||||
# Show workspace info for new sessions
|
||||
if self.valves.DEBUG and self.valves.SHOW_WORKSPACE_INFO:
|
||||
if self.valves.DEBUG:
|
||||
if session.workspace_path:
|
||||
await self._emit_debug_log(
|
||||
f"Session workspace: {session.workspace_path}",
|
||||
@@ -1012,7 +1423,11 @@ class Pipe:
|
||||
if body.get("stream", False):
|
||||
init_msg = ""
|
||||
if self.valves.DEBUG:
|
||||
init_msg = f"> [Debug] Agent working in: {os.getcwd()}\n"
|
||||
init_msg = (
|
||||
f"> [Debug] Agent working in: {self._get_workspace_dir()}\n"
|
||||
)
|
||||
if mcp_server_names:
|
||||
init_msg += f"> [Debug] 🔌 Connected MCP Servers: {', '.join(mcp_server_names)}\n"
|
||||
|
||||
# Transfer client ownership to stream_response
|
||||
should_stop_client = False
|
||||
|
||||
@@ -4,11 +4,12 @@ author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/awesome-openwebui
|
||||
funding_url: https://github.com/open-webui
|
||||
description: 集成 GitHub Copilot SDK。支持动态模型、多轮对话、流式输出、多模态输入、无限会话及前端调试日志。
|
||||
version: 0.2.3
|
||||
requirements: github-copilot-sdk
|
||||
version: 0.3.0
|
||||
requirements: github-copilot-sdk==0.1.22
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
import base64
|
||||
@@ -18,46 +19,36 @@ import logging
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional, Union, AsyncGenerator, List, Any, Dict
|
||||
from pydantic import BaseModel, Field
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union, AsyncGenerator, List, Any, Dict, Callable
|
||||
from types import SimpleNamespace
|
||||
from pydantic import BaseModel, Field, create_model
|
||||
from datetime import datetime, timezone
|
||||
import contextlib
|
||||
|
||||
# 导入 Copilot SDK 模块
|
||||
from copilot import CopilotClient, define_tool
|
||||
|
||||
# 导入 OpenWebUI 配置和工具模块
|
||||
from open_webui.config import TOOL_SERVER_CONNECTIONS
|
||||
from open_webui.utils.tools import get_tools as get_openwebui_tools
|
||||
from open_webui.models.tools import Tools
|
||||
from open_webui.models.users import Users
|
||||
|
||||
# Setup logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RandomNumberParams(BaseModel):
|
||||
min: int = Field(description="最小值(包含)")
|
||||
max: int = Field(description="最大值(包含)")
|
||||
|
||||
|
||||
@define_tool(description="在指定范围内生成随机整数。")
|
||||
async def generate_random_number(params: RandomNumberParams) -> str:
|
||||
import random
|
||||
|
||||
if params.min >= params.max:
|
||||
raise ValueError("min 必须小于 max")
|
||||
number = random.randint(params.min, params.max)
|
||||
return f"生成的随机数: {number}"
|
||||
|
||||
|
||||
class Pipe:
|
||||
class Valves(BaseModel):
|
||||
GH_TOKEN: str = Field(
|
||||
default="",
|
||||
description="GitHub 细粒度 Token(需要 Copilot Requests 权限)",
|
||||
description="GitHub OAuth Token (来自 'gh auth token'),用于 Copilot Chat (必须)",
|
||||
)
|
||||
MODEL_ID: str = Field(
|
||||
default="gpt-5-mini",
|
||||
description="默认 Copilot 模型名(动态获取失败时使用)",
|
||||
)
|
||||
CLI_PATH: str = Field(
|
||||
default="/usr/local/bin/copilot",
|
||||
description="Copilot CLI 路径",
|
||||
COPILOT_CLI_VERSION: str = Field(
|
||||
default="0.0.405",
|
||||
description="指定安装/强制使用的 Copilot CLI 版本 (例如 '0.0.405')。留空则使用最新版。",
|
||||
)
|
||||
DEBUG: bool = Field(
|
||||
default=False,
|
||||
@@ -71,10 +62,6 @@ class Pipe:
|
||||
default=True,
|
||||
description="显示模型推理/思考过程",
|
||||
)
|
||||
SHOW_WORKSPACE_INFO: bool = Field(
|
||||
default=True,
|
||||
description="调试模式下显示会话工作空间路径与摘要",
|
||||
)
|
||||
EXCLUDE_KEYWORDS: str = Field(
|
||||
default="",
|
||||
description="排除包含这些关键词的模型(逗号分隔,如:codex, haiku)",
|
||||
@@ -103,13 +90,14 @@ class Pipe:
|
||||
default="",
|
||||
description='自定义环境变量(JSON 格式,例如 {"VAR": "value"})',
|
||||
)
|
||||
ENABLE_TOOLS: bool = Field(
|
||||
default=False,
|
||||
description="启用自定义工具(例如:随机数)",
|
||||
|
||||
ENABLE_OPENWEBUI_TOOLS: bool = Field(
|
||||
default=True,
|
||||
description="启用 OpenWebUI 工具 (包括自定义工具和工具服务器工具)。",
|
||||
)
|
||||
AVAILABLE_TOOLS: str = Field(
|
||||
default="all",
|
||||
description="可用工具:'all' 或逗号分隔列表(例如:'generate_random_number')",
|
||||
ENABLE_MCP_SERVER: bool = Field(
|
||||
default=True,
|
||||
description="启用直接 MCP 客户端连接 (推荐)。",
|
||||
)
|
||||
REASONING_EFFORT: str = Field(
|
||||
default="medium",
|
||||
@@ -121,25 +109,35 @@ class Pipe:
|
||||
)
|
||||
|
||||
class UserValves(BaseModel):
|
||||
GH_TOKEN: str = Field(
|
||||
default="",
|
||||
description="个人 GitHub Fine-grained Token (覆盖全局设置)",
|
||||
)
|
||||
REASONING_EFFORT: str = Field(
|
||||
default="",
|
||||
description="推理强度级别 (low, medium, high, xhigh)。留空以使用全局设置。",
|
||||
)
|
||||
CLI_PATH: str = Field(
|
||||
default="",
|
||||
description="自定义 Copilot CLI 路径。留空以使用全局设置。",
|
||||
)
|
||||
DEBUG: bool = Field(
|
||||
default=False,
|
||||
description="启用技术调试日志(连接信息等)",
|
||||
)
|
||||
SHOW_THINKING: bool = Field(
|
||||
default=True,
|
||||
description="显示模型推理/思考过程",
|
||||
description="显示模型的推理/思考过程",
|
||||
)
|
||||
MODEL_ID: str = Field(
|
||||
default="",
|
||||
description="自定义模型 ID (例如 gpt-4o)。留空以使用全局默认值。",
|
||||
|
||||
ENABLE_OPENWEBUI_TOOLS: bool = Field(
|
||||
default=True,
|
||||
description="启用 OpenWebUI 工具 (包括自定义工具和工具服务器工具,覆盖全局设置)。",
|
||||
)
|
||||
ENABLE_MCP_SERVER: bool = Field(
|
||||
default=True,
|
||||
description="启用动态 MCP 服务器加载 (覆盖全局设置)。",
|
||||
)
|
||||
|
||||
ENFORCE_FORMATTING: bool = Field(
|
||||
default=True,
|
||||
description="强制启用格式化指导 (覆盖全局设置)",
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
@@ -150,6 +148,7 @@ class Pipe:
|
||||
self.temp_dir = tempfile.mkdtemp(prefix="copilot_images_")
|
||||
self.thinking_started = False
|
||||
self._model_cache = [] # 模型列表缓存
|
||||
self._last_update_check = 0 # 上次 CLI 更新检查时间
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
@@ -338,9 +337,31 @@ class Pipe:
|
||||
|
||||
return system_prompt_content, system_prompt_source
|
||||
|
||||
def _get_workspace_dir(self) -> str:
|
||||
"""获取具有智能默认值的有效工作空间目录。"""
|
||||
if self.valves.WORKSPACE_DIR:
|
||||
return self.valves.WORKSPACE_DIR
|
||||
|
||||
# OpenWebUI 容器的智能默认值
|
||||
if os.path.exists("/app/backend/data"):
|
||||
cwd = "/app/backend/data/copilot_workspace"
|
||||
else:
|
||||
# 本地回退:当前工作目录的子目录
|
||||
cwd = os.path.join(os.getcwd(), "copilot_workspace")
|
||||
|
||||
# 确保目录存在
|
||||
if not os.path.exists(cwd):
|
||||
try:
|
||||
os.makedirs(cwd, exist_ok=True)
|
||||
except Exception as e:
|
||||
print(f"Error creating workspace {cwd}: {e}")
|
||||
return os.getcwd() # 如果创建失败回退到 CWD
|
||||
|
||||
return cwd
|
||||
|
||||
def _build_client_config(self, body: dict) -> dict:
|
||||
"""根据 Valves 和请求构建 CopilotClient 配置"""
|
||||
cwd = self.valves.WORKSPACE_DIR if self.valves.WORKSPACE_DIR else os.getcwd()
|
||||
cwd = self._get_workspace_dir()
|
||||
client_config = {}
|
||||
if os.environ.get("COPILOT_CLI_PATH"):
|
||||
client_config["cli_path"] = os.environ["COPILOT_CLI_PATH"]
|
||||
@@ -359,6 +380,270 @@ class Pipe:
|
||||
|
||||
return client_config
|
||||
|
||||
async def _initialize_custom_tools(self, __user__=None, __event_call__=None):
|
||||
"""根据配置初始化自定义工具"""
|
||||
|
||||
if not self.valves.ENABLE_OPENWEBUI_TOOLS:
|
||||
return []
|
||||
|
||||
# 动态加载 OpenWebUI 工具
|
||||
openwebui_tools = await self._load_openwebui_tools(
|
||||
__user__=__user__, __event_call__=__event_call__
|
||||
)
|
||||
|
||||
return openwebui_tools
|
||||
|
||||
def _json_schema_to_python_type(self, schema: dict) -> Any:
|
||||
"""将 JSON Schema 类型转换为 Python 类型以用于 Pydantic 模型。"""
|
||||
if not isinstance(schema, dict):
|
||||
return Any
|
||||
|
||||
schema_type = schema.get("type")
|
||||
if isinstance(schema_type, list):
|
||||
schema_type = next((t for t in schema_type if t != "null"), schema_type[0])
|
||||
|
||||
if schema_type == "string":
|
||||
return str
|
||||
if schema_type == "integer":
|
||||
return int
|
||||
if schema_type == "number":
|
||||
return float
|
||||
if schema_type == "boolean":
|
||||
return bool
|
||||
if schema_type == "object":
|
||||
return Dict[str, Any]
|
||||
if schema_type == "array":
|
||||
items_schema = schema.get("items", {})
|
||||
item_type = self._json_schema_to_python_type(items_schema)
|
||||
return List[item_type]
|
||||
|
||||
return Any
|
||||
|
||||
def _convert_openwebui_tool(self, tool_name: str, tool_dict: dict):
|
||||
"""将 OpenWebUI 工具定义转换为 Copilot SDK 工具。"""
|
||||
# 净化工具名称以匹配模式 ^[a-zA-Z0-9_-]+$
|
||||
sanitized_tool_name = re.sub(r"[^a-zA-Z0-9_-]", "_", tool_name)
|
||||
|
||||
# 如果净化后的名称为空或仅包含分隔符(例如纯中文名称),生成回退名称
|
||||
if not sanitized_tool_name or re.match(r"^[_.-]+$", sanitized_tool_name):
|
||||
hash_suffix = hashlib.md5(tool_name.encode("utf-8")).hexdigest()[:8]
|
||||
sanitized_tool_name = f"tool_{hash_suffix}"
|
||||
|
||||
if sanitized_tool_name != tool_name:
|
||||
logger.debug(f"将工具名称 '{tool_name}' 净化为 '{sanitized_tool_name}'")
|
||||
|
||||
spec = tool_dict.get("spec", {}) if isinstance(tool_dict, dict) else {}
|
||||
params_schema = spec.get("parameters", {}) if isinstance(spec, dict) else {}
|
||||
properties = params_schema.get("properties", {})
|
||||
required = params_schema.get("required", [])
|
||||
|
||||
if not isinstance(properties, dict):
|
||||
properties = {}
|
||||
if not isinstance(required, list):
|
||||
required = []
|
||||
|
||||
required_set = set(required)
|
||||
fields = {}
|
||||
for param_name, param_schema in properties.items():
|
||||
param_type = self._json_schema_to_python_type(param_schema)
|
||||
description = ""
|
||||
if isinstance(param_schema, dict):
|
||||
description = param_schema.get("description", "")
|
||||
|
||||
if param_name in required_set:
|
||||
if description:
|
||||
fields[param_name] = (
|
||||
param_type,
|
||||
Field(..., description=description),
|
||||
)
|
||||
else:
|
||||
fields[param_name] = (param_type, ...)
|
||||
else:
|
||||
optional_type = Optional[param_type]
|
||||
if description:
|
||||
fields[param_name] = (
|
||||
optional_type,
|
||||
Field(default=None, description=description),
|
||||
)
|
||||
else:
|
||||
fields[param_name] = (optional_type, None)
|
||||
|
||||
if fields:
|
||||
ParamsModel = create_model(f"{sanitized_tool_name}_Params", **fields)
|
||||
else:
|
||||
ParamsModel = create_model(f"{sanitized_tool_name}_Params")
|
||||
|
||||
tool_callable = tool_dict.get("callable")
|
||||
tool_description = spec.get("description", "") if isinstance(spec, dict) else ""
|
||||
if not tool_description and isinstance(spec, dict):
|
||||
tool_description = spec.get("summary", "")
|
||||
|
||||
# 关键: 如果工具名称被净化(例如中文转哈希),语义会丢失。
|
||||
# 我们必须将原始名称注入到描述中,以便模型知道它的作用。
|
||||
if sanitized_tool_name != tool_name:
|
||||
tool_description = f"功能 '{tool_name}': {tool_description}"
|
||||
|
||||
async def _tool(params):
|
||||
payload = params.model_dump() if hasattr(params, "model_dump") else {}
|
||||
return await tool_callable(**payload)
|
||||
|
||||
_tool.__name__ = sanitized_tool_name
|
||||
_tool.__doc__ = tool_description
|
||||
|
||||
# 转换调试日志
|
||||
logger.debug(
|
||||
f"正在转换工具 '{sanitized_tool_name}': {tool_description[:50]}..."
|
||||
)
|
||||
|
||||
# 核心关键点:必须显式传递 types,否则 define_tool 无法推断动态函数的参数
|
||||
# 显式传递 name 确保 SDK 注册的名称正确
|
||||
return define_tool(
|
||||
name=sanitized_tool_name,
|
||||
description=tool_description,
|
||||
params_type=ParamsModel,
|
||||
)(_tool)
|
||||
|
||||
def _build_openwebui_request(self):
|
||||
"""构建一个最小的 request 模拟对象用于 OpenWebUI 工具加载。"""
|
||||
app_state = SimpleNamespace(
|
||||
config=SimpleNamespace(
|
||||
TOOL_SERVER_CONNECTIONS=TOOL_SERVER_CONNECTIONS.value
|
||||
),
|
||||
TOOLS={},
|
||||
)
|
||||
app = SimpleNamespace(state=app_state)
|
||||
request = SimpleNamespace(
|
||||
app=app,
|
||||
cookies={},
|
||||
state=SimpleNamespace(token=SimpleNamespace(credentials="")),
|
||||
)
|
||||
return request
|
||||
|
||||
async def _load_openwebui_tools(self, __user__=None, __event_call__=None):
|
||||
"""动态加载 OpenWebUI 工具并转换为 Copilot SDK 工具。"""
|
||||
if isinstance(__user__, (list, tuple)):
|
||||
user_data = __user__[0] if __user__ else {}
|
||||
elif isinstance(__user__, dict):
|
||||
user_data = __user__
|
||||
else:
|
||||
user_data = {}
|
||||
|
||||
if not user_data:
|
||||
return []
|
||||
|
||||
user_id = user_data.get("id") or user_data.get("user_id")
|
||||
if not user_id:
|
||||
return []
|
||||
|
||||
user = Users.get_user_by_id(user_id)
|
||||
if not user:
|
||||
return []
|
||||
|
||||
# 1. 获取用户自定义工具 (Python 脚本)
|
||||
tool_items = Tools.get_tools_by_user_id(user_id, permission="read")
|
||||
tool_ids = [tool.id for tool in tool_items] if tool_items else []
|
||||
|
||||
# 2. 获取 OpenAPI 工具服务器工具
|
||||
# 我们手动添加已启用的 OpenAPI 服务器,因为 Tools.get_tools_by_user_id 仅检查数据库。
|
||||
# open_webui.utils.tools.get_tools 会处理实际的加载和访问控制。
|
||||
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
|
||||
for server in TOOL_SERVER_CONNECTIONS.value:
|
||||
# 我们在此处仅添加 'openapi' 服务器,因为 get_tools 目前似乎仅支持 'openapi' (默认为此)。
|
||||
# MCP 工具通过 ENABLE_MCP_SERVER 单独处理。
|
||||
if server.get("type") == "openapi":
|
||||
# get_tools 期望的格式: "server:<id>" 隐含 type="openapi"
|
||||
server_id = server.get("id")
|
||||
if server_id:
|
||||
tool_ids.append(f"server:{server_id}")
|
||||
|
||||
if not tool_ids:
|
||||
return []
|
||||
|
||||
request = self._build_openwebui_request()
|
||||
extra_params = {
|
||||
"__request__": request,
|
||||
"__user__": user_data,
|
||||
"__event_emitter__": None,
|
||||
"__event_call__": __event_call__,
|
||||
"__chat_id__": None,
|
||||
"__message_id__": None,
|
||||
"__model_knowledge__": [],
|
||||
}
|
||||
|
||||
tools_dict = await get_openwebui_tools(request, tool_ids, user, extra_params)
|
||||
if not tools_dict:
|
||||
return []
|
||||
|
||||
converted_tools = []
|
||||
for tool_name, tool_def in tools_dict.items():
|
||||
try:
|
||||
converted_tools.append(
|
||||
self._convert_openwebui_tool(tool_name, tool_def)
|
||||
)
|
||||
except Exception as e:
|
||||
await self._emit_debug_log(
|
||||
f"加载 OpenWebUI 工具 '{tool_name}' 失败: {e}",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
return converted_tools
|
||||
|
||||
def _parse_mcp_servers(self) -> Optional[dict]:
|
||||
"""
|
||||
从 OpenWebUI TOOL_SERVER_CONNECTIONS 动态加载 MCP 服务器配置。
|
||||
返回兼容 CopilotClient 的 mcp_servers 字典。
|
||||
"""
|
||||
if not self.valves.ENABLE_MCP_SERVER:
|
||||
return None
|
||||
|
||||
mcp_servers = {}
|
||||
|
||||
# 遍历 OpenWebUI 工具服务器连接
|
||||
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
|
||||
connections = TOOL_SERVER_CONNECTIONS.value
|
||||
else:
|
||||
connections = []
|
||||
|
||||
for conn in connections:
|
||||
if conn.get("type") == "mcp":
|
||||
info = conn.get("info", {})
|
||||
# 使用 info 中的 ID 或自动生成
|
||||
raw_id = info.get("id", f"mcp-server-{len(mcp_servers)}")
|
||||
|
||||
# 净化 server_id (使用与工具相同的逻辑)
|
||||
server_id = re.sub(r"[^a-zA-Z0-9_-]", "_", raw_id)
|
||||
if not server_id or re.match(r"^[_.-]+$", server_id):
|
||||
hash_suffix = hashlib.md5(raw_id.encode("utf-8")).hexdigest()[:8]
|
||||
server_id = f"server_{hash_suffix}"
|
||||
|
||||
url = conn.get("url")
|
||||
if not url:
|
||||
continue
|
||||
|
||||
# 构建 Header (处理认证)
|
||||
headers = {}
|
||||
auth_type = conn.get("auth_type", "bearer")
|
||||
key = conn.get("key", "")
|
||||
|
||||
if auth_type == "bearer" and key:
|
||||
headers["Authorization"] = f"Bearer {key}"
|
||||
elif auth_type == "basic" and key:
|
||||
headers["Authorization"] = f"Basic {key}"
|
||||
|
||||
# 合并自定义 headers
|
||||
custom_headers = conn.get("headers", {})
|
||||
if isinstance(custom_headers, dict):
|
||||
headers.update(custom_headers)
|
||||
|
||||
mcp_servers[server_id] = {
|
||||
"type": "http",
|
||||
"url": url,
|
||||
"headers": headers,
|
||||
"tools": ["*"], # 默认启用所有工具
|
||||
}
|
||||
|
||||
return mcp_servers if mcp_servers else None
|
||||
|
||||
def _build_session_config(
|
||||
self,
|
||||
chat_id: Optional[str],
|
||||
@@ -366,7 +651,6 @@ class Pipe:
|
||||
custom_tools: List[Any],
|
||||
system_prompt_content: Optional[str],
|
||||
is_streaming: bool,
|
||||
reasoning_effort: str = "",
|
||||
):
|
||||
"""构建 Copilot SDK 的 SessionConfig"""
|
||||
from copilot.types import SessionConfig, InfiniteSessionConfig
|
||||
@@ -414,11 +698,12 @@ class Pipe:
|
||||
"tools": custom_tools,
|
||||
"system_message": system_message_config,
|
||||
"infinite_sessions": infinite_session_config,
|
||||
# 注册权限处理 Hook
|
||||
}
|
||||
|
||||
# 如果不是默认值(medium),添加 reasoning_effort
|
||||
if reasoning_effort and reasoning_effort.lower() != "medium":
|
||||
session_params["reasoning_effort"] = reasoning_effort.lower()
|
||||
mcp_servers = self._parse_mcp_servers()
|
||||
if mcp_servers:
|
||||
session_params["mcp_servers"] = mcp_servers
|
||||
|
||||
return SessionConfig(**session_params)
|
||||
|
||||
@@ -545,24 +830,6 @@ class Pipe:
|
||||
|
||||
return system_prompt_content, system_prompt_source
|
||||
|
||||
def _initialize_custom_tools(self):
|
||||
"""根据配置初始化自定义工具"""
|
||||
if not self.valves.ENABLE_TOOLS:
|
||||
return []
|
||||
|
||||
# 定义所有可用工具(在此注册新工具)
|
||||
all_tools = {
|
||||
"generate_random_number": generate_random_number,
|
||||
}
|
||||
|
||||
# 根据配置过滤
|
||||
if self.valves.AVAILABLE_TOOLS == "all":
|
||||
return list(all_tools.values())
|
||||
|
||||
# 仅启用指定的工具
|
||||
enabled = [t.strip() for t in self.valves.AVAILABLE_TOOLS.split(",")]
|
||||
return [all_tools[name] for name in enabled if name in all_tools]
|
||||
|
||||
async def _emit_debug_log(self, message: str, __event_call__=None):
|
||||
"""在 DEBUG 开启时将日志输出到前端控制台。"""
|
||||
if not self.valves.DEBUG:
|
||||
@@ -764,8 +1031,8 @@ class Pipe:
|
||||
# 失败时返回默认模型
|
||||
return [
|
||||
{
|
||||
"id": f"{self.id}-{self.valves.MODEL_ID}",
|
||||
"name": f"GitHub Copilot ({self.valves.MODEL_ID})",
|
||||
"id": f"{self.id}-gpt-5-mini",
|
||||
"name": f"GitHub Copilot (gpt-5-mini)",
|
||||
}
|
||||
]
|
||||
finally:
|
||||
@@ -774,8 +1041,8 @@ class Pipe:
|
||||
await self._emit_debug_log(f"Pipes Error: {e}")
|
||||
return [
|
||||
{
|
||||
"id": f"{self.id}-{self.valves.MODEL_ID}",
|
||||
"name": f"GitHub Copilot ({self.valves.MODEL_ID})",
|
||||
"id": f"{self.id}-gpt-5-mini",
|
||||
"name": f"GitHub Copilot (gpt-5-mini)",
|
||||
}
|
||||
]
|
||||
|
||||
@@ -807,30 +1074,93 @@ class Pipe:
|
||||
return client
|
||||
|
||||
def _setup_env(self, __event_call__=None):
|
||||
cli_path = self.valves.CLI_PATH
|
||||
found = False
|
||||
cli_path = "/usr/local/bin/copilot"
|
||||
if os.environ.get("COPILOT_CLI_PATH"):
|
||||
cli_path = os.environ["COPILOT_CLI_PATH"]
|
||||
|
||||
target_version = self.valves.COPILOT_CLI_VERSION.strip()
|
||||
found = False
|
||||
current_version = None
|
||||
|
||||
# 内部 helper: 获取版本
|
||||
def get_cli_version(path):
|
||||
try:
|
||||
output = (
|
||||
subprocess.check_output(
|
||||
[path, "--version"], stderr=subprocess.STDOUT
|
||||
)
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
# Copilot CLI 输出通常包含 "copilot version X.Y.Z" 或直接是版本号
|
||||
match = re.search(r"(\d+\.\d+\.\d+)", output)
|
||||
return match.group(1) if match else output
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# 检查默认路径
|
||||
if os.path.exists(cli_path):
|
||||
found = True
|
||||
current_version = get_cli_version(cli_path)
|
||||
|
||||
# 二次检查系统路径
|
||||
if not found:
|
||||
sys_path = shutil.which("copilot")
|
||||
if sys_path:
|
||||
cli_path = sys_path
|
||||
found = True
|
||||
current_version = get_cli_version(cli_path)
|
||||
|
||||
# 判断是否需要安装/更新
|
||||
should_install = False
|
||||
install_reason = ""
|
||||
|
||||
if not found:
|
||||
should_install = True
|
||||
install_reason = "CLI 未找到"
|
||||
elif target_version:
|
||||
# 标准化版本号 (移除 'v' 前缀)
|
||||
norm_target = target_version.lstrip("v")
|
||||
norm_current = current_version.lstrip("v") if current_version else ""
|
||||
|
||||
if norm_target != norm_current:
|
||||
should_install = True
|
||||
install_reason = (
|
||||
f"版本不匹配 (当前: {current_version}, 目标: {target_version})"
|
||||
)
|
||||
|
||||
if should_install:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"正在安装 Copilot CLI: {install_reason}...", __event_call__
|
||||
)
|
||||
try:
|
||||
env = os.environ.copy()
|
||||
if target_version:
|
||||
env["VERSION"] = target_version
|
||||
|
||||
subprocess.run(
|
||||
"curl -fsSL https://gh.io/copilot-install | bash",
|
||||
shell=True,
|
||||
check=True,
|
||||
env=env,
|
||||
)
|
||||
if os.path.exists(self.valves.CLI_PATH):
|
||||
cli_path = self.valves.CLI_PATH
|
||||
|
||||
# 优先检查默认安装路径,其次是系统路径
|
||||
if os.path.exists("/usr/local/bin/copilot"):
|
||||
cli_path = "/usr/local/bin/copilot"
|
||||
found = True
|
||||
except:
|
||||
pass
|
||||
elif shutil.which("copilot"):
|
||||
cli_path = shutil.which("copilot")
|
||||
found = True
|
||||
|
||||
if found:
|
||||
current_version = get_cli_version(cli_path)
|
||||
except Exception as e:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Copilot CLI 安装失败: {e}", __event_call__
|
||||
)
|
||||
|
||||
if found:
|
||||
os.environ["COPILOT_CLI_PATH"] = cli_path
|
||||
@@ -840,7 +1170,14 @@ class Pipe:
|
||||
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Copilot CLI 已定位: {cli_path}", __event_call__
|
||||
f"已找到 Copilot CLI: {cli_path} (版本: {current_version})",
|
||||
__event_call__,
|
||||
)
|
||||
else:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
"错误: 未找到 Copilot CLI。相关 Agent 功能将被禁用。",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
if self.valves.GH_TOKEN:
|
||||
@@ -850,6 +1187,8 @@ class Pipe:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync("Warning: GH_TOKEN 未设置。", __event_call__)
|
||||
|
||||
self._sync_mcp_config(__event_call__)
|
||||
|
||||
def _process_images(self, messages, __event_call__=None):
|
||||
attachments = []
|
||||
text_content = ""
|
||||
@@ -944,9 +1283,113 @@ class Pipe:
|
||||
except Exception as e:
|
||||
self._emit_debug_log_sync(f"配置同步检查失败: {e}", __event_call__)
|
||||
|
||||
def _sync_mcp_config(self, __event_call__=None):
|
||||
"""已弃用:MCP 配置现在通过 SessionConfig 动态处理。"""
|
||||
pass
|
||||
|
||||
# ==================== 内部实现 ====================
|
||||
# _pipe_impl() 包含主请求处理逻辑。
|
||||
# ================================================
|
||||
def _sync_copilot_config(self, reasoning_effort: str, __event_call__=None):
|
||||
"""
|
||||
如果设置了 REASONING_EFFORT,则动态更新 ~/.copilot/config.json。
|
||||
这提供了一个回退机制,以防 API 注入被服务器忽略。
|
||||
"""
|
||||
if not reasoning_effort:
|
||||
return
|
||||
|
||||
effort = reasoning_effort
|
||||
|
||||
# 检查模型是否支持 xhigh
|
||||
# 目前只有 gpt-5.2-codex 支持 xhigh
|
||||
if effort == "xhigh":
|
||||
# 简单检查,使用默认模型 ID
|
||||
if (
|
||||
"gpt-5.2-codex"
|
||||
not in self._collect_model_ids(
|
||||
body={},
|
||||
request_model=self.id,
|
||||
real_model_id=None,
|
||||
)[0].lower()
|
||||
):
|
||||
# 如果不支持则回退到 high
|
||||
effort = "high"
|
||||
|
||||
try:
|
||||
# 目标标准路径 ~/.copilot/config.json
|
||||
config_path = os.path.expanduser("~/.copilot/config.json")
|
||||
config_dir = os.path.dirname(config_path)
|
||||
|
||||
# 仅当目录存在时才继续(避免在路径错误时创建垃圾文件)
|
||||
if not os.path.exists(config_dir):
|
||||
return
|
||||
|
||||
data = {}
|
||||
# 读取现有配置
|
||||
if os.path.exists(config_path):
|
||||
try:
|
||||
with open(config_path, "r") as f:
|
||||
data = json.load(f)
|
||||
except Exception:
|
||||
data = {}
|
||||
|
||||
# 如果有变化则更新
|
||||
current_val = data.get("reasoning_effort")
|
||||
if current_val != effort:
|
||||
data["reasoning_effort"] = effort
|
||||
try:
|
||||
with open(config_path, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
self._emit_debug_log_sync(
|
||||
f"已动态更新 ~/.copilot/config.json: reasoning_effort='{effort}'",
|
||||
__event_call__,
|
||||
)
|
||||
except Exception as e:
|
||||
self._emit_debug_log_sync(
|
||||
f"写入 config.json 失败: {e}", __event_call__
|
||||
)
|
||||
except Exception as e:
|
||||
self._emit_debug_log_sync(f"配置同步检查失败: {e}", __event_call__)
|
||||
|
||||
async def _update_copilot_cli(self, cli_path: str, __event_call__=None):
|
||||
"""异步任务:如果需要则更新 Copilot CLI。"""
|
||||
import time
|
||||
|
||||
try:
|
||||
# 检查频率(例如:每小时一次)
|
||||
now = time.time()
|
||||
if now - self._last_update_check < 3600:
|
||||
return
|
||||
|
||||
self._last_update_check = now
|
||||
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
"触发异步 Copilot CLI 更新检查...", __event_call__
|
||||
)
|
||||
|
||||
# 我们创建一个子进程来运行更新
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
cli_path,
|
||||
"update",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
|
||||
stdout, stderr = await process.communicate()
|
||||
|
||||
if self.valves.DEBUG and process.returncode == 0:
|
||||
self._emit_debug_log_sync("Copilot CLI 更新检查完成", __event_call__)
|
||||
elif process.returncode != 0 and self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(
|
||||
f"Copilot CLI 更新失败: {stderr.decode()}", __event_call__
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
if self.valves.DEBUG:
|
||||
self._emit_debug_log_sync(f"CLI 更新任务异常: {e}", __event_call__)
|
||||
|
||||
async def _pipe_impl(
|
||||
self,
|
||||
body: dict,
|
||||
@@ -956,12 +1399,23 @@ class Pipe:
|
||||
__event_call__=None,
|
||||
) -> Union[str, AsyncGenerator]:
|
||||
self._setup_env(__event_call__)
|
||||
|
||||
cwd = self._get_workspace_dir()
|
||||
if self.valves.DEBUG:
|
||||
await self._emit_debug_log(f"当前工作目录: {cwd}", __event_call__)
|
||||
|
||||
# CLI Update Check
|
||||
if os.environ.get("COPILOT_CLI_PATH"):
|
||||
asyncio.create_task(
|
||||
self._update_copilot_cli(os.environ["COPILOT_CLI_PATH"], __event_call__)
|
||||
)
|
||||
|
||||
if not self.valves.GH_TOKEN:
|
||||
return "Error: 请在 Valves 中配置 GH_TOKEN。"
|
||||
|
||||
# 解析用户选择的模型
|
||||
request_model = body.get("model", "")
|
||||
real_model_id = self.valves.MODEL_ID # 默认值
|
||||
real_model_id = request_model
|
||||
|
||||
# 确定有效的推理强度和调试设置
|
||||
if __user__:
|
||||
@@ -979,6 +1433,10 @@ class Pipe:
|
||||
if user_valves.REASONING_EFFORT
|
||||
else self.valves.REASONING_EFFORT
|
||||
)
|
||||
|
||||
# Sync config for reasoning effort (Legacy/Fallback)
|
||||
self._sync_copilot_config(effective_reasoning_effort, __event_call__)
|
||||
|
||||
# 如果用户启用了 DEBUG,则覆盖全局设置
|
||||
if user_valves.DEBUG:
|
||||
self.valves.DEBUG = True
|
||||
@@ -995,6 +1453,14 @@ class Pipe:
|
||||
await self._emit_debug_log(
|
||||
f"使用选择的模型: {real_model_id}", __event_call__
|
||||
)
|
||||
elif __metadata__ and __metadata__.get("base_model_id"):
|
||||
base_model_id = __metadata__.get("base_model_id", "")
|
||||
if base_model_id.startswith(f"{self.id}-"):
|
||||
real_model_id = base_model_id[len(f"{self.id}-") :]
|
||||
await self._emit_debug_log(
|
||||
f"使用基础模型: {real_model_id} (继承自自定义模型 {request_model})",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
messages = body.get("messages", [])
|
||||
if not messages:
|
||||
@@ -1019,32 +1485,66 @@ class Pipe:
|
||||
is_streaming = body.get("stream", False)
|
||||
await self._emit_debug_log(f"请求流式传输: {is_streaming}", __event_call__)
|
||||
|
||||
# 处理多模态(图像)和提取最后的消息文本
|
||||
last_text, attachments = self._process_images(messages, __event_call__)
|
||||
|
||||
client = CopilotClient(self._build_client_config(body))
|
||||
should_stop_client = True
|
||||
try:
|
||||
await client.start()
|
||||
|
||||
# 初始化自定义工具
|
||||
custom_tools = self._initialize_custom_tools()
|
||||
custom_tools = await self._initialize_custom_tools(
|
||||
__user__=__user__, __event_call__=__event_call__
|
||||
)
|
||||
if custom_tools:
|
||||
tool_names = [t.name for t in custom_tools]
|
||||
await self._emit_debug_log(
|
||||
f"已启用 {len(custom_tools)} 个自定义工具: {tool_names}",
|
||||
__event_call__,
|
||||
)
|
||||
# 详细打印每个工具的描述 (用于调试)
|
||||
if self.valves.DEBUG:
|
||||
for t in custom_tools:
|
||||
await self._emit_debug_log(
|
||||
f"📋 工具详情: {t.name} - {t.description[:100]}...",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
# 检查 MCP 服务器
|
||||
mcp_servers = self._parse_mcp_servers()
|
||||
mcp_server_names = list(mcp_servers.keys()) if mcp_servers else []
|
||||
if mcp_server_names:
|
||||
await self._emit_debug_log(
|
||||
f"🔌 MCP 服务器已配置: {mcp_server_names}",
|
||||
__event_call__,
|
||||
)
|
||||
else:
|
||||
await self._emit_debug_log(
|
||||
"ℹ️ 未在 OpenWebUI 连接中发现 MCP 服务器。",
|
||||
__event_call__,
|
||||
)
|
||||
|
||||
session = None
|
||||
|
||||
if chat_id:
|
||||
try:
|
||||
# 复用已解析的 mcp_servers
|
||||
resume_config = (
|
||||
{"mcp_servers": mcp_servers} if mcp_servers else None
|
||||
)
|
||||
# 尝试直接使用 chat_id 作为 session_id 恢复会话
|
||||
session = await client.resume_session(chat_id)
|
||||
session = (
|
||||
await client.resume_session(chat_id, resume_config)
|
||||
if resume_config
|
||||
else await client.resume_session(chat_id)
|
||||
)
|
||||
await self._emit_debug_log(
|
||||
f"已通过 ChatID 恢复会话: {chat_id}", __event_call__
|
||||
)
|
||||
|
||||
# 显示工作空间信息(如果可用)
|
||||
if self.valves.DEBUG and self.valves.SHOW_WORKSPACE_INFO:
|
||||
if self.valves.DEBUG:
|
||||
if session.workspace_path:
|
||||
await self._emit_debug_log(
|
||||
f"会话工作空间: {session.workspace_path}",
|
||||
@@ -1107,7 +1607,7 @@ class Pipe:
|
||||
await self._emit_debug_log(f"创建了新会话: {new_sid}", __event_call__)
|
||||
|
||||
# 显示新会话的工作空间信息
|
||||
if self.valves.DEBUG and self.valves.SHOW_WORKSPACE_INFO:
|
||||
if self.valves.DEBUG:
|
||||
if session.workspace_path:
|
||||
await self._emit_debug_log(
|
||||
f"会话工作空间: {session.workspace_path}",
|
||||
@@ -1133,6 +1633,9 @@ class Pipe:
|
||||
else:
|
||||
init_msg = f"> [Debug] 已通过 ChatID 恢复会话: {chat_id}\n"
|
||||
|
||||
if mcp_server_names:
|
||||
init_msg += f"> [Debug] 🔌 已连接 MCP 服务器: {', '.join(mcp_server_names)}\n"
|
||||
|
||||
return self.stream_response(
|
||||
client,
|
||||
session,
|
||||
|
||||
Reference in New Issue
Block a user