feat: add task lifecycle management and improve generation reliability
Centralize timeout policies, stall detection, and error classification for image/video/text generation tasks. Improve ecommerce OSS upload flow and add script evaluation enhancements. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,8 @@ interface EvalResult {
|
||||
totalScore: number;
|
||||
grade: string;
|
||||
dimensionScores: Record<string, number>;
|
||||
subScores?: Record<string, Record<string, number>>;
|
||||
evidence?: Record<string, string[]>;
|
||||
summary: string;
|
||||
issues: string[];
|
||||
highlights: string[];
|
||||
@@ -192,6 +194,60 @@ const SCORE_DIMENSIONS: ScoreDimension[] = [
|
||||
{ key: "content", label: "内容深度", maxScore: 15, hint: "主题表达·情感共鸣·思想内核", detail: "核心设定将科技伦理与人性困境紧密结合,主题表达深刻有力。" },
|
||||
];
|
||||
|
||||
const SUB_SCORE_LABELS: Record<string, string> = {
|
||||
openingImpact: "开篇冲击",
|
||||
suspenseChain: "悬念链",
|
||||
sceneHook: "场内钩子",
|
||||
structure: "结构完整",
|
||||
rhythm: "节奏推进",
|
||||
conflict: "冲突强度",
|
||||
reversal: "反转效率",
|
||||
motivation: "动机清晰",
|
||||
arc: "人物弧光",
|
||||
voice: "语言辨识",
|
||||
relationship: "关系张力",
|
||||
causality: "因果链",
|
||||
worldRules: "世界规则",
|
||||
foreshadowing: "伏笔回收",
|
||||
continuity: "连续性",
|
||||
sceneDetail: "场景细节",
|
||||
shotPotential: "镜头潜力",
|
||||
aigcFeasibility: "AIGC 可实现",
|
||||
theme: "主题表达",
|
||||
emotion: "情感共鸣",
|
||||
marketFit: "市场匹配",
|
||||
originality: "原创性",
|
||||
};
|
||||
|
||||
function clampScore(score: unknown, maxScore: number): number {
|
||||
const numeric = Number(score);
|
||||
if (!Number.isFinite(numeric)) return 0;
|
||||
return Math.max(0, Math.min(maxScore, numeric));
|
||||
}
|
||||
|
||||
function getDimensionScore(result: EvalResult, dim: ScoreDimension): number {
|
||||
const value = result.dimensionScores[dim.key] ?? (dim.key === "logic" ? result.dimensionScores.dialogue : undefined);
|
||||
return clampScore(value, dim.maxScore);
|
||||
}
|
||||
|
||||
function formatSubScoreLabel(key: string): string {
|
||||
return SUB_SCORE_LABELS[key] ?? key.replace(/([A-Z])/g, " $1").trim();
|
||||
}
|
||||
|
||||
function getDimensionSubScores(result: EvalResult, dim: ScoreDimension): Array<[string, number]> {
|
||||
const scores = result.subScores?.[dim.key] ?? (dim.key === "logic" ? result.subScores?.dialogue : undefined);
|
||||
if (!scores) return [];
|
||||
return Object.entries(scores)
|
||||
.map(([key, value]) => [key, clampScore(value, dim.maxScore)] as [string, number])
|
||||
.filter(([, value]) => value > 0)
|
||||
.slice(0, 5);
|
||||
}
|
||||
|
||||
function getDimensionEvidence(result: EvalResult, dim: ScoreDimension): string[] {
|
||||
const evidence = result.evidence?.[dim.key] ?? (dim.key === "logic" ? result.evidence?.dialogue : undefined);
|
||||
return Array.isArray(evidence) ? evidence.map(String).map((item) => item.trim()).filter(Boolean).slice(0, 3) : [];
|
||||
}
|
||||
|
||||
function formatReportMarkdown(result: EvalResult, script: string): string {
|
||||
const lines: string[] = [];
|
||||
lines.push(`# 剧本评测报告`);
|
||||
@@ -203,9 +259,16 @@ function formatReportMarkdown(result: EvalResult, script: string): string {
|
||||
lines.push("");
|
||||
lines.push(`## 六维评分`);
|
||||
for (const dim of SCORE_DIMENSIONS) {
|
||||
const score = result.dimensionScores[dim.key] ?? 0;
|
||||
const score = getDimensionScore(result, dim);
|
||||
const pct = Math.round((score / dim.maxScore) * 100);
|
||||
const subScores = getDimensionSubScores(result, dim);
|
||||
const evidence = getDimensionEvidence(result, dim);
|
||||
const nestedReportLines = [
|
||||
...subScores.map(([key, value]) => ` - ${formatSubScoreLabel(key)}: ${value}`),
|
||||
...evidence.map((item) => ` - 证据: ${item}`),
|
||||
];
|
||||
lines.push(`- **${dim.label}**: ${score}/${dim.maxScore} (${pct}%) — ${dim.hint}`);
|
||||
lines.push(...nestedReportLines);
|
||||
}
|
||||
if (result.highlights.length > 0) {
|
||||
lines.push("");
|
||||
@@ -636,7 +699,7 @@ function ScriptTokensPage() {
|
||||
</div>
|
||||
<div className="script-eval-report__chart-grid">
|
||||
{SCORE_DIMENSIONS.map((dim, dimIndex) => {
|
||||
const score = result.dimensionScores[dim.key] ?? 0;
|
||||
const score = getDimensionScore(result, dim);
|
||||
const pct = Math.max(0, Math.min(1, score / dim.maxScore));
|
||||
const lossPct = 1 - pct;
|
||||
const isPerfect = score === dim.maxScore;
|
||||
@@ -676,6 +739,51 @@ function ScriptTokensPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="script-eval-report__detail-grid">
|
||||
{SCORE_DIMENSIONS.map((dim) => {
|
||||
const score = getDimensionScore(result, dim);
|
||||
const pct = Math.round((score / dim.maxScore) * 100);
|
||||
const subScores = getDimensionSubScores(result, dim);
|
||||
const evidence = getDimensionEvidence(result, dim);
|
||||
|
||||
return (
|
||||
<section className="script-eval-report__detail-card" key={dim.key}>
|
||||
<header className="script-eval-report__detail-head">
|
||||
<div>
|
||||
<span>{dim.label}</span>
|
||||
<strong>{score}<small>/{dim.maxScore}</small></strong>
|
||||
</div>
|
||||
<em>{pct}%</em>
|
||||
</header>
|
||||
<p className="script-eval-report__detail-hint">{dim.hint}</p>
|
||||
{subScores.length > 0 ? (
|
||||
<div className="script-eval-report__subscore-list">
|
||||
{subScores.map(([key, value]) => {
|
||||
const subPct = Math.max(0, Math.min(100, Math.round((value / dim.maxScore) * 100)));
|
||||
return (
|
||||
<div className="script-eval-report__subscore-row" key={key}>
|
||||
<span>{formatSubScoreLabel(key)}</span>
|
||||
<div className="script-eval-report__subscore-bar" aria-hidden="true">
|
||||
<i style={{ width: `${subPct}%` }} />
|
||||
</div>
|
||||
<b>{value}</b>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<p className="script-eval-report__detail-empty">等待模型返回更细的子项评分;当前先按主维度分数展示。</p>
|
||||
)}
|
||||
{evidence.length > 0 ? (
|
||||
<ul className="script-eval-report__evidence-list">
|
||||
{evidence.map((item, index) => <li key={index}>{item}</li>)}
|
||||
</ul>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="script-eval-report__findings">
|
||||
{result.highlights.length > 0 ? (
|
||||
<section className="script-eval-report__finding-group is-highlight">
|
||||
|
||||
Reference in New Issue
Block a user