refactor: 重构多源数据入库架构,移除任务派发器并优化并行处理

核心变更:
- 移除 task-dispatcher agent,将并行调度逻辑迁移至 add-trending 命令
- 重构 project-analyzer 支持单任务处理模式(通过 taskId 参数)
- 优化并行处理策略:固定 3 实例分批处理,避免文件竞争
- 改进任务状态管理:pending → processing → completed/failed
- 各 scraper 增加输出文件规范说明

文件变更:
- 删除: .claude/agents/task-dispatcher.md
- 修改: .claude/agents/project-analyzer.md(单任务模式、状态机)
- 修改: .claude/commands/add-trending.md(直接并行调度)
- 修改: .claude/settings.json(代理配置注释)
- 新增: prisma/migrations/、scripts/scrape-huggingface.js

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-06 20:59:16 +08:00
co-authored by Claude
parent 3bbf481008
commit 2d3796da43
11 changed files with 427 additions and 270 deletions
-1
View File
@@ -10,7 +10,6 @@ description: |
输入参数:{"workspace": ".trending-workspace/..."}
model: inherit
color: green
tools: Read, Write, Bash
---
# 批量入库器 Agent
-1
View File
@@ -10,7 +10,6 @@ description: |
输入参数:{"workspace": ".trending-workspace/..."}
model: inherit
color: purple
tools: Read, Write, Bash
---
# 统一去重器 Agent
+86 -68
View File
@@ -10,7 +10,6 @@ description: |
输入参数:{"workspace": ".trending-workspace/..."}
model: inherit
color: blue
tools: Read, Write, Bash
---
# 项目分析器 Agent
@@ -29,21 +28,39 @@ tools: Read, Write, Bash
```json
{
"workspace": ".trending-workspace/..."
"workspace": ".trending-workspace/...",
"taskId": 5
}
```
**参数说明**:
- `workspace`: 工作区路径
- `taskId`: 要处理的单个任务 ID(对应 task-queue.json 中的任务编号)
## 执行步骤
### Step 1: 读取任务队列
从工作区读取 `task-queue.json`,获取所有 `status: "pending"`任务。
从工作区读取 `task-queue.json`,获取所有任务数据
### Step 2: 处理每个项目
### Step 2: 获取指定任务
对每个待处理项目:
根据 `taskId` 参数从任务队列中找到对应的任务。
#### 2.1 访问项目页面
**验证**:
- 确认任务存在
- 确认任务状态为 `pending`(避免重复处理)
- 如果任务状态不是 `pending`,直接退出并返回当前状态
### Step 3: 更新任务状态为 processing
将任务状态从 `pending` 更新为 `processing`(防止其他实例重复处理)。
### Step 4: 处理单个项目
对指定的项目执行以下操作:
#### 4.1 访问项目页面
使用 chrome-devtools-mcp 访问项目 URL
@@ -51,7 +68,7 @@ tools: Read, Write, Bash
- **Hugging Face 模型**: 访问 Hugging Face 模型页面
- **Papers with Code**: 访问项目/论文页面
#### 2.2 提取详细信息
#### 4.2 提取详细信息
从页面提取以下信息:
@@ -77,7 +94,7 @@ tools: Read, Write, Bash
- 任务类别
- 引用数
#### 2.3 理解项目价值(核心)
#### 4.3 理解项目价值(核心)
**项目用途**:项目能做什么?
- 核心功能是什么?
@@ -95,7 +112,7 @@ tools: Read, Write, Bash
从页面内容中提炼这些信息,用用户友好的语言描述。
#### 2.4 生成中英双语内容
#### 4.4 生成中英双语内容
**name / nameEn**: 项目名称翻译
- 通常保持英文名称不变
@@ -113,7 +130,7 @@ tools: Read, Write, Bash
- **技术特点**: 技术亮点
- **使用指南**: 快速开始或使用示例
#### 2.5 提取结构化标签(1-10 个)
#### 4.5 提取结构化标签(1-10 个)
从以下来源提取标签:
- GitHub Topics
@@ -133,7 +150,7 @@ tools: Read, Write, Bash
}
```
#### 2.6 构造外部链接数组(1-10 个)
#### 4.6 构造外部链接数组(1-10 个)
收集项目相关链接:
@@ -159,7 +176,7 @@ tools: Read, Write, Bash
}
```
#### 2.7 计算质量评分
#### 4.7 计算质量评分
总分 100 分,>= 40 分通过:
@@ -192,68 +209,69 @@ function calculateQualityScore(project): number {
}
```
#### 2.8 更新任务状态
#### 4.8 更新任务状态
将任务状态从 `pending` 更新为 `completed``failed`(质量不足)。
### Step 3: 输出分析结果
### Step 5: 更新任务状态为最终状态
输出 `analyzed-projects.json`
将任务状态从 `processing` 更新为
- `completed` - 质量评分 >= 40
- `failed` - 质量评分 < 40 或处理出错
### Step 6: 输出分析结果
输出 `analyzed-project-{taskId}.json`(避免多实例文件冲突):
**成功情况**
```json
{
"metadata": {
"totalTasks": 35,
"processed": 35,
"passed": 32,
"failed": 3,
"failureReasons": {
"lowQuality": 3
}
},
"projects": [
{
"source": "github",
"name": "LangChain",
"nameEn": "LangChain",
"description": "通过组合性构建大型语言模型应用程序的框架,支持链式调用、代理、工具集成等核心功能。",
"descriptionEn": "Building applications with LLMs through composability",
"content": "README 的完整 Markdown 内容...",
"contentEn": "README content...",
"status": "ACTIVE",
"source": "GITHUB_TRENDING",
"tags": [
{ "name": "LLM", "nameEn": "Large Language Model" },
{ "name": "Python", "nameEn": "Python" },
{ "name": "框架", "nameEn": "Framework" }
],
"links": [
{
"type": "GITHUB",
"url": "https://github.com/langchain-ai/langchain",
"title": "GitHub 仓库"
},
{
"type": "WEBSITE",
"url": "https://python.langchain.com",
"title": "官方文档"
}
],
"qualityScore": 85
}
]
"taskId": 5,
"success": true,
"project": {
"source": "github",
"name": "LangChain",
"nameEn": "LangChain",
"description": "通过组合性构建大型语言模型应用程序的框架,支持链式调用、代理、工具集成等核心功能。",
"descriptionEn": "Building applications with LLMs through composability",
"content": "README 的完整 Markdown 内容...",
"contentEn": "README content...",
"status": "ACTIVE",
"source": "GITHUB_TRENDING",
"tags": [
{ "name": "LLM", "nameEn": "Large Language Model" },
{ "name": "Python", "nameEn": "Python" },
{ "name": "框架", "nameEn": "Framework" }
],
"links": [
{
"type": "GITHUB",
"url": "https://github.com/langchain-ai/langchain",
"title": "GitHub 仓库"
},
{
"type": "WEBSITE",
"url": "https://python.langchain.com",
"title": "官方文档"
}
],
"qualityScore": 85
}
}
```
## 并行处理策略
支持多个 Project Analyzer 实例同时运行:
1. 每个实例读取 `task-queue.json`
2. 获取 `status: "pending"` 的第一个任务
3. 将任务状态更新为 `processing`(防止其他实例重复处理)
4. 处理任务
5. 将任务状态更新为 `completed``failed`
**失败情况**
```json
{
"taskId": 5,
"success": false,
"error": "质量评分不足",
"errorDetails": {
"qualityScore": 25,
"threshold": 40
}
}
```
## 错误处理
@@ -266,7 +284,7 @@ function calculateQualityScore(project): number {
## 输出
成功后,返回:
- 处理任务数量
- 通过质量评分的项目数量
- 失败项目数量及原因
- analyzed-projects.json 路径
- taskId处理任务 ID
- success(是否成功)
- 项目数据(成功时)或错误信息(失败时)
- analyzed-project-{taskId}.json 路径
+26 -1
View File
@@ -10,7 +10,6 @@ description: |
输入参数:{"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."}
model: inherit
color: black
tools: Read, Write, Bash
---
# GitHub Trending 爬虫
@@ -143,9 +142,35 @@ article.Box-row
| 无 AI 相关项目 | 返回空项目列表,提示 "未找到 AI 相关项目" |
| 数量不足 | 返回找到的所有项目,不报错 |
## 输出文件
将结果写入工作区:`scraped-github-projects.json`
```json
{
"source": "github",
"count": 25,
"projects": [
{
"source": "github",
"name": "langchain-ai/langchain",
"url": "https://github.com/langchain-ai/langchain",
"description": "Building applications with LLMs through composability",
"metadata": {
"stars": 85432,
"starsDelta": "+234 today",
"language": "Python",
"forks": 12543
}
}
]
}
```
## 输出
成功后,返回:
- 输出文件路径:`{workspace}/scraped-github-projects.json`
- 爬取的项目数量
- 过滤后的项目数量
- 项目列表
@@ -10,7 +10,6 @@ description: |
输入参数:{"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."}
model: inherit
color: yellow
tools: Read, Write, Bash
---
# Hugging Face Trending 爬虫
@@ -135,8 +134,34 @@ Hugging Face 页面结构可能动态变化,需要根据实际情况调整选
| 页面解析失败 | 返回空项目列表,记录错误 |
| 无模型数据 | 返回空项目列表 |
## 输出文件
将结果写入工作区:`scraped-huggingface-projects.json`
```json
{
"source": "huggingface",
"count": 25,
"projects": [
{
"source": "huggingface",
"name": "meta-llama/Llama-2-7b",
"url": "https://huggingface.co/meta-llama/Llama-2-7b",
"description": "Llama 2 is a collection of pretrained and fine-tuned generative text models...",
"metadata": {
"likes": 15234,
"downloads": 5000000,
"pipeline": "text-generation",
"task": "Text Generation"
}
}
]
}
```
## 输出
成功后,返回:
- 输出文件路径:`{workspace}/scraped-huggingface-projects.json`
- 爬取的模型数量
- 模型列表(按点赞数/下载量排序)
+26 -1
View File
@@ -10,7 +10,6 @@ description: |
输入参数:{"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."}
model: inherit
color: cyan
tools: Read, Write, Bash
---
# Papers with Code 爬虫
@@ -133,8 +132,34 @@ Papers with Code 页面结构可能动态变化,需要根据实际情况调整
| 页面解析失败 | 返回空项目列表,记录错误 |
| 无符合条件的论文 | 返回空项目列表 |
## 输出文件
将结果写入工作区:`scraped-paperswithcode-projects.json`
```json
{
"source": "paperswithcode",
"count": 25,
"projects": [
{
"source": "paperswithcode",
"name": "YOLOv7: Trainable bag-of-freebies sets new state-of-the-art",
"url": "https://github.com/WongKinYiu/yolov7",
"paperUrl": "https://paperswithcode.com/paper/yolov7-trainable-bag-of-freebies-sets-new",
"description": "YOLOv7 implements bag-of-freebies and bag-of-specials...",
"metadata": {
"stars": 8000,
"tasks": ["Object Detection", "Computer Vision"],
"framework": "PyTorch"
}
}
]
}
```
## 输出
成功后,返回:
- 输出文件路径:`{workspace}/scraped-paperswithcode-projects.json`
- 爬取的论文/项目数量
- 项目列表(按 Stars 数量排序)
-162
View File
@@ -1,162 +0,0 @@
---
name: task-dispatcher
description: |
作为数据获取流程的核心协调者。解析执行参数,创建工作区,并行调度所有数据源爬虫,汇总原始数据。使用此 agent 当需要从 GitHub Trending、Hugging Face、Papers with Code 等数据源获取 AI 项目时。
示例场景:
- 定期获取最新的 AI 项目趋势
- 从多个数据源收集项目数据
输入参数:{"source": "all", "period": "daily", "limit": 25, "workspace": ".trending-workspace/..."}
model: inherit
color: orange
tools: Read, Write, Bash
---
# 任务派发器 Agent
## 职责
作为数据获取流程的核心协调者,负责:
1. 解析执行参数
2. 创建工作区
3. 并行调度所有数据源爬虫
4. 汇总原始数据
## 输入参数
```json
{
"source": "all",
"period": "daily",
"limit": 25,
"workspace": ".trending-workspace/..."
}
```
**参数说明**:
- `source`: 数据源筛选,`all`(默认)/ `github` / `huggingface` / `paperswithcode`
## 执行步骤
### Step 1: 初始化工作区
1. 生成时间戳目录名:`{YYYYMMDD-HHMMSS}`
2. 创建完整工作区路径:`.trending-workspace/{timestamp}/`
3. 初始化 `progress.json`
```json
{
"startTime": "2025-01-04T12:00:00Z",
"currentStage": "initializing",
"stages": {
"dispatch": "pending",
"scraping": "pending",
"aggregating": "pending"
}
}
```
### Step 2: 根据 source 参数确定要调用的爬虫
**所有可用数据源**
| 源名称 | 爬虫文件 | URL |
|--------|----------|-----|
| github | `.claude/agents/scrapers/github-trending.md` | https://github.com/trending |
| huggingface | `.claude/agents/scrapers/huggingface-trending.md` | https://huggingface.co/models |
| paperswithcode | `.claude/agents/scrapers/papers-with-code.md` | https://paperswithcode.com/ |
**根据 source 参数筛选**:
- `source=all`: 调用上述所有爬虫
- `source=github`: 仅调用 GitHub Trending 爬虫
- `source=huggingface`: 仅调用 Hugging Face 爬虫
- `source=paperswithcode`: 仅调用 Papers with Code 爬虫
### Step 3: 并行调用筛选后的爬虫
**重要**: 必须使用单个消息发送多个 Task 工具调用来实现并行执行。
对筛选出的每个数据源爬虫:
- 构造输入参数(period, limit, workspace
- 调用爬虫 Agent
### Step 4: 汇总原始数据
1. 等待所有爬虫完成
2. 汇总所有爬虫返回的项目数据
3. 输出 `raw-projects.json`
```json
{
"metadata": {
"timestamp": "2025-01-04T12:00:00Z",
"period": "daily",
"limit": 25,
"sources": ["github", "huggingface"],
"sourceCounts": {
"github": 25,
"huggingface": 20
},
"totalRaw": 45
},
"projects": [
{
"source": "github",
"name": "langchain-ai/langchain",
"url": "https://github.com/langchain-ai/langchain",
"description": "Building applications with LLMs through composability",
"metadata": {
"stars": 85432,
"starsDelta": "+234",
"language": "Python",
"forks": 12543
}
},
{
"source": "huggingface",
"name": "meta-llama/Llama-2-7b",
"url": "https://huggingface.co/meta-llama/Llama-2-7b",
"description": "Llama 2 7B parameter model",
"metadata": {
"likes": 15234,
"downloads": 500000,
"pipeline": "text-generation"
}
}
]
}
```
### Step 5: 更新进度
更新 `progress.json`
```json
{
"startTime": "2025-01-04T12:00:00Z",
"currentStage": "completed",
"stages": {
"dispatch": "completed",
"scraping": "completed",
"aggregating": "completed"
},
"endTime": "2025-01-04T12:05:00Z",
"duration": "5m"
}
```
## 错误处理
| 场景 | 处理方式 |
|------|---------|
| 某个爬虫失败 | 记录失败源到 `errors.json`,其他爬虫继续 |
| 所有爬虫失败 | 错误提示 "所有数据源均失败" |
| 工作区创建失败 | 错误提示并终止 |
## 输出
成功后,返回:
- 工作区路径
- 汇总的原始项目数量
- 各数据源的项目数量
+141 -29
View File
@@ -17,7 +17,7 @@ $ARGUMENTS
- **使用 Task 工具调用各个 Agent**,让 Agent 自主完成其职责
- **主窗口仅负责协调 Agent 调用**,不直接处理业务逻辑
本命令通过任务派发器架构,从多个数据源并行爬取 AI 相关项目,经过去重、分析、质量评分后批量入库。
本命令从多个数据源并行爬取 AI 相关项目,经过去重、分析、质量评分后批量入库。
**命令格式**: `/add-trending [source] [period] [limit]`
@@ -32,11 +32,17 @@ $ARGUMENTS
- `/add-trending huggingface daily 10` - 仅 Hugging Face,日榜10个
- `/add-trending all weekly` - 所有数据源,周榜
## 数据源配置
| 源名称 | Agent 名称 | URL |
|--------|-----------|-----|
| github | github-trending | https://github.com/trending |
| huggingface | huggingface-trending | https://huggingface.co/models |
| paperswithcode | papers-with-code | https://paperswithcode.com/ |
## 执行流程
**重要**: 本命令使用专用的 Agent 架构处理工作流,由 Agent 之间相互调用完成整个流程。
### Stage 1: 初始化与任务派发
### Stage 1: 初始化工作区与并行爬取
1. **解析参数**:
-`$ARGUMENTS` 解析 source、period 和 limit
@@ -44,13 +50,100 @@ $ARGUMENTS
2. **创建工作区**:
- 生成时间戳目录: `.trending-workspace/{YYYYMMDD-HHMMSS}/`
- 初始化 `progress.json` 文件
- 初始化 `progress.json` 文件:
```json
{
"startTime": "2025-01-06T12:00:00Z",
"currentStage": "scraping",
"stages": {
"scraping": "pending",
"deduplicating": "pending",
"analyzing": "pending",
"ingesting": "pending"
},
"config": {
"source": "all",
"period": "daily",
"limit": 25
}
}
```
3. **执行任务派发器**:
- **使用 Task 工具调用** `task-dispatcher` agent
- 将 source/period/limit/workspace 参数传递给任务派发器
- 任务派发器并行调度对应的爬虫
- 输出 `raw-projects.json`
3. **确定要调用的 scrapers**:
根据 source 参数筛选:
| source | 调用的 scrapers |
|--------|-----------------|
| all | github-trending, huggingface-trending, papers-with-code |
| github | github-trending |
| huggingface | huggingface-trending |
| paperswithcode | papers-with-code |
4. **并行调用 scrapers**:
**关键**: 必须在单个消息中发送所有 Task 调用,以实现真正的并行执行。
示例(source=all:
```
Task(github-trending, {"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."})
Task(huggingface-trending, {"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."})
Task(papers-with-code, {"period": "daily", "limit": 25, "workspace": ".trending-workspace/..."})
```
5. **等待所有 scraper 完成并汇总**:
每个 scraper 输出到各自的文件:
- `scraped-github-projects.json`
- `scraped-huggingface-projects.json`
- `scraped-paperswithcode-projects.json`
读取所有输出文件,合并生成 `raw-projects.json`:
```json
{
"metadata": {
"timestamp": "2025-01-06T12:00:00Z",
"period": "daily",
"limit": 25,
"sources": ["github", "huggingface"],
"sourceCounts": {
"github": 25,
"huggingface": 20
},
"totalRaw": 45
},
"projects": [
{
"source": "github",
"name": "langchain-ai/langchain",
"url": "https://github.com/langchain-ai/langchain",
"description": "Building applications with LLMs through composability",
"metadata": {
"stars": 85432,
"starsDelta": "+234",
"language": "Python",
"forks": 12543
}
}
]
}
```
6. **更新进度**:
```json
{
"startTime": "2025-01-06T12:00:00Z",
"currentStage": "scraping",
"stages": {
"scraping": "completed",
"deduplicating": "pending",
"analyzing": "pending",
"ingesting": "pending"
},
"config": {
"source": "all",
"period": "daily",
"limit": 25
}
}
```
### Stage 2: 统一去重
@@ -61,16 +154,38 @@ $ARGUMENTS
- 使用 **dbhub PostgreSQL MCP** 执行去重查询
- 输出 `new-projects.json` 和 `task-queue.json`
### Stage 3: 项目分析
### Stage 3: 项目分析 (并行,固定 3 实例分批处理)
1. **执行项目分析器**:
- **使用 Task 工具调用** `project-analyzer` agent
- 将 workspace 参数传递给分析器
- 分析器处理任务队列中的项目
- 使用 **chrome-devtools-mcp** 访问项目页面
- 生成中英双语内容
- 计算质量评分
- 输出 `analyzed-projects.json`
1. **读取任务队列**:
- 读取 `task-queue.json`
- 提取所有 `status: "pending"` 的任务
- 记录任务数量 N
2. **分批并行处理**:
- **固定并行度**: 3 个实例
- **每批处理**: 3 个任务(最后一批可能少于 3 个)
- **批次数**: `Math.ceil(N / 3)`
- **循环执行**以下步骤,直到所有任务完成:
**对每一批**:
- 选取 3 个 `status: "pending"` 的任务(记录其 taskId
- **使用单个消息发送 3 个 Task 工具调用**(实现并行):
```
Task(project-analyzer, {"workspace": "...", "taskId": 1})
Task(project-analyzer, {"workspace": "...", "taskId": 2})
Task(project-analyzer, {"workspace": "...", "taskId": 3})
```
- **等待这 3 个实例完成**
- **检查剩余任务**:重新读取 `task-queue.json`,确认是否还有 `pending` 任务
- **继续下一批**:如果有 pending 任务,重复上述步骤
3. **等待所有批次完成**:
- 确认 `task-queue.json` 中没有 `status: "pending"` 或 `processing` 的任务
4. **汇总结果**:
- 读取所有 `analyzed-project-{taskId}.json` 文件
- 合并生成 `analyzed-projects.json`
- 统计通过/失败的项目数量
### Stage 4: 批量入库
@@ -86,18 +201,14 @@ $ARGUMENTS
2. **清理旧工作区**(删除 7 天前的)
3. **输出最终报告**
## 数据源爬虫
当前支持的数据源(可扩展):
- GitHub Trending: `https://github.com/trending`
- Hugging Face Models: `https://huggingface.co/models`
- Papers with Code: `https://paperswithcode.com/`
## 工作区文件结构
```
.trending-workspace/{timestamp}/
├── raw-projects.json # 所有数据源的原始数据
├── scraped-github-projects.json # GitHub 原始数据
├── scraped-huggingface-projects.json # Hugging Face 原始数据
├── scraped-paperswithcode-projects.json # Papers with Code 原始数据
├── raw-projects.json # 所有数据源的汇总数据
├── new-projects.json # 去重后的新项目
├── task-queue.json # 分析任务队列
├── analyzed-projects.json # 分析完成的项目
@@ -107,6 +218,7 @@ $ARGUMENTS
## 关键规则
- **必须使用单个消息发送多个 Task 调用**:实现 scrapers 真正并行执行
- **必须使用 Agent 工作流**:所有数据处理由专用 Agent 完成,不在主窗口执行
- **必须使用 Task 工具**调用 Agent:让 Agent 自主完成其职责
- **必须**先去重再分析,避免处理已存在的项目
@@ -132,7 +244,7 @@ $ARGUMENTS
🚀 多源数据自动入库启动
⚙️ 配置: source=github, period=daily, limit=25
✅ Stage 1/4: 任务派发
✅ Stage 1/4: 数据爬取
🔍 数据源: GitHub Trending
📊 GitHub: 25 个项目
📦 汇总: 25 个原始项目
@@ -156,7 +268,7 @@ $ARGUMENTS
- 入库成功: 16 个
- 耗时: 约2分钟
📁 工作区: .trending-workspace/20250104-120000/
📁 工作区: .trending-workspace/20250106-120000/
```
**单数据源测试示例**:
+6 -6
View File
@@ -1,6 +1,6 @@
{
"env": {
"HTTP_PROXY": "http://proxy3.bj.petrochina:8080",
"HTTPS_PROXY": "http://proxy3.bj.petrochina:8080"
}
}
// {
// "env": {
// "HTTP_PROXY": "http://proxy3.bj.petrochina:8080",
// "HTTPS_PROXY": "http://proxy3.bj.petrochina:8080"
// }
// }
+3
View File
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
+113
View File
@@ -0,0 +1,113 @@
// Simple Hugging Face scraper
const https = require('https');
const { HttpsProxyAgent } = require('https-proxy-agent');
async function scrapeHuggingFace() {
try {
console.log('Fetching Hugging Face models page...');
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
const agent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : undefined;
const html = await new Promise((resolve, reject) => {
const options = {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
}
};
if (agent) {
options.agent = agent;
}
const req = https.get('https://huggingface.co/models', options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode === 200) {
resolve(data);
} else {
reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
}
});
});
req.on('error', reject);
req.setTimeout(30000, () => {
req.destroy();
reject(new Error('Request timeout'));
});
});
console.log(`Page fetched successfully, size: ${html.length} bytes`);
// Extract model information
const models = [];
const modelLinkRegex = /<a\s+href="\/models\/([^"]+)"[^>]*>/gi;
const seenModels = new Set();
let match;
while ((match = modelLinkRegex.exec(html)) !== null) {
const modelId = decodeURIComponent(match[1]);
// Filter: must have org/model format
if (!modelId.includes('/')) continue;
if (modelId.includes('/discussions')) continue;
if (modelId.includes('/blob')) continue;
if (modelId.includes('/tree')) continue;
if (modelId.includes('/commit')) continue;
if (seenModels.has(modelId)) continue;
seenModels.add(modelId);
models.push({
source: 'huggingface',
name: modelId,
url: `https://huggingface.co/${modelId}`,
description: modelId,
metadata: {
likes: 0,
downloads: 0,
pipeline: ''
}
});
if (models.length >= 100) break;
}
console.log(`Extracted ${models.length} unique models`);
// Take first 25 (they should be roughly ordered by popularity on the page)
const topModels = models.slice(0, 25);
const fs = require('fs');
const outputPath = 'D:\\Code\\AI\\agent-park-v2\\.trending-workspace\\20260106-1226\\scraped-huggingface-projects.json';
fs.writeFileSync(outputPath, JSON.stringify(topModels, null, 2), 'utf8');
console.log(`\nData saved to: ${outputPath}`);
console.log('\nTop 25 Models:');
topModels.forEach((m, i) => {
console.log(`${i + 1}. ${m.name}`);
});
} catch (error) {
console.error('Error:', error.message);
// Output empty result on error
const fs = require('fs');
const outputPath = 'D:\\Code\\AI\\agent-park-v2\\.trending-workspace\\20260106-1226\\scraped-huggingface-projects.json';
const errorResult = {
error: error.message,
projects: [],
timestamp: new Date().toISOString()
};
fs.writeFileSync(outputPath, JSON.stringify(errorResult, null, 2), 'utf8');
console.log(`Error result saved to: ${outputPath}`);
}
}
scrapeHuggingFace();