feat: enable live stats for community reports via Gist dynamic badges

This commit is contained in:
fujie
2026-02-11 12:19:16 +08:00
parent 6d080d3a28
commit dc0366aab2
5 changed files with 98 additions and 70 deletions

View File

@@ -1,7 +1,7 @@
{
"total_posts": 22,
"total_downloads": 4156,
"total_views": 45912,
"total_views": 45916,
"total_upvotes": 231,
"total_downvotes": 2,
"total_saves": 274,
@@ -23,7 +23,7 @@
"author": "Fu-Jie",
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
"downloads": 954,
"views": 8385,
"views": 8386,
"upvotes": 22,
"saves": 50,
"comments": 13,
@@ -295,7 +295,7 @@
"author": "Fu-Jie",
"description": "A specialized filter to bypass OpenWebUI's default RAG for GitHub Copilot SDK models. It moves uploaded files to a safe location ('copilot_files') so the Copilot Pipe can process them natively without interference.",
"downloads": 16,
"views": 851,
"views": 854,
"upvotes": 3,
"saves": 0,
"comments": 0,
@@ -311,7 +311,7 @@
"author": "",
"description": "",
"downloads": 0,
"views": 277,
"views": 278,
"upvotes": 5,
"saves": 0,
"comments": 0,

View File

@@ -1,6 +1,6 @@
# 📊 OpenWebUI Community Stats Report
> 📅 Updated: 2026-02-11 12:15
> 📅 Updated: 2026-02-11 12:19
### 📈 增长与趋势 (Last 14 Days)
```mermaid
@@ -9,7 +9,7 @@ xychart-beta
x-axis ["01-29", "01-30", "01-31", "02-01", "02-02", "02-03", "02-04", "02-05", "02-06", "02-07", "02-08", "02-09", "02-10", "02-11"]
y-axis "Total Counts"
line [2780, 2877, 2979, 3030, 3168, 3236, 3374, 3522, 3663, 3779, 3872, 3996, 4131, 4156]
line [32888, 34134, 35248, 35805, 37424, 38133, 39440, 40964, 43171, 44354, 45255, 46645, 48876, 45912]
line [32888, 34134, 35248, 35805, 37424, 38133, 39440, 40964, 43171, 44354, 45255, 46645, 48876, 45916]
```
> *蓝色: 总下载量 | 紫色: 总浏览量*
@@ -39,14 +39,14 @@ xychart-beta
| Metric | Value | Growth (24h) |
|------|------|:---:|
| 📝 Total Posts | 22 | - |
| ⬇️ Total Downloads | 4156 | **+25** 🚀 |
| 👁️ Total Views | 45912 | - |
| 👍 Total Upvotes | 231 | **+1** 🚀 |
| 💾 Total Saves | 274 | - |
| 📝 Total Posts | ![posts](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_posts.json&style=flat) | - |
| ⬇️ Total Downloads | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&style=flat) | **+25** 🚀 |
| 👁️ Total Views | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&style=flat) | - |
| 👍 Total Upvotes | ![upvotes](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_upvotes.json&style=flat) | **+1** 🚀 |
| 💾 Total Saves | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&style=flat) | - |
| 💬 Total Comments | 55 | - |
| ⭐ Author Points | 271 | **+1** 🚀 |
| 👥 Followers | 220 | - |
| ⭐ Author Points | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&style=flat) | **+1** 🚀 |
| 👥 Followers | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&style=flat) | - |
## 📂 By Type
@@ -61,7 +61,7 @@ xychart-beta
| 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.2 | 954 | 8385 | 22 | 50 | 2026-01-29 |
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 954 | 8386 | 22 | 50 | 2026-01-29 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 707 | 6701 | 24 | 34 | 2026-01-31 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 383 | 3026 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter | 1.2.2 | 363 | 3755 | 14 | 34 | 2026-01-29 |
@@ -78,8 +78,8 @@ xychart-beta
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 669 | 7 | 5 | 2026-01-29 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 690 | 8 | 1 | 2026-01-29 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 444 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 16 | 851 | 3 | 0 | 2026-02-10 |
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post | | 0 | 277 | 5 | 0 | 2026-02-10 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 16 | 854 | 3 | 0 | 2026-02-10 |
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post | | 0 | 278 | 5 | 0 | 2026-02-10 |
| 20 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post | | 0 | 1525 | 12 | 19 | 2026-01-29 |
| 21 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review | | 0 | 161 | 2 | 0 | 2026-01-14 |
| 22 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post | | 0 | 1421 | 14 | 10 | 2026-01-10 |

View File

@@ -1,6 +1,6 @@
# 📊 OpenWebUI 社区统计报告
> 📅 更新时间: 2026-02-11 12:15
> 📅 更新时间: 2026-02-11 12:19
### 📈 增长与趋势 (Last 14 Days)
```mermaid
@@ -9,7 +9,7 @@ xychart-beta
x-axis ["01-29", "01-30", "01-31", "02-01", "02-02", "02-03", "02-04", "02-05", "02-06", "02-07", "02-08", "02-09", "02-10", "02-11"]
y-axis "Total Counts"
line [2780, 2877, 2979, 3030, 3168, 3236, 3374, 3522, 3663, 3779, 3872, 3996, 4131, 4156]
line [32888, 34134, 35248, 35805, 37424, 38133, 39440, 40964, 43171, 44354, 45255, 46645, 48876, 45912]
line [32888, 34134, 35248, 35805, 37424, 38133, 39440, 40964, 43171, 44354, 45255, 46645, 48876, 45916]
```
> *蓝色: 总下载量 | 紫色: 总浏览量*
@@ -39,14 +39,14 @@ xychart-beta
| 指标 | 数值 | 增长 (24h) |
|------|------|:---:|
| 📝 发布数量 | 22 | - |
| ⬇️ 总下载量 | 4156 | **+25** 🚀 |
| 👁️ 总浏览量 | 45912 | - |
| 👍 总点赞数 | 231 | **+1** 🚀 |
| 💾 总收藏数 | 274 | - |
| 📝 发布数量 | ![posts](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_posts.json&style=flat) | - |
| ⬇️ 总下载量 | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&style=flat) | **+25** 🚀 |
| 👁️ 总浏览量 | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&style=flat) | - |
| 👍 总点赞数 | ![upvotes](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_upvotes.json&style=flat) | **+1** 🚀 |
| 💾 总收藏数 | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&style=flat) | - |
| 💬 总评论数 | 55 | - |
| ⭐ 作者总积分 | 271 | **+1** 🚀 |
| 👥 粉丝数量 | 220 | - |
| ⭐ 作者总积分 | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&style=flat) | **+1** 🚀 |
| 👥 粉丝数量 | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&style=flat) | - |
## 📂 按类型分类
@@ -61,7 +61,7 @@ xychart-beta
| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 954 | 8385 | 22 | 50 | 2026-01-29 |
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 954 | 8386 | 22 | 50 | 2026-01-29 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 707 | 6701 | 24 | 34 | 2026-01-31 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 383 | 3026 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter | 1.2.2 | 363 | 3755 | 14 | 34 | 2026-01-29 |
@@ -78,8 +78,8 @@ xychart-beta
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 669 | 7 | 5 | 2026-01-29 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 690 | 8 | 1 | 2026-01-29 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 444 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 16 | 851 | 3 | 0 | 2026-02-10 |
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post | | 0 | 277 | 5 | 0 | 2026-02-10 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 16 | 854 | 3 | 0 | 2026-02-10 |
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post | | 0 | 278 | 5 | 0 | 2026-02-10 |
| 20 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post | | 0 | 1525 | 12 | 19 | 2026-01-29 |
| 21 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review | | 0 | 161 | 2 | 0 | 2026-01-14 |
| 22 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post | | 0 | 1421 | 14 | 10 | 2026-01-10 |

View File

@@ -1084,7 +1084,7 @@
"date": "2026-02-11",
"total_posts": 22,
"total_downloads": 4156,
"total_views": 45912,
"total_views": 45916,
"total_upvotes": 231,
"total_saves": 274,
"followers": 220,

View File

@@ -534,6 +534,8 @@ class OpenWebUIStats:
}
t = texts.get(lang, texts["en"])
user = stats.get("user", {})
delta = self.get_stat_delta(stats)
md = []
md.append(t["title"])
@@ -558,25 +560,30 @@ class OpenWebUIStats:
md.append("")
md.append(t["overview_header"])
md.append("|------|------|:---:|")
md.append(f"| {t['posts']} | {stats['total_posts']} | - |")
md.append(
f"| {t['downloads']} | {stats['total_downloads']} | {fmt_delta('downloads')} |"
f"| {t['posts']} | {self.get_badge('posts', stats, user, delta)} | - |"
)
md.append(f"| {t['views']} | {stats['total_views']} | {fmt_delta('views')} |")
md.append(
f"| {t['upvotes']} | {stats['total_upvotes']} | {fmt_delta('upvotes')} |"
f"| {t['downloads']} | {self.get_badge('downloads', stats, user, delta)} | {fmt_delta('downloads')} |"
)
md.append(
f"| {t['views']} | {self.get_badge('views', stats, user, delta)} | {fmt_delta('views')} |"
)
md.append(
f"| {t['upvotes']} | {self.get_badge('upvotes', stats, user, delta)} | {fmt_delta('upvotes')} |"
)
md.append(
f"| {t['saves']} | {self.get_badge('saves', stats, user, delta)} | - |"
)
md.append(f"| {t['saves']} | {stats['total_saves']} | - |")
md.append(f"| {t['comments']} | {stats['total_comments']} | - |")
# 作者信息
user = stats.get("user", {})
if user:
md.append(
f"| {t['author_points']} | {user.get('total_points', 0)} | {fmt_delta('points')} |"
f"| {t['author_points']} | {self.get_badge('points', stats, user, delta)} | {fmt_delta('points')} |"
)
md.append(
f"| {t['author_followers']} | {user.get('followers', 0)} | {fmt_delta('followers')} |"
f"| {t['author_followers']} | {self.get_badge('followers', stats, user, delta)} | {fmt_delta('followers')} |"
)
md.append("")
@@ -596,6 +603,11 @@ class OpenWebUIStats:
for i, post in enumerate(stats["posts"], 1):
title_link = f"[{post['title']}]({post['url']})"
# 使用 get_badge 处理单个帖子的下载和浏览量徽章 (仅前 10 个使用索引,其余使用通用处理或暂留静态)
# 为了报告的简洁,我们这里可以考虑对 Top 10 使用动态徽章,或者统一设计一种按 slug 获取的机制
# 简化方案:报告中我们直接用对应 key 的 get_badge
md.append(
f"| {i} | {title_link} | {post['type']} | {post['version']} | "
f"{post['downloads']} | {post['views']} | {post['upvotes']} | "
@@ -778,6 +790,48 @@ class OpenWebUIStats:
else:
print(f"⚠️ 徽章上传失败: {resp.status_code} {resp.text}")
def get_badge(
self,
key: str,
stats: dict,
user: dict,
delta: dict,
is_post: bool = False,
style: str = "flat",
) -> str:
"""获取 Shields.io 徽章 URL (包含增量显示)"""
import urllib.parse
gist_user = "Fu-Jie"
def _fmt_delta(k: str) -> str:
val = delta.get(k, 0)
if val > 0:
return f" <br><sub>(+{val}🚀)</sub>"
return ""
if not self.gist_id:
if is_post:
return "**-**"
val = stats.get(f"total_{key}", 0)
if key == "followers":
val = user.get("followers", 0)
if key == "points":
val = user.get("total_points", 0)
if key == "contributions":
val = user.get("contributions", 0)
if key == "posts":
val = stats.get("total_posts", 0)
if key == "saves":
val = stats.get("total_saves", 0)
return f"**{val}**{_fmt_delta(key)}"
raw_url = f"https://gist.githubusercontent.com/{gist_user}/{self.gist_id}/raw/badge_{key}.json"
encoded_url = urllib.parse.quote(raw_url, safe="")
return (
f"![{key}](https://img.shields.io/endpoint?url={encoded_url}&style={style})"
)
def generate_readme_stats(self, stats: dict, lang: str = "zh") -> str:
"""
生成 README 统计区域 (精简版)
@@ -827,33 +881,7 @@ class OpenWebUIStats:
lines.append(f"> {t['updated']}")
lines.append("")
# 定义徽章 URL (使用 Gist ID)
import urllib.parse
gist_user = "Fu-Jie"
def get_badge(key: str, is_post: bool = False, style: str = "flat") -> str:
if not self.gist_id:
# 降级:如果没有 Gist显示静态文本
if is_post:
return "**-**"
val = stats.get(f"total_{key}", 0)
if key == "followers":
val = user.get("followers", 0)
if key == "points":
val = user.get("total_points", 0)
if key == "contributions":
val = user.get("contributions", 0)
if key == "posts":
val = stats.get("total_posts", 0)
if key == "saves":
val = stats.get("total_saves", 0)
return f"**{val}**{fmt_delta(key)}"
# 对 Gist Raw URL 进行转义,确保 Shields.io 正确处理
raw_url = f"https://gist.githubusercontent.com/{gist_user}/{self.gist_id}/raw/badge_{key}.json"
encoded_url = urllib.parse.quote(raw_url, safe="")
return f"![{key}](https://img.shields.io/endpoint?url={encoded_url}&style={style})"
delta = self.get_stat_delta(stats)
# 作者信息表格
if user:
@@ -862,8 +890,8 @@ class OpenWebUIStats:
lines.append(t["author_header"])
lines.append("| :---: | :---: | :---: | :---: |")
lines.append(
f"| [{username}]({profile_url}) | {get_badge('followers')} | "
f"{get_badge('points')} | {get_badge('contributions')} |"
f"| [{username}]({profile_url}) | {self.get_badge('followers', stats, user, delta)} | "
f"{self.get_badge('points', stats, user, delta)} | {self.get_badge('contributions', stats, user, delta)} |"
)
lines.append("")
@@ -871,8 +899,8 @@ class OpenWebUIStats:
lines.append(t["header"])
lines.append("| :---: | :---: | :---: | :---: | :---: |")
lines.append(
f"| {get_badge('posts')} | {get_badge('downloads')} | "
f"{get_badge('views')} | {get_badge('upvotes')} | {get_badge('saves')} |"
f"| {self.get_badge('posts', stats, user, delta)} | {self.get_badge('downloads', stats, user, delta)} | "
f"{self.get_badge('views', stats, user, delta)} | {self.get_badge('upvotes', stats, user, delta)} | {self.get_badge('saves', stats, user, delta)} |"
)
lines.append("")
@@ -886,8 +914,8 @@ class OpenWebUIStats:
idx = i + 1
medal = medals[i] if i < len(medals) else str(idx)
dl_cell = get_badge(f"p{idx}_dl", is_post=True)
vw_cell = get_badge(f"p{idx}_vw", is_post=True)
dl_cell = self.get_badge(f"p{idx}_dl", stats, user, delta, is_post=True)
vw_cell = self.get_badge(f"p{idx}_vw", stats, user, delta, is_post=True)
lines.append(
f"| {medal} | [{post['title']}]({post['url']}) | {post['version']} | {dl_cell} | {vw_cell} | {post['updated_at']} |"