climage 0.1.0 → 0.2.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 +118 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +117 -5
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -111,9 +111,17 @@ var xaiProvider = {
|
|
|
111
111
|
const results = [];
|
|
112
112
|
for (let i = 0; i < json.data.length; i++) {
|
|
113
113
|
const img = json.data[i];
|
|
114
|
+
if (!img) continue;
|
|
114
115
|
if (img.url) {
|
|
115
116
|
const { bytes, mimeType } = await downloadBytes(img.url);
|
|
116
|
-
results.push({
|
|
117
|
+
results.push({
|
|
118
|
+
provider: "xai",
|
|
119
|
+
model,
|
|
120
|
+
index: i,
|
|
121
|
+
url: img.url,
|
|
122
|
+
bytes,
|
|
123
|
+
...mimeType !== void 0 ? { mimeType } : {}
|
|
124
|
+
});
|
|
117
125
|
continue;
|
|
118
126
|
}
|
|
119
127
|
if (img.b64_json) {
|
|
@@ -173,7 +181,15 @@ var falProvider = {
|
|
|
173
181
|
const img = images[i];
|
|
174
182
|
if (!img?.url) continue;
|
|
175
183
|
const { bytes, mimeType } = await downloadBytes2(img.url);
|
|
176
|
-
|
|
184
|
+
const finalMimeType = img.content_type ?? mimeType;
|
|
185
|
+
out.push({
|
|
186
|
+
provider: "fal",
|
|
187
|
+
model,
|
|
188
|
+
index: i,
|
|
189
|
+
url: img.url,
|
|
190
|
+
bytes,
|
|
191
|
+
...finalMimeType !== void 0 ? { mimeType: finalMimeType } : {}
|
|
192
|
+
});
|
|
177
193
|
}
|
|
178
194
|
if (!out.length) throw new Error("fal returned images but none were downloadable");
|
|
179
195
|
return out;
|
|
@@ -224,15 +240,108 @@ var googleProvider = {
|
|
|
224
240
|
const rawBytes = img?.image?.imageBytes;
|
|
225
241
|
if (!rawBytes) continue;
|
|
226
242
|
const bytes = typeof rawBytes === "string" ? Uint8Array.from(Buffer.from(rawBytes, "base64")) : rawBytes;
|
|
227
|
-
out.push({
|
|
243
|
+
out.push({
|
|
244
|
+
provider: "google",
|
|
245
|
+
model,
|
|
246
|
+
index: i,
|
|
247
|
+
bytes,
|
|
248
|
+
mimeType: mimeForFormat(req.format)
|
|
249
|
+
});
|
|
228
250
|
}
|
|
229
251
|
if (!out.length) throw new Error("Google returned images but no bytes were present");
|
|
230
252
|
return out;
|
|
231
253
|
}
|
|
232
254
|
};
|
|
233
255
|
|
|
256
|
+
// src/providers/openai.ts
|
|
257
|
+
var OPENAI_API_BASE = "https://api.openai.com/v1";
|
|
258
|
+
function getOpenAIApiKey(env) {
|
|
259
|
+
return env.OPENAI_API_KEY || env.OPENAI_KEY;
|
|
260
|
+
}
|
|
261
|
+
async function downloadBytes3(url) {
|
|
262
|
+
const res = await fetch(url);
|
|
263
|
+
if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);
|
|
264
|
+
const ab = await res.arrayBuffer();
|
|
265
|
+
const ct = res.headers.get("content-type");
|
|
266
|
+
return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };
|
|
267
|
+
}
|
|
268
|
+
function mapAspectRatioToSize(aspectRatio, model) {
|
|
269
|
+
if (!aspectRatio) return void 0;
|
|
270
|
+
const ar = aspectRatio.trim();
|
|
271
|
+
if (model?.startsWith("gpt-image")) {
|
|
272
|
+
if (ar === "1:1") return "1024x1024";
|
|
273
|
+
if (ar === "3:2" || ar === "4:3" || ar === "16:9") return "1536x1024";
|
|
274
|
+
if (ar === "2:3" || ar === "3:4" || ar === "9:16") return "1024x1536";
|
|
275
|
+
} else if (model === "dall-e-3") {
|
|
276
|
+
if (ar === "1:1") return "1024x1024";
|
|
277
|
+
if (ar === "16:9" || ar === "4:3") return "1792x1024";
|
|
278
|
+
if (ar === "9:16" || ar === "3:4") return "1024x1792";
|
|
279
|
+
}
|
|
280
|
+
return void 0;
|
|
281
|
+
}
|
|
282
|
+
var openaiProvider = {
|
|
283
|
+
id: "openai",
|
|
284
|
+
displayName: "OpenAI (GPT Image / DALL-E)",
|
|
285
|
+
isAvailable(env) {
|
|
286
|
+
return Boolean(getOpenAIApiKey(env));
|
|
287
|
+
},
|
|
288
|
+
async generate(req, env) {
|
|
289
|
+
const apiKey = getOpenAIApiKey(env);
|
|
290
|
+
if (!apiKey) throw new Error("Missing OpenAI API key. Set OPENAI_API_KEY.");
|
|
291
|
+
const model = req.model ?? "gpt-image-1";
|
|
292
|
+
const size = mapAspectRatioToSize(req.aspectRatio, model);
|
|
293
|
+
const body = {
|
|
294
|
+
model,
|
|
295
|
+
prompt: req.prompt,
|
|
296
|
+
n: req.n,
|
|
297
|
+
...size ? { size } : {},
|
|
298
|
+
// gpt-image-1 doesn't support response_format, defaults to b64_json
|
|
299
|
+
// dall-e-2/3 support response_format
|
|
300
|
+
...!model.startsWith("gpt-image") ? { response_format: "url" } : {}
|
|
301
|
+
};
|
|
302
|
+
const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {
|
|
303
|
+
method: "POST",
|
|
304
|
+
headers: {
|
|
305
|
+
authorization: `Bearer ${apiKey}`,
|
|
306
|
+
"content-type": "application/json"
|
|
307
|
+
},
|
|
308
|
+
body: JSON.stringify(body)
|
|
309
|
+
});
|
|
310
|
+
if (!res.ok) {
|
|
311
|
+
const txt = await res.text().catch(() => "");
|
|
312
|
+
throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);
|
|
313
|
+
}
|
|
314
|
+
const json = await res.json();
|
|
315
|
+
if (!json.data?.length) throw new Error("OpenAI returned no images");
|
|
316
|
+
const results = [];
|
|
317
|
+
for (let i = 0; i < json.data.length; i++) {
|
|
318
|
+
const img = json.data[i];
|
|
319
|
+
if (!img) continue;
|
|
320
|
+
if (img.url) {
|
|
321
|
+
const dl = await downloadBytes3(img.url);
|
|
322
|
+
results.push({
|
|
323
|
+
provider: "openai",
|
|
324
|
+
model,
|
|
325
|
+
index: i,
|
|
326
|
+
url: img.url,
|
|
327
|
+
bytes: dl.bytes,
|
|
328
|
+
...dl.mimeType ? { mimeType: dl.mimeType } : {}
|
|
329
|
+
});
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (img.b64_json) {
|
|
333
|
+
const bytes = Uint8Array.from(Buffer.from(img.b64_json, "base64"));
|
|
334
|
+
results.push({ provider: "openai", model, index: i, bytes });
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
throw new Error("OpenAI returned image without url or b64_json");
|
|
338
|
+
}
|
|
339
|
+
return results;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
234
343
|
// src/core/router.ts
|
|
235
|
-
var providers = [googleProvider, xaiProvider, falProvider];
|
|
344
|
+
var providers = [googleProvider, xaiProvider, falProvider, openaiProvider];
|
|
236
345
|
function listProviders() {
|
|
237
346
|
return [...providers];
|
|
238
347
|
}
|
|
@@ -244,7 +353,10 @@ function pickProvider(id, env) {
|
|
|
244
353
|
return p2;
|
|
245
354
|
}
|
|
246
355
|
const p = providers.find((pp) => pp.isAvailable(env));
|
|
247
|
-
if (!p)
|
|
356
|
+
if (!p)
|
|
357
|
+
throw new Error(
|
|
358
|
+
"No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment."
|
|
359
|
+
);
|
|
248
360
|
return p;
|
|
249
361
|
}
|
|
250
362
|
function normalizeOptions(prompt, opts) {
|
|
@@ -309,6 +421,7 @@ Env:
|
|
|
309
421
|
GEMINI_API_KEY (or GOOGLE_API_KEY)
|
|
310
422
|
XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)
|
|
311
423
|
FAL_KEY (or FAL_API_KEY)
|
|
424
|
+
OPENAI_API_KEY
|
|
312
425
|
|
|
313
426
|
Examples:
|
|
314
427
|
npx climage "make image of kitten"
|
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"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process'\n\nimport { generateImage, listProviders } from './index.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 images (default: 1)\n --format <png|jpg|webp> Output format (default: png)\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 (xAI supports e.g. 4:3)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\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\nExamples:\n npx climage \"make image of kitten\"\n npx climage \"A cat in a tree\" --provider xai --n 4\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\n const take = (name: string): string => {\n const v = args.shift()\n if (!v) throw new Error(`Missing value for ${name}`)\n return v\n }\n\n while (args.length) {\n const a = args[0]\n if (!a) break\n if (a === '-h' || a === '--help') usage(0)\n if (a === '--json') {\n json = true\n args.shift()\n continue\n }\n if (!a.startsWith('-')) break\n\n args.shift()\n switch (a) {\n case '--provider':\n opts.provider = take(a) as ProviderId\n break\n case '--model':\n opts.model = take(a)\n break\n case '--n':\n opts.n = Number(take(a))\n break\n case '--format':\n opts.format = take(a) as any\n break\n case '--out':\n opts.out = take(a)\n break\n case '--outDir':\n opts.outDir = take(a)\n break\n case '--name':\n opts.name = take(a)\n break\n case '--aspect-ratio':\n opts.aspectRatio = take(a)\n break\n case '--verbose':\n opts.verbose = true\n break\n default:\n throw new Error(`Unknown option: ${a}`)\n }\n }\n\n const prompt = args.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 images = await generateImage(prompt, opts)\n\n if (json) {\n process.stdout.write(JSON.stringify({ images }, null, 2) + '\\n')\n return\n }\n\n for (const img of images) {\n process.stdout.write(img.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 { GenerateOptions, GenerateRequest, GeneratedImage, GeneratedImagePartial, Provider, ProviderEnv, ProviderId } 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'\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider]\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) throw new Error('No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.')\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(prompt: string, opts: GenerateOptions = {}): 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(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\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<{ provider: 'xai'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i]\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url)\n results.push({ provider: 'xai', model, index: i, url: img.url, bytes, mimeType })\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(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\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<{ provider: 'fal'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\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 out.push({ provider: 'fal', model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType })\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<{ provider: 'google'; model?: string; index: number; bytes: Uint8Array; mimeType?: string }>\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 = typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes\n out.push({ provider: 'google', model, index: i, bytes, mimeType: mimeForFormat(req.format) })\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present')\n return out\n },\n}\n"],"mappings":"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","names":["process","path","process","fs","path","downloadBytes","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 { generateImage, listProviders } from './index.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 images (default: 1)\n --format <png|jpg|webp> Output format (default: png)\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 (xAI supports e.g. 4:3)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\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`);\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\n const take = (name: string): string => {\n const v = args.shift();\n if (!v) throw new Error(`Missing value for ${name}`);\n return v;\n };\n\n while (args.length) {\n const a = args[0];\n if (!a) break;\n if (a === '-h' || a === '--help') usage(0);\n if (a === '--json') {\n json = true;\n args.shift();\n continue;\n }\n if (!a.startsWith('-')) break;\n\n args.shift();\n switch (a) {\n case '--provider':\n opts.provider = take(a) as ProviderId;\n break;\n case '--model':\n opts.model = take(a);\n break;\n case '--n':\n opts.n = Number(take(a));\n break;\n case '--format':\n opts.format = take(a) as any;\n break;\n case '--out':\n opts.out = take(a);\n break;\n case '--outDir':\n opts.outDir = take(a);\n break;\n case '--name':\n opts.name = take(a);\n break;\n case '--aspect-ratio':\n opts.aspectRatio = take(a);\n break;\n case '--verbose':\n opts.verbose = true;\n break;\n default:\n throw new Error(`Unknown option: ${a}`);\n }\n }\n\n const prompt = args.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 images = await generateImage(prompt, opts);\n\n if (json) {\n process.stdout.write(JSON.stringify({ images }, null, 2) + '\\n');\n return;\n }\n\n for (const img of images) {\n process.stdout.write(img.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 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":["process","path","process","fs","path","downloadBytes","downloadBytes","p","path","providers","process"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -106,9 +106,17 @@ var xaiProvider = {
|
|
|
106
106
|
const results = [];
|
|
107
107
|
for (let i = 0; i < json.data.length; i++) {
|
|
108
108
|
const img = json.data[i];
|
|
109
|
+
if (!img) continue;
|
|
109
110
|
if (img.url) {
|
|
110
111
|
const { bytes, mimeType } = await downloadBytes(img.url);
|
|
111
|
-
results.push({
|
|
112
|
+
results.push({
|
|
113
|
+
provider: "xai",
|
|
114
|
+
model,
|
|
115
|
+
index: i,
|
|
116
|
+
url: img.url,
|
|
117
|
+
bytes,
|
|
118
|
+
...mimeType !== void 0 ? { mimeType } : {}
|
|
119
|
+
});
|
|
112
120
|
continue;
|
|
113
121
|
}
|
|
114
122
|
if (img.b64_json) {
|
|
@@ -168,7 +176,15 @@ var falProvider = {
|
|
|
168
176
|
const img = images[i];
|
|
169
177
|
if (!img?.url) continue;
|
|
170
178
|
const { bytes, mimeType } = await downloadBytes2(img.url);
|
|
171
|
-
|
|
179
|
+
const finalMimeType = img.content_type ?? mimeType;
|
|
180
|
+
out.push({
|
|
181
|
+
provider: "fal",
|
|
182
|
+
model,
|
|
183
|
+
index: i,
|
|
184
|
+
url: img.url,
|
|
185
|
+
bytes,
|
|
186
|
+
...finalMimeType !== void 0 ? { mimeType: finalMimeType } : {}
|
|
187
|
+
});
|
|
172
188
|
}
|
|
173
189
|
if (!out.length) throw new Error("fal returned images but none were downloadable");
|
|
174
190
|
return out;
|
|
@@ -219,15 +235,108 @@ var googleProvider = {
|
|
|
219
235
|
const rawBytes = img?.image?.imageBytes;
|
|
220
236
|
if (!rawBytes) continue;
|
|
221
237
|
const bytes = typeof rawBytes === "string" ? Uint8Array.from(Buffer.from(rawBytes, "base64")) : rawBytes;
|
|
222
|
-
out.push({
|
|
238
|
+
out.push({
|
|
239
|
+
provider: "google",
|
|
240
|
+
model,
|
|
241
|
+
index: i,
|
|
242
|
+
bytes,
|
|
243
|
+
mimeType: mimeForFormat(req.format)
|
|
244
|
+
});
|
|
223
245
|
}
|
|
224
246
|
if (!out.length) throw new Error("Google returned images but no bytes were present");
|
|
225
247
|
return out;
|
|
226
248
|
}
|
|
227
249
|
};
|
|
228
250
|
|
|
251
|
+
// src/providers/openai.ts
|
|
252
|
+
var OPENAI_API_BASE = "https://api.openai.com/v1";
|
|
253
|
+
function getOpenAIApiKey(env) {
|
|
254
|
+
return env.OPENAI_API_KEY || env.OPENAI_KEY;
|
|
255
|
+
}
|
|
256
|
+
async function downloadBytes3(url) {
|
|
257
|
+
const res = await fetch(url);
|
|
258
|
+
if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);
|
|
259
|
+
const ab = await res.arrayBuffer();
|
|
260
|
+
const ct = res.headers.get("content-type");
|
|
261
|
+
return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };
|
|
262
|
+
}
|
|
263
|
+
function mapAspectRatioToSize(aspectRatio, model) {
|
|
264
|
+
if (!aspectRatio) return void 0;
|
|
265
|
+
const ar = aspectRatio.trim();
|
|
266
|
+
if (model?.startsWith("gpt-image")) {
|
|
267
|
+
if (ar === "1:1") return "1024x1024";
|
|
268
|
+
if (ar === "3:2" || ar === "4:3" || ar === "16:9") return "1536x1024";
|
|
269
|
+
if (ar === "2:3" || ar === "3:4" || ar === "9:16") return "1024x1536";
|
|
270
|
+
} else if (model === "dall-e-3") {
|
|
271
|
+
if (ar === "1:1") return "1024x1024";
|
|
272
|
+
if (ar === "16:9" || ar === "4:3") return "1792x1024";
|
|
273
|
+
if (ar === "9:16" || ar === "3:4") return "1024x1792";
|
|
274
|
+
}
|
|
275
|
+
return void 0;
|
|
276
|
+
}
|
|
277
|
+
var openaiProvider = {
|
|
278
|
+
id: "openai",
|
|
279
|
+
displayName: "OpenAI (GPT Image / DALL-E)",
|
|
280
|
+
isAvailable(env) {
|
|
281
|
+
return Boolean(getOpenAIApiKey(env));
|
|
282
|
+
},
|
|
283
|
+
async generate(req, env) {
|
|
284
|
+
const apiKey = getOpenAIApiKey(env);
|
|
285
|
+
if (!apiKey) throw new Error("Missing OpenAI API key. Set OPENAI_API_KEY.");
|
|
286
|
+
const model = req.model ?? "gpt-image-1";
|
|
287
|
+
const size = mapAspectRatioToSize(req.aspectRatio, model);
|
|
288
|
+
const body = {
|
|
289
|
+
model,
|
|
290
|
+
prompt: req.prompt,
|
|
291
|
+
n: req.n,
|
|
292
|
+
...size ? { size } : {},
|
|
293
|
+
// gpt-image-1 doesn't support response_format, defaults to b64_json
|
|
294
|
+
// dall-e-2/3 support response_format
|
|
295
|
+
...!model.startsWith("gpt-image") ? { response_format: "url" } : {}
|
|
296
|
+
};
|
|
297
|
+
const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {
|
|
298
|
+
method: "POST",
|
|
299
|
+
headers: {
|
|
300
|
+
authorization: `Bearer ${apiKey}`,
|
|
301
|
+
"content-type": "application/json"
|
|
302
|
+
},
|
|
303
|
+
body: JSON.stringify(body)
|
|
304
|
+
});
|
|
305
|
+
if (!res.ok) {
|
|
306
|
+
const txt = await res.text().catch(() => "");
|
|
307
|
+
throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);
|
|
308
|
+
}
|
|
309
|
+
const json = await res.json();
|
|
310
|
+
if (!json.data?.length) throw new Error("OpenAI returned no images");
|
|
311
|
+
const results = [];
|
|
312
|
+
for (let i = 0; i < json.data.length; i++) {
|
|
313
|
+
const img = json.data[i];
|
|
314
|
+
if (!img) continue;
|
|
315
|
+
if (img.url) {
|
|
316
|
+
const dl = await downloadBytes3(img.url);
|
|
317
|
+
results.push({
|
|
318
|
+
provider: "openai",
|
|
319
|
+
model,
|
|
320
|
+
index: i,
|
|
321
|
+
url: img.url,
|
|
322
|
+
bytes: dl.bytes,
|
|
323
|
+
...dl.mimeType ? { mimeType: dl.mimeType } : {}
|
|
324
|
+
});
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (img.b64_json) {
|
|
328
|
+
const bytes = Uint8Array.from(Buffer.from(img.b64_json, "base64"));
|
|
329
|
+
results.push({ provider: "openai", model, index: i, bytes });
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
throw new Error("OpenAI returned image without url or b64_json");
|
|
333
|
+
}
|
|
334
|
+
return results;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
229
338
|
// src/core/router.ts
|
|
230
|
-
var providers = [googleProvider, xaiProvider, falProvider];
|
|
339
|
+
var providers = [googleProvider, xaiProvider, falProvider, openaiProvider];
|
|
231
340
|
function listProviders() {
|
|
232
341
|
return [...providers];
|
|
233
342
|
}
|
|
@@ -239,7 +348,10 @@ function pickProvider(id, env) {
|
|
|
239
348
|
return p2;
|
|
240
349
|
}
|
|
241
350
|
const p = providers.find((pp) => pp.isAvailable(env));
|
|
242
|
-
if (!p)
|
|
351
|
+
if (!p)
|
|
352
|
+
throw new Error(
|
|
353
|
+
"No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment."
|
|
354
|
+
);
|
|
243
355
|
return p;
|
|
244
356
|
}
|
|
245
357
|
function normalizeOptions(prompt, opts) {
|
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"],"sourcesContent":["import path from 'node:path'\n\nimport type { GenerateOptions, GenerateRequest, GeneratedImage, GeneratedImagePartial, Provider, ProviderEnv, ProviderId } 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'\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider]\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) throw new Error('No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.')\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(prompt: string, opts: GenerateOptions = {}): 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(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\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<{ provider: 'xai'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i]\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url)\n results.push({ provider: 'xai', model, index: i, url: img.url, bytes, mimeType })\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(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\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<{ provider: 'fal'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\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 out.push({ provider: 'fal', model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType })\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<{ provider: 'google'; model?: string; index: number; bytes: Uint8Array; mimeType?: string }>\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 = typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes\n out.push({ provider: 'google', model, index: i, bytes, mimeType: mimeForFormat(req.format) })\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present')\n return out\n },\n}\n"],"mappings":";AAAA,OAAOA,WAAU;;;ACAjB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAOC,cAAa;AACpB,OAAO,YAAY;AASZ,SAAS,QAAQ,MAAMA,SAAQ,IAAI,GAAkB;AAC1D,QAAM,aAAa,CAAC,QAAQ,YAAY;AACxC,QAAM,cAAwB,CAAC;AAE/B,aAAW,QAAQ,YAAY;AAC7B,UAAM,IAAI,KAAK,KAAK,KAAK,IAAI;AAC7B,QAAI,CAAC,GAAG,WAAW,CAAC,EAAG;AACvB,WAAO,OAAO,EAAE,MAAM,GAAG,UAAU,MAAM,CAAC;AAC1C,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,SAAO,EAAE,KAAKA,SAAQ,KAAoB,YAAY;AACxD;;;ACxBA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAIV,SAAS,mBAAmB,QAA2C;AAC5E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEO,SAAS,cAAc,QAAwB;AACpD,SAAOA,MAAK,WAAW,MAAM,IAAI,SAASA,MAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;AAC9E;AAEO,SAAS,eAAe,KAAsB,OAAuB;AAC1E,QAAM,MAAM,mBAAmB,IAAI,MAAM;AACzC,MAAI,IAAI,IAAK,QAAOA,MAAK,QAAQ,QAAQ,IAAI,GAAG,IAAI,GAAG;AAEvD,QAAM,OAAO,GAAG,IAAI,QAAQ,IAAI,IAAI,SAAS;AAC7C,QAAM,SAAS,IAAI,IAAI,IAAI,IAAI,OAAO,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,KAAK;AACtE,QAAM,WAAW,GAAG,IAAI,GAAG,MAAM,IAAI,GAAG;AACxC,SAAOA,MAAK,KAAK,IAAI,QAAQ,QAAQ;AACvC;AAEA,eAAsB,eAAe,UAAkB,OAAkC;AACvF,QAAMD,IAAG,MAAMC,MAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,QAAMD,IAAG,UAAU,UAAU,KAAK;AACpC;;;ACjCO,SAAS,QAAQ,OAAe,SAAS,IAAY;AAC1D,QAAM,IAAI,MACP,KAAK,EACL,YAAY,EACZ,QAAQ,UAAU,EAAE,EACpB,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AAEzB,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,SAAS,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,QAAQ,EAAE,IAAI;AACtE;AAEO,SAAS,sBAAsB,IAAI,oBAAI,KAAK,GAAW;AAC5D,QAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,SACE,EAAE,YAAY,IACd,IAAI,EAAE,SAAS,IAAI,CAAC,IACpB,IAAI,EAAE,QAAQ,CAAC,IACf,MACA,IAAI,EAAE,SAAS,CAAC,IAChB,IAAI,EAAE,WAAW,CAAC,IAClB,IAAI,EAAE,WAAW,CAAC;AAEtB;;;ACrBA,IAAM,eAAe;AAErB,SAAS,aAAa,KAAsC;AAC1D,SAAO,IAAI,eAAe,IAAI,aAAa,IAAI;AACjD;AAYA,eAAe,cAAc,KAAgE;AAC3F,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,GAAG;AACxE,QAAM,KAAK,MAAM,IAAI,YAAY;AACjC,QAAM,KAAK,IAAI,QAAQ,IAAI,cAAc,KAAK;AAC9C,SAAO,EAAE,OAAO,IAAI,WAAW,EAAE,GAAG,UAAU,GAAG;AACnD;AAEO,IAAM,cAAwB;AAAA,EACnC,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,YAAY,KAAK;AACf,WAAO,QAAQ,aAAa,GAAG,CAAC;AAAA,EAClC;AAAA,EACA,MAAM,SAAS,KAAsB,KAAkB;AACrD,UAAM,SAAS,aAAa,GAAG;AAC/B,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,sDAAsD;AAEnF,UAAM,QAAQ,IAAI,SAAS;AAC3B,UAAM,OAAgC;AAAA,MACpC;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ,GAAG,IAAI;AAAA;AAAA,MAEP,GAAI,IAAI,cAAc,EAAE,cAAc,IAAI,YAAY,IAAI,CAAC;AAAA;AAAA,MAE3D,iBAAiB;AAAA,IACnB;AAEA,UAAM,MAAM,MAAM,MAAM,GAAG,YAAY,uBAAuB;AAAA,MAC5D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,MAAM;AAAA,QAC/B,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC3C,YAAM,IAAI,MAAM,2BAA2B,IAAI,MAAM,MAAM,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,IAChF;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAI,CAAC,KAAK,MAAM,OAAQ,OAAM,IAAI,MAAM,wBAAwB;AAEhE,UAAM,UAAU,CAAC;AAEjB,aAAS,IAAI,GAAG,IAAI,KAAK,KAAK,QAAQ,KAAK;AACzC,YAAM,MAAM,KAAK,KAAK,CAAC;AACvB,UAAI,IAAI,KAAK;AACX,cAAM,EAAE,OAAO,SAAS,IAAI,MAAM,cAAc,IAAI,GAAG;AACvD,gBAAQ,KAAK,EAAE,UAAU,OAAO,OAAO,OAAO,GAAG,KAAK,IAAI,KAAK,OAAO,SAAS,CAAC;AAChF;AAAA,MACF;AACA,UAAI,IAAI,UAAU;AAChB,cAAM,QAAQ,WAAW,KAAK,OAAO,KAAK,IAAI,UAAU,QAAQ,CAAC;AACjE,gBAAQ,KAAK,EAAE,UAAU,OAAO,OAAO,OAAO,GAAG,MAAM,CAAC;AACxD;AAAA,MACF;AACA,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT;AACF;;;ACnFA,SAAS,WAAW;AAIpB,SAAS,UAAU,KAAsC;AAEvD,SAAO,IAAI,eAAe,IAAI;AAChC;AAWA,eAAeE,eAAc,KAAgE;AAC3F,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,GAAG;AACxE,QAAM,KAAK,MAAM,IAAI,YAAY;AACjC,QAAM,KAAK,IAAI,QAAQ,IAAI,cAAc,KAAK;AAC9C,SAAO,EAAE,OAAO,IAAI,WAAW,EAAE,GAAG,UAAU,GAAG;AACnD;AAEO,IAAM,cAAwB;AAAA,EACnC,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,YAAY,KAAK;AACf,WAAO,QAAQ,UAAU,GAAG,CAAC;AAAA,EAC/B;AAAA,EACA,MAAM,SAAS,KAAsB,KAAkB;AACrD,UAAM,MAAM,UAAU,GAAG;AACzB,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,oDAAoD;AAG9E,QAAI,OAAO,EAAE,aAAa,IAAI,CAAC;AAG/B,UAAM,QAAQ,IAAI,SAAS;AAI3B,QAAI,aAAkB;AACtB,QAAI,IAAI,aAAa;AACnB,YAAM,KAAK,IAAI,YAAY,KAAK;AAChC,UAAI,OAAO,MAAO,cAAa;AAAA,eACtB,OAAO,MAAO,cAAa;AAAA,eAC3B,OAAO,OAAQ,cAAa;AAAA,eAC5B,OAAO,MAAO,cAAa;AAAA,eAC3B,OAAO,OAAQ,cAAa;AAAA,IACvC;AAEA,UAAM,QAAiC;AAAA,MACrC,QAAQ,IAAI;AAAA,MACZ,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA;AAAA,MAEnC,GAAI,IAAI,IAAI,EAAE,YAAY,IAAI,EAAE,IAAI,CAAC;AAAA,IACvC;AAEA,UAAM,SAAU,MAAM,IAAI,UAAU,OAAO,EAAE,MAAM,CAAC;AAEpD,UAAM,SAAS,QAAQ,MAAM;AAC7B,QAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,wBAAwB;AAE7D,UAAM,MAAM,CAAC;AAEb,aAAS,IAAI,GAAG,IAAI,KAAK,IAAI,OAAO,QAAQ,IAAI,CAAC,GAAG,KAAK;AACvD,YAAM,MAAM,OAAO,CAAC;AACpB,UAAI,CAAC,KAAK,IAAK;AACf,YAAM,EAAE,OAAO,SAAS,IAAI,MAAMA,eAAc,IAAI,GAAG;AACvD,UAAI,KAAK,EAAE,UAAU,OAAO,OAAO,OAAO,GAAG,KAAK,IAAI,KAAK,OAAO,UAAU,IAAI,gBAAgB,SAAS,CAAC;AAAA,IAC5G;AAEA,QAAI,CAAC,IAAI,OAAQ,OAAM,IAAI,MAAM,gDAAgD;AAEjF,WAAO;AAAA,EACT;AACF;;;AC/EA,SAAS,mBAAmB;AAI5B,SAAS,gBAAgB,KAAsC;AAE7D,SAAO,IAAI,kBAAkB,IAAI,kBAAkB,IAAI;AACzD;AAEA,SAAS,cAAc,QAA2C;AAChE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AAEO,IAAM,iBAA2B;AAAA,EACtC,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,YAAY,KAAK;AACf,WAAO,QAAQ,gBAAgB,GAAG,CAAC;AAAA,EACrC;AAAA,EACA,MAAM,SAAS,KAAsB,KAAkB;AACrD,UAAM,SAAS,gBAAgB,GAAG;AAClC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iEAAiE;AAE9F,UAAM,KAAK,IAAI,YAAY,EAAE,OAAO,CAAC;AAGrC,UAAM,QAAQ,IAAI,SAAS;AAE3B,UAAM,MAAM,MAAM,GAAG,OAAO,eAAe;AAAA,MACzC;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ,QAAQ;AAAA,QACN,gBAAgB,IAAI;AAAA,QACpB,gBAAgB,cAAc,IAAI,MAAM;AAAA;AAAA,MAE1C;AAAA,IACF,CAAC;AAED,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,0CAA0C;AAE7E,UAAM,MAAM,CAAC;AAEb,aAAS,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,KAAK;AACrD,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,WAAW,KAAK,OAAO;AAC7B,UAAI,CAAC,SAAU;AAEf,YAAM,QAAQ,OAAO,aAAa,WAC9B,WAAW,KAAK,OAAO,KAAK,UAAU,QAAQ,CAAC,IAC/C;AACJ,UAAI,KAAK,EAAE,UAAU,UAAU,OAAO,OAAO,GAAG,OAAO,UAAU,cAAc,IAAI,MAAM,EAAE,CAAC;AAAA,IAC9F;AAEA,QAAI,CAAC,IAAI,OAAQ,OAAM,IAAI,MAAM,kDAAkD;AACnF,WAAO;AAAA,EACT;AACF;;;ANvDA,IAAM,YAAwB,CAAC,gBAAgB,aAAa,WAAW;AAEhE,SAAS,gBAA4B;AAC1C,SAAO,CAAC,GAAG,SAAS;AACtB;AAEO,SAAS,aAAa,IAAgB,KAA4B;AACvE,MAAI,OAAO,QAAQ;AACjB,UAAMC,KAAI,UAAU,KAAK,CAACA,OAAMA,GAAE,OAAO,EAAE;AAC3C,QAAI,CAACA,GAAG,OAAM,IAAI,MAAM,qBAAqB,EAAE,EAAE;AACjD,QAAI,CAACA,GAAE,YAAY,GAAG,EAAG,OAAM,IAAI,MAAM,YAAY,EAAE,qCAAqC;AAC5F,WAAOA;AAAA,EACT;AAEA,QAAM,IAAI,UAAU,KAAK,CAAC,OAAO,GAAG,YAAY,GAAG,CAAC;AACpD,MAAI,CAAC,EAAG,OAAM,IAAI,MAAM,0FAA0F;AAClH,SAAO;AACT;AAEA,SAAS,iBAAiB,QAAgB,MAAwC;AAChF,QAAM,OAAO,KAAK,KAAK;AACvB,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC;AAEpD,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,SAAS,cAAc,KAAK,UAAU,GAAG;AAC/C,QAAM,YAAY,sBAAsB;AAExC,QAAM,WAAW,QAAQ,KAAK,QAAQ,MAAM;AAE5C,SAAO;AAAA,IACL;AAAA,IACA,UAAU,KAAK,YAAY;AAAA,IAC3B,OAAO,KAAK,SAAS;AAAA,IACrB;AAAA,IACA,aAAa,KAAK,eAAe;AAAA,IACjC;AAAA,IACA;AAAA,IACA,KAAK,KAAK,MAAMC,MAAK,QAAQ,QAAQ,IAAI,GAAG,KAAK,GAAG,IAAI;AAAA,IACxD;AAAA,IACA;AAAA,IACA,SAAS,QAAQ,KAAK,OAAO;AAAA,EAC/B;AACF;AAEA,eAAsB,cAAc,QAAgB,OAAwB,CAAC,GAA8B;AACzG,QAAM,EAAE,IAAI,IAAI,QAAQ,QAAQ,IAAI,CAAC;AACrC,QAAM,MAAM,iBAAiB,QAAQ,IAAI;AACzC,QAAM,WAAW,aAAa,IAAI,UAAU,GAAG;AAE/C,QAAM,WAAW,MAAM,SAAS,SAAS,KAAK,GAAG;AACjD,QAAM,SAA2B,CAAC;AAElC,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,IAAuC,SAAS,CAAC;AACvD,QAAI,CAAC,EAAG;AACR,UAAM,WAAW,eAAe,KAAK,CAAC;AACtC,UAAM,eAAe,UAAU,EAAE,KAAK;AACtC,WAAO,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC;AAAA,EAChC;AAEA,SAAO;AACT;","names":["path","process","fs","path","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 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"]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "climage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Generate images from the terminal via multiple providers (xAI, Google, fal)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/miguelm-bot/climage"
|
|
10
|
+
},
|
|
7
11
|
"type": "module",
|
|
8
12
|
"bin": {
|
|
9
13
|
"climage": "./dist/cli.js"
|