R46: 脚本诊断维度改名——钩子设置→爆款开场、共鸣和共情→创意和爆点(排设定承接前);DIAG_KEY_ALIAS 旧 key 兼容保历史分数;data-pages ah→ai

This commit is contained in:
maogeigei committed 2026-09-03 19:22:33 +08:00
1 parent 05ea2c29c8
commit e3bc43e48f
2 files changed
+12 -8

No files matched your search

@@ -1448,7 +1448,7 @@ async function openCustomScriptView(id) {
/* ================= AI脚本诊断 ================= */
async function renderReviews(view) {
const d = await api('/api/dsh/rewrites').catch((e) => ({ ok: false, error: e.message }));
const DIMS = ['设定承接', '框架节奏', '钩子设置', '叙事逻辑', '极致事件', '共鸣和共情', '其他', '总分'];
const DIMS = ['创意和爆点', '设定承接', '框架节奏', '爆款开场', '叙事逻辑', '极致事件', '其他', '总分'];
if (!d.ok) { view.innerHTML = `<div class="page"><div class="page-toolbar">${toolbarBack()}</div><div class="empty">${esc(d.error || '加载失败')}</div></div>`; bindBack(view); return; }
const items = (d.items || []).filter((x) => x.status === 'done' && x.script_len > 0);
// 补账号名
@@ -1474,7 +1474,7 @@ async function renderReviews(view) {
const sd = dimsOf(row);
const rv = reviewOf(row);
const dimsTd = DIMS.map((dim) => {
const v = dim === '总分' ? sd.total : sd.dims[dim];
const v = dim === '总分' ? sd.total : diagDimVal(sd.dims, dim);
const clickable = dim === '总分' && rv && typeof v === 'number';
return `<td style="text-align:center;${dim === '总分' && typeof v === 'number' ? 'color:var(--primary);font-weight:600' : 'color:var(--dim)'}">${clickable ? `<a class="link" data-review="${rv.id}">${fmtScore(v)}</a>` : fmtScore(v)}</td>`;
}).join('');
@@ -1547,9 +1547,9 @@ async function renderReviews(view) {
const rv = d3.review;
const typeName = rv.type === 'source' ? '原视频脚本复盘' : rv.type === 'compare' ? '对比分析' : 'AI 脚本复盘';
let dimsObj = {}; try { dimsObj = JSON.parse(rv.dims_json || '{}'); } catch (e) {}
const DIMS_ALL = ['设定承接', '框架节奏', '钩子设置', '叙事逻辑', '极致事件', '共鸣和共情', '格式规范性', '台词口语化', '内容合规', '教程完整链', '其他'];
const DIMS_ALL = ['创意和爆点', '设定承接', '框架节奏', '爆款开场', '叙事逻辑', '极致事件', '格式规范性', '台词口语化', '内容合规', '教程完整链', '其他'];
const scoreColor = (v) => (v >= 75 ? '#3a9e6d' : v >= 60 ? '#d99a2b' : '#d9534f');
const scoreBar = (dims, prefix) => DIMS_ALL.map((k) => { const v = dims[k]; const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? scoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? scoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
const scoreBar = (dims, prefix) => DIMS_ALL.map((k) => { const v = diagDimVal(dims, k); const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? scoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? scoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
let body = '';
if (rv.type === 'compare') {
const aiD = dimsObj.ai || {}, srcD = dimsObj.source || {};
@@ -1580,7 +1580,11 @@ async function renderReviews(view) {
—— 分镜内容 = 该视频下 storyboard_log 中属当前版本的记录 + 生成/重新生成入口(仅参考选题脚本;自定义选题无视频载体不支持)
数据源:/api/dsh/video-script + /api/dsh/video-detail(参考选题)/ /api/dsh/custom-script(自定义选题)
+ /api/dsh/review-full?rewriteId=(当前版本诊断)+ /api/dsh/storyboards?videoId=(分镜) */
const DIAG_DIMS = ['设定承接', '框架节奏', '钩子设置', '叙事逻辑', '极致事件', '共鸣和共情', '格式规范性', '台词口语化', '内容合规', '教程完整链', '其他'];
const DIAG_DIMS = ['创意和爆点', '设定承接', '框架节奏', '爆款开场', '叙事逻辑', '极致事件', '格式规范性', '台词口语化', '内容合规', '教程完整链', '其他'];
/* R46 维度术语改名(09-03):钩子设置→爆款开场、共鸣和共情→创意和爆点(排设定承接前)。
维度名兼作 dims_json 数据 key——历史复盘仍为旧 key,取值回退别名兼容(新 key 缺失时读旧 key),保证历史分数继续展示 */
const DIAG_KEY_ALIAS = { '爆款开场': '钩子设置', '创意和爆点': '共鸣和共情' };
const diagDimVal = (dims, k) => { const v = dims[k]; return (typeof v === 'number' && Number.isFinite(v)) ? v : (DIAG_KEY_ALIAS[k] ? dims[DIAG_KEY_ALIAS[k]] : v); };
const diagScoreColor = (v) => (v >= 75 ? '#3a9e6d' : v >= 60 ? '#d99a2b' : '#d9534f');
const diagFmtScore = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : '-');
@@ -1604,7 +1608,7 @@ async function reportFullReview(reviewId) {
const rv = d3.review;
const typeName = rv.type === 'source' ? '原视频脚本复盘' : rv.type === 'compare' ? '对比分析' : 'AI 脚本复盘';
let dimsObj = {}; try { dimsObj = JSON.parse(rv.dims_json || '{}'); } catch (e) {}
const scoreBar = (dims, prefix) => DIAG_DIMS.map((k) => { const v = dims[k]; const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? diagScoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? diagScoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
const scoreBar = (dims, prefix) => DIAG_DIMS.map((k) => { const v = diagDimVal(dims, k); const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? diagScoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? diagScoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
let body = '';
if (rv.type === 'compare') {
const aiD = dimsObj.ai || {}, srcD = dimsObj.source || {};
@@ -1701,7 +1705,7 @@ async function openScriptModal({ rewriteId, videoId } = {}) {
const diagHtml = (dg) => {
const { rv, dims, total, srcTotal } = dg;
const totalFin = Number.isFinite(total);
const scoreBar = DIAG_DIMS.map((k) => { const v = dims[k]; const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? diagScoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? diagScoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
const scoreBar = DIAG_DIMS.map((k) => { const v = diagDimVal(dims, k); const has = typeof v === 'number' && Number.isFinite(v); return `<div class="score-row"><span class="score-name">${esc(k)}</span><div class="score-bar"><div class="score-fill" style="width:${has ? v : 0}%;background:${has ? diagScoreColor(v) : '#eee'}"></div></div><span class="score-val" style="color:${has ? diagScoreColor(v) : 'var(--dim)'}">${has ? v : '—'}</span></div>`; }).join('');
let html = `<div class="score-box"><div class="score-box-title">AI 总分 ${diagFmtScore(totalFin ? total : Number(rv.total))}${rv.type === 'compare' && Number.isFinite(srcTotal) ? `(对比源脚本 ${diagFmtScore(srcTotal)})` : ''}${rv.verdict ? ` · <span style="color:${totalFin ? diagScoreColor(total) : 'var(--dim)'}">${esc(rv.verdict)}</span>` : ''}</div>${scoreBar}</div>`;
let issues = []; try { issues = JSON.parse(rv.issues_json || '[]'); } catch (e) {}
if (issues.length) html += `<div class="review-issues"><div class="rw-pane-title">问题清单</div>${issues.map((it) => `<div class="issue-row"><span style="color:${it.severity === '高' ? '#d9534f' : it.severity === '中' ? '#d99a2b' : '#3a9e6d'};font-weight:600">${esc(it.severity || '低')}</span><span>${esc(it.issue || '')}</span>${it.suggestion ? `<span class="dim">→ ${esc(it.suggestion)}</span>` : ''}</div>`).join('')}</div>`;
@@ -42,6 +42,6 @@
</div>
<script src="app.js?v=20260903y"></script>
<script src="data-pages.js?v=20260903ag"></script>
<script src="data-pages.js?v=20260903ai"></script>
</body>
</html>