Add ecosystem growth metrics mode

Add four-repository ecosystem aggregation to the growth metrics script, update the growth plan to use it, and cover the new path with unit tests.
This commit is contained in:
zhifu gao
2026-06-30 10:04:34 +08:00
committed by GitHub
parent 6dd389f524
commit 2bd721ec55
3 changed files with 255 additions and 17 deletions
+118 -14
View File
@@ -14,10 +14,18 @@ import os
import sys
import urllib.error
import urllib.request
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Sequence
DEFAULT_REPO = "modelscope/FunASR"
DEFAULT_ECOSYSTEM_REPOS = [
"modelscope/FunASR",
"FunAudioLLM/Fun-ASR",
"FunAudioLLM/SenseVoice",
"modelscope/FunClip",
]
DEFAULT_PACKAGE = "funasr"
DEFAULT_BASELINE_STARS = 31224
DEFAULT_TARGET_ADDITIONAL_STARS = 20000
def fetch_json(url: str, headers: Optional[Dict[str, str]] = None) -> Any:
@@ -44,23 +52,27 @@ def github_headers() -> Dict[str, str]:
return headers
def collect_metrics(repo: str, package: str) -> Dict[str, Any]:
def collect_github_repo_metrics(repo: str) -> Dict[str, Any]:
owner_repo = repo.strip("/")
github = fetch_json(f"https://api.github.com/repos/{owner_repo}", github_headers())
return {
"repo": owner_repo,
"stars": github.get("stargazers_count"),
"forks": github.get("forks_count"),
"watchers": github.get("subscribers_count"),
"open_issues": github.get("open_issues_count"),
"default_branch": github.get("default_branch"),
"pushed_at": github.get("pushed_at"),
"html_url": github.get("html_url"),
}
def collect_metrics(repo: str, package: str) -> Dict[str, Any]:
github = collect_github_repo_metrics(repo)
pypi = fetch_json(f"https://pypi.org/pypi/{package}/json", {"User-Agent": "funasr-growth-metrics"})
latest_release = github.get("pushed_at")
metrics = {
"collected_at_utc": dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat(),
"github": {
"repo": owner_repo,
"stars": github.get("stargazers_count"),
"forks": github.get("forks_count"),
"watchers": github.get("subscribers_count"),
"open_issues": github.get("open_issues_count"),
"default_branch": github.get("default_branch"),
"pushed_at": latest_release,
"html_url": github.get("html_url"),
},
"github": github,
"pypi": {
"package": package,
"version": pypi.get("info", {}).get("version"),
@@ -71,6 +83,36 @@ def collect_metrics(repo: str, package: str) -> Dict[str, Any]:
return metrics
def collect_ecosystem_metrics(
repos: Sequence[str],
package: str,
baseline_stars: int,
target_additional_stars: int,
) -> Dict[str, Any]:
repositories = [collect_github_repo_metrics(repo) for repo in repos]
pypi = fetch_json(f"https://pypi.org/pypi/{package}/json", {"User-Agent": "funasr-growth-metrics"})
total_stars = sum(repo.get("stars") or 0 for repo in repositories)
added_stars = total_stars - baseline_stars
remaining_to_target = max(target_additional_stars - added_stars, 0)
return {
"collected_at_utc": dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat(),
"ecosystem": {
"repositories": repositories,
"total_stars": total_stars,
"baseline_stars": baseline_stars,
"target_additional_stars": target_additional_stars,
"added_stars": added_stars,
"remaining_to_target": remaining_to_target,
},
"pypi": {
"package": package,
"version": pypi.get("info", {}).get("version"),
"summary": pypi.get("info", {}).get("summary"),
"project_url": pypi.get("info", {}).get("project_url"),
},
}
def format_markdown(metrics: Dict[str, Any], star_goal: int) -> str:
github = metrics["github"]
pypi = metrics["pypi"]
@@ -96,11 +138,63 @@ def format_markdown(metrics: Dict[str, Any], star_goal: int) -> str:
return "\n".join(lines) + "\n"
def format_ecosystem_markdown(metrics: Dict[str, Any]) -> str:
ecosystem = metrics["ecosystem"]
pypi = metrics["pypi"]
lines = [
f"# FunASR Ecosystem Growth Snapshot ({metrics['collected_at_utc']})",
"",
f"- Combined GitHub stars: **{ecosystem['total_stars']:,}**",
f"- Baseline stars: **{ecosystem['baseline_stars']:,}**",
f"- Added since baseline: **{ecosystem['added_stars']:,}** / {ecosystem['target_additional_stars']:,}",
f"- Remaining to target: **{ecosystem['remaining_to_target']:,}**",
f"- PyPI package: **{pypi.get('package')} {pypi.get('version')}**",
"",
"## Repositories",
"",
"| Repository | Stars | Forks | Open issues | Last push |",
"|---|---:|---:|---:|---|",
]
for repo in ecosystem["repositories"]:
lines.append(
f"| [{repo['repo']}]({repo.get('html_url')}) | "
f"{(repo.get('stars') or 0):,} | "
f"{(repo.get('forks') or 0):,} | "
f"{(repo.get('open_issues') or 0):,} | "
f"`{repo.get('pushed_at')}` |"
)
lines.extend(
[
"",
"## Links",
"",
f"- PyPI: {pypi.get('project_url')}",
"- GitHub Pages: https://modelscope.github.io/FunASR/",
"- Trendshift: https://trendshift.io/repositories/10479",
]
)
return "\n".join(lines) + "\n"
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Collect FunASR growth metrics.")
parser.add_argument("--repo", default=DEFAULT_REPO, help="GitHub repository, e.g. modelscope/FunASR")
parser.add_argument(
"--repos",
nargs="+",
default=DEFAULT_ECOSYSTEM_REPOS,
help="GitHub repositories for --ecosystem mode",
)
parser.add_argument("--ecosystem", action="store_true", help="Collect the four-repository FunASR ecosystem")
parser.add_argument("--pypi-package", default=DEFAULT_PACKAGE, help="PyPI package name")
parser.add_argument("--star-goal", type=int, default=20000, help="Target GitHub star count")
parser.add_argument("--baseline-stars", type=int, default=DEFAULT_BASELINE_STARS, help="Ecosystem baseline stars")
parser.add_argument(
"--target-additional-stars",
type=int,
default=DEFAULT_TARGET_ADDITIONAL_STARS,
help="Ecosystem added-star target",
)
parser.add_argument("--format", choices=["markdown", "json"], default="markdown", help="Output format")
return parser.parse_args()
@@ -108,13 +202,23 @@ def parse_args() -> argparse.Namespace:
def main() -> int:
args = parse_args()
try:
metrics = collect_metrics(args.repo, args.pypi_package)
if args.ecosystem:
metrics = collect_ecosystem_metrics(
args.repos,
args.pypi_package,
args.baseline_stars,
args.target_additional_stars,
)
else:
metrics = collect_metrics(args.repo, args.pypi_package)
except RuntimeError as exc:
print(exc, file=sys.stderr)
return 1
if args.format == "json":
print(json.dumps(metrics, ensure_ascii=False, indent=2))
elif args.ecosystem:
print(format_ecosystem_markdown(metrics), end="")
else:
print(format_markdown(metrics, args.star_goal), end="")
return 0