export interface ParsedShot { n: number prompt: string role: 'initial' | 'extension' } function parseMarkedBlocks(text: string, marker: RegExp): ParsedShot[] { const src = String(text || '').replace(/\r\n/g, '\n') const markers: { n: number; start: number; end: number }[] = [] for (const match of src.matchAll(marker)) { markers.push({ n: Number(match[1]), start: match.index || 0, end: (match.index || 0) + match[0].length }) } const blocks: { n: number; prompt: string }[] = [] if (!markers.length) { const prompt = src.trim() return prompt ? [{ n: 1, prompt, role: 'initial' }] : [] } const preamble = src.slice(0, markers[0].start).trim() if (preamble) blocks.push({ n: 1, prompt: preamble }) for (let i = 0; i < markers.length; i++) { const from = markers[i].end const to = i + 1 < markers.length ? markers[i + 1].start : src.length const prompt = src.slice(from, to).trim() if (prompt) blocks.push({ n: markers[i].n, prompt }) } const byN = new Map() for (const block of blocks) { const prev = byN.get(block.n) byN.set(block.n, prev ? `${prev}\n${block.prompt}` : block.prompt) } return [...byN.entries()] .sort((a, b) => a[0] - b[0]) .map(([n, prompt], index) => ({ n, prompt, role: index === 0 ? 'initial' : 'extension' })) } export function parseShotScript(text: string): ParsedShot[] { return parseMarkedBlocks(text, /^[ \t]*shot\s+(\d+)\b/gim) } export function parseImageBatchScript(text: string): ParsedShot[] { return parseMarkedBlocks(text, /^[ \t]*(?:shot|image|prompt)\s+(\d+)\b/gim) }