从 P5 的 HTML → 自动化审计 + 执行摘要 + 浏览器预览 + 交接 —— 项目闭环的最后一公里。
输入:P5 产出的 HTML 报告
输出:
docs/<品类>/4.采集执行摘要.md(交接文档)scripts/tools/_audit-<品类>-voc.js 必做 9 项const LA = require('./<品类>-analyze.js');
const data = LA.loadMerged();
const items = data.items;
const fs = require('fs');
console.log('===== <品类> VOC 质量审计 =====');
console.log(`总条数:${items.length} / 平台:${Object.keys(data.meta?.platforms || {}).join('+')}`);
// === 1. 各章节核心 VOC 抽查(章节主题 × 证据内容一致性)===
const CH_PROBES = [
{ ch: 'Ch1.1 成人版爆款', opts: { keyword: '本品名', contentMatch: /肠鸣|胃胀|好了|有用/ } },
{ ch: 'Ch2.1 妈咪爱场景', opts: { keyword: '妈咪爱', contentMatch: /宝宝|孩子|医生|月龄/ } },
// ... 每章至少 1 项
];
for (const p of CH_PROBES) {
const hit = LA.getEvidence(items, { ...p.opts, top: 3 });
console.log(`▶ ${p.ch}: ${hit.length} 条命中`);
if (hit.length < 3) console.log(` ⚠️ 证据不足`);
}
// === 2. H1-H8 假设覆盖检查 ===
console.log('\n▶ H1-H8 假设覆盖:');
for (let i = 1; i <= 8; i++) {
const n = items.filter(it => (it.hypotheses || []).includes('H' + i)).length;
const status = n >= 100 ? '✓' : n >= 50 ? '⚠️' : '❌';
console.log(` H${i}: ${n} 条 ${status}`);
}
// === 3. 重复检查(前 40 字相同)===
const bucket = new Map();
for (const it of items) {
const key = (it.content || '').slice(0, 40);
if (!bucket.has(key)) bucket.set(key, []);
bucket.get(key).push(it);
}
const dupGroups = [...bucket.values()].filter(g => g.length > 1).sort((a, b) => b.length - a.length);
console.log(`\n▶ 重复组 ${dupGroups.length} 组(前 5):`);
dupGroups.slice(0, 5).forEach((g, i) => {
console.log(` [${i + 1}] ${g.length} 条 · 「${g[0].content.slice(0, 60)}」`);
});
// === 4. 跳题检查(高赞无相关词)===
const offtopic = items.filter(it => {
const c = it.content || '';
if (c.length < 15) return false;
const hasRelevant = /<品类相关 regex>/.test(c);
return !hasRelevant && (it.likes || 0) >= 100;
});
console.log(`\n▶ 高赞跳题 ${offtopic.length} 条(前 10):`);
// === 5. HTML 产出质量 ===
const html = fs.readFileSync('reports/<品类>-voc-insight-report.html', 'utf8');
console.log('\n▶ HTML 产出:');
console.log(' 大小:', (html.length / 1024).toFixed(1), 'KB');
console.log(' sections:', (html.match(/<section class="report-section"/g) || []).length);
console.log(' Coming Soon:', (html.match(/Coming in Batch/g) || []).length);
// === 6. 证据卡数量 ===
const vocCardCount = (html.match(/border-left:3px solid/g) || []).length;
console.log(' VOC 证据卡:', vocCardCount, vocCardCount < 100 ? '⚠️ 过少' : '✓');
// === 7. 决策列表数量 ===
const decisionCount = (html.match(/落地决策/g) || []).length;
console.log(' 决策列表:', decisionCount, decisionCount < 20 ? '⚠️ 过少' : '✓');
// === 8. 空段检查(有 section 但无内容)===
const emptySection = (html.match(/<section[^>]*>\s*<div class="section-inner">\s*<\/div>\s*<\/section>/g) || []).length;
console.log(' 空 section:', emptySection);
// === 9. 封面数字与 _merged.json 一致 ===
const coverItemMatch = html.match(/(\d{3,5})\s*条/);
const metaCount = items.length;
if (coverItemMatch && parseInt(coverItemMatch[1]) !== metaCount) {
console.log(` ⚠️ 封面 ${coverItemMatch[1]} 条 != merged ${metaCount} 条`);
}
console.log('\n===== ✅ 审计完成 =====');
| 指标 | 绿灯 ✅ | 黄灯 ⚠️ | 红灯 ❌ |
|---|---|---|---|
| 总 VOC 条数 | ≥ 目标盘 | 达目标 80% | < 目标 80% |
| H1-H8 每条覆盖 | ≥ 100 | 50-99 | < 50 |
| 重复组数 | < 5 组 | 5-20 组 | > 20 组 |
| 高赞跳题 | < 20 条 | 20-50 条 | > 50 条 |
| HTML 大小 | 400-750 KB | 300-400 或 750-1000 | < 300 或 > 1000 |
| Coming Soon | 0 | 1-2 | ≥ 3 |
| VOC 证据卡 | ≥ 100 | 60-100 | < 60 |
| 决策列表 | ≥ 28(每章≥3.5) | 20-27 | < 20 |
红灯必须处理再交付。黄灯可接受但要在执行摘要里标注已知短板。
docs/<品类>/4.采集执行摘要.md 必有 7 节:
> **状态**:✅ 真实采集完成 · **<N> 条真实 VOC** · **<M> 产品** · **<K> 平台** · **H1-H8 全覆盖**
| 批次 | 主题 | XHS kw | 抖音 kw | 耗时 |
| --- | --- | --- | --- | --- |
| Batch 1 | P0 · 本品 + 头部竞品 | 11 | 5 | 20 分钟 |
| ... | | | | |
| 假设 | 主题 | 条数 | 备注 |
|---|---|---|---|
| H1 | ... | 1125 | ✓ 强覆盖 |
| H6 | ... | 126 | △ 较少(建议后续补采)|
| 章节 | 子章数 | 状态 | 核心 VOC 证据 |
|---|---|---|---|
| Ch1 诘问起点 | 3 | ✅ | 对比 ♥62890 vs ♥40 |
| Ch2 ... | 4 | ✅ | ... |
列出每章最有代表性的 VOC(带 ♥+昵称+片段),便于产品方快速理解证据密度。
- [x] Batch 1-3 全量采集完整
- [x] H1-H8 全部 > 100 条覆盖
- [x] 0 Coming Soon 占位
- [x] 0 重复 VOC 引用
- [△] H6 包装 VOC 较少(126 条)—— 建议后续从京东/天猫差评补采
### 增量刷新
node scripts/tools/<品类>-collect.js --batch=1 --force
node scripts/tools/<品类>-collect.js --merge
node scripts/tools/gen-<品类>.js
### 质量审计
node scripts/tools/_audit-<品类>-voc.js
### 浏览器预览
node scripts/tools/preview-reports.js # localhost:8787
详见 templates/4.采集执行摘要.template.md。
node scripts/tools/preview-reports.js
# 打开 http://localhost:8787
# 点击 <品类>-voc-insight-report.html
打开 HTML 后人工复审:
## 交付物
### 📊 HTML 报告
- `reports/<品类>-voc-insight-report.html`(<大小> KB)
- 打开方式:浏览器直接拖入 / 双击
### 📝 文档(4-5 份 markdown)
- `docs/<品类>/0.基础调研.md`
- `docs/<品类>/1.场景的补充.md`
- `docs/<品类>/2.VOC深度思路.md`
- `docs/<品类>/3.采集矩阵.md`
- `docs/<品类>/4.采集执行摘要.md`
### 💾 原始数据(可追溯)
- `docs/<品类>/raw/xhs/*.json`(<N> 个文件)
- `docs/<品类>/raw/douyin/*.json`
- `docs/<品类>/raw/_merged.json`(合并统一格式)
- `docs/<品类>/raw/comments-flat.jsonl`(行级流)
- `docs/<品类>/raw/audit.log`
### 🔧 代码(供后续维护)
- `scripts/tools/<品类>-*.js`(采集 + 分析 + 组件 + 章节 + 渲染 + 审计)
| 产品方可能问 | 标准回答 |
|---|---|
| "VOC 数据真实吗?" | 100% 真实 · 所有 API 调用记录在 audit.log · 每条 item 可在 _merged.json 回溯 platform+user_id+note_id |
| "为什么某条高赞 VOC 没用上?" | getEvidence 每章用不同 seed 乱序 · 避免同一条被 3 章引用 · 可指定章节放进去 |
| "能不能换个角度写 Ch4?" | 重写 <品类>-ch4-kano.js · 1-2 小时可产出新版 · 其他章不受影响(模块化) |
| "我要把某品牌改为竞品 A" | 编辑 3.采集矩阵.md 加 kw · 跑 --batch=4 --force · 重新 gen |
# 每月跑一次,刷最新 VOC
node scripts/tools/<品类>-collect.js --batch=all --force --merge
node scripts/tools/gen-<品类>.js
# 比较新旧报告,看热点漂移
raw/ 文件夹Phase 6 完成的 7 个条件:
_audit-<品类>-voc.js 跑通,红灯 = 04.采集执行摘要.md 7 节齐全STATUS.md 打完结标签