UNPKG

@just-every/ensemble

Version:

LLM provider abstraction layer with unified streaming interface

132 lines 5.83 kB
import { BaseModelProvider } from './base_provider.js'; import { costTracker } from '../utils/cost_tracker.js'; import { log_llm_error, log_llm_request, log_llm_response } from '../utils/llm_logger.js'; const IDEOGRAM_BASE = 'https://api.ideogram.ai'; function mapResolution(size) { if (!size) return undefined; const s = String(size); const allowed = new Set([ '1792x1024', '1536x1024', '1365x1024', '1280x720', '1024x1024', '1024x1536', '1216x832', '1088x1088', '1216x1216', '1344x1344', '1536x1536', '1792x1792', '1792x1024', '1792x1792', '1024x1792' ]); if (allowed.has(s)) return s; if (s === 'square') return '1024x1024'; if (s === 'landscape') return '1792x1024'; if (s === 'portrait') return '1024x1792'; return undefined; } export class IdeogramProvider extends BaseModelProvider { constructor() { super('ideogram'); } async *createResponseStream() { throw new Error('Ideogram provider does not support text streaming'); } async createImage(prompt, model, agent, opts) { const apiKey = process.env.IDEOGRAM_API_KEY; if (!apiKey) throw new Error('Ideogram provider: IDEOGRAM_API_KEY is not set'); const requestId = log_llm_request(agent.agent_id || 'default', 'ideogram', model, { prompt, opts }, new Date()); try { const resolution = mapResolution(opts?.size); const n = Math.max(1, Math.min(4, opts?.n || 1)); const hasSource = !!opts?.source_images; if (hasSource) { const src = Array.isArray(opts?.source_images) ? opts.source_images[0] : opts.source_images; let imgBlob = null; let maskBlob = null; try { const toBlob = async (val, fallbackName) => { if (!val) return null; const s = typeof val === 'string' ? val : val?.data || val; if (typeof s !== 'string') return null; if (s.startsWith('data:')) { const m = /^data:([^;]+);base64,(.+)$/i.exec(s); if (!m) return null; const buf = Buffer.from(m[2], 'base64'); return new Blob([buf], { type: m[1] || 'image/png' }); } if (/^https?:\/\//i.test(s)) { const r = await fetch(s); const ab = await r.arrayBuffer(); const ct = r.headers.get('content-type') || 'image/png'; return new Blob([ab], { type: ct }); } return null; }; imgBlob = await toBlob(src, 'image.png'); if (opts?.mask) maskBlob = await toBlob(opts.mask, 'mask.png'); } catch (e) { throw new Error(`Ideogram: failed to load source image/mask: ${e}`); } if (!imgBlob) throw new Error('Ideogram edit: no usable source image'); const form = new FormData(); form.append('prompt', prompt); form.append('rendering_speed', 'DEFAULT'); form.append('image', imgBlob, 'image.png'); if (maskBlob) form.append('mask', maskBlob, 'mask.png'); const res = await fetch(`${IDEOGRAM_BASE}/v1/ideogram-v3/edit`, { method: 'POST', headers: { 'Api-Key': apiKey, }, body: form, }); if (!res.ok) throw new Error(`Ideogram edit failed: ${res.status} ${await res.text()}`); const data = await res.json(); const urls = (data?.data || []).map((d) => d?.url).filter(Boolean); if (!urls.length) throw new Error('Ideogram edit: no image URLs returned'); costTracker.addUsage({ model, image_count: urls.length, request_id: opts?.request_id, metadata: { source: 'ideogram', mode: 'edit' } }); return urls; } const body = { prompt, model: 'V_3', num_images: n, }; if (resolution) body.resolution = resolution; const res = await fetch(`${IDEOGRAM_BASE}/v1/ideogram-v3/generate`, { method: 'POST', headers: { 'Api-Key': apiKey, 'Content-Type': 'application/json', }, body: JSON.stringify(body), }); if (!res.ok) throw new Error(`Ideogram create failed: ${res.status} ${await res.text()}`); const data = await res.json(); const urls = (data?.data || []).map((d) => d?.url).filter(Boolean); if (urls.length === 0) throw new Error('Ideogram: no image URLs returned'); costTracker.addUsage({ model, image_count: urls.length, request_id: opts?.request_id, metadata: { source: 'ideogram' } }); return urls; } catch (err) { log_llm_error(requestId, err); throw err; } finally { log_llm_response(requestId, { ok: true }); } } } export const ideogramProvider = new IdeogramProvider(); //# sourceMappingURL=ideogram.js.map