feat: 初始化项目,添加文档

This commit is contained in:
meijiali
2026-07-01 16:59:59 +08:00
commit 289d7e2c82
9 changed files with 4447 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+235
View File
@@ -0,0 +1,235 @@
# API-Spike-Douyin.md:抖音热点到评论抓取链路验证
## 1. 文档信息
- 文档阶段:API Spike 验证
- 验证平台:抖音
- API 服务:TikHub API
- 验证目标:确认「抖音热点榜单 → 热点相关视频 → 单个视频一级评论」链路可跑通
- 验证结论:链路已跑通,可作为 MVP 阶段抖音评论抓取方案
---
## 2. 最终跑通链路
MVP 阶段抖音抓取采用以下链路:
1. 获取抖音创作者热点榜单。
2. 从热点榜单中读取热点标题。
3. 使用热点标题作为关键词搜索抖音视频。
4. 从搜索结果中读取视频 `aweme_id`
5. 使用 `aweme_id` 获取单个视频一级评论。
链路表达:
```text
fetch_creator_hot_spot_billboard
→ hot.title
→ fetch_video_search_v2(keyword = hot.title)
→ aweme_info.aweme_id
→ fetch_video_comments(aweme_id)
→ comments
```
---
## 3. 接口一:获取抖音热点榜单
### 3.1 接口信息
```http
GET https://api.tikhub.io/api/v1/douyin/creator/fetch_creator_hot_spot_billboard
```
### 3.2 MVP 请求参数
```text
billboard_tag=0
hot_search_type=1
```
参数含义:
- `billboard_tag=0`:获取全部热点标签。
- `hot_search_type=1`:获取热点总榜。
### 3.3 MVP 需要字段
热点条目需要读取:
```text
query_id
title
rank
category
hot_score
```
字段用途:
- `query_id`:热点 ID,作为热点原始标识保存。
- `title`:热点标题,用于后续关键词搜索视频。
- `rank`:热点排名。
- `category`:热点分类。
- `hot_score`:热点热度值。
---
## 4. 接口二:通过热点标题搜索相关视频
### 4.1 接口信息
```http
POST https://api.tikhub.io/api/v1/douyin/search/fetch_video_search_v2
```
### 4.2 MVP 请求体
```json
{
"keyword": "<热点标题>",
"cursor": 0,
"sort_type": "0",
"publish_time": "0",
"filter_duration": "0",
"content_type": "1",
"search_id": "",
"backtrace": ""
}
```
参数含义:
- `keyword`:热点标题,来自热点榜单条目的 `title`
- `cursor=0`:第一页搜索结果。
- `sort_type=0`:综合排序。
- `publish_time=0`:不限发布时间。
- `filter_duration=0`:不限视频时长。
- `content_type=1`:搜索视频内容。
### 4.3 MVP 需要字段
视频条目需要读取:
```text
aweme_info.aweme_id
aweme_info.desc
aweme_info.author
aweme_info.statistics
aweme_info.create_time
```
字段用途:
- `aweme_id`:视频作品 ID,用于后续评论抓取。
- `desc`:视频标题或描述。
- `author`:作者基础信息。
- `statistics`:视频互动数据,如评论数、点赞数等。
- `create_time`:视频发布时间。
---
## 5. 接口三:获取单个视频一级评论
### 5.1 接口信息
```http
GET https://api.tikhub.io/api/v1/douyin/app/v3/fetch_video_comments
```
### 5.2 MVP 请求参数
```text
aweme_id=<视频 aweme_id>
cursor=0
count=20
```
参数含义:
- `aweme_id`:视频作品 ID,来自视频搜索结果。
- `cursor=0`:第一页评论。
- `count=20`:按接口建议保持默认值。
### 5.3 MVP 需要字段
评论条目需要读取:
```text
cid / comment_id
text
user
digg_count
create_time
```
字段用途:
- `cid``comment_id`:评论 ID,用于去重和关联。
- `text`:评论正文。
- `user`:评论作者基础信息。
- `digg_count`:评论点赞数。
- `create_time`:评论发布时间。
---
## 6. 已验证样例
本次验证中,抖音链路已成功跑通以下样例:
```text
热点标题:2026年广州中考开考
热点 query_id2552790
视频 aweme_id7657020050364189986
视频描述:15.1万名考生报名参加广州中考,广州首次启用智能安检门和无线电作弊防控设备
评论 ID7657143740201812773
评论内容:湖南已放假,广东还在中考中。高考与中考不是全国统一的吗?
```
该样例证明:
1. 可以获取抖音热点榜单。
2. 可以基于热点标题搜索到相关视频。
3. 可以从视频搜索结果中获取 `aweme_id`
4. 可以基于 `aweme_id` 获取视频一级评论。
---
## 7. MVP 开发结论
抖音侧 MVP 抓取链路采用:
```text
热点榜单接口
→ 热点标题关键词搜索视频
→ 视频评论接口
```
开发阶段应将外部 API 字段映射设计为可调整结构,保留原始 JSON 响应,避免后续接口字段变化时影响核心数据追溯。
MVP 阶段建议默认抓取规模:
```text
Top 5 热点
× 每个热点最多 5 条视频
× 每条视频最多 50 条一级评论
```
正式实现中应支持配置:
```text
hot_limit
video_limit_per_hot
comment_limit_per_video
```
---
## 8. 后续文档衔接
本 API Spike 结果用于支撑后续文档:
1. `FeatureSummary.md`:拆解抖音抓取相关功能模块。
2. `DevelopmentPlan.md`:设计后端服务、任务流程、数据模型和异常处理。
3. `TDD`:围绕字段映射、分页、去重和任务状态编写测试。
4. `Tasks`:拆分具体开发任务。
+265
View File
@@ -0,0 +1,265 @@
# API-Spike-Xiaohongshu.md:小红书热榜到评论抓取链路验证
## 1. 文档信息
- 文档阶段:API Spike 验证
- 验证平台:小红书
- API 服务:TikHub API
- 验证目标:确认「小红书热榜 → 热点相关笔记 → 单篇笔记一级评论」链路可跑通
- 验证结论:链路已跑通,可作为 MVP 阶段小红书评论抓取方案
---
## 2. 最终跑通链路
MVP 阶段小红书抓取采用以下链路:
1. 获取小红书热榜。
2. 从热榜列表中读取真实热榜标题。
3. 使用热榜标题作为关键词搜索小红书笔记。
4. 从搜索结果中优先选择 `comments_count > 0` 的笔记。
5. 使用笔记 `note_id` 获取单篇笔记一级评论。
链路表达:
```text
fetch_hot_list
→ data.data.items[].title
→ search_notes(keyword = hot.title)
→ note.id
→ get_note_comments(note_id)
→ comments
```
---
## 3. 接口一:获取小红书热榜
### 3.1 接口信息
```http
GET https://api.tikhub.io/api/v1/xiaohongshu/web_v2/fetch_hot_list
```
### 3.2 MVP 请求参数
该接口 MVP 阶段不需要额外请求参数。
### 3.3 MVP 需要字段
真实热榜条目位于:
```text
data.data.items[]
```
热榜条目需要读取:
```text
id
title
score
rank_change
type
word_type
```
字段用途:
- `id`:热榜条目原始 ID,作为热点原始标识保存。
- `title`:热榜标题,用于后续关键词搜索笔记。
- `score`:热榜热度值。
- `rank_change`:排名变化。
- `type`:热榜条目类型。
- `word_type`:热榜标签,如「热」或「无」。
注意:
```text
data.data.title
```
是热榜模块标题,例如「搜索发现」,不应作为热榜条目使用。
---
## 4. 接口二:通过热榜标题搜索相关笔记
### 4.1 接口信息
```http
GET https://api.tikhub.io/api/v1/xiaohongshu/app_v2/search_notes
```
### 4.2 MVP 请求参数
```text
keyword=<热榜标题>
page=1
sort=general
note_type=0
```
参数含义:
- `keyword`:热榜标题,来自 `data.data.items[].title`
- `page=1`:第一页搜索结果。
- `sort=general`:综合排序。
- `note_type=0`:不限笔记类型。
### 4.3 MVP 需要字段
搜索结果中的笔记信息位于:
```text
data.data.items[].note
```
笔记条目需要读取:
```text
id
title
desc
type
user
liked_count / nice_count
comments_count
collected_count
shared_count
timestamp / update_time
```
字段用途:
- `id`:笔记 ID,用于后续评论抓取。
- `title`:笔记标题。
- `desc`:笔记正文或摘要。
- `type`:笔记类型,如图文或视频。
- `user`:作者基础信息。
- `liked_count``nice_count`:点赞数。
- `comments_count`:评论数,用于优先选择有评论的笔记。
- `collected_count`:收藏数。
- `shared_count`:分享数。
- `timestamp``update_time`:发布时间或更新时间。
---
## 5. 接口三:获取单篇笔记一级评论
### 5.1 接口信息
```http
GET https://api.tikhub.io/api/v1/xiaohongshu/app_v2/get_note_comments
```
### 5.2 MVP 请求参数
```text
note_id=<笔记 id>
cursor=
index=0
pageArea=UNFOLDED
sort_strategy=latest_v2
```
参数含义:
- `note_id`:笔记 ID,来自搜索结果中的 `data.data.items[].note.id`
- `cursor`:评论分页游标,第一页为空。
- `index=0`:第一页索引。
- `pageArea=UNFOLDED`:评论展开区域。
- `sort_strategy=latest_v2`:按最新评论排序。
### 5.3 MVP 需要字段
评论列表位于:
```text
data.data.comments[]
```
评论条目需要读取:
```text
id / comment_id
content / text
user_info / user
like_count
create_time
```
字段用途:
- `id``comment_id`:评论 ID,用于去重和关联。
- `content``text`:评论正文。
- `user_info``user`:评论作者基础信息。
- `like_count`:评论点赞数。
- `create_time`:评论发布时间。
---
## 6. 已验证样例
本次验证中,小红书链路已成功跑通以下样例:
```text
热榜标题:耗时三年拍下古诗词里的中国
搜索笔记:张岱笔下的江南夜色,一字入画
note_id6a4319410000000217023ee7
评论 ID6a433517000000001403b657
评论内容:都很美啊![点赞R]
```
该样例证明:
1. 可以获取小红书真实热榜条目。
2. 可以基于热榜标题搜索到相关笔记。
3. 可以从笔记搜索结果中获取 `note_id`
4. 可以基于 `note_id` 获取笔记一级评论。
---
## 7. MVP 开发结论
小红书侧 MVP 抓取链路采用:
```text
热榜接口
→ 热榜标题关键词搜索笔记
→ 笔记评论接口
```
开发阶段应注意:
1. 热榜真实条目应从 `data.data.items[]` 读取,不要使用外层模块标题。
2. 搜索结果不要无脑取第一条,应优先选择 `comments_count > 0` 的笔记。
3. 笔记评论接口返回空评论时不一定是接口失败,可能是该笔记本身无评论。
4. 外部 API 字段映射应保持可调整,并保留原始 JSON 响应用于排障。
MVP 阶段建议默认抓取规模:
```text
Top 5 热榜
× 每个热榜最多 5 篇笔记
× 每篇笔记最多 50 条一级评论
```
正式实现中应支持配置:
```text
hot_limit
note_limit_per_hot
comment_limit_per_note
```
---
## 8. 后续文档衔接
本 API Spike 结果用于支撑后续文档:
1. `FeatureSummary.md`:拆解小红书抓取相关功能模块。
2. `DevelopmentPlan.md`:设计后端服务、任务流程、数据模型和异常处理。
3. `TDD`:围绕字段映射、分页、空评论、去重和任务状态编写测试。
4. `Tasks`:拆分具体开发任务。
File diff suppressed because it is too large Load Diff
+683
View File
@@ -0,0 +1,683 @@
# FeatureSummary.md:小红书 / 抖音热榜评论抓取 + AI 分析报告工具
## 1. 文档信息
- 文档阶段:FeatureSummary(产品功能文档)
- 需求来源:`docs/RequirementsDoc.md``docs/PRD.md`
- API Spike 依据:`docs/API-Spike-Xiaohongshu.md``docs/API-Spike-Douyin.md`
- 项目类型:学习型小工具 / 全栈流程演示项目
- MVP 周期:约 4 天(单人开发)
- 当前版本目标:将 PRD 中的产品需求拆解为功能模块、优先级、验收点与后续技术文档衔接事项
---
## 2. 功能总览
MVP 核心流程:
```text
用户手动触发任务
→ 选择平台(小红书 / 抖音)
→ 获取热点榜单
→ 按热点拆分相关内容条目
→ 抓取内容条目一级评论
→ AI 评论级结构化分析
→ 生成热点级与内容条目级报告
→ 页面查看
→ 导出 Markdown / CSV
```
功能模块:
1. 任务创建与任务状态管理
2. 平台选择与抓取参数配置
3. 小红书热点、笔记与评论抓取
4. 抖音热点、视频与评论抓取
5. 数据存储与原始响应保留
6. AI 评论级结构化分析
7. 热点级汇总报告
8. 内容条目级分析报告
9. 页面查看
10. 导出
11. 异常处理与基础容错
12. 配置、安全与部署
---
## 3. 优先级定义
- P0:MVP 必须实现,缺失会导致主流程无法验收。
- P1:MVP 建议实现,可提升可用性或排障效率,但不应阻塞主流程。
- P2:后续版本考虑,当前 FeatureSummary 仅记录为边界,不纳入 4 天 MVP。
---
## 4. P0 功能列表
### F01 任务创建与状态管理
功能目标:
- 用户可以从页面手动创建一次抓取任务;
- 系统记录任务平台、创建时间、任务状态、错误原因与基础统计信息;
- 任务状态支持运行中、成功、失败。
功能范围:
- 支持手动触发,不支持定时触发;
- 创建任务后前端不需要等待整个抓取和 AI 分析流程同步完成;
- 同一用户可重复创建任务,多次任务视为独立执行;
- 任务最终状态规则:
- 没有任何内容条目成功完成抓取和分析时,任务失败;
- 至少 1 条内容条目成功完成抓取和分析时,任务可标记成功,并展示失败内容条目数或错误摘要。
- AI 分析质量不扩展任务状态模型,使用独立字段记录:
- `analysis_success_rate`:任务内成功生成情绪分类和方向标签的评论占比;
- `analysis_status`:AI 分析质量状态,可取值为正常、分析不足;
-`analysis_success_rate < 80%` 时,任务状态仍可按内容条目处理结果标记成功,但 `analysis_status` 标记为分析不足。
- 任务数据模型须包含:
- `total_items_count`:任务内计划或实际纳入处理的内容条目总数;
- `processed_items_count`:已完成抓取与分析处理的内容条目数;
- `successful_items_count`:成功完成抓取与分析的内容条目数。
- `analysis_success_rate`
- `analysis_status`
核心验收:
- 用户可以在页面创建任务;
- 任务创建后可在任务列表看到记录;
- 任务完成后状态能更新为成功或失败;
- AI 分析成功率低于 80% 时,任务列表可展示分析不足提示;
- 失败时页面能展示简要错误原因。
### F02 平台选择与抓取规模配置
功能目标:
- 用户可以选择抓取平台;
- 用户可以在任务创建页面调整 MVP 抓取规模;
- 系统按用户配置或默认规模执行抓取。
功能范围:
- 支持平台:小红书、抖音;
- 任务创建页面提供抓取规模配置项:
- 热点关键词数量上限:默认 5,取值范围 1–10;
- 每热点内容条目数上限:默认 5,取值范围 1–10;
- 每内容条目评论数上限:默认 50,取值范围 10–100。
- 默认约 1,250 条评论 / 平台 / 任务;
- 具体上限值可由 DevelopmentPlan 结合平台 API 限制最终确认,但 MVP 页面须提供配置入口。
核心验收:
- 用户创建任务时可以明确选择小红书或抖音;
- 用户创建任务时可以查看并调整抓取规模配置;
- 前端对抓取规模配置做范围校验,非法值不能提交;
- 任务记录保存所选平台;
- 未调整配置时,系统按默认规模抓取数据。
### F03 小红书抓取链路
功能目标:
- 根据小红书热榜获取相关笔记,并抓取笔记一级评论。
已验证链路:
```text
fetch_hot_list
→ data.data.items[].title
→ search_notes(keyword = hot.title)
→ note.id
→ get_note_comments(note_id)
→ comments
```
功能范围:
- 获取小红书热榜;
- 从热榜条目读取真实热榜标题;
- 使用热榜标题搜索相关笔记;
- 优先选择 `comments_count > 0` 的笔记;
-`comments_count > 0` 的笔记不足目标数量,补充选取 `comments_count = 0` 的笔记至目标数;
- 若平台返回总笔记数本身不足目标数,以实际可用数量为准,不视为任务失败;
- 使用笔记 ID 抓取一级评论;
- 若单次评论 API 返回评论数不足目标值,继续翻页请求;
- 评论翻页终止条件:达到目标评论数、API 返回数据为空,或达到最大翻页轮次;
- 最大翻页轮次建议 5 次,最终由 DevelopmentPlan 结合 API 特性确认;
- 翻页期间遇到限流时,沿用 F11 的指数退避策略;
- 小红书内容条目统一称为笔记,不区分图文笔记和视频笔记。
核心验收:
- 系统能展示小红书 Top 5 热点;
- 每个热点最多展示 5 条相关笔记;
- 每条成功获取的笔记能抓取最多 50 条一级评论;
- 评论至少保留评论内容和所属笔记关系;
- 字段缺失时不阻塞整体流程。
### F04 抖音抓取链路
功能目标:
- 根据抖音热点榜单获取相关视频,并抓取视频一级评论。
已验证链路:
```text
fetch_creator_hot_spot_billboard
→ hot.title
→ fetch_video_search_v2(keyword = hot.title)
→ aweme_info.aweme_id
→ fetch_video_comments(aweme_id)
→ comments
```
功能范围:
- 获取抖音热点榜单;
- 从热点榜单读取热点标题;
- 使用热点标题搜索相关视频;
- 从搜索结果读取视频 `aweme_id`
- 使用 `aweme_id` 抓取一级评论;
- 若单次评论 API 返回评论数不足目标值,继续翻页请求;
- 评论翻页终止条件:达到目标评论数、API 返回数据为空,或达到最大翻页轮次;
- 最大翻页轮次建议 5 次,最终由 DevelopmentPlan 结合 API 特性确认;
- 翻页期间遇到限流时,沿用 F11 的指数退避策略;
- 抖音内容条目为视频。
核心验收:
- 系统能展示抖音 Top 5 热点;
- 每个热点最多展示 5 条相关视频;
- 每条成功获取的视频能抓取最多 50 条一级评论;
- 评论至少保留评论内容和所属视频关系;
- 字段缺失时不阻塞整体流程。
### F05 数据存储与原始响应保留
功能目标:
- 保存任务、热点、内容条目、评论、AI 分析结果与报告所需数据;
- 保留原始 API 响应,便于排障和后续字段调整。
功能范围:
- 任务数据:
- 任务 ID
- 平台;
- 创建时间;
- 状态;
- 错误原因;
- 已获取热点数;
- 已获取内容条目数;
- `total_items_count`
- `processed_items_count`
- `successful_items_count`
- 热点数据:
- 平台;
- 任务 ID
- 排名;
- 热点 ID
- 热点标题或摘要;
- 热度值或榜单指标;
- 原始 API 响应。
- 内容条目数据:
- 平台;
- 任务 ID
- 所属热点 ID
- 内容条目 ID
- 内容条目类型;
- 标题或内容摘要;
- URL
- 抓取状态或分析状态;
- 原始 API 响应。
- 评论数据:
- 评论 ID
- 所属热点;
- 所属内容条目;
- 评论内容;
- 作者基础信息;
- 点赞数;
- 评论时间;
- 情绪倾向;
- 方向标签;
- 可选简短理由;
- 原始评论 API 响应;
- 可选 AI 原始响应。
核心验收:
- 任务、热点、内容条目、评论之间有关联关系;
- 原始评论内容必须保留;
- AI 分析结果能追溯到原始评论;
- 同一任务内,同一内容条目下同一评论 ID 不重复入库,或重复抓取时更新已有记录。
### F06 AI 评论级结构化分析
功能目标:
- 对已抓取评论生成结构化分析结果,支撑评论明细展示和报告统计。
功能范围:
- 对每条评论输出:
- 情绪倾向:正向、负向、中性;
- 方向标签:AI 自动生成的开放标签,每条评论可有 1~3 个标签;
- 简短理由:可选字段。
- 不预设固定标签字典;
- 近义标签合并不作为 MVP 强制要求;
- AI 分析建议按批量处理思路实现,具体批量大小由 DevelopmentPlan 确认;
- 具体批量大小和并发策略依赖 AI 服务选型结果,由 DevelopmentPlan 确认;
- Prompt 须强制要求 LLM 返回严格 JSON Array 结构,禁止混入自然语言说明;
- 后端须对 LLM 输出做 JSON Schema 校验;
- 解析失败时触发重试,最多 N 次,N 由 DevelopmentPlan 结合所选 AI 服务确认,建议 3 次;
- AI 返回无法解析或缺失必填字段时,单条评论标记为未知、空标签或分析失败,不阻塞其他评论。
- 任务完成后统计 `analysis_success_rate`;低于 80% 时写入 `analysis_status = 分析不足`,但不改变任务成功 / 失败状态。
核心验收:
- 已抓取评论能生成情绪分类;
- 已抓取评论能生成方向标签,或在无法判断时给出空标签 / 未知标签;
- 评论明细页能展示评论内容、情绪和标签;
- 单条 AI 分析失败不会导致整个任务崩溃。
### F07 热点级汇总报告
功能目标:
- 为每个热点生成一份轻量汇总报告,展示该热点下所有内容条目的整体评论情况。
功能范围:
- 报告基于该热点下所有已分析内容条目的评论级结构化结果聚合生成;
- MVP 阶段建议采用预生成型报告:任务完成后由后台生成并存库,用户访问报告页时读取已生成结果;
- 若 DevelopmentPlan 改为实时聚合,须明确响应延迟、重复计算和缓存策略;
- 报告至少包含:
- 热点基础信息;
- 内容条目数量;
- 总评论样本数量;
- 正向、负向、中性评论数量和占比;
- Top 5 方向标签及数量;
- 典型评论若干;
- AI 生成的简短热点总结。
- 情绪分布和标签分布由评论级结构化结果计算;
- 方向标签按字面值聚合,不要求语义近义标签自动归并;
- 热点总结建议不超过 300 字;
- 不做平台级日报或跨热点汇总。
核心验收:
- 每个已完成分析的热点可查看热点级汇总报告;
- 报告中的内容条目数、样本数、情绪数量和占比与评论明细一致;
- 报告可以导出为 Markdown。
### F08 内容条目级分析报告
功能目标:
- 为每条内容条目生成一份分析报告,展示单条视频 / 笔记的评论反馈。
功能范围:
- 报告至少包含:
- 样本评论数量;
- 正向、负向、中性评论数量和占比;
- 主要方向标签及占比;
- 典型正向评论 1~2 条;
- 典型负向评论 1~2 条;
- 典型中性评论 1~2 条;
- AI 生成的简短内容条目级总结。
- 情绪分布和标签分布由评论级结构化结果计算;
- MVP 阶段建议采用预生成型报告:任务完成后由后台生成并存库,用户访问报告页时读取已生成结果;
- 若 DevelopmentPlan 改为实时聚合,须明确响应延迟、重复计算和缓存策略;
- 方向标签按字面值聚合,MVP 展示 Top 5 标签及数量;
- 典型评论默认按情绪分组后按点赞数降序选取;
- 如果点赞数字段不可用,按抓取顺序选取;
- 内容条目级总结建议不超过 200 字。
核心验收:
- 每条已完成分析的内容条目可查看内容条目级报告;
- 报告中的样本数、情绪数量和占比与评论明细一致;
- 报告可以导出为 Markdown。
### F09 页面查看
功能目标:
- 用户可以在 Web 页面完成任务创建、状态查看、结果浏览和导出操作。
页面范围:
- 任务列表 / 首页;
- 热点与内容条目列表页;
- 热点级汇总报告页;
- 内容条目详情页;
- 评论明细展示区域。
页面能力:
- 任务列表 / 首页:
- 平台选择;
- 抓取规模配置表单区域;
- 配置项输入范围提示与非法值校验;
- 手动触发按钮;
- 刷新任务列表按钮;
- 任务创建时间;
- 任务状态;
- AI 分析状态或分析成功率;
- 成功 X / 共 Y 条内容条目;
- 任务基础信息;
- 错误原因;
- 可选基础进度。
- 热点与内容条目列表页:
- 平台;
- 抓取时间或任务标识;
- 任务状态和错误原因;
- AI 分析状态或分析成功率;
- 成功 X / 共 Y 条内容条目;
- 热点排名;
- 热点标题或摘要;
- 内容条目标题或摘要;
- 内容条目类型;
- 分析状态;
- 进入热点级报告和内容条目详情的入口。
- 热点级汇总报告页:
- 热点基础信息;
- 内容条目数量;
- 样本数量;
- 情绪分布;
- Top 5 方向标签;
- 典型评论;
- 简短热点总结;
- Markdown 导出入口。
- 内容条目详情页:
- 热点基础信息;
- 内容条目基础信息;
- 内容条目级分析报告;
- 评论明细;
- Markdown 报告导出入口;
- CSV 评论明细导出入口。
核心验收:
- 用户可以从任务进入热点与内容条目列表;
- 用户可以进入热点级汇总报告;
- 用户可以进入内容条目详情;
- 用户可以在详情中同时查看统计结果和原始评论;
- 任务运行中时,用户可通过手动刷新按钮更新任务状态;
- 任务列表展示任务创建时间,供用户判断任务执行时长;
- 导出入口清晰可见。
### F10 导出
功能目标:
- 用户可以将报告和评论明细导出为文件,用于本地分析、分享或归档。
功能范围:
- 热点级汇总报告导出为 Markdown;
- 内容条目级分析报告导出为 Markdown;
- 内容条目评论明细导出为 CSV。
- CSV 使用 `UTF-8-SIG` 编码,确保国内用户通过 Excel 直接打开时中文字符正常显示;
- CSV 文件命名格式为 `{platform}_{task_id}_{hotspot_keyword}.csv`
- `hotspot_keyword` 超过 20 字符时截断并附加省略号,避免文件名过长。
核心字段:
- Markdown 热点级汇总报告:
- 热点基础信息;
- 内容条目数量;
- 评论样本量;
- 情绪分布;
- 方向标签分布;
- 典型评论;
- 热点总结。
- Markdown 内容条目级报告:
- 所属热点信息;
- 内容条目基础信息;
- 评论样本量;
- 情绪分布;
- 方向标签分布;
- 典型评论;
- 内容条目总结。
- CSV 内容条目评论明细:
- 平台;
- 抓取日期或任务标识;
- 热点信息;
- 内容条目信息;
- 评论 ID
- 评论内容;
- 情绪倾向;
- 方向标签;
- 点赞数;
- 评论时间。
核心验收:
- 用户能下载 CSV 评论明细;
- 用户能下载 Markdown 热点级汇总报告;
- 用户能下载 Markdown 内容条目级报告;
- 导出内容与页面展示一致。
### F11 异常处理与基础容错
功能目标:
- 保证单个热点、内容条目或评论分析失败时,尽量不影响整批任务继续执行。
功能范围:
- 错误信息展示:
- API 请求失败;
- 平台 API 请求被限流(HTTP 429);
- API 响应异常;
- AI 调用失败或超时;
- 数据入库失败。
- 容错行为:
- 单个热点或内容条目抓取 / 分析失败时记录错误;
- 收到 429 响应时,采用指数退避策略重试,建议等待间隔为 1s → 2s → 4s;
- 超过最大重试次数后将该条目标记为失败,继续处理后续条目,不阻断整批任务;
- 尝试继续处理剩余热点或内容条目;
- AI 单条解析失败时,该评论标记为未知或分析失败;
- 用户输入非法抓取规模配置值时,前端提示具体字段错误并阻止提交;
- 不新增“部分成功”或“部分失败”任务状态;当 AI 结构化成功率不足但仍有可查看结果时,统一使用 `analysis_status` 标记分析不足。
核心验收:
- 单个内容条目失败不直接终止整个任务;
- 任务失败时可看到失败状态和简要错误原因;
- 错误原因至少包含失败阶段和错误类型;
- 至少 1 条内容条目成功完成抓取和分析时,任务可产生可查看结果。
### F12 配置、安全与部署
功能目标:
- 支持本机或组内服务器部署;
- 敏感配置不进入代码仓库。
功能范围:
- 使用 Docker Compose 统一编排所需组件;
- 支持浏览器访问 Web 页面;
- API Key、AI Key 等通过环境变量或未纳入版本控制的配置文件管理;
- 默认用于内部环境,不面向公网开放;
- MVP 默认不做登录和权限控制。
核心验收:
- 系统可以通过 Docker Compose 启动;
- 启动后可在浏览器访问;
- 敏感配置不写入代码仓库。
---
## 5. P1 功能列表
P1 功能不应阻塞 MVP 主流程,但可在时间允许时实现。
### F13 基础进度展示
功能范围:
- 展示已处理内容条目数 / 总内容条目数;
- 可展示成功内容条目数 / 失败内容条目数;
- 前端进度展示直接复用 F01 的 `processed_items_count``total_items_count``successful_items_count` 字段;
- 禁止前后端各自独立实现进度计数逻辑;
- 不做复杂进度条和阶段级任务编排。
### F14 前端自动刷新
功能范围:
- 任务运行中时,前端可用简单轮询刷新任务状态;
- P0 已提供手动刷新兜底,P1 在此基础上实现自动轮询;
- 若未实现自动轮询,用户通过刷新按钮或页面刷新查看最新状态。
### F15 开发调试信息入口
功能范围:
- 在内容条目详情页可选展示原始 JSON;
- 仅用于开发和排障;
- 不作为正式用户功能。
---
## 6. P2 / 当前不纳入范围
以下能力不纳入当前 4 天 MVP
- 定时自动抓取任务;
- 任务并发控制、分布式锁、复杂任务调度;
- 自动补跑、任务阶段粒度展示、单条内容条目单独重试;
- Top 50 及以上热点抓取;
- 单条内容条目 200 条及以上评论抓取;
- 平台级每日汇总报告;
- 跨热点聚合 Top 话题和平台层总结;
- 登录鉴权;
- 多用户与角色权限管理;
- 操作审计;
- Excel 导出;
- 用户侧正式 JSON 导出;
- 二级评论抓取;
- 评论回复、自动发布、私信运营;
- 长期趋势分析;
- 品牌专题分析;
- 关键词筛选热点;
- 移动端适配;
- 复杂 BI 大屏;
- 评论人工标注校正工作台;
- 自动形成运营建议或营销动作;
- 外部分享链接、公开访问和权限控制。
---
## 7. 功能依赖关系
```text
F02 平台选择与抓取规模配置
→ F01 任务创建与状态管理
→ F03 小红书抓取链路 / F04 抖音抓取链路
→ F05 数据存储与原始响应保留
→ F06 AI 评论级结构化分析
→ F07 热点级汇总报告 / F08 内容条目级分析报告
→ F09 页面查看
→ F10 导出
```
横向支撑能力:
- F11 异常处理与基础容错;
- F12 配置、安全与部署。
---
## 8. 关键验收清单
MVP 完成时至少需要满足:
1. 系统可通过 Docker Compose 启动,并能在浏览器访问。
2. 用户可从页面选择小红书或抖音并手动触发任务。
3. 系统可获取默认 Top 5 热点。
4. 系统可为每个热点拆分默认最多 5 条内容条目。
5. 系统可为每条内容条目抓取默认最多 50 条一级评论。
6. 任务内至少 80% 的评论成功生成情绪分类和方向标签,视为该验收项通过;低于此比例时任务状态仍遵循成功 / 失败规则,但 `analysis_status` 须标记为分析不足,并在页面展示提示。
7. 系统可生成热点级汇总报告。
8. 系统可生成内容条目级分析报告。
9. 页面可查看任务列表、热点列表、热点级报告、内容条目详情和评论明细。
10. 用户可导出 CSV 评论明细。
11. 用户可导出 Markdown 热点级汇总报告。
12. 用户可导出 Markdown 内容条目级报告。
13. 任务失败时,页面可展示失败状态,错误原因须至少包含失败阶段(如:数据抓取阶段 / AI 分析阶段)和错误类型(如:网络超时 / API 限流 / 解析失败)。
14. 报告统计数据与评论结构化结果一致。
---
## 9. 后续文档衔接
### 9.1 DevelopmentPlan.md 需要重点解决
- AI 服务选型须作为第一优先决策项,在架构设计开始前锁定;
- AI 服务选型需覆盖:批量接口支持能力、输出 JSON Schema 控制方式、单次 Token 上限、API 调用成本估算;
- AI 请求并发数上限与单次请求超时时间,建议并发不超过 3 个、超时 30s;
- 后台任务实现方式:简单线程 / 协程、任务队列或其他方案;
- 数据库选型与表结构设计;
- 小红书 / 抖音字段映射和兼容策略;
- 评论分页、限流、异常码与失败处理;
- AI 服务选型、批量大小、输出 schema、解析失败兜底;
- 报告生成策略:预生成或实时聚合;若采用预生成型,须同步确认报告数据的更新 / 重算触发机制;
- 报告生成逻辑和统计计算方式;
- 同一内容条目(相同 URL 或内容 ID)出现在多个热点搜索结果中时的去重策略;建议 MVP 阶段保留重复数据,并通过 `task_id + hotspot_id + item_id` 联合主键区分;
- 前后端 API 契约;
- Docker Compose 组件和启动验收方式;
- 是否提供 `/health` 健康检查端点。
### 9.2 UIDesign.md 需要重点解决
- 任务列表 / 首页信息结构;
- 热点与内容条目列表的信息层级;
- 热点级汇总报告展示方式;
- 内容条目详情页与评论明细布局;
- 导出入口位置;
- 任务运行中、失败、空数据状态展示。
### 9.3 TDD.md 需要重点覆盖
- 平台选择与任务创建;
- 小红书字段映射;
- 抖音字段映射;
- 评论去重;
- 空评论场景;
- 单个内容条目失败但任务继续;
- AI 输出解析失败;
- 情绪和标签统计一致性;
- Markdown / CSV 导出内容一致性。
### 9.4 Tasks.md 需要按模块拆解
- 后端任务与状态;
- 小红书抓取;
- 抖音抓取;
- 数据模型;
- AI 分析;
- 报告生成;
- 前端页面;
- 导出;
- Docker Compose
- 测试与验收。
---
## 10. 审阅建议
后续三 AI 审阅 `FeatureSummary.md` 时,建议重点检查:
1. 是否忠实继承 `RequirementsDoc.md``PRD.md`
2. 是否误加入当前 MVP 不需要的新功能;
3. P0 / P1 / P2 优先级是否合理;
4. 是否遗漏主流程中的关键功能模块;
5. 验收清单是否可测;
6. 是否有需要用户重新决策的问题。
+690
View File
@@ -0,0 +1,690 @@
# PRD.md:小红书 / 抖音热榜评论抓取 + AI 分析报告工具
## 1. 文档信息与版本说明
- 文档阶段:PRDProduct Requirement Document,产品需求文档)
- 需求来源:`docs/RequirementsDoc.md`
- API Spike 依据:`docs/API-Spike-Xiaohongshu.md``docs/API-Spike-Douyin.md`
- 项目类型:学习型小工具 / 全栈流程演示项目
- MVP 周期:约 4 天(单人开发)
- 目标用户:组内成员 / 演示使用
- 当前版本目标:定义产品功能、用户流程、页面需求与验收标准
### 1.1 范围说明
本 PRD 严格继承当前 `RequirementsDoc.md` 的范围,不扩展到此前讨论中但未进入需求文档的能力。
MVP 重点是跑通「手动触发抓取 → 获取热点榜单 → 拆分热点相关内容条目 → 抓取一级评论 → AI 分析 → 页面展示 → 导出」的完整闭环。
小红书与抖音的最小抓取链路已通过 API Spike 验证,PRD 阶段不锁定所有接口字段细节,后续由 DevelopmentPlan 和开发实现补充字段映射、分页、限流与异常处理方案。
## 2. 产品概述
本产品是一个面向组内成员的内部演示型工具,用于从小红书和抖音获取少量热点榜单,将每个热点拆分为相关内容条目,抓取内容条目下的一级评论,并通过 AI 对评论进行情绪和讨论方向分析。抖音内容条目为视频,小红书内容条目统一称为笔记,不区分图文和视频。用户可以在 Web 页面查看热点列表、热点级汇总报告、内容条目列表、内容条目级分析报告和评论明细,也可以导出 CSV 评论明细、Markdown 热点级汇总报告和 Markdown 内容条目级报告。
产品不追求首版大规模采集、复杂权限、定时任务或平台级深度分析。MVP 成功的核心判断是全流程是否可用、结果是否可查看、导出是否可获得。
## 3. 产品目标
### 3.1 总体目标
在 4 天单人开发周期内,完成一个可本机或局域网部署的全栈演示产品,体现从外部数据接入、数据存储、AI 结构化分析到 Web 展示与导出的完整链路。
### 3.2 MVP 目标
MVP 必须达成:
1. 用户可以在页面选择平台并手动触发抓取任务。
2. 系统可以获取小红书或抖音的 Top N 热点榜单。
3. 系统可以将每个热点拆分出相关内容条目,并抓取每条内容条目的一级评论。
4. 系统可以对评论生成情绪分类和方向标签。
5. 系统可以生成热点级汇总报告和内容条目级分析报告。
6. 用户可以查看任务、热点、内容条目、报告和评论明细。
7. 用户可以导出 CSV 评论明细、Markdown 热点级汇总报告和 Markdown 内容条目级报告。
8. 系统可以通过 Docker Compose 启动并在浏览器访问。
### 3.3 产品原则
- 流程完整优先于规模和复杂度。
- 页面简洁可用优先于视觉精细度。
- 统计数据来自结构化分析结果,避免只依赖 AI 自由总结。
- 外部 API 和 AI 输出 schema 保持可调整,不在 PRD 阶段锁死技术细节。
## 4. 目标用户与使用场景
### 4.1 目标用户
- 组内开发者:验证接口、联调流程、演示全栈能力。
- 产品或数据分析同事:查看热点内容评论的基础情绪和方向分布。
- 演示观看者:理解抓取、分析、展示、导出的完整产品闭环。
### 4.2 用户权限
MVP 默认不做登录和权限控制。所有能访问系统页面的用户拥有相同功能权限。
如果后续教学或审阅场景明确要求访问控制,可追加单管理员账号方案;该能力不属于当前 PRD 的默认范围。
### 4.3 核心使用场景
用户希望快速查看某个平台热点下相关内容条目的评论基础反馈时:
1. 打开 Web 页面。
2. 选择平台:小红书或抖音。
3. 点击按钮手动创建抓取任务。
4. 等待系统完成热点榜单获取、内容条目拆分、评论抓取和 AI 分析。
5. 在热点列表和内容条目列表中查看抓取到的热点及其相关视频/笔记。
6. 进入热点汇总报告页,查看该热点下所有内容条目的整体评论分析。
7. 进入内容条目详情页,查看内容条目级分析报告和评论明细。
8. 按需导出 CSV 评论明细或 Markdown 分析报告。
## 5. 核心用户流程
### 5.1 手动抓取与分析流程
1. 用户进入首页或任务页。
2. 用户选择平台。
3. 用户点击「开始抓取」或同类操作按钮。
4. 系统创建一条抓取任务并立即返回任务记录,任务状态进入「运行中」。
5. 后端在后台继续执行任务,不要求前端 HTTP 请求一直阻塞等待完成。
6. 系统调用外部 API 获取该平台 Top N 热点榜单。
7. 系统将每个热点拆分为相关内容条目。
8. 系统依次抓取每条内容条目的一级评论。
9. 系统调用 AI 对评论进行结构化分析。
10. 系统生成内容条目级分析报告。
11. 系统按热点聚合内容条目级结果,生成热点级汇总报告。
12. 任务完成后状态变为「成功」;如全局失败则状态变为「失败」并展示错误原因。
13. 用户通过刷新任务列表或点击刷新按钮查看最新状态,然后查看结果或执行导出。
### 5.2 结果查看流程
1. 用户在任务列表中选择某次任务。
2. 系统展示该任务下的热点列表。
3. 用户展开或进入某个热点,查看该热点下的相关内容条目。
4. 用户可以进入热点级汇总报告,查看该热点下所有内容条目的整体评论情况。
5. 用户选择某个内容条目进入详情页。
6. 系统展示热点基础信息、内容条目基础信息、内容条目级分析报告和评论明细。
7. 用户可以根据评论情绪或方向标签理解该内容条目的讨论情况。
### 5.3 导出流程
1. 用户在内容条目详情页点击导出入口。
2. 导出该内容条目的评论明细时,系统生成 CSV 文件。
3. 导出热点级汇总报告或内容条目级报告时,系统生成 Markdown 文件。
4. 用户下载文件用于本地分析、分享或归档。
## 6. 功能需求
### 6.1 平台选择
用户需要能够在前端页面选择抓取平台。
支持平台:
- 小红书
- 抖音
验收标准:
- 页面存在平台选择控件。
- 用户可以明确选择小红书或抖音。
- 创建任务时,任务记录中保存所选平台。
### 6.2 手动创建抓取任务
MVP 仅支持用户手动触发任务,不支持定时自动任务。
功能要求:
- 用户点击按钮后,系统创建一条抓取任务。
- 任务初始状态为「运行中」。
- 任务记录需要保存平台、触发时间、任务状态和错误信息。
- 同一用户可以重复触发任务;多次任务视为独立执行。
- 后端允许采用简单后台任务模型,创建任务后立即返回任务 ID 或任务记录,抓取、分析和报告生成在后台继续执行。
- MVP 不要求 WebSocket,也不强制自动轮询;前端至少提供刷新按钮或页面刷新能力用于查看最新任务状态。
验收标准:
- 用户能从页面创建抓取任务。
- 任务创建后能在页面看到任务记录。
- 任务完成后状态能更新为成功或失败。
- 用户无需等待一次 HTTP 请求完成全部抓取和 AI 分析。
### 6.3 热点榜单获取与内容条目拆分
系统需要通过现有外部 API 获取所选平台的热点榜单,并拆分出每个热点下的相关内容条目。
功能要求:
- 每次任务默认抓取 Top 5 热点。
- 支持通过配置调整到 Top 10 热点。
- MVP 不追求 Top 50 或更大规模。
- 每个热点需要拆分出相关内容条目:
- 默认每个热点最多拆分 5 条内容条目;
- 支持通过配置调整到 10 条内容条目;
- 如果某个热点下内容条目不足 5 条,则抓取全部可获得内容条目;
- MVP 不追求穷尽单个热点下所有视频/笔记;
- 抖音内容条目为视频;
- 小红书内容条目统一称为笔记,不区分图文和视频。
- 默认抓取规模约为:5 个热点 × 每热点 5 条内容条目 × 每条内容条目 50 条一级评论 = 1,250 条评论 / 平台 / 任务。
- 系统保存平台、热点排名、热点标题、内容条目 ID、标题或摘要、URL、抓取时间等可用字段。
验收标准:
- 系统能按默认规模获取 Top 5 热点并展示在页面。
- 系统能展示每个热点下最多 5 条相关内容条目。
- 热点、内容条目与任务有关联关系。
- API 字段缺失时,页面能以可用字段展示,不阻塞整体流程。
### 6.4 一级评论抓取
系统需要抓取每条内容条目下的一级评论。
功能要求:
- 仅抓取一级评论。
- 默认单条内容条目评论上限为 50 条。
- 支持通过配置调整到 100 条。
- 评论不足上限时抓取全部可获得评论。
- 抓取顺序以 API 默认顺序为准,不强制按时间或热度排序。
- 数据按任务隔离:每次任务独立保存自己的热点、内容条目和评论结果。
- 同一任务内,同一内容条目下以评论 ID 进行基础去重;跨任务不强制全局去重。
验收标准:
- 系统能为每条成功获取的内容条目抓取一级评论。
- 评论记录至少包含评论内容和所属内容条目。
- 如 API 提供评论 ID、作者、点赞数、评论时间,应尽量保存并展示。
- 同一内容条目同一评论 ID 不重复入库,或重复抓取时更新已有记录。
### 6.5 AI 评论级结构化分析
系统需要对评论进行 AI 结构化分析。
分析字段:
- 情绪倾向:正向、负向、中性。
- 方向标签:开放标签,由 AI 根据评论内容生成,每条评论可有 1~3 个标签。
- 简短理由:可选字段,用一句话解释情绪或标签判断。
功能要求:
- 不预设固定标签字典。
- AI 可以生成如价格争议、外观种草、使用体验、质量吐槽、求购买链接、玩梗讨论等标签。
- 近义标签合并不作为 MVP 强制要求。
- 分析结果必须与原始评论关联。
- AI 分析默认采用批量处理思路,例如每批 10~20 条评论,具体批量大小在 DevelopmentPlan 中确认。
- 如果 AI 返回内容无法解析或缺失必填字段,单条评论应标记为「未知」情绪、空标签或分析失败原因,不应阻塞后续评论分析。
验收标准:
- 已抓取评论能生成情绪分类。
- 已抓取评论能生成至少一个方向标签,或在无法判断时给出空标签/未知标签。
- 评论明细页能展示评论内容、情绪和标签。
- AI 分析失败的单条评论不会导致整个任务崩溃。
### 6.6 热点级汇总报告
系统需要为每个热点生成一份轻量热点级汇总报告。
报告内容:
- 热点基础信息。
- 该热点下内容条目数量。
- 总评论样本数量。
- 正向、负向、中性评论整体数量和占比。
- Top 5 方向标签及数量。
- 典型评论若干。
- AI 生成的简短热点总结。
功能要求:
- 热点级汇总报告基于该热点下所有已分析内容条目的评论级结构化结果聚合生成。
- 情绪分布和标签分布应由评论级结构化结果计算。
- 方向标签统计按标签字面值聚合,MVP 仅展示出现频次最高的 Top 5 标签及数量,不要求语义近义标签自动归并。
- 典型评论默认在该热点下按情绪分组后按点赞数降序选取。
- 热点级总结由 AI 基于统计结果、Top 标签和典型评论生成,建议不超过 300 字。
- MVP 不做平台级日报或跨热点汇总。
验收标准:
- 每个已完成分析的热点可查看一份热点级汇总报告。
- 报告中的内容条目数、样本数、情绪数量和占比与该热点下评论明细一致。
- 报告可以导出为 Markdown。
### 6.7 内容条目级分析报告
系统需要为每条内容条目生成一份内容条目级分析报告。
报告内容:
- 样本评论数量。
- 正向、负向、中性评论数量和占比。
- 主要方向标签及占比。
- 典型正向评论 1~2 条。
- 典型负向评论 1~2 条。
- 典型中性评论 1~2 条。
- AI 生成的简短内容条目级总结。
功能要求:
- 情绪分布和标签分布应由评论级结构化结果计算。
- 方向标签统计按标签字面值聚合,MVP 仅展示出现频次最高的 Top 5 标签及数量,不要求语义近义标签自动归并。
- 典型评论默认按情绪分组后按点赞数降序选取每类前 1~2 条。
- 如果点赞数字段不可用,典型评论按抓取顺序选取每类前 1~2 条。
- 内容条目级总结由 AI 基于统计结果、Top 标签和典型评论生成,建议不超过 200 字。
- 总结强调事实统计和常见观点,不要求深度运营洞察。
验收标准:
- 每条已完成分析的内容条目可查看一份内容条目级报告。
- 报告中的样本数、情绪数量和占比与评论明细一致。
- 报告可以导出为 Markdown。
## 7. 页面与交互需求
### 7.1 任务列表 / 首页
页面目标:让用户创建抓取任务并查看任务状态。
页面元素:
- 平台选择控件。
- 手动触发按钮。
- 刷新任务列表按钮。
- 任务列表。
- 任务状态:运行中、成功、失败。
- 任务基础信息:平台、创建时间、热点数量、内容条目数量、错误原因。
- 可选进度信息:已处理内容条目数 / 总内容条目数。
交互要求:
- 用户选择平台后点击按钮创建任务。
- 创建后任务列表能展示新任务。
- 任务失败时展示简要错误原因。
- 用户点击任务行进入该任务的热点与内容条目列表页。
- MVP 不单独设计任务详情页;任务状态、错误原因和基础进度在任务列表行内展示,或在热点与内容条目列表页顶部展示。
- 用户通过刷新按钮或页面刷新获取任务最新状态;自动轮询可作为实现优化,不是 MVP 必须项。
### 7.2 热点与内容条目列表页
页面目标:展示某次任务抓取到的热点,以及每个热点下的相关内容条目。
页面元素:
- 平台。
- 抓取时间或任务标识。
- 任务状态、错误原因和基础进度。
- 热点排名。
- 热点标题或摘要。
- 进入热点级汇总报告的操作入口。
- 内容条目标题或摘要。
- 内容条目类型:抖音视频 / 小红书笔记。
- 分析状态。
- 进入详情的操作入口。
交互要求:
- 用户可以从任务进入热点与内容条目列表。
- 用户可以查看热点下的相关内容条目。
- 用户可以进入热点级汇总报告。
- 用户可以点击内容条目进入详情页。
### 7.3 热点级汇总报告页
页面目标:展示单个热点下所有内容条目的整体评论分析。
页面元素:
- 热点基础信息。
- 内容条目数量。
- 总评论样本数量。
- 情绪分布。
- Top 5 方向标签。
- 典型评论。
- 简短热点总结。
- 导出 Markdown 热点级汇总报告入口。
### 7.4 内容条目详情页
页面目标:展示内容条目级分析报告和评论明细。
页面元素:
- 热点基础信息。
- 内容条目基础信息。
- 样本评论数量。
- 情绪分布。
- 标签分布。
- 典型评论。
- 简短总结。
- 评论明细列表。
- 导出 Markdown 报告入口。
- 导出 CSV 评论明细入口。
- 可选开发调试信息入口:展示该内容条目或评论的原始 JSON,仅供开发和排障使用,不作为正式用户功能。
交互要求:
- 用户能同时查看统计结果和原始评论。
- 导出入口应清晰可见。
### 7.5 评论明细展示
评论明细至少展示:
- 评论内容。
- 情绪倾向。
- 方向标签。
- 点赞数(如有)。
- 评论时间(如有)。
- 作者基础信息(如有)。
MVP 不强制提供复杂筛选、搜索或人工校正。
## 8. 数据与分析结果需求
### 8.1 任务数据
任务需要记录:
- 任务 ID。
- 平台。
- 创建时间。
- 状态。
- 错误原因。
- 已获取热点数。
- 已获取内容条目数。
- 可选进度信息,如已处理内容条目数 / 总内容条目数。
### 8.2 热点与内容条目数据
热点需要记录:
- 平台。
- 任务 ID。
- 排名。
- 热点 ID。
- 热点标题或摘要。
- 热度值或榜单指标(如 API 提供)。
- 原始 API 响应 `raw_data`,用于接口联调和排障。
内容条目需要记录:
- 平台。
- 任务 ID。
- 所属热点 ID。
- 内容条目 ID。
- 内容条目类型:抖音视频 / 小红书笔记。
- 标题或内容摘要。
- URL。
- 抓取状态或分析状态。
- 原始 API 响应 `raw_data`,用于接口联调和排障。
字段以 API 实际返回能力为准。
### 8.3 评论数据
评论需要记录:
- 评论 ID。
- 所属热点。
- 所属内容条目。
- 评论内容。
- 作者基础信息。
- 点赞数。
- 评论时间。
- 情绪倾向。
- 方向标签。
- 可选简短理由。
- 原始评论 API 响应 `raw_data`
- 可选 AI 原始响应 `ai_raw_data`,用于排查 AI 输出解析问题。
字段以 API 实际返回能力为准。原始评论内容必须保留。
### 8.4 报告数据
热点级汇总报告需要记录或可重新生成:
- 热点基础信息。
- 内容条目数量。
- 总评论样本数量。
- 情绪统计。
- 标签统计。
- 典型评论。
- 简短热点总结。
内容条目级报告需要记录或可重新生成:
- 样本评论数量。
- 情绪统计。
- 标签统计。
- 典型评论。
- 简短总结。
报告统计应来自评论级结构化结果。
## 9. 导出需求
### 9.1 Markdown 热点级汇总报告导出
导出入口:
- 热点级汇总报告页。
建议内容:
- 热点基础信息。
- 内容条目数量。
- 总评论样本数量。
- 情绪分布。
- Top 方向标签。
- 典型评论。
- 热点总结。
验收标准:
- 用户能下载 Markdown 文件。
- Markdown 内容结构清晰,满足常见 Markdown 阅读器可解析的基本格式。
- Markdown 报告与页面展示的热点级汇总报告一致。
### 9.2 Markdown 内容条目级报告导出
导出入口:
- 内容条目详情页。
建议内容:
- 所属热点信息。
- 内容条目基础信息。
- 评论样本数量。
- 情绪分布。
- Top 方向标签。
- 典型评论。
- 内容条目总结。
验收标准:
- 用户能下载 Markdown 文件。
- Markdown 内容结构清晰,满足常见 Markdown 阅读器可解析的基本格式。
- Markdown 报告与页面展示的内容条目级报告一致。
### 9.3 CSV 内容条目评论明细导出
导出入口:
- 内容条目详情页。
建议字段:
- 平台。
- 抓取日期或任务标识。
- 热点 ID。
- 热点标题或摘要。
- 内容条目 ID。
- 内容条目标题或摘要。
- 评论 ID。
- 评论内容。
- 情绪倾向。
- 方向标签。
- 点赞数。
- 评论时间。
验收标准:
- 用户能下载 CSV 文件。
- CSV 编码建议为 UTF-8;是否添加 BOM 由 DevelopmentPlan 确认。
- CSV 内容能用常见表格工具打开。
- CSV 中的评论数据与页面展示一致。
## 10. 异常与状态需求
### 10.1 任务状态
MVP 支持三种任务状态:
- 运行中。
- 成功。
- 失败。
可选展示:
- 已处理内容条目数 / 总内容条目数。
- 成功内容条目数 / 失败内容条目数。
状态判定规则:
- 全部流程仍在执行时,任务状态为「运行中」。
- 至少有 1 条内容条目成功完成抓取和分析时,任务最终状态可标记为「成功」,同时在任务行或列表页顶部展示失败内容条目数和错误信息。
- 如果没有任何内容条目成功完成抓取和分析,任务最终状态标记为「失败」。
- MVP 不新增「部分成功」状态。
### 10.2 错误展示
任务失败时需要展示简要错误原因,例如:
- API 请求失败。
- API 响应异常。
- AI 调用失败或超时。
- 数据入库失败。
错误信息不要求面向非技术用户完全友好,但必须足够支持开发者排查。
### 10.3 容错行为
- 单个热点或内容条目抓取/分析失败时,应记录错误并尝试继续处理剩余内容。
- MVP 不要求实现部分成功状态。
- MVP 不要求自动补跑、单条内容条目重试、分布式锁或复杂任务恢复。
- AI 单条解析失败时,该评论标记为未知或分析失败,不阻塞其他评论。
## 11. 非功能需求
### 11.1 可用性
- 页面结构应简单清晰。
- 用户能快速知道当前有哪些任务、任务是否成功、内容条目分析结果在哪里查看。
- 错误信息应可见。
### 11.2 可维护性
- 外部 API 调用、数据存储、AI 分析、报告生成、页面展示和导出应保持模块边界清晰。
- 平台、Top N、单条内容条目评论上限应可配置。
- AI 提示词和输出结构应便于后续调整。
### 11.3 数据质量
- 保留原始评论内容。
- 评论级 AI 结果可追溯到原始评论。
- 报告统计由结构化结果计算。
- 不因 AI 总结文本替代结构化统计。
### 11.4 安全与配置
- API Key、AI Key 等敏感配置不得写入代码仓库。
- 敏感配置通过环境变量或未纳入版本控制的配置文件管理。
- MVP 默认用于内部环境,不面向公网开放。
## 12. MVP 成功标准
MVP 必须满足:
1. 系统可以通过 Docker Compose 启动,并能在浏览器访问。
2. 用户可以从页面手动触发抓取任务。
3. 用户可以选择小红书或抖音作为平台。
4. 系统可以从外部 API 获取所选平台默认 Top 5 热点。
5. 系统可以从每个热点拆分出默认最多 5 条相关内容条目,并为每条内容条目抓取默认最多 50 条一级评论。
6. 系统可以为评论生成情绪分类和方向标签。
7. 系统可以生成热点级汇总报告和内容条目级分析报告。
8. 用户可以查看任务列表、热点列表、热点级汇总报告、内容条目列表、内容条目详情和评论明细。
9. 用户可以导出 CSV 评论明细。
10. 用户可以导出 Markdown 热点级汇总报告和内容条目级分析报告。
11. 任务失败时,页面能展示失败状态和简要错误原因。
质量与稳定性目标为尽力达成,不作为硬性阻塞:
- 情绪分类与方向标签人工抽查时方向基本合理;建议演示验收时随机抽查 10 条评论,7 条及以上判断方向可接受即视为基本可用。
- 报告统计数据与评论结构化结果一致。
- 单个热点或内容条目失败不导致整批任务完全不可用。
## 13. Out of Scope
以下能力不纳入当前 MVP
- 定时自动抓取任务。
- 任务并发控制、分布式锁、复杂任务调度。
- 自动补跑、任务阶段粒度展示、单条内容条目单独重试。
- Top 50 及以上热点抓取。
- 单条内容条目 200 条及以上评论抓取。
- 平台级每日汇总报告。
- 跨热点聚合 Top 话题和平台层总结。
- 登录鉴权。
- 多用户与角色权限管理。
- 操作审计。
- Excel 导出。
- 用户侧正式 JSON 导出。
- 二级评论抓取。
- 评论回复、自动发布、私信运营。
- 长期趋势分析。
- 品牌专题分析。
- 关键词筛选热点。
- 移动端适配。
- 复杂 BI 大屏。
- 评论人工标注校正工作台。
- 自动形成运营建议或营销动作。
- 外部分享链接、公开访问和权限控制。
## 14. 待确认事项
以下事项不阻塞 PRD。小红书 / 抖音最小抓取链路已通过 API Spike 验证,后续需要在 DevelopmentPlan 和开发阶段确认工程化细节:
1. 小红书 / 抖音热点榜单、内容条目与评论数据的字段映射和兼容策略。
2. 小红书 / 抖音热点到内容条目的关联落库方式。
3. 小红书 / 抖音评论 API 的分页策略、排序规则、限流策略和异常码。
4. 外部 API 在默认规模和配置上限下的稳定性。
5. AI 服务提供商、模型名称、费用和调用速率限制。
6. AI 输出结构的具体 schema,例如字段名称、枚举值和标签格式。
7. Docker Compose 中数据库和任务处理方案的具体技术选型。
8. 前后端核心 API 接口设计,包括创建任务、查询任务列表、查询热点与内容条目列表、查询内容条目详情、导出 CSV 和导出 Markdown。
9. 前端状态刷新机制是否从手动刷新升级为简单定时轮询。
10. Docker Compose 启动验收细节,包括是否自动初始化数据库、是否需要 migration、首页访问是否作为健康判断。
11. 是否提供 `/health` 健康检查端点,用于部署和联调验证。
12. API Spike 中的真实 JSON 样例应作为 DevelopmentPlan 与开发实现的字段映射依据。
## 15. 后续文档衔接说明
PRD 完成并通过审阅后,后续文档按以下顺序推进:
1. `FeatureSummary.md`:拆解功能模块、优先级和版本边界。
2. `DevelopmentPlan.md`:确定技术选型、架构、接口、数据模型和开发计划。
3. `UIDesign.md`:定义关键页面结构、信息层级和交互细节。
4. `TDD.md`:定义测试驱动开发计划和验收测试场景。
5. `Tasks.md`:拆解具体开发任务、依赖关系和排期。
每份主文档产出后,按 `RequirementsDoc.md` 中定义的审阅流程生成独立 review 文件,汇总修订并经用户确认后再进入下一阶段。
DevelopmentPlan.md 需要优先决策:
- 后台任务实现方式:简单线程/协程、任务队列或其他方案。
- AI 批量调用大小、输出解析、失败兜底和内容条目级总结 prompt。
- 数据模型是否沿用 PRD 默认的按任务隔离策略。
- 数据库、前端框架、后端框架和 Docker Compose 组件。
- 前后端 API 契约和状态刷新机制。
+493
View File
@@ -0,0 +1,493 @@
# RequirementsDoc.md:小红书 / 抖音热榜评论抓取 + AI 分析报告工具
## 1. 文档信息
- 文档阶段:RequirementsDoc(需求规格说明)
- 项目类型:学习型小工具 / 全栈流程演示项目
- MVP 周期:约 4 天(单人开发)
- 目标用户:组内成员 / 演示使用
- 当前状态:需求已确认,小红书 / 抖音最小抓取链路已通过 API Spike 跑通
- 核心目标说明:本项目首要目标是完整跑通「热点榜单抓取 → 内容条目拆分 → 评论抓取 → 存储 → AI 分析 → 展示 → 导出」的全栈闭环流程,功能深度和规模服从于流程完整性。
---
## 2. 项目背景
组内希望有一个内部工具,用于:
- 获取小红书和抖音的热点榜单;
- 将每个热点拆分为相关内容条目,其中抖音内容条目为视频,小红书内容条目统一称为笔记;
- 抓取内容条目下的一级评论;
- 使用 AI 对评论的情绪和讨论方向进行结构化分析;
- 在 Web 页面查看分析结果,并支持导出。
现状:
- 已有小红书和抖音相关抓取 API 及 Key;
- 小红书最小链路已通过 `docs/API-Spike-Xiaohongshu.md` 验证:热榜 → 相关笔记 → 笔记一级评论;
- 抖音最小链路已通过 `docs/API-Spike-Douyin.md` 验证:热点榜单 → 相关视频 → 视频一级评论;
- 本文档只定义业务目标、范围与验收标准;
- 字段映射、分页、限流、异常码、规模稳定性等调用细节在后续技术文档和开发阶段继续确认。
---
## 3. 产品目标
### 3.1 总体目标
在 4 天单人开发周期内,完成一个可本机/局域网部署的演示型产品,体现从数据抓取到 AI 分析再到可视化与导出的完整技术链路。
### 3.2 MVP 目标
MVP 首要目标:流程跑通,而非功能完备或大规模数据处理。
需要覆盖的环节:
1. 获取小红书和抖音的热点榜单(每平台少量热点即可,具体见 5.1)。
2. 将每个热点拆分为相关内容条目,并抓取内容条目下的一级评论。
3. 使用 AI 对评论进行情绪与方向标签的结构化分析。
4. 在 Web 页面展示热点列表、热点级汇总报告、内容条目列表、内容条目详情与评论明细。
5. 支持导出评论明细、热点级汇总报告与内容条目级分析报告。
设计原则:
- 首先保证各环节功能打通;
- 规模、性能与健壮性在 MVP 阶段从简;
- 代码结构明确,便于后续扩展。
---
## 4. 用户与使用场景
### 4.1 目标用户
- 组内成员(包括开发者、产品、数据分析人员);
- 技术演示或课堂讲解场景。
MVP 阶段:
- 不区分角色类型;
- 默认所有访问者具有相同功能权限。
### 4.2 核心使用场景
1. 用户打开系统的 Web 页面。
2. 用户选择平台(小红书 / 抖音),手动触发一次抓取任务。
3. 系统调用外部 API
- 获取该平台的热点榜单(Top N)。
- 获取每个热点下的相关内容条目。
- 获取这些内容条目下的一级评论。
4. 系统调用 AI 对已抓取评论进行结构化分析:
- 情绪分类;
- 方向标签;
- 可选简短理由。
5. 用户在页面查看:
- 热点列表与内容条目列表(含抓取与分析状态);
- 单个热点的汇总分析报告;
- 单个内容条目的分析报告;
- 评论明细。
6. 用户可将:
- 评论明细导出为 CSV
- 热点级汇总报告导出为 Markdown;
- 内容条目级分析报告导出为 Markdown。
---
## 5. MVP 范围
### 5.1 热点榜单获取与内容条目拆分
功能范围:
- 支持两个平台:小红书、抖音。
- 每平台每次默认抓取 Top 5 条热点:
- 热点数量可配置到 Top 10
- MVP 不追求 Top 50 或更大规模。
- 每个热点默认最多拆分 5 条相关内容条目:
- 内容条目数量可配置到 10 条;
- 如果某个热点下内容条目不足 5 条,则抓取全部可获得内容条目;
- MVP 不追求穷尽单个热点下所有视频/笔记。
- 抖音内容条目为视频;
- 小红书内容条目统一称为笔记,不区分图文笔记和视频笔记。
- 默认抓取规模约为:5 个热点 × 每热点 5 条内容条目 × 每条内容条目 50 条一级评论 = 1,250 条评论 / 平台 / 任务。
- 对每次抓取操作记录:
- 平台;
- 抓取执行时间(或日期);
- 热点排名;
- 热点基础信息(如热点标题、热度值、榜单来源等,可根据 API 字段实际决定);
- 内容条目基础信息(如标题/内容摘要、内容 ID、URL 等,可根据 API 字段实际决定);
- 抓取状态(成功 / 失败)。
技术约束:
- 热点榜单和内容条目数据源来自已有外部 API;
- API 字段映射与数据结构以 API Spike 结果为基础,由后续技术文档继续细化。
### 5.2 评论抓取
功能范围:
- 仅抓取一级评论,不抓取二级评论或回复链。
- 每条内容条目默认最多抓取 50 条一级评论:
- 评论数量可配置到 100 条;
- 不足上限时抓取全部可获得的评论。
- 抓取顺序:
- 以 API 默认顺序为主(如时间顺序或热度顺序);
- 不强制排序要求。
数据字段(视 API 支持情况而定):
- 评论内容;
- 评论 ID(用于去重与关联);
- 评论作者基础信息(如昵称或用户 ID);
- 点赞数(如有);
- 评论时间;
- 所属平台;
- 所属热点 ID/信息;
- 所属内容条目 ID/信息。
去重逻辑:
- 对同一内容条目重复抓取时,以评论 ID 做基本去重;
- 最简单策略为:同一内容条目同一评论 ID 不重复入库或更新已有记录。
### 5.3 任务触发
功能范围:
- MVP 仅支持用户手动触发抓取任务:
- 从前端点击按钮触发后端调用;
- 不做自动定时任务。
- 一次任务流程:
- 抓取热点榜单;
- 拆分热点下的相关内容条目;
- 抓取对应内容条目的一级评论;
- 调用 AI 分析评论;
- 生成内容条目级分析数据,供页面展示与导出。
- 不处理并发控制与多任务调度问题:
- 同一用户可重复触发任务;
- 同平台的多次任务视为独立执行,后续由开发计划决定是否覆盖或追加数据。
### 5.4 AI 评论分析
功能范围:
- 对每条评论进行结构化分析,输出结构包括:
- 情绪倾向:正向 / 负向 / 中性;
- 方向标签:AI 自动生成的开放标签,如:
- 价格争议;
- 外观种草;
- 使用体验;
- 质量吐槽;
- 求购买链接;
- 玩梗讨论;
- 等等;
- 可选简短理由:一句话解释该分类与标签的原因(非必需字段)。
标签体系:
- 不预设固定的标签字典;
- 允许模型自由生成标签;
- 标签主要用于:
- 后续统计汇总;
- 筛选典型评论。
约束说明:
- 近义标签合并不作为 MVP 强制要求:
- 如果实现方便,允许简单合并(如手动规则);
- 未实现不影响 MVP 验收。
### 5.5 热点级汇总报告
功能范围:
- 对每个热点生成一份轻量热点级汇总报告;
- 报告基于该热点下已抓取内容条目的评论级分析结果聚合生成;
- MVP 不做平台级日报,也不做跨热点汇总报告。
报告至少包含:
1. 热点基础信息;
2. 该热点下内容条目数量;
3. 总评论样本数量;
4. 正向 / 负向 / 中性评论整体数量和占比;
5. Top 5 方向标签及数量;
6. 典型评论若干;
7. AI 生成的简短热点总结。
### 5.6 内容条目级分析报告
功能范围:
- 对每个内容条目生成一份内容条目级分析报告;
- 报告至少包含:
1. 样本评论数量;
2. 正向 / 负向 / 中性评论数量和占比;
3. 主要方向标签及占比(可按标签聚合统计);
4. 典型评论:
- 典型正向评论 1~2 条;
- 典型负向评论 1~2 条;
- 典型中性评论 1~2 条;
- 典型的挑选可基于情绪+点赞数或由 AI 挑选;
5. AI 生成的简短内容条目级总结:
- 强调事实性统计、常见观点;
- 不要求深度运营洞察。
### 5.7 页面查看
功能范围:
- 热点与内容条目列表页:
- 展示抓取到的热点列表;
- 展示每个热点下的相关内容条目列表;
- 包含平台、热点标题、内容条目标题/摘要、抓取时间、分析状态等基本信息。
- 支持进入单个热点的汇总报告。
- 内容条目详情页:
- 展示内容条目级分析报告(见 5.6);
- 展示评论明细列表:
- 评论内容;
- 情绪与方向标签;
- 点赞数等基础信息。
- 任务状态查看:
- 任务级状态:运行中 / 成功 / 失败;
- 每次任务的基本信息(时间、平台、热点数、内容条目数)。
UI 不要求精细设计,MVP 以简洁可用为目标。
### 5.8 导出
功能范围:
- 热点级汇总报告导出为 Markdown:
- 字段包括:热点基础信息、内容条目数量、评论样本量、情绪分布、方向标签分布、典型评论、总结;
- 以结构化 Markdown 文本输出,便于阅读和版本管理。
- 内容条目级报告导出为 Markdown:
- 字段包括:所属热点信息、内容条目基础信息、评论样本量、情绪分布、方向标签分布、典型评论、总结;
- 以结构化 Markdown 文本输出,便于阅读和版本管理。
- 内容条目评论明细导出为 CSV
- 字段包括:平台、抓取日期/任务标识、热点信息、内容条目信息、评论内容、情绪、方向标签、点赞数、评论时间等;
- 用于后续本地分析或导入其他工具。
### 5.9 部署
部署目标:
- 使用 Docker Compose 实现一键启动:
- 后端服务;
- 前端服务;
- 数据库(如 PostgreSQL / MySQL / SQLite 服务化);
- 支持在开发者本机或组内服务器部署;
- 通过浏览器访问 Web 页面进行操作。
具体技术选型:
- 在后续 DevelopmentPlan.md 中确定;
- MVP 要求 docker-compose.yml 能将所需组件统一编排。
---
## 6. 任务状态与异常处理(精简版)
功能范围:
- 任务状态:
- 运行中;
- 成功;
- 失败。
- 进度展示(可选,建议实现):
- 已处理内容条目数 / 总内容条目数(例如“3 / 8”);
- 简单数值即可,不做复杂进度条。
- 错误信息:
- 在任务详情中展示失败原因简要说明,例如:
- API 请求失败;
- API 响应异常;
- AI 调用失败或超时;
- 数据入库失败等。
- 容错行为:
- 单个热点或内容条目抓取或分析失败时:
- 记录错误;
- 尝试继续处理剩余热点或内容条目;
- 不要求严格保证“所有内容条目都成功”,但整体任务不因单个内容条目失败直接终止。
约束说明:
- 不做复杂任务编排和恢复机制;
- 不实现:
- 部分成功状态;
- 自动补跑;
- 分布式锁;
- 阶段拆分与单独重试。
---
## 7. 非功能需求
### 7.1 可用性
- 页面结构简单清晰,用户能快速理解:
- 当前有哪些抓取任务;
- 每个任务的状态;
- 热点、内容条目分析的结果与评论明细。
- 错误信息可见,方便调试与排查。
### 7.2 可维护性
- 核心流程模块化:
- 外部 API 调用;
- 数据存储;
- AI 分析;
- 报告生成;
- 前端展示与导出。
- 抓取参数可配置:
- 平台;
- 每次抓取的热点数量(Top N);
- 单条内容条目评论上限。
- AI 提示词与输出 schema 单独管理,便于后续迭代。
### 7.3 数据质量
- 保留原始评论内容,不对原文做不可逆修改。
- AI 结构化结果(情绪、标签、理由)要与原始评论关联(如通过评论 ID)。
- 报告中的统计数据由结构化结果计算,而不是仅依赖模型自由生成的总体总结。
### 7.4 安全与配置
- API Key、AI Key 等敏感信息不写入代码仓库:
- 使用环境变量或配置文件(不纳入版本控制)。
- 系统默认用于内部环境,不开放公网访问。
- 登录鉴权:
- MVP 默认不做登录与权限控制;
- 如教学或审阅要求访问控制,再追加单管理员账号方案。
---
## 8. MVP 成功标准
必须达成的验收点:
1. 系统能通过 Docker Compose 启动,并在浏览器访问。
2. 用户可以从页面手动触发抓取任务,指定平台(小红书 / 抖音)。
3. 系统能从外部 API 获取该平台默认 Top 5 热点。
4. 系统能从每个热点拆分出相关内容条目,并对每条内容条目抓取一级评论(默认规模为 5 × 5 × 50,配置上限为 10 × 10 × 100)。
5. 系统能对评论生成:
- 情绪分类;
- 方向标签;
- (可选)简短理由。
6. 系统能生成并展示热点级汇总报告与内容条目级分析报告:
- 情绪分布;
- 标签分布;
- 典型评论;
- 简短总结。
7. 用户可以在页面查看:
- 热点列表;
- 热点级汇总报告;
- 内容条目列表;
- 内容条目详情;
- 评论明细。
8. 用户可导出:
- CSV 评论明细;
- Markdown 热点级汇总报告;
- Markdown 内容条目级分析报告。
9. 任务失败时,能看到任务状态为“失败”,并能看到简要错误原因。
质量与稳定性目标(尽力达成,不作为硬性阻塞):
- 情绪分类与方向标签抽查时方向基本合理。
- 报告中的统计数据与评论结构化结果一致。
- 单个热点或内容条目失败不导致整批任务完全不可用。
---
## 9. 暂不纳入 MVP 的范围(Out of Scope
以下能力明确不在 4 天 MVP 内:
- 定时自动抓取任务(如每日定时调度)。
- 任务并发控制、分布式锁、复杂任务调度。
- 自动补跑、任务阶段粒度显示(获取热点榜单、拆分内容条目、抓取评论、AI 分析等细粒度阶段)。
- 大规模批量抓取:
- Top 50 及以上热点;
- 单条内容条目 200 条及以上评论。
- 平台级每日汇总报告:
- 小红书整体 / 抖音整体的汇总分析;
- 跨热点聚合的 Top 话题、平台层总结等(降为后续 P1)。
- 多用户与角色权限管理:
- 注册、登录、角色控制、操作审计。
- 登录鉴权(除非明确教学需要)。
- Excel 导出、用户侧正式 JSON 导出。
- 二级评论抓取、评论回复功能、自动发布、私信运营。
- 长期趋势分析(跨天、跨周、跨月趋势)。
- 品牌专题分析、关键词筛选热点。
- 移动端适配、复杂 BI 大屏可视化。
- 评论人工标注校正工作台。
- 自动形成运营建议或营销动作。
- 外部分享链接、公开访问和权限控制。
---
## 10. 待确认事项
以下事项不阻塞本需求文档,在 PRD、DevelopmentPlan 或开发阶段逐步确认。小红书 / 抖音最小抓取链路已通过 API Spike 验证,后续重点是把已验证链路产品化、工程化:
1. 小红书 / 抖音热点榜单、内容条目与评论 API 的工程化细节:
- 字段映射与字段兼容策略;
- 原始 JSON 保存方式;
- 热点与内容条目的关联落库方式。
2. 评论 API 的:
- 分页策略;
- 排序规则(时间 / 热度);
- 限流策略;
- 异常码定义。
3. AI 服务的选型:
- 提供商;
- 模型名称;
- 费用和调用速率限制;
- 是否需要批量调用或并发控制。
4. AI 输出结构的具体 schema
- 字段名称;
- 枚举值规范(情绪、标签字段的格式约定)。
5. Docker Compose 的架构:
- 是否引入任务队列组件(如 Celery / Redis);
- 或在 MVP 阶段采用简单同步处理。
---
## 11. 文档开发与审阅流程
采用 Spec 先行的文档驱动开发流程,文档顺序:
1. RequirementsDoc.md(当前文档)
2. PRD.md(产品需求文档)
3. FeatureSummary.md(功能拆解与优先级)
4. DevelopmentPlan.md(技术方案与实现路径)
5. UIDesign.md(关键页面与交互草图)
6. TDD.md(测试设计文档)
7. Tasks.md(任务拆解与排期)
审阅要求:
- 不直接修改主文档,每个审阅方生成独立审阅文件:
- 文件命名建议:`review-<文档名>-<审阅方>.md`
- 审阅语言为中文,采用结构化形式。
- 审阅重点:
- 缺失需求;
- 模糊或冲突需求;
- 过度设计风险;
- 验收标准是否充分;
- 后续文档与实现的风险点。
- 审阅发现需要用户决策的问题时:
- 以问题或建议形式提出;
- 不擅自更改主文档。
- 主 AI 负责汇总多方审阅意见,形成修订建议;
- 用户确认修订后的主文档后,方可进入下一阶段文档编写。
---
+958
View File
@@ -0,0 +1,958 @@
# UIDesign.md:小红书 / 抖音热榜评论抓取 + AI 分析报告工具
> 版本:v1.1
> 状态:MVP 设计稿(已审阅)
> 最后更新:2025-07-10
> 关联文档:DevelopmentPlan.md / FeatureSummary.md
## 1. 文档信息
- 文档阶段:UIDesign(界面与交互设计文档)
- 需求与技术依据:`PRD.md``FeatureSummary.md``DevelopmentPlan.md`
- 视觉风格:工程化、简洁、信息密度高,以数据看板、表格和轻量报告为主
- 技术实现前提:FastAPI Jinja2 模板 + Bootstrap 5 CDN + 简单 CSS + 原生 JSHTMX 作为 P1 局部刷新增强方案
- 目标用户:内部演示、开发联调、产品/数据分析同事查看抓取与分析结果
## 2. 设计原则与全局规范
### 2.1 设计原则
- 信息优先:核心数据,包括进度、状态、评论样本数、情绪分布和导出入口,必须在第一视觉层级。
- 状态透明:任务的等待、运行、成功、失败、AI 样本不足和分析失败必须通过统一 Badge、颜色和文案展示。
- 极简交互:避免复杂弹窗和多步引导,抓取、查看、导出等操作入口扁平化呈现。
- 调试友好:MVP 是工程演示工具,允许在详情页保留原始 JSON 调试入口,但不作为正式用户功能。
- 移动端可读:不依赖 Hover 作为主信息通道,错误原因和状态说明应直接可见。
### 2.2 全局样式规范
推荐直接使用 Bootstrap 5 CDN,降低 4 天 MVP 开发复杂度。
主色调:
- Primary(主要操作/高亮):`#0d6efd`
- Success(成功/正向情绪):`#198754`
- Danger(失败/负向情绪/错误):`#dc3545`
- Warning(运行中/中性情绪/分析不足):`#ffc107`
- Secondary(次要信息/未知状态):`#6c757d`
版式:
- 顶部固定导航栏。
- 主体内容区居中,最大宽度建议 `1200px`
- 页面主体使用 Bootstrap `.container`
- 模块使用 Card、Table、Accordion、Alert、Badge、Progress Bar 等基础组件。
- 不做复杂营销式视觉设计,优先保证密集信息下的可读性和操作效率。
## 3. 路由与接口总表
### 页面路由(返回 HTML,由 Jinja2 渲染)
| 方法 | 路径 | 用途 | 对应模板 |
|---|---|---|---|
| GET | `/` | 首页 / 任务列表页 | `index.html` |
| GET | `/tasks/{task_id}` | 任务详情页(热点与内容条目列表) | `tasks/detail.html` |
| GET | `/hotspots/{hotspot_id}/report` | 热点级汇总报告页 | `hotspots/report.html` |
| GET | `/items/{item_id}` | 内容条目详情页 | `items/detail.html` |
### API 接口(返回 JSON,供前端 JS 调用)
| 方法 | 路径 | 用途 | 返回格式 |
|---|---|---|---|
| POST | `/api/tasks` | 创建抓取任务 | JSON `{task_id, status}` |
| GET | `/api/tasks/{task_id}` | 查询任务最新状态 | JSON |
### 局部刷新接口(返回 HTML Fragment,供 HTMX 调用)
| 方法 | 路径 | 用途 | 返回格式 |
|---|---|---|---|
| GET | `/partials/tasks` | 刷新任务列表表格行 | HTML Fragment`task_rows.html` |
### 导出接口(返回文件流)
| 方法 | 路径 | 用途 | 返回格式 |
|---|---|---|---|
| GET | `/api/export/items/{item_id}/comments.csv` | 导出内容条目评论明细 CSV | File |
| GET | `/api/export/items/{item_id}/report.md` | 导出内容条目分析报告 Markdown | File |
| GET | `/api/export/hotspots/{hotspot_id}/report.md` | 导出热点汇总报告 Markdown | File |
| GET | `/api/export/hotspots/{hotspot_id}/comments.csv` | 导出热点下全部评论汇总 CSV | File |
## 4. 状态枚举与 UI 映射规范
所有模板中的状态展示统一依据以下枚举值映射,禁止在模板中硬编码中文状态文案。
### Task.status
| 后端值 | 中文展示 | Badge 样式 |
|---|---|---|
| `pending` | 等待中 | `bg-secondary` |
| `running` | 运行中 | `bg-warning text-dark` |
| `success` | 已完成 | `bg-success` |
| `failed` | 失败 | `bg-danger` |
### Task.analysis_status
| 后端值 | 中文展示 | Badge 样式 | 说明 |
|---|---|---|---|
| `normal` | — | 不展示 | 正常,无需提示 |
| `insufficient` | ⚠️ AI 样本不足 | `bg-warning text-dark` | 展示 Alert 提示 |
| `failed` | ⚠️ AI 分析失败 | `bg-danger` | 展示 Alert 提示 |
### Item.status
| 后端值 | 中文展示 | 样式 |
|---|---|---|
| `pending` | 等待抓取 | `text-secondary` |
| `crawling` | 抓取中 | `text-warning` |
| `analyzing` | 分析中 | `text-info` |
| `success` | 已分析 | `text-success` |
| `crawl_failed` | 抓取失败 | `text-danger` |
| `analysis_failed` | 分析失败 | `text-danger` |
### Comment.analysis_status
| 后端值 | 中文展示 | 说明 |
|---|---|---|
| `success` | — | 正常,无需特殊标注 |
| `insufficient` | 样本不足 | 灰色斜体提示 |
| `failed` | 解析失败 | 红色文字 |
| `skipped` | 未分析 | 灰色文字 |
### sentiment(情绪倾向)
| 后端值 | 中文展示 | Badge 样式 |
|---|---|---|
| `positive` | 正向 | `bg-success` |
| `neutral` | 中性 | `bg-warning text-dark` |
| `negative` | 负向 | `bg-danger` |
| `unknown` | 未知 | `bg-secondary` |
## 5. 面包屑导航与页面标题规范
### 各页面面包屑路径
| 页面 | 面包屑层级 |
|---|---|
| `/` | 首页 |
| `/tasks/{task_id}` | 首页 任务 \#{task_id} |
| `/hotspots/{hotspot_id}/report` | 首页 任务 \#{task_id} 热点 \#{rank}{title} 汇总报告 |
| `/items/{item_id}` | 首页 任务 \#{task_id} 热点 \#{rank}{title} {item_title} |
面包屑使用 Bootstrap 的 `<nav aria-label="breadcrumb">` 组件,放置于页面 `<main>` 容器顶部、页面标题之上。
### 浏览器标签页 `<title>` 格式
| 页面 | `<title>` 格式 |
|---|---|
| `/` | `任务列表 - 热榜评论分析工具` |
| `/tasks/{task_id}` | `任务 \#{task_id} - 热榜评论分析工具` |
| `/hotspots/{hotspot_id}/report` | `{hotspot_title} 汇总报告 - 热榜评论分析工具` |
| `/items/{item_id}` | `{item_title} 详情 - 热榜评论分析工具` |
`base.html` 中使用 Jinja2 block
```jinja2
<title>{% block title %}热榜评论分析工具{% endblock %}</title>
```
各子页面覆盖:
```jinja2
{% block title %}任务列表 - 热榜评论分析工具{% endblock %}
```
## 6. 全局布局(Global Layout
所有页面共享 `base.html` 布局。
```text
+-------------------------------------------------------------+
| [Logo/Title] 抓取与分析工具 [首页/任务列表] |
+-------------------------------------------------------------+
| |
| Breadcrumb: 首页 > 任务 #1234 > 热点分析 |
| |
| [ 主体内容区域 ] |
| |
+-------------------------------------------------------------+
| Footer: 内部演示工具 | 仅供学习参考 |
+-------------------------------------------------------------+
```
基础结构:
- Navbar:左侧为产品名「热榜评论分析工具」,右侧保留「任务列表」入口。
- Breadcrumb:每个页面放在标题上方。
- Main:页面核心内容,使用 `.container py-4`
- Footer:简短说明「内部演示工具 | 仅供学习参考」。
## 7. 核心页面设计
### 7.1 首页 / 任务列表页(`/`)
页面目标:提供配置入口触发抓取;查看历史与当前任务进度。
#### 区域 A:创建任务表单
使用 Bootstrap Card 承载表单,字段紧凑排列。
字段控件:
- 平台选择:Radio Buttons 或 Select,选项为「小红书」「抖音」。
- 热点数量上限:Number Input,默认 `5`,范围 `1-10`
- 每热点内容上限:Number Input,默认 `5`,范围 `1-10`
- 每内容评论上限:Number Input,默认 `50`,范围 `10-100`
- 操作按钮:`开始抓取`Primary Button。
#### 表单提交交互(异步 JS 模式)
- 表单**不使用** HTML `<form action="..." method="POST">` 同步提交,改用 JavaScript `fetch()` 异步提交。
- 点击「开始抓取」按钮后的流程:
```javascript
// static/app.js
async function submitTask() {
const btn = document.getElementById("submit-btn");
const errorBox = document.getElementById("form-error");
// 1. 读取表单值
const payload = {
platform: document.getElementById("platform").value,
hotspot_limit: parseInt(document.getElementById("hotspot_limit").value),
item_limit: parseInt(document.getElementById("item_limit").value),
comment_limit: parseInt(document.getElementById("comment_limit").value),
};
// 2. 禁用按钮,显示 Loading
btn.disabled = true;
btn.innerHTML = `<span class="spinner-border spinner-border-sm"></span> 提交中...`;
errorBox.classList.add("d-none");
try {
const resp = await fetch("/api/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
if (resp.ok) {
// 3. 成功:跳转至新任务详情页
const data = await resp.json();
window.location.href = `/tasks/${data.task_id}`;
} else if (resp.status === 422) {
// 4. 校验失败:在表单上方渲染错误 Alert
const data = await resp.json();
const messages = data.detail.map(e => e.msg).join("");
errorBox.textContent = `参数错误:${messages}`;
errorBox.classList.remove("d-none");
} else {
errorBox.textContent = "服务器错误,请稍后重试。";
errorBox.classList.remove("d-none");
}
} catch (e) {
errorBox.textContent = "网络异常,请检查连接后重试。";
errorBox.classList.remove("d-none");
} finally {
btn.disabled = false;
btn.innerHTML = "开始抓取";
}
}
```
- 表单顶部须预留错误展示区:
```html
<div id="form-error" class="alert alert-danger d-none" role="alert"></div>
```
- **表单提交成功后**:直接跳转至 `/tasks/{new_task_id}`,用户可立即在任务详情页看到初始 `pending` 状态。
#### 规模预估提示(表单底部)
在三个配置输入框下方,实时展示预估抓取规模:
```html
<div class="form-text text-muted mt-2" id="scale-hint">
预计最多抓取:<strong id="scale-calc">1250</strong> 条评论
(实际数量可能受平台返回数量、去重、失败、限流影响)
</div>
```
```javascript
// 三个输入框 oninput 时实时更新
function updateScaleHint() {
const h = parseInt(document.getElementById("hotspot_limit").value) || 0;
const i = parseInt(document.getElementById("item_limit").value) || 0;
const c = parseInt(document.getElementById("comment_limit").value) || 0;
document.getElementById("scale-calc").textContent = (h * i * c).toLocaleString();
}
```
#### 区域 B:任务列表
使用 Table 展示任务。
表头:
```text
任务 ID / 平台 / 创建时间 / 配置规模 / 进度 / 状态 / 操作
```
进度展示:
- 已成功内容条目数 / 总内容条目数。
- 可同时展示 Bootstrap Progress Bar。
- 如果任务刚创建且 `started_at` 为空,进度列显示「等待开始...」灰色文字。
#### 任务列表状态列与错误信息展示
- 状态列展示 `status` 对应的 Badge(见状态枚举规范章节)。
-`analysis_status != 'normal'`,在 Badge 后追加 ⚠️ 图标。
- **错误信息展示层级**
- 任务列表中,仅在状态 Badge 下方以灰色小字直接展示 `error_stage` / `error_type`(不使用 Hover tooltip,Hover 不支持移动端且不适合长文本):
```html
<span class="badge bg-danger">失败</span>
<br>
<small class="text-muted">{{ task.error_stage }} / {{ task.error_type }}</small>
```
- 完整 `error_message` 仅在 `/tasks/{task_id}` 任务详情页展示。
- Tooltip 可作为 `error_type` 的辅助说明(限 50 字以内),不作为主信息通道。
#### 配置规模列展示格式
```html
<small class="text-muted">热点 {{ task.hotspot_limit }} / 内容 {{ task.item_limit }} / 评论 {{ task.comment_limit }}</small>
```
#### P1 方案:HTMX 任务列表自动轮询
HTMX 通过 `/partials/tasks` 接口获取 HTML Fragment(服务端渲染 `task_rows.html`),每 5 秒更新一次 `<tbody>` 内容,无需手写 DOM 操作。
```html
<!-- index.html 任务列表区域 -->
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="text-muted small">
<span id="refresh-spinner" class="htmx-indicator">⟳ 刷新中...</span>
</span>
<button
class="btn btn-sm btn-outline-secondary"
hx-get="/partials/tasks"
hx-target="#task-table-body"
hx-swap="innerHTML"
hx-indicator="#refresh-spinner">
↻ 手动刷新
</button>
</div>
<table class="table table-hover align-middle">
<thead>
<tr>
<th>任务 ID</th>
<th>平台</th>
<th>创建时间</th>
<th>配置规模</th>
<th>进度</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody
id="task-table-body"
hx-get="/partials/tasks"
hx-trigger="every 5s [document.querySelector('.badge.bg-warning') !== null]"
hx-swap="innerHTML"
hx-indicator="#refresh-spinner">
{% include "partials/task_rows.html" %}
</tbody>
</table>
```
说明:
- `hx-trigger="every 5s [condition]"` 中的条件判断页面上是否存在 `running` 状态的任务(Badge 为 `bg-warning`)。所有任务完成后条件为 false,自动停止轮询,避免无效请求。
- `hx-indicator` 在请求进行中显示「⟳ 刷新中...」提示。
- `/partials/tasks` 返回纯 HTML Fragment`<tr>` 行集合),不是 JSON。
#### P0 方案:原生 JS 定时轮询(HTMX 不可用时降级)
```javascript
// static/app.js
function startPolling() {
const interval = setInterval(async () => {
const resp = await fetch("/partials/tasks");
const html = await resp.text();
document.getElementById("task-table-body").innerHTML = html;
// 若页面上已无 running 状态,停止轮询
if (!document.querySelector(".badge.bg-warning")) {
clearInterval(interval);
}
}, 5000);
}
if (document.querySelector(".badge.bg-warning")) startPolling();
```
### 7.2 热点与内容条目列表页(`/tasks/{task_id}`
页面目标:展示任务宏观执行结果,作为进入具体报告的路由中枢。
#### 区域 A:任务概览看板
使用 Card + Bootstrap `row + col` 网格排列。
#### 任务概览看板字段清单
| 字段 | 数据来源 | 展示位置 |
|---|---|---|
| 任务 ID | `task.id` | 左上 |
| 平台 | `task.platform`(小红书 / 抖音) | 左上并排 |
| 创建时间 | `task.created_at` | 第二行左 |
| 任务耗时 | `task.finished_at - task.started_at`(运行中显示「进行中」) | 第二行右 |
| 任务状态 | `task.status` Badge | 第三行左 |
| AI 分析状态 | `task.analysis_status` Badgenormal 时不展示) | 第三行右 |
| 内容条目进度 | 成功 {success_count} / 共 {total_count} 条 | 第四行 |
| 失败条目数 | `task.failed_items_count`(大于 0 时显示红色) | 第四行并排 |
| 错误阶段 / 类型 | `task.error_stage` / `task.error_type`(仅 `status=failed` 时展示) | 第五行,红色 Alert |
| 完整错误信息 | `task.error_message`(仅 `status=failed` 时,折叠展示) | 第五行,可展开 |
#### 区域 B:热点手风琴列表
`rank` 排序展示热点。
```text
▼ 热点 #1: [热点标题] (热度: 120w) -------------------- [ 查看热点级汇总报告 ↗ ]
|
|-- [视频/笔记] 标题摘要 1 | 状态: 已分析 | [ 查看详情 ↗ ]
|-- [视频/笔记] 标题摘要 2 | 状态: 抓取失败 (API限流)
|-- [视频/笔记] 标题摘要 3 | 状态: 已分析 | [ 查看详情 ↗ ]
▶ 热点 #2: [热点标题] (热度: 98w) --------------------- [ 查看热点级汇总报告 ↗ ]
```
#### 手风琴默认展开状态
- 默认展开 `rank=1` 的第一个热点,其余折叠。
- 若热点下所有内容条目均为 `crawl_failed`,该热点的「查看汇总报告」按钮置灰,`disabled`,Tooltip 文本:「暂无报告(该热点内容全部抓取失败)」。
#### 任务 running 时内容列表空状态
`task.status = running``hotspots` 列表为空(抓取尚未返回任何热点),展示:
```html
<div class="text-center text-muted py-5">
<div class="spinner-border text-warning mb-3" role="status"></div>
<p>正在抓取热点数据,请稍候...</p>
<small>页面将每 5 秒自动刷新</small>
</div>
```
### 7.3 热点级汇总报告页(`/hotspots/{hotspot_id}/report`
页面目标:展示跨内容条目的聚合分析结果。
#### 热点报告页面包屑
```html
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">首页</a></li>
<li class="breadcrumb-item"><a href="/tasks/{{ task.id }}">任务 #{{ task.id }}</a></li>
<li class="breadcrumb-item"><a href="/tasks/{{ task.id }}">热点 #{{ hotspot.rank }}{{ hotspot.title }}</a></li>
<li class="breadcrumb-item active">汇总报告</li>
</ol>
</nav>
```
#### 顶部操作栏
右上角提供:
- `导出 Markdown 报告`
- `导出热点下全部评论 CSV`
导出按钮可用状态遵循「导出交互规范」章节。
#### 数据看板
基础统计卡片:
- 关联内容条目数。
- 评论样本总量。
- 成功分析评论数。
- AI 分析状态。
#### 情绪分布展示规范
情绪分布不能只展示百分比,必须并列展示具体条数:
```html
<!-- 正向情绪行示例 -->
<div class="d-flex justify-content-between mb-1">
<span>🟩 正向</span>
<span class="text-muted">{{ positive_count }} 条({{ positive_pct }}%</span>
</div>
<div class="progress mb-3" style="height: 12px;">
<div class="progress-bar bg-success" style="width: {{ positive_pct }}%"></div>
</div>
```
三种情绪(正向 / 中性 / 负向)均按此格式展示,数据来源为 `report.metrics_json` 中的情绪统计字段。
#### 标签与总结
- Top 5 标签云:例如 `[ 价格实惠 (15) ] [ 质量好 (12) ] [ 物流慢 (8) ]`
- AI 热点总结:使用浅蓝色 Callout 展示,不超过 300 字。
- 如果 `analysis_status = insufficient`,展示样本不足 Alert。
- 如果 `analysis_status = failed`,展示「总结生成失败,请查看上方统计数据。」灰色文本。
#### 典型评论
按情绪分列展示:
- 正向代表:1-2 条,显示点赞数。
- 中性代表:1-2 条,显示点赞数。
- 负向代表:1-2 条,显示点赞数。
### 7.4 内容条目详情页(`/items/{item_id}`
页面目标:单条内容的深度报告与评论明细展示。
#### 顶部操作栏
- `导出 Markdown 报告`
- `导出 CSV 评论明细`
#### 原始内容链接
在内容条目基础信息区域末尾展示:
```html
{% if item.url %}
<a href="{{ item.url }}" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-outline-secondary">
🔗 查看原始内容
</a>
{% else %}
<button class="btn btn-sm btn-outline-secondary" disabled title="原始链接不可用">
🔗 查看原始内容
</button>
{% endif %}
```
#### 区域 A:内容条目级分析报告
结构与热点级报告一致,但范围限定为单个内容条目:
- 样本评论数量。
- 情绪条数和占比。
- Top 5 标签。
- AI 总结,建议 200 字以内。
- 典型评论。
如果报告尚未生成,展示 Spinner +「报告生成中,请稍候...」。
#### 原始 JSON 调试入口(原生折叠,零 JS)
```html
<details class="mt-3">
<summary class="btn btn-sm btn-outline-secondary" style="display: inline-block; cursor: pointer;">
🐞 查看原始 JSON(调试)
</summary>
<div class="mt-2 p-3 bg-light rounded border">
<pre class="mb-0" style="max-height: 400px; overflow-y: auto; font-size: 0.8em;">{{ item.raw_data | tojson(indent=2) }}</pre>
</div>
</details>
```
优点:
- 零 JS 依赖,使用 HTML5 原生 `<details>/<summary>` 元素。
- 自动支持长内容滚动,不存在 Modal 在小屏幕溢出的问题。
- 点击展开 / 再点收起,体验如手风琴折叠。
#### 区域 B:评论明细列表
#### 评论明细展示策略
- MVP 阶段评论明细**一次性展示,不做后端分页**。
- 最多展示 100 条评论,按**点赞数降序**排列;点赞数相同时按**评论时间降序**。
- 若评论总数超过 50 条,在表格上方展示数量提示:
```html
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="text-muted small">共 {{ total_comment_count }} 条评论,展示前 {{ comments | length }} 条</span>
<span class="text-muted small">如需查看全部,请导出 CSV</span>
</div>
```
表头:
```text
评论 ID / 评论内容 / 情绪倾向 / 方向标签 / 点赞数 / 评论时间
```
展示逻辑:
- 情绪倾向:使用 `sentiment_badge` Macro。
- 方向标签:将 JSON Array 解析为多个独立的小 Tag 块;为空显示 `-`
- 评论内容:长文本使用 CSS `text-truncate`,可在详情或 tooltip 中查看完整内容。
-`comment.analysis_status == 'failed'`,情绪列显示「解析失败」红色文字,不影响其他行。
- 若评论为空,展示「暂无评论数据(该内容无评论或评论抓取为空)」。
## 8. 表单校验、交互状态与空状态
### 8.1 表单校验行为
前端拦截:
- 热点数量范围:`1-10`
- 每热点内容上限范围:`1-10`
- 每内容评论上限范围:`10-100`
- 输入非法值时,Input 边框变红,失去焦点及提交时显示提示文本,例如「最大值为 10」。
- 非法输入阻止提交。
后端双重校验:
- 若绕过前端提交,FastAPI 返回 HTTP 422。
- 页面通过异步 JS 将错误信息渲染到 `#form-error` Alert。
### 8.2 空状态场景
| 场景 | 页面 | 展示内容 |
|---|---|---|
| 任务列表无任何任务 | 首页 | 「还没有任何任务,请在上方创建第一个任务 🚀」 |
| 任务 running 但热点列表为空 | 任务详情页 | Spinner + 「正在抓取热点数据,请稍候...」 |
| 热点下评论数为 0 | 内容详情页评论区 | 「暂无评论数据(该内容无评论或评论抓取为空)」 |
| 任务刚创建未开始(`started_at` 为空) | 任务列表进度列 | 「等待开始...」灰色文字 |
| AI 样本不足(`analysis_status = insufficient`) | 报告页总结区域 | ⚠️ Alert:「当前有效评论样本不足,AI 总结暂不可用。建议增加评论抓取数量后重新分析。」 |
| AI 总结生成失败(`analysis_status = failed`) | 报告页总结区域 | 「总结生成失败,请查看上方统计数据。」灰色文字 |
| 报告尚未生成(内容条目分析中) | 内容详情页报告区 | Spinner + 「报告生成中,请稍候...」 |
| 导出文件内容为空 | 导出按钮点击后 | `alert("当前暂无可导出评论数据")` |
### 8.3 单条目失败不阻塞
如果某个视频或笔记抓取失败:
- 手风琴列表中该条目置灰。
- 不可点击详情。
- 状态列显示失败原因,例如「API 限流」。
- 其他成功条目仍可查看报告和评论明细。
如果 AI 总结生成失败:
- 页面不应 500。
- 总结区域展示「总结生成失败,请查看上方统计数据。」。
- 结构化统计和评论明细仍正常展示。
## 9. 导出交互规范
### 导出按钮可用/置灰前提条件
| 场景 | 按钮状态 | Tooltip 文本 |
|---|---|---|
| `task.status = running` | `disabled` | 任务运行中,请等待完成后导出 |
| `task.status = failed` 且无成功内容条目 | `disabled` | 任务失败,无可导出数据 |
| `item.status = crawl_failed` | `disabled` | 内容抓取失败,无评论数据 |
| 可导出(任务已完成且有数据) | 可点击 | — |
| 评论数为 0 | `disabled` | 当前暂无可导出评论数据 |
### 导出交互实现(增强型 JS Blob 下载)
```javascript
// static/app.js
async function downloadExport(url, defaultFilename) {
const btn = event.currentTarget;
const originalText = btn.innerHTML;
// 1. 按钮置灰,显示 Loading
btn.disabled = true;
btn.innerHTML = `<span class="spinner-border spinner-border-sm"></span> 生成中...`;
try {
const resp = await fetch(url);
if (!resp.ok) {
alert("导出失败,请稍后重试。");
return;
}
// 2. 从响应头获取文件名
const disposition = resp.headers.get("Content-Disposition");
const filenameMatch = disposition && disposition.match(/filename\*?=(?:UTF-8'')?["']?([^"';\n]+)/i);
const filename = filenameMatch ? decodeURIComponent(filenameMatch[1]) : defaultFilename;
// 3. 触发浏览器下载
const blob = await resp.blob();
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = blobUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(blobUrl);
} catch (e) {
alert("网络异常,请检查连接后重试。");
} finally {
// 4. 恢复按钮状态
btn.disabled = false;
btn.innerHTML = originalText;
}
}
```
### 导出按钮 HTML 示例
```html
<!-- 内容条目详情页导出区域 -->
<div class="d-flex gap-2 mt-3">
<button
class="btn btn-outline-primary"
onclick="downloadExport('/api/export/items/{{ item.id }}/comments.csv', 'comments.csv')"
{% if item.status != 'success' %}disabled title="内容抓取失败,无评论数据"{% endif %}>
⬇️ 导出评论 CSV
</button>
<button
class="btn btn-outline-secondary"
onclick="downloadExport('/api/export/items/{{ item.id }}/report.md', 'report.md')"
{% if not report %}disabled title="报告尚未生成"{% endif %}>
⬇️ 导出 Markdown 报告
</button>
</div>
```
### CSV 导出安全处理(防 Excel 公式注入)
后端 `export_service.py` 导出 CSV 时,若评论内容首字符为 `=``+``-``@`,须在该字符前添加单引号前缀:
```python
def sanitize_csv_field(value: str) -> str:
"""防止 CSV 公式注入"""
if value and value[0] in ('=', '+', '-', '@'):
return f"'{value}"
return value
```
此项为后端实现规范,在 UIDesign 中作为说明记录。
## 10. 实施建议
### 10.1 模板复用
模板结构建议使用 Jinja2 的 `{% extends "base.html" %}``{% block content %}` 减少重复代码。
页面级模板仅负责布局和数据展示,状态 Badge、情绪 Badge、标签列表等重复结构应抽成 Macro。
### 10.2 样式框架
为了在 4 天 MVP 周期内完成,建议在 `base.html` 中直接引入 Bootstrap 5CSS + JS bundle)。Accordion、Badge、Progress Bar、Alert、Table、Button 等组件开箱即用。
### 10.3 Jinja2 自定义 Filter 注册(必须在 main.py 中完成)
原生 Jinja2 **没有** `from_json` Filter,直接在模板中使用 `{{ value | from_json }}` 会抛出 `TemplateAssertionError`。须在 FastAPI 初始化时手动注册:
```python
# app/main.py
import json
from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")
def from_json_filter(value):
"""将 JSON 字符串解析为 Python 对象,用于 Jinja2 模板"""
try:
return json.loads(value) if value else []
except (json.JSONDecodeError, TypeError):
return []
templates.env.filters["from_json"] = from_json_filter
```
注册后,模板中可安全使用:
```jinja2
{% for label in comment.labels | from_json %}
<span class="badge bg-secondary">{{ label }}</span>
{% else %}
<span class="text-muted">-</span>
{% endfor %}
```
### 10.4 base.html CDN 引入顺序
HTMX 必须在 Bootstrap JS Bundle 之后引入,避免事件冲突。推荐的 `<head>` 结构:
```html
<!-- ① Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- ② 自定义样式 -->
<link href="/static/app.css" rel="stylesheet">
<!-- ③ Bootstrap 5 JS Bundle(含 Popper,须在 HTMX 之前) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- ④ HTMX(P1 轮询方案,可选) -->
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<!-- ⑤ 自定义 JS(defer 确保 DOM 加载完成后执行) -->
<script src="/static/app.js" defer></script>
```
### 10.5 Jinja2 `|safe` Filter 使用约束
- Jinja2 默认对所有变量启用 HTML 转义,**禁止随意使用 `|safe`**。
- 仅在以下场景允许使用 `|safe`:由后端程序生成、非用户输入的可信 HTML 片段(如报告 Markdown 渲染后的 HTML)。
- 所有来源于外部平台的评论内容、热点标题、用户昵称等字段,严禁使用 `|safe`,必须经过 Jinja2 默认转义。
- 外部链接须添加安全属性:`<a href="..." target="_blank" rel="noopener noreferrer">`
## 11. 模板目录结构与 Jinja2 组件规范
### 模板目录结构
```text
templates/
├── base.html # 全局布局:导航栏、面包屑、CSS/JS 引入
├── index.html # 首页 / 任务列表页
├── tasks/
│ └── detail.html # 任务详情页(热点手风琴)
├── hotspots/
│ └── report.html # 热点级汇总报告页
├── items/
│ └── detail.html # 内容条目详情页
└── partials/
├── task_rows.html # 任务列表表格行(HTMX 局部刷新片段)
├── status_badge.html # 任务状态 Badge 组件
├── sentiment_badge.html # 情绪倾向 Badge 组件
└── label_tags.html # 标签 Badge 列表组件
```
### Jinja2 Macro 组件规范
#### status_badge(任务状态 Badge
`partials/status_badge.html` 中定义:
```jinja2
{% macro status_badge(status) %}
{% set config = {
"pending": ("等待中", "bg-secondary"),
"running": ("运行中", "bg-warning text-dark"),
"success": ("已完成", "bg-success"),
"failed": ("失败", "bg-danger"),
} %}
{% set label, style = config.get(status, ("未知", "bg-secondary")) %}
<span class="badge {{ style }}">{{ label }}</span>
{% endmacro %}
```
使用方式:
```jinja2
{% from "partials/status_badge.html" import status_badge %}
{{ status_badge(task.status) }}
```
#### sentiment_badge(情绪倾向 Badge
```jinja2
{% macro sentiment_badge(sentiment) %}
{% set config = {
"positive": ("正向", "bg-success"),
"neutral": ("中性", "bg-warning text-dark"),
"negative": ("负向", "bg-danger"),
} %}
{% set label, style = config.get(sentiment, ("未知", "bg-secondary")) %}
<span class="badge {{ style }}">{{ label }}</span>
{% endmacro %}
```
#### label_tags(标签列表)
```jinja2
{% macro label_tags(labels_json) %}
{% for label in labels_json | from_json %}
<span class="badge bg-secondary me-1">{{ label }}</span>
{% else %}
<span class="text-muted">-</span>
{% endfor %}
{% endmacro %}
```
## 12. 模板变量结构参考
以下为各页面 Jinja2 模板的后端数据结构示例,供模板开发对照使用。
### 首页(index.html
```python
{
"tasks": [
{
"id": 123,
"platform": "xhs", # "xhs" | "douyin"
"created_at": "2025-01-01 10:00:00",
"hotspot_limit": 5,
"item_limit": 5,
"comment_limit": 50,
"total_items_count": 25,
"successful_items_count": 18,
"failed_items_count": 3,
"status": "running", # 见状态枚举
"analysis_status": "normal", # 见状态枚举
"error_stage": None,
"error_type": None,
"error_message": None,
}
]
}
```
### 内容条目详情页(items/detail.html
```python
{
"task": { "id": 123, "platform": "douyin" },
"hotspot": { "id": 456, "rank": 1, "title": "热点标题" },
"item": {
"id": 789,
"title": "视频标题",
"platform": "douyin",
"url": "https://www.douyin.com/video/xxx",
"status": "success",
"raw_data": { ... }, # 调试用,通过 | tojson 渲染
},
"report": {
"comment_count": 100,
"sentiment": {
"positive": { "count": 60, "pct": 60.0 },
"neutral": { "count": 20, "pct": 20.0 },
"negative": { "count": 20, "pct": 20.0 },
},
"top_labels": [
{ "name": "价格实惠", "count": 15 },
{ "name": "质量好", "count": 12 },
],
"summary": "该内容评论整体偏正向,用户对价格和质量满意度较高...",
"analysis_status": "success",
},
"comments": [
{
"id": 1,
"content": "这个产品不错",
"sentiment": "positive",
"labels": "[\"质量好\", \"价格实惠\"]", # JSON 字符串,模板用 | from_json 解析
"like_count": 20,
"created_at": "2025-01-01 11:00:00",
"analysis_status": "success",
}
],
"total_comment_count": 150, # 数据库实际总数,用于"展示前 N 条"提示
}
```
---
## 变更日志
| 日期 | 版本 | 变更内容 |
|---|---|---|
| 2025-07-10 | v1.0 | 初始版本 |
| 2025-07-10 | v1.1 | 基于双审阅报告合并修订(共 17 条指令):补充文档元数据;新增完整路由总表(页面路由 / API 接口 / HTMX 局部刷新 / 导出接口);新增状态枚举与 UI 映射规范(Task / Item / Comment / sentiment 四层);新增面包屑路径与 `<title>` 命名规范;表单提交改为异步 JS fetch 模式,422 错误表单内渲染;新增表单规模预估实时计算提示;任务列表错误信息从 Hover 改为直接展示 error_stage / error_type;修复 HTMX 代码片段截断问题,补全含条件触发的完整轮询示例;补充任务概览看板字段清单、手风琴默认展开规则和热点报告按钮置灰条件;情绪分布改为数值+百分比并列展示;评论明细限制 100 条 + 总数提示 + 按点赞数降序;新增原始内容 URL 跳转入口;JSON 调试入口从 Modal 改为原生 `<details>` 折叠;导出交互改为增强型 JS Blob 下载 + 补充按钮可用/置灰前提条件 + CSV 公式注入防护;补充 Jinja2 from_json filter 注册规范;补充 CDN 引入顺序和 `|safe` 使用约束;新增模板目录结构与三个 Jinja2 Macro 组件规范(status_badge / sentiment_badge / label_tags);补充 8 条空状态场景;新增模板变量结构参考(首页 + 内容详情页)。 |