Files
aigen/utils/parseRecommend.ts
TowstyandCursor 40cd17f35c Add MiniMax and PinkCherry LTX as pickable video engines, with still or text start.
Shot 1 can run text-to-video; later shots still extend from the last frame. Recommend output is also normalized into shot-script cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 19:38:53 -05:00

63 lines
2.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { parseShotScript } from './parseShots'
export function parseEditPasses(text: string): string[] | null {
const src = String(text || '').replace(/\r\n/g, '\n')
const marker = /^[ \t]*---pass\s+(\d+)---[ \t]*$/gim
const markers = [...src.matchAll(marker)]
if (!markers.length) return null
const parts: string[] = []
const preamble = src.slice(0, markers[0].index || 0).trim()
for (let i = 0; i < markers.length; i++) {
const from = (markers[i].index || 0) + markers[i][0].length
const to = i + 1 < markers.length ? (markers[i + 1].index || src.length) : src.length
const body = src.slice(from, to).trim()
if (body) parts.push(body)
}
if (!parts.length) return null
if (preamble && preamble.length > 40) {
parts[0] = `${preamble}\n\n${parts[0]}`
}
return parts
}
export function looksLikeShotScript(text: string) {
return /^[ \t]*shot\s+[2-9]\d*\b/im.test(String(text || ''))
}
function stripFences(text: string) {
return String(text || '')
.replace(/^\s*```(?:[\w-]+)?\s*\n?/, '')
.replace(/\n?```\s*$/, '')
.trim()
}
function splitInlineShotMarkers(text: string) {
return String(text || '')
.replace(/\r\n/g, '\n')
.replace(/(^|[^A-Za-z])shot\s+(\d+)\s*[:.)\-]?\s*/gi, '$1\n\nshot $2\n')
.replace(/\n{3,}/g, '\n\n')
.trim()
}
function formatShotBody(body: string) {
let text = String(body || '').trim()
text = text.replace(/^\s*[:.\-–)]\s*/, '')
text = text.replace(/\s*\[SHOT CONFIGURATION\]\s*/gi, '\n\n[SHOT CONFIGURATION]\n')
text = text.replace(/\s*\[SUBJECT DIRECTION(?:\s*&\s*ACTION)?\]\s*/gi, '\n\n[SUBJECT DIRECTION & ACTION]\n')
text = text.replace(/\s*\[AUDIO CUES\]\s*/gi, '\n\n[AUDIO CUES]\n')
text = text.replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n').trim()
return text
}
export function normalizeShotScript(text: string) {
const src = splitInlineShotMarkers(stripFences(text))
const shots = parseShotScript(src)
if (!shots.length) return src
if (shots.length === 1 && !/^[ \t]*shot\s+\d+\b/im.test(src)) {
return formatShotBody(shots[0].prompt)
}
return shots
.map(shot => `shot ${shot.n}\n${formatShotBody(shot.prompt)}`.trim())
.join('\n\n')
}