function extraPictureNumbers(extraRefs: number | number[]) { if (Array.isArray(extraRefs)) { return [...new Set(extraRefs.map(Number).filter(n => n >= 2 && n <= 5))].sort((a, b) => a - b) } const extras = Math.max(0, Math.min(4, extraRefs)) return Array.from({ length: extras }, (_, i) => i + 2) } export function identityBoilerplate(extraRefs: number | number[] = 0) { const extras = extraPictureNumbers(extraRefs) const secondary = extras.length === 0 ? '' : extras.length === 1 ? ` is a secondary reference angle for profile details.` : ` ${extras.map(n => ``).join(' and ')} are secondary reference angles for profile features only.` return ` is the exact facial identity, hairstyle, body proportions and clothing of the main character. Preserve this identity with high fidelity even when the subject temporarily leaves the frame and returns.${secondary}` } export function looksLikeIdentityPrompt(text: string) { return /primary identity anchor|exact facial identity/i.test(String(text || '')) } export function buildIdentityPrompt(actionPrompt: string, extraRefs: number | number[] = 0) { const action = String(actionPrompt || '').trim() if (looksLikeIdentityPrompt(action)) return action const boilerplate = identityBoilerplate(extraRefs) return action ? `${boilerplate}\n\n${action}` : boilerplate } export const IDENTITY_ACTION_TEMPLATE = `[SHOT CONFIGURATION] - Shot Type: Medium close-up, 50mm lens, eye-level - Camera Movement: Slow tracking dolly-in following the subject - Lighting: Warm golden-hour rim lighting with soft directional fill from screen left - Environment/Scenery: Dense pine forest, soft ambient ground mist [SUBJECT DIRECTION & ACTION] The subject from walks slowly through the path, glancing toward camera-left in awe. She turns slightly, speaking softly: "Look at the way the light hits the trees." [AUDIO CUES] Ambient forest breeze, soft footsteps on twigs, warm cinematic background strings.`