// 审计 Ch1-Ch3 实际展示的 VOC 证据质量: // 对每一条 getEvidence(...) 调用复现其结果, // 打印 "slide · 角色 · 平台 · 昵称 · 点赞 · 内容" → 让人眼见即可评估是否对路。 const LA = require('./liver-analyze.js'); const data = LA.loadMerged(); const items = data.items; function printList(title, arr) { console.log('\n──────────────────────────────────────'); console.log(title); console.log('──────────────────────────────────────'); if (!arr || !arr.length) { console.log(' (空)'); return; } arr.forEach((it, i) => { const rating = typeof it.rating === 'number' ? ` ★${it.rating}` : ''; const title = it.title ? ` | "${it.title.slice(0, 40)}"` : ''; console.log( ` [${i + 1}] ${it.platform.toUpperCase()} · ${it.keyword} · ${it.nickname}${rating} · ♥${it.likes}${title}` ); console.log(` 「${(it.content || '').replace(/\n/g, ' ').slice(0, 180)}」`); }); } console.log('╔════════════════════════════════════════════════════════╗'); console.log('║ 江中肝纯片 VOC 报告 · Ch1-Ch3 evidence 审计 ║'); console.log('╚════════════════════════════════════════════════════════╝'); // ===== 1.1 DMY 认知空白 ===== printList('【1.1】XHS "肝纯片" + 水飞蓟提及(mind1)', LA.getEvidence(items, { keyword: '肝纯片', contentMatch: /水飞蓟|silymarin/i, top: 3, seed: 5 })); printList('【1.1】XHS "江中肝纯片" + 总黄酮提及(mind2)', LA.getEvidence(items, { keyword: '江中肝纯片', contentMatch: /总黄酮|成分|黄酮|护肝片/i, top: 2, seed: 7 })); printList('【1.1】XHS "藤茶" top 3(按 likes)', items.filter(it => it.keyword === '藤茶').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【1.1】Amazon dihydromyricetin ★≥4 top 3', items.filter(it => it.keyword === 'dihydromyricetin' && it.rating >= 4) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); // ===== 1.2 海王金樽警示 ===== printList('【1.2】"海王金樽" + 广告/老哒/硬广/[捂脸]', items.filter(it => it.keyword === '海王金樽' && /广告|老哒|硬广|洗脑|杠杠的|捂脸|福/i.test(it.content || '')) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 4)); printList('【1.2】"海王金樽" 正向寡淡(likes<10)', items.filter(it => it.keyword === '海王金樽' && /神|可以|性价比|get/i.test(it.content || '') && (it.likes || 0) < 10) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【1.2】"解酒神器" 品类整体情绪', items.filter(it => it.keyword === '解酒神器' && /横竖|死呗|对手|笑哭|酒蒙子|催吐|商家/i.test(it.content || '')) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); // ===== 2.1 藤茶千年食饮 ===== printList('【2.1】XHS "藤茶" top 4(取前 4 作文化叙事)', items.filter(it => it.keyword === '藤茶').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 4)); // ===== 2.2 DMY 科学力 ===== printList('【2.2】Amazon dihydromyricetin ★≥4 top 4', items.filter(it => it.keyword === 'dihydromyricetin' && it.rating >= 4) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 4)); // ===== 2.3 水飞蓟反面 ===== printList('【2.3】XHS "水飞蓟" + 怀疑/副作用关键词', items.filter(it => it.keyword === '水飞蓟' && /效果寥寥|没效|不行|差远|双环醇|尿.*变|变橙|胃疼|不知道|是不是|进口|医生/i.test(it.content || '')) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【2.3】XHS "奶蓟草" + 花/野花/苏格兰', items.filter(it => it.keyword === '奶蓟草' && /花|蓟|野花|苏格兰|止血/i.test(it.content || '')) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【2.3】Amazon milk thistle ★≤2 top 3', items.filter(it => it.keyword === 'milk thistle' && it.rating <= 2) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【2.3】Amazon silymarin ★≤2 top 2', items.filter(it => it.keyword === 'silymarin' && it.rating <= 2) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); // ===== 3.2 五大竞品 ===== printList('【3.2】Swisse top 2', items.filter(it => it.keyword === 'swisse护肝片').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【3.2】易善复 top 2', items.filter(it => it.keyword === '易善复').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【3.2】葵花护肝片 top 2', items.filter(it => it.keyword === '葵花护肝片').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【3.2】片仔癀护肝 top 2', items.filter(it => it.keyword === '片仔癀护肝').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【3.2】海王金樽 top 2', items.filter(it => it.keyword === '海王金樽').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 2)); printList('【3.2】汤臣倍健护肝 top 1', items.filter(it => it.keyword === '汤臣倍健护肝').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 1)); // ===== 3.3 三大人群 ===== printList('【3.3A】脂肪肝 top 3', items.filter(it => it.keyword === '脂肪肝').sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【3.3B】熬夜伤肝/熬夜护肝 top 3', items.filter(it => it.keyword === '熬夜伤肝' || it.keyword === '熬夜护肝') .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); printList('【3.3C】应酬解酒/解酒神器/酒局必备 top 3', items.filter(it => /应酬|解酒|酒局/.test(it.keyword || '')) .sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, 3)); console.log('\n\n========== 数据质量自检 =========='); // 检查重复问题 const dupMap = new Map(); for (const it of items) { const key = `${it.platform}|${it.content?.slice(0, 50)}`; dupMap.set(key, (dupMap.get(key) || 0) + 1); } const dups = [...dupMap.entries()].filter(([k, v]) => v > 1).sort((a, b) => b[1] - a[1]); console.log(`重复评论(前 50 字相同): ${dups.length} 组`); console.log('Top 5 重复条目:'); dups.slice(0, 5).forEach(([k, v]) => console.log(` ×${v} ${k.slice(0, 120)}`)); // 空内容 const empty = items.filter(it => !(it.content || '').trim()); console.log(`\n空内容: ${empty.length}`); // 平台统计 const byPlatform = {}; for (const it of items) byPlatform[it.platform] = (byPlatform[it.platform] || 0) + 1; console.log('\n平台分布:', byPlatform); // 评论内容和 keyword 的 "相关性" 启发式 function topicHit(it) { const c = it.content || ''; const kw = it.keyword || ''; // 如果评论字数 < 4 或 只有表情符号 视为无内容 if (c.replace(/\s/g, '').length < 4) return 'too-short'; // 如果评论里出现了 kw 的任何片段 视为相关 if (kw && kw.length >= 2) { const parts = kw.split(/护肝|片|解酒/).filter(Boolean); for (const p of parts) { if (p.length >= 2 && c.includes(p)) return 'kw-hit'; } if (c.includes(kw)) return 'kw-hit'; } return 'may-drift'; } const hitStats = { 'kw-hit': 0, 'too-short': 0, 'may-drift': 0 }; for (const it of items) hitStats[topicHit(it)]++; console.log('\n相关性启发式:', hitStats); console.log(` kw-hit = 评论文本直接提到 keyword 片段`); console.log(` too-short = 评论长度 < 4 字符(表情/短回复)`); console.log(` may-drift = 长评论但可能跑题`);