#!/usr/bin/env node /** * 江中 VOC 报告生成主入口 * * 输入:data/jiangzhong-{product}-voc.json * 输出:reports/jiangzhong-{product}-voc-report.html * * 用法: * node scripts/tools/gen-voc-report.js # 全量 3 产品 * node scripts/tools/gen-voc-report.js liver # 指定单产品 */ const fs = require('fs'); const path = require('path'); const { analyze, extractThemes, cleanText } = require('./voc-analyze'); const { buildHTML } = require('./voc-render'); const PRODUCTS = [ { id: 'liver', file: 'jiangzhong-liver-voc.json' }, { id: 'probiotic', file: 'jiangzhong-probiotic-voc.json' }, { id: 'monkey', file: 'jiangzhong-monkey-voc.json' }, ]; const DATA_DIR = path.resolve(__dirname, '..', '..', 'data'); const REPORT_DIR = path.resolve(__dirname, '..', '..', 'reports'); if (!fs.existsSync(REPORT_DIR)) fs.mkdirSync(REPORT_DIR, { recursive: true }); function generateOne(productId) { const target = PRODUCTS.find((p) => p.id === productId); if (!target) throw new Error(`unknown product: ${productId}`); const vocPath = path.join(DATA_DIR, target.file); if (!fs.existsSync(vocPath)) { console.log(` ⚠️ ${target.id}: 数据缺失 ${vocPath}`); return; } const voc = JSON.parse(fs.readFileSync(vocPath, 'utf-8')); const A = analyze(voc); // 收集语料做主题聚类 const commentTexts = A.topComments.map((c) => cleanText(c.content || '')); const noteTexts = A.topNotes.map((n) => cleanText((n.title || '') + ' ' + (n.desc || ''))); const themes = extractThemes([...commentTexts, ...noteTexts]); const html = buildHTML({ product: voc.product, category: voc.category, collectedAt: new Date(voc.collected_at).toLocaleDateString('zh-CN'), A, themes, }); const outPath = path.join(REPORT_DIR, `jiangzhong-${target.id}-voc-report.html`); fs.writeFileSync(outPath, html, 'utf-8'); const kb = (html.length / 1024).toFixed(1); console.log(` ✅ ${voc.product}: ${outPath} (${kb}KB, ${A.metrics.notes} 笔记 / ${A.metrics.sampleComments} 评论)`); } function main() { const argId = process.argv[2]; console.log(''); console.log('╔══════════════════════════════════════════════════════════╗'); console.log('║ 江中 VOC 报告生成器 ║'); console.log('╚══════════════════════════════════════════════════════════╝'); console.log(` 输出目录: ${REPORT_DIR}`); console.log(''); if (argId) { generateOne(argId); } else { for (const p of PRODUCTS) { try { generateOne(p.id); } catch (e) { console.log(` ❌ ${p.id}: ${e.message}`); } } } console.log(''); console.log('📄 Done.'); } main();