diff --git a/.github/workflows/community-stats.yml b/.github/workflows/community-stats.yml index 801e70e..434985c 100644 --- a/.github/workflows/community-stats.yml +++ b/.github/workflows/community-stats.yml @@ -38,9 +38,12 @@ jobs: id: old_stats run: | if [ -f docs/community-stats.json ]; then + cp docs/community-stats.json docs/community-stats.json.old echo "total_posts=$(jq -r '.total_posts // 0' docs/community-stats.json)" >> $GITHUB_OUTPUT + echo "versions=$(jq -r '[.posts[] | {slug: .slug, version: .version}] | sort_by(.slug) | map("\(.slug):\(.version)") | join(",")' docs/community-stats.json)" >> $GITHUB_OUTPUT else echo "total_posts=0" >> $GITHUB_OUTPUT + echo "versions=" >> $GITHUB_OUTPUT fi - name: Generate stats report @@ -56,12 +59,15 @@ jobs: id: new_stats run: | echo "total_posts=$(jq -r '.total_posts // 0' docs/community-stats.json)" >> $GITHUB_OUTPUT + echo "versions=$(jq -r '[.posts[] | {slug: .slug, version: .version}] | sort_by(.slug) | map("\(.slug):\(.version)") | join(",")' docs/community-stats.json)" >> $GITHUB_OUTPUT - name: Check for significant changes id: check_changes run: | OLD_POSTS="${{ steps.old_stats.outputs.total_posts }}" NEW_POSTS="${{ steps.new_stats.outputs.total_posts }}" + OLD_VERSIONS="${{ steps.old_stats.outputs.versions }}" + NEW_VERSIONS="${{ steps.new_stats.outputs.versions }}" SHOULD_COMMIT="false" CHANGE_REASON="" @@ -69,14 +75,20 @@ jobs: if [ "$NEW_POSTS" -gt "$OLD_POSTS" ]; then SHOULD_COMMIT="true" CHANGE_REASON="new plugin added ($OLD_POSTS -> $NEW_POSTS)" - echo "đŸ“Ļ New plugin detected: $OLD_POSTS -> $NEW_POSTS" + elif [ "$NEW_POSTS" -lt "$OLD_POSTS" ]; then + SHOULD_COMMIT="true" + CHANGE_REASON="plugin removed ($OLD_POSTS -> $NEW_POSTS)" + elif [ "$OLD_VERSIONS" != "$NEW_VERSIONS" ]; then + SHOULD_COMMIT="true" + CHANGE_REASON="plugin versions updated" + echo "🔄 Version change detected" fi echo "should_commit=$SHOULD_COMMIT" >> $GITHUB_OUTPUT echo "change_reason=$CHANGE_REASON" >> $GITHUB_OUTPUT if [ "$SHOULD_COMMIT" = "false" ]; then - echo "â„šī¸ No significant changes detected, skipping commit" + echo "â„šī¸ No significant changes (posts or versions), skipping commit" else echo "✅ Significant changes detected: $CHANGE_REASON" fi diff --git a/scripts/openwebui_stats.py b/scripts/openwebui_stats.py index 1973d3c..6f5efef 100644 --- a/scripts/openwebui_stats.py +++ b/scripts/openwebui_stats.py @@ -277,12 +277,37 @@ class OpenWebUIStats: }, } + def _get_plugin_obj(self, post: dict) -> dict: + """Extract the actual plugin object from post['data'] (handling different keys like function/tool/pipe).""" + data = post.get("data", {}) or {} + if not data: + return {} + + # Priority 1: Use post['type'] as the key (standard behavior) + post_type = post.get("type") + if post_type and post_type in data and data[post_type]: + return data[post_type] + + # Priority 2: Fallback to 'function' (most common for actions/filters/pipes) + if "function" in data and data["function"]: + return data["function"] + + # Priority 3: Try other known keys + for k in ["tool", "pipe", "action", "filter", "prompt", "model"]: + if k in data and data[k]: + return data[k] + + # Priority 4: If there's only one key in data, assume that's the one + if len(data) == 1: + return list(data.values())[0] or {} + + return {} + def _resolve_post_type(self, post: dict) -> str: """Resolve the post category type""" top_type = post.get("type") - function_data = post.get("data", {}) or {} - function_obj = function_data.get("function", {}) or {} - meta = function_obj.get("meta", {}) or {} + plugin_obj = self._get_plugin_obj(post) + meta = plugin_obj.get("meta", {}) or {} manifest = meta.get("manifest", {}) or {} # Category identification priority: @@ -292,8 +317,8 @@ class OpenWebUIStats: post_type = "unknown" if meta.get("type"): post_type = meta.get("type") - elif function_obj.get("type"): - post_type = function_obj.get("type") + elif plugin_obj.get("type"): + post_type = plugin_obj.get("type") elif top_type: post_type = top_type elif not meta and not function_obj: @@ -302,7 +327,7 @@ class OpenWebUIStats: post_type = self._normalize_post_type(post_type) # Unified and heuristic identification logic - if post_type == "unknown" and function_obj: + if post_type == "unknown" and plugin_obj: post_type = "action" if post_type == "action" or post_type == "unknown": @@ -600,9 +625,8 @@ class OpenWebUIStats: for post in posts: post_type = self._resolve_post_type(post) - function_data = post.get("data", {}) or {} - function_obj = function_data.get("function", {}) or {} - meta = function_obj.get("meta", {}) or {} + plugin_obj = self._get_plugin_obj(post) + meta = plugin_obj.get("meta", {}) or {} manifest = meta.get("manifest", {}) or {} # Accumulate statistics