// Image facade — mirrors tts.js. Picks the active portrait engine (local Z-Image on your // GPU, or cloud FLUX; in-browser SD-Turbo / Janus get added here later) and exposes one // generatePortrait(). The persona panel + the Settings image bar import only from here. import { engineLocal as zimagelocal, engineKleinZeroGpu as klein, engineCloud as flux, engineCloudDev as fluxdev } from '/web/imagenServer.js' import { engine as bonsai } from '/web/imagenBonsai.js' const ENGINES = [zimagelocal, klein, bonsai, flux, fluxdev] // Default: local Z-Image on localhost (your GPU), Klein ZeroGPU in prod. Persisted across // refreshes; a saved choice wins if it's still available. const KEY = 'tinyarmy.imageEngine' let activeId = (() => { let saved = '' try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ } const e = ENGINES.find((x) => x.id === saved) return e && e.available() ? saved : 'klein-zerogpu' })() const eng = () => ENGINES.find((e) => e.id === activeId) || ENGINES.find((e) => e.available()) || ENGINES[0] export const listImageEngines = () => ENGINES.map((e) => ({ id: e.id, label: e.label, available: e.available(), note: e.note || '' })) export const getImageEngineId = () => activeId const _listeners = new Set() export function onImageEngineChange(fn) { _listeners.add(fn); return () => _listeners.delete(fn) } export function setImageEngine(id) { if (!ENGINES.some((e) => e.id === id) || id === activeId) return activeId = id try { localStorage.setItem(KEY, id) } catch { /* ignore */ } for (const fn of _listeners) { try { fn(id) } catch { /* ignore */ } } } export const imageNeedsDownload = () => !!eng().needsDownload export const imageBackendLabel = () => eng().backendLabel() export const imageNetworked = () => !!eng().networked export async function ensureImage(onProgress) { return eng().ensure(onProgress) } // Generate a portrait → PNG Blob. `prompt` is the appearance description; `seed` keeps it // reproducible where the engine supports it. export async function generatePortrait(prompt, { seed } = {}) { return eng().generate(prompt, { seed }) }