const fs = require('fs'); const path = require('path'); const DEFAULT_VOC_ISSUES = [ { issue: '第一次了解怕踩雷', insight: '用户不是不想选,而是不知道怎么判断才稳。', title: '第一次了解我们,按这个顺序看不容易踩雷', hook: '第一次接触别急着下决定,先看这 3 点最稳。', script: '第一次了解我们,如果你怕选错、怕花冤枉钱,可以先按这个顺序判断。第一步先看核心产品或服务能不能解决你最关心的问题;第二步看真实用户的反馈和案例;第三步再对比价格和适配度。这样你不是盲选,而是在判断到底值不值。', shots: ['产品/服务全貌', '核心卖点特写', '真实案例展示', '用户使用场景'], commentPrompt: '第一次了解你最担心什么?评论区告诉我,我帮你判断。', metric: '评论里“怎么选/第一次/适不适合/怎么对比”的提问是否增加' }, { issue: '觉得价格贵', insight: '用户真正想知道的是贵在哪里、值不值、怎么选更划算。', title: '为什么我们不是最便宜的,但很多老用户还会复购', hook: '如果你只看价格,会觉得我们不便宜,但这几个地方才是成本。', script: '很多用户第一次看价格会犹豫,所以今天直接讲清楚。我们贵的地方不是噱头,而是这几项投入、这套服务的稳定性,还有长期使用的保障。第一次不建议盲选,可以先从入门方案开始,既能体验核心价值,也不会一下子超预算。', shots: ['成本构成展示', '服务/工艺过程', '前后效果对比', '不同方案价格说明'], commentPrompt: '想看入门方案怎么选,还是进阶方案怎么搭配?', metric: '评论里“贵/值不值”下降,“方案/怎么选”上升' }, { issue: '担心买了不适合自己', insight: '适配焦虑要用“适合谁、不适合谁”来降低。', title: '这个适合谁、不适合谁,我直接说清楚', hook: '先说不适合什么人,再说适合什么人。', script: '我们不想只讲好的一面,所以今天直接说清楚。我们适合这类需求、这种预算、这种使用场景的人;如果你的情况是另外几种,可能要先看看其他选择。讲清楚不适合谁,反而能减少你拿到手之后的落差。', shots: ['不同人群标签', '适配场景对比', '真实使用反馈', '正面说明'], commentPrompt: '你的需求和预算大概是什么?我帮你判断适不适合。', metric: '评论里“适不适合/像我这种/能不能用”的互动是否增加' }, { issue: '不知道核心差异是什么', insight: '卖点要从“我们很好”讲到“为什么和别人不一样”。', title: '别人也在做,我们到底不一样在哪', hook: '不是所有卖点都重要,但这一个差异值得你了解。', script: '很多同行都说自己好,但用户真正想知道的是差异在哪。我们最核心的不是参数堆叠,而是这个做法、这套体验和这类长期结果。第一次了解,你可以不用全看完,但一定要看这一点,因为它最能代表我们想做的事。', shots: ['核心差异演示', '关键细节特写', '用户真实反应', '对比说明'], commentPrompt: '你选这类产品或服务时,最看重哪个点?', metric: '收藏、转发、评论里“想了解/值得/怎么联系”的信号是否增加' }, { issue: '担心售后服务跟不上', insight: '服务焦虑要用流程透明和响应承诺来降低。', title: '买之前先知道:出问题找谁、多久响应', hook: '我们最怕的是你遇到问题不知道该找谁。', script: '售后和服务是很多人下单前最担心的,所以我们把流程提前说清楚。咨询、售后、退换、维护分别走哪个入口,多久能响应,都有明确说明。你不用猜流程,遇到问题直接按指引找对应的人,我们也会持续优化响应速度。', shots: ['服务流程图', '响应承诺说明', '售后入口', '真实处理记录'], commentPrompt: '你最在意响应速度、解决能力,还是后续保障?', metric: '评论里“没人管/服务慢”下降,“流程/保障”正向反馈增加' }, { issue: '内容看着种草,实际怕落差', insight: '内容要降低夸张表达,主动讲适合谁、不适合谁。', title: '不想只拍好看的,今天把真实情况说清楚', hook: '先说缺点,再说适合什么人。', script: '我们不想只拍滤镜很好看的内容,所以今天直接说清楚。我们适合这类需求、愿意接受这些前提的人;如果你期待的是另外几种效果,可能要提前了解清楚。讲清楚真实情况,反而能减少你接触之后的落差。', shots: ['真实场景', '无滤镜实拍', '真实使用过程', '正面说明'], commentPrompt: '你接触之前最想先知道优点还是缺点?', metric: '评论里“真实/避坑/适合谁”的互动是否增加' }, { issue: '不知道为什么值得专门选你', insight: '要把特色从“好”讲到“为什么值得选”。', title: '如果你只选一次,建议把这件事想明白', hook: '不是所有理由都重要,但这一个值得你了解一次。', script: '很多同行都说自己好,但用户真正想知道为什么值得专门选你。我们最核心的不是名头,而是这个方法、这份长期结果和这类真实场景。第一次了解,你可以不用全部记住,但一定要看这一点,因为它最能代表我们的价值。', shots: ['核心价值演示', '长期结果展示', '用户真实反馈', '场景氛围'], commentPrompt: '你会为了哪种结果专门选一家?', metric: '收藏、转发、评论里“想要/值得/怎么联系”的信号是否增加' } ]; function splitList(value) { if (!value) return []; if (Array.isArray(value)) return value.flatMap(splitList); return String(value).split(/[;;\n\r]+/).map(item => item.trim()).filter(Boolean); } function readTextIfExists(filePath) { if (!filePath) return ''; const absolute = path.resolve(filePath); if (!fs.existsSync(absolute)) return ''; return fs.readFileSync(absolute, 'utf8').replace(/^\uFEFF/, ''); } function collectIssues(input = {}) { const explicit = splitList(input.issues || input.problems || input.vocIssues || input.contentDirections || input.directions || input.evidence || input.comments); if (explicit.length) return explicit.slice(0, 12); const text = String(input.reportText || input.evidenceText || input.context || input.background || '').trim() || readTextIfExists(input.report || input.reportPath); const lines = splitList(text).filter(line => /价格|贵|踩雷|服务|售后|怎么选|适合|不适合|落差|案例|对比|值不值|效果|质量|体验|方案|差异|卖点|为什么|预算/.test(line)); return lines.length ? lines.slice(0, 12) : DEFAULT_VOC_ISSUES.map(item => item.issue); } function inferTemplate(issue, index, input = {}) { const text = String(issue || ''); const matched = DEFAULT_VOC_ISSUES.find(item => text.includes(item.issue) || item.issue.includes(text) || (/踩雷|第一次|怎么选|不会选/.test(text) && item.issue.includes('踩雷')) || (/贵|价格|性价比|值不值|预算/.test(text) && item.issue.includes('价格')) || (/适合|不适合|适配/.test(text) && item.issue.includes('适合')) || (/差异|卖点|特色|不一样|区别/.test(text) && item.issue.includes('差异')) || (/服务|售后|没人管|响应|态度/.test(text) && item.issue.includes('服务')) || (/落差|种草|滤镜|网红/.test(text) && item.issue.includes('落差')) || (/为什么|值得|理由/.test(text) && item.issue.includes('值得')) ); return matched || DEFAULT_VOC_ISSUES[index % DEFAULT_VOC_ISSUES.length]; } function buildContentPlan(input = {}) { const brand = String(input.project || input.brand || input.store || '你的品牌').trim(); const industry = String(input.industry || input.category || '通用行业').trim(); const platform = String(input.platform || '抖音/小红书').trim(); const days = Math.max(1, Math.min(Number(input.days || 7), 15)); const issues = collectIssues(input); const plan = Array.from({ length: days }, (_, index) => { const sourceIssue = issues[index % issues.length]; const template = inferTemplate(sourceIssue, index, input); return { day: index + 1, userIssue: sourceIssue || template.issue, insight: template.insight, title: template.title, hook: template.hook, script: template.script, shots: template.shots, commentPrompt: template.commentPrompt, validationMetric: template.metric, platform }; }); const assistantMessage = [ '# 7 天 VOC 内容选题与口播脚本', '', '## 你这轮能拿到什么', `- 一份面向 ${brand} 的 7 天内容选题表。`, '- 每条内容都绑定一个真实用户问题,不做空泛爆款标题。', '- 每条都包含前 3 秒钩子、口播脚本、镜头建议、评论区引导和验证指标。', '', '## 业务口径', `- 品牌:${brand}`, `- 行业/品类:${industry}`, `- 发布平台:${platform}`, `- 内容周期:${days} 天`, '', '## 7 天内容表', ...plan.map(item => [ '', `### Day ${item.day}:${item.title}`, `- 回应的用户问题:${item.userIssue}`, `- 洞察判断:${item.insight}`, `- 前 3 秒钩子:${item.hook}`, `- 口播脚本:${item.script}`, `- 镜头建议:${item.shots.join(' -> ')}`, `- 评论区引导:${item.commentPrompt}`, `- 验证指标:${item.validationMetric}` ].join('\n')), '', '## 拍摄提醒', '- 先拍真实场景、真实产品、真实服务流程,不要只拍滤镜氛围。', '- 每条内容只解决一个用户问题,避免一条视频讲太多。', '- 发完后把评论里的新问题继续放回 VOC 问题池,下一轮再优化。', '', '## 下一步建议', '1. 先选 2 条最容易拍的内容今天开拍。', '2. 发布 7 天后,把评论反馈告诉我,我会判断哪些选题有效、哪些要降权。', '3. 如果已经有趋势报告或问题池,可以把 Top 3 问题传进来,我会重排内容顺序。' ].join('\n'); return { status: 'ok', assistantMessage, summary: { brand, industry, platform, days, topicCount: plan.length, sourceIssueCount: issues.length }, data: { brand, industry, platform, issues, plan }, files: [], nextActions: [ '选择 2 条最容易拍的内容先执行', '发布后把评论反馈放回 VOC 问题池', '7 天后反馈有效/无效,我会更新内容方向' ], warnings: [], errors: [] }; } module.exports = { buildContentPlan };