/** * Example custom image backend adapter (feature 2026-08-16). * * Any OpenAI-compatible-ish or arbitrary REST API can be plugged in by writing * a file like this and pointing a backend at it: * * dsh-multimodal: * image: * backends: * my-api: * kind: custom * adapterFile: D:/path/to/example-custom.mjs * baseURL: https://api.example.com/v1 * apiKeyEnv: MY_API_KEY * model: my-image-model * defaultSize: 1024*1024 * activeBackend: my-api * * The adapter receives everything it needs (prompt, size, key, baseURL, model, * signal, fetch, log) and must return image URLs or base64 payloads. * Loaded with full process privileges — only point it at files you trust. */ /** * @type {import('../../src/image-gen.ts').CustomImageBackendAdapter} */ export default { async generate({ prompt, size, n, negative_prompt, reference_image, apiKey, baseURL, model, signal, fetch, log }) { log(`calling ${model} size=${size} n=${n}`) // Arbitrary protocol: build your own request here. const body = { model, prompt, size, n: Math.max(1, n), ...(negative_prompt !== undefined ? { negative_prompt } : {}), ...(reference_image !== undefined ? { reference_image } : {}), } const response = await fetch(`${baseURL.replace(/\/$/, '')}/images/generate`, { method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}`, }, body: JSON.stringify(body), signal, }) if (!response.ok) { const text = await response.text().catch(() => '') throw new Error(`my-api HTTP ${response.status}: ${text.slice(0, 200)}`) } const data = await response.json() // Adapt the response shape to the contract: urls[] and/or b64s[]. const urls = Array.isArray(data.images) ? data.images.map((it) => it.url).filter(Boolean) : [] const b64s = Array.isArray(data.images) ? data.images.map((it) => it.b64_json).filter(Boolean) : [] log(`got ${urls.length} urls, ${b64s.length} base64`) return { urls, b64s } }, }