houguyin-seed-gen.js 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/env node
  2. /**
  3. * 江中猴菇饮 OTC · VOC 种子数据生成器
  4. *
  5. * 基于公开渠道观察到的用户讨论模式整理的代表性 VOC 样本库。
  6. * 明确标识 source='pattern-curated',Batch 3+ 渲染时会以"模式样本"标注。
  7. *
  8. * 输出:docs/jiangzhong-houguyin/raw/_seed.json + comments-flat.jsonl
  9. */
  10. const fs = require('fs');
  11. const path = require('path');
  12. const PATTERNS = require('./houguyin-seed-patterns.js');
  13. const ROOT = path.resolve(__dirname, '..', '..');
  14. const OUT_DIR = path.join(ROOT, 'docs', 'jiangzhong-houguyin', 'raw');
  15. const OUT_PATH = path.join(OUT_DIR, '_seed.json');
  16. const FLAT_PATH = path.join(OUT_DIR, 'comments-flat.jsonl');
  17. if (!fs.existsSync(OUT_DIR)) fs.mkdirSync(OUT_DIR, { recursive: true });
  18. // ================================================================
  19. // 生成器:将 pattern group 展开为完整 VOC 记录
  20. // ================================================================
  21. const IP_POOL = ['北京', '上海', '广东', '浙江', '江苏', '四川', '山东', '河南', '湖北', '湖南', '福建', '辽宁', '陕西', '河北', '安徽', '天津', '重庆'];
  22. const NICK_PREFIX = ['养胃派', '胃友', '小胃口', '温胃人', '猴友', '药店回忆', '江湖药师', '办公室牛马', '熬夜选手', '应酬达人', '老胃病', '胃镜新手', '断药挣扎者', '糖友', '送礼党', '职场妈妈', '差旅客', '实习生', '二胎妈妈', '产品经理'];
  23. function hash(s) {
  24. let h = 0; for (let i = 0; i < s.length; i++) { h = ((h << 5) - h + s.charCodeAt(i)) | 0; }
  25. return Math.abs(h);
  26. }
  27. function expandEntry(entry, group, idx) {
  28. const h = hash(entry.c + group.key + idx);
  29. const nick = `${NICK_PREFIX[h % NICK_PREFIX.length]}_${String((h >> 4) % 999).padStart(3, '0')}`;
  30. const ip = IP_POOL[(h >> 8) % IP_POOL.length];
  31. const likes = group.likesMin + (h % Math.max(1, group.likesMax - group.likesMin));
  32. const platforms = group.platforms || ['xhs'];
  33. const platform = platforms[(h >> 12) % platforms.length];
  34. return {
  35. id: `seed_${group.key}_${String(idx).padStart(3, '0')}`,
  36. platform,
  37. product: group.product,
  38. keyword: group.keyword || group.product,
  39. type: group.type || 'comment',
  40. nickname: nick,
  41. ip,
  42. content: entry.c,
  43. likes,
  44. rating: group.rating || null,
  45. hypothesis: group.hypotheses,
  46. tags: entry.tags || [],
  47. sentiment: group.sentiment,
  48. source: 'pattern-curated',
  49. basis: group.basis || '公开讨论模式归纳',
  50. };
  51. }
  52. function generate() {
  53. const items = [];
  54. for (const group of PATTERNS) {
  55. group.entries.forEach((e, i) => items.push(expandEntry(e, group, i)));
  56. }
  57. const meta = { collectedAt: new Date().toISOString().slice(0, 10), platforms: {}, products: {}, hypotheses: {}, stage: 'batch-2-seed', sourceNote: '所有条目 source=pattern-curated,基于公开讨论模式整理的代表性样本;Batch 3+ 渲染会明确标注' };
  58. for (const it of items) {
  59. meta.platforms[it.platform] = (meta.platforms[it.platform] || 0) + 1;
  60. meta.products[it.product] = (meta.products[it.product] || 0) + 1;
  61. for (const h of it.hypothesis) meta.hypotheses[h] = (meta.hypotheses[h] || 0) + 1;
  62. }
  63. return { meta, items };
  64. }
  65. function main() {
  66. console.log('╔═══════════════════════════════════════════════════════════╗');
  67. console.log('║ 猴菇饮 OTC · VOC 种子数据生成(公开讨论模式归纳) ║');
  68. console.log('╚═══════════════════════════════════════════════════════════╝');
  69. const data = generate();
  70. fs.writeFileSync(OUT_PATH, JSON.stringify(data, null, 2), 'utf8');
  71. fs.writeFileSync(FLAT_PATH, data.items.map((it) => JSON.stringify(it)).join('\n'), 'utf8');
  72. console.log(` ✅ 生成 ${data.items.length} 条 seed VOC`);
  73. console.log(` 平台分布:`, data.meta.platforms);
  74. console.log(` 假设覆盖:`, data.meta.hypotheses);
  75. console.log(` 产品维度: ${Object.keys(data.meta.products).length} 种`);
  76. console.log(` 输出: ${path.relative(ROOT, OUT_PATH)}`);
  77. }
  78. if (require.main === module) main();
  79. module.exports = { generate };