使用 Hugging Face REST API 构建 Hackathon 参与度积分排行榜:hf-skills 的 hackers-leaderboard 实现解析
【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub
导读
本文以hugging-face-skills项目中的 hackers-leaderboard 应用为对象,讲解如何基于 Hugging Face 开放的 REST API,自动统计一个组织(如hf-skills)在 Models、Datasets、Spaces 三类仓库上的讨论、评论、PR 与仓库所有权等活动数据,并按"一次活动记一分"的规则生成可发布的排行榜。读者阅读后将掌握:积分数据采集器collect_points.py的完整工作流、外部 Trending 仓库扫描的扩展用法、结果向 Hugging Face Dataset 推送的发布流程,以及基于 Gradio 的排行榜展示页app.py的实现思路,可据此为自己的组织或社区活动搭建同类"贡献力看板"。
一、背景:为 Hackathon 贡献行为设计一套可自动计量的积分体系
该应用是 Hugging Facehf-skills组织在 2025 年底社区 Hackathon 期间使用的活动组件之一。同目录下的 quests/README.md 显示,这场为期四周的黑客马拉松通过"用 Coding Agent 升级开源 AI 生态"的方式组织参与,参与者需要在 hf-skills 组织 下评估模型、发布数据集、微调并共享模型,每一次贡献都折算成 XP,最终进入排行榜角逐奖励。
Hackathon 活动天然需要一套"公平、可解释、能自动化运行"的积分规则。Hackers Leaderboard 给出的答案是异常简单直接的一套度量标准:不看代码质量主观打分,只看客观可数的一等公民动作。其 README 开篇即声明:
| 活动 | 分值 |
|---|---|
| 💬 开启一个 Discussion | 1 |
| 📝 发表一条评论 | 1 |
| 🔀 开启一个 PR | 1 |
| 📦 拥有 / 创建一个仓库 | 1 |
之所以说它"简单且公平",是因为上述四类事件都能通过 Hugging Face 公开 API 稳定枚举(不依赖解析 HTML),天然适合写成定时任务批量拉取。仓库中的collect_points.py就是这套规则的程序化表达,app.py则是结果的公开展示层。
二、项目结构与运行环境
该组件位于仓库 hugging-face-skills/apps/hackers-leaderboard,共四个文件,职责划分清晰:
- README.md:计分规则、CLI 用法、Options 表与输出格式说明,即本文展开的主体文档;
- collect_points.py:纯 Python 实现的积分采集器,负责从 Hub API 抓取活动并汇总为 JSON/JSONL;
- app.py:基于 Gradio 5.x 的排行榜 Web 展示页,直接读取已发布的 Dataset;
- requirements.txt:声明依赖
gradio>=5.50.0、huggingface_hub>=1.1.4、requests>=2.32.5。
值得说明的是,该目录下另一姐妹应用 evals-leaderboard(由
collect_evals.py+app.py组成)负责的是模型评测结果的排行榜,与本组件的"参与度积分排行榜"是两个独立的子系统,本文不展开评测部分。
2.1 环境准备
在运行采集器前,建议先创建独立的 Python 环境并按 requirements.txt 安装依赖:
pip install -r hugging-face-skills/apps/hackers-leaderboard/requirements.txtcollect_points.py使用requests调用 REST API(可独立工作),huggingface_hub则负责两个可选能力:拉取组织成员列表(见 collect_points.py)与向 Hub 上传数据集结果(见push_to_hub)。即使不传HF_TOKEN也能运行,脚本在 main 中只会给出"可能被限流"的警告,这说明采集器在设计上保证了对匿名访问的容错,但写操作(--push-to-hub)必须携带具备写权限的 HF_TOKEN。
三、CLI 用法与全部选项
文档给出了采集器完整可复用的命令行形态。以下命令均应在项目目录内执行(HF_TOKEN=$HF_TOKEN仅为环境变量注入示例,实际按你的 shell 习惯导出即可)。
基础用法:只统计组织仓库内活动
HF_TOKEN=$HF_TOKEN python collect_points.py进阶用法:额外扫描外部 Trending 仓库
HF_TOKEN=$HF_TOKEN python collect_points.py --scan-external按需限定扫描的仓库类型
HF_TOKEN=$HF_TOKEN python collect_points.py --scan-external --repo-type models HF_TOKEN=$HF_TOKEN python collect_points.py --scan-external --repo-type models datasets采集完成后直接推送为 HF Dataset
HF_TOKEN=$HF_TOKEN python collect_points.py --scan-external --push-to-hub自定义本地输出文件与目标数据集仓库
python collect_points.py --output my_leaderboard.json --repo-id my-org/my-dataset对应的参数解析位于 collect_points.py,除--scan-external与--push-to-hub为布尔开关外,其余均为可选参数。全部选项汇总如下:
| Flag | 说明 |
|---|---|
--scan-external | 开启外部扫描:在 Hub Trending 仓库中查找组织成员的 PR 与 Discussion 活动 |
--repo-type | 限定外部扫描的仓库类型,可选models、datasets、spaces,可重复/多值传入;不指定则默认扫描全部三类(见scan_external_repos中默认值["models", "datasets", "spaces"]) |
--push-to-hub | 将统计结果推送到 HF Dataset |
--repo-id | 目标数据集仓库 ID,默认hf-skills/hackers-leaderboard |
--output | 本地 JSON 输出路径,默认leaderboard.json |
命令行默认只打印积分 Top 20 并保存本地 JSON(见 main),最终是否发布到 Hub 完全由--push-to-hub决定,因此你可以先本地试跑校对规则,再决定发布。
四、采集器工作流:数据从 Hub 到 JSONL 的完整链路
collect_points.py的核心是PointsCollector类(源码定义)。它的整体流程由collect_all()与可选的scan_external_repos()串联,下面逐环节拆解其底层实现。
4.1 组织成员与三类仓库枚举
collect_all()首先通过_fetch_org_members()拉取组织全部成员并初始化其统计对象(外部贡献者在后续按需创建,is_org_member置为False,见_add_point中 L375-L377),随后分别请求:
GET /api/models?author=hf-skills&limit=1000 GET /api/datasets?author=hf-skills&limit=1000 GET /api/spaces?author=hf-skills&limit=1000即_list_repos()中端点API_BASE/{repo_type}配合author过滤的实现(L287-L298)。拿到全部仓库后,代码把三类仓库统一标成model / dataset / space的内部类型,再逐个仓库继续处理。
4.2 逐仓库扫描:信用归属与讨论枚举
对每个仓库,采集器先做仓库所有者的信用归属:只有所有者不是组织本身(owner != ORG_NAME)时才加repos_owned分——因为组织统一创建的仓库不计入任何个人名下。紧接着调用_scan_discussions()走讨论枚举:
GET /api/{models|datasets|spaces}/{namespace}/{repo}/discussions?limit=100该请求复用DISCUSSION_LIMIT = 100的页大小上限(L31)。拿到discussions数组后逐条执行_process_discussion():
- 判断
isPullRequest字段:为 PR 则记prs_opened,否则记discussions_opened,作者为组织本身的讨论一律跳过; - 只要讨论存在编号
num,就再请求一次讨论详情GET /api/{type}/{repo_id}/discussions/{disc_num},通过events列表中type == "comment"的事件统计评论数(_fetch_comments(),L341-L361)。代码注释明确只统计comment事件,"不计入初始帖、状态变更等",因此不会把"开启讨论"本身重复计入评论分。
所有加分统一走_add_point()(L363-L390),它在累加四类计数之外还会把每条活动的{type, repo_id, discussion_num, timestamp}追加进activities列表,形成可追溯的活动明细——这正是 README 中"支持按活动明细审计"的实现基础,也是后续扩展成事件流分析的关键预留。
4.3 每讨论一次点,统计由 UserStats 精确聚合
UserStats(dataclass 定义)负责单用户的聚合状态,四个计数字段与总分的映射关系如下(与文档计分表一一对应):
@property def total_points(self) -> int: return self.discussions_opened + self.comments_made + self.prs_opened + self.repos_owned由于每一类活动都恰好对应 1 分,总分就是四个计数之和,get_leaderboard()再按total_points降序排列输出(L392-L396),这从实现上保证了 README 表格"1 point per activity"规则的严格一致,不会出现加权或重叠计分的歧义。
五、外部扫描模式:把组织影响力扩散到整个 Hub
组织仓库的活动统计只能覆盖成员在自家仓库内的行为。Hackathon 中许多高分玩法是"去别人家仓库提 PR/留讨论"(例如为热门模型贡献评测),这些行为同样值得计分,这正是--scan-external存在的意义。
scan_external_repos()(L143-L175)的逻辑分两层:
- 按类型拉取当前 Hub 的 Trending 仓库列表(
GET /api/{type}?sort=trendingScore&limit=50,常量TRENDING_LIMIT = 50,L177-L188); - 对每个非组织仓库(跳过
hf-skills/前缀,避免与组织内扫描重复),按成员逐个用 author 过滤查询该仓库上的活动:
GET /api/{type}/{namespace}/{repo}/discussions?author={member}&type=pull_request&status=all GET /api/{type}/{namespace}/{repo}/discussions?author={member}&type=discussion&status=all这是_fetch_member_discussions()(L215-L258)的实现。利用author+type+status=all的查询参数组合,可以精确命中某成员在某仓库的开 PR / 开讨论记录;若命中且该讨论存在评论(numComments > 0),再走_fetch_discussion_comments()补齐评论计分。
从设计上可以推断,这种"先枚举 Trending 再按成员过滤"的双层扫描把请求量控制在了成员数 × 50 × 每成员 2 类查询的有限量级内,比"遍历全 Hub"可行得多,但它天然只覆盖扫描时刻在 Trending 榜单上的仓库,因此 README 也把外部模式定位为组织内部统计的补充而非替代。
5.1 三种典型调用形态的取舍
| 运行方式 | 覆盖范围 | 典型使用时机 |
|---|---|---|
python collect_points.py | 组织内全部 models/datasets/spaces | 日常基线统计,口径最稳定 |
追加--scan-external | 上述内容 + 当前 Trending 外部仓库 | 结算前扩大采集窗口,避免漏掉外部贡献 |
追加--scan-external --repo-type datasets | 仅扫描 Trending 数据集 | 本期 Hackathon 主题为数据集周时定向结算 |
六、输出与发布:本地 JSON、排行榜排序与 HF Dataset 推送
6.1 本地输出格式
文档明确采集结果会保存为JSONL(Dataset 消费友好),同时本地文件以 JSON 落地。save_json()(L398-L409)在单条用户记录之外又包了一层元信息,生成如下结构:
{ "generated_at": "2026-01-01T00:00:00+00:00", "organization": "hf-skills", "total_participants": 42, "leaderboard": [ { "username": "user123", "is_org_member": true, "total_points": 15, "discussions_opened": 3, "comments_made": 8, "prs_opened": 2, "repos_owned": 2 } ] }其中单用户对象的字段(UserStats.to_dict)与 README 给出的示例完全一致,额外还携带is_org_member布尔字段,用于区分组织成员与外部贡献者——外部贡献者因为没有repos_owned等组织内动作,通常总分偏低,标记字段可避免榜单解读时产生误解。
6.2 推送为 HF Dataset
--push-to-hub触发push_to_hub()(L411-L458)。该函数使用huggingface_hub的HfApi完成三步:
create_repo(repo_id, repo_type="dataset", exist_ok=True)确保目标数据集仓库存在,可重复执行而不会因已存在报错;- 将 Leaderboard 逐行序列化为 JSONL 上传到
data/leaderboard.jsonl; - 将包含
generated_at、total_participants、total_points的元数据以缩进 JSON 上传到data/metadata.json,提交信息附带 UTC 时间戳便于版本追踪。
默认目标为hf-skills/hackers-leaderboard,可通过--repo-id覆盖为任意自有数据集仓库。可以这样安排定时发布:把带--push-to-hub的命令挂进 cron,每次结算自动覆盖data/*下的两个文件,Dataset 的历史版本由 Hub 自动保留。
6.3 Gradio 展示应用如何读取数据
app.py 是整个系统的"只读前端":它不直接调用采集器,而是通过requests拉取已发布 Dataset 的 raw 文件(L33-L35):
LEADERBOARD_URL = "https://huggingface.co/datasets/hf-skills/hackers-leaderboard/raw/main/data/leaderboard.jsonl" METADATA_URL = "https://huggingface.co/datasets/hf-skills/hackers-leaderboard/raw/main/data/metadata.json"fetch_leaderboard()将 JSONL 逐行解析成记录数组,并同步读取元数据;refresh_handler()(L58-L86)负责把记录渲染成表格行——从源码看,当前版本的列表行由"排名、可点击的用户名(Markdown 链接指向其 Hub 主页)、以 PR 数为计的分值"构成(排名从 1 开始由行号生成),状态栏则以 Markdown 展示数据来源、最近更新时间、参与人数与总积分。页面通过gr.Blocks()布局,并在demo.load钩子中绑定刷新函数,因此打开页面即自动加载最新数据,无需手动点击。
运行展示页只需:
HF_TOKEN=$HF_TOKEN python app.py部署提示:该目录 README 的 YAML frontmatter 声明了
sdk: gradio、sdk_version: 5.50.0、app_file: app.py,这组字段正是 Hugging Face Spaces 原生识别的配置,意味着采集器输出 Dataset 后,把app.py本体部署为 Space 即可对外公开排行榜,实现"采集器定时写库、Space 只读展示"的职责分离架构。
七、实战:从克隆到跑通一次完整结算
将以上环节串成一个最小可执行的结算流程:
- 安装依赖:
pip install -r hugging-face-skills/apps/hackers-leaderboard/requirements.txt; - 首次运行采集(可匿名,但建议带 token 以降低限流风险):
HF_TOKEN=$HF_TOKEN python hugging-face-skills/apps/hackers-leaderboard/collect_points.py此时会在当前目录生成
leaderboard.json并打印 Top 20 榜单; - 核对积分口径:打开
leaderboard.json,把discussions_opened / comments_made / prs_opened / repos_owned四字段累加后与total_points比对(实现上二者必然相等,可作为自检手段); - 决定是否扩大范围:需要统计成员在外部 Trending 仓库的贡献时追加
--scan-external,想限定仓库类型再追加--repo-type; - 发布到 Hub:追加
--push-to-hub(必须配置具写权限的HF_TOKEN),确认输出 Dataset 仓库下出现data/leaderboard.jsonl与data/metadata.json; - 上线展示:以
app.py为app_file在 Spaces 部署,或在本地运行python app.py预览。
八、结合仓库源码的注意事项与扩展思路
- 请求量与限流:
_list_repos每类单次请求即取limit=1000的仓库列表,随后对每个仓库的讨论与评论做多次 API 调用,属于典型的 N+1 模式。成员越多、仓库越大,请求数越可观,运行时应留意 HF API 的限流策略,必要时错峰执行;无 token 时脚本虽不中断,但更易触发限流。 - 组织成员获取的降级路径:
_fetch_org_members()首选huggingface_hub的HfApi.list_organization_members(),失败时降级为直接请求GET /api/organizations/hf-skills/members并兼容user / username / name三种响应字段(L92-L104),说明采集器对 API 演进有一定容忍度。 - 展示口径与采集口径的解耦:README 示例的单用户 JSON 含完整四维计数,而当前
app.py的表格行主要填充 PR 数一维字段(表头保留了讨论列占位)。如果想完整呈现四类活动,可参照refresh_handler的行构建逻辑扩展为全字段多列渲染——这属于前端展示的可选增强,不影响底层采集与数据完整性。 - 扩展复用点:
UserStats.activities明细、--repo-type参数化、--output / --repo-id覆盖机制都已内置,如需为"不同主题周使用不同计分口径"或"输出为 CSV"做扩展,改动都集中在_add_point聚合与save_json / push_to_hub序列化层,可作为二次开发的入手位置。
总结
Hackers Leaderboard 是一个把"Hugging Face 组织活动计量"落到实处的完整范例:以 README 约定的四项计分规则为契约,collect_points.py 用约 200 行核心逻辑完成了从组织仓库枚举、讨论/评论/PR 逐层拉取到按用户聚合、排序、落盘与 Dataset 发布的全链路,app.py 再以 Gradio 提供公开可刷新的展示层。整套设计展示了"公开 REST API + JSONL 数据交换 + Spaces 只读前端"这一轻量数据产品架构的可行性:不依赖私有数据库,不依赖服务端定时框架,甚至采集器与展示页可以完全解耦运行。若你要为某个社区组织搭建贡献度看板,这套组件从规则定义、采集实现到发布展示均提供了可直接借鉴的代码级参考。
【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考