climage 0.2.2 → 0.3.0
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/README.md +161 -19
- package/dist/cli.js +1070 -166
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +48 -7
- package/dist/index.js +941 -114
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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 GeneratedImage,\n GeneratedImagePartial,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport { makeOutputPath, resolveOutDir, writeImageFile } 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\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 normalizeOptions(prompt: string, opts: GenerateOptions): GenerateRequest {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const format = opts.format ?? 'png';\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\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 };\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedImage[]> {\n const { env } = loadEnv(process.cwd());\n const req = normalizeOptions(prompt, opts);\n const provider = pickProvider(req.provider, env);\n\n const partials = await provider.generate(req, env);\n const images: GeneratedImage[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedImagePartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i);\n await writeImageFile(filePath, p.bytes);\n images.push({ ...p, filePath });\n }\n\n return images;\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 { GeneratedImage, GenerateRequest } from './types.js';\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 }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format);\n if (req.out) return path.resolve(process.cwd(), req.out);\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 writeImageFile(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(images: GeneratedImage[]) {\n return {\n images: images.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}\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 { GenerateRequest, Provider, ProviderEnv } 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\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI (grok-imagine-image)',\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 const model = req.model ?? 'grok-imagine-image';\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\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 if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n const results = [] as Array<{\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 if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\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 const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type { GenerateRequest, Provider, ProviderEnv } 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 FalImage = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalImage[];\n};\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\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 // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Default model: Flux dev (fast + popular). Can be overridden via --model.\n const model = req.model ?? 'fal-ai/flux/dev';\n\n // Map common aspect ratios to fal enums when possible.\n // If user passes e.g. 4:3, use landscape_4_3.\n let image_size: any = undefined;\n if (req.aspectRatio) {\n const ar = req.aspectRatio.trim();\n if (ar === '1:1') image_size = 'square';\n else if (ar === '4:3') image_size = 'landscape_4_3';\n else if (ar === '16:9') image_size = 'landscape_16_9';\n else if (ar === '3:4') image_size = 'portrait_4_3';\n else if (ar === '9:16') image_size = 'portrait_16_9';\n }\n\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n ...(image_size ? { image_size } : {}),\n // Some fal models support \"num_images\"; flux/dev returns images array length.\n ...(req.n ? { num_images: req.n } : {}),\n };\n\n const result = (await fal.subscribe(model, { input })) as { data: FalResult };\n\n const images = result?.data?.images;\n if (!images?.length) throw new Error('fal returned no images');\n\n const out = [] as Array<{\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(images.length, req.n); i++) {\n const img = images[i];\n if (!img?.url) continue;\n const { bytes, mimeType } = await downloadBytes(img.url);\n const finalMimeType = img.content_type ?? mimeType;\n out.push({\n provider: 'fal',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('fal returned images but none were downloadable');\n\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type { GenerateRequest, Provider, ProviderEnv } 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 mimeForFormat(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\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen)',\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 const ai = new GoogleGenAI({ apiKey });\n\n // Default to Imagen for pure text-to-image.\n const model = req.model ?? 'imagen-4.0-generate-001';\n\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForFormat(req.format),\n // Note: aspect ratio / size varies by model. Add later.\n },\n });\n\n const imgs = res.generatedImages;\n if (!imgs?.length) throw new Error('Google generateImages returned no images');\n\n const out = [] as Array<{\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) continue;\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n out.push({\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n return out;\n },\n};\n","import type { GenerateRequest, Provider, ProviderEnv } 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\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\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 return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\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();\n // gpt-image-1 supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), auto\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 }\n\n return undefined;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\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 // Default to gpt-image-1 (latest), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\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\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 if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\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 if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\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 const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n"],"mappings":"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","names":["path","process","fs","path","downloadBytes","downloadBytes","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 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);\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\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format);\n if (req.out) return path.resolve(process.cwd(), req.out);\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 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 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 maxInputImages: 1,\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 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 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\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();\n // gpt-image-1.5/1/1-mini supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), auto\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 }\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 (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\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"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "climage",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Generate images from the terminal via multiple providers (xAI, Google, fal)",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Generate images and videos from the terminal via multiple providers (xAI, Google, fal)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "",
|
|
7
7
|
"repository": {
|