79 lines
3.1 KiB
TypeScript
79 lines
3.1 KiB
TypeScript
const normalizeText = (value: unknown) =>
|
|
typeof value === "string" || typeof value === "number" ? String(value).trim() : "";
|
|
|
|
export function normalizeVideoAnalysisRows(
|
|
value: unknown,
|
|
framePreviews: string[] = [],
|
|
nodeId = "video-story",
|
|
) {
|
|
if (!Array.isArray(value)) return [];
|
|
return value
|
|
.map((item, index) => {
|
|
const raw =
|
|
item && typeof item === "object" && !Array.isArray(item)
|
|
? (item as Record<string, unknown>)
|
|
: {};
|
|
const sceneDescription = normalizeText(
|
|
raw.sceneDescription || raw.scene || raw.title || raw.description,
|
|
);
|
|
const narrative = normalizeText(
|
|
raw.narrative || raw.story || raw.storyContent || raw.narration || raw.summary,
|
|
);
|
|
const shot = normalizeText(raw.shot || raw.shotNumber || raw.index || index + 1);
|
|
const startTime = normalizeText(raw.startTime ?? raw.start ?? raw.start_time);
|
|
const endTime = normalizeText(raw.endTime ?? raw.end ?? raw.end_time);
|
|
const duration = normalizeText(raw.duration ?? raw.durationSeconds ?? raw.duration_seconds);
|
|
const shotSize = normalizeText(
|
|
raw.shotSize || raw.frameSize || raw.shot_type || raw.sceneScale,
|
|
);
|
|
const cameraAngle = normalizeText(raw.cameraAngle || raw.angle || raw.camera_angle);
|
|
const cameraMovement = normalizeText(
|
|
raw.cameraMovement || raw.cameraMove || raw.camera_motion || raw.motionType,
|
|
);
|
|
const focusDepth = normalizeText(
|
|
raw.focusDepth || raw.depthOfField || raw.focalDepth || raw.focus_depth,
|
|
);
|
|
const lighting = normalizeText(raw.lighting || raw.light || raw.lightDesign);
|
|
const backgroundMusic = normalizeText(raw.backgroundMusic || raw.music || raw.bgm);
|
|
const voiceAndSfx = normalizeText(raw.voiceAndSfx || raw.sound || raw.audio || raw.sfx);
|
|
const imagePrompt = normalizeText(
|
|
raw.imagePrompt || raw.image_generation_prompt || raw.image,
|
|
);
|
|
const motionPrompt = normalizeText(
|
|
raw.motionPrompt || raw.motion || raw.videoPrompt || raw.video_motion_prompt,
|
|
);
|
|
const keyframeIndex = Number(
|
|
raw.keyframeIndex || raw.frameIndex || raw.key_frame_index || index + 1,
|
|
);
|
|
if (!sceneDescription && !narrative && !imagePrompt) return null;
|
|
const normalizedFrameIndex =
|
|
Number.isFinite(keyframeIndex) && keyframeIndex > 0
|
|
? Math.max(0, Math.min(framePreviews.length - 1, Math.round(keyframeIndex) - 1))
|
|
: index % Math.max(framePreviews.length, 1);
|
|
return {
|
|
id: normalizeText(raw.id) || `${nodeId}-analysis-${index}`,
|
|
shot: shot || String(index + 1),
|
|
startTime,
|
|
endTime,
|
|
duration,
|
|
sceneDescription,
|
|
narrative,
|
|
shotSize,
|
|
cameraAngle,
|
|
cameraMovement,
|
|
focusDepth,
|
|
lighting,
|
|
backgroundMusic,
|
|
voiceAndSfx,
|
|
imagePrompt,
|
|
motionPrompt,
|
|
keyframeUrl:
|
|
normalizeText(raw.keyframeUrl || raw.previewUrl || raw.imageUrl) ||
|
|
framePreviews[normalizedFrameIndex] ||
|
|
"",
|
|
};
|
|
})
|
|
.filter((item): item is NonNullable<typeof item> => Boolean(item))
|
|
.slice(0, 120);
|
|
}
|