// VOC 报告 HTML 渲染器 · v2
const { esc, fmtNum, fmtMoney, cleanText } = require('./voc-analyze');
const STYLES = require('./voc-styles');
const SCRIPTS = require('./voc-scripts');
function renderNav(product, hasDouyin, hasTikTok) {
const sections = [
{ id: 's0', tip: '封面' }, { id: 's1', tip: '执行摘要' },
{ id: 's2', tip: '核心洞察' }, { id: 's3', tip: '爆款笔记' },
{ id: 's4', tip: '用户原声' }, { id: 's5', tip: 'KOL 分析' },
{ id: 's6', tip: 'Amazon 对标' },
...(hasTikTok ? [{ id: 'sttk', tip: 'TikTok 海外' }] : []),
...(hasDouyin ? [{ id: 'sdy', tip: '抖音阵地' }] : []),
{ id: 's7', tip: '痛点亮点' },
{ id: 's8', tip: '机会矩阵' }, { id: 's9', tip: '行动建议' },
];
return `
BRAIN· HACK / VOC
${esc(product)} — 洞察报告 v2.0
${sections.map((s, i) => ` `).join('\n ')}
`;
}
function renderS0Cover({ product, category, collectedAt, A, slideNum, slideTotal }) {
return `
VOC / 2026 / 中国市场 · Amazon 对标
${esc(category)}
${esc(product)}
用户洞察 · VOC 报告
基于小红书 ${A.metrics.notes} 篇相关笔记 ·
${A.metrics.sampleComments} 条真实评论 ·
${A.kols.length} 位作者画像 ·
${A.amazonProducts.length > 0 ? `叠加 Amazon ${A.amazonProducts.length} 款国际对标产品` : '国际品类对标中'},
解构用户真实需求、场景与未被满足的机会。
${fmtNum(A.metrics.totalLikes)}
累计点赞
${fmtNum(A.metrics.totalComments)}
累计评论
${fmtNum(A.metrics.totalCollected)}
累计收藏
${fmtNum(A.metrics.totalShared)}
累计分享
SCROLL DOWN · 采集时间 ${collectedAt}
`;
}
function renderS1Summary({ A, slideNum, slideTotal }) {
const engRate = A.metrics.totalLikes > 0 ? ((A.metrics.totalComments / A.metrics.totalLikes) * 100).toFixed(1) : '—';
return `
01 · Executive Summary
执行摘要
核心数据一览,洞察始于规模。
笔记样本
${A.metrics.notes}
关键词覆盖 ${Object.keys(A.meta.xiaohongshu?.by_keyword || {}).length} 个维度
评论原声
${A.metrics.sampleComments}
来自 Top 笔记深度抓取
作者画像
${A.kols.length}
头部 ${A.kolTier.head.length} · 腰部 ${A.kolTier.mid.length} · KOC ${A.kolTier.tail.length}
评论/点赞比
${engRate} %
用户参与深度指标
GEO DISTRIBUTION
用户地域 TOP 10
`;
}
function renderS2Insights({ A, themes, slideNum, slideTotal }) {
const topPain = themes.pain[0] || { tag: '—', count: 0 };
const topBright = themes.bright[0] || { tag: '—', count: 0 };
const topScenario = themes.scenarios[0] || { tag: '—', count: 0 };
const hotNote = A.topNotes[0] || {};
const topComment = A.topComments[0] || {};
return `
02 · Core Insights
三条核心洞察
从数据里提炼出的不言而喻的真相。
用户对此品类的第一反应是 ${esc(topPain.tag)} 而非功效或品牌。
在 ${A.metrics.sampleComments} 条评论中,"${esc(topPain.tag)}"被反复提及 ${topPain.count} 次,超过任何品牌词。这是品类级的心智障碍,比产品本身更值得投资解决。
${topPain.count} 提及次数
${topBright.count} 正向对照
${((topPain.count / Math.max(1, A.metrics.sampleComments)) * 100).toFixed(1)}% 覆盖率
最高赞笔记 ${fmtNum(hotNote.liked_count || 0)} 赞, 主题围绕 ${esc(topScenario.tag)} 。
"${esc(cleanText(hotNote.title || '').slice(0, 40))} " — 证明 ${esc(topScenario.tag)} 是此品类最强的种草切入点。内容方向 / 产品卖点 / 投流素材都应围绕这一场景聚焦。
${fmtNum(hotNote.liked_count || 0)} 最高赞
${fmtNum(hotNote.comments_count || 0)} 评论
${fmtNum(hotNote.collected_count || 0)} 收藏
一条 ${fmtNum(topComment.like_count || 0)} 赞的评论, 说明 ${esc(topBright.tag)} 是消费者自发认同的卖点。
"${esc(cleanText(topComment.content || '').slice(0, 70))} " — 这条评论的点赞数体现消费者的共识形成 。这个表达本身就是可直接挪用的最佳营销文案。
${fmtNum(topComment.like_count || 0)} 评论获赞
${topBright.count} 亮点提及
${topScenario.count} 场景覆盖
`;
}
function renderS3Notes({ A, slideNum, slideTotal }) {
const top12 = A.topNotes.slice(0, 12);
return `
03 · Top Notes
爆款笔记 · 种草全景
按点赞数排序的 Top 12 笔记 · 标题 / 互动结构 / 发布人画像
${top12.map((n, i) => `
#${String(i + 1).padStart(2, '0')}
${esc(cleanText(n.title || ''))}
${n.type === 'video' ? '视频' : '图文'}
${n.user?.red_official_verified ? '官方认证 ' : ''}
${fmtNum(n.liked_count)} LIKES
${fmtNum(n.comments_count)} COMMENTS
${fmtNum(n.collected_count)} SAVES
@${esc(n.user?.nickname || '未知作者')}
`).join('\n ')}
NOTE HEATMAP
笔记互动热力图
X 轴=点赞 · Y 轴=评论 · 气泡大小=收藏 · 找出低评论高收藏的"干货潜力"笔记
`;
}
function renderS4Voices({ A, slideNum, slideTotal }) {
const voices = A.topComments.slice(0, 15);
return `
04 · Voice Wall
用户真实原声
高赞评论 Top 15 · 未经任何编辑的 VOC 原始语料
${voices.map((c, i) => `
${esc(cleanText(c.content))}
${esc((c.user_info?.nickname || '匿名').slice(0, 14))}${c.ip_location ? ' · ' + esc(c.ip_location) : ''}
♥ ${fmtNum(c.like_count || 0)}
`).join('\n ')}
`;
}
function renderS5KOL({ A, slideNum, slideTotal }) {
const T = A.kolTier;
const totalQualified = A.kols.length;
const filtered = A.metrics.kolsFiltered || 0;
const hasAnyKol = totalQualified > 0;
const hasTopTier = T.head.length + T.mid.length > 0;
return `
05 · KOL Landscape
作者生态分层
仅展示 ≥ 1000 粉且真实活跃的作者 · 已过滤 ${filtered} 位低粉低互动账号
头部 KOL (50w+)
${T.head.length}
品牌背书 · 单篇合作单价高
腰部达人 (5w-50w)
${T.mid.length}
性价比最高 · 批量合作
尾部 (5k-5w)
${T.tail.length}
垂类精准 · 素材铺量
KOC (1k-5k)
${T.koc.length}
真实口碑 · 低成本试水
${!hasAnyKol ? `
本次采样未发现 ≥1000 粉合格作者 , 说明此品类在小红书尚未形成规模化 KOL 生态。
有效样本仅 ${filtered} 个微型账号(粉丝多在百位数),无稳定流量池。这是品类空白信号 :
· 策略上 — 用 品牌自营矩阵 抢占心智(而非依赖达人合作) · 执行上 — 做 大号跨品类合作 (健康/养生/母婴领域头部)切入垂类
· 测试上 — 站外抖音 + 微信私域 成本可能更低效果更高
` : `
合格作者 Top ${Math.min(totalQualified, 9)} · 按粉丝排序
${A.kols.slice(0, 9).map((k) => `
${k.images ? `
` : '
'}
${esc(k.nickname || '')}${k.red_official_verified ? ' 官方 ' : ''}
${esc(cleanText(k.desc || '暂无简介').slice(0, 70))}
${fmtNum(k.fans)} 粉丝
${fmtNum(k.interaction || k.likes)} 赞藏
${k.ip_location ? `${esc(k.ip_location)} ` : ''}
`).join('\n ')}
${!hasTopTier ? `
STRATEGIC NOTE
头部/腰部缺失的含义
目前合格样本全部集中在「尾部 + KOC」区间,这说明:
1. 此品类属于 真实口碑驱动型 ,靠数十位 KOC 铺量比签一位头部更有效;
2. 建议 优先批量投放 ${T.tail.length + T.koc.length} 位尾部/KOC 作者 ,以真实体验 × 素材密度驱动种草;
3. 未来如需引爆,再考虑跨品类头部合作(如 母婴 / 健康科普 / 生活方式 赛道的 5w+ 达人)。
` : ''}
`}
`;
}
function renderS6Amazon({ A, slideNum, slideTotal }) {
const amz = A.amazon;
if (!amz || amz.empty) {
return `
06 · Amazon Benchmark
Amazon 国际对标
此品类在 Sorftime 未返回产品,需补充英文关键词或确认 domain 映射。
数据未采集或关键词无匹配产品。建议补充英文关键词后重跑采集脚本。
`;
}
const hasReviews = Object.keys(amz.reviewsSummary || {}).length > 0;
const hasDetails = (amz.detailProducts || []).length > 0;
// ═════════════════════════════════════════════
// 6.0 · 核心发现 & 机会评估(分析层 · hero)
// ═════════════════════════════════════════════
const op = amz.opportunity;
const findings = amz.keyFindings || [];
const toneColor = (t) => ({
green: 'var(--green)', amber: 'var(--amber)', rose: 'var(--rose)',
blue: 'var(--blue)', purple: 'var(--purple)',
}[t] || 'var(--amber)');
const executiveLayer = op ? `
6.0 · 核心发现 & 机会评估
基于 ${amz.total} 款产品 + ${op.dimensions.length} 维度诊断的判断层 · 每个结论都是可以直接拍板的行动锚点
CATEGORY OPPORTUNITY
${esc(op.grade.split(' · ')[0])}
${esc(op.grade.split(' · ')[1] || '')}
${op.totalScore} / ${op.maxScore}
甜点价位:${esc(op.sweetSpot)}
${op.dimensions.map((d) => `
${d.icon}
${esc(d.name)}
${esc(d.level)}
${[1,2,3,4,5].map((i) => ` `).join('')}
${d.note.replace(/\*\*(.+?)\*\*/g, '$1 ')}
`).join('')}
${findings.map((f, i) => `
FINDING ${String(i + 1).padStart(2, '0')}
${f.icon}
${esc(f.title)}
${f.body}
`).join('')}
` : '';
// 6.1 品类全景
const overview = `
6.1 · 品类全景
产品样本
${amz.total}
${amz.keywords.length} 组关键词 × 3 页
均价 / 中位
$${amz.priceStats.mean.toFixed(1)}
中位 $${amz.priceStats.median.toFixed(2)} · $${amz.priceStats.min.toFixed(1)}–$${amz.priceStats.max.toFixed(0)}
平均评分
${amz.avgRating.toFixed(2)}
用户质量期望 · 中位 ${amz.medianRating.toFixed(1)}
月销总额
${fmtMoney(amz.totalMonthlyRevenue)}
CR5 ${amz.top5Share.toFixed(1)}% · HHI ${Math.round(amz.hhi)}
`;
// 6.2 品牌格局
const top10Brands = amz.topBrands.slice(0, 10);
const brandStructure = `
6.2 · 品牌格局
TOP 10 BRANDS
Top 10 品牌表
# 品牌 SKU 份额 月销额
${top10Brands.map((b, i) => `
${String(i + 1).padStart(2, '0')}
${esc(b.brand)}
${b.count}
${b.share.toFixed(1)}%
${fmtMoney(b.sales)}
`).join('')}
⚠ 市场集中度: CR5 = ${amz.top5Share.toFixed(1)}% , HHI = ${Math.round(amz.hhi)}
${amz.top5Share >= 60 ? '(高度集中,头部垄断 )' : amz.top5Share >= 40 ? '(中度集中,需差异化切入 )' : '(竞争充分,进入门槛低 )'}
`;
// ═════════════════════════════════════
// 6.2+ · Top 5 竞品深度画像(分析层 · 紧跟 6.2 品牌格局)
// ═════════════════════════════════════
const dossiers = amz.competitorDossiers || [];
const dossiersSection = dossiers.length ? `
6.2+ · Top ${dossiers.length} 竞品深度画像
不是看品牌数据,而是看它在市场中的位置 、它外部的优势 、它给新玩家留下的缝
${dossiers.map((d, i) => `
#${String(i + 1).padStart(2, '0')}
${esc(d.brand)}
${esc(d.positioning)}
均价
$${d.avgPrice.toFixed(1)}
评分
★ ${d.avgRating.toFixed(2)}
${d.topProduct ? `
TOP PRODUCT · ${esc(d.topProduct.asin)}
${esc((d.topProduct.title || '').slice(0, 70))}
$${d.topProduct.price.toFixed(2)}
★ ${d.topProduct.rating.toFixed(1)}
${fmtNum(d.topProduct.reviewCount)} 评
${fmtNum(d.topProduct.monthlySales)}/月
` : ''}
✅ STRENGTHS
${d.strengths.length ? d.strengths.map((s) => `
${esc(s.label)} ×${s.n}
`).join('') : '
评论样本少,未提炼出明显优势
'}
⚠ WEAKNESSES
${d.weaknesses.length ? d.weaknesses.map((w) => `
${esc(w.label)} ×${w.n}
`).join('') : '
差评样本少,未捉到明显缝
'}
价格差 ${d.priceVsCategory > 0 ? '+' : ''}$${d.priceVsCategory} · 评分差 ${d.ratingVsCategory > 0 ? '+' : ''}${d.ratingVsCategory}
${d.totalReviews ? fmtNum(d.totalReviews) + ' 评论' : ''}
`).join('')}
` : '';
// 6.3 Top 产品矩阵
const topBySalesRows = amz.topBySales.slice(0, 8).map((p, i) => `
${String(i + 1).padStart(2, '0')}
${esc(p.Brand || 'N/A')}
${esc((p.Title || '').slice(0, 80))}
$${((p.SalesPrice || p.Price || 0) / 100).toFixed(2)}
${fmtNum(p.ListingSalesVolumeOfMonth || 0)}
${p.Ratings ? `★ ${p.Ratings}` : '—'}${fmtNum(p.RatingsCount || 0)} 评
${esc(p.Asin || '—')}
`).join('');
const topByReviewsRows = amz.topByReviews.slice(0, 8).map((p, i) => `
${String(i + 1).padStart(2, '0')}
${esc(p.Brand || 'N/A')}
${esc((p.Title || '').slice(0, 80))}
★ ${p.Ratings || '—'}
${fmtNum(p.RatingsCount || 0)}
$${((p.SalesPrice || p.Price || 0) / 100).toFixed(2)}
`).join('');
const topMatrix = `
6.3 · Top 产品矩阵
MONTHLY SALES LEADERS
月销量 Top 8
# 品牌 / 产品 售价 月销 评分 ASIN
${topBySalesRows}
REVIEW VOLUME LEADERS
评论数 Top 8 · 用户口碑沉淀
# 品牌 / 产品 评分 评论数 售价
${topByReviewsRows}
REVIEW COUNT DISTRIBUTION
评论数分布 · 口碑沉淀结构
`;
// 6.4 深度产品画像
const detailSection = hasDetails ? `
6.4 · 深度产品画像
对 Top ${amz.detailProducts.length} 款拉取完整 ProductRequest · 含 BSR / 上线日 / Buybox 卖家 / 变体数
${amz.detailProducts.slice(0, 6).map((p) => {
const photo = (typeof p.photo === 'string' ? p.photo : p.photo?.Url) || '';
return `
${photo ? `
` : '
'}
${esc(p.brand || 'N/A')}
${p.hasVideo ? '有视频 ' : ''}
${p.aplus ? 'A+ ' : ''}
${p.brandStore ? '品牌店 ' : ''}
${p.variantCount > 1 ? `${p.variantCount} 变体 ` : ''}
${esc((p.title || '').slice(0, 78))}
ASIN · ${esc(p.asin)}
评分
★ ${p.rating || '—'} · ${fmtNum(p.ratingsCount || 0)}
月销
${fmtNum(p.monthlySales || 0)}
BSR
${p.bsrRank ? '#' + fmtNum(p.bsrRank) : '—'}
上线天数
${p.onlineDays ? p.onlineDays + 'd' : '—'}
Buybox 卖家
${esc((p.buyboxSeller || '—').slice(0, 16))}
`;
}).join('')}
${amz.avgOnlineDays > 0 ? `
MARKET MATURITY
品类成熟度:平均上线 ${amz.avgOnlineDays} 天 (${(amz.avgOnlineDays / 365).toFixed(1)} 年)
Top ${amz.detailProducts.length} 深度样本中 · ${amz.newProducts} 款新品(<180d) · ${amz.matureProducts} 款成熟品(≥1年)
${amz.matureProducts > amz.newProducts ? '· 市场结构稳固,新玩家需强差异化' : '· 新品频出,市场动态,有迭代窗口'}
` : ''}` : '';
// 6.5 评论深度
const reviewSamples = hasReviews ? Object.values(amz.reviewsSummary) : [];
const reviewSection = hasReviews ? `
6.5 · 真实评论抽样
对 Top ${reviewSamples.length} 款抓取真实评论 · 按星级分布 + 正负面抽样
${reviewSamples.map((r) => {
const posSample = r.positiveReviews[0];
const negSample = r.negativeReviews[0];
const starStr = [5, 4, 3, 2, 1].map((s) => `${'★'.repeat(s)} ${r.starDist[s] || 0}`).join(' ');
return `
${esc(r.asin)}
${esc(r.brand || 'N/A')} · ${esc((r.title || '').slice(0, 50))}
★ ${r.averageRating.toFixed(2)}
${r.total} 条抽样
${starStr}
${posSample ? `
★ ${posSample.Star ?? posSample.Rating ?? posSample.rating} · ${esc(String(posSample.Title || posSample.title || '好评').slice(0, 40))}${posSample.ConsumerName ? ' · ' + esc(String(posSample.ConsumerName).slice(0, 16)) : ''}${posSample.IsVP ? ' ✓VP ' : ''}
${esc(cleanText(posSample.Content || posSample.content || '').slice(0, 240))}
` : '
'}
${negSample ? `
★ ${negSample.Star ?? negSample.Rating ?? negSample.rating} · ${esc(String(negSample.Title || negSample.title || '差评').slice(0, 40))}${negSample.ConsumerName ? ' · ' + esc(String(negSample.ConsumerName).slice(0, 16)) : ''}${negSample.IsVP ? ' ✓VP ' : ''}
${esc(cleanText(negSample.Content || negSample.content || '').slice(0, 240))}
` : '
'}
`;
}).join('')}
STAR DISTRIBUTION
各产品 5 星分布对比
` : '';
// ═════════════════════════════════════
// 6.5+ · VOC 用户原声(分析层 · 紧跟 6.5 评论抽样)
// ═════════════════════════════════════
const vt = amz.amazonThemes;
const renderBarRow = (items, color, totalRef) => items.map((t) => {
const pct = totalRef ? Math.min(100, (t.count / totalRef * 100)) : 0;
return `
${t.emoji || t.icon || '•'}
${esc(t.tag.split(' · ')[1] || t.tag)}
${t.count} · ${t.pct.toFixed(1)}%
${t.examples?.[0] ? `
"${esc(t.examples[0].text.slice(0, 90))}${t.examples[0].text.length > 90 ? '…' : ''}"${t.examples[0].brand ? ` · ${esc(t.examples[0].brand)} ` : ''}
` : ''}
`;
}).join('');
const vocThemesSection = vt && (vt.pain.length || vt.bright.length || vt.scenarios.length) ? `
6.5+ · VOC 用户原声主题
从 ${vt.totalReviews} 条真实评论中聚类 · ${vt.negReviews} 条差评 × ${vt.posReviews} 条好评 · 高频词聚类后得出的结构性主题
PAIN POINTS · 痛点
🔴 用户核心痛点 Top ${vt.pain.length}
${vt.pain.length ? renderBarRow(vt.pain, 'var(--rose)', vt.negReviews || 1) : '
差评样本不足以提炼共同痛点
'}
BRIGHT SPOTS · 亮点
🟢 用户最爱亮点 Top ${vt.bright.length}
${vt.bright.length ? renderBarRow(vt.bright, 'var(--green)', vt.posReviews || 1) : '
好评样本不足
'}
USAGE SCENARIOS · 场景
📍 使用场景分布
${vt.scenarios.length ? renderBarRow(vt.scenarios, 'var(--blue)', vt.totalReviews || 1) : '
评论中未明显捉到场景信号
'}
` : '';
// ═════════════════════════════════════
// 6.6 · 战略建议(分析层 · 收尾)
// ═════════════════════════════════════
const st = amz.strategy;
const renderTrack = (track, accent, eyebrow) => `
${eyebrow}
${track.badge}
${esc(track.title)}
${track.items.map((x) => `✓ ${x} `).join('')}
`;
const strategySection = st ? `
6.6 · 从数据到行动 · 三马车战略建议
基于以上所有分析维度(机会等级 ${esc(op?.grade || '—')} )导出的分阶段可执行动作
${renderTrack(st.short, 'var(--amber)', 'TRACK 1 · 0-30 DAYS')}
${renderTrack(st.mid, 'var(--green)', 'TRACK 2 · 30-90 DAYS')}
${renderTrack(st.long, 'var(--purple)', 'TRACK 3 · 90+ DAYS')}
` : '';
return `
06 · Amazon Benchmark
Amazon 国际对标
${amz.keywords.length} 组英文关键词 × 3 页 · ${amz.total} 款产品 · Top ${amz.detailProducts.length} 深度详情 · Top ${Object.keys(amz.reviewsSummary).length} 真实评论
${executiveLayer}
${overview}
${brandStructure}
${dossiersSection}
${topMatrix}
${detailSection}
${reviewSection}
${vocThemesSection}
${strategySection}
`;
}
function renderSDouyin({ A, slideNum, slideTotal }) {
const dy = A.douyin;
if (!dy || dy.empty) return '';
const v = dy.video;
const u = dy.userProfile;
const topCmts = dy.topComments || [];
const topPosts = dy.topPosts || [];
const userPosts = dy.userPosts || [];
const searches = dy.searches || {};
const shareType = dy.shareType || 'video';
const accountCards = dy.accountCards || [];
const agg = dy.aggMetrics;
// ---------- 账号矩阵(主号 + 竞品号 + 垂类号,多卡一排)----------
// 只在有 2+ 账号时才展示矩阵,单账号走 heroUser 旧样式
const roleToneMap = {
'官方号': { bg: 'rgba(255,0,80,.14)', fg: '#FF3E75', border: 'rgba(255,0,80,.3)' },
'品牌竞品': { bg: 'rgba(245,166,35,.14)', fg: '#F5A623', border: 'rgba(245,166,35,.3)' },
'品牌竞品号': { bg: 'rgba(245,166,35,.14)', fg: '#F5A623', border: 'rgba(245,166,35,.3)' },
'垂类博主': { bg: 'rgba(139,92,246,.14)', fg: '#A78BFA', border: 'rgba(139,92,246,.3)' },
'垂类博主号': { bg: 'rgba(139,92,246,.14)', fg: '#A78BFA', border: 'rgba(139,92,246,.3)' },
'补充号': { bg: 'rgba(0,220,130,.14)', fg: '#22C581', border: 'rgba(0,220,130,.3)' },
};
const accountMatrix = accountCards.length >= 2 ? `
抖音账号矩阵 · ${accountCards.length} 个账号
${agg ? `· 累计粉丝 ${fmtNum(agg.total_followers)}
· 采样作品 ${agg.total_posts_sampled}
· 认证账号 ${agg.verified_count}/${agg.total_accounts} ` : ''}
${accountCards.map((c) => {
const tone = roleToneMap[c.role] || roleToneMap['官方号'];
const hasData = !c.error && c.nickname !== '—';
if (!hasData) {
return `
${esc(c.role)}
${esc(c.label || c.role)}
⚠ ${esc((c.error || '数据不可用').slice(0, 80))}
${esc(c.share_url || '')}
`;
}
return `
${esc(c.role)}
${c.custom_verify ? `✓ ${esc(c.custom_verify.slice(0, 14))} ` : ''}
${c.avatar ? `
` : `
`}
${esc((c.nickname || '—').slice(0, 20))}
${esc((c.signature || '').slice(0, 40))}
${fmtNum(c.follower_count)}
粉丝
${fmtNum(c.aweme_count)}
作品
${fmtNum(c.total_favorited)}
获赞
${c.top_post ? `
TOP POST
${esc(cleanText(c.top_post.desc || '').slice(0, 90))}
♥ ${fmtNum(c.top_post.digg)}
💬 ${fmtNum(c.top_post.comment)}
${c.top_post.play > 0 ? `▶ ${fmtNum(c.top_post.play)} ` : ''}
` : `
暂无作品数据
`}
`;
}).join('')}
` : '';
// ---------- Hero:作者画像卡 + 作品节奏 ----------
const heroUser = u ? `
${u.avatar ? `
` : '
'}
抖音 · ${shareType === 'user' ? '品牌旗舰店' : '视频'}
${u.custom_verify ? `${esc(u.custom_verify.slice(0, 20))} ` : ''}
${u.ip_location ? `${esc(u.ip_location)} ` : ''}
${esc(u.nickname || '—')}
${esc((u.signature || '暂无简介').slice(0, 120))}
粉丝
${fmtNum(u.follower_count || 0)}
作品
${fmtNum(u.aweme_count || 0)}
获赞
${fmtNum(u.total_favorited || 0)}
关注
${fmtNum(u.following_count || 0)}
PRODUCTION RHYTHM
作品节奏均值
${dy.authorStats ? `
${fmtNum(Math.round(dy.authorStats.avgDigg))}
AVG ♥ LIKES
${fmtNum(Math.round(dy.authorStats.avgComment))}
AVG 💬 COMMENT
${fmtNum(Math.round(dy.authorStats.avgPlay))}
AVG ▶ PLAY
${(u.follower_count || 0) > 500000
? `头部品牌号 :${fmtNum(u.follower_count)} 粉丝 + 高频发布 (${u.aweme_count} 作品) 已建立稳定内容资产,适合做 KOL 型种草。`
: (u.follower_count || 0) > 10000
? `成长期品牌号 :粉丝 ${fmtNum(u.follower_count)},内容储备 ${u.aweme_count} 支,应加大高转化爆款内容产出。`
: `起步品牌号 :粉丝仅 ${fmtNum(u.follower_count)},首要任务是建立内容基线和选定垂类话题。`}
` : '
暂无作品均值数据。
'}
` : '';
// ---------- Hot video 卡片(仅 video-type 分享链)----------
const videoCard = v ? `
${v.cover ? `
` : ''}
品牌视频
${(v.text_extra || []).slice(0, 3).map((t) => `#${esc(t)} `).join('')}
${esc(cleanText(v.desc || '').slice(0, 160))}
点赞
${fmtNum(v.statistics?.digg_count || 0)}
评论
${fmtNum(v.statistics?.comment_count || 0)}
分享
${fmtNum(v.statistics?.share_count || 0)}
播放
${fmtNum(v.statistics?.play_count || 0)}
` : '';
// ---------- Top Posts 散点 + 卡片网格 ----------
const topPostsSection = topPosts.length ? `
品牌号作品热度图 · Top ${topPosts.length}
POST SCATTER
X=点赞 · Y=评论 · 气泡=转发
TOP ${Math.min(topPosts.length, 5)} POSTS
爆款作品清单
${topPosts.slice(0, 5).map((p, i) => `
${p.cover ? `
` : '
'}
#${String(i + 1).padStart(2, '0')}
${esc(cleanText(p.desc || '').slice(0, 80))}
♥ ${fmtNum(p.digg)}
💬 ${fmtNum(p.comment)}
▶ ${fmtNum(p.play)}
`).join('')}
` : '';
// ---------- 评论墙 ----------
const commentWall = topCmts.length ? `
抖音评论墙 · Top ${Math.min(topCmts.length, 12)}
${topCmts.slice(0, 12).map((c, i) => `
${esc(cleanText(c.text || ''))}
${esc((c.user?.nickname || '匿名').slice(0, 14))}${c.ip_label ? ' · ' + esc(c.ip_label) : ''}
♥ ${fmtNum(c.digg_count || 0)}
`).join('')}
` : '';
// ---------- 完整作品表 ----------
const userPostsTable = userPosts.length ? `
品牌号完整作品流 · ${userPosts.length} 条
# 内容 点赞 评论 播放 分享 收藏
${userPosts.slice().sort((a, b) => (b.statistics?.digg_count || 0) - (a.statistics?.digg_count || 0)).slice(0, 12).map((p, i) => `
${String(i + 1).padStart(2, '0')}
${esc(cleanText(p.desc || '').slice(0, 72))}
${fmtNum(p.statistics?.digg_count || 0)}
${fmtNum(p.statistics?.comment_count || 0)}
${fmtNum(p.statistics?.play_count || 0)}
${fmtNum(p.statistics?.share_count || 0)}
${fmtNum(p.statistics?.collect_count || 0)}
`).join('')}
` : '';
// ---------- 关键词搜索(若有 cookie)----------
const searchSection = Object.keys(searches).length ? `
品类关键词热度
${Object.entries(searches).map(([kw, info]) => {
if (!info || info._error) return `
"${esc(kw)}"
⚠ ${esc(String(info?._error || '无数据').slice(0, 60))}
`;
if (!info.count) return `
KEYWORD "${esc(kw)}"
当前品类曝光低,搜索结果为 0 条 — 说明此品类在抖音尚未形成内容沉淀,是蓝海机会 。
`;
return `
KEYWORD "${esc(kw)}"
总点赞
${fmtNum(info.totalDigg)}
${(info.top || []).slice(0, 3).map((t) => `
${fmtNum(t.digg)}❤ ${esc((t.desc || '').slice(0, 50))}
`).join('')}
`;
}).join('')}
` : '';
return `
DY · Douyin Presence
抖音阵地深度
${accountCards.length >= 2 ? `多账号矩阵采样:官方号 + 品牌竞品 + 垂类博主 · 主号深度画像如下` : (shareType === 'user' ? '通过品牌旗舰店分享链直抓 · 账号画像 / 作品流 / 评论 / 品类搜索' : '通过品牌视频分享链直抓 · 视频/评论/作者主页/品类搜索')}
${renderDouyinTrendsBlock({ A })}
${accountMatrix}
${heroUser}
${videoCard}
${topPostsSection}
${commentWall}
${userPostsTable}
${searchSection}
`;
}
function renderS7Themes({ themes, slideNum, slideTotal }) {
const renderGroup = (list, cls, title, eyebrow, color) => `
${eyebrow}
${title}
${list.slice(0, 6).map((t) => `
${esc(t.tag)}
${t.count} 次提及
${(t.examples || []).slice(0, 2).map((e) => `"${esc(cleanText(e).slice(0, 80))}" `).join('')}
`).join('\n ')}
`;
return `
07 · Themes Cluster
痛点 · 亮点 · 场景
从真实语料中提炼出的 VOC 主题 · 标注频次与典型原声
${renderGroup(themes.pain, 'pain', '痛点主题', '07.1 · PAIN POINTS', 'var(--rose)')}
${renderGroup(themes.bright, 'bright', '亮点主题', '07.2 · BRIGHT SPOTS', 'var(--green)')}
${renderGroup(themes.scenarios, 'scene', '场景主题', '07.3 · USAGE SCENARIOS', 'var(--blue)')}
`;
}
function renderS8Matrix({ themes, slideNum, slideTotal }) {
const q1 = themes.pain.filter((t) => ['口感差', '效果不显'].includes(t.tag)).slice(0, 2);
const q2 = themes.bright.slice(0, 3);
const q3 = themes.pain.filter((t) => ['信任危机', '价格敏感', '副作用担忧'].includes(t.tag)).slice(0, 2);
const q4 = themes.scenarios.slice(0, 2);
return `
08 · Opportunity Matrix
品类机会矩阵
四象限 · 产品可解决性 × 用户痛点强度
痛点强度 LOW → HIGH
QUADRANT I · 产品机会
高痛点 · 产品可优化解决
${q1.map((t) => `${esc(t.tag)} (${t.count})`).join(' / ') || '尚无强信号'}。这些痛点可通过产品配方、剂型、包装直接优化 — 直接迭代 ROI 最高。
QUADRANT II · 强化既有
低痛点 · 产品可强化放大
${q2.map((t) => `${esc(t.tag)} (${t.count})`).join(' / ') || '尚无强信号'}。这些是消费者已认同的优势,内容营销直接放大。
QUADRANT III · 教育必投
高痛点 · 非产品端
${q3.map((t) => `${esc(t.tag)} (${t.count})`).join(' / ') || '尚无强信号'}。这些是品类心智问题,需要 PR / 教育内容 / 品牌信任建设长期解决。
QUADRANT IV · 场景机会
潜在使用场景 · 可扩展
${q4.map((t) => `${esc(t.tag)} (${t.count})`).join(' / ') || '尚无强信号'}。这些场景是新增长入口,可通过 campaign / 联名 / KOC 铺量打开。
产品可解决性 LOW → HIGH
`;
}
function renderS9Action({ A, themes, slideNum, slideTotal }) {
const topPain = themes.pain[0]?.tag || '核心痛点';
const topScene = themes.scenarios[0]?.tag || '场景';
const topKol = A.kols[0];
return `
09 · Action Plan
30 天行动建议
产品 / 内容 / 渠道 三路并进,从 VOC 到落地。
TRACK A · PRODUCT
产品端
✓ 针对「${esc(topPain)}」推出改良版 SKU / 新剂型
✓ 包装文案直接借用高赞评论原文
✓ 上市前用同样 VOC 链路做 A/B 预测试
TRACK B · CONTENT
内容端
✓ 切入「${esc(topScene)}」场景做系列种草
✓ 复用 Top 爆款笔记标题公式批量产出
✓ 用高赞评论作为视频字幕 / 金句 BGM
TRACK C · CHANNEL
渠道端
✓ 头部 ${A.kolTier.head.length} 位优先合作${topKol ? `(如 ${esc(topKol.nickname)})` : ''}
✓ 腰部 ${A.kolTier.mid.length} 位批量铺垫品类心智
✓ KOC ${A.kolTier.tail.length} 位素材铺量支撑投流
30 天时间线
DAY 01 — 07 · 对齐
对齐核心 VOC 发现 + 快速小样测试
把本报告的 Top 3 洞察 / Top 痛点 / Top 爆款笔记,在内部做 1 次品牌 / 产品 / 运营 / 投放四方对齐会。选 1-2 个高赞评论金句,做小样社交投流测试。
DAY 08 — 14 · 内容
复用爆款结构,启动 KOC 铺量
以「${esc(topScene)}」为切入点,量产 20-30 条 KOC 笔记;每条笔记用不同的高赞评论做卡点。配合 ${A.kolTier.mid.length} 位腰部达人同步发种草。
DAY 15 — 21 · 放大
基于数据优选,头部合作上场
根据 Day 08-14 的测试数据,锁定 2-3 个最强素材方向,启动头部 KOL 合作。同步通过 Amazon 国际对标数据测试是否跨境放量。
DAY 22 — 30 · 复盘
收集新一轮 VOC,迭代下次投放
重新跑 VOC 采集脚本,对比 30 天前后的痛点词频变化。把"新涌现的痛点"作为下一迭代的产品优化 input,形成闭环。
`;
}
function renderFooter() {
return ``;
}
// ============================================================
// TikTok · Amazon 的内容端对标(独立 slide)
// ============================================================
function renderSTikTok({ A, slideNum, slideTotal }) {
const tt = A.tiktok;
if (!tt || tt.empty) return '';
const m = tt.metrics || {};
const topVids = tt.topVideos || [];
const topAuthors = tt.topAuthors || [];
const topCmts = tt.topComments || [];
const topTags = tt.topHashtags || [];
const topRegions = tt.topRegions || [];
const byKw = tt.byKeywordStats || {};
const keywords = tt.keywords_used || Object.keys(byKw);
const topCatUsers = tt.topCategoryUsers || [];
const TT_CYAN = '#25F4EE';
const TT_PINK = '#FE2C55';
// --- Hero metrics 四大数字 + 认证率 + 触达粉丝 ---
const heroMetrics = `
VIDEOS
${fmtNum(m.totalVideos)}
跨 ${keywords.length} 个英文关键词
TOTAL PLAYS
${fmtNum(m.totalPlay)}
平均 ER ${(m.avgEngagementRate * 100).toFixed(1)}%
TOTAL LIKES
${fmtNum(m.totalDigg)}
评论 ${fmtNum(m.totalComment)} · 分享 ${fmtNum(m.totalShare)}
CREATORS
${m.totalAuthors}
认证 ${m.verifiedAuthors} · 触达粉丝 ${fmtNum(m.totalFollowersReached)}
`;
// --- 关键词覆盖 bar row ---
const maxKwDigg = Math.max(1, ...Object.values(byKw).map((v) => v.totalDigg || 0));
const keywordCoverage = Object.keys(byKw).length ? `
KEYWORD COVERAGE
英文关键词覆盖深度 · TikTok 搜索反馈
${Object.entries(byKw).map(([kw, s]) => {
const pct = Math.round((s.totalDigg / maxKwDigg) * 100);
return `
${esc(kw)}
${s.videos} 视频 · ${fmtNum(s.totalDigg)} 赞 · ${fmtNum(s.totalPlay)} 播
`;
}).join('')}
` : '';
// --- Top 作者卡 ---
const authorsBlock = topAuthors.length ? `
Top ${topAuthors.length} 海外创作者矩阵 按粉丝排序
${topAuthors.map((a) => `
${a.avatar ? `
` : `
`}
${esc((a.nickname || '—').slice(0, 20))}
@${esc(a.unique_id || '')}${a.region ? ' · ' + esc(a.region) : ''}
${a.custom_verify ? `
✓ ${esc(String(a.custom_verify).slice(0, 8))} ` : ''}
${esc(a.signature || '(no bio)')}
${fmtNum(a.follower_count)}
FOLLOWERS
${fmtNum(a.aweme_count)}
VIDEOS
${fmtNum(a.total_favorited)}
LIKES
${a.best_post ? `
BEST POST
${esc(cleanText(a.best_post.desc || '').slice(0, 90))}
♥ ${fmtNum(a.best_post.digg)}
▶ ${fmtNum(a.best_post.play)}
` : `
暂无 Best Post 数据
`}
`).join('')}
` : '';
// --- Top Videos 网格 ---
const topVideosBlock = topVids.length ? `
爆款视频 Top ${Math.min(topVids.length, 9)} 按点赞排序 · 品类流量锚点
${topVids.slice(0, 9).map((v, i) => `
${v.cover ? `
` : `
`}
#${String(i + 1).padStart(2, '0')}
${v._from_keyword ? `· ${esc(v._from_keyword)} ` : ''}
${esc(cleanText(v.desc || '').slice(0, 140))}
♥ ${fmtNum(v.digg)}
💬 ${fmtNum(v.comment)}
▶ ${fmtNum(v.play)}
↗ ${fmtNum(v.share)}
${v.author ? `
@${esc(v.author.unique_id || v.author.nickname || '')}
· ${fmtNum(v.author.follower_count || 0)}粉
${v.author.custom_verify ? `✓ ` : ''}
` : ''}
${(v.hashtags || []).length ? `
${(v.hashtags || []).slice(0, 4).map((h) => `#${esc(h)} `).join('')}
` : ''}
`).join('')}
` : '';
// --- 评论墙 ---
const commentBlock = topCmts.length ? `
📣 海外用户原声 Top ${Math.min(topCmts.length, 12)}
${topCmts.slice(0, 12).map((c, i) => `
${esc(cleanText(c.text || ''))}
${esc((c.user?.nickname || c.user?.unique_id || 'user').slice(0, 20))}${c.user?.region ? ' · ' + esc(c.user.region) : ''}
♥ ${fmtNum(c.digg_count || 0)}
`).join('')}
` : '';
// --- Hashtag 词云(Top List) ---
const hashtagBlock = topTags.length ? `
HASHTAG FREQUENCY
Top ${Math.min(topTags.length, 16)} 热门标签
${topTags.slice(0, 16).map((t, i) => {
const size = i < 3 ? '1.1rem' : i < 8 ? '.95rem' : '.85rem';
const opacity = i < 3 ? 1 : 0.85;
const color = i < 3 ? TT_PINK : TT_CYAN;
return `
#${esc(t.tag)} ${t.count}
`;
}).join('')}
REGION MIX
创作者地区分布
${topRegions.length ? `
${topRegions.map(([r, c]) => {
const pct = Math.round((c / (m.totalVideos || 1)) * 100);
return `
`;
}).join('')}
` : `
无地区数据
`}
` : '';
// --- 品类头部账号(从 user search 获取) ---
const catUserBlock = topCatUsers.length ? `
🏷 品类头部账号 来自 TikTok 用户搜索 · 可作为 B 侧合作 / 学习对象
${topCatUsers.map((u) => `
${u.avatar ? `
` : `
`}
${esc((u.nickname || '').slice(0, 18))}${u.custom_verify ? ' ✓ ' : ''}
@${esc(u.unique_id || '')}
${fmtNum(u.follower_count || 0)}
粉丝
`).join('')}
` : '';
return `
TT · TikTok Presence
TikTok 海外阵地
Amazon 的内容端对标 · ${keywords.map((k) => esc(k)).join(' / ')} · 不需 cookie 直通海外版
${heroMetrics}
${keywordCoverage}
${authorsBlock}
${topVideosBlock}
${commentBlock}
${hashtagBlock}
${catUserBlock}
${renderTTAdsBlock({ A })}
`;
}
// ============================================================
// Market Intel · TikTok Ads 官方情报 block(注入 TikTok slide 尾部)
// ============================================================
function renderTTAdsBlock({ A }) {
const mi = A.marketIntel;
if (!mi || mi.empty || !mi.ttAds?.hasData) return '';
const { insights, relatedKeywords, relatedFromKeyword } = mi.ttAds;
const TT_CYAN = '#25F4EE';
const TT_PINK = '#FE2C55';
// Insight 卡:每个 keyword 1 张
const insightsCards = insights.length ? `
${insights.map((ins, i) => {
const postChange = ins.post_change || 0;
const trendColor = postChange > 50 ? '#22c55e' : (postChange > 0 ? TT_CYAN : '#f97316');
const trendArrow = postChange > 0 ? '▲' : (postChange < 0 ? '▼' : '●');
return `
AD KEYWORD #${i + 1}
TikTok Creative Center
"${esc(ins.keyword)}"
IMPRESSIONS
${fmtNum(ins.impression)}
POST CHANGE
${trendArrow} ${(postChange || 0).toFixed(1)}%
CTR
${(ins.ctr || 0).toFixed(2)}%
CVR
${(ins.cvr || 0).toFixed(2)}%
📝 ${fmtNum(ins.post)} posts
♥ ${fmtNum(ins.like)}
💬 ${fmtNum(ins.comment)}
↗ ${fmtNum(ins.share)}
💰 ${fmtNum(ins.cost)}
`;
}).join('')}
` : '';
// Related keywords 词云:按 score 渐变字号
const relatedBlock = relatedKeywords.length ? `
RELATED KEYWORD NETWORK
Top ${relatedKeywords.length} · 来源: "${esc(relatedFromKeyword)}"
TikTok Ads 官方相关词图谱
${relatedKeywords.map((r, i) => {
const pct = (r.score || 0) / 100;
const fontSize = (0.8 + pct * 0.6).toFixed(2); // 0.8~1.4rem
const color = i < 3 ? TT_PINK : (i < 10 ? TT_CYAN : 'var(--text-2)');
const opacity = (0.6 + pct * 0.4).toFixed(2);
return `
${esc(r.name)} ${r.score}
`;
}).join('')}
` : '';
return `
TT · OFFICIAL MARKET INTEL
TikTok Creative Center 官方情报 第一方数据 · 广告主视角的市场真相
${insightsCards}
${relatedBlock}
`;
}
// ============================================================
// Market Intel · Douyin 全站热榜基线 block(注入 Douyin slide 顶部)
// ============================================================
function renderDouyinTrendsBlock({ A }) {
const mi = A.marketIntel;
if (!mi || mi.empty || !mi.douyinGlobal?.hasGlobal) return '';
const { hotWords, webHotSearch, hotTopics, categoryHitTotal, filterKeywords } = mi.douyinGlobal;
const DY_PINK = '#FF3E75';
const hotWordsBlock = hotWords.length ? `
HOT WORD BILLBOARD
抖音星图 · 近 24h 热词 Top 6
${hotWords.map((w, i) => `
#${String(i + 1).padStart(2, '0')}
${esc(w.title)}
${fmtNum(w.score)}
`).join('')}
` : '';
const webHotBlock = webHotSearch.length ? `
WEB HOT SEARCH
抖音 Web 首页热搜 Top 6
${webHotSearch.map((w, i) => `
#${String(i + 1).padStart(2, '0')}
${esc(w.word)}
${fmtNum(w.view_count)}
`).join('')}
` : '';
const hotTopicsBlock = hotTopics.length ? `
HOT TOPIC CHALLENGE
抖音热挑战 Top 5
${hotTopics.map((t, i) => `
#${esc(t.challenge_name)}
▶ ${fmtNum(t.play_cnt)}
📝 ${fmtNum(t.publish_cnt)} 篇参与
`).join('')}
` : '';
const categoryNote = filterKeywords.length ? `
品类过滤命中: 用关键词 [${filterKeywords.slice(0, 6).map((k) => esc(k)).join(' / ')}] 过滤以上 5 份站级热榜,共命中 ${categoryHitTotal} 条相关内容 —
${categoryHitTotal === 0 ? '说明本品类在抖音全站 Top 榜未形成内容沉淀,是品牌蓝海 :现有头部创作者尚未进入健康/滋补赛道。' : '说明本品类已有热点渗透,可顺势挂载热话题做内容承接。'}
` : '';
return `
DOUYIN · CONTENT ECOSYSTEM BASELINE
抖音站级热榜信号 中国内容生态基线 · 决定品牌内容投放语境
Douyin Billboard API
${hotWordsBlock}
${webHotBlock}
${hotTopicsBlock}
${categoryNote}
`;
}
function buildHTML({ product, category, collectedAt, A, themes }) {
const amz = A.amazon || {};
const hasDouyin = A.douyin && !A.douyin.empty;
const hasTikTok = A.tiktok && !A.tiktok.empty;
// 鲜活的星级分布:把每款产品的 5 星分布转成 ECharts 友好结构
const starDistProducts = Object.values(amz.reviewsSummary || {}).map((r) => ({
asin: r.asin,
brand: r.brand || 'N/A',
title: (r.title || '').slice(0, 28),
stars: [5, 4, 3, 2, 1].map((s) => r.starDist[s] || 0),
}));
// 抖音作品散点
const douyinPosts = hasDouyin ? (A.douyin.topPosts || []).concat(
(A.douyin.userPosts || []).slice(0, 20).map((v) => ({
aweme_id: v.aweme_id, desc: v.desc,
digg: v.statistics?.digg_count || 0,
comment: v.statistics?.comment_count || 0,
share: v.statistics?.share_count || 0,
play: v.statistics?.play_count || 0,
}))
).filter((v, i, arr) => arr.findIndex((x) => x.aweme_id === v.aweme_id) === i).slice(0, 30) : [];
const chartData = {
priceBuckets: amz.priceBuckets || A.priceBuckets || {},
topBrands: (A.topBrands || []).slice(0, 8),
topBrandShares: (amz.topBrands || []).slice(0, 8).map((b) => ({
name: b.brand, value: +b.share.toFixed(1), sales: b.sales, count: b.count,
})),
ratingBuckets: amz.ratingBuckets || {},
reviewCountBuckets: amz.reviewCountBuckets || {},
starDistProducts,
topIPs: A.topIPs || [],
noteHeatmap: (A.topNotes || []).slice(0, 20).map((n) => ({
title: cleanText(n.title || '').slice(0, 22),
liked: n.liked_count || 0,
comments: n.comments_count || 0,
collected: n.collected_count || 0,
})),
douyinPosts,
};
// Slide 编号(基础 10 张 + TikTok/抖音 各占一张)
const slideTotal = 10 + (hasTikTok ? 1 : 0) + (hasDouyin ? 1 : 0);
const sn = (i) => String(i).padStart(2, '0');
let n = 1;
const s0 = sn(n++), s1 = sn(n++), s2 = sn(n++), s3 = sn(n++), s4 = sn(n++);
const s5 = sn(n++), s6 = sn(n++);
const sttk = hasTikTok ? sn(n++) : '';
const sdy = hasDouyin ? sn(n++) : '';
const s7 = sn(n++), s8 = sn(n++), s9 = sn(n++);
const ST = String(slideTotal).padStart(2, '0');
return `
${esc(product)} · VOC 洞察报告
${STYLES}
${renderNav(product, hasDouyin, hasTikTok)}
${s0}
/
${ST}
↓ / Space
|
滚动或按键切换
${renderS0Cover({ product, category, collectedAt, A, slideNum: s0, slideTotal: ST })}
${renderS1Summary({ A, slideNum: s1, slideTotal: ST })}
${renderS2Insights({ A, themes, slideNum: s2, slideTotal: ST })}
${renderS3Notes({ A, slideNum: s3, slideTotal: ST })}
${renderS4Voices({ A, slideNum: s4, slideTotal: ST })}
${renderS5KOL({ A, slideNum: s5, slideTotal: ST })}
${renderS6Amazon({ A, slideNum: s6, slideTotal: ST })}
${hasTikTok ? renderSTikTok({ A, slideNum: sttk, slideTotal: ST }) : ''}
${hasDouyin ? renderSDouyin({ A, slideNum: sdy, slideTotal: ST }) : ''}
${renderS7Themes({ themes, slideNum: s7, slideTotal: ST })}
${renderS8Matrix({ themes, slideNum: s8, slideTotal: ST })}
${renderS9Action({ A, themes, slideNum: s9, slideTotal: ST })}
${renderFooter()}
`;
}
module.exports = { buildHTML };