后端 - 新增 app/task_progress.py 线程安全进度注册表 - 任务改为后台线程异步执行(_run_task_background),手动触发立即返回 task_key - 6 个任务函数(summarizer/tagger/scorer/deduplicator/brief/taxonomy)循环内上报进度 - scheduler 定时任务同步上报进度(trigger=scheduled) - 新增 GET /api/tasks/progress 与 POST /api/tasks/progress/reset 接口 - 新增 POST /api/test-connection 接口连通性测试(独立短超时客户端) - 修复 ai_client/rss_client 配置在 import 时固化的 bug(改为 property 运行时读取 settings), 导致实际任务用 .env 假 key 调 LLM 401 - 修复 ai_client 对 reasoning 模型(MiniMax-M3 等)输出 <think> 块的 JSON 解析失败 - 修复 taxonomy bootstrap:LLM 超时(改用 300s 专用 client)、MiniMax 输出审查 (精简样本仅标题 + 约束生成中性类目名)、失败误报 success(改抛异常如实标记) - 修复 models.py 双外键关系映射启动崩溃(显式 foreign_keys) - 修复 main.py SPA 路由 404、ArticleOut.published_at 序列化 500 - 移除 lifespan 同步 bootstrap 阻塞启动,改由 scheduler 后台异步执行 前端 - Deep Ink 高对比度暗色主题重构,修复 Element Plus 暗色模式对比度问题 - Tasks 页面任务进度实时展示(进度条/阶段/计数/状态/触发来源)+ 1.5s 轮询 - 接口测试面板(rssKeeper / LLM 连通性 + 延迟) - 修复 nextJobs jobId 映射 bug 部署与文档 - Dockerfile 优化(BuildKit 缓存挂载、预编译 wheel、去 gcc、阿里云镜像源) - 新增 API.md 接口文档 Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
dataClean 接口文档
服务地址:
http://<host>:7331所有/api/*接口(除/health)在配置了API_TOKEN时需要在请求头携带Authorization: Bearer <token>。
目录
鉴权
若服务端配置了 API_TOKEN,除 /health 外所有接口需要在请求头携带:
Authorization: Bearer <API_TOKEN>
未携带或 token 无效时返回 401 / 403。未配置 API_TOKEN 时不启用鉴权(仅建议内网使用)。
健康检查
GET /health
服务存活探针,无需鉴权。
响应
{ "status": "ok", "service": "dataClean" }
文章接口
GET /api/articles
分页查询加工后的文章,支持按日期、分类、标签过滤。
查询参数
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
date |
string | 否 | - | 日期 YYYY-MM-DD,按 fetched_at 过滤当天 |
category |
string | 否 | - | 精确分类名 |
tag |
string | 否 | - | 标签名(JSON 数组精确匹配) |
representative_only |
bool | 否 | false |
仅返回重复组代表文章 |
limit |
int | 否 | 50 |
1–200 |
offset |
int | 否 | 0 |
分页偏移 |
响应 ArticleListOut
{
"total": 200,
"items": [
{
"id": 1,
"rk_article_id": 28124,
"title": "文章标题",
"link": "https://...",
"feed_title": "来源",
"category": "科技",
"tags": ["AI", "芯片"],
"heat_score": 45.2,
"importance_score": 60.0,
"duplication_score": 25.0,
"composite_score": 52.56,
"ai_summary": "AI 生成的摘要",
"is_representative": false,
"published_at": "2026-06-13T13:48:42"
}
]
}
GET /api/articles/{article_id}
获取单篇文章详情。
路径参数 article_id:int
响应 ArticleOut(同上 items 元素)
错误 404 文章不存在
简报接口
GET /api/briefs
列出每日简报(按日期倒序)。
查询参数 limit:int,默认 30,范围 1–100
响应 List[BriefOut]
[
{
"id": 1,
"brief_date": "2026-06-13",
"total_articles": 200,
"unique_articles": 150,
"by_category": { "科技": [{...}], "财经": [{...}] },
"markdown_path": "/app/data/briefs/2026-06-13/daily-brief.md"
}
]
GET /api/briefs/{date}
获取指定日期简报。
路径参数 date:string,YYYY-MM-DD
响应 BriefOut 错误 404 简报不存在
POST /api/briefs/{date}/regenerate
强制重新生成指定日期简报。同步执行(需持任务锁)。
响应
{ "message": "简报已重新生成", "data": { ... } }
错误 409 已有任务执行中
分类体系接口
GET /api/taxonomy
列出分类/标签/打分规则。
查询参数 kind:string,可选,过滤类型:category / tag / heat_rule / importance_rule / duplication_rule
响应 List[TaxonomyOut]
[
{
"id": 1,
"name": "科技",
"kind": "category",
"description": "人工智能、芯片、互联网等",
"keywords": ["AI", "芯片", "大模型"],
"weight": 1.0,
"created_by_ai": true
}
]
POST /api/taxonomy/bootstrap
初始化或强制重建分类体系(后台异步执行)。
查询参数 force:bool,默认 false。true 时清空后重建。
响应(立即返回)
{ "message": "taxonomy 初始化已开始", "task_key": "bootstrap_taxonomy" }
错误 409 已有任务执行中。可通过 GET /api/tasks/progress 查看 bootstrap_taxonomy 进度。
任务接口
所有任务接口均为后台异步执行:提交后立即返回 task_key,任务在线程池执行,通过进度接口轮询。
任务全局互斥(共享 _task_lock):同一时刻仅一个任务运行。
POST /api/tasks/summarize
拉取 rssKeeper 最近 24 小时文章,为无摘要/短摘要文章生成 AI 摘要。
响应
{ "message": "摘要任务已开始", "task_key": "summarize" }
错误 409 已有任务执行中
POST /api/tasks/tag-score-dedup
对当天文章执行:分类打标 → 去重 → 打分(三阶段,进度合并显示)。
响应
{ "message": "分类/去重/打分任务已开始", "task_key": "tag_score_dedup" }
POST /api/tasks/brief
生成当天每日简报(force 重新生成)。
响应
{ "message": "简报生成任务已开始", "task_key": "generate_daily_brief" }
任务进度
GET /api/tasks/progress
返回所有任务的实时进度快照(前端每 ~1.5 秒轮询)。
响应
{
"summarize": {
"status": "running",
"stage": "生成摘要",
"current": 75,
"total": 200,
"message": null,
"started_at": "2026-06-13T14:30:00+00:00",
"updated_at": "2026-06-13T14:32:15+00:00",
"finished_at": null,
"trigger": "manual"
},
"tag_score_dedup": { "status": "idle", "stage": "", "current": 0, "total": 0, "message": null, "started_at": null, "updated_at": null, "finished_at": null, "trigger": null },
"generate_daily_brief": { "..." : "同上结构" },
"bootstrap_taxonomy": { "..." : "同上结构" }
}
字段说明
| 字段 | 说明 |
|---|---|
status |
idle / running / success / error |
stage |
当前阶段文案(如「生成摘要」「LLM 生成分类体系」) |
current / total |
进度计数,total=0 时为阶段型任务(用 indeterminate 进度条) |
message |
附加信息或错误详情(status=error 时为错误信息) |
started_at / finished_at |
ISO 8601 时间戳 |
trigger |
manual(手动触发)/ scheduled(定时触发) |
POST /api/tasks/progress/reset
重置指定任务的进度为 idle(清除终态显示)。
查询参数 task_key:string,必填
响应 { "message": "已重置" }
接口连通性测试
POST /api/test-connection
测试 rssKeeper 与 LLM API 连通性,返回状态与延迟。每个测试使用独立短超时客户端(10 秒、0 重试)。
响应 ConnectionTestResponse
{
"rss_keeper": {
"name": "rssKeeper",
"status": "ok",
"latency_ms": 26.0,
"error": null
},
"llm": {
"name": "LLM",
"status": "ok",
"latency_ms": 6871.4,
"error": null
}
}
status 为 error 时 error 字段含失败原因,latency_ms 为 null。
配置管理接口
配置修改保存到数据库,部分配置(调度间隔等)需重启服务生效。
GET /api/settings
列出所有可编辑配置。敏感项(OPENAI_API_KEY / API_TOKEN)返回脱敏值。
响应 List[SettingOut]
[
{
"key": "OPENAI_API_KEY",
"value": "sk-c...2R_8",
"description": "LLM API Key",
"is_sensitive": true,
"is_masked": true,
"updated_at": "2026-06-13T..."
}
]
PUT /api/settings/{key}
更新单个配置项。
请求体
{ "value": "新值" }
响应 { "message": "配置已保存,重启服务后生效" } 错误 400 无效配置项
PUT /api/settings
批量更新配置。
请求体
{ "settings": { "OPENAI_MODEL": "gpt-4o-mini", "OPENAI_TIMEOUT": "60" } }
响应 { "message": "配置已保存,重启服务后生效" } 错误 400 列出无效配置项
POST /api/settings/reset
将所有配置重置为环境变量默认值。
响应 { "message": "配置已重置为环境变量默认值,重启服务后生效" }
可编辑配置清单
| key | 说明 | 敏感 |
|---|---|---|
RSSKEEPER_BASE_URL |
rssKeeper 服务地址 | 否 |
OPENAI_API_KEY |
LLM API Key | 是 |
OPENAI_BASE_URL |
LLM API 基础地址 | 否 |
OPENAI_MODEL |
LLM 模型名 | 否 |
OPENAI_TIMEOUT |
LLM 调用超时(秒) | 否 |
OPENAI_MAX_RETRIES |
LLM 最大重试次数 | 否 |
SUMMARIZE_INTERVAL_MINUTES |
摘要任务间隔(分钟) | 否 |
TAG_SCORE_INTERVAL_MINUTES |
分类/打分/去重任务间隔(分钟) | 否 |
DAILY_BRIEF_HOUR |
每日简报生成小时 | 否 |
DAILY_BRIEF_MINUTE |
每日简报生成分钟 | 否 |
TITLE_SIMILARITY_THRESHOLD |
标题相似度阈值 | 否 |
CONTENT_SIMILARITY_THRESHOLD |
内容相似度阈值 | 否 |
MAX_AI_SUMMARY_LENGTH |
AI 摘要最大长度 | 否 |
MIN_ORIGINAL_SUMMARY_LENGTH |
原始摘要最小长度 | 否 |
BRIEF_TOP_N_PER_CATEGORY |
简报每分类显示文章数 | 否 |
LOG_LEVEL |
日志级别 | 否 |
API_TOKEN |
API 鉴权 Token(空则不启用) | 是 |
CORS_ALLOWED_ORIGINS |
CORS 允许来源(逗号分隔) | 否 |
仪表盘统计
GET /api/stats
返回仪表盘统计与下次定时任务时间。
响应 StatsOut
{
"total_articles": 200,
"today_articles": 50,
"ai_summarized": 180,
"categories": 12,
"tags": 43,
"duplicate_groups": 5,
"briefs": 1,
"next_jobs": {
"fetch_and_summarize": "2026-06-13T17:39:13+08:00",
"tag_score_deduplicate": "2026-06-14T16:39:13+08:00",
"generate_daily_brief": "2026-06-14T08:00:00+08:00"
}
}
错误码
| 状态码 | 含义 | 触发场景 |
|---|---|---|
200 |
成功 | 正常请求 |
400 |
参数错误 | 无效配置项 / 请求体格式错误 |
401 |
未认证 | 未携带 Authorization 头(启用了鉴权时) |
403 |
鉴权失败 | token 无效 |
404 |
资源不存在 | 文章/简报不存在 |
409 |
冲突 | 已有任务正在执行(任务全局互斥) |
422 |
校验失败 | 响应模型序列化失败等 |
500 |
服务器错误 | 内部异常 |
定时任务
服务启动后由 APScheduler 自动注册(时区 Asia/Shanghai):
| Job ID | 触发方式 | 默认 |
|---|---|---|
bootstrap_taxonomy |
启动时一次(DateTrigger) | taxonomy 为空时生成 |
fetch_and_summarize |
间隔 | 每 60 分钟 |
tag_score_deduplicate |
间隔 | 每 1440 分钟(24 小时) |
generate_daily_brief |
Cron | 每日 08:00 |
间隔参数可通过配置接口修改,修改后需重启服务生效。