- Enhanced cursor behavior for new tools: semantic select, mask lasso, and mask rectangle. - Updated mask edit state to include mask asset ID and kind. - Implemented inpaint region commands for adding, applying, and removing inpaint regions. - Introduced new operations for lasso and semantic selection tools. - Created UI components for candidate review and inpaint region management. - Added tests for inpaint region commands to ensure functionality. - Updated various components to support new inpaint features and improve user experience.
44 lines
2.6 KiB
TypeScript
44 lines
2.6 KiB
TypeScript
export async function fetchGenerationOptions(): Promise<unknown> {
|
|
const response = await fetch("/api/comfy/models");
|
|
if (!response.ok) throw new Error("Unable to load ComfyUI models");
|
|
return response.json() as Promise<unknown>;
|
|
}
|
|
|
|
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");
|
|
}
|