@djangocfg/imgai 2.1.41 → 2.1.43

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/bin.cjs CHANGED
@@ -1,275 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ var chalk = require('chalk');
4
5
  var commander = require('commander');
5
- var path2 = require('path');
6
- var url = require('url');
7
6
  var dotenv = require('dotenv');
8
- var chalk = require('chalk');
9
7
  var ora = require('ora');
10
- var inquirer = require('inquirer');
11
- var fs = require('fs-extra');
12
- var sharp = require('sharp');
8
+ var path = require('path');
9
+ var url = require('url');
10
+ var fs3 = require('fs-extra');
11
+ var glob = require('glob');
12
+ var sharp2 = require('sharp');
13
13
  var OpenAI = require('openai');
14
14
  var Anthropic = require('@anthropic-ai/sdk');
15
- var glob = require('glob');
15
+ var inquirer = require('inquirer');
16
16
 
17
17
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18
18
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
19
19
 
20
- var path2__default = /*#__PURE__*/_interopDefault(path2);
21
- var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
22
20
  var chalk__default = /*#__PURE__*/_interopDefault(chalk);
21
+ var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
23
22
  var ora__default = /*#__PURE__*/_interopDefault(ora);
24
- var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
25
- var fs__default = /*#__PURE__*/_interopDefault(fs);
26
- var sharp__default = /*#__PURE__*/_interopDefault(sharp);
23
+ var path__default = /*#__PURE__*/_interopDefault(path);
24
+ var fs3__default = /*#__PURE__*/_interopDefault(fs3);
25
+ var sharp2__default = /*#__PURE__*/_interopDefault(sharp2);
27
26
  var OpenAI__default = /*#__PURE__*/_interopDefault(OpenAI);
28
27
  var Anthropic__default = /*#__PURE__*/_interopDefault(Anthropic);
28
+ var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
29
29
 
30
- var ImageGenerator = class {
31
- config;
32
- openai;
33
- anthropic;
34
- constructor(config) {
35
- this.config = config;
36
- this.initializeProviders();
37
- }
38
- initializeProviders() {
39
- const openaiKey = this.config.openaiApiKey || process.env.OPENAI_API_KEY;
40
- const anthropicKey = this.config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
41
- if (openaiKey) {
42
- this.openai = new OpenAI__default.default({ apiKey: openaiKey });
43
- }
44
- if (anthropicKey) {
45
- this.anthropic = new Anthropic__default.default({ apiKey: anthropicKey });
46
- }
47
- if (!this.openai && this.config.provider === "openai") {
48
- throw new Error("OpenAI API key required. Set OPENAI_API_KEY or pass openaiApiKey in config.");
49
- }
50
- }
51
- // ──────────────────────────────────────────────────────────────────────────
52
- // SINGLE IMAGE GENERATION
53
- // ──────────────────────────────────────────────────────────────────────────
54
- async generate(options) {
55
- const startTime = Date.now();
56
- try {
57
- const fullPrompt = this.buildPrompt(options.prompt);
58
- const imageData = await this.generateWithOpenAI(fullPrompt);
59
- const filename = options.filename || this.generateFilename(options.prompt);
60
- const category = options.category || "general";
61
- const outputDir = path2__default.default.join(
62
- this.config.projectRoot,
63
- this.config.outputDir,
64
- category
65
- );
66
- await fs__default.default.ensureDir(outputDir);
67
- const originalPath = path2__default.default.join(outputDir, `${filename}.png`);
68
- await fs__default.default.writeFile(originalPath, Buffer.from(imageData, "base64"));
69
- const resizeOptions = options.resize || this.config.resize;
70
- let finalPath = originalPath;
71
- if (resizeOptions) {
72
- finalPath = await this.resizeImage(originalPath, resizeOptions);
73
- if (finalPath !== originalPath) {
74
- await fs__default.default.remove(originalPath);
75
- }
76
- }
77
- const imageInfo = await this.getImageInfo(finalPath, category);
78
- imageInfo.metadata = {
79
- prompt: options.prompt,
80
- caption: options.metadata?.caption,
81
- tags: options.tags,
82
- category,
83
- generatedAt: /* @__PURE__ */ new Date(),
84
- model: "dall-e-3"
85
- };
86
- const duration = Date.now() - startTime;
87
- return {
88
- success: true,
89
- imagePath: finalPath,
90
- imageUrl: imageInfo.url,
91
- imageInfo,
92
- duration
93
- };
94
- } catch (error) {
95
- return {
96
- success: false,
97
- error: error instanceof Error ? error.message : "Unknown error",
98
- duration: Date.now() - startTime
99
- };
100
- }
101
- }
102
- // ──────────────────────────────────────────────────────────────────────────
103
- // BATCH GENERATION
104
- // ──────────────────────────────────────────────────────────────────────────
105
- async generateBatch(options) {
106
- const startTime = Date.now();
107
- const results = [];
108
- const concurrency = options.concurrency || 2;
109
- const delayBetween = options.delayBetween || 2e3;
110
- for (let i = 0; i < options.items.length; i += concurrency) {
111
- const batch = options.items.slice(i, i + concurrency);
112
- const batchPromises = batch.map(async (item) => {
113
- const result = await this.generate({
114
- prompt: item.prompt,
115
- filename: item.filename,
116
- category: item.category
117
- });
118
- return result;
119
- });
120
- const batchResults = await Promise.all(batchPromises);
121
- for (const result of batchResults) {
122
- results.push(result);
123
- if (options.onProgress) {
124
- options.onProgress(results.length, options.items.length, result);
125
- }
126
- }
127
- if (i + concurrency < options.items.length) {
128
- await this.delay(delayBetween);
129
- }
130
- }
131
- return {
132
- total: results.length,
133
- success: results.filter((r) => r.success).length,
134
- failed: results.filter((r) => !r.success).length,
135
- results,
136
- duration: Date.now() - startTime
137
- };
138
- }
139
- // ──────────────────────────────────────────────────────────────────────────
140
- // PROMPT ENHANCEMENT (using Claude/GPT)
141
- // ──────────────────────────────────────────────────────────────────────────
142
- async enhancePrompt(basePrompt, context) {
143
- const systemPrompt = `You are an expert at creating image generation prompts.
144
- Given a description, create:
145
- 1. A detailed visual prompt (max 150 words) for DALL-E 3
146
- 2. A descriptive filename (lowercase, hyphens, max 30 chars)
147
- 3. A short caption (max 50 words)
148
-
149
- ${this.config.prefix ? `Style prefix: ${this.config.prefix}` : ""}
150
- ${this.config.suffix ? `Style suffix: ${this.config.suffix}` : ""}
151
-
152
- Return ONLY valid JSON: {"prompt": "...", "filename": "...", "caption": "..."}`;
153
- const userPrompt = context ? `Description: ${basePrompt}
154
- Context: ${context}` : `Description: ${basePrompt}`;
155
- if (this.anthropic && this.config.provider === "anthropic") {
156
- const response = await this.anthropic.messages.create({
157
- model: "claude-3-5-sonnet-20241022",
158
- max_tokens: 500,
159
- messages: [
160
- { role: "user", content: `${systemPrompt}
161
-
162
- ${userPrompt}` }
163
- ]
164
- });
165
- const text = response.content[0].type === "text" ? response.content[0].text : "";
166
- return JSON.parse(text);
167
- }
168
- if (this.openai) {
169
- const response = await this.openai.chat.completions.create({
170
- model: "gpt-4-turbo-preview",
171
- messages: [
172
- { role: "system", content: systemPrompt },
173
- { role: "user", content: userPrompt }
174
- ],
175
- max_tokens: 500,
176
- temperature: 0.7,
177
- response_format: { type: "json_object" }
178
- });
179
- const text = response.choices[0]?.message?.content || "{}";
180
- return JSON.parse(text);
181
- }
182
- throw new Error("No AI provider configured for prompt enhancement");
183
- }
184
- // ──────────────────────────────────────────────────────────────────────────
185
- // PRIVATE METHODS
186
- // ──────────────────────────────────────────────────────────────────────────
187
- async generateWithOpenAI(prompt) {
188
- if (!this.openai) {
189
- throw new Error("OpenAI client not initialized");
190
- }
191
- const response = await this.openai.images.generate({
192
- model: "dall-e-3",
193
- prompt,
194
- n: 1,
195
- size: this.config.size,
196
- quality: this.config.quality,
197
- style: this.config.dalleStyle || "natural",
198
- response_format: "b64_json"
199
- });
200
- const imageData = response.data?.[0]?.b64_json;
201
- if (!imageData) {
202
- throw new Error("No image data received from OpenAI");
203
- }
204
- return imageData;
205
- }
206
- async resizeImage(inputPath, options) {
207
- const { width, height, quality = 85, format = "webp", fit = "inside" } = options;
208
- let pipeline = sharp__default.default(inputPath);
209
- if (width || height) {
210
- pipeline = pipeline.resize(width, height, {
211
- fit,
212
- withoutEnlargement: true
213
- });
214
- }
215
- const outputPath = inputPath.replace(/\.[^.]+$/, `.${format}`);
216
- switch (format) {
217
- case "webp":
218
- pipeline = pipeline.webp({ quality });
219
- break;
220
- case "jpeg":
221
- pipeline = pipeline.jpeg({ quality });
222
- break;
223
- case "png":
224
- pipeline = pipeline.png({ quality });
225
- break;
226
- case "avif":
227
- pipeline = pipeline.avif({ quality });
228
- break;
229
- }
230
- await pipeline.toFile(outputPath);
231
- return outputPath;
232
- }
233
- async getImageInfo(imagePath, category) {
234
- const stats = await fs__default.default.stat(imagePath);
235
- const metadata = await sharp__default.default(imagePath).metadata();
236
- const filename = path2__default.default.basename(imagePath);
237
- const extension = path2__default.default.extname(filename).slice(1);
238
- const id = path2__default.default.basename(filename, path2__default.default.extname(filename));
239
- const publicDir = path2__default.default.join(this.config.projectRoot, this.config.publicDir);
240
- const relativePath = path2__default.default.relative(publicDir, imagePath);
241
- const url = "/" + relativePath.replace(/\\/g, "/");
242
- return {
243
- id,
244
- filename,
245
- extension,
246
- path: relativePath,
247
- url,
248
- size: stats.size,
249
- width: metadata.width,
250
- height: metadata.height,
251
- createdAt: stats.birthtime,
252
- modifiedAt: stats.mtime
253
- };
254
- }
255
- buildPrompt(basePrompt) {
256
- const parts = [];
257
- if (this.config.prefix) {
258
- parts.push(this.config.prefix);
259
- }
260
- parts.push(basePrompt);
261
- if (this.config.suffix) {
262
- parts.push(this.config.suffix);
263
- }
264
- return parts.join(" ");
265
- }
266
- generateFilename(prompt) {
267
- return prompt.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "-").substring(0, 30);
268
- }
269
- delay(ms) {
270
- return new Promise((resolve) => setTimeout(resolve, ms));
271
- }
272
- };
273
30
  var DEFAULT_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "avif", "gif", "svg"];
274
31
  var DEFAULT_DIRECTORIES = ["static/images", "images", "assets"];
275
32
  var ImageScanner = class {
@@ -288,15 +45,15 @@ var ImageScanner = class {
288
45
  includeDimensions = true,
289
46
  recursive = true
290
47
  } = options;
291
- const publicDir = path2__default.default.join(this.config.projectRoot, this.config.publicDir);
48
+ const publicDir = path__default.default.join(this.config.projectRoot, this.config.publicDir);
292
49
  const images = [];
293
50
  const byCategory = {};
294
51
  const byExtension = {};
295
52
  let totalSize = 0;
296
53
  const patterns = directories.flatMap((dir) => {
297
- const basePath = path2__default.default.join(publicDir, dir);
54
+ const basePath = path__default.default.join(publicDir, dir);
298
55
  const extPattern = `*.{${extensions.join(",")}}`;
299
- return recursive ? [path2__default.default.join(basePath, "**", extPattern)] : [path2__default.default.join(basePath, extPattern)];
56
+ return recursive ? [path__default.default.join(basePath, "**", extPattern)] : [path__default.default.join(basePath, extPattern)];
300
57
  });
301
58
  for (const pattern of patterns) {
302
59
  const files = await glob.glob(pattern, { nodir: true });
@@ -363,17 +120,17 @@ var ImageScanner = class {
363
120
  // PRIVATE METHODS
364
121
  // ──────────────────────────────────────────────────────────────────────────
365
122
  async processImage(filePath, publicDir, includeDimensions) {
366
- const stats = await fs__default.default.stat(filePath);
367
- const filename = path2__default.default.basename(filePath);
368
- const extension = path2__default.default.extname(filename).slice(1).toLowerCase();
369
- const id = path2__default.default.basename(filename, path2__default.default.extname(filename));
370
- const relativePath = path2__default.default.relative(publicDir, filePath).replace(/\\/g, "/");
123
+ const stats = await fs3__default.default.stat(filePath);
124
+ const filename = path__default.default.basename(filePath);
125
+ const extension = path__default.default.extname(filename).slice(1).toLowerCase();
126
+ const id = path__default.default.basename(filename, path__default.default.extname(filename));
127
+ const relativePath = path__default.default.relative(publicDir, filePath).replace(/\\/g, "/");
371
128
  const url = "/" + relativePath;
372
129
  let width;
373
130
  let height;
374
131
  if (includeDimensions && extension !== "svg") {
375
132
  try {
376
- const metadata = await sharp__default.default(filePath).metadata();
133
+ const metadata = await sharp2__default.default(filePath).metadata();
377
134
  width = metadata.width;
378
135
  height = metadata.height;
379
136
  } catch {
@@ -411,6 +168,8 @@ function formatDuration(ms) {
411
168
  if (ms < 1e3) return `${ms}ms`;
412
169
  return `${(ms / 1e3).toFixed(2)}s`;
413
170
  }
171
+
172
+ // src/config/generator.ts
414
173
  var ConfigGenerator = class {
415
174
  config;
416
175
  scanner;
@@ -423,10 +182,10 @@ var ConfigGenerator = class {
423
182
  // ──────────────────────────────────────────────────────────────────────────
424
183
  async generate() {
425
184
  const catalog = await this.scanner.buildCatalog();
426
- const outputPath = path2__default.default.join(this.config.projectRoot, this.config.configOutputPath);
427
- await fs__default.default.ensureDir(path2__default.default.dirname(outputPath));
185
+ const outputPath = path__default.default.join(this.config.projectRoot, this.config.configOutputPath);
186
+ await fs3__default.default.ensureDir(path__default.default.dirname(outputPath));
428
187
  const content = this.generateTypeScript(catalog);
429
- await fs__default.default.writeFile(outputPath, content, "utf-8");
188
+ await fs3__default.default.writeFile(outputPath, content, "utf-8");
430
189
  return outputPath;
431
190
  }
432
191
  // ──────────────────────────────────────────────────────────────────────────
@@ -542,8 +301,249 @@ export const IMAGE_CATALOG_META = {
542
301
  return ` '${category}': [${imageRefs.join(", ")}]`;
543
302
  }
544
303
  };
304
+ var ImageGenerator = class {
305
+ config;
306
+ openai;
307
+ anthropic;
308
+ constructor(config) {
309
+ this.config = config;
310
+ this.initializeProviders();
311
+ }
312
+ initializeProviders() {
313
+ const openaiKey = this.config.openaiApiKey || process.env.OPENAI_API_KEY;
314
+ const anthropicKey = this.config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
315
+ if (openaiKey) {
316
+ this.openai = new OpenAI__default.default({ apiKey: openaiKey });
317
+ }
318
+ if (anthropicKey) {
319
+ this.anthropic = new Anthropic__default.default({ apiKey: anthropicKey });
320
+ }
321
+ if (!this.openai && this.config.provider === "openai") {
322
+ throw new Error("OpenAI API key required. Set OPENAI_API_KEY or pass openaiApiKey in config.");
323
+ }
324
+ }
325
+ // ──────────────────────────────────────────────────────────────────────────
326
+ // SINGLE IMAGE GENERATION
327
+ // ──────────────────────────────────────────────────────────────────────────
328
+ async generate(options) {
329
+ const startTime = Date.now();
330
+ try {
331
+ const fullPrompt = this.buildPrompt(options.prompt);
332
+ const imageData = await this.generateWithOpenAI(fullPrompt);
333
+ const filename = options.filename || this.generateFilename(options.prompt);
334
+ const category = options.category || "general";
335
+ const outputDir = path__default.default.join(
336
+ this.config.projectRoot,
337
+ this.config.outputDir,
338
+ category
339
+ );
340
+ await fs3__default.default.ensureDir(outputDir);
341
+ const originalPath = path__default.default.join(outputDir, `${filename}.png`);
342
+ await fs3__default.default.writeFile(originalPath, Buffer.from(imageData, "base64"));
343
+ const resizeOptions = options.resize || this.config.resize;
344
+ let finalPath = originalPath;
345
+ if (resizeOptions) {
346
+ finalPath = await this.resizeImage(originalPath, resizeOptions);
347
+ if (finalPath !== originalPath) {
348
+ await fs3__default.default.remove(originalPath);
349
+ }
350
+ }
351
+ const imageInfo = await this.getImageInfo(finalPath, category);
352
+ imageInfo.metadata = {
353
+ prompt: options.prompt,
354
+ caption: options.metadata?.caption,
355
+ tags: options.tags,
356
+ category,
357
+ generatedAt: /* @__PURE__ */ new Date(),
358
+ model: "dall-e-3"
359
+ };
360
+ const duration = Date.now() - startTime;
361
+ return {
362
+ success: true,
363
+ imagePath: finalPath,
364
+ imageUrl: imageInfo.url,
365
+ imageInfo,
366
+ duration
367
+ };
368
+ } catch (error) {
369
+ return {
370
+ success: false,
371
+ error: error instanceof Error ? error.message : "Unknown error",
372
+ duration: Date.now() - startTime
373
+ };
374
+ }
375
+ }
376
+ // ──────────────────────────────────────────────────────────────────────────
377
+ // BATCH GENERATION
378
+ // ──────────────────────────────────────────────────────────────────────────
379
+ async generateBatch(options) {
380
+ const startTime = Date.now();
381
+ const results = [];
382
+ const concurrency = options.concurrency || 2;
383
+ const delayBetween = options.delayBetween || 2e3;
384
+ for (let i = 0; i < options.items.length; i += concurrency) {
385
+ const batch = options.items.slice(i, i + concurrency);
386
+ const batchPromises = batch.map(async (item) => {
387
+ const result = await this.generate({
388
+ prompt: item.prompt,
389
+ filename: item.filename,
390
+ category: item.category
391
+ });
392
+ return result;
393
+ });
394
+ const batchResults = await Promise.all(batchPromises);
395
+ for (const result of batchResults) {
396
+ results.push(result);
397
+ if (options.onProgress) {
398
+ options.onProgress(results.length, options.items.length, result);
399
+ }
400
+ }
401
+ if (i + concurrency < options.items.length) {
402
+ await this.delay(delayBetween);
403
+ }
404
+ }
405
+ return {
406
+ total: results.length,
407
+ success: results.filter((r) => r.success).length,
408
+ failed: results.filter((r) => !r.success).length,
409
+ results,
410
+ duration: Date.now() - startTime
411
+ };
412
+ }
413
+ // ──────────────────────────────────────────────────────────────────────────
414
+ // PROMPT ENHANCEMENT (using Claude/GPT)
415
+ // ──────────────────────────────────────────────────────────────────────────
416
+ async enhancePrompt(basePrompt, context) {
417
+ const systemPrompt = `You are an expert at creating image generation prompts.
418
+ Given a description, create:
419
+ 1. A detailed visual prompt (max 150 words) for DALL-E 3
420
+ 2. A descriptive filename (lowercase, hyphens, max 30 chars)
421
+ 3. A short caption (max 50 words)
422
+
423
+ ${this.config.prefix ? `Style prefix: ${this.config.prefix}` : ""}
424
+ ${this.config.suffix ? `Style suffix: ${this.config.suffix}` : ""}
425
+
426
+ Return ONLY valid JSON: {"prompt": "...", "filename": "...", "caption": "..."}`;
427
+ const userPrompt = context ? `Description: ${basePrompt}
428
+ Context: ${context}` : `Description: ${basePrompt}`;
429
+ if (this.anthropic && this.config.provider === "anthropic") {
430
+ const response = await this.anthropic.messages.create({
431
+ model: "claude-3-5-sonnet-20241022",
432
+ max_tokens: 500,
433
+ messages: [
434
+ { role: "user", content: `${systemPrompt}
545
435
 
546
- // src/cli/index.ts
436
+ ${userPrompt}` }
437
+ ]
438
+ });
439
+ const text = response.content[0].type === "text" ? response.content[0].text : "";
440
+ return JSON.parse(text);
441
+ }
442
+ if (this.openai) {
443
+ const response = await this.openai.chat.completions.create({
444
+ model: "gpt-4-turbo-preview",
445
+ messages: [
446
+ { role: "system", content: systemPrompt },
447
+ { role: "user", content: userPrompt }
448
+ ],
449
+ max_tokens: 500,
450
+ temperature: 0.7,
451
+ response_format: { type: "json_object" }
452
+ });
453
+ const text = response.choices[0]?.message?.content || "{}";
454
+ return JSON.parse(text);
455
+ }
456
+ throw new Error("No AI provider configured for prompt enhancement");
457
+ }
458
+ // ──────────────────────────────────────────────────────────────────────────
459
+ // PRIVATE METHODS
460
+ // ──────────────────────────────────────────────────────────────────────────
461
+ async generateWithOpenAI(prompt) {
462
+ if (!this.openai) {
463
+ throw new Error("OpenAI client not initialized");
464
+ }
465
+ const response = await this.openai.images.generate({
466
+ model: "dall-e-3",
467
+ prompt,
468
+ n: 1,
469
+ size: this.config.size,
470
+ quality: this.config.quality,
471
+ style: this.config.dalleStyle || "natural",
472
+ response_format: "b64_json"
473
+ });
474
+ const imageData = response.data?.[0]?.b64_json;
475
+ if (!imageData) {
476
+ throw new Error("No image data received from OpenAI");
477
+ }
478
+ return imageData;
479
+ }
480
+ async resizeImage(inputPath, options) {
481
+ const { width, height, quality = 85, format = "webp", fit = "inside" } = options;
482
+ let pipeline = sharp2__default.default(inputPath);
483
+ if (width || height) {
484
+ pipeline = pipeline.resize(width, height, {
485
+ fit,
486
+ withoutEnlargement: true
487
+ });
488
+ }
489
+ const outputPath = inputPath.replace(/\.[^.]+$/, `.${format}`);
490
+ switch (format) {
491
+ case "webp":
492
+ pipeline = pipeline.webp({ quality });
493
+ break;
494
+ case "jpeg":
495
+ pipeline = pipeline.jpeg({ quality });
496
+ break;
497
+ case "png":
498
+ pipeline = pipeline.png({ quality });
499
+ break;
500
+ case "avif":
501
+ pipeline = pipeline.avif({ quality });
502
+ break;
503
+ }
504
+ await pipeline.toFile(outputPath);
505
+ return outputPath;
506
+ }
507
+ async getImageInfo(imagePath, category) {
508
+ const stats = await fs3__default.default.stat(imagePath);
509
+ const metadata = await sharp2__default.default(imagePath).metadata();
510
+ const filename = path__default.default.basename(imagePath);
511
+ const extension = path__default.default.extname(filename).slice(1);
512
+ const id = path__default.default.basename(filename, path__default.default.extname(filename));
513
+ const publicDir = path__default.default.join(this.config.projectRoot, this.config.publicDir);
514
+ const relativePath = path__default.default.relative(publicDir, imagePath);
515
+ const url = "/" + relativePath.replace(/\\/g, "/");
516
+ return {
517
+ id,
518
+ filename,
519
+ extension,
520
+ path: relativePath,
521
+ url,
522
+ size: stats.size,
523
+ width: metadata.width,
524
+ height: metadata.height,
525
+ createdAt: stats.birthtime,
526
+ modifiedAt: stats.mtime
527
+ };
528
+ }
529
+ buildPrompt(basePrompt) {
530
+ const parts = [];
531
+ if (this.config.prefix) {
532
+ parts.push(this.config.prefix);
533
+ }
534
+ parts.push(basePrompt);
535
+ if (this.config.suffix) {
536
+ parts.push(this.config.suffix);
537
+ }
538
+ return parts.join(" ");
539
+ }
540
+ generateFilename(prompt) {
541
+ return prompt.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "-").substring(0, 30);
542
+ }
543
+ delay(ms) {
544
+ return new Promise((resolve) => setTimeout(resolve, ms));
545
+ }
546
+ };
547
547
  var ImageAICLI = class {
548
548
  config;
549
549
  generator;
@@ -873,10 +873,10 @@ var ImageAICLI = class {
873
873
 
874
874
  // src/cli/bin.ts
875
875
  var __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bin.cjs', document.baseURI).href)));
876
- var __dirname$1 = path2__default.default.dirname(__filename$1);
876
+ var __dirname$1 = path__default.default.dirname(__filename$1);
877
877
  dotenv__default.default.config();
878
- dotenv__default.default.config({ path: path2__default.default.resolve(process.cwd(), ".env.local") });
879
- dotenv__default.default.config({ path: path2__default.default.resolve(__dirname$1, "../../.env") });
878
+ dotenv__default.default.config({ path: path__default.default.resolve(process.cwd(), ".env.local") });
879
+ dotenv__default.default.config({ path: path__default.default.resolve(__dirname$1, "../../.env") });
880
880
  var program = new commander.Command();
881
881
  function createConfig(options) {
882
882
  const projectRoot = options.root || process.cwd();
@@ -974,7 +974,7 @@ program.command("batch").alias("b").description("Batch generate images from file
974
974
  const config = createConfig(options);
975
975
  const generator = new ImageGenerator(config);
976
976
  const fs4 = await import('fs-extra');
977
- const filePath = path2__default.default.resolve(process.cwd(), file);
977
+ const filePath = path__default.default.resolve(process.cwd(), file);
978
978
  if (!await fs4.pathExists(filePath)) {
979
979
  console.error(chalk__default.default.red(`File not found: ${filePath}`));
980
980
  process.exit(1);