// Клиент ComfyUI API. import { COMFY } from './config.ts'; export class ComfyError extends Error {} export async function comfyJson(pathname: string, body?: unknown): Promise { let r: Response; try { r = await fetch(new URL(pathname, COMFY), body === undefined ? undefined : { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); } catch { throw new ComfyError('ComfyUI недоступен по адресу ' + COMFY.origin); } const text = await r.text(); let json: { error?: { message?: string } | string } | undefined; try { json = JSON.parse(text); } catch { /* не JSON */ } if (!r.ok) { const e = json?.error; throw new ComfyError(typeof e === 'string' ? e : e?.message ?? JSON.stringify(json ?? text)); } return json as T; } /** Ставит граф в очередь, возвращает prompt_id. */ export async function queuePrompt(graph: object): Promise { const r = await comfyJson<{ prompt_id: string }>('/prompt', { prompt: graph }); return r.prompt_id; } /** Загрузка картинки в ComfyUI/input/. При совпадении имени ComfyUI сам даёт новое имя. */ export async function uploadImage(name: string, data: Blob, subfolder: string) { const form = new FormData(); form.append('image', data, name); form.append('subfolder', subfolder); let r: Response; try { r = await fetch(new URL('/upload/image', COMFY), { method: 'POST', body: form }); } catch { throw new ComfyError('ComfyUI недоступен'); } if (!r.ok) throw new ComfyError('ComfyUI не принял файл: ' + await r.text()); const j = await r.json() as { name: string; subfolder?: string; type?: string }; return { filename: j.name, subfolder: j.subfolder ?? '', type: j.type ?? 'input' }; } /** GET /view — файл из папок ComfyUI как есть (Response для потоковой отдачи). */ export async function view(params: URLSearchParams): Promise { try { return await fetch(new URL('/view?' + params, COMFY)); } catch { throw new ComfyError('ComfyUI недоступен'); } }