diff --git a/.github/workflows/community-stats.yml b/.github/workflows/community-stats.yml index c898298..37828cd 100644 --- a/.github/workflows/community-stats.yml +++ b/.github/workflows/community-stats.yml @@ -1,5 +1,5 @@ # OpenWebUI 社区统计报告自动生成 -# 每小时自动获取并更新社区统计数据 +# 使用 GitHub Gist 存储动态徽章数据,避免频繁 commit name: Community Stats @@ -39,10 +39,52 @@ jobs: run: | python scripts/openwebui_stats.py - - name: Check for changes + - name: Upload badges to Gist + if: ${{ secrets.GIST_TOKEN != '' && secrets.GIST_ID != '' }} + env: + GIST_TOKEN: ${{ secrets.GIST_TOKEN }} + GIST_ID: ${{ secrets.GIST_ID }} + run: | + # Upload each badge JSON to Gist + for badge in docs/badges/*.json; do + filename=$(basename "$badge") + content=$(cat "$badge" | jq -c '.') + + # Update Gist file + curl -s -X PATCH \ + -H "Authorization: token $GIST_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/gists/$GIST_ID" \ + -d "{\"files\":{\"$filename\":{\"content\":$content}}}" + + echo "✅ Uploaded $filename to Gist" + done + + - name: Check for significant changes id: check_changes run: | - git diff --quiet docs/community-stats.zh.md docs/community-stats.md README.md README_CN.md || echo "changed=true" >> $GITHUB_OUTPUT + # Only commit if there are changes to markdown files (not just time updates) + # This reduces commit frequency by only committing when actual data changes + + # Get current stats + NEW_DOWNLOADS=$(jq -r '.total_downloads' docs/community-stats.json 2>/dev/null || echo "0") + NEW_POSTS=$(jq -r '.total_posts' docs/community-stats.json 2>/dev/null || echo "0") + + # Get previous stats from git + OLD_DOWNLOADS=$(git show HEAD:docs/community-stats.json 2>/dev/null | jq -r '.total_downloads' 2>/dev/null || echo "0") + OLD_POSTS=$(git show HEAD:docs/community-stats.json 2>/dev/null | jq -r '.total_posts' 2>/dev/null || echo "0") + + echo "Previous: $OLD_DOWNLOADS downloads, $OLD_POSTS posts" + echo "Current: $NEW_DOWNLOADS downloads, $NEW_POSTS posts" + + # Only mark as changed if downloads or posts count changed + if [ "$NEW_DOWNLOADS" != "$OLD_DOWNLOADS" ] || [ "$NEW_POSTS" != "$OLD_POSTS" ]; then + echo "changed=true" >> $GITHUB_OUTPUT + echo "📊 Stats changed, will commit" + else + echo "changed=false" >> $GITHUB_OUTPUT + echo "⏭️ No significant changes, skipping commit" + fi - name: Commit and push changes if: steps.check_changes.outputs.changed == 'true' diff --git a/scripts/openwebui_stats.py b/scripts/openwebui_stats.py index 1a22df7..0df96ae 100644 --- a/scripts/openwebui_stats.py +++ b/scripts/openwebui_stats.py @@ -331,6 +331,67 @@ class OpenWebUIStats: json.dump(stats, f, ensure_ascii=False, indent=2) print(f"✅ JSON 数据已保存到: {filepath}") + def generate_shields_endpoints(self, stats: dict, output_dir: str = "docs/badges"): + """ + 生成 Shields.io endpoint JSON 文件 + + Args: + stats: 统计数据 + output_dir: 输出目录 + """ + Path(output_dir).mkdir(parents=True, exist_ok=True) + + def format_number(n: int) -> str: + """格式化数字为易读格式""" + if n >= 1000000: + return f"{n/1000000:.1f}M" + elif n >= 1000: + return f"{n/1000:.1f}k" + return str(n) + + # 各种徽章数据 + badges = { + "downloads": { + "schemaVersion": 1, + "label": "downloads", + "message": format_number(stats["total_downloads"]), + "color": "blue", + "namedLogo": "openwebui", + }, + "plugins": { + "schemaVersion": 1, + "label": "plugins", + "message": str(stats["total_posts"]), + "color": "green", + }, + "followers": { + "schemaVersion": 1, + "label": "followers", + "message": format_number(stats.get("user", {}).get("followers", 0)), + "color": "blue", + }, + "points": { + "schemaVersion": 1, + "label": "points", + "message": format_number(stats.get("user", {}).get("total_points", 0)), + "color": "orange", + }, + "upvotes": { + "schemaVersion": 1, + "label": "upvotes", + "message": format_number(stats["total_upvotes"]), + "color": "brightgreen", + }, + } + + for name, data in badges.items(): + filepath = Path(output_dir) / f"{name}.json" + with open(filepath, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2) + print(f" 📊 Generated badge: {name}.json") + + print(f"✅ Shields.io endpoints saved to: {output_dir}/") + def generate_readme_stats(self, stats: dict, lang: str = "zh") -> str: """ 生成 README 统计徽章区域 @@ -537,6 +598,10 @@ def main(): json_path = script_dir / "docs" / "community-stats.json" stats_client.save_json(stats, str(json_path)) + # 生成 Shields.io endpoint JSON (用于动态徽章) + badges_dir = script_dir / "docs" / "badges" + stats_client.generate_shields_endpoints(stats, str(badges_dir)) + # 更新 README 文件 readme_path = script_dir / "README.md" readme_cn_path = script_dir / "README_CN.md"