_audit-lactic-voc.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/env node
  2. // ==============================================================================
  3. // 乳酸菌素片儿童版 VOC 质量审计脚本
  4. // ==============================================================================
  5. // 检查:重复 / 跳题 / 内容过短 / 纯表情 / 与章节主题不相关等问题
  6. // ==============================================================================
  7. const LA = require('./lactic-analyze.js');
  8. const data = LA.loadMerged();
  9. const items = data.items;
  10. function dump(title, arr, maxShow = 5) {
  11. console.log('\n' + '─'.repeat(60));
  12. console.log(`【${title}】`);
  13. console.log('─'.repeat(60));
  14. arr.slice(0, maxShow).forEach((it, i) => {
  15. console.log(` [${i + 1}] ${it.platform.toUpperCase()} · ${it.keyword} · ${it.nickname} · ♥${it.likes}`);
  16. console.log(` 「${(it.content || '').slice(0, 160)}」`);
  17. });
  18. }
  19. console.log('=========================================');
  20. console.log('江中乳酸菌素片儿童版 · VOC 质量审计');
  21. console.log(`总条数:${items.length} / 平台:${Object.keys(data.meta?.platforms || {}).join('+')}`);
  22. console.log('=========================================');
  23. // === 1. 检查 Ch1.1 引用的爆款 VOC 是否相关 ===
  24. console.log('\n▶ Ch1.1 · 成人版爆款 VOC(应该都提到乳酸菌素片/肠胃)');
  25. const adultHit = LA.getEvidence(items, {
  26. keyword: '乳酸菌素片',
  27. contentMatch: /肠鸣|胃胀|神药|便秘|好了|有用|治好|咕噜/,
  28. minChars: 20, top: 4, seed: 7,
  29. });
  30. dump('Ch1.1 成人版爆款', adultHit);
  31. // === 2. 检查 Ch2.1 妈咪爱 VOC ===
  32. console.log('\n▶ Ch2.1 · 妈咪爱家长场景(应该是宝宝/孩子相关)');
  33. const maomi = LA.getEvidence(items, {
  34. keyword: '妈咪爱',
  35. contentMatch: /宝宝|孩子|月|胀气|胀肚|便秘|腹泻|医生|儿科|医院/,
  36. minChars: 30, top: 4, seed: 7,
  37. });
  38. dump('Ch2.1 妈咪爱场景', maomi);
  39. // === 3. 检查 Ch2.2 亿活/金双岐 ===
  40. console.log('\n▶ Ch2.2 · 亿活/金双岐(应该是腹泻/抗生素/菌群相关)');
  41. const yihuo = LA.getEvidence(items, {
  42. keyword: '亿活 儿童',
  43. contentMatch: /腹泻|抗生素|酵母菌|布拉氏|发烧|宝宝|孩子|儿童|药店/,
  44. minChars: 30, top: 3, seed: 5,
  45. });
  46. dump('Ch2.2 亿活', yihuo);
  47. const jinshuangqi = LA.getEvidence(items, {
  48. keyword: '金双岐',
  49. contentMatch: /拉肚|便秘|菌群|三联|嚼|腹泻|宝宝|孩子/,
  50. minChars: 25, top: 3, seed: 9,
  51. });
  52. dump('Ch2.2 金双岐', jinshuangqi);
  53. // === 4. 检查 Ch3.1 合生元 ===
  54. console.log('\n▶ Ch3.1 · 合生元(应该是儿童/宝宝场景)');
  55. const hsy = LA.getEvidence(items, {
  56. keyword: '合生元益生菌',
  57. contentMatch: /宝宝|孩子|奶味|便秘|拉肚|幼儿园|月龄|岁/,
  58. minChars: 30, top: 4, seed: 7,
  59. });
  60. dump('Ch3.1 合生元', hsy);
  61. // === 5. 检查 Ch3.2 万益蓝(不应该出现成人减肥)===
  62. console.log('\n▶ Ch3.2 · 万益蓝(此产品主打成人减肥,儿童 VOC 稀薄 - 是我们要揭示的定位错位)');
  63. const wyl = LA.getEvidence(items, { keyword: '万益蓝益生菌', minChars: 30, top: 3, seed: 13 });
  64. dump('Ch3.2 万益蓝 top', wyl);
  65. // === 6. 检查 Ch3.2 拜奥 ===
  66. console.log('\n▶ Ch3.2 · 拜奥(应该是宝宝/胀气/滴剂相关)');
  67. const baiao = LA.getEvidence(items, {
  68. keyword: '拜奥益生菌',
  69. contentMatch: /宝宝|孩子|月|胀气|绿便|滴/,
  70. minChars: 20, top: 3, seed: 7,
  71. });
  72. dump('Ch3.2 拜奥', baiao);
  73. // === 7. 场景 Ch5 检查 ===
  74. console.log('\n▶ Ch5.1 · 入园生病');
  75. const entry = LA.getEvidence(items, {
  76. contentMatch: /入园|幼儿园|开学|交叉感染|集体|开园|托班|小班/,
  77. minChars: 20, top: 4, seed: 5,
  78. });
  79. dump('Ch5.1 入园', entry);
  80. console.log('\n▶ Ch5.2 · 抗生素后');
  81. const abx = LA.getEvidence(items, {
  82. contentMatch: /抗生素|消炎药|头孢|阿莫西林|输液|杀菌|菌群|肠道菌群/,
  83. minChars: 30, top: 4, seed: 7,
  84. });
  85. dump('Ch5.2 抗生素后', abx);
  86. console.log('\n▶ Ch5.3 · 挑食积食');
  87. const picky = LA.getEvidence(items, {
  88. contentMatch: /挑食|饭渣|不爱吃饭|厌食|专注度|饮食|食欲|脾胃|不吃菜/,
  89. minChars: 30, top: 4, seed: 7,
  90. });
  91. dump('Ch5.3 挑食', picky);
  92. console.log('\n▶ Ch5.4 · 换季腹泻');
  93. const season = LA.getEvidence(items, {
  94. contentMatch: /换季|春秋|天气转凉|季节|秋冬|春夏|拉稀|腹泻反复|反复拉/,
  95. minChars: 25, top: 4, seed: 7,
  96. });
  97. dump('Ch5.4 换季', season);
  98. // === 8. 重复检查 ===
  99. console.log('\n▶ 全量重复检查(前 40 字相同视为重复)');
  100. const bucket = new Map();
  101. for (const it of items) {
  102. const key = (it.content || '').slice(0, 40);
  103. if (!bucket.has(key)) bucket.set(key, []);
  104. bucket.get(key).push(it);
  105. }
  106. const dupGroups = [...bucket.values()].filter((g) => g.length > 1).sort((a, b) => b.length - a.length);
  107. console.log(`共 ${dupGroups.length} 组重复`);
  108. dupGroups.slice(0, 5).forEach((g, i) => {
  109. console.log(` [重复组 ${i + 1}] ${g.length} 条`);
  110. console.log(` 「${g[0].content.slice(0, 80)}」`);
  111. console.log(` 出现在关键词: ${[...new Set(g.map((x) => x.keyword))].slice(0, 5).join(', ')}`);
  112. });
  113. // === 9. 潜在跳题 VOC(短/纯表情/无关内容)===
  114. console.log('\n▶ 潜在跳题 VOC(纯表情 / 过短 / 无肠道/益生菌/儿童相关词)');
  115. const offtopic = items.filter((it) => {
  116. const c = it.content || '';
  117. if (c.length < 15) return true;
  118. const stripped = c.replace(/\[[^\]]+\]/g, '').replace(/[\s\p{P}\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu, '');
  119. if (stripped.length < 8) return true;
  120. const hasRelevant = /肠|胃|便|益生菌|宝宝|孩子|儿童|娃|月|岁|奶|辅食|菌|消化|乳酸/.test(c);
  121. return !hasRelevant && (it.likes || 0) >= 100;
  122. });
  123. console.log(`共 ${offtopic.length} 条潜在跳题(高赞 >100)`);
  124. offtopic.slice(0, 10).sort((a, b) => b.likes - a.likes).forEach((it, i) => {
  125. console.log(` [${i + 1}] ♥${it.likes} · ${it.keyword} · ${it.nickname}: ${(it.content || '').slice(0, 120)}`);
  126. });
  127. console.log('\n=========================================');
  128. console.log('✅ 审计完成');
  129. console.log('=========================================');