diff --git a/src/api/scriptEvalClient.ts b/src/api/scriptEvalClient.ts index 3afa296..bc11345 100644 --- a/src/api/scriptEvalClient.ts +++ b/src/api/scriptEvalClient.ts @@ -107,6 +107,17 @@ function isRecord(value: unknown): value is Record { return Boolean(value && typeof value === "object" && !Array.isArray(value)); } +function normalizeEvidenceItems(source: unknown[], limit: number): string[] { + const items: string[] = []; + for (const item of source) { + const value = String(item).trim(); + if (!value) continue; + items.push(value); + if (items.length >= limit) break; + } + return items; +} + function normalizeNestedScores(value: unknown): Record> { if (!isRecord(value)) return {}; @@ -132,7 +143,7 @@ function normalizeEvidence(value: unknown): Record { const source = value[dimensionKey] ?? (dimensionKey === "logic" ? value.dialogue : undefined); if (!Array.isArray(source)) continue; - const items = source.map(String).map((item) => item.trim()).filter(Boolean).slice(0, 3); + const items = normalizeEvidenceItems(source, 3); if (items.length > 0) normalized[dimensionKey] = items; } diff --git a/src/features/canvas/useCanvasNodeDrag.ts b/src/features/canvas/useCanvasNodeDrag.ts index 4db866d..eb27cb5 100644 --- a/src/features/canvas/useCanvasNodeDrag.ts +++ b/src/features/canvas/useCanvasNodeDrag.ts @@ -82,11 +82,16 @@ export function useCanvasNodeDrag(params: UseCanvasNodeDragParams) { const cy = pos.y + size.height / 2; const right = pos.x + size.width; const bottom = pos.y + size.height; - const others = [ - ...textNodesRef.current.filter((n) => n.id !== draggedId).map((n) => ({ pos: n.position, size: n.size })), - ...imageNodesRef.current.filter((n) => n.id !== draggedId).map((n) => ({ pos: n.position, size: n.size })), - ...videoNodesRef.current.filter((n) => n.id !== draggedId).map((n) => ({ pos: n.position, size: n.size })), - ]; + const others: Array<{ pos: CanvasPoint; size: CanvasNodeSize }> = []; + for (const node of textNodesRef.current) { + if (node.id !== draggedId) others.push({ pos: node.position, size: node.size }); + } + for (const node of imageNodesRef.current) { + if (node.id !== draggedId) others.push({ pos: node.position, size: node.size }); + } + for (const node of videoNodesRef.current) { + if (node.id !== draggedId) others.push({ pos: node.position, size: node.size }); + } for (const other of others) { const ocx = other.pos.x + other.size.width / 2; const ocy = other.pos.y + other.size.height / 2; diff --git a/src/features/image-workbench/ImageWorkbenchPage.tsx b/src/features/image-workbench/ImageWorkbenchPage.tsx index 17a5827..bbe351b 100644 --- a/src/features/image-workbench/ImageWorkbenchPage.tsx +++ b/src/features/image-workbench/ImageWorkbenchPage.tsx @@ -81,6 +81,20 @@ const CAMERA_EFFECT_PRESETS = [ { key: "hdr", label: "HDR", prompt: "HDR高动态范围,明暗细节丰富,色彩饱和" }, ] as const; +const CAMERA_EFFECT_PROMPT_BY_KEY = new Map( + CAMERA_EFFECT_PRESETS.map((effect) => [effect.key, effect.prompt]), +); + +function getCameraEffectsPrompt(effectKeys: Set): string { + if (effectKeys.size === 0) return ""; + const prompts: string[] = []; + for (const key of effectKeys) { + const prompt = CAMERA_EFFECT_PROMPT_BY_KEY.get(key); + if (prompt) prompts.push(prompt); + } + return prompts.join(","); +} + function shotScaleToZoom(shotScale: number): number { const map: Record = { 1: 24, 2: 28, 3: 32, 4: 35, 5: 40, 6: 50, 7: 60, 8: 75, 9: 85, 10: 100 }; return map[Math.round(Math.max(1, Math.min(10, shotScale)))] || 40; @@ -400,9 +414,7 @@ function ImageWorkbenchPage({ initialTool = "workbench", onOpenMore, onSelectVie const refUrls = await uploadReferenceImages([cameraImage]); const model = "wan2.7-image-pro"; const cameraDesc = `镜头预设: ${cameraPreset}, 方向: ${cameraDirection}, 水平: ${cameraHorizontal}°, 垂直: ${cameraVertical}°, 倾斜: ${cameraRoll}°, 焦距: ${cameraZoom}mm`; - const effectsDesc = cameraEffects.size > 0 - ? Array.from(cameraEffects).map((key) => CAMERA_EFFECT_PRESETS.find((e) => e.key === key)?.prompt).filter(Boolean).join(",") - : ""; + const effectsDesc = getCameraEffectsPrompt(cameraEffects); const fullPrompt = cameraPromptEnabled && cameraPrompt.trim() ? `${cameraDesc}${effectsDesc ? `。视觉效果: ${effectsDesc}` : ""}。${cameraPrompt}` : `${cameraDesc}${effectsDesc ? `。视觉效果: ${effectsDesc}` : ""}。保持人物和场景一致,按照镜头参数重新构图。`; diff --git a/src/features/script-tokens/ScriptTokensPage.tsx b/src/features/script-tokens/ScriptTokensPage.tsx index b553a84..1f7060b 100644 --- a/src/features/script-tokens/ScriptTokensPage.tsx +++ b/src/features/script-tokens/ScriptTokensPage.tsx @@ -245,9 +245,21 @@ function getDimensionSubScores(result: EvalResult, dim: ScoreDimension): Array<[ .slice(0, 5); } +function normalizeEvidenceItems(evidence: unknown[] | undefined, limit: number): string[] { + if (!Array.isArray(evidence)) return []; + const items: string[] = []; + for (const item of evidence) { + const value = String(item).trim(); + if (!value) continue; + items.push(value); + if (items.length >= limit) break; + } + return items; +} + 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) : []; + return normalizeEvidenceItems(evidence, 3); } function formatReportMarkdown(result: EvalResult, script: string): string {