Spaces:
Running
Running
| // 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 }) | |
| } | |