export async function fetchGenerationOptions(): Promise { const response = await fetch("/api/comfy/models"); if (!response.ok) throw new Error("Unable to load ComfyUI models"); return response.json() as Promise; } export type GenerationResult = { source: string; mimeType: string; seed: number }; export async function requestSemanticSelection(body: { inputImage: string; x: number; y: number; model?: string }, signal?: AbortSignal): Promise<{ source: string; mimeType: string }> { const response = await fetch("/api/comfy/segment", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal }); if (!response.ok) throw new Error(await response.text()); return response.json() as Promise<{ source: string; mimeType: string }>; } export async function requestGeneration(body: unknown, signal?: AbortSignal, onProgress?: (progress: number, detail: string) => void): Promise<{ results: GenerationResult[] }> { const response = await fetch("/api/comfy/generate", { method: "POST", headers: { "content-type": "application/json", accept: "application/x-ndjson" }, body: JSON.stringify(body), signal }); if (!response.ok) throw new Error(await response.text()); const contentType = response.headers.get("content-type") ?? ""; if (contentType.includes("application/x-ndjson") && response.body) { const reader = response.body.getReader(); const decoder = new TextDecoder(); let pending = ""; while (true) { const { value, done } = await reader.read(); pending += decoder.decode(value, { stream: !done }); const lines = pending.split("\n"); pending = lines.pop() ?? ""; for (const line of lines) { if (!line.trim()) continue; const event = JSON.parse(line) as { type: "progress"; progress: number; detail: string } | { type: "result"; results: GenerationResult[] } | { type: "error"; message: string }; if (event.type === "progress") onProgress?.(event.progress, event.detail); if (event.type === "error") throw new Error(event.message); if (event.type === "result") return { results: event.results }; } if (done) break; } throw new Error("Generation stream ended without results"); } const payload = await response.json() as { results?: GenerationResult[]; source?: string; mimeType?: string }; if (payload.results?.length) return { results: payload.results }; if (payload.source) return { results: [{ source: payload.source, mimeType: payload.mimeType ?? "image/png", seed: 0 }] }; throw new Error("Generation returned no results"); }