# 调研结果 `result.json` 格式 本目录是这一格式的参考实现。后续做新调研时按这个结构组织, 配套的 `index.html` viewer 不用改就能复用。 --- ## 1. 目录结构 ``` / ├── result.json # 必需 - 主数据(下面详述) ├── images/ # 必需 - 本地化的所有图片 │ └── *.jpg | *.png | *.webp ├── index.html # 复用 viewer (从本目录复制即可) ├── serve.sh # 复用启动器 (从本目录复制即可) └── curate.py # 可选 - 生成 result.json 的脚本 ``` 约定: - `index.html` + `serve.sh` 是无依赖的(marked.js 走 CDN), 直接拷过去就能用 - 图片必须**本地化**(网络 URL 不算), 路径相对于 result.json 所在目录 --- ## 2. `result.json` schema 顶层是 **数组**, 每个元素是一条调研内容。 每一条必须是一个原始内容,不允许做总结/汇总。 ```ts type ResearchItem = { title: string; // 标题 description: string; // 一句话讲清楚: 这条内容回应了什么调研需求 / 为什么有价值 cover: string; // 封面图相对路径, 如 "images/foo-01.jpg"; 无封面填 "" author: string; // 作者; 不知道时填平台默认值如 "小红书博主" body: string; // 主要内容(markdown); 原文越完整越好 images: string[]; // 所有图的相对路径列表, 第一张通常就是 cover channel: string; // 来源渠道/平台 ID (枚举见下) url: string; // 溯源链接; 没有 URL 时填 "" feedback: Feedback; // 互动数据(命名统一, 缺失为 null) note: string; // 其他元信息(怎么找到的 / 缓存索引等), 见下 }; type Feedback = { view_count: number | null; // 阅读量 / 播放量 like_count: number | null; // 点赞 comment_count: number | null; // 评论数 collect_count: number | null; // 收藏 share_count: number | null; // 分享 }; type Result = ResearchItem[]; ``` ### 字段细则 | 字段 | 必需 | 说明 | |------|------|------| | `title` | ✓ | 取原文标题; 没有就用核心句子的前 30 字 | | `description` | ✓ | **AI 视角的一句话价值判断**, 不是原文摘要。回答"为什么值得收录"。控制在 1-3 句 | | `cover` | ✓ | 无图时填 `""`; viewer 会显示"无封面"占位 | | `author` | ✓ | 平台缺省: `小红书博主` / `知乎作者` / `B 站 UP` 等; YouTube 用 `author` 字段 | | `body` | ✓ | 原文 markdown。可保留 `#话题#` 等原始标签, 不必清洗 | | `images` | ✓ | 列表; 没有就 `[]`。每条建议**封顶 6 张** | | `channel` | ✓ | 平台 ID, 见下方枚举 | | `url` | ✓ | 用于点击"原文"跳转。本地资料没有 URL 时留 `""`, 信息写在 `note` | | `feedback` | ✓ | 互动数据 dict, **必须带齐所有标准 key**, 缺失值用 `null`(不是 `0`) | | `note` | ✓ | 其他溯源信息, 推荐 ` \| ` 分隔 | ### `channel` 枚举 `xhs` / `zhihu` / `youtube` / `bili` / `gzh`(公众号) / `weibo` / `douyin` / `toutiao` / `sph`(视频号) / `github` / `x` / `other` viewer 用 channel 决定 badge 颜色和过滤菜单。 ### `feedback` 命名统一规则 - **始终包含**所有 5 个标准 key, 即使该平台不提供 - **缺失值显式为 `null`**, 不要用 `0` 假装"无数据" - 搜索结果置顶项出现 `0` 几乎都是接口没返回, 应当作 `null` 处理 - 标准 key 不够用时可加额外字段, 但已有的 5 个不要换名 ```jsonc // xhs - 只能拿到 like_count "feedback": { "view_count": null, "like_count": 1683, "comment_count": null, "collect_count": null, "share_count": null } // youtube - 只有 view_count "feedback": { "view_count": 68216, "like_count": null, "comment_count": null, "collect_count": null, "share_count": null } ``` ### `note` 字段约定 这是一个在特殊情况下用来兜底记录特殊信息的字段,如无必要可以留空。 平台已经在 `channel`, 互动数据已经在 `feedback`, 这里别重复。 --- ## 3. 图片管理 - 必须**本地化**, 不依赖外部 CDN - 命名约定: `-.`, 如 `xhs-jimeng-iphone-01.jpg` - 同一条目的图按 `01, 02, ...` 编号 - 文件夹永远叫 `images/` - 扩展名按实际格式给; 网站给的 webp 也常用 `.jpg` 后缀, viewer 不挑 --- ## 4. 完整示例 ```json [ { "description": "从摄影师视角讲皮肤质感: 错误 vs 正确提示词对照, Nano Banana 2 实操;\"自然皮肤纹理/可见毛孔/雀斑/绒毛/油性高光/微瑕疵\" 等具体词清单, 直接可复用。", "cover": "images/zh-skin-texture-01.jpg", "title": "拒绝AI人像图片一眼假——皮肤质感", "author": "知乎作者", "body": "普通的AI人像都长着一副标准的AI脸:皮肤光滑得像剥了壳的鸡蛋...(原文 markdown)", "images": [ "images/zh-skin-texture-01.jpg", "images/zh-skin-texture-02.jpg", "images/zh-skin-texture-03.jpg" ], "channel": "zhihu", "url": "https://zhuanlan.zhihu.com/p/2022921513209271574", "feedback": { "view_count": null, "like_count": 4, "comment_count": null, "collect_count": null, "share_count": null }, "note": "" } ] ``` --- ## 5. viewer 标注是怎么和 JSON 配合的 (注意区分两个"反馈": JSON 里的 `feedback` 字段是平台**互动数据**; viewer 里用户的 ✓/✗/评论叫**标注**, 走另一套机制) - viewer 的 ✓/✗/评论 **只缓存在浏览器 localStorage** (key 含 URL path, 不同调研目录互不污染) - 点"导出标注"得到 markdown 文本, 自带每条的 `url` 和 `note` 引用——把这段 文本贴回对话, 我就能定位回 result.json 里的具体条目继续作业 - result.json 本身**不被 viewer 修改**; 想保留某次的标注快照, 把导出的 markdown 单独存一份就行 --- ## 6. 给"未来的我"的清单 接到一个新的调研任务, 走这套格式时: - [ ] 在合适目录新建 `analysis//` - [ ] 跑搜索 / 抓内容 → 选高价值条目(一般 15-25 条上限) - [ ] 每条**本地化封面 + 6 张内的图**到 `images/` - [ ] 写 `description` 时回答"为什么收录这条", 不要只复述标题 - [ ] `channel` 用枚举值; `feedback` 5 个 key 必须齐, 缺失用 `null` - [ ] `note` 不重复 channel / feedback,用来记录有必要的特殊信息,可以留空 - [ ] 拷贝本目录的 `index.html` + `serve.sh` 过去 - [ ] 跑 `./serve.sh` 自查一遍能不能正常显示