139 lines
5.1 KiB
TypeScript
139 lines
5.1 KiB
TypeScript
const normalizeText = (value: unknown) => String(value || "").trim();
|
|
|
|
function normalizeStoryShot(value: unknown, index: number) {
|
|
const text = normalizeText(value);
|
|
if (/^\d+$/.test(text)) return text.padStart(2, "0");
|
|
return text || String(index + 1).padStart(2, "0");
|
|
}
|
|
|
|
type NormalizedStoryScriptRow = {
|
|
shot: string;
|
|
duration: string;
|
|
scene: string;
|
|
sceneDescription: string;
|
|
shotSize: string;
|
|
lighting: string;
|
|
dialogue: string;
|
|
backgroundMusic: string;
|
|
voiceAndSfx: string;
|
|
cameraMovement: string;
|
|
imagePrompt: string;
|
|
motionPrompt: string;
|
|
keyframeUrl: string;
|
|
};
|
|
|
|
export function normalizeStoryScriptRows(value: unknown): NormalizedStoryScriptRow[] {
|
|
if (!Array.isArray(value)) return [];
|
|
return value
|
|
.map((item, index) => {
|
|
if (Array.isArray(item)) {
|
|
const cells = item.map((cell) => normalizeText(cell));
|
|
if (!cells.some(Boolean)) return null;
|
|
const shot = normalizeStoryShot(cells[0], index);
|
|
const secondCellLooksLikeDuration = /^\d+(\.\d+)?\s*(s|秒)?$/i.test(cells[1] || "");
|
|
if (!(secondCellLooksLikeDuration ? cells.slice(2) : cells.slice(1)).some(Boolean)) return null;
|
|
const duration = secondCellLooksLikeDuration ? cells[1] : "5s";
|
|
const scene = secondCellLooksLikeDuration ? cells[2] || `镜头 ${shot}` : cells[1] || `镜头 ${shot}`;
|
|
const sceneDescription = secondCellLooksLikeDuration ? cells[2] || scene : cells[2] || cells[3] || scene;
|
|
return {
|
|
shot,
|
|
duration,
|
|
scene,
|
|
sceneDescription,
|
|
shotSize: (secondCellLooksLikeDuration ? cells[3] : "") || "中景",
|
|
lighting: (secondCellLooksLikeDuration ? cells[4] : cells[4]) || "电影感光影",
|
|
dialogue: (secondCellLooksLikeDuration ? cells[5] : "") || "+",
|
|
backgroundMusic: "无",
|
|
voiceAndSfx: (secondCellLooksLikeDuration ? cells[6] : cells[3]) || "无",
|
|
cameraMovement: (secondCellLooksLikeDuration ? cells[7] : "") || "缓慢推镜头",
|
|
imagePrompt: (secondCellLooksLikeDuration ? cells[8] : cells[5]) || sceneDescription,
|
|
motionPrompt:
|
|
(secondCellLooksLikeDuration ? cells[9] || cells[7] : cells[6]) ||
|
|
"保持镜头运动自然、连贯,围绕主体动作推进。",
|
|
keyframeUrl: "",
|
|
};
|
|
}
|
|
|
|
const raw =
|
|
item && typeof item === "object" && !Array.isArray(item)
|
|
? (item as Record<string, unknown>)
|
|
: {};
|
|
const shot = normalizeStoryShot(raw.shot || raw.shotNumber || raw.index || raw.id, index);
|
|
const duration = normalizeText(raw.duration || raw.length || raw.time || raw.seconds);
|
|
const scene = normalizeText(raw.scene || raw.location || raw.title);
|
|
const sceneDescription = normalizeText(
|
|
raw.sceneDescription ||
|
|
raw.description ||
|
|
raw.visual ||
|
|
raw.picture ||
|
|
raw.screen ||
|
|
raw.summary,
|
|
);
|
|
const shotSize = normalizeText(
|
|
raw.shotSize || raw.frameSize || raw.shot_type || raw.sceneScale || raw.cameraShot,
|
|
);
|
|
const lighting = normalizeText(
|
|
raw.lighting || raw.light || raw.atmosphere || raw.mood || raw.lightMood,
|
|
);
|
|
const dialogue = normalizeText(
|
|
raw.dialogue || raw.dialog || raw.narration || raw.voiceover || raw.monologue || raw.line,
|
|
);
|
|
const cameraMovement = normalizeText(
|
|
raw.cameraMovement || raw.cameraMove || raw.movement || raw.lensMovement || raw.motion,
|
|
);
|
|
const imagePrompt = normalizeText(
|
|
raw.imagePrompt ||
|
|
raw.image_generation_prompt ||
|
|
raw.image ||
|
|
raw.keyframePrompt ||
|
|
raw.keyFramePrompt,
|
|
);
|
|
const motionPrompt = normalizeText(
|
|
raw.motionPrompt ||
|
|
raw.videoPrompt ||
|
|
raw.video_motion_prompt ||
|
|
raw.motion ||
|
|
raw.cameraMovement,
|
|
);
|
|
const backgroundMusic = normalizeText(
|
|
raw.backgroundMusic || raw.music || raw.bgm || raw.soundtrack,
|
|
);
|
|
const voiceAndSfx = normalizeText(
|
|
raw.voiceAndSfx || raw.voice || raw.sound || raw.audio || raw.sfx,
|
|
);
|
|
|
|
if (
|
|
!scene &&
|
|
!sceneDescription &&
|
|
!imagePrompt &&
|
|
!motionPrompt &&
|
|
!backgroundMusic &&
|
|
!voiceAndSfx
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
shot,
|
|
duration: duration || "5s",
|
|
scene,
|
|
sceneDescription: sceneDescription || imagePrompt || scene || `镜头 ${shot}`,
|
|
shotSize: shotSize || "中景",
|
|
lighting: lighting || "电影感光影",
|
|
dialogue: dialogue || "+",
|
|
backgroundMusic: backgroundMusic || "无",
|
|
voiceAndSfx: voiceAndSfx || "无",
|
|
cameraMovement: cameraMovement || "缓慢推镜头",
|
|
imagePrompt: imagePrompt || sceneDescription || scene || `镜头 ${shot}关键帧`,
|
|
motionPrompt: motionPrompt || cameraMovement || "保持镜头运动自然、连贯,围绕主体动作推进。",
|
|
keyframeUrl: "",
|
|
};
|
|
})
|
|
.filter(
|
|
(
|
|
item,
|
|
): item is NormalizedStoryScriptRow => Boolean(item),
|
|
)
|
|
.slice(0, 18);
|
|
}
|