climage 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +6 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -285,8 +285,7 @@ async function generateXaiVideo(req, apiKey) {
|
|
|
285
285
|
prompt: req.prompt,
|
|
286
286
|
model,
|
|
287
287
|
...req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {},
|
|
288
|
-
|
|
289
|
-
...imageUrl ? { image_url: imageUrl } : {},
|
|
288
|
+
...imageUrl ? { image: { url: imageUrl } } : {},
|
|
290
289
|
// Add duration (xAI supports 1-15 seconds)
|
|
291
290
|
...req.duration !== void 0 ? { duration: req.duration } : {}
|
|
292
291
|
};
|
|
@@ -294,7 +293,7 @@ async function generateXaiVideo(req, apiKey) {
|
|
|
294
293
|
"Request body:",
|
|
295
294
|
JSON.stringify({
|
|
296
295
|
...createBody,
|
|
297
|
-
|
|
296
|
+
image: createBody.image ? { url: `...(${String(createBody.image.url).length} chars)` } : void 0
|
|
298
297
|
})
|
|
299
298
|
);
|
|
300
299
|
log("Calling xAI videos/generations...");
|
|
@@ -849,7 +848,10 @@ async function generateWithGemini(ai, model, req) {
|
|
|
849
848
|
model,
|
|
850
849
|
contents: buildContents(),
|
|
851
850
|
config: {
|
|
852
|
-
responseModalities: ["IMAGE"]
|
|
851
|
+
responseModalities: ["IMAGE"],
|
|
852
|
+
// Gemini native image generation (Nano Banana) supports aspect ratio via imageConfig.
|
|
853
|
+
// Note: when editing from an input image, the model may still bias toward the input image's aspect.
|
|
854
|
+
...req.aspectRatio ? { imageConfig: { aspectRatio: req.aspectRatio } } : {}
|
|
853
855
|
}
|
|
854
856
|
});
|
|
855
857
|
log3(`API call ${i + 1} took ${Date.now() - callStart}ms`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process';\n\nimport { generateMedia, listProviders } from './index.js';\nimport { toJsonResult } from './core/output.js';\nimport type { GenerateOptions, ProviderId } from './core/types.js';\n\nfunction usage(code = 0) {\n const providers = listProviders()\n .map((p) => `${p.id}`)\n .join(', ');\n\n // eslint-disable-next-line no-console\n console.log(`climage\n\nUsage:\n climage \"prompt\"\n\nOptions:\n --provider <auto|${providers}> Provider (default: auto)\n --model <id> Model id (provider-specific)\n --n <1..10> Number of outputs (default: 1)\n --type <image|video> Output type (default: image)\n --video Shortcut for: --type video\n --format <png|jpg|webp|mp4|webm|gif>\n Output format (default: png for image, mp4 for video)\n --out <path> Output file path (only when n=1)\n --outDir <dir> Output directory (default: .)\n --name <text> Base name (slugified); default: prompt\n --aspect-ratio <w:h> Aspect ratio (provider-specific)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\n\nInput Images:\n --input <path> Input image for editing or reference (repeatable)\n --start-frame <path> First frame image (for video generation)\n --end-frame <path> Last frame image (for video interpolation)\n --duration <seconds> Video duration in seconds (provider-specific)\n\nEnv:\n GEMINI_API_KEY (or GOOGLE_API_KEY)\n XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)\n FAL_KEY (or FAL_API_KEY)\n OPENAI_API_KEY\n\nExamples:\n npx climage \"make image of kitten\"\n npx climage \"A cat in a tree\" --provider xai --n 4\n npx climage \"a cinematic shot of a corgi running\" --provider fal --type video\n npx climage \"make the cat orange\" --provider xai --input photo.jpg\n npx climage \"the cat walks away\" --video --provider google --start-frame cat.png\n npx climage \"morphing transition\" --video --provider fal --start-frame a.png --end-frame b.png\n`);\n process.exit(code);\n}\n\nfunction parseArgs(argv: string[]): { prompt: string; opts: GenerateOptions; json: boolean } {\n const args = [...argv];\n const opts: GenerateOptions = {};\n let json = false;\n const promptParts: string[] = [];\n const inputImages: string[] = [];\n\n // Options that take a value\n const optionsWithValue = new Set([\n '--provider',\n '--model',\n '--n',\n '--type',\n '--format',\n '--out',\n '--outDir',\n '--name',\n '--aspect-ratio',\n '--input',\n '--start-frame',\n '--end-frame',\n '--duration',\n ]);\n\n let i = 0;\n while (i < args.length) {\n const a = args[i];\n if (!a) {\n i++;\n continue;\n }\n\n // Help\n if (a === '-h' || a === '--help') usage(0);\n\n // Boolean flags\n if (a === '--json') {\n json = true;\n i++;\n continue;\n }\n if (a === '--video') {\n opts.kind = 'video';\n i++;\n continue;\n }\n if (a === '--verbose') {\n opts.verbose = true;\n i++;\n continue;\n }\n\n // Options with values\n if (optionsWithValue.has(a)) {\n const v = args[i + 1];\n if (!v || v.startsWith('-')) throw new Error(`Missing value for ${a}`);\n switch (a) {\n case '--provider':\n opts.provider = v as ProviderId;\n break;\n case '--model':\n opts.model = v;\n break;\n case '--n':\n opts.n = Number(v);\n break;\n case '--type':\n opts.kind = v as any;\n break;\n case '--format':\n opts.format = v as any;\n break;\n case '--out':\n opts.out = v;\n break;\n case '--outDir':\n opts.outDir = v;\n break;\n case '--name':\n opts.name = v;\n break;\n case '--aspect-ratio':\n opts.aspectRatio = v;\n break;\n case '--input':\n inputImages.push(v);\n break;\n case '--start-frame':\n opts.startFrame = v;\n break;\n case '--end-frame':\n opts.endFrame = v;\n break;\n case '--duration':\n opts.duration = Number(v);\n break;\n }\n i += 2;\n continue;\n }\n\n // Unknown option\n if (a.startsWith('-')) {\n throw new Error(`Unknown option: ${a}`);\n }\n\n // Non-option = prompt part\n promptParts.push(a);\n i++;\n }\n\n // Add collected input images to opts\n if (inputImages.length) {\n opts.inputImages = inputImages;\n }\n\n const prompt = promptParts.join(' ').trim();\n if (!prompt) throw new Error('Missing prompt');\n\n return { prompt, opts, json };\n}\n\nasync function main() {\n try {\n const { prompt, opts, json } = parseArgs(process.argv.slice(2));\n const items = await generateMedia(prompt, opts);\n\n if (json) {\n process.stdout.write(JSON.stringify(toJsonResult(items), null, 2) + '\\n');\n return;\n }\n\n for (const item of items) {\n process.stdout.write(item.filePath + '\\n');\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`climage: ${msg}\\n`);\n process.stderr.write(`Run: climage --help\\n`);\n process.exit(1);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain();\n","import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedMedia,\n GeneratedMediaPartial,\n MediaKind,\n OutputFormat,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport {\n makeOutputPath,\n resolveImageInput,\n resolveImageInputs,\n resolveOutDir,\n writeMediaFile,\n} from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[router]', ...args);\n}\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction defaultFormatForKind(kind: MediaKind): OutputFormat {\n return kind === 'video' ? 'mp4' : 'png';\n}\n\nasync function normalizeOptions(\n prompt: string,\n opts: GenerateOptions,\n verbose: boolean\n): Promise<GenerateRequest> {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const kind = opts.kind ?? 'image';\n const format = opts.format ?? defaultFormatForKind(kind);\n\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n // Resolve input images (convert local paths to data URIs)\n let inputImages: string[] | undefined;\n if (opts.inputImages?.length) {\n log(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);\n inputImages = await resolveImageInputs(opts.inputImages);\n log(verbose, `Resolved input images`);\n }\n\n // Resolve start/end frames for video\n let startFrame: string | undefined;\n let endFrame: string | undefined;\n\n if (opts.startFrame) {\n log(verbose, `Resolving start frame: ${opts.startFrame}`);\n startFrame = await resolveImageInput(opts.startFrame);\n }\n\n if (opts.endFrame) {\n log(verbose, `Resolving end frame: ${opts.endFrame}`);\n endFrame = await resolveImageInput(opts.endFrame);\n }\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n kind,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n // New fields\n inputImages,\n startFrame,\n endFrame,\n duration: opts.duration,\n };\n}\n\n/**\n * Validate request parameters against provider capabilities.\n */\nfunction validateRequestForProvider(req: GenerateRequest, provider: Provider): void {\n const caps = provider.capabilities;\n\n // Validate input images count\n const inputCount = req.inputImages?.length ?? 0;\n if (inputCount > caps.maxInputImages) {\n throw new Error(\n `Provider ${provider.id} supports max ${caps.maxInputImages} input image(s), but ${inputCount} provided`\n );\n }\n\n // Validate aspect ratio\n if (req.aspectRatio) {\n const normalized = req.aspectRatio.trim().replace(/\\s+/g, '');\n\n // Always enforce a basic w:h shape to avoid passing junk downstream.\n const looksLikeRatio = /^\\d+:\\d+$/.test(normalized);\n if (!looksLikeRatio) {\n throw new Error(`Invalid aspect ratio: \"${req.aspectRatio}\" (expected format: w:h)`);\n }\n\n // If provider has an allowlist and does NOT support arbitrary custom ratios, validate against it.\n if (\n caps.supportsCustomAspectRatio !== true &&\n Array.isArray(caps.supportedAspectRatios) &&\n caps.supportedAspectRatios.length\n ) {\n const ok = caps.supportedAspectRatios.includes(normalized);\n if (!ok) {\n throw new Error(\n `Provider ${provider.id} does not support aspect ratio \"${normalized}\". ` +\n `Supported: ${caps.supportedAspectRatios.join(', ')}`\n );\n }\n }\n }\n\n // Validate video interpolation (start + end frame)\n if (req.endFrame && !caps.supportsVideoInterpolation) {\n throw new Error(\n `Provider ${provider.id} does not support video interpolation (end frame). ` +\n `Only startFrame is supported for image-to-video.`\n );\n }\n\n // Validate duration range\n if (req.duration !== undefined && req.kind === 'video' && caps.videoDurationRange) {\n const [min, max] = caps.videoDurationRange;\n if (req.duration < min || req.duration > max) {\n throw new Error(\n `Provider ${provider.id} supports video duration ${min}-${max}s, but ${req.duration}s requested`\n );\n }\n }\n\n // Validate image editing support\n if (req.kind === 'image' && inputCount > 0 && !caps.supportsImageEditing) {\n throw new Error(`Provider ${provider.id} does not support image editing with input images`);\n }\n}\n\nexport async function generateMedia(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n const { env } = loadEnv(process.cwd());\n const verbose = Boolean(opts.verbose);\n\n // Normalize and resolve options (including reading input image files)\n const req = await normalizeOptions(prompt, opts, verbose);\n\n // Build a summary object for logging (truncate large data URIs)\n const reqSummary = {\n ...req,\n prompt: req.prompt.slice(0, 50) + '...',\n inputImages: req.inputImages?.map((img) =>\n img.startsWith('data:') ? `data:...${img.length} chars` : img\n ),\n startFrame: req.startFrame?.startsWith('data:')\n ? `data:...${req.startFrame.length} chars`\n : req.startFrame,\n endFrame: req.endFrame?.startsWith('data:')\n ? `data:...${req.endFrame.length} chars`\n : req.endFrame,\n };\n log(verbose, 'Request:', JSON.stringify(reqSummary));\n\n const provider = pickProvider(req.provider, env);\n log(verbose, 'Selected provider:', provider.id, '| supports:', provider.supports);\n\n if (!provider.supports.includes(req.kind)) {\n throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);\n }\n\n // Validate request against provider capabilities\n validateRequestForProvider(req, provider);\n\n log(verbose, 'Calling provider.generate()...');\n const startTime = Date.now();\n\n const partials = await provider.generate(req, env);\n\n log(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);\n\n const items: GeneratedMedia[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedMediaPartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i, p.mimeType);\n log(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);\n await writeMediaFile(filePath, p.bytes);\n items.push({ ...p, filePath });\n }\n\n log(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);\n return items;\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'image' });\n}\n\nexport async function generateVideo(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'video' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GenerateRequest, GeneratedMedia } from './types.js';\n\n/** Map file extensions to MIME types for images. */\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.avif': 'image/avif',\n '.heif': 'image/heif',\n '.heic': 'image/heic',\n};\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n case 'mp4':\n return 'mp4';\n case 'webm':\n return 'webm';\n case 'gif':\n return 'gif';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nfunction extensionFromMimeType(mimeType: string | undefined): string | undefined {\n if (!mimeType) return undefined;\n\n const t = mimeType.toLowerCase().split(';')[0]?.trim();\n if (!t) return undefined;\n\n // Images\n if (t === 'image/png') return 'png';\n if (t === 'image/jpeg') return 'jpg';\n if (t === 'image/webp') return 'webp';\n if (t === 'image/gif') return 'gif';\n if (t === 'image/avif') return 'avif';\n\n // Videos\n if (t === 'video/mp4') return 'mp4';\n if (t === 'video/webm') return 'webm';\n\n return undefined;\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number, mimeType?: string): string {\n // If user explicitly requested an output path, respect it verbatim.\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n // Some providers return a different MIME type than requested (e.g. JPEG bytes even if\n // --format png was requested). Prefer the actual MIME type for file extension to avoid\n // misleading file names.\n const ext = extensionFromMimeType(mimeType) ?? extensionForFormat(req.format);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeMediaFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(items: GeneratedMedia[]) {\n const images = items\n .filter((i) => i.kind === 'image')\n .map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n }));\n\n const videos = items\n .filter((i) => i.kind === 'video')\n .map((vid) => ({\n provider: vid.provider,\n model: vid.model,\n index: vid.index,\n filePath: vid.filePath,\n url: vid.url,\n bytes: vid.bytes.byteLength,\n mimeType: vid.mimeType,\n }));\n\n return {\n ...(images.length ? { images } : {}),\n ...(videos.length ? { videos } : {}),\n };\n}\n\n/**\n * Resolve an image input path or URL to a usable format.\n * - URLs (http/https) are returned as-is\n * - Data URIs are returned as-is\n * - Local file paths are read and converted to base64 data URIs\n *\n * @param pathOrUrl - A file path or URL to an image\n * @returns The resolved image as a URL or data URI\n */\nexport async function resolveImageInput(pathOrUrl: string): Promise<string> {\n // Already a URL (http/https)\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n // Already a data URI\n if (pathOrUrl.startsWith('data:')) {\n return pathOrUrl;\n }\n\n // Local file path - resolve and read\n const resolvedPath = path.isAbsolute(pathOrUrl)\n ? pathOrUrl\n : path.resolve(process.cwd(), pathOrUrl);\n\n const ext = path.extname(resolvedPath).toLowerCase();\n const mimeType = IMAGE_MIME_TYPES[ext];\n\n if (!mimeType) {\n throw new Error(\n `Unsupported image format: ${ext}. Supported: ${Object.keys(IMAGE_MIME_TYPES).join(', ')}`\n );\n }\n\n const fileBuffer = await fs.readFile(resolvedPath);\n const base64 = fileBuffer.toString('base64');\n\n return `data:${mimeType};base64,${base64}`;\n}\n\n/**\n * Resolve multiple image inputs in parallel.\n *\n * @param pathsOrUrls - Array of file paths or URLs\n * @returns Array of resolved images as URLs or data URIs\n */\nexport async function resolveImageInputs(pathsOrUrls: string[]): Promise<string[]> {\n return Promise.all(pathsOrUrls.map(resolveImageInput));\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\ntype XaiVideoGenerationResponse = {\n request_id?: string;\n};\n\ntype XaiVideoResultResponse = {\n // When pending\n status?: 'pending' | string;\n // When complete - video info is at top level, not nested in response\n video?: {\n duration?: number;\n respect_moderation?: boolean;\n url?: string | null;\n };\n model?: string;\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[xai]', ...args);\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Generate images using xAI's /v1/images/generations endpoint (text-to-image).\n */\nasync function generateXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n log('Starting image generation, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling xAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Edit images using xAI's /v1/images/edits endpoint (image-to-image).\n * Uses JSON format with image_url (data URI or URL).\n */\nasync function editXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n const inputImage = req.inputImages?.[0];\n if (!inputImage) throw new Error('No input image provided for editing');\n\n if ((req.inputImages?.length ?? 0) > 1) {\n throw new Error(\n 'xAI image editing supports only 1 input image (image_url). ' +\n 'Provide exactly one --input for xAI edits.'\n );\n }\n\n log('Starting image editing, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n image: { url: inputImage }, // Object with url field containing data URI or URL\n response_format: 'url',\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n };\n log('Request body:', JSON.stringify({ ...body, image: { url: '...(data uri)...' } }));\n\n log('Calling xAI images/edits...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI edits failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Process xAI image response and download images.\n */\nasync function processXaiImageResponse(json: XaiImagesResponse, model: string) {\n const results = [] as Array<{\n kind: 'image';\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n}\n\nasync function generateXaiVideo(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-video';\n\n // Get image URL from startFrame or inputImages[0]\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if ((req.inputImages?.length ?? 0) > 1 && !req.startFrame) {\n throw new Error(\n 'xAI video generation supports only 1 input image (image_url). ' +\n 'Provide exactly one --input or use --start-frame.'\n );\n }\n log(\n 'Starting video generation, model:',\n model,\n 'hasImageUrl:',\n !!imageUrl,\n 'duration:',\n req.duration\n );\n\n // xAI is async: create request_id, then poll /v1/videos/{request_id}\n // Note: xAI video API uses image_url as a string (data URI or URL), not an object\n const createBody: Record<string, unknown> = {\n prompt: req.prompt,\n model,\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Add image_url for image-to-video (data URI or URL string)\n ...(imageUrl ? { image_url: imageUrl } : {}),\n // Add duration (xAI supports 1-15 seconds)\n ...(req.duration !== undefined ? { duration: req.duration } : {}),\n };\n log(\n 'Request body:',\n JSON.stringify({\n ...createBody,\n image_url: createBody.image_url\n ? `...(${String(createBody.image_url).length} chars)`\n : undefined,\n })\n );\n\n log('Calling xAI videos/generations...');\n const startTime = Date.now();\n\n const createRes = await fetch(`${XAI_API_BASE}/videos/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(createBody),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${createRes.status}`);\n\n if (!createRes.ok) {\n const txt = await createRes.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI video generations failed (${createRes.status}): ${txt.slice(0, 500)}`);\n }\n\n const createJson = (await createRes.json()) as XaiVideoGenerationResponse;\n const requestId = createJson.request_id;\n log('Got request_id:', requestId);\n if (!requestId) throw new Error('xAI video generation returned no request_id');\n\n // Poll (best-effort). Video generation can take a while.\n const maxAttempts = 120; // ~6 minutes at 3s interval\n const intervalMs = 3000;\n\n let result: XaiVideoResultResponse | undefined;\n log(`Starting poll loop (max ${maxAttempts} attempts, ${intervalMs}ms interval)...`);\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const res = await fetch(`${XAI_API_BASE}/videos/${encodeURIComponent(requestId)}`, {\n method: 'GET',\n headers: {\n authorization: `Bearer ${apiKey}`,\n },\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log(`Poll attempt ${attempt + 1} failed:`, txt.slice(0, 500));\n throw new Error(`xAI video poll failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiVideoResultResponse;\n result = json;\n\n log(\n `Poll attempt ${attempt + 1}/${maxAttempts}: status=${json.status}, raw:`,\n JSON.stringify(json).slice(0, 300)\n );\n\n // xAI returns video object at top level (not nested in response) when complete\n if (json.video?.url) {\n log('Video generation complete!');\n break;\n }\n\n if (json.status === 'failed' || json.status === 'error') {\n log('Video generation failed:', JSON.stringify(json));\n throw new Error(`xAI video generation failed: ${JSON.stringify(json)}`);\n }\n\n await sleep(intervalMs);\n }\n\n if (!result?.video?.url) {\n log('Timed out. Last result:', JSON.stringify(result));\n throw new Error(`xAI video generation timed out (request_id=${requestId})`);\n }\n\n const url = result.video.url;\n log('Video URL:', url);\n\n // Check moderation status\n if (result.video?.respect_moderation === false) {\n throw new Error('xAI video generation was blocked by moderation');\n }\n\n const { bytes, mimeType } = await downloadBytes(url);\n\n log(`Successfully generated video, ${bytes.byteLength} bytes`);\n return [\n {\n kind: 'video' as const,\n provider: 'xai' as const,\n model: result.model ?? model,\n index: 0,\n url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n },\n ];\n}\n\nconst xaiCapabilities: ProviderCapabilities = {\n // xAI docs show a single image_url for edits and a single image_url for image-to-video.\n maxInputImages: 1,\n // xAI aspect_ratio examples show \"4:3\"; docs don't publish a strict allowlist.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: false, // xAI does not support end frame\n videoDurationRange: [1, 15], // 1-15 seconds\n supportsImageEditing: true,\n};\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI',\n supports: ['image', 'video'],\n capabilities: xaiCapabilities,\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n if (req.kind === 'video') return generateXaiVideo(req, apiKey);\n\n // Use edit endpoint if input images provided, otherwise generation\n const hasInputImages = req.inputImages && req.inputImages.length > 0;\n if (hasInputImages) {\n log('Input images detected, using edit endpoint');\n return editXaiImages(req, apiKey);\n }\n return generateXaiImages(req, apiKey);\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalMedia = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalMedia[];\n image?: FalMedia;\n videos?: FalMedia[];\n video?: FalMedia;\n};\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[fal]', ...args);\n}\n\nasync function downloadBytes(\n url: string,\n verbose: boolean\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log(verbose, 'Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(verbose, `Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nfunction pickMany(result: FalResult, kind: 'image' | 'video'): FalMedia[] {\n if (kind === 'image') {\n if (Array.isArray(result.images) && result.images.length) return result.images;\n if (result.image?.url) return [result.image];\n return [];\n }\n\n if (Array.isArray(result.videos) && result.videos.length) return result.videos;\n if (result.video?.url) return [result.video];\n return [];\n}\n\n// Default models per kind and input type\nconst DEFAULT_IMAGE_MODEL = 'fal-ai/flux/dev';\nconst DEFAULT_IMAGE_TO_IMAGE_MODEL = 'fal-ai/flux/dev/image-to-image';\nconst DEFAULT_VIDEO_MODEL = 'fal-ai/ltxv-2/text-to-video/fast'; // LTX Video 2.0 Fast - very quick\nconst DEFAULT_IMAGE_TO_VIDEO_MODEL = 'fal-ai/vidu/q2/image-to-video'; // Vidu Q2 for image-to-video\nconst DEFAULT_START_END_VIDEO_MODEL = 'fal-ai/vidu/start-end-to-video'; // Vidu for start-end interpolation\nconst DEFAULT_REFERENCE_VIDEO_MODEL = 'fal-ai/vidu/q2/reference-to-video'; // Vidu Q2 for reference images\n\n/**\n * Determine the best model based on request inputs.\n */\nfunction selectVideoModel(req: GenerateRequest): string {\n // User specified model takes precedence\n if (req.model) return req.model;\n\n // Start + End frame → interpolation model\n if (req.startFrame && req.endFrame) {\n return DEFAULT_START_END_VIDEO_MODEL;\n }\n\n // Reference images (inputImages without startFrame) → reference-to-video\n if (req.inputImages?.length && !req.startFrame) {\n return DEFAULT_REFERENCE_VIDEO_MODEL;\n }\n\n // Start frame only → image-to-video\n if (req.startFrame || req.inputImages?.length) {\n return DEFAULT_IMAGE_TO_VIDEO_MODEL;\n }\n\n // No images → text-to-video\n return DEFAULT_VIDEO_MODEL;\n}\n\n/**\n * Determine the best image model based on request inputs.\n */\nfunction selectImageModel(req: GenerateRequest): string {\n if (req.model) return req.model;\n if (req.inputImages?.length) return DEFAULT_IMAGE_TO_IMAGE_MODEL;\n return DEFAULT_IMAGE_MODEL;\n}\n\n/**\n * Map aspect ratio string to fal enum values.\n */\nfunction mapAspectRatio(aspectRatio?: string): string | undefined {\n if (!aspectRatio) return undefined;\n const ar = aspectRatio.trim();\n if (ar === '1:1') return 'square';\n if (ar === '4:3') return 'landscape_4_3';\n if (ar === '16:9') return 'landscape_16_9';\n if (ar === '3:4') return 'portrait_4_3';\n if (ar === '9:16') return 'portrait_16_9';\n return ar; // Pass through if not mapped\n}\n\n/**\n * Build input for video generation based on request parameters.\n */\nfunction buildVideoInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n // Start + End frame interpolation (Vidu start-end-to-video)\n if (req.startFrame && req.endFrame) {\n input.start_image_url = req.startFrame;\n input.end_image_url = req.endFrame;\n // Vidu supports movement_amplitude\n return input;\n }\n\n // Reference images (Vidu reference-to-video)\n if (req.inputImages?.length && !req.startFrame) {\n input.reference_image_urls = req.inputImages.slice(0, 7); // Max 7 reference images\n const ar = mapAspectRatio(req.aspectRatio);\n if (ar) input.aspect_ratio = ar;\n if (req.duration) input.duration = String(req.duration); // Vidu uses string enum\n return input;\n }\n\n // Single image → image-to-video\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if (imageUrl) {\n input.image_url = imageUrl;\n if (req.duration) input.duration = String(req.duration);\n return input;\n }\n\n // Text-to-video\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_videos = req.n;\n\n return input;\n}\n\n/**\n * Build input for image generation based on request parameters.\n */\nfunction buildImageInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_images = req.n;\n\n // Image-to-image: add input image\n if (req.inputImages?.[0]) {\n input.image_url = req.inputImages[0];\n // Common i2i parameters\n input.strength = 0.75; // Default strength for image-to-image\n }\n\n return input;\n}\n\nconst falCapabilities: ProviderCapabilities = {\n maxInputImages: 7, // Vidu supports up to 7 reference images\n // fal models vary. We map common ratios to enums, but also allow custom pass-through.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: true, // Vidu start-end-to-video\n videoDurationRange: [2, 8], // Vidu supports 2-8 seconds\n supportsImageEditing: true,\n};\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n supports: ['image', 'video'],\n capabilities: falCapabilities,\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n const verbose = req.verbose;\n log(verbose, 'Starting generation, kind:', req.kind, 'n:', req.n);\n log(\n verbose,\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Select model based on kind and inputs\n const model = req.kind === 'video' ? selectVideoModel(req) : selectImageModel(req);\n log(verbose, 'Selected model:', model);\n\n // Build input based on kind\n const input = req.kind === 'video' ? buildVideoInput(req) : buildImageInput(req);\n\n // Log input without large data URIs\n const inputSummary = { ...input };\n for (const key of ['image_url', 'start_image_url', 'end_image_url']) {\n if (\n typeof inputSummary[key] === 'string' &&\n (inputSummary[key] as string).startsWith('data:')\n ) {\n inputSummary[key] = `data:...${(inputSummary[key] as string).length} chars`;\n }\n }\n if (Array.isArray(inputSummary.reference_image_urls)) {\n inputSummary.reference_image_urls = (inputSummary.reference_image_urls as string[]).map(\n (url) => (url.startsWith('data:') ? `data:...${url.length} chars` : url)\n );\n }\n log(verbose, 'Request input:', JSON.stringify(inputSummary));\n\n log(verbose, 'Calling fal.subscribe...');\n const startTime = Date.now();\n\n const subscribeOptions: Parameters<typeof fal.subscribe>[1] = {\n input,\n logs: verbose,\n };\n if (verbose) {\n subscribeOptions.onQueueUpdate = (update) => {\n log(true, 'Queue update:', update.status, JSON.stringify(update).slice(0, 200));\n };\n }\n\n const result = (await fal.subscribe(model, subscribeOptions)) as { data: FalResult };\n\n log(verbose, `fal.subscribe completed in ${Date.now() - startTime}ms`);\n log(verbose, 'Raw result keys:', Object.keys(result?.data ?? {}));\n log(verbose, 'Result preview:', JSON.stringify(result?.data ?? {}).slice(0, 500));\n\n const items = pickMany(result?.data ?? {}, req.kind);\n log(verbose, `Found ${items.length} ${req.kind}(s) in response`);\n\n if (!items?.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(\n `fal returned no ${noun}. Raw response: ${JSON.stringify(result?.data).slice(0, 300)}`\n );\n }\n\n const out = [] as Array<{\n kind: 'image' | 'video';\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(items.length, req.n); i++) {\n const m = items[i];\n if (!m?.url) {\n log(verbose, `Item ${i} has no URL, skipping`);\n continue;\n }\n log(verbose, `Downloading item ${i}...`);\n const { bytes, mimeType } = await downloadBytes(m.url, verbose);\n const finalMimeType = m.content_type ?? mimeType;\n out.push({\n kind: req.kind,\n provider: 'fal',\n model,\n index: i,\n url: m.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(`fal returned ${noun} but none were downloadable`);\n }\n\n log(verbose, `Successfully generated ${out.length} ${req.kind}(s)`);\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForImageFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[google]', ...args);\n}\n\n// Model aliases for Nano Banana (Gemini native image generation)\nconst MODEL_ALIASES: Record<string, string> = {\n 'nano-banana': 'gemini-2.5-flash-image',\n 'nano-banana-pro': 'gemini-3-pro-image-preview',\n // Veo (video)\n veo2: 'veo-2.0-generate-001',\n 'veo-2': 'veo-2.0-generate-001',\n veo3: 'veo-3.0-generate-001',\n 'veo-3': 'veo-3.0-generate-001',\n 'veo-3.1': 'veo-3.1-generate-preview',\n veo31: 'veo-3.1-generate-preview',\n};\n\n// Veo 3.1 models that support advanced features (interpolation, reference images)\nconst VEO_31_MODELS = ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview'];\n\n/**\n * Check if model supports Veo 3.1 features (interpolation, reference images).\n */\nfunction isVeo31Model(model: string): boolean {\n return VEO_31_MODELS.some((m) => model.includes(m) || model.includes('veo-3.1'));\n}\n\n/**\n * Parse a data URI and extract base64 data and mime type.\n */\nfunction parseDataUri(dataUri: string): { data: string; mimeType: string } | null {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1] ?? 'image/png', data: match[2] ?? '' };\n}\n\n/**\n * Convert image input (URL or data URI) to format suitable for Google API.\n */\nfunction imageToGoogleFormat(\n imageInput: string\n): { inlineData: { data: string; mimeType: string } } | { fileUri: string } {\n // Data URI - extract base64\n if (imageInput.startsWith('data:')) {\n const parsed = parseDataUri(imageInput);\n if (parsed) {\n return { inlineData: { data: parsed.data, mimeType: parsed.mimeType } };\n }\n }\n // URL - use as file URI\n return { fileUri: imageInput };\n}\n\n// Gemini native image models (use generateContent with IMAGE modality)\nconst GEMINI_IMAGE_MODELS = ['gemini-2.5-flash-image', 'gemini-3-pro-image-preview'];\n\nfunction resolveModel(model: string | undefined): string {\n if (!model) return 'gemini-2.5-flash-image'; // Default: Nano Banana (fast)\n return MODEL_ALIASES[model] ?? model;\n}\n\nfunction isGeminiImageModel(model: string): boolean {\n return GEMINI_IMAGE_MODELS.some((m) => model.startsWith(m));\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Google video download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\nconst googleCapabilities: ProviderCapabilities = {\n maxInputImages: 3, // Veo 3.1 supports up to 3 reference images\n // Imagen / Veo aspect ratio is expressed as \"w:h\" (e.g. \"16:9\").\n // Public docs/examples focus on the common set below.\n supportedAspectRatios: ['1:1', '4:3', '3:4', '16:9', '9:16'],\n supportsVideoInterpolation: true, // Veo 3.1 supports first + last frame\n videoDurationRange: [4, 8], // Veo 3.1 supports 4, 6, 8 seconds\n supportsImageEditing: true,\n};\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen / Veo)',\n supports: ['image', 'video'],\n capabilities: googleCapabilities,\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n log(\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n const ai = new GoogleGenAI({ apiKey });\n\n if (req.kind === 'video') {\n // Default to Veo 3.1 if using advanced features, otherwise Veo 2\n const hasAdvancedFeatures = req.startFrame || req.endFrame || req.inputImages?.length;\n const defaultModel = hasAdvancedFeatures\n ? 'veo-3.1-generate-preview'\n : 'veo-2.0-generate-001';\n const model = MODEL_ALIASES[req.model ?? ''] ?? req.model ?? defaultModel;\n log('Using video model:', model);\n\n // Warn if using advanced features with non-Veo 3.1 model\n if (hasAdvancedFeatures && !isVeo31Model(model)) {\n log(\n 'WARNING: Advanced video features (startFrame, endFrame, referenceImages) require Veo 3.1'\n );\n }\n\n return generateWithVeo(ai, model, req);\n }\n\n const model = resolveModel(req.model);\n log('Resolved model:', model);\n\n // Use Gemini native image generation for Gemini models\n if (isGeminiImageModel(model)) {\n log('Using Gemini native image generation');\n return generateWithGemini(ai, model, req);\n }\n\n // Use Imagen API for imagen-* models\n log('Using Imagen API');\n return generateWithImagen(ai, model, req);\n },\n};\n\n// Generate videos using Veo via Gemini API.\nasync function generateWithVeo(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Veo video generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n // Build config for generateVideos\n const config: Record<string, unknown> = {\n numberOfVideos: req.n,\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n // Add duration if specified (Veo 3.1 supports 4, 6, 8)\n ...(req.duration !== undefined ? { durationSeconds: String(req.duration) } : {}),\n };\n\n // Build reference images array for Veo 3.1 (up to 3 images)\n if (req.inputImages?.length && isVeo31Model(model)) {\n const referenceImages = req.inputImages.slice(0, 3).map((img) => {\n const imageData = imageToGoogleFormat(img);\n return {\n image: imageData,\n referenceType: 'asset' as const,\n };\n });\n (config as any).referenceImages = referenceImages;\n log('Added', referenceImages.length, 'reference images');\n }\n\n // Build generateVideos params\n const generateParams: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n config,\n };\n\n // Add image (first frame) for Veo 3.1 image-to-video\n const firstFrameImage =\n req.startFrame ?? (req.inputImages?.length === 1 ? req.inputImages[0] : undefined);\n if (firstFrameImage && isVeo31Model(model)) {\n const imageData = imageToGoogleFormat(firstFrameImage);\n (generateParams as any).image = imageData;\n log('Added first frame image');\n }\n\n // Add lastFrame for Veo 3.1 interpolation\n if (req.endFrame && isVeo31Model(model)) {\n const lastFrameData = imageToGoogleFormat(req.endFrame);\n (config as any).lastFrame = lastFrameData;\n log('Added last frame for interpolation');\n }\n\n // The SDK returns a long-running operation. Poll until done.\n log('Calling ai.models.generateVideos...');\n let op = await ai.models.generateVideos(generateParams as any);\n\n log('Initial operation state:', op.done ? 'done' : 'pending', 'name:', (op as any).name);\n\n const maxAttempts = 60; // ~10 minutes at 10s\n const intervalMs = 10000;\n\n for (let attempt = 0; attempt < maxAttempts && !op.done; attempt++) {\n log(`Poll attempt ${attempt + 1}/${maxAttempts}...`);\n await sleep(intervalMs);\n op = await ai.operations.getVideosOperation({ operation: op });\n log(`Poll result: done=${op.done}`);\n }\n\n log(`Operation completed in ${Date.now() - startTime}ms`);\n\n if (!op.done) {\n log('Timed out. Operation state:', JSON.stringify(op).slice(0, 500));\n throw new Error('Google Veo video generation timed out');\n }\n\n const videos = op.response?.generatedVideos;\n log('Generated videos count:', videos?.length);\n\n if (!videos?.length) {\n log('Full response:', JSON.stringify(op.response).slice(0, 1000));\n throw new Error('Google Veo returned no videos');\n }\n\n const out: Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(videos.length, req.n); i++) {\n const v = videos[i];\n log(`Processing video ${i}:`, JSON.stringify(v).slice(0, 300));\n const uri = (v as any)?.video?.uri as string | undefined;\n if (!uri) {\n log(`Video ${i} has no URI, skipping`);\n continue;\n }\n\n // SDK may return gs:// URIs on Vertex; we only support downloadable http(s) URLs.\n if (uri.startsWith('gs://')) {\n throw new Error(\n `Google Veo returned a gs:// URI (${uri}). Configure outputGcsUri / Vertex flow to fetch from GCS.`\n );\n }\n\n const { bytes, mimeType } = await downloadBytes(uri);\n out.push({\n kind: 'video',\n provider: 'google',\n model,\n index: i,\n url: uri,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('Google Veo returned videos but none were downloadable');\n log(`Successfully generated ${out.length} video(s)`);\n return out;\n}\n\n// Generate images using Gemini native image generation\nasync function generateWithGemini(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n const hasInputImage = req.inputImages?.length;\n log(\n 'Starting Gemini image generation, model:',\n model,\n 'n:',\n req.n,\n 'hasInputImage:',\n !!hasInputImage\n );\n const startTime = Date.now();\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n // Build contents - either text prompt or multimodal with image for editing\n const buildContents = () => {\n if (hasInputImage && req.inputImages?.[0]) {\n // Multimodal content: image + text prompt for editing\n const imageData = imageToGoogleFormat(req.inputImages[0]);\n return [{ ...imageData }, { text: req.prompt }] as const;\n }\n // Text-only prompt\n return req.prompt;\n };\n\n // Gemini native image generation produces one image per call\n // Generate sequentially for n > 1\n for (let i = 0; i < req.n; i++) {\n log(`Generating image ${i + 1}/${req.n}...`);\n const callStart = Date.now();\n\n try {\n const res = await ai.models.generateContent({\n model,\n contents: buildContents() as any,\n config: {\n responseModalities: ['IMAGE'],\n },\n });\n\n log(`API call ${i + 1} took ${Date.now() - callStart}ms`);\n\n const parts = res.candidates?.[0]?.content?.parts;\n log(`Response has ${parts?.length ?? 0} parts`);\n\n if (!parts) {\n log(\n `No parts in response for image ${i}. Full response:`,\n JSON.stringify(res).slice(0, 500)\n );\n continue;\n }\n\n for (const part of parts) {\n if (part.inlineData?.data) {\n const rawBytes = part.inlineData.data;\n const bytes =\n typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes, mimeType: ${part.inlineData.mimeType}`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: part.inlineData.mimeType ?? mimeForImageFormat(req.format),\n });\n break; // One image per call\n }\n }\n } catch (err) {\n log(`Error generating image ${i}:`, err);\n throw err;\n }\n }\n\n log(`Total generation time: ${Date.now() - startTime}ms`);\n\n if (!out.length) throw new Error('Gemini returned no images');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n\n// Generate images using Imagen API\nasync function generateWithImagen(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Imagen generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n log('Calling ai.models.generateImages...');\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForImageFormat(req.format),\n // Imagen 4 supports aspectRatio\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n },\n });\n\n log(`API call took ${Date.now() - startTime}ms`);\n\n const imgs = res.generatedImages;\n log('Generated images count:', imgs?.length);\n\n if (!imgs?.length) {\n log('Full response:', JSON.stringify(res).slice(0, 1000));\n throw new Error('Google generateImages returned no images');\n }\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) {\n log(`Image ${i} has no bytes, skipping`);\n continue;\n }\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForImageFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[openai]', ...args);\n}\n\n/**\n * Convert a data URI to a Blob for FormData upload.\n */\nfunction dataUriToBlob(dataUri: string): Blob {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) throw new Error('Invalid data URI');\n const mimeType = match[1] ?? 'image/png';\n const base64 = match[2] ?? '';\n const binary = Buffer.from(base64, 'base64');\n return new Blob([binary], { type: mimeType });\n}\n\n/**\n * Fetch an image from URL and return as Blob.\n */\nasync function urlToBlob(url: string): Promise<Blob> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Failed to fetch image: ${res.status}`);\n return res.blob();\n}\n\n/**\n * Convert image input (data URI or URL) to a Blob.\n */\nasync function imageInputToBlob(input: string): Promise<Blob> {\n if (input.startsWith('data:')) {\n return dataUriToBlob(input);\n }\n return urlToBlob(input);\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\nfunction supportedAspectRatiosForModel(model: string): string[] {\n if (model.startsWith('gpt-image')) {\n // These map onto the 3 supported sizes.\n return ['1:1', '3:2', '4:3', '16:9', '2:3', '3:4', '9:16'];\n }\n if (model === 'dall-e-3') {\n return ['1:1', '4:3', '16:9', '3:4', '9:16'];\n }\n if (model === 'dall-e-2') {\n // DALL·E 2 only supports square sizes.\n return ['1:1'];\n }\n // Unknown model: we don't know what aspect ratios map to sizes.\n return [];\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim().replace(/\\s+/g, '');\n\n // gpt-image-* supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait)\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n } else if (model === 'dall-e-2') {\n if (ar === '1:1') return '1024x1024';\n }\n\n return undefined;\n}\n\nconst openaiCapabilities: ProviderCapabilities = {\n maxInputImages: 2, // image + optional mask\n supportsVideoInterpolation: false, // OpenAI doesn't support video\n // videoDurationRange omitted - no video support\n supportsImageEditing: true,\n};\n\n/**\n * Generate images using OpenAI's edit endpoint (for image editing with input images).\n */\nasync function generateWithEdit(\n req: GenerateRequest,\n apiKey: string,\n model: string\n): Promise<\n Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Using edit endpoint for image editing');\n const startTime = Date.now();\n\n // Build FormData for multipart upload\n const formData = new FormData();\n formData.append('model', model);\n formData.append('prompt', req.prompt);\n formData.append('n', String(req.n));\n\n // Add size if specified\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n if (size) formData.append('size', size);\n\n // Add the input image\n const imageInput = req.inputImages?.[0];\n if (!imageInput) throw new Error('No input image provided for editing');\n\n const imageBlob = await imageInputToBlob(imageInput);\n formData.append('image', imageBlob, 'image.png');\n log('Added input image to form data');\n\n // Add mask if provided (second input image)\n const maskInput = req.inputImages?.[1];\n if (maskInput) {\n const maskBlob = await imageInputToBlob(maskInput);\n formData.append('mask', maskBlob, 'mask.png');\n log('Added mask image to form data');\n }\n\n log('Calling OpenAI images/edits...');\n const res = await fetch(`${OPENAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n // Don't set content-type - FormData sets it with boundary\n },\n body: formData,\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI edit failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI edit returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully edited ${results.length} image(s)`);\n return results;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n supports: ['image'],\n capabilities: openaiCapabilities,\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n // Default to gpt-image-1 (stable), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n log('Using model:', model, 'hasInputImages:', !!req.inputImages?.length);\n\n // Use edit endpoint if input images provided\n if (req.inputImages?.length) {\n return generateWithEdit(req, apiKey, model);\n }\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling OpenAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n },\n};\n"],"mappings":"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","names":["process","path","process","fs","path","path","fs","log","downloadBytes","key","verboseMode","log","downloadBytes","sleep","model","verboseMode","log","downloadBytes","log","p","path","providers","process"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process';\n\nimport { generateMedia, listProviders } from './index.js';\nimport { toJsonResult } from './core/output.js';\nimport type { GenerateOptions, ProviderId } from './core/types.js';\n\nfunction usage(code = 0) {\n const providers = listProviders()\n .map((p) => `${p.id}`)\n .join(', ');\n\n // eslint-disable-next-line no-console\n console.log(`climage\n\nUsage:\n climage \"prompt\"\n\nOptions:\n --provider <auto|${providers}> Provider (default: auto)\n --model <id> Model id (provider-specific)\n --n <1..10> Number of outputs (default: 1)\n --type <image|video> Output type (default: image)\n --video Shortcut for: --type video\n --format <png|jpg|webp|mp4|webm|gif>\n Output format (default: png for image, mp4 for video)\n --out <path> Output file path (only when n=1)\n --outDir <dir> Output directory (default: .)\n --name <text> Base name (slugified); default: prompt\n --aspect-ratio <w:h> Aspect ratio (provider-specific)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\n\nInput Images:\n --input <path> Input image for editing or reference (repeatable)\n --start-frame <path> First frame image (for video generation)\n --end-frame <path> Last frame image (for video interpolation)\n --duration <seconds> Video duration in seconds (provider-specific)\n\nEnv:\n GEMINI_API_KEY (or GOOGLE_API_KEY)\n XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)\n FAL_KEY (or FAL_API_KEY)\n OPENAI_API_KEY\n\nExamples:\n npx climage \"make image of kitten\"\n npx climage \"A cat in a tree\" --provider xai --n 4\n npx climage \"a cinematic shot of a corgi running\" --provider fal --type video\n npx climage \"make the cat orange\" --provider xai --input photo.jpg\n npx climage \"the cat walks away\" --video --provider google --start-frame cat.png\n npx climage \"morphing transition\" --video --provider fal --start-frame a.png --end-frame b.png\n`);\n process.exit(code);\n}\n\nfunction parseArgs(argv: string[]): { prompt: string; opts: GenerateOptions; json: boolean } {\n const args = [...argv];\n const opts: GenerateOptions = {};\n let json = false;\n const promptParts: string[] = [];\n const inputImages: string[] = [];\n\n // Options that take a value\n const optionsWithValue = new Set([\n '--provider',\n '--model',\n '--n',\n '--type',\n '--format',\n '--out',\n '--outDir',\n '--name',\n '--aspect-ratio',\n '--input',\n '--start-frame',\n '--end-frame',\n '--duration',\n ]);\n\n let i = 0;\n while (i < args.length) {\n const a = args[i];\n if (!a) {\n i++;\n continue;\n }\n\n // Help\n if (a === '-h' || a === '--help') usage(0);\n\n // Boolean flags\n if (a === '--json') {\n json = true;\n i++;\n continue;\n }\n if (a === '--video') {\n opts.kind = 'video';\n i++;\n continue;\n }\n if (a === '--verbose') {\n opts.verbose = true;\n i++;\n continue;\n }\n\n // Options with values\n if (optionsWithValue.has(a)) {\n const v = args[i + 1];\n if (!v || v.startsWith('-')) throw new Error(`Missing value for ${a}`);\n switch (a) {\n case '--provider':\n opts.provider = v as ProviderId;\n break;\n case '--model':\n opts.model = v;\n break;\n case '--n':\n opts.n = Number(v);\n break;\n case '--type':\n opts.kind = v as any;\n break;\n case '--format':\n opts.format = v as any;\n break;\n case '--out':\n opts.out = v;\n break;\n case '--outDir':\n opts.outDir = v;\n break;\n case '--name':\n opts.name = v;\n break;\n case '--aspect-ratio':\n opts.aspectRatio = v;\n break;\n case '--input':\n inputImages.push(v);\n break;\n case '--start-frame':\n opts.startFrame = v;\n break;\n case '--end-frame':\n opts.endFrame = v;\n break;\n case '--duration':\n opts.duration = Number(v);\n break;\n }\n i += 2;\n continue;\n }\n\n // Unknown option\n if (a.startsWith('-')) {\n throw new Error(`Unknown option: ${a}`);\n }\n\n // Non-option = prompt part\n promptParts.push(a);\n i++;\n }\n\n // Add collected input images to opts\n if (inputImages.length) {\n opts.inputImages = inputImages;\n }\n\n const prompt = promptParts.join(' ').trim();\n if (!prompt) throw new Error('Missing prompt');\n\n return { prompt, opts, json };\n}\n\nasync function main() {\n try {\n const { prompt, opts, json } = parseArgs(process.argv.slice(2));\n const items = await generateMedia(prompt, opts);\n\n if (json) {\n process.stdout.write(JSON.stringify(toJsonResult(items), null, 2) + '\\n');\n return;\n }\n\n for (const item of items) {\n process.stdout.write(item.filePath + '\\n');\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`climage: ${msg}\\n`);\n process.stderr.write(`Run: climage --help\\n`);\n process.exit(1);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain();\n","import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedMedia,\n GeneratedMediaPartial,\n MediaKind,\n OutputFormat,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport {\n makeOutputPath,\n resolveImageInput,\n resolveImageInputs,\n resolveOutDir,\n writeMediaFile,\n} from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[router]', ...args);\n}\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction defaultFormatForKind(kind: MediaKind): OutputFormat {\n return kind === 'video' ? 'mp4' : 'png';\n}\n\nasync function normalizeOptions(\n prompt: string,\n opts: GenerateOptions,\n verbose: boolean\n): Promise<GenerateRequest> {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const kind = opts.kind ?? 'image';\n const format = opts.format ?? defaultFormatForKind(kind);\n\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n // Resolve input images (convert local paths to data URIs)\n let inputImages: string[] | undefined;\n if (opts.inputImages?.length) {\n log(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);\n inputImages = await resolveImageInputs(opts.inputImages);\n log(verbose, `Resolved input images`);\n }\n\n // Resolve start/end frames for video\n let startFrame: string | undefined;\n let endFrame: string | undefined;\n\n if (opts.startFrame) {\n log(verbose, `Resolving start frame: ${opts.startFrame}`);\n startFrame = await resolveImageInput(opts.startFrame);\n }\n\n if (opts.endFrame) {\n log(verbose, `Resolving end frame: ${opts.endFrame}`);\n endFrame = await resolveImageInput(opts.endFrame);\n }\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n kind,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n // New fields\n inputImages,\n startFrame,\n endFrame,\n duration: opts.duration,\n };\n}\n\n/**\n * Validate request parameters against provider capabilities.\n */\nfunction validateRequestForProvider(req: GenerateRequest, provider: Provider): void {\n const caps = provider.capabilities;\n\n // Validate input images count\n const inputCount = req.inputImages?.length ?? 0;\n if (inputCount > caps.maxInputImages) {\n throw new Error(\n `Provider ${provider.id} supports max ${caps.maxInputImages} input image(s), but ${inputCount} provided`\n );\n }\n\n // Validate aspect ratio\n if (req.aspectRatio) {\n const normalized = req.aspectRatio.trim().replace(/\\s+/g, '');\n\n // Always enforce a basic w:h shape to avoid passing junk downstream.\n const looksLikeRatio = /^\\d+:\\d+$/.test(normalized);\n if (!looksLikeRatio) {\n throw new Error(`Invalid aspect ratio: \"${req.aspectRatio}\" (expected format: w:h)`);\n }\n\n // If provider has an allowlist and does NOT support arbitrary custom ratios, validate against it.\n if (\n caps.supportsCustomAspectRatio !== true &&\n Array.isArray(caps.supportedAspectRatios) &&\n caps.supportedAspectRatios.length\n ) {\n const ok = caps.supportedAspectRatios.includes(normalized);\n if (!ok) {\n throw new Error(\n `Provider ${provider.id} does not support aspect ratio \"${normalized}\". ` +\n `Supported: ${caps.supportedAspectRatios.join(', ')}`\n );\n }\n }\n }\n\n // Validate video interpolation (start + end frame)\n if (req.endFrame && !caps.supportsVideoInterpolation) {\n throw new Error(\n `Provider ${provider.id} does not support video interpolation (end frame). ` +\n `Only startFrame is supported for image-to-video.`\n );\n }\n\n // Validate duration range\n if (req.duration !== undefined && req.kind === 'video' && caps.videoDurationRange) {\n const [min, max] = caps.videoDurationRange;\n if (req.duration < min || req.duration > max) {\n throw new Error(\n `Provider ${provider.id} supports video duration ${min}-${max}s, but ${req.duration}s requested`\n );\n }\n }\n\n // Validate image editing support\n if (req.kind === 'image' && inputCount > 0 && !caps.supportsImageEditing) {\n throw new Error(`Provider ${provider.id} does not support image editing with input images`);\n }\n}\n\nexport async function generateMedia(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n const { env } = loadEnv(process.cwd());\n const verbose = Boolean(opts.verbose);\n\n // Normalize and resolve options (including reading input image files)\n const req = await normalizeOptions(prompt, opts, verbose);\n\n // Build a summary object for logging (truncate large data URIs)\n const reqSummary = {\n ...req,\n prompt: req.prompt.slice(0, 50) + '...',\n inputImages: req.inputImages?.map((img) =>\n img.startsWith('data:') ? `data:...${img.length} chars` : img\n ),\n startFrame: req.startFrame?.startsWith('data:')\n ? `data:...${req.startFrame.length} chars`\n : req.startFrame,\n endFrame: req.endFrame?.startsWith('data:')\n ? `data:...${req.endFrame.length} chars`\n : req.endFrame,\n };\n log(verbose, 'Request:', JSON.stringify(reqSummary));\n\n const provider = pickProvider(req.provider, env);\n log(verbose, 'Selected provider:', provider.id, '| supports:', provider.supports);\n\n if (!provider.supports.includes(req.kind)) {\n throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);\n }\n\n // Validate request against provider capabilities\n validateRequestForProvider(req, provider);\n\n log(verbose, 'Calling provider.generate()...');\n const startTime = Date.now();\n\n const partials = await provider.generate(req, env);\n\n log(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);\n\n const items: GeneratedMedia[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedMediaPartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i, p.mimeType);\n log(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);\n await writeMediaFile(filePath, p.bytes);\n items.push({ ...p, filePath });\n }\n\n log(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);\n return items;\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'image' });\n}\n\nexport async function generateVideo(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'video' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GenerateRequest, GeneratedMedia } from './types.js';\n\n/** Map file extensions to MIME types for images. */\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.avif': 'image/avif',\n '.heif': 'image/heif',\n '.heic': 'image/heic',\n};\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n case 'mp4':\n return 'mp4';\n case 'webm':\n return 'webm';\n case 'gif':\n return 'gif';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nfunction extensionFromMimeType(mimeType: string | undefined): string | undefined {\n if (!mimeType) return undefined;\n\n const t = mimeType.toLowerCase().split(';')[0]?.trim();\n if (!t) return undefined;\n\n // Images\n if (t === 'image/png') return 'png';\n if (t === 'image/jpeg') return 'jpg';\n if (t === 'image/webp') return 'webp';\n if (t === 'image/gif') return 'gif';\n if (t === 'image/avif') return 'avif';\n\n // Videos\n if (t === 'video/mp4') return 'mp4';\n if (t === 'video/webm') return 'webm';\n\n return undefined;\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number, mimeType?: string): string {\n // If user explicitly requested an output path, respect it verbatim.\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n // Some providers return a different MIME type than requested (e.g. JPEG bytes even if\n // --format png was requested). Prefer the actual MIME type for file extension to avoid\n // misleading file names.\n const ext = extensionFromMimeType(mimeType) ?? extensionForFormat(req.format);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeMediaFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(items: GeneratedMedia[]) {\n const images = items\n .filter((i) => i.kind === 'image')\n .map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n }));\n\n const videos = items\n .filter((i) => i.kind === 'video')\n .map((vid) => ({\n provider: vid.provider,\n model: vid.model,\n index: vid.index,\n filePath: vid.filePath,\n url: vid.url,\n bytes: vid.bytes.byteLength,\n mimeType: vid.mimeType,\n }));\n\n return {\n ...(images.length ? { images } : {}),\n ...(videos.length ? { videos } : {}),\n };\n}\n\n/**\n * Resolve an image input path or URL to a usable format.\n * - URLs (http/https) are returned as-is\n * - Data URIs are returned as-is\n * - Local file paths are read and converted to base64 data URIs\n *\n * @param pathOrUrl - A file path or URL to an image\n * @returns The resolved image as a URL or data URI\n */\nexport async function resolveImageInput(pathOrUrl: string): Promise<string> {\n // Already a URL (http/https)\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n // Already a data URI\n if (pathOrUrl.startsWith('data:')) {\n return pathOrUrl;\n }\n\n // Local file path - resolve and read\n const resolvedPath = path.isAbsolute(pathOrUrl)\n ? pathOrUrl\n : path.resolve(process.cwd(), pathOrUrl);\n\n const ext = path.extname(resolvedPath).toLowerCase();\n const mimeType = IMAGE_MIME_TYPES[ext];\n\n if (!mimeType) {\n throw new Error(\n `Unsupported image format: ${ext}. Supported: ${Object.keys(IMAGE_MIME_TYPES).join(', ')}`\n );\n }\n\n const fileBuffer = await fs.readFile(resolvedPath);\n const base64 = fileBuffer.toString('base64');\n\n return `data:${mimeType};base64,${base64}`;\n}\n\n/**\n * Resolve multiple image inputs in parallel.\n *\n * @param pathsOrUrls - Array of file paths or URLs\n * @returns Array of resolved images as URLs or data URIs\n */\nexport async function resolveImageInputs(pathsOrUrls: string[]): Promise<string[]> {\n return Promise.all(pathsOrUrls.map(resolveImageInput));\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\ntype XaiVideoGenerationResponse = {\n request_id?: string;\n};\n\ntype XaiVideoResultResponse = {\n // When pending\n status?: 'pending' | string;\n // When complete - video info is at top level, not nested in response\n video?: {\n duration?: number;\n respect_moderation?: boolean;\n url?: string | null;\n };\n model?: string;\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[xai]', ...args);\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Generate images using xAI's /v1/images/generations endpoint (text-to-image).\n */\nasync function generateXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n log('Starting image generation, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling xAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Edit images using xAI's /v1/images/edits endpoint (image-to-image).\n * Uses JSON format with image_url (data URI or URL).\n */\nasync function editXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n const inputImage = req.inputImages?.[0];\n if (!inputImage) throw new Error('No input image provided for editing');\n\n if ((req.inputImages?.length ?? 0) > 1) {\n throw new Error(\n 'xAI image editing supports only 1 input image (image_url). ' +\n 'Provide exactly one --input for xAI edits.'\n );\n }\n\n log('Starting image editing, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n image: { url: inputImage }, // Object with url field containing data URI or URL\n response_format: 'url',\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n };\n log('Request body:', JSON.stringify({ ...body, image: { url: '...(data uri)...' } }));\n\n log('Calling xAI images/edits...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI edits failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Process xAI image response and download images.\n */\nasync function processXaiImageResponse(json: XaiImagesResponse, model: string) {\n const results = [] as Array<{\n kind: 'image';\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n}\n\nasync function generateXaiVideo(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-video';\n\n // Get image URL from startFrame or inputImages[0]\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if ((req.inputImages?.length ?? 0) > 1 && !req.startFrame) {\n throw new Error(\n 'xAI video generation supports only 1 input image (image_url). ' +\n 'Provide exactly one --input or use --start-frame.'\n );\n }\n log(\n 'Starting video generation, model:',\n model,\n 'hasImageUrl:',\n !!imageUrl,\n 'duration:',\n req.duration\n );\n\n // xAI is async: create request_id, then poll /v1/videos/{request_id}\n // NOTE: xAI uses an OpenAI-like schema for image inputs. For video generation,\n // providing a plain `image_url` string may be accepted but ignored by the model.\n // Use the object form `{ image: { url } }` so --start-frame is actually applied.\n const createBody: Record<string, unknown> = {\n prompt: req.prompt,\n model,\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n ...(imageUrl ? { image: { url: imageUrl } } : {}),\n // Add duration (xAI supports 1-15 seconds)\n ...(req.duration !== undefined ? { duration: req.duration } : {}),\n };\n log(\n 'Request body:',\n JSON.stringify({\n ...createBody,\n image: createBody.image\n ? { url: `...(${String((createBody.image as any).url).length} chars)` }\n : undefined,\n })\n );\n\n log('Calling xAI videos/generations...');\n const startTime = Date.now();\n\n const createRes = await fetch(`${XAI_API_BASE}/videos/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(createBody),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${createRes.status}`);\n\n if (!createRes.ok) {\n const txt = await createRes.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI video generations failed (${createRes.status}): ${txt.slice(0, 500)}`);\n }\n\n const createJson = (await createRes.json()) as XaiVideoGenerationResponse;\n const requestId = createJson.request_id;\n log('Got request_id:', requestId);\n if (!requestId) throw new Error('xAI video generation returned no request_id');\n\n // Poll (best-effort). Video generation can take a while.\n const maxAttempts = 120; // ~6 minutes at 3s interval\n const intervalMs = 3000;\n\n let result: XaiVideoResultResponse | undefined;\n log(`Starting poll loop (max ${maxAttempts} attempts, ${intervalMs}ms interval)...`);\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const res = await fetch(`${XAI_API_BASE}/videos/${encodeURIComponent(requestId)}`, {\n method: 'GET',\n headers: {\n authorization: `Bearer ${apiKey}`,\n },\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log(`Poll attempt ${attempt + 1} failed:`, txt.slice(0, 500));\n throw new Error(`xAI video poll failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiVideoResultResponse;\n result = json;\n\n log(\n `Poll attempt ${attempt + 1}/${maxAttempts}: status=${json.status}, raw:`,\n JSON.stringify(json).slice(0, 300)\n );\n\n // xAI returns video object at top level (not nested in response) when complete\n if (json.video?.url) {\n log('Video generation complete!');\n break;\n }\n\n if (json.status === 'failed' || json.status === 'error') {\n log('Video generation failed:', JSON.stringify(json));\n throw new Error(`xAI video generation failed: ${JSON.stringify(json)}`);\n }\n\n await sleep(intervalMs);\n }\n\n if (!result?.video?.url) {\n log('Timed out. Last result:', JSON.stringify(result));\n throw new Error(`xAI video generation timed out (request_id=${requestId})`);\n }\n\n const url = result.video.url;\n log('Video URL:', url);\n\n // Check moderation status\n if (result.video?.respect_moderation === false) {\n throw new Error('xAI video generation was blocked by moderation');\n }\n\n const { bytes, mimeType } = await downloadBytes(url);\n\n log(`Successfully generated video, ${bytes.byteLength} bytes`);\n return [\n {\n kind: 'video' as const,\n provider: 'xai' as const,\n model: result.model ?? model,\n index: 0,\n url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n },\n ];\n}\n\nconst xaiCapabilities: ProviderCapabilities = {\n // xAI docs show a single image_url for edits and a single image_url for image-to-video.\n maxInputImages: 1,\n // xAI aspect_ratio examples show \"4:3\"; docs don't publish a strict allowlist.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: false, // xAI does not support end frame\n videoDurationRange: [1, 15], // 1-15 seconds\n supportsImageEditing: true,\n};\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI',\n supports: ['image', 'video'],\n capabilities: xaiCapabilities,\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n if (req.kind === 'video') return generateXaiVideo(req, apiKey);\n\n // Use edit endpoint if input images provided, otherwise generation\n const hasInputImages = req.inputImages && req.inputImages.length > 0;\n if (hasInputImages) {\n log('Input images detected, using edit endpoint');\n return editXaiImages(req, apiKey);\n }\n return generateXaiImages(req, apiKey);\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalMedia = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalMedia[];\n image?: FalMedia;\n videos?: FalMedia[];\n video?: FalMedia;\n};\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[fal]', ...args);\n}\n\nasync function downloadBytes(\n url: string,\n verbose: boolean\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log(verbose, 'Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(verbose, `Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nfunction pickMany(result: FalResult, kind: 'image' | 'video'): FalMedia[] {\n if (kind === 'image') {\n if (Array.isArray(result.images) && result.images.length) return result.images;\n if (result.image?.url) return [result.image];\n return [];\n }\n\n if (Array.isArray(result.videos) && result.videos.length) return result.videos;\n if (result.video?.url) return [result.video];\n return [];\n}\n\n// Default models per kind and input type\nconst DEFAULT_IMAGE_MODEL = 'fal-ai/flux/dev';\nconst DEFAULT_IMAGE_TO_IMAGE_MODEL = 'fal-ai/flux/dev/image-to-image';\nconst DEFAULT_VIDEO_MODEL = 'fal-ai/ltxv-2/text-to-video/fast'; // LTX Video 2.0 Fast - very quick\nconst DEFAULT_IMAGE_TO_VIDEO_MODEL = 'fal-ai/vidu/q2/image-to-video'; // Vidu Q2 for image-to-video\nconst DEFAULT_START_END_VIDEO_MODEL = 'fal-ai/vidu/start-end-to-video'; // Vidu for start-end interpolation\nconst DEFAULT_REFERENCE_VIDEO_MODEL = 'fal-ai/vidu/q2/reference-to-video'; // Vidu Q2 for reference images\n\n/**\n * Determine the best model based on request inputs.\n */\nfunction selectVideoModel(req: GenerateRequest): string {\n // User specified model takes precedence\n if (req.model) return req.model;\n\n // Start + End frame → interpolation model\n if (req.startFrame && req.endFrame) {\n return DEFAULT_START_END_VIDEO_MODEL;\n }\n\n // Reference images (inputImages without startFrame) → reference-to-video\n if (req.inputImages?.length && !req.startFrame) {\n return DEFAULT_REFERENCE_VIDEO_MODEL;\n }\n\n // Start frame only → image-to-video\n if (req.startFrame || req.inputImages?.length) {\n return DEFAULT_IMAGE_TO_VIDEO_MODEL;\n }\n\n // No images → text-to-video\n return DEFAULT_VIDEO_MODEL;\n}\n\n/**\n * Determine the best image model based on request inputs.\n */\nfunction selectImageModel(req: GenerateRequest): string {\n if (req.model) return req.model;\n if (req.inputImages?.length) return DEFAULT_IMAGE_TO_IMAGE_MODEL;\n return DEFAULT_IMAGE_MODEL;\n}\n\n/**\n * Map aspect ratio string to fal enum values.\n */\nfunction mapAspectRatio(aspectRatio?: string): string | undefined {\n if (!aspectRatio) return undefined;\n const ar = aspectRatio.trim();\n if (ar === '1:1') return 'square';\n if (ar === '4:3') return 'landscape_4_3';\n if (ar === '16:9') return 'landscape_16_9';\n if (ar === '3:4') return 'portrait_4_3';\n if (ar === '9:16') return 'portrait_16_9';\n return ar; // Pass through if not mapped\n}\n\n/**\n * Build input for video generation based on request parameters.\n */\nfunction buildVideoInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n // Start + End frame interpolation (Vidu start-end-to-video)\n if (req.startFrame && req.endFrame) {\n input.start_image_url = req.startFrame;\n input.end_image_url = req.endFrame;\n // Vidu supports movement_amplitude\n return input;\n }\n\n // Reference images (Vidu reference-to-video)\n if (req.inputImages?.length && !req.startFrame) {\n input.reference_image_urls = req.inputImages.slice(0, 7); // Max 7 reference images\n const ar = mapAspectRatio(req.aspectRatio);\n if (ar) input.aspect_ratio = ar;\n if (req.duration) input.duration = String(req.duration); // Vidu uses string enum\n return input;\n }\n\n // Single image → image-to-video\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if (imageUrl) {\n input.image_url = imageUrl;\n if (req.duration) input.duration = String(req.duration);\n return input;\n }\n\n // Text-to-video\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_videos = req.n;\n\n return input;\n}\n\n/**\n * Build input for image generation based on request parameters.\n */\nfunction buildImageInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_images = req.n;\n\n // Image-to-image: add input image\n if (req.inputImages?.[0]) {\n input.image_url = req.inputImages[0];\n // Common i2i parameters\n input.strength = 0.75; // Default strength for image-to-image\n }\n\n return input;\n}\n\nconst falCapabilities: ProviderCapabilities = {\n maxInputImages: 7, // Vidu supports up to 7 reference images\n // fal models vary. We map common ratios to enums, but also allow custom pass-through.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: true, // Vidu start-end-to-video\n videoDurationRange: [2, 8], // Vidu supports 2-8 seconds\n supportsImageEditing: true,\n};\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n supports: ['image', 'video'],\n capabilities: falCapabilities,\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n const verbose = req.verbose;\n log(verbose, 'Starting generation, kind:', req.kind, 'n:', req.n);\n log(\n verbose,\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Select model based on kind and inputs\n const model = req.kind === 'video' ? selectVideoModel(req) : selectImageModel(req);\n log(verbose, 'Selected model:', model);\n\n // Build input based on kind\n const input = req.kind === 'video' ? buildVideoInput(req) : buildImageInput(req);\n\n // Log input without large data URIs\n const inputSummary = { ...input };\n for (const key of ['image_url', 'start_image_url', 'end_image_url']) {\n if (\n typeof inputSummary[key] === 'string' &&\n (inputSummary[key] as string).startsWith('data:')\n ) {\n inputSummary[key] = `data:...${(inputSummary[key] as string).length} chars`;\n }\n }\n if (Array.isArray(inputSummary.reference_image_urls)) {\n inputSummary.reference_image_urls = (inputSummary.reference_image_urls as string[]).map(\n (url) => (url.startsWith('data:') ? `data:...${url.length} chars` : url)\n );\n }\n log(verbose, 'Request input:', JSON.stringify(inputSummary));\n\n log(verbose, 'Calling fal.subscribe...');\n const startTime = Date.now();\n\n const subscribeOptions: Parameters<typeof fal.subscribe>[1] = {\n input,\n logs: verbose,\n };\n if (verbose) {\n subscribeOptions.onQueueUpdate = (update) => {\n log(true, 'Queue update:', update.status, JSON.stringify(update).slice(0, 200));\n };\n }\n\n const result = (await fal.subscribe(model, subscribeOptions)) as { data: FalResult };\n\n log(verbose, `fal.subscribe completed in ${Date.now() - startTime}ms`);\n log(verbose, 'Raw result keys:', Object.keys(result?.data ?? {}));\n log(verbose, 'Result preview:', JSON.stringify(result?.data ?? {}).slice(0, 500));\n\n const items = pickMany(result?.data ?? {}, req.kind);\n log(verbose, `Found ${items.length} ${req.kind}(s) in response`);\n\n if (!items?.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(\n `fal returned no ${noun}. Raw response: ${JSON.stringify(result?.data).slice(0, 300)}`\n );\n }\n\n const out = [] as Array<{\n kind: 'image' | 'video';\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(items.length, req.n); i++) {\n const m = items[i];\n if (!m?.url) {\n log(verbose, `Item ${i} has no URL, skipping`);\n continue;\n }\n log(verbose, `Downloading item ${i}...`);\n const { bytes, mimeType } = await downloadBytes(m.url, verbose);\n const finalMimeType = m.content_type ?? mimeType;\n out.push({\n kind: req.kind,\n provider: 'fal',\n model,\n index: i,\n url: m.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(`fal returned ${noun} but none were downloadable`);\n }\n\n log(verbose, `Successfully generated ${out.length} ${req.kind}(s)`);\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForImageFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[google]', ...args);\n}\n\n// Model aliases for Nano Banana (Gemini native image generation)\nconst MODEL_ALIASES: Record<string, string> = {\n 'nano-banana': 'gemini-2.5-flash-image',\n 'nano-banana-pro': 'gemini-3-pro-image-preview',\n // Veo (video)\n veo2: 'veo-2.0-generate-001',\n 'veo-2': 'veo-2.0-generate-001',\n veo3: 'veo-3.0-generate-001',\n 'veo-3': 'veo-3.0-generate-001',\n 'veo-3.1': 'veo-3.1-generate-preview',\n veo31: 'veo-3.1-generate-preview',\n};\n\n// Veo 3.1 models that support advanced features (interpolation, reference images)\nconst VEO_31_MODELS = ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview'];\n\n/**\n * Check if model supports Veo 3.1 features (interpolation, reference images).\n */\nfunction isVeo31Model(model: string): boolean {\n return VEO_31_MODELS.some((m) => model.includes(m) || model.includes('veo-3.1'));\n}\n\n/**\n * Parse a data URI and extract base64 data and mime type.\n */\nfunction parseDataUri(dataUri: string): { data: string; mimeType: string } | null {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1] ?? 'image/png', data: match[2] ?? '' };\n}\n\n/**\n * Convert image input (URL or data URI) to format suitable for Google API.\n */\nfunction imageToGoogleFormat(\n imageInput: string\n): { inlineData: { data: string; mimeType: string } } | { fileUri: string } {\n // Data URI - extract base64\n if (imageInput.startsWith('data:')) {\n const parsed = parseDataUri(imageInput);\n if (parsed) {\n return { inlineData: { data: parsed.data, mimeType: parsed.mimeType } };\n }\n }\n // URL - use as file URI\n return { fileUri: imageInput };\n}\n\n// Gemini native image models (use generateContent with IMAGE modality)\nconst GEMINI_IMAGE_MODELS = ['gemini-2.5-flash-image', 'gemini-3-pro-image-preview'];\n\nfunction resolveModel(model: string | undefined): string {\n if (!model) return 'gemini-2.5-flash-image'; // Default: Nano Banana (fast)\n return MODEL_ALIASES[model] ?? model;\n}\n\nfunction isGeminiImageModel(model: string): boolean {\n return GEMINI_IMAGE_MODELS.some((m) => model.startsWith(m));\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Google video download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\nconst googleCapabilities: ProviderCapabilities = {\n maxInputImages: 3, // Veo 3.1 supports up to 3 reference images\n // Imagen / Veo aspect ratio is expressed as \"w:h\" (e.g. \"16:9\").\n // Public docs/examples focus on the common set below.\n supportedAspectRatios: ['1:1', '4:3', '3:4', '16:9', '9:16'],\n supportsVideoInterpolation: true, // Veo 3.1 supports first + last frame\n videoDurationRange: [4, 8], // Veo 3.1 supports 4, 6, 8 seconds\n supportsImageEditing: true,\n};\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen / Veo)',\n supports: ['image', 'video'],\n capabilities: googleCapabilities,\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n log(\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n const ai = new GoogleGenAI({ apiKey });\n\n if (req.kind === 'video') {\n // Default to Veo 3.1 if using advanced features, otherwise Veo 2\n const hasAdvancedFeatures = req.startFrame || req.endFrame || req.inputImages?.length;\n const defaultModel = hasAdvancedFeatures\n ? 'veo-3.1-generate-preview'\n : 'veo-2.0-generate-001';\n const model = MODEL_ALIASES[req.model ?? ''] ?? req.model ?? defaultModel;\n log('Using video model:', model);\n\n // Warn if using advanced features with non-Veo 3.1 model\n if (hasAdvancedFeatures && !isVeo31Model(model)) {\n log(\n 'WARNING: Advanced video features (startFrame, endFrame, referenceImages) require Veo 3.1'\n );\n }\n\n return generateWithVeo(ai, model, req);\n }\n\n const model = resolveModel(req.model);\n log('Resolved model:', model);\n\n // Use Gemini native image generation for Gemini models\n if (isGeminiImageModel(model)) {\n log('Using Gemini native image generation');\n return generateWithGemini(ai, model, req);\n }\n\n // Use Imagen API for imagen-* models\n log('Using Imagen API');\n return generateWithImagen(ai, model, req);\n },\n};\n\n// Generate videos using Veo via Gemini API.\nasync function generateWithVeo(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Veo video generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n // Build config for generateVideos\n const config: Record<string, unknown> = {\n numberOfVideos: req.n,\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n // Add duration if specified (Veo 3.1 supports 4, 6, 8)\n ...(req.duration !== undefined ? { durationSeconds: String(req.duration) } : {}),\n };\n\n // Build reference images array for Veo 3.1 (up to 3 images)\n if (req.inputImages?.length && isVeo31Model(model)) {\n const referenceImages = req.inputImages.slice(0, 3).map((img) => {\n const imageData = imageToGoogleFormat(img);\n return {\n image: imageData,\n referenceType: 'asset' as const,\n };\n });\n (config as any).referenceImages = referenceImages;\n log('Added', referenceImages.length, 'reference images');\n }\n\n // Build generateVideos params\n const generateParams: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n config,\n };\n\n // Add image (first frame) for Veo 3.1 image-to-video\n const firstFrameImage =\n req.startFrame ?? (req.inputImages?.length === 1 ? req.inputImages[0] : undefined);\n if (firstFrameImage && isVeo31Model(model)) {\n const imageData = imageToGoogleFormat(firstFrameImage);\n (generateParams as any).image = imageData;\n log('Added first frame image');\n }\n\n // Add lastFrame for Veo 3.1 interpolation\n if (req.endFrame && isVeo31Model(model)) {\n const lastFrameData = imageToGoogleFormat(req.endFrame);\n (config as any).lastFrame = lastFrameData;\n log('Added last frame for interpolation');\n }\n\n // The SDK returns a long-running operation. Poll until done.\n log('Calling ai.models.generateVideos...');\n let op = await ai.models.generateVideos(generateParams as any);\n\n log('Initial operation state:', op.done ? 'done' : 'pending', 'name:', (op as any).name);\n\n const maxAttempts = 60; // ~10 minutes at 10s\n const intervalMs = 10000;\n\n for (let attempt = 0; attempt < maxAttempts && !op.done; attempt++) {\n log(`Poll attempt ${attempt + 1}/${maxAttempts}...`);\n await sleep(intervalMs);\n op = await ai.operations.getVideosOperation({ operation: op });\n log(`Poll result: done=${op.done}`);\n }\n\n log(`Operation completed in ${Date.now() - startTime}ms`);\n\n if (!op.done) {\n log('Timed out. Operation state:', JSON.stringify(op).slice(0, 500));\n throw new Error('Google Veo video generation timed out');\n }\n\n const videos = op.response?.generatedVideos;\n log('Generated videos count:', videos?.length);\n\n if (!videos?.length) {\n log('Full response:', JSON.stringify(op.response).slice(0, 1000));\n throw new Error('Google Veo returned no videos');\n }\n\n const out: Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(videos.length, req.n); i++) {\n const v = videos[i];\n log(`Processing video ${i}:`, JSON.stringify(v).slice(0, 300));\n const uri = (v as any)?.video?.uri as string | undefined;\n if (!uri) {\n log(`Video ${i} has no URI, skipping`);\n continue;\n }\n\n // SDK may return gs:// URIs on Vertex; we only support downloadable http(s) URLs.\n if (uri.startsWith('gs://')) {\n throw new Error(\n `Google Veo returned a gs:// URI (${uri}). Configure outputGcsUri / Vertex flow to fetch from GCS.`\n );\n }\n\n const { bytes, mimeType } = await downloadBytes(uri);\n out.push({\n kind: 'video',\n provider: 'google',\n model,\n index: i,\n url: uri,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('Google Veo returned videos but none were downloadable');\n log(`Successfully generated ${out.length} video(s)`);\n return out;\n}\n\n// Generate images using Gemini native image generation\nasync function generateWithGemini(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n const hasInputImage = req.inputImages?.length;\n log(\n 'Starting Gemini image generation, model:',\n model,\n 'n:',\n req.n,\n 'hasInputImage:',\n !!hasInputImage\n );\n const startTime = Date.now();\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n // Build contents - either text prompt or multimodal with image for editing\n const buildContents = () => {\n if (hasInputImage && req.inputImages?.[0]) {\n // Multimodal content: image + text prompt for editing\n const imageData = imageToGoogleFormat(req.inputImages[0]);\n return [{ ...imageData }, { text: req.prompt }] as const;\n }\n // Text-only prompt\n return req.prompt;\n };\n\n // Gemini native image generation produces one image per call\n // Generate sequentially for n > 1\n for (let i = 0; i < req.n; i++) {\n log(`Generating image ${i + 1}/${req.n}...`);\n const callStart = Date.now();\n\n try {\n const res = await ai.models.generateContent({\n model,\n contents: buildContents() as any,\n config: {\n responseModalities: ['IMAGE'],\n // Gemini native image generation (Nano Banana) supports aspect ratio via imageConfig.\n // Note: when editing from an input image, the model may still bias toward the input image's aspect.\n ...(req.aspectRatio ? { imageConfig: { aspectRatio: req.aspectRatio } } : {}),\n },\n });\n\n log(`API call ${i + 1} took ${Date.now() - callStart}ms`);\n\n const parts = res.candidates?.[0]?.content?.parts;\n log(`Response has ${parts?.length ?? 0} parts`);\n\n if (!parts) {\n log(\n `No parts in response for image ${i}. Full response:`,\n JSON.stringify(res).slice(0, 500)\n );\n continue;\n }\n\n for (const part of parts) {\n if (part.inlineData?.data) {\n const rawBytes = part.inlineData.data;\n const bytes =\n typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes, mimeType: ${part.inlineData.mimeType}`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: part.inlineData.mimeType ?? mimeForImageFormat(req.format),\n });\n break; // One image per call\n }\n }\n } catch (err) {\n log(`Error generating image ${i}:`, err);\n throw err;\n }\n }\n\n log(`Total generation time: ${Date.now() - startTime}ms`);\n\n if (!out.length) throw new Error('Gemini returned no images');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n\n// Generate images using Imagen API\nasync function generateWithImagen(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Imagen generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n log('Calling ai.models.generateImages...');\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForImageFormat(req.format),\n // Imagen 4 supports aspectRatio\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n },\n });\n\n log(`API call took ${Date.now() - startTime}ms`);\n\n const imgs = res.generatedImages;\n log('Generated images count:', imgs?.length);\n\n if (!imgs?.length) {\n log('Full response:', JSON.stringify(res).slice(0, 1000));\n throw new Error('Google generateImages returned no images');\n }\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) {\n log(`Image ${i} has no bytes, skipping`);\n continue;\n }\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForImageFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[openai]', ...args);\n}\n\n/**\n * Convert a data URI to a Blob for FormData upload.\n */\nfunction dataUriToBlob(dataUri: string): Blob {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) throw new Error('Invalid data URI');\n const mimeType = match[1] ?? 'image/png';\n const base64 = match[2] ?? '';\n const binary = Buffer.from(base64, 'base64');\n return new Blob([binary], { type: mimeType });\n}\n\n/**\n * Fetch an image from URL and return as Blob.\n */\nasync function urlToBlob(url: string): Promise<Blob> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Failed to fetch image: ${res.status}`);\n return res.blob();\n}\n\n/**\n * Convert image input (data URI or URL) to a Blob.\n */\nasync function imageInputToBlob(input: string): Promise<Blob> {\n if (input.startsWith('data:')) {\n return dataUriToBlob(input);\n }\n return urlToBlob(input);\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\nfunction supportedAspectRatiosForModel(model: string): string[] {\n if (model.startsWith('gpt-image')) {\n // These map onto the 3 supported sizes.\n return ['1:1', '3:2', '4:3', '16:9', '2:3', '3:4', '9:16'];\n }\n if (model === 'dall-e-3') {\n return ['1:1', '4:3', '16:9', '3:4', '9:16'];\n }\n if (model === 'dall-e-2') {\n // DALL·E 2 only supports square sizes.\n return ['1:1'];\n }\n // Unknown model: we don't know what aspect ratios map to sizes.\n return [];\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim().replace(/\\s+/g, '');\n\n // gpt-image-* supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait)\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n } else if (model === 'dall-e-2') {\n if (ar === '1:1') return '1024x1024';\n }\n\n return undefined;\n}\n\nconst openaiCapabilities: ProviderCapabilities = {\n maxInputImages: 2, // image + optional mask\n supportsVideoInterpolation: false, // OpenAI doesn't support video\n // videoDurationRange omitted - no video support\n supportsImageEditing: true,\n};\n\n/**\n * Generate images using OpenAI's edit endpoint (for image editing with input images).\n */\nasync function generateWithEdit(\n req: GenerateRequest,\n apiKey: string,\n model: string\n): Promise<\n Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Using edit endpoint for image editing');\n const startTime = Date.now();\n\n // Build FormData for multipart upload\n const formData = new FormData();\n formData.append('model', model);\n formData.append('prompt', req.prompt);\n formData.append('n', String(req.n));\n\n // Add size if specified\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n if (size) formData.append('size', size);\n\n // Add the input image\n const imageInput = req.inputImages?.[0];\n if (!imageInput) throw new Error('No input image provided for editing');\n\n const imageBlob = await imageInputToBlob(imageInput);\n formData.append('image', imageBlob, 'image.png');\n log('Added input image to form data');\n\n // Add mask if provided (second input image)\n const maskInput = req.inputImages?.[1];\n if (maskInput) {\n const maskBlob = await imageInputToBlob(maskInput);\n formData.append('mask', maskBlob, 'mask.png');\n log('Added mask image to form data');\n }\n\n log('Calling OpenAI images/edits...');\n const res = await fetch(`${OPENAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n // Don't set content-type - FormData sets it with boundary\n },\n body: formData,\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI edit failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI edit returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully edited ${results.length} image(s)`);\n return results;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n supports: ['image'],\n capabilities: openaiCapabilities,\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n // Default to gpt-image-1 (stable), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n log('Using model:', model, 'hasInputImages:', !!req.inputImages?.length);\n\n // Use edit endpoint if input images provided\n if (req.inputImages?.length) {\n return generateWithEdit(req, apiKey, model);\n }\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling OpenAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n },\n};\n"],"mappings":"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","names":["process","path","process","fs","path","path","fs","log","downloadBytes","key","verboseMode","log","downloadBytes","sleep","model","verboseMode","log","downloadBytes","log","p","path","providers","process"]}
|
package/dist/index.js
CHANGED
|
@@ -256,8 +256,7 @@ async function generateXaiVideo(req, apiKey) {
|
|
|
256
256
|
prompt: req.prompt,
|
|
257
257
|
model,
|
|
258
258
|
...req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {},
|
|
259
|
-
|
|
260
|
-
...imageUrl ? { image_url: imageUrl } : {},
|
|
259
|
+
...imageUrl ? { image: { url: imageUrl } } : {},
|
|
261
260
|
// Add duration (xAI supports 1-15 seconds)
|
|
262
261
|
...req.duration !== void 0 ? { duration: req.duration } : {}
|
|
263
262
|
};
|
|
@@ -265,7 +264,7 @@ async function generateXaiVideo(req, apiKey) {
|
|
|
265
264
|
"Request body:",
|
|
266
265
|
JSON.stringify({
|
|
267
266
|
...createBody,
|
|
268
|
-
|
|
267
|
+
image: createBody.image ? { url: `...(${String(createBody.image.url).length} chars)` } : void 0
|
|
269
268
|
})
|
|
270
269
|
);
|
|
271
270
|
log("Calling xAI videos/generations...");
|
|
@@ -820,7 +819,10 @@ async function generateWithGemini(ai, model, req) {
|
|
|
820
819
|
model,
|
|
821
820
|
contents: buildContents(),
|
|
822
821
|
config: {
|
|
823
|
-
responseModalities: ["IMAGE"]
|
|
822
|
+
responseModalities: ["IMAGE"],
|
|
823
|
+
// Gemini native image generation (Nano Banana) supports aspect ratio via imageConfig.
|
|
824
|
+
// Note: when editing from an input image, the model may still bias toward the input image's aspect.
|
|
825
|
+
...req.aspectRatio ? { imageConfig: { aspectRatio: req.aspectRatio } } : {}
|
|
824
826
|
}
|
|
825
827
|
});
|
|
826
828
|
log3(`API call ${i + 1} took ${Date.now() - callStart}ms`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedMedia,\n GeneratedMediaPartial,\n MediaKind,\n OutputFormat,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport {\n makeOutputPath,\n resolveImageInput,\n resolveImageInputs,\n resolveOutDir,\n writeMediaFile,\n} from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[router]', ...args);\n}\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction defaultFormatForKind(kind: MediaKind): OutputFormat {\n return kind === 'video' ? 'mp4' : 'png';\n}\n\nasync function normalizeOptions(\n prompt: string,\n opts: GenerateOptions,\n verbose: boolean\n): Promise<GenerateRequest> {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const kind = opts.kind ?? 'image';\n const format = opts.format ?? defaultFormatForKind(kind);\n\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n // Resolve input images (convert local paths to data URIs)\n let inputImages: string[] | undefined;\n if (opts.inputImages?.length) {\n log(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);\n inputImages = await resolveImageInputs(opts.inputImages);\n log(verbose, `Resolved input images`);\n }\n\n // Resolve start/end frames for video\n let startFrame: string | undefined;\n let endFrame: string | undefined;\n\n if (opts.startFrame) {\n log(verbose, `Resolving start frame: ${opts.startFrame}`);\n startFrame = await resolveImageInput(opts.startFrame);\n }\n\n if (opts.endFrame) {\n log(verbose, `Resolving end frame: ${opts.endFrame}`);\n endFrame = await resolveImageInput(opts.endFrame);\n }\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n kind,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n // New fields\n inputImages,\n startFrame,\n endFrame,\n duration: opts.duration,\n };\n}\n\n/**\n * Validate request parameters against provider capabilities.\n */\nfunction validateRequestForProvider(req: GenerateRequest, provider: Provider): void {\n const caps = provider.capabilities;\n\n // Validate input images count\n const inputCount = req.inputImages?.length ?? 0;\n if (inputCount > caps.maxInputImages) {\n throw new Error(\n `Provider ${provider.id} supports max ${caps.maxInputImages} input image(s), but ${inputCount} provided`\n );\n }\n\n // Validate aspect ratio\n if (req.aspectRatio) {\n const normalized = req.aspectRatio.trim().replace(/\\s+/g, '');\n\n // Always enforce a basic w:h shape to avoid passing junk downstream.\n const looksLikeRatio = /^\\d+:\\d+$/.test(normalized);\n if (!looksLikeRatio) {\n throw new Error(`Invalid aspect ratio: \"${req.aspectRatio}\" (expected format: w:h)`);\n }\n\n // If provider has an allowlist and does NOT support arbitrary custom ratios, validate against it.\n if (\n caps.supportsCustomAspectRatio !== true &&\n Array.isArray(caps.supportedAspectRatios) &&\n caps.supportedAspectRatios.length\n ) {\n const ok = caps.supportedAspectRatios.includes(normalized);\n if (!ok) {\n throw new Error(\n `Provider ${provider.id} does not support aspect ratio \"${normalized}\". ` +\n `Supported: ${caps.supportedAspectRatios.join(', ')}`\n );\n }\n }\n }\n\n // Validate video interpolation (start + end frame)\n if (req.endFrame && !caps.supportsVideoInterpolation) {\n throw new Error(\n `Provider ${provider.id} does not support video interpolation (end frame). ` +\n `Only startFrame is supported for image-to-video.`\n );\n }\n\n // Validate duration range\n if (req.duration !== undefined && req.kind === 'video' && caps.videoDurationRange) {\n const [min, max] = caps.videoDurationRange;\n if (req.duration < min || req.duration > max) {\n throw new Error(\n `Provider ${provider.id} supports video duration ${min}-${max}s, but ${req.duration}s requested`\n );\n }\n }\n\n // Validate image editing support\n if (req.kind === 'image' && inputCount > 0 && !caps.supportsImageEditing) {\n throw new Error(`Provider ${provider.id} does not support image editing with input images`);\n }\n}\n\nexport async function generateMedia(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n const { env } = loadEnv(process.cwd());\n const verbose = Boolean(opts.verbose);\n\n // Normalize and resolve options (including reading input image files)\n const req = await normalizeOptions(prompt, opts, verbose);\n\n // Build a summary object for logging (truncate large data URIs)\n const reqSummary = {\n ...req,\n prompt: req.prompt.slice(0, 50) + '...',\n inputImages: req.inputImages?.map((img) =>\n img.startsWith('data:') ? `data:...${img.length} chars` : img\n ),\n startFrame: req.startFrame?.startsWith('data:')\n ? `data:...${req.startFrame.length} chars`\n : req.startFrame,\n endFrame: req.endFrame?.startsWith('data:')\n ? `data:...${req.endFrame.length} chars`\n : req.endFrame,\n };\n log(verbose, 'Request:', JSON.stringify(reqSummary));\n\n const provider = pickProvider(req.provider, env);\n log(verbose, 'Selected provider:', provider.id, '| supports:', provider.supports);\n\n if (!provider.supports.includes(req.kind)) {\n throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);\n }\n\n // Validate request against provider capabilities\n validateRequestForProvider(req, provider);\n\n log(verbose, 'Calling provider.generate()...');\n const startTime = Date.now();\n\n const partials = await provider.generate(req, env);\n\n log(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);\n\n const items: GeneratedMedia[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedMediaPartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i, p.mimeType);\n log(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);\n await writeMediaFile(filePath, p.bytes);\n items.push({ ...p, filePath });\n }\n\n log(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);\n return items;\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'image' });\n}\n\nexport async function generateVideo(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'video' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GenerateRequest, GeneratedMedia } from './types.js';\n\n/** Map file extensions to MIME types for images. */\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.avif': 'image/avif',\n '.heif': 'image/heif',\n '.heic': 'image/heic',\n};\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n case 'mp4':\n return 'mp4';\n case 'webm':\n return 'webm';\n case 'gif':\n return 'gif';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nfunction extensionFromMimeType(mimeType: string | undefined): string | undefined {\n if (!mimeType) return undefined;\n\n const t = mimeType.toLowerCase().split(';')[0]?.trim();\n if (!t) return undefined;\n\n // Images\n if (t === 'image/png') return 'png';\n if (t === 'image/jpeg') return 'jpg';\n if (t === 'image/webp') return 'webp';\n if (t === 'image/gif') return 'gif';\n if (t === 'image/avif') return 'avif';\n\n // Videos\n if (t === 'video/mp4') return 'mp4';\n if (t === 'video/webm') return 'webm';\n\n return undefined;\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number, mimeType?: string): string {\n // If user explicitly requested an output path, respect it verbatim.\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n // Some providers return a different MIME type than requested (e.g. JPEG bytes even if\n // --format png was requested). Prefer the actual MIME type for file extension to avoid\n // misleading file names.\n const ext = extensionFromMimeType(mimeType) ?? extensionForFormat(req.format);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeMediaFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(items: GeneratedMedia[]) {\n const images = items\n .filter((i) => i.kind === 'image')\n .map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n }));\n\n const videos = items\n .filter((i) => i.kind === 'video')\n .map((vid) => ({\n provider: vid.provider,\n model: vid.model,\n index: vid.index,\n filePath: vid.filePath,\n url: vid.url,\n bytes: vid.bytes.byteLength,\n mimeType: vid.mimeType,\n }));\n\n return {\n ...(images.length ? { images } : {}),\n ...(videos.length ? { videos } : {}),\n };\n}\n\n/**\n * Resolve an image input path or URL to a usable format.\n * - URLs (http/https) are returned as-is\n * - Data URIs are returned as-is\n * - Local file paths are read and converted to base64 data URIs\n *\n * @param pathOrUrl - A file path or URL to an image\n * @returns The resolved image as a URL or data URI\n */\nexport async function resolveImageInput(pathOrUrl: string): Promise<string> {\n // Already a URL (http/https)\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n // Already a data URI\n if (pathOrUrl.startsWith('data:')) {\n return pathOrUrl;\n }\n\n // Local file path - resolve and read\n const resolvedPath = path.isAbsolute(pathOrUrl)\n ? pathOrUrl\n : path.resolve(process.cwd(), pathOrUrl);\n\n const ext = path.extname(resolvedPath).toLowerCase();\n const mimeType = IMAGE_MIME_TYPES[ext];\n\n if (!mimeType) {\n throw new Error(\n `Unsupported image format: ${ext}. Supported: ${Object.keys(IMAGE_MIME_TYPES).join(', ')}`\n );\n }\n\n const fileBuffer = await fs.readFile(resolvedPath);\n const base64 = fileBuffer.toString('base64');\n\n return `data:${mimeType};base64,${base64}`;\n}\n\n/**\n * Resolve multiple image inputs in parallel.\n *\n * @param pathsOrUrls - Array of file paths or URLs\n * @returns Array of resolved images as URLs or data URIs\n */\nexport async function resolveImageInputs(pathsOrUrls: string[]): Promise<string[]> {\n return Promise.all(pathsOrUrls.map(resolveImageInput));\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\ntype XaiVideoGenerationResponse = {\n request_id?: string;\n};\n\ntype XaiVideoResultResponse = {\n // When pending\n status?: 'pending' | string;\n // When complete - video info is at top level, not nested in response\n video?: {\n duration?: number;\n respect_moderation?: boolean;\n url?: string | null;\n };\n model?: string;\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[xai]', ...args);\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Generate images using xAI's /v1/images/generations endpoint (text-to-image).\n */\nasync function generateXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n log('Starting image generation, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling xAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Edit images using xAI's /v1/images/edits endpoint (image-to-image).\n * Uses JSON format with image_url (data URI or URL).\n */\nasync function editXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n const inputImage = req.inputImages?.[0];\n if (!inputImage) throw new Error('No input image provided for editing');\n\n if ((req.inputImages?.length ?? 0) > 1) {\n throw new Error(\n 'xAI image editing supports only 1 input image (image_url). ' +\n 'Provide exactly one --input for xAI edits.'\n );\n }\n\n log('Starting image editing, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n image: { url: inputImage }, // Object with url field containing data URI or URL\n response_format: 'url',\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n };\n log('Request body:', JSON.stringify({ ...body, image: { url: '...(data uri)...' } }));\n\n log('Calling xAI images/edits...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI edits failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Process xAI image response and download images.\n */\nasync function processXaiImageResponse(json: XaiImagesResponse, model: string) {\n const results = [] as Array<{\n kind: 'image';\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n}\n\nasync function generateXaiVideo(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-video';\n\n // Get image URL from startFrame or inputImages[0]\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if ((req.inputImages?.length ?? 0) > 1 && !req.startFrame) {\n throw new Error(\n 'xAI video generation supports only 1 input image (image_url). ' +\n 'Provide exactly one --input or use --start-frame.'\n );\n }\n log(\n 'Starting video generation, model:',\n model,\n 'hasImageUrl:',\n !!imageUrl,\n 'duration:',\n req.duration\n );\n\n // xAI is async: create request_id, then poll /v1/videos/{request_id}\n // Note: xAI video API uses image_url as a string (data URI or URL), not an object\n const createBody: Record<string, unknown> = {\n prompt: req.prompt,\n model,\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Add image_url for image-to-video (data URI or URL string)\n ...(imageUrl ? { image_url: imageUrl } : {}),\n // Add duration (xAI supports 1-15 seconds)\n ...(req.duration !== undefined ? { duration: req.duration } : {}),\n };\n log(\n 'Request body:',\n JSON.stringify({\n ...createBody,\n image_url: createBody.image_url\n ? `...(${String(createBody.image_url).length} chars)`\n : undefined,\n })\n );\n\n log('Calling xAI videos/generations...');\n const startTime = Date.now();\n\n const createRes = await fetch(`${XAI_API_BASE}/videos/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(createBody),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${createRes.status}`);\n\n if (!createRes.ok) {\n const txt = await createRes.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI video generations failed (${createRes.status}): ${txt.slice(0, 500)}`);\n }\n\n const createJson = (await createRes.json()) as XaiVideoGenerationResponse;\n const requestId = createJson.request_id;\n log('Got request_id:', requestId);\n if (!requestId) throw new Error('xAI video generation returned no request_id');\n\n // Poll (best-effort). Video generation can take a while.\n const maxAttempts = 120; // ~6 minutes at 3s interval\n const intervalMs = 3000;\n\n let result: XaiVideoResultResponse | undefined;\n log(`Starting poll loop (max ${maxAttempts} attempts, ${intervalMs}ms interval)...`);\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const res = await fetch(`${XAI_API_BASE}/videos/${encodeURIComponent(requestId)}`, {\n method: 'GET',\n headers: {\n authorization: `Bearer ${apiKey}`,\n },\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log(`Poll attempt ${attempt + 1} failed:`, txt.slice(0, 500));\n throw new Error(`xAI video poll failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiVideoResultResponse;\n result = json;\n\n log(\n `Poll attempt ${attempt + 1}/${maxAttempts}: status=${json.status}, raw:`,\n JSON.stringify(json).slice(0, 300)\n );\n\n // xAI returns video object at top level (not nested in response) when complete\n if (json.video?.url) {\n log('Video generation complete!');\n break;\n }\n\n if (json.status === 'failed' || json.status === 'error') {\n log('Video generation failed:', JSON.stringify(json));\n throw new Error(`xAI video generation failed: ${JSON.stringify(json)}`);\n }\n\n await sleep(intervalMs);\n }\n\n if (!result?.video?.url) {\n log('Timed out. Last result:', JSON.stringify(result));\n throw new Error(`xAI video generation timed out (request_id=${requestId})`);\n }\n\n const url = result.video.url;\n log('Video URL:', url);\n\n // Check moderation status\n if (result.video?.respect_moderation === false) {\n throw new Error('xAI video generation was blocked by moderation');\n }\n\n const { bytes, mimeType } = await downloadBytes(url);\n\n log(`Successfully generated video, ${bytes.byteLength} bytes`);\n return [\n {\n kind: 'video' as const,\n provider: 'xai' as const,\n model: result.model ?? model,\n index: 0,\n url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n },\n ];\n}\n\nconst xaiCapabilities: ProviderCapabilities = {\n // xAI docs show a single image_url for edits and a single image_url for image-to-video.\n maxInputImages: 1,\n // xAI aspect_ratio examples show \"4:3\"; docs don't publish a strict allowlist.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: false, // xAI does not support end frame\n videoDurationRange: [1, 15], // 1-15 seconds\n supportsImageEditing: true,\n};\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI',\n supports: ['image', 'video'],\n capabilities: xaiCapabilities,\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n if (req.kind === 'video') return generateXaiVideo(req, apiKey);\n\n // Use edit endpoint if input images provided, otherwise generation\n const hasInputImages = req.inputImages && req.inputImages.length > 0;\n if (hasInputImages) {\n log('Input images detected, using edit endpoint');\n return editXaiImages(req, apiKey);\n }\n return generateXaiImages(req, apiKey);\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalMedia = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalMedia[];\n image?: FalMedia;\n videos?: FalMedia[];\n video?: FalMedia;\n};\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[fal]', ...args);\n}\n\nasync function downloadBytes(\n url: string,\n verbose: boolean\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log(verbose, 'Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(verbose, `Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nfunction pickMany(result: FalResult, kind: 'image' | 'video'): FalMedia[] {\n if (kind === 'image') {\n if (Array.isArray(result.images) && result.images.length) return result.images;\n if (result.image?.url) return [result.image];\n return [];\n }\n\n if (Array.isArray(result.videos) && result.videos.length) return result.videos;\n if (result.video?.url) return [result.video];\n return [];\n}\n\n// Default models per kind and input type\nconst DEFAULT_IMAGE_MODEL = 'fal-ai/flux/dev';\nconst DEFAULT_IMAGE_TO_IMAGE_MODEL = 'fal-ai/flux/dev/image-to-image';\nconst DEFAULT_VIDEO_MODEL = 'fal-ai/ltxv-2/text-to-video/fast'; // LTX Video 2.0 Fast - very quick\nconst DEFAULT_IMAGE_TO_VIDEO_MODEL = 'fal-ai/vidu/q2/image-to-video'; // Vidu Q2 for image-to-video\nconst DEFAULT_START_END_VIDEO_MODEL = 'fal-ai/vidu/start-end-to-video'; // Vidu for start-end interpolation\nconst DEFAULT_REFERENCE_VIDEO_MODEL = 'fal-ai/vidu/q2/reference-to-video'; // Vidu Q2 for reference images\n\n/**\n * Determine the best model based on request inputs.\n */\nfunction selectVideoModel(req: GenerateRequest): string {\n // User specified model takes precedence\n if (req.model) return req.model;\n\n // Start + End frame → interpolation model\n if (req.startFrame && req.endFrame) {\n return DEFAULT_START_END_VIDEO_MODEL;\n }\n\n // Reference images (inputImages without startFrame) → reference-to-video\n if (req.inputImages?.length && !req.startFrame) {\n return DEFAULT_REFERENCE_VIDEO_MODEL;\n }\n\n // Start frame only → image-to-video\n if (req.startFrame || req.inputImages?.length) {\n return DEFAULT_IMAGE_TO_VIDEO_MODEL;\n }\n\n // No images → text-to-video\n return DEFAULT_VIDEO_MODEL;\n}\n\n/**\n * Determine the best image model based on request inputs.\n */\nfunction selectImageModel(req: GenerateRequest): string {\n if (req.model) return req.model;\n if (req.inputImages?.length) return DEFAULT_IMAGE_TO_IMAGE_MODEL;\n return DEFAULT_IMAGE_MODEL;\n}\n\n/**\n * Map aspect ratio string to fal enum values.\n */\nfunction mapAspectRatio(aspectRatio?: string): string | undefined {\n if (!aspectRatio) return undefined;\n const ar = aspectRatio.trim();\n if (ar === '1:1') return 'square';\n if (ar === '4:3') return 'landscape_4_3';\n if (ar === '16:9') return 'landscape_16_9';\n if (ar === '3:4') return 'portrait_4_3';\n if (ar === '9:16') return 'portrait_16_9';\n return ar; // Pass through if not mapped\n}\n\n/**\n * Build input for video generation based on request parameters.\n */\nfunction buildVideoInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n // Start + End frame interpolation (Vidu start-end-to-video)\n if (req.startFrame && req.endFrame) {\n input.start_image_url = req.startFrame;\n input.end_image_url = req.endFrame;\n // Vidu supports movement_amplitude\n return input;\n }\n\n // Reference images (Vidu reference-to-video)\n if (req.inputImages?.length && !req.startFrame) {\n input.reference_image_urls = req.inputImages.slice(0, 7); // Max 7 reference images\n const ar = mapAspectRatio(req.aspectRatio);\n if (ar) input.aspect_ratio = ar;\n if (req.duration) input.duration = String(req.duration); // Vidu uses string enum\n return input;\n }\n\n // Single image → image-to-video\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if (imageUrl) {\n input.image_url = imageUrl;\n if (req.duration) input.duration = String(req.duration);\n return input;\n }\n\n // Text-to-video\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_videos = req.n;\n\n return input;\n}\n\n/**\n * Build input for image generation based on request parameters.\n */\nfunction buildImageInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_images = req.n;\n\n // Image-to-image: add input image\n if (req.inputImages?.[0]) {\n input.image_url = req.inputImages[0];\n // Common i2i parameters\n input.strength = 0.75; // Default strength for image-to-image\n }\n\n return input;\n}\n\nconst falCapabilities: ProviderCapabilities = {\n maxInputImages: 7, // Vidu supports up to 7 reference images\n // fal models vary. We map common ratios to enums, but also allow custom pass-through.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: true, // Vidu start-end-to-video\n videoDurationRange: [2, 8], // Vidu supports 2-8 seconds\n supportsImageEditing: true,\n};\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n supports: ['image', 'video'],\n capabilities: falCapabilities,\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n const verbose = req.verbose;\n log(verbose, 'Starting generation, kind:', req.kind, 'n:', req.n);\n log(\n verbose,\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Select model based on kind and inputs\n const model = req.kind === 'video' ? selectVideoModel(req) : selectImageModel(req);\n log(verbose, 'Selected model:', model);\n\n // Build input based on kind\n const input = req.kind === 'video' ? buildVideoInput(req) : buildImageInput(req);\n\n // Log input without large data URIs\n const inputSummary = { ...input };\n for (const key of ['image_url', 'start_image_url', 'end_image_url']) {\n if (\n typeof inputSummary[key] === 'string' &&\n (inputSummary[key] as string).startsWith('data:')\n ) {\n inputSummary[key] = `data:...${(inputSummary[key] as string).length} chars`;\n }\n }\n if (Array.isArray(inputSummary.reference_image_urls)) {\n inputSummary.reference_image_urls = (inputSummary.reference_image_urls as string[]).map(\n (url) => (url.startsWith('data:') ? `data:...${url.length} chars` : url)\n );\n }\n log(verbose, 'Request input:', JSON.stringify(inputSummary));\n\n log(verbose, 'Calling fal.subscribe...');\n const startTime = Date.now();\n\n const subscribeOptions: Parameters<typeof fal.subscribe>[1] = {\n input,\n logs: verbose,\n };\n if (verbose) {\n subscribeOptions.onQueueUpdate = (update) => {\n log(true, 'Queue update:', update.status, JSON.stringify(update).slice(0, 200));\n };\n }\n\n const result = (await fal.subscribe(model, subscribeOptions)) as { data: FalResult };\n\n log(verbose, `fal.subscribe completed in ${Date.now() - startTime}ms`);\n log(verbose, 'Raw result keys:', Object.keys(result?.data ?? {}));\n log(verbose, 'Result preview:', JSON.stringify(result?.data ?? {}).slice(0, 500));\n\n const items = pickMany(result?.data ?? {}, req.kind);\n log(verbose, `Found ${items.length} ${req.kind}(s) in response`);\n\n if (!items?.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(\n `fal returned no ${noun}. Raw response: ${JSON.stringify(result?.data).slice(0, 300)}`\n );\n }\n\n const out = [] as Array<{\n kind: 'image' | 'video';\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(items.length, req.n); i++) {\n const m = items[i];\n if (!m?.url) {\n log(verbose, `Item ${i} has no URL, skipping`);\n continue;\n }\n log(verbose, `Downloading item ${i}...`);\n const { bytes, mimeType } = await downloadBytes(m.url, verbose);\n const finalMimeType = m.content_type ?? mimeType;\n out.push({\n kind: req.kind,\n provider: 'fal',\n model,\n index: i,\n url: m.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(`fal returned ${noun} but none were downloadable`);\n }\n\n log(verbose, `Successfully generated ${out.length} ${req.kind}(s)`);\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForImageFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[google]', ...args);\n}\n\n// Model aliases for Nano Banana (Gemini native image generation)\nconst MODEL_ALIASES: Record<string, string> = {\n 'nano-banana': 'gemini-2.5-flash-image',\n 'nano-banana-pro': 'gemini-3-pro-image-preview',\n // Veo (video)\n veo2: 'veo-2.0-generate-001',\n 'veo-2': 'veo-2.0-generate-001',\n veo3: 'veo-3.0-generate-001',\n 'veo-3': 'veo-3.0-generate-001',\n 'veo-3.1': 'veo-3.1-generate-preview',\n veo31: 'veo-3.1-generate-preview',\n};\n\n// Veo 3.1 models that support advanced features (interpolation, reference images)\nconst VEO_31_MODELS = ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview'];\n\n/**\n * Check if model supports Veo 3.1 features (interpolation, reference images).\n */\nfunction isVeo31Model(model: string): boolean {\n return VEO_31_MODELS.some((m) => model.includes(m) || model.includes('veo-3.1'));\n}\n\n/**\n * Parse a data URI and extract base64 data and mime type.\n */\nfunction parseDataUri(dataUri: string): { data: string; mimeType: string } | null {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1] ?? 'image/png', data: match[2] ?? '' };\n}\n\n/**\n * Convert image input (URL or data URI) to format suitable for Google API.\n */\nfunction imageToGoogleFormat(\n imageInput: string\n): { inlineData: { data: string; mimeType: string } } | { fileUri: string } {\n // Data URI - extract base64\n if (imageInput.startsWith('data:')) {\n const parsed = parseDataUri(imageInput);\n if (parsed) {\n return { inlineData: { data: parsed.data, mimeType: parsed.mimeType } };\n }\n }\n // URL - use as file URI\n return { fileUri: imageInput };\n}\n\n// Gemini native image models (use generateContent with IMAGE modality)\nconst GEMINI_IMAGE_MODELS = ['gemini-2.5-flash-image', 'gemini-3-pro-image-preview'];\n\nfunction resolveModel(model: string | undefined): string {\n if (!model) return 'gemini-2.5-flash-image'; // Default: Nano Banana (fast)\n return MODEL_ALIASES[model] ?? model;\n}\n\nfunction isGeminiImageModel(model: string): boolean {\n return GEMINI_IMAGE_MODELS.some((m) => model.startsWith(m));\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Google video download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\nconst googleCapabilities: ProviderCapabilities = {\n maxInputImages: 3, // Veo 3.1 supports up to 3 reference images\n // Imagen / Veo aspect ratio is expressed as \"w:h\" (e.g. \"16:9\").\n // Public docs/examples focus on the common set below.\n supportedAspectRatios: ['1:1', '4:3', '3:4', '16:9', '9:16'],\n supportsVideoInterpolation: true, // Veo 3.1 supports first + last frame\n videoDurationRange: [4, 8], // Veo 3.1 supports 4, 6, 8 seconds\n supportsImageEditing: true,\n};\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen / Veo)',\n supports: ['image', 'video'],\n capabilities: googleCapabilities,\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n log(\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n const ai = new GoogleGenAI({ apiKey });\n\n if (req.kind === 'video') {\n // Default to Veo 3.1 if using advanced features, otherwise Veo 2\n const hasAdvancedFeatures = req.startFrame || req.endFrame || req.inputImages?.length;\n const defaultModel = hasAdvancedFeatures\n ? 'veo-3.1-generate-preview'\n : 'veo-2.0-generate-001';\n const model = MODEL_ALIASES[req.model ?? ''] ?? req.model ?? defaultModel;\n log('Using video model:', model);\n\n // Warn if using advanced features with non-Veo 3.1 model\n if (hasAdvancedFeatures && !isVeo31Model(model)) {\n log(\n 'WARNING: Advanced video features (startFrame, endFrame, referenceImages) require Veo 3.1'\n );\n }\n\n return generateWithVeo(ai, model, req);\n }\n\n const model = resolveModel(req.model);\n log('Resolved model:', model);\n\n // Use Gemini native image generation for Gemini models\n if (isGeminiImageModel(model)) {\n log('Using Gemini native image generation');\n return generateWithGemini(ai, model, req);\n }\n\n // Use Imagen API for imagen-* models\n log('Using Imagen API');\n return generateWithImagen(ai, model, req);\n },\n};\n\n// Generate videos using Veo via Gemini API.\nasync function generateWithVeo(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Veo video generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n // Build config for generateVideos\n const config: Record<string, unknown> = {\n numberOfVideos: req.n,\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n // Add duration if specified (Veo 3.1 supports 4, 6, 8)\n ...(req.duration !== undefined ? { durationSeconds: String(req.duration) } : {}),\n };\n\n // Build reference images array for Veo 3.1 (up to 3 images)\n if (req.inputImages?.length && isVeo31Model(model)) {\n const referenceImages = req.inputImages.slice(0, 3).map((img) => {\n const imageData = imageToGoogleFormat(img);\n return {\n image: imageData,\n referenceType: 'asset' as const,\n };\n });\n (config as any).referenceImages = referenceImages;\n log('Added', referenceImages.length, 'reference images');\n }\n\n // Build generateVideos params\n const generateParams: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n config,\n };\n\n // Add image (first frame) for Veo 3.1 image-to-video\n const firstFrameImage =\n req.startFrame ?? (req.inputImages?.length === 1 ? req.inputImages[0] : undefined);\n if (firstFrameImage && isVeo31Model(model)) {\n const imageData = imageToGoogleFormat(firstFrameImage);\n (generateParams as any).image = imageData;\n log('Added first frame image');\n }\n\n // Add lastFrame for Veo 3.1 interpolation\n if (req.endFrame && isVeo31Model(model)) {\n const lastFrameData = imageToGoogleFormat(req.endFrame);\n (config as any).lastFrame = lastFrameData;\n log('Added last frame for interpolation');\n }\n\n // The SDK returns a long-running operation. Poll until done.\n log('Calling ai.models.generateVideos...');\n let op = await ai.models.generateVideos(generateParams as any);\n\n log('Initial operation state:', op.done ? 'done' : 'pending', 'name:', (op as any).name);\n\n const maxAttempts = 60; // ~10 minutes at 10s\n const intervalMs = 10000;\n\n for (let attempt = 0; attempt < maxAttempts && !op.done; attempt++) {\n log(`Poll attempt ${attempt + 1}/${maxAttempts}...`);\n await sleep(intervalMs);\n op = await ai.operations.getVideosOperation({ operation: op });\n log(`Poll result: done=${op.done}`);\n }\n\n log(`Operation completed in ${Date.now() - startTime}ms`);\n\n if (!op.done) {\n log('Timed out. Operation state:', JSON.stringify(op).slice(0, 500));\n throw new Error('Google Veo video generation timed out');\n }\n\n const videos = op.response?.generatedVideos;\n log('Generated videos count:', videos?.length);\n\n if (!videos?.length) {\n log('Full response:', JSON.stringify(op.response).slice(0, 1000));\n throw new Error('Google Veo returned no videos');\n }\n\n const out: Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(videos.length, req.n); i++) {\n const v = videos[i];\n log(`Processing video ${i}:`, JSON.stringify(v).slice(0, 300));\n const uri = (v as any)?.video?.uri as string | undefined;\n if (!uri) {\n log(`Video ${i} has no URI, skipping`);\n continue;\n }\n\n // SDK may return gs:// URIs on Vertex; we only support downloadable http(s) URLs.\n if (uri.startsWith('gs://')) {\n throw new Error(\n `Google Veo returned a gs:// URI (${uri}). Configure outputGcsUri / Vertex flow to fetch from GCS.`\n );\n }\n\n const { bytes, mimeType } = await downloadBytes(uri);\n out.push({\n kind: 'video',\n provider: 'google',\n model,\n index: i,\n url: uri,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('Google Veo returned videos but none were downloadable');\n log(`Successfully generated ${out.length} video(s)`);\n return out;\n}\n\n// Generate images using Gemini native image generation\nasync function generateWithGemini(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n const hasInputImage = req.inputImages?.length;\n log(\n 'Starting Gemini image generation, model:',\n model,\n 'n:',\n req.n,\n 'hasInputImage:',\n !!hasInputImage\n );\n const startTime = Date.now();\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n // Build contents - either text prompt or multimodal with image for editing\n const buildContents = () => {\n if (hasInputImage && req.inputImages?.[0]) {\n // Multimodal content: image + text prompt for editing\n const imageData = imageToGoogleFormat(req.inputImages[0]);\n return [{ ...imageData }, { text: req.prompt }] as const;\n }\n // Text-only prompt\n return req.prompt;\n };\n\n // Gemini native image generation produces one image per call\n // Generate sequentially for n > 1\n for (let i = 0; i < req.n; i++) {\n log(`Generating image ${i + 1}/${req.n}...`);\n const callStart = Date.now();\n\n try {\n const res = await ai.models.generateContent({\n model,\n contents: buildContents() as any,\n config: {\n responseModalities: ['IMAGE'],\n },\n });\n\n log(`API call ${i + 1} took ${Date.now() - callStart}ms`);\n\n const parts = res.candidates?.[0]?.content?.parts;\n log(`Response has ${parts?.length ?? 0} parts`);\n\n if (!parts) {\n log(\n `No parts in response for image ${i}. Full response:`,\n JSON.stringify(res).slice(0, 500)\n );\n continue;\n }\n\n for (const part of parts) {\n if (part.inlineData?.data) {\n const rawBytes = part.inlineData.data;\n const bytes =\n typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes, mimeType: ${part.inlineData.mimeType}`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: part.inlineData.mimeType ?? mimeForImageFormat(req.format),\n });\n break; // One image per call\n }\n }\n } catch (err) {\n log(`Error generating image ${i}:`, err);\n throw err;\n }\n }\n\n log(`Total generation time: ${Date.now() - startTime}ms`);\n\n if (!out.length) throw new Error('Gemini returned no images');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n\n// Generate images using Imagen API\nasync function generateWithImagen(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Imagen generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n log('Calling ai.models.generateImages...');\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForImageFormat(req.format),\n // Imagen 4 supports aspectRatio\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n },\n });\n\n log(`API call took ${Date.now() - startTime}ms`);\n\n const imgs = res.generatedImages;\n log('Generated images count:', imgs?.length);\n\n if (!imgs?.length) {\n log('Full response:', JSON.stringify(res).slice(0, 1000));\n throw new Error('Google generateImages returned no images');\n }\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) {\n log(`Image ${i} has no bytes, skipping`);\n continue;\n }\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForImageFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[openai]', ...args);\n}\n\n/**\n * Convert a data URI to a Blob for FormData upload.\n */\nfunction dataUriToBlob(dataUri: string): Blob {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) throw new Error('Invalid data URI');\n const mimeType = match[1] ?? 'image/png';\n const base64 = match[2] ?? '';\n const binary = Buffer.from(base64, 'base64');\n return new Blob([binary], { type: mimeType });\n}\n\n/**\n * Fetch an image from URL and return as Blob.\n */\nasync function urlToBlob(url: string): Promise<Blob> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Failed to fetch image: ${res.status}`);\n return res.blob();\n}\n\n/**\n * Convert image input (data URI or URL) to a Blob.\n */\nasync function imageInputToBlob(input: string): Promise<Blob> {\n if (input.startsWith('data:')) {\n return dataUriToBlob(input);\n }\n return urlToBlob(input);\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\nfunction supportedAspectRatiosForModel(model: string): string[] {\n if (model.startsWith('gpt-image')) {\n // These map onto the 3 supported sizes.\n return ['1:1', '3:2', '4:3', '16:9', '2:3', '3:4', '9:16'];\n }\n if (model === 'dall-e-3') {\n return ['1:1', '4:3', '16:9', '3:4', '9:16'];\n }\n if (model === 'dall-e-2') {\n // DALL·E 2 only supports square sizes.\n return ['1:1'];\n }\n // Unknown model: we don't know what aspect ratios map to sizes.\n return [];\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim().replace(/\\s+/g, '');\n\n // gpt-image-* supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait)\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n } else if (model === 'dall-e-2') {\n if (ar === '1:1') return '1024x1024';\n }\n\n return undefined;\n}\n\nconst openaiCapabilities: ProviderCapabilities = {\n maxInputImages: 2, // image + optional mask\n supportsVideoInterpolation: false, // OpenAI doesn't support video\n // videoDurationRange omitted - no video support\n supportsImageEditing: true,\n};\n\n/**\n * Generate images using OpenAI's edit endpoint (for image editing with input images).\n */\nasync function generateWithEdit(\n req: GenerateRequest,\n apiKey: string,\n model: string\n): Promise<\n Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Using edit endpoint for image editing');\n const startTime = Date.now();\n\n // Build FormData for multipart upload\n const formData = new FormData();\n formData.append('model', model);\n formData.append('prompt', req.prompt);\n formData.append('n', String(req.n));\n\n // Add size if specified\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n if (size) formData.append('size', size);\n\n // Add the input image\n const imageInput = req.inputImages?.[0];\n if (!imageInput) throw new Error('No input image provided for editing');\n\n const imageBlob = await imageInputToBlob(imageInput);\n formData.append('image', imageBlob, 'image.png');\n log('Added input image to form data');\n\n // Add mask if provided (second input image)\n const maskInput = req.inputImages?.[1];\n if (maskInput) {\n const maskBlob = await imageInputToBlob(maskInput);\n formData.append('mask', maskBlob, 'mask.png');\n log('Added mask image to form data');\n }\n\n log('Calling OpenAI images/edits...');\n const res = await fetch(`${OPENAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n // Don't set content-type - FormData sets it with boundary\n },\n body: formData,\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI edit failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI edit returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully edited ${results.length} image(s)`);\n return results;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n supports: ['image'],\n capabilities: openaiCapabilities,\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n // Default to gpt-image-1 (stable), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n log('Using model:', model, 'hasInputImages:', !!req.inputImages?.length);\n\n // Use edit endpoint if input images provided\n if (req.inputImages?.length) {\n return generateWithEdit(req, apiKey, model);\n }\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling OpenAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n },\n};\n"],"mappings":"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","names":["path","process","fs","path","path","fs","log","downloadBytes","key","verboseMode","log","downloadBytes","sleep","model","verboseMode","log","downloadBytes","log","p","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedMedia,\n GeneratedMediaPartial,\n MediaKind,\n OutputFormat,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport {\n makeOutputPath,\n resolveImageInput,\n resolveImageInputs,\n resolveOutDir,\n writeMediaFile,\n} from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[router]', ...args);\n}\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction defaultFormatForKind(kind: MediaKind): OutputFormat {\n return kind === 'video' ? 'mp4' : 'png';\n}\n\nasync function normalizeOptions(\n prompt: string,\n opts: GenerateOptions,\n verbose: boolean\n): Promise<GenerateRequest> {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const kind = opts.kind ?? 'image';\n const format = opts.format ?? defaultFormatForKind(kind);\n\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n // Resolve input images (convert local paths to data URIs)\n let inputImages: string[] | undefined;\n if (opts.inputImages?.length) {\n log(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);\n inputImages = await resolveImageInputs(opts.inputImages);\n log(verbose, `Resolved input images`);\n }\n\n // Resolve start/end frames for video\n let startFrame: string | undefined;\n let endFrame: string | undefined;\n\n if (opts.startFrame) {\n log(verbose, `Resolving start frame: ${opts.startFrame}`);\n startFrame = await resolveImageInput(opts.startFrame);\n }\n\n if (opts.endFrame) {\n log(verbose, `Resolving end frame: ${opts.endFrame}`);\n endFrame = await resolveImageInput(opts.endFrame);\n }\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n kind,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n // New fields\n inputImages,\n startFrame,\n endFrame,\n duration: opts.duration,\n };\n}\n\n/**\n * Validate request parameters against provider capabilities.\n */\nfunction validateRequestForProvider(req: GenerateRequest, provider: Provider): void {\n const caps = provider.capabilities;\n\n // Validate input images count\n const inputCount = req.inputImages?.length ?? 0;\n if (inputCount > caps.maxInputImages) {\n throw new Error(\n `Provider ${provider.id} supports max ${caps.maxInputImages} input image(s), but ${inputCount} provided`\n );\n }\n\n // Validate aspect ratio\n if (req.aspectRatio) {\n const normalized = req.aspectRatio.trim().replace(/\\s+/g, '');\n\n // Always enforce a basic w:h shape to avoid passing junk downstream.\n const looksLikeRatio = /^\\d+:\\d+$/.test(normalized);\n if (!looksLikeRatio) {\n throw new Error(`Invalid aspect ratio: \"${req.aspectRatio}\" (expected format: w:h)`);\n }\n\n // If provider has an allowlist and does NOT support arbitrary custom ratios, validate against it.\n if (\n caps.supportsCustomAspectRatio !== true &&\n Array.isArray(caps.supportedAspectRatios) &&\n caps.supportedAspectRatios.length\n ) {\n const ok = caps.supportedAspectRatios.includes(normalized);\n if (!ok) {\n throw new Error(\n `Provider ${provider.id} does not support aspect ratio \"${normalized}\". ` +\n `Supported: ${caps.supportedAspectRatios.join(', ')}`\n );\n }\n }\n }\n\n // Validate video interpolation (start + end frame)\n if (req.endFrame && !caps.supportsVideoInterpolation) {\n throw new Error(\n `Provider ${provider.id} does not support video interpolation (end frame). ` +\n `Only startFrame is supported for image-to-video.`\n );\n }\n\n // Validate duration range\n if (req.duration !== undefined && req.kind === 'video' && caps.videoDurationRange) {\n const [min, max] = caps.videoDurationRange;\n if (req.duration < min || req.duration > max) {\n throw new Error(\n `Provider ${provider.id} supports video duration ${min}-${max}s, but ${req.duration}s requested`\n );\n }\n }\n\n // Validate image editing support\n if (req.kind === 'image' && inputCount > 0 && !caps.supportsImageEditing) {\n throw new Error(`Provider ${provider.id} does not support image editing with input images`);\n }\n}\n\nexport async function generateMedia(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n const { env } = loadEnv(process.cwd());\n const verbose = Boolean(opts.verbose);\n\n // Normalize and resolve options (including reading input image files)\n const req = await normalizeOptions(prompt, opts, verbose);\n\n // Build a summary object for logging (truncate large data URIs)\n const reqSummary = {\n ...req,\n prompt: req.prompt.slice(0, 50) + '...',\n inputImages: req.inputImages?.map((img) =>\n img.startsWith('data:') ? `data:...${img.length} chars` : img\n ),\n startFrame: req.startFrame?.startsWith('data:')\n ? `data:...${req.startFrame.length} chars`\n : req.startFrame,\n endFrame: req.endFrame?.startsWith('data:')\n ? `data:...${req.endFrame.length} chars`\n : req.endFrame,\n };\n log(verbose, 'Request:', JSON.stringify(reqSummary));\n\n const provider = pickProvider(req.provider, env);\n log(verbose, 'Selected provider:', provider.id, '| supports:', provider.supports);\n\n if (!provider.supports.includes(req.kind)) {\n throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);\n }\n\n // Validate request against provider capabilities\n validateRequestForProvider(req, provider);\n\n log(verbose, 'Calling provider.generate()...');\n const startTime = Date.now();\n\n const partials = await provider.generate(req, env);\n\n log(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);\n\n const items: GeneratedMedia[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedMediaPartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i, p.mimeType);\n log(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);\n await writeMediaFile(filePath, p.bytes);\n items.push({ ...p, filePath });\n }\n\n log(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);\n return items;\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'image' });\n}\n\nexport async function generateVideo(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedMedia[]> {\n return generateMedia(prompt, { ...opts, kind: 'video' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GenerateRequest, GeneratedMedia } from './types.js';\n\n/** Map file extensions to MIME types for images. */\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.avif': 'image/avif',\n '.heif': 'image/heif',\n '.heic': 'image/heic',\n};\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n case 'mp4':\n return 'mp4';\n case 'webm':\n return 'webm';\n case 'gif':\n return 'gif';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nfunction extensionFromMimeType(mimeType: string | undefined): string | undefined {\n if (!mimeType) return undefined;\n\n const t = mimeType.toLowerCase().split(';')[0]?.trim();\n if (!t) return undefined;\n\n // Images\n if (t === 'image/png') return 'png';\n if (t === 'image/jpeg') return 'jpg';\n if (t === 'image/webp') return 'webp';\n if (t === 'image/gif') return 'gif';\n if (t === 'image/avif') return 'avif';\n\n // Videos\n if (t === 'video/mp4') return 'mp4';\n if (t === 'video/webm') return 'webm';\n\n return undefined;\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number, mimeType?: string): string {\n // If user explicitly requested an output path, respect it verbatim.\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n // Some providers return a different MIME type than requested (e.g. JPEG bytes even if\n // --format png was requested). Prefer the actual MIME type for file extension to avoid\n // misleading file names.\n const ext = extensionFromMimeType(mimeType) ?? extensionForFormat(req.format);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeMediaFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(items: GeneratedMedia[]) {\n const images = items\n .filter((i) => i.kind === 'image')\n .map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n }));\n\n const videos = items\n .filter((i) => i.kind === 'video')\n .map((vid) => ({\n provider: vid.provider,\n model: vid.model,\n index: vid.index,\n filePath: vid.filePath,\n url: vid.url,\n bytes: vid.bytes.byteLength,\n mimeType: vid.mimeType,\n }));\n\n return {\n ...(images.length ? { images } : {}),\n ...(videos.length ? { videos } : {}),\n };\n}\n\n/**\n * Resolve an image input path or URL to a usable format.\n * - URLs (http/https) are returned as-is\n * - Data URIs are returned as-is\n * - Local file paths are read and converted to base64 data URIs\n *\n * @param pathOrUrl - A file path or URL to an image\n * @returns The resolved image as a URL or data URI\n */\nexport async function resolveImageInput(pathOrUrl: string): Promise<string> {\n // Already a URL (http/https)\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n // Already a data URI\n if (pathOrUrl.startsWith('data:')) {\n return pathOrUrl;\n }\n\n // Local file path - resolve and read\n const resolvedPath = path.isAbsolute(pathOrUrl)\n ? pathOrUrl\n : path.resolve(process.cwd(), pathOrUrl);\n\n const ext = path.extname(resolvedPath).toLowerCase();\n const mimeType = IMAGE_MIME_TYPES[ext];\n\n if (!mimeType) {\n throw new Error(\n `Unsupported image format: ${ext}. Supported: ${Object.keys(IMAGE_MIME_TYPES).join(', ')}`\n );\n }\n\n const fileBuffer = await fs.readFile(resolvedPath);\n const base64 = fileBuffer.toString('base64');\n\n return `data:${mimeType};base64,${base64}`;\n}\n\n/**\n * Resolve multiple image inputs in parallel.\n *\n * @param pathsOrUrls - Array of file paths or URLs\n * @returns Array of resolved images as URLs or data URIs\n */\nexport async function resolveImageInputs(pathsOrUrls: string[]): Promise<string[]> {\n return Promise.all(pathsOrUrls.map(resolveImageInput));\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\ntype XaiVideoGenerationResponse = {\n request_id?: string;\n};\n\ntype XaiVideoResultResponse = {\n // When pending\n status?: 'pending' | string;\n // When complete - video info is at top level, not nested in response\n video?: {\n duration?: number;\n respect_moderation?: boolean;\n url?: string | null;\n };\n model?: string;\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[xai]', ...args);\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Generate images using xAI's /v1/images/generations endpoint (text-to-image).\n */\nasync function generateXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n log('Starting image generation, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling xAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Edit images using xAI's /v1/images/edits endpoint (image-to-image).\n * Uses JSON format with image_url (data URI or URL).\n */\nasync function editXaiImages(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-image';\n const inputImage = req.inputImages?.[0];\n if (!inputImage) throw new Error('No input image provided for editing');\n\n if ((req.inputImages?.length ?? 0) > 1) {\n throw new Error(\n 'xAI image editing supports only 1 input image (image_url). ' +\n 'Provide exactly one --input for xAI edits.'\n );\n }\n\n log('Starting image editing, model:', model, 'n:', req.n);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n image: { url: inputImage }, // Object with url field containing data URI or URL\n response_format: 'url',\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n };\n log('Request body:', JSON.stringify({ ...body, image: { url: '...(data uri)...' } }));\n\n log('Calling xAI images/edits...');\n const startTime = Date.now();\n\n const res = await fetch(`${XAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI edits failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n return processXaiImageResponse(json, model);\n}\n\n/**\n * Process xAI image response and download images.\n */\nasync function processXaiImageResponse(json: XaiImagesResponse, model: string) {\n const results = [] as Array<{\n kind: 'image';\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n}\n\nasync function generateXaiVideo(req: GenerateRequest, apiKey: string) {\n const model = req.model ?? 'grok-imagine-video';\n\n // Get image URL from startFrame or inputImages[0]\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if ((req.inputImages?.length ?? 0) > 1 && !req.startFrame) {\n throw new Error(\n 'xAI video generation supports only 1 input image (image_url). ' +\n 'Provide exactly one --input or use --start-frame.'\n );\n }\n log(\n 'Starting video generation, model:',\n model,\n 'hasImageUrl:',\n !!imageUrl,\n 'duration:',\n req.duration\n );\n\n // xAI is async: create request_id, then poll /v1/videos/{request_id}\n // NOTE: xAI uses an OpenAI-like schema for image inputs. For video generation,\n // providing a plain `image_url` string may be accepted but ignored by the model.\n // Use the object form `{ image: { url } }` so --start-frame is actually applied.\n const createBody: Record<string, unknown> = {\n prompt: req.prompt,\n model,\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n ...(imageUrl ? { image: { url: imageUrl } } : {}),\n // Add duration (xAI supports 1-15 seconds)\n ...(req.duration !== undefined ? { duration: req.duration } : {}),\n };\n log(\n 'Request body:',\n JSON.stringify({\n ...createBody,\n image: createBody.image\n ? { url: `...(${String((createBody.image as any).url).length} chars)` }\n : undefined,\n })\n );\n\n log('Calling xAI videos/generations...');\n const startTime = Date.now();\n\n const createRes = await fetch(`${XAI_API_BASE}/videos/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(createBody),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${createRes.status}`);\n\n if (!createRes.ok) {\n const txt = await createRes.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`xAI video generations failed (${createRes.status}): ${txt.slice(0, 500)}`);\n }\n\n const createJson = (await createRes.json()) as XaiVideoGenerationResponse;\n const requestId = createJson.request_id;\n log('Got request_id:', requestId);\n if (!requestId) throw new Error('xAI video generation returned no request_id');\n\n // Poll (best-effort). Video generation can take a while.\n const maxAttempts = 120; // ~6 minutes at 3s interval\n const intervalMs = 3000;\n\n let result: XaiVideoResultResponse | undefined;\n log(`Starting poll loop (max ${maxAttempts} attempts, ${intervalMs}ms interval)...`);\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const res = await fetch(`${XAI_API_BASE}/videos/${encodeURIComponent(requestId)}`, {\n method: 'GET',\n headers: {\n authorization: `Bearer ${apiKey}`,\n },\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log(`Poll attempt ${attempt + 1} failed:`, txt.slice(0, 500));\n throw new Error(`xAI video poll failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiVideoResultResponse;\n result = json;\n\n log(\n `Poll attempt ${attempt + 1}/${maxAttempts}: status=${json.status}, raw:`,\n JSON.stringify(json).slice(0, 300)\n );\n\n // xAI returns video object at top level (not nested in response) when complete\n if (json.video?.url) {\n log('Video generation complete!');\n break;\n }\n\n if (json.status === 'failed' || json.status === 'error') {\n log('Video generation failed:', JSON.stringify(json));\n throw new Error(`xAI video generation failed: ${JSON.stringify(json)}`);\n }\n\n await sleep(intervalMs);\n }\n\n if (!result?.video?.url) {\n log('Timed out. Last result:', JSON.stringify(result));\n throw new Error(`xAI video generation timed out (request_id=${requestId})`);\n }\n\n const url = result.video.url;\n log('Video URL:', url);\n\n // Check moderation status\n if (result.video?.respect_moderation === false) {\n throw new Error('xAI video generation was blocked by moderation');\n }\n\n const { bytes, mimeType } = await downloadBytes(url);\n\n log(`Successfully generated video, ${bytes.byteLength} bytes`);\n return [\n {\n kind: 'video' as const,\n provider: 'xai' as const,\n model: result.model ?? model,\n index: 0,\n url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n },\n ];\n}\n\nconst xaiCapabilities: ProviderCapabilities = {\n // xAI docs show a single image_url for edits and a single image_url for image-to-video.\n maxInputImages: 1,\n // xAI aspect_ratio examples show \"4:3\"; docs don't publish a strict allowlist.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: false, // xAI does not support end frame\n videoDurationRange: [1, 15], // 1-15 seconds\n supportsImageEditing: true,\n};\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI',\n supports: ['image', 'video'],\n capabilities: xaiCapabilities,\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n if (req.kind === 'video') return generateXaiVideo(req, apiKey);\n\n // Use edit endpoint if input images provided, otherwise generation\n const hasInputImages = req.inputImages && req.inputImages.length > 0;\n if (hasInputImages) {\n log('Input images detected, using edit endpoint');\n return editXaiImages(req, apiKey);\n }\n return generateXaiImages(req, apiKey);\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalMedia = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalMedia[];\n image?: FalMedia;\n videos?: FalMedia[];\n video?: FalMedia;\n};\n\nfunction log(verbose: boolean, ...args: unknown[]) {\n if (verbose) console.error('[fal]', ...args);\n}\n\nasync function downloadBytes(\n url: string,\n verbose: boolean\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log(verbose, 'Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(verbose, `Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nfunction pickMany(result: FalResult, kind: 'image' | 'video'): FalMedia[] {\n if (kind === 'image') {\n if (Array.isArray(result.images) && result.images.length) return result.images;\n if (result.image?.url) return [result.image];\n return [];\n }\n\n if (Array.isArray(result.videos) && result.videos.length) return result.videos;\n if (result.video?.url) return [result.video];\n return [];\n}\n\n// Default models per kind and input type\nconst DEFAULT_IMAGE_MODEL = 'fal-ai/flux/dev';\nconst DEFAULT_IMAGE_TO_IMAGE_MODEL = 'fal-ai/flux/dev/image-to-image';\nconst DEFAULT_VIDEO_MODEL = 'fal-ai/ltxv-2/text-to-video/fast'; // LTX Video 2.0 Fast - very quick\nconst DEFAULT_IMAGE_TO_VIDEO_MODEL = 'fal-ai/vidu/q2/image-to-video'; // Vidu Q2 for image-to-video\nconst DEFAULT_START_END_VIDEO_MODEL = 'fal-ai/vidu/start-end-to-video'; // Vidu for start-end interpolation\nconst DEFAULT_REFERENCE_VIDEO_MODEL = 'fal-ai/vidu/q2/reference-to-video'; // Vidu Q2 for reference images\n\n/**\n * Determine the best model based on request inputs.\n */\nfunction selectVideoModel(req: GenerateRequest): string {\n // User specified model takes precedence\n if (req.model) return req.model;\n\n // Start + End frame → interpolation model\n if (req.startFrame && req.endFrame) {\n return DEFAULT_START_END_VIDEO_MODEL;\n }\n\n // Reference images (inputImages without startFrame) → reference-to-video\n if (req.inputImages?.length && !req.startFrame) {\n return DEFAULT_REFERENCE_VIDEO_MODEL;\n }\n\n // Start frame only → image-to-video\n if (req.startFrame || req.inputImages?.length) {\n return DEFAULT_IMAGE_TO_VIDEO_MODEL;\n }\n\n // No images → text-to-video\n return DEFAULT_VIDEO_MODEL;\n}\n\n/**\n * Determine the best image model based on request inputs.\n */\nfunction selectImageModel(req: GenerateRequest): string {\n if (req.model) return req.model;\n if (req.inputImages?.length) return DEFAULT_IMAGE_TO_IMAGE_MODEL;\n return DEFAULT_IMAGE_MODEL;\n}\n\n/**\n * Map aspect ratio string to fal enum values.\n */\nfunction mapAspectRatio(aspectRatio?: string): string | undefined {\n if (!aspectRatio) return undefined;\n const ar = aspectRatio.trim();\n if (ar === '1:1') return 'square';\n if (ar === '4:3') return 'landscape_4_3';\n if (ar === '16:9') return 'landscape_16_9';\n if (ar === '3:4') return 'portrait_4_3';\n if (ar === '9:16') return 'portrait_16_9';\n return ar; // Pass through if not mapped\n}\n\n/**\n * Build input for video generation based on request parameters.\n */\nfunction buildVideoInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n // Start + End frame interpolation (Vidu start-end-to-video)\n if (req.startFrame && req.endFrame) {\n input.start_image_url = req.startFrame;\n input.end_image_url = req.endFrame;\n // Vidu supports movement_amplitude\n return input;\n }\n\n // Reference images (Vidu reference-to-video)\n if (req.inputImages?.length && !req.startFrame) {\n input.reference_image_urls = req.inputImages.slice(0, 7); // Max 7 reference images\n const ar = mapAspectRatio(req.aspectRatio);\n if (ar) input.aspect_ratio = ar;\n if (req.duration) input.duration = String(req.duration); // Vidu uses string enum\n return input;\n }\n\n // Single image → image-to-video\n const imageUrl = req.startFrame ?? req.inputImages?.[0];\n if (imageUrl) {\n input.image_url = imageUrl;\n if (req.duration) input.duration = String(req.duration);\n return input;\n }\n\n // Text-to-video\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_videos = req.n;\n\n return input;\n}\n\n/**\n * Build input for image generation based on request parameters.\n */\nfunction buildImageInput(req: GenerateRequest): Record<string, unknown> {\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n };\n\n const imageSize = mapAspectRatio(req.aspectRatio);\n if (imageSize) input.image_size = imageSize;\n if (req.n) input.num_images = req.n;\n\n // Image-to-image: add input image\n if (req.inputImages?.[0]) {\n input.image_url = req.inputImages[0];\n // Common i2i parameters\n input.strength = 0.75; // Default strength for image-to-image\n }\n\n return input;\n}\n\nconst falCapabilities: ProviderCapabilities = {\n maxInputImages: 7, // Vidu supports up to 7 reference images\n // fal models vary. We map common ratios to enums, but also allow custom pass-through.\n supportsCustomAspectRatio: true,\n supportsVideoInterpolation: true, // Vidu start-end-to-video\n videoDurationRange: [2, 8], // Vidu supports 2-8 seconds\n supportsImageEditing: true,\n};\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n supports: ['image', 'video'],\n capabilities: falCapabilities,\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n const verbose = req.verbose;\n log(verbose, 'Starting generation, kind:', req.kind, 'n:', req.n);\n log(\n verbose,\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Select model based on kind and inputs\n const model = req.kind === 'video' ? selectVideoModel(req) : selectImageModel(req);\n log(verbose, 'Selected model:', model);\n\n // Build input based on kind\n const input = req.kind === 'video' ? buildVideoInput(req) : buildImageInput(req);\n\n // Log input without large data URIs\n const inputSummary = { ...input };\n for (const key of ['image_url', 'start_image_url', 'end_image_url']) {\n if (\n typeof inputSummary[key] === 'string' &&\n (inputSummary[key] as string).startsWith('data:')\n ) {\n inputSummary[key] = `data:...${(inputSummary[key] as string).length} chars`;\n }\n }\n if (Array.isArray(inputSummary.reference_image_urls)) {\n inputSummary.reference_image_urls = (inputSummary.reference_image_urls as string[]).map(\n (url) => (url.startsWith('data:') ? `data:...${url.length} chars` : url)\n );\n }\n log(verbose, 'Request input:', JSON.stringify(inputSummary));\n\n log(verbose, 'Calling fal.subscribe...');\n const startTime = Date.now();\n\n const subscribeOptions: Parameters<typeof fal.subscribe>[1] = {\n input,\n logs: verbose,\n };\n if (verbose) {\n subscribeOptions.onQueueUpdate = (update) => {\n log(true, 'Queue update:', update.status, JSON.stringify(update).slice(0, 200));\n };\n }\n\n const result = (await fal.subscribe(model, subscribeOptions)) as { data: FalResult };\n\n log(verbose, `fal.subscribe completed in ${Date.now() - startTime}ms`);\n log(verbose, 'Raw result keys:', Object.keys(result?.data ?? {}));\n log(verbose, 'Result preview:', JSON.stringify(result?.data ?? {}).slice(0, 500));\n\n const items = pickMany(result?.data ?? {}, req.kind);\n log(verbose, `Found ${items.length} ${req.kind}(s) in response`);\n\n if (!items?.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(\n `fal returned no ${noun}. Raw response: ${JSON.stringify(result?.data).slice(0, 300)}`\n );\n }\n\n const out = [] as Array<{\n kind: 'image' | 'video';\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(items.length, req.n); i++) {\n const m = items[i];\n if (!m?.url) {\n log(verbose, `Item ${i} has no URL, skipping`);\n continue;\n }\n log(verbose, `Downloading item ${i}...`);\n const { bytes, mimeType } = await downloadBytes(m.url, verbose);\n const finalMimeType = m.content_type ?? mimeType;\n out.push({\n kind: req.kind,\n provider: 'fal',\n model,\n index: i,\n url: m.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) {\n const noun = req.kind === 'video' ? 'videos' : 'images';\n throw new Error(`fal returned ${noun} but none were downloadable`);\n }\n\n log(verbose, `Successfully generated ${out.length} ${req.kind}(s)`);\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForImageFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[google]', ...args);\n}\n\n// Model aliases for Nano Banana (Gemini native image generation)\nconst MODEL_ALIASES: Record<string, string> = {\n 'nano-banana': 'gemini-2.5-flash-image',\n 'nano-banana-pro': 'gemini-3-pro-image-preview',\n // Veo (video)\n veo2: 'veo-2.0-generate-001',\n 'veo-2': 'veo-2.0-generate-001',\n veo3: 'veo-3.0-generate-001',\n 'veo-3': 'veo-3.0-generate-001',\n 'veo-3.1': 'veo-3.1-generate-preview',\n veo31: 'veo-3.1-generate-preview',\n};\n\n// Veo 3.1 models that support advanced features (interpolation, reference images)\nconst VEO_31_MODELS = ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview'];\n\n/**\n * Check if model supports Veo 3.1 features (interpolation, reference images).\n */\nfunction isVeo31Model(model: string): boolean {\n return VEO_31_MODELS.some((m) => model.includes(m) || model.includes('veo-3.1'));\n}\n\n/**\n * Parse a data URI and extract base64 data and mime type.\n */\nfunction parseDataUri(dataUri: string): { data: string; mimeType: string } | null {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1] ?? 'image/png', data: match[2] ?? '' };\n}\n\n/**\n * Convert image input (URL or data URI) to format suitable for Google API.\n */\nfunction imageToGoogleFormat(\n imageInput: string\n): { inlineData: { data: string; mimeType: string } } | { fileUri: string } {\n // Data URI - extract base64\n if (imageInput.startsWith('data:')) {\n const parsed = parseDataUri(imageInput);\n if (parsed) {\n return { inlineData: { data: parsed.data, mimeType: parsed.mimeType } };\n }\n }\n // URL - use as file URI\n return { fileUri: imageInput };\n}\n\n// Gemini native image models (use generateContent with IMAGE modality)\nconst GEMINI_IMAGE_MODELS = ['gemini-2.5-flash-image', 'gemini-3-pro-image-preview'];\n\nfunction resolveModel(model: string | undefined): string {\n if (!model) return 'gemini-2.5-flash-image'; // Default: Nano Banana (fast)\n return MODEL_ALIASES[model] ?? model;\n}\n\nfunction isGeminiImageModel(model: string): boolean {\n return GEMINI_IMAGE_MODELS.some((m) => model.startsWith(m));\n}\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Google video download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nasync function sleep(ms: number) {\n await new Promise((r) => setTimeout(r, ms));\n}\n\nconst googleCapabilities: ProviderCapabilities = {\n maxInputImages: 3, // Veo 3.1 supports up to 3 reference images\n // Imagen / Veo aspect ratio is expressed as \"w:h\" (e.g. \"16:9\").\n // Public docs/examples focus on the common set below.\n supportedAspectRatios: ['1:1', '4:3', '3:4', '16:9', '9:16'],\n supportsVideoInterpolation: true, // Veo 3.1 supports first + last frame\n videoDurationRange: [4, 8], // Veo 3.1 supports 4, 6, 8 seconds\n supportsImageEditing: true,\n};\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen / Veo)',\n supports: ['image', 'video'],\n capabilities: googleCapabilities,\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n log(\n 'Input images:',\n req.inputImages?.length ?? 0,\n 'startFrame:',\n !!req.startFrame,\n 'endFrame:',\n !!req.endFrame\n );\n\n const ai = new GoogleGenAI({ apiKey });\n\n if (req.kind === 'video') {\n // Default to Veo 3.1 if using advanced features, otherwise Veo 2\n const hasAdvancedFeatures = req.startFrame || req.endFrame || req.inputImages?.length;\n const defaultModel = hasAdvancedFeatures\n ? 'veo-3.1-generate-preview'\n : 'veo-2.0-generate-001';\n const model = MODEL_ALIASES[req.model ?? ''] ?? req.model ?? defaultModel;\n log('Using video model:', model);\n\n // Warn if using advanced features with non-Veo 3.1 model\n if (hasAdvancedFeatures && !isVeo31Model(model)) {\n log(\n 'WARNING: Advanced video features (startFrame, endFrame, referenceImages) require Veo 3.1'\n );\n }\n\n return generateWithVeo(ai, model, req);\n }\n\n const model = resolveModel(req.model);\n log('Resolved model:', model);\n\n // Use Gemini native image generation for Gemini models\n if (isGeminiImageModel(model)) {\n log('Using Gemini native image generation');\n return generateWithGemini(ai, model, req);\n }\n\n // Use Imagen API for imagen-* models\n log('Using Imagen API');\n return generateWithImagen(ai, model, req);\n },\n};\n\n// Generate videos using Veo via Gemini API.\nasync function generateWithVeo(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Veo video generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n // Build config for generateVideos\n const config: Record<string, unknown> = {\n numberOfVideos: req.n,\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n // Add duration if specified (Veo 3.1 supports 4, 6, 8)\n ...(req.duration !== undefined ? { durationSeconds: String(req.duration) } : {}),\n };\n\n // Build reference images array for Veo 3.1 (up to 3 images)\n if (req.inputImages?.length && isVeo31Model(model)) {\n const referenceImages = req.inputImages.slice(0, 3).map((img) => {\n const imageData = imageToGoogleFormat(img);\n return {\n image: imageData,\n referenceType: 'asset' as const,\n };\n });\n (config as any).referenceImages = referenceImages;\n log('Added', referenceImages.length, 'reference images');\n }\n\n // Build generateVideos params\n const generateParams: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n config,\n };\n\n // Add image (first frame) for Veo 3.1 image-to-video\n const firstFrameImage =\n req.startFrame ?? (req.inputImages?.length === 1 ? req.inputImages[0] : undefined);\n if (firstFrameImage && isVeo31Model(model)) {\n const imageData = imageToGoogleFormat(firstFrameImage);\n (generateParams as any).image = imageData;\n log('Added first frame image');\n }\n\n // Add lastFrame for Veo 3.1 interpolation\n if (req.endFrame && isVeo31Model(model)) {\n const lastFrameData = imageToGoogleFormat(req.endFrame);\n (config as any).lastFrame = lastFrameData;\n log('Added last frame for interpolation');\n }\n\n // The SDK returns a long-running operation. Poll until done.\n log('Calling ai.models.generateVideos...');\n let op = await ai.models.generateVideos(generateParams as any);\n\n log('Initial operation state:', op.done ? 'done' : 'pending', 'name:', (op as any).name);\n\n const maxAttempts = 60; // ~10 minutes at 10s\n const intervalMs = 10000;\n\n for (let attempt = 0; attempt < maxAttempts && !op.done; attempt++) {\n log(`Poll attempt ${attempt + 1}/${maxAttempts}...`);\n await sleep(intervalMs);\n op = await ai.operations.getVideosOperation({ operation: op });\n log(`Poll result: done=${op.done}`);\n }\n\n log(`Operation completed in ${Date.now() - startTime}ms`);\n\n if (!op.done) {\n log('Timed out. Operation state:', JSON.stringify(op).slice(0, 500));\n throw new Error('Google Veo video generation timed out');\n }\n\n const videos = op.response?.generatedVideos;\n log('Generated videos count:', videos?.length);\n\n if (!videos?.length) {\n log('Full response:', JSON.stringify(op.response).slice(0, 1000));\n throw new Error('Google Veo returned no videos');\n }\n\n const out: Array<{\n kind: 'video';\n provider: 'google';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(videos.length, req.n); i++) {\n const v = videos[i];\n log(`Processing video ${i}:`, JSON.stringify(v).slice(0, 300));\n const uri = (v as any)?.video?.uri as string | undefined;\n if (!uri) {\n log(`Video ${i} has no URI, skipping`);\n continue;\n }\n\n // SDK may return gs:// URIs on Vertex; we only support downloadable http(s) URLs.\n if (uri.startsWith('gs://')) {\n throw new Error(\n `Google Veo returned a gs:// URI (${uri}). Configure outputGcsUri / Vertex flow to fetch from GCS.`\n );\n }\n\n const { bytes, mimeType } = await downloadBytes(uri);\n out.push({\n kind: 'video',\n provider: 'google',\n model,\n index: i,\n url: uri,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('Google Veo returned videos but none were downloadable');\n log(`Successfully generated ${out.length} video(s)`);\n return out;\n}\n\n// Generate images using Gemini native image generation\nasync function generateWithGemini(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n const hasInputImage = req.inputImages?.length;\n log(\n 'Starting Gemini image generation, model:',\n model,\n 'n:',\n req.n,\n 'hasInputImage:',\n !!hasInputImage\n );\n const startTime = Date.now();\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n // Build contents - either text prompt or multimodal with image for editing\n const buildContents = () => {\n if (hasInputImage && req.inputImages?.[0]) {\n // Multimodal content: image + text prompt for editing\n const imageData = imageToGoogleFormat(req.inputImages[0]);\n return [{ ...imageData }, { text: req.prompt }] as const;\n }\n // Text-only prompt\n return req.prompt;\n };\n\n // Gemini native image generation produces one image per call\n // Generate sequentially for n > 1\n for (let i = 0; i < req.n; i++) {\n log(`Generating image ${i + 1}/${req.n}...`);\n const callStart = Date.now();\n\n try {\n const res = await ai.models.generateContent({\n model,\n contents: buildContents() as any,\n config: {\n responseModalities: ['IMAGE'],\n // Gemini native image generation (Nano Banana) supports aspect ratio via imageConfig.\n // Note: when editing from an input image, the model may still bias toward the input image's aspect.\n ...(req.aspectRatio ? { imageConfig: { aspectRatio: req.aspectRatio } } : {}),\n },\n });\n\n log(`API call ${i + 1} took ${Date.now() - callStart}ms`);\n\n const parts = res.candidates?.[0]?.content?.parts;\n log(`Response has ${parts?.length ?? 0} parts`);\n\n if (!parts) {\n log(\n `No parts in response for image ${i}. Full response:`,\n JSON.stringify(res).slice(0, 500)\n );\n continue;\n }\n\n for (const part of parts) {\n if (part.inlineData?.data) {\n const rawBytes = part.inlineData.data;\n const bytes =\n typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes, mimeType: ${part.inlineData.mimeType}`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: part.inlineData.mimeType ?? mimeForImageFormat(req.format),\n });\n break; // One image per call\n }\n }\n } catch (err) {\n log(`Error generating image ${i}:`, err);\n throw err;\n }\n }\n\n log(`Total generation time: ${Date.now() - startTime}ms`);\n\n if (!out.length) throw new Error('Gemini returned no images');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n\n// Generate images using Imagen API\nasync function generateWithImagen(\n ai: GoogleGenAI,\n model: string,\n req: GenerateRequest\n): Promise<\n Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Starting Imagen generation, model:', model, 'n:', req.n);\n const startTime = Date.now();\n\n log('Calling ai.models.generateImages...');\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForImageFormat(req.format),\n // Imagen 4 supports aspectRatio\n ...(req.aspectRatio ? { aspectRatio: req.aspectRatio } : {}),\n },\n });\n\n log(`API call took ${Date.now() - startTime}ms`);\n\n const imgs = res.generatedImages;\n log('Generated images count:', imgs?.length);\n\n if (!imgs?.length) {\n log('Full response:', JSON.stringify(res).slice(0, 1000));\n throw new Error('Google generateImages returned no images');\n }\n\n const out: Array<{\n kind: 'image';\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }> = [];\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) {\n log(`Image ${i} has no bytes, skipping`);\n continue;\n }\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n log(`Image ${i}: got ${bytes.byteLength} bytes`);\n out.push({\n kind: 'image',\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForImageFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n log(`Successfully generated ${out.length} image(s)`);\n return out;\n}\n","import type {\n GenerateRequest,\n Provider,\n ProviderCapabilities,\n ProviderEnv,\n} from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]) {\n if (verboseMode) console.error('[openai]', ...args);\n}\n\n/**\n * Convert a data URI to a Blob for FormData upload.\n */\nfunction dataUriToBlob(dataUri: string): Blob {\n const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) throw new Error('Invalid data URI');\n const mimeType = match[1] ?? 'image/png';\n const base64 = match[2] ?? '';\n const binary = Buffer.from(base64, 'base64');\n return new Blob([binary], { type: mimeType });\n}\n\n/**\n * Fetch an image from URL and return as Blob.\n */\nasync function urlToBlob(url: string): Promise<Blob> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Failed to fetch image: ${res.status}`);\n return res.blob();\n}\n\n/**\n * Convert image input (data URI or URL) to a Blob.\n */\nasync function imageInputToBlob(input: string): Promise<Blob> {\n if (input.startsWith('data:')) {\n return dataUriToBlob(input);\n }\n return urlToBlob(input);\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n log('Downloading from:', url.slice(0, 100) + '...');\n const start = Date.now();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n log(`Downloaded ${ab.byteLength} bytes in ${Date.now() - start}ms, type: ${ct}`);\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\nfunction supportedAspectRatiosForModel(model: string): string[] {\n if (model.startsWith('gpt-image')) {\n // These map onto the 3 supported sizes.\n return ['1:1', '3:2', '4:3', '16:9', '2:3', '3:4', '9:16'];\n }\n if (model === 'dall-e-3') {\n return ['1:1', '4:3', '16:9', '3:4', '9:16'];\n }\n if (model === 'dall-e-2') {\n // DALL·E 2 only supports square sizes.\n return ['1:1'];\n }\n // Unknown model: we don't know what aspect ratios map to sizes.\n return [];\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim().replace(/\\s+/g, '');\n\n // gpt-image-* supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait)\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n } else if (model === 'dall-e-2') {\n if (ar === '1:1') return '1024x1024';\n }\n\n return undefined;\n}\n\nconst openaiCapabilities: ProviderCapabilities = {\n maxInputImages: 2, // image + optional mask\n supportsVideoInterpolation: false, // OpenAI doesn't support video\n // videoDurationRange omitted - no video support\n supportsImageEditing: true,\n};\n\n/**\n * Generate images using OpenAI's edit endpoint (for image editing with input images).\n */\nasync function generateWithEdit(\n req: GenerateRequest,\n apiKey: string,\n model: string\n): Promise<\n Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>\n> {\n log('Using edit endpoint for image editing');\n const startTime = Date.now();\n\n // Build FormData for multipart upload\n const formData = new FormData();\n formData.append('model', model);\n formData.append('prompt', req.prompt);\n formData.append('n', String(req.n));\n\n // Add size if specified\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n if (size) formData.append('size', size);\n\n // Add the input image\n const imageInput = req.inputImages?.[0];\n if (!imageInput) throw new Error('No input image provided for editing');\n\n const imageBlob = await imageInputToBlob(imageInput);\n formData.append('image', imageBlob, 'image.png');\n log('Added input image to form data');\n\n // Add mask if provided (second input image)\n const maskInput = req.inputImages?.[1];\n if (maskInput) {\n const maskBlob = await imageInputToBlob(maskInput);\n formData.append('mask', maskBlob, 'mask.png');\n log('Added mask image to form data');\n }\n\n log('Calling OpenAI images/edits...');\n const res = await fetch(`${OPENAI_API_BASE}/images/edits`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n // Don't set content-type - FormData sets it with boundary\n },\n body: formData,\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI edit failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI edit returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully edited ${results.length} image(s)`);\n return results;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n supports: ['image'],\n capabilities: openaiCapabilities,\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n verboseMode = req.verbose;\n log('Provider initialized, kind:', req.kind);\n\n // Default to gpt-image-1 (stable), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n log('Using model:', model, 'hasInputImages:', !!req.inputImages?.length);\n\n // Use edit endpoint if input images provided\n if (req.inputImages?.length) {\n return generateWithEdit(req, apiKey, model);\n }\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n if (req.aspectRatio && !size) {\n const supported = supportedAspectRatiosForModel(model);\n throw new Error(\n `OpenAI model ${model} does not support aspect ratio \"${req.aspectRatio}\". ` +\n `Supported: ${supported.length ? supported.join(', ') : 'unknown (model not recognized)'}`\n );\n }\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n log('Request body:', JSON.stringify(body));\n\n log('Calling OpenAI images/generations...');\n const startTime = Date.now();\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n log(`API responded in ${Date.now() - startTime}ms, status: ${res.status}`);\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n log('Error response:', txt.slice(0, 1000));\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n log('Response data count:', json.data?.length);\n\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n kind: 'image';\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n log(`Processing image ${i}...`);\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n kind: 'image',\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n log(`Image ${i} is base64 encoded, ${img.b64_json.length} chars`);\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ kind: 'image', provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n log(`Successfully generated ${results.length} image(s)`);\n return results;\n },\n};\n"],"mappings":"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","names":["path","process","fs","path","path","fs","log","downloadBytes","key","verboseMode","log","downloadBytes","sleep","model","verboseMode","log","downloadBytes","log","p","path"]}
|