feat: 添加项目发现去重检查 API

新增去重检查功能,避免创建重复的探索任务:

API 端点:POST /api/discovery/check-duplicates

功能特性:
- 检查 URL 是否已存在 PENDING/IN_PROGRESS 任务
- 检查 URL 是否已存在 COMPLETED/FAILED 任务
- 检查 URL 对应的项目是否已通过 ExternalLink 收录
- 返回每条 URL 的 shouldCreate 判断和建议原因

新增文件:
- src/app/api/discovery/check-duplicates/route.ts: 去重检查逻辑
- src/lib/validations.ts: CheckTaskDuplicatesSchema

文档更新:
- docs/discovery-workflow.md: 添加步骤 2.5 去重检查文档
  - API 调用示例
  - 返回结果说明
  - 去重逻辑优先级
  - n8n 集成建议
This commit is contained in:
2026-01-18 17:44:29 +08:00
parent 18d96911b3
commit d5bf20bbf3
3 changed files with 371 additions and 4 deletions
+115 -4
View File
@@ -15,14 +15,22 @@
├─ 筛选符合条件的项目链接
2. 调用创建任务 API
2. 调用去重检查 API (推荐)
POST /api/discovery/check-duplicates
├─ 检查 URL 是否已存在任务
├─ 检查 URL 对应项目是否已收录
├─ 过滤出需要创建的 URL
3. 调用创建任务 API
POST /api/discovery/tasks
├─ 存入 ProjectDiscoveryTask 表
├─ 状态: PENDING
3. 手动触发本地命令 (定期执行)
4. 手动触发本地命令 (定期执行)
/discover-projects
├─ 通过 curl 获取待处理任务
@@ -38,7 +46,7 @@
│ └─ 自动重试失败的提交
4. 完成任务并入库
5. 完成任务并入库
POST /api/discovery/tasks/{id}/complete
├─ 验证数据格式 (Zod Schema)
@@ -50,7 +58,7 @@
├─ 更新任务状态: COMPLETED/FAILED
5. 数据已入库,可在前台展示
6. 数据已入库,可在前台展示
```
---
@@ -108,6 +116,109 @@ curl -X POST https://your-domain.com/api/discovery/tasks \
---
### 步骤 2.5: 调用去重检查 API(推荐)
**API 端点**: `POST /api/discovery/check-duplicates`
**调用示例**:
```bash
curl -X POST https://your-domain.com/api/discovery/check-duplicates \
-H "Content-Type: application/json" \
-d '{
"apiKey": "YOUR_API_KEY",
"urls": [
"https://github.com/langchain-ai/langchain",
"https://github.com/openai/openai-quickstart-python"
]
}'
```
**返回结果**:
```json
{
"success": true,
"results": [
{
"url": "https://github.com/langchain-ai/langchain",
"shouldCreate": false,
"reason": "Task already exists with status PENDING",
"existingTask": {
"id": "cmxxxxx",
"status": "PENDING",
"sourceUrl": "https://github.com/langchain-ai/langchain",
"createdAt": "2025-01-18T10:00:00Z",
"projectId": null
}
},
{
"url": "https://github.com/openai/openai-quickstart-python",
"shouldCreate": true,
"reason": "No existing task or project found"
}
],
"stats": {
"total": 2,
"shouldCreate": 1,
"duplicate": 1
}
}
```
**去重逻辑**(按优先级):
1. **优先级 1**: 检查是否有 PENDING/IN_PROGRESS 的相同 URL 任务
- 如果存在 → `shouldCreate: false`
- 原因:任务已在处理中,避免重复探索
2. **优先级 2**: 检查是否有 COMPLETED/FAILED 的相同 URL 任务
- 如果存在 → `shouldCreate: false`
- 原因:任务已探索过,无需重复
3. **优先级 3**: 检查 URL 对应的项目是否已存在(通过 ExternalLink
- 如果存在 → `shouldCreate: false`
- 原因:项目已通过其他来源收录
4. **默认**: 允许创建新任务
- `shouldCreate: true`
**n8n 集成建议**:
```javascript
// n8n Workflow 示例
const checkResponse = await fetch('https://your-domain.com/api/discovery/check-duplicates', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: 'YOUR_API_KEY',
urls: collectedUrls // 从上一步收集的 URL 列表
})
})
const { results, stats } = await checkResponse.json()
// 过滤出应该创建任务的 URL
const urlsToCreate = results
.filter(r => r.shouldCreate)
.map(r => r.url)
// 只为不重复的 URL 创建任务
if (urlsToCreate.length > 0) {
await fetch('https://your-domain.com/api/discovery/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: 'YOUR_API_KEY',
tasks: urlsToCreate.map(url => ({
sourceUrl: url,
sourceType: 'github_trending'
}))
})
})
}
console.log(`创建 ${urlsToCreate.length} 个新任务,跳过 ${stats.duplicate} 个重复任务`)
```
---
### 步骤 3: 手动触发本地命令
**执行环境**: 本地开发环境 (Local Development)