@djangocfg/imgai 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -0
- package/dist/cli/bin.cjs +996 -0
- package/dist/cli/bin.cjs.map +1 -0
- package/dist/cli/bin.d.cts +1 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +981 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/index.cjs +859 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +846 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index-DfR5DU9w.d.cts +221 -0
- package/dist/index-DfR5DU9w.d.ts +221 -0
- package/dist/index.cjs +905 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +882 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var inquirer = require('inquirer');
|
|
5
|
+
var ora = require('ora');
|
|
6
|
+
var fs = require('fs-extra');
|
|
7
|
+
var path2 = require('path');
|
|
8
|
+
var sharp = require('sharp');
|
|
9
|
+
var OpenAI = require('openai');
|
|
10
|
+
var Anthropic = require('@anthropic-ai/sdk');
|
|
11
|
+
var glob = require('glob');
|
|
12
|
+
|
|
13
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
+
|
|
15
|
+
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
16
|
+
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
17
|
+
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
18
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
19
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
20
|
+
var sharp__default = /*#__PURE__*/_interopDefault(sharp);
|
|
21
|
+
var OpenAI__default = /*#__PURE__*/_interopDefault(OpenAI);
|
|
22
|
+
var Anthropic__default = /*#__PURE__*/_interopDefault(Anthropic);
|
|
23
|
+
|
|
24
|
+
// src/cli/index.ts
|
|
25
|
+
var ImageGenerator = class {
|
|
26
|
+
config;
|
|
27
|
+
openai;
|
|
28
|
+
anthropic;
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.initializeProviders();
|
|
32
|
+
}
|
|
33
|
+
initializeProviders() {
|
|
34
|
+
const openaiKey = this.config.openaiApiKey || process.env.OPENAI_API_KEY;
|
|
35
|
+
const anthropicKey = this.config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
|
|
36
|
+
if (openaiKey) {
|
|
37
|
+
this.openai = new OpenAI__default.default({ apiKey: openaiKey });
|
|
38
|
+
}
|
|
39
|
+
if (anthropicKey) {
|
|
40
|
+
this.anthropic = new Anthropic__default.default({ apiKey: anthropicKey });
|
|
41
|
+
}
|
|
42
|
+
if (!this.openai && this.config.provider === "openai") {
|
|
43
|
+
throw new Error("OpenAI API key required. Set OPENAI_API_KEY or pass openaiApiKey in config.");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
47
|
+
// SINGLE IMAGE GENERATION
|
|
48
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
49
|
+
async generate(options) {
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
try {
|
|
52
|
+
const fullPrompt = this.buildPrompt(options.prompt);
|
|
53
|
+
const imageData = await this.generateWithOpenAI(fullPrompt);
|
|
54
|
+
const filename = options.filename || this.generateFilename(options.prompt);
|
|
55
|
+
const category = options.category || "general";
|
|
56
|
+
const outputDir = path2__default.default.join(
|
|
57
|
+
this.config.projectRoot,
|
|
58
|
+
this.config.outputDir,
|
|
59
|
+
category
|
|
60
|
+
);
|
|
61
|
+
await fs__default.default.ensureDir(outputDir);
|
|
62
|
+
const originalPath = path2__default.default.join(outputDir, `${filename}.png`);
|
|
63
|
+
await fs__default.default.writeFile(originalPath, Buffer.from(imageData, "base64"));
|
|
64
|
+
const resizeOptions = options.resize || this.config.resize;
|
|
65
|
+
let finalPath = originalPath;
|
|
66
|
+
if (resizeOptions) {
|
|
67
|
+
finalPath = await this.resizeImage(originalPath, resizeOptions);
|
|
68
|
+
if (finalPath !== originalPath) {
|
|
69
|
+
await fs__default.default.remove(originalPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const imageInfo = await this.getImageInfo(finalPath, category);
|
|
73
|
+
imageInfo.metadata = {
|
|
74
|
+
prompt: options.prompt,
|
|
75
|
+
caption: options.metadata?.caption,
|
|
76
|
+
tags: options.tags,
|
|
77
|
+
category,
|
|
78
|
+
generatedAt: /* @__PURE__ */ new Date(),
|
|
79
|
+
model: "dall-e-3"
|
|
80
|
+
};
|
|
81
|
+
const duration = Date.now() - startTime;
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
imagePath: finalPath,
|
|
85
|
+
imageUrl: imageInfo.url,
|
|
86
|
+
imageInfo,
|
|
87
|
+
duration
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
93
|
+
duration: Date.now() - startTime
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
98
|
+
// BATCH GENERATION
|
|
99
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
100
|
+
async generateBatch(options) {
|
|
101
|
+
const startTime = Date.now();
|
|
102
|
+
const results = [];
|
|
103
|
+
const concurrency = options.concurrency || 2;
|
|
104
|
+
const delayBetween = options.delayBetween || 2e3;
|
|
105
|
+
for (let i = 0; i < options.items.length; i += concurrency) {
|
|
106
|
+
const batch = options.items.slice(i, i + concurrency);
|
|
107
|
+
const batchPromises = batch.map(async (item) => {
|
|
108
|
+
const result = await this.generate({
|
|
109
|
+
prompt: item.prompt,
|
|
110
|
+
filename: item.filename,
|
|
111
|
+
category: item.category
|
|
112
|
+
});
|
|
113
|
+
return result;
|
|
114
|
+
});
|
|
115
|
+
const batchResults = await Promise.all(batchPromises);
|
|
116
|
+
for (const result of batchResults) {
|
|
117
|
+
results.push(result);
|
|
118
|
+
if (options.onProgress) {
|
|
119
|
+
options.onProgress(results.length, options.items.length, result);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (i + concurrency < options.items.length) {
|
|
123
|
+
await this.delay(delayBetween);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
total: results.length,
|
|
128
|
+
success: results.filter((r) => r.success).length,
|
|
129
|
+
failed: results.filter((r) => !r.success).length,
|
|
130
|
+
results,
|
|
131
|
+
duration: Date.now() - startTime
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
135
|
+
// PROMPT ENHANCEMENT (using Claude/GPT)
|
|
136
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
137
|
+
async enhancePrompt(basePrompt, context) {
|
|
138
|
+
const systemPrompt = `You are an expert at creating image generation prompts.
|
|
139
|
+
Given a description, create:
|
|
140
|
+
1. A detailed visual prompt (max 150 words) for DALL-E 3
|
|
141
|
+
2. A descriptive filename (lowercase, hyphens, max 30 chars)
|
|
142
|
+
3. A short caption (max 50 words)
|
|
143
|
+
|
|
144
|
+
${this.config.style ? `Style guide: ${this.config.style}` : ""}
|
|
145
|
+
|
|
146
|
+
Return ONLY valid JSON: {"prompt": "...", "filename": "...", "caption": "..."}`;
|
|
147
|
+
const userPrompt = context ? `Description: ${basePrompt}
|
|
148
|
+
Context: ${context}` : `Description: ${basePrompt}`;
|
|
149
|
+
if (this.anthropic && this.config.provider === "anthropic") {
|
|
150
|
+
const response = await this.anthropic.messages.create({
|
|
151
|
+
model: "claude-3-5-sonnet-20241022",
|
|
152
|
+
max_tokens: 500,
|
|
153
|
+
messages: [
|
|
154
|
+
{ role: "user", content: `${systemPrompt}
|
|
155
|
+
|
|
156
|
+
${userPrompt}` }
|
|
157
|
+
]
|
|
158
|
+
});
|
|
159
|
+
const text = response.content[0].type === "text" ? response.content[0].text : "";
|
|
160
|
+
return JSON.parse(text);
|
|
161
|
+
}
|
|
162
|
+
if (this.openai) {
|
|
163
|
+
const response = await this.openai.chat.completions.create({
|
|
164
|
+
model: "gpt-4-turbo-preview",
|
|
165
|
+
messages: [
|
|
166
|
+
{ role: "system", content: systemPrompt },
|
|
167
|
+
{ role: "user", content: userPrompt }
|
|
168
|
+
],
|
|
169
|
+
max_tokens: 500,
|
|
170
|
+
temperature: 0.7,
|
|
171
|
+
response_format: { type: "json_object" }
|
|
172
|
+
});
|
|
173
|
+
const text = response.choices[0]?.message?.content || "{}";
|
|
174
|
+
return JSON.parse(text);
|
|
175
|
+
}
|
|
176
|
+
throw new Error("No AI provider configured for prompt enhancement");
|
|
177
|
+
}
|
|
178
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
179
|
+
// PRIVATE METHODS
|
|
180
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
181
|
+
async generateWithOpenAI(prompt) {
|
|
182
|
+
if (!this.openai) {
|
|
183
|
+
throw new Error("OpenAI client not initialized");
|
|
184
|
+
}
|
|
185
|
+
const response = await this.openai.images.generate({
|
|
186
|
+
model: "dall-e-3",
|
|
187
|
+
prompt,
|
|
188
|
+
n: 1,
|
|
189
|
+
size: this.config.size,
|
|
190
|
+
quality: this.config.quality,
|
|
191
|
+
response_format: "b64_json"
|
|
192
|
+
});
|
|
193
|
+
const imageData = response.data?.[0]?.b64_json;
|
|
194
|
+
if (!imageData) {
|
|
195
|
+
throw new Error("No image data received from OpenAI");
|
|
196
|
+
}
|
|
197
|
+
return imageData;
|
|
198
|
+
}
|
|
199
|
+
async resizeImage(inputPath, options) {
|
|
200
|
+
const { width, height, quality = 85, format = "webp", fit = "inside" } = options;
|
|
201
|
+
let pipeline = sharp__default.default(inputPath);
|
|
202
|
+
if (width || height) {
|
|
203
|
+
pipeline = pipeline.resize(width, height, {
|
|
204
|
+
fit,
|
|
205
|
+
withoutEnlargement: true
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const outputPath = inputPath.replace(/\.[^.]+$/, `.${format}`);
|
|
209
|
+
switch (format) {
|
|
210
|
+
case "webp":
|
|
211
|
+
pipeline = pipeline.webp({ quality });
|
|
212
|
+
break;
|
|
213
|
+
case "jpeg":
|
|
214
|
+
pipeline = pipeline.jpeg({ quality });
|
|
215
|
+
break;
|
|
216
|
+
case "png":
|
|
217
|
+
pipeline = pipeline.png({ quality });
|
|
218
|
+
break;
|
|
219
|
+
case "avif":
|
|
220
|
+
pipeline = pipeline.avif({ quality });
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
await pipeline.toFile(outputPath);
|
|
224
|
+
return outputPath;
|
|
225
|
+
}
|
|
226
|
+
async getImageInfo(imagePath, category) {
|
|
227
|
+
const stats = await fs__default.default.stat(imagePath);
|
|
228
|
+
const metadata = await sharp__default.default(imagePath).metadata();
|
|
229
|
+
const filename = path2__default.default.basename(imagePath);
|
|
230
|
+
const extension = path2__default.default.extname(filename).slice(1);
|
|
231
|
+
const id = path2__default.default.basename(filename, path2__default.default.extname(filename));
|
|
232
|
+
const publicDir = path2__default.default.join(this.config.projectRoot, this.config.publicDir);
|
|
233
|
+
const relativePath = path2__default.default.relative(publicDir, imagePath);
|
|
234
|
+
const url = "/" + relativePath.replace(/\\/g, "/");
|
|
235
|
+
return {
|
|
236
|
+
id,
|
|
237
|
+
filename,
|
|
238
|
+
extension,
|
|
239
|
+
path: relativePath,
|
|
240
|
+
url,
|
|
241
|
+
size: stats.size,
|
|
242
|
+
width: metadata.width,
|
|
243
|
+
height: metadata.height,
|
|
244
|
+
createdAt: stats.birthtime,
|
|
245
|
+
modifiedAt: stats.mtime
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
buildPrompt(basePrompt) {
|
|
249
|
+
if (this.config.style) {
|
|
250
|
+
return `${this.config.style}. ${basePrompt}`;
|
|
251
|
+
}
|
|
252
|
+
return basePrompt;
|
|
253
|
+
}
|
|
254
|
+
generateFilename(prompt) {
|
|
255
|
+
return prompt.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "-").substring(0, 30);
|
|
256
|
+
}
|
|
257
|
+
delay(ms) {
|
|
258
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
var DEFAULT_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "avif", "gif", "svg"];
|
|
262
|
+
var DEFAULT_DIRECTORIES = ["static/images", "images", "assets"];
|
|
263
|
+
var ImageScanner = class {
|
|
264
|
+
config;
|
|
265
|
+
constructor(config) {
|
|
266
|
+
this.config = config;
|
|
267
|
+
}
|
|
268
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
269
|
+
// SCAN IMAGES
|
|
270
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
271
|
+
async scan(options = {}) {
|
|
272
|
+
const startTime = Date.now();
|
|
273
|
+
const {
|
|
274
|
+
directories = DEFAULT_DIRECTORIES,
|
|
275
|
+
extensions = DEFAULT_EXTENSIONS,
|
|
276
|
+
includeDimensions = true,
|
|
277
|
+
recursive = true
|
|
278
|
+
} = options;
|
|
279
|
+
const publicDir = path2__default.default.join(this.config.projectRoot, this.config.publicDir);
|
|
280
|
+
const images = [];
|
|
281
|
+
const byCategory = {};
|
|
282
|
+
const byExtension = {};
|
|
283
|
+
let totalSize = 0;
|
|
284
|
+
const patterns = directories.flatMap((dir) => {
|
|
285
|
+
const basePath = path2__default.default.join(publicDir, dir);
|
|
286
|
+
const extPattern = `*.{${extensions.join(",")}}`;
|
|
287
|
+
return recursive ? [path2__default.default.join(basePath, "**", extPattern)] : [path2__default.default.join(basePath, extPattern)];
|
|
288
|
+
});
|
|
289
|
+
for (const pattern of patterns) {
|
|
290
|
+
const files = await glob.glob(pattern, { nodir: true });
|
|
291
|
+
for (const filePath of files) {
|
|
292
|
+
try {
|
|
293
|
+
const imageInfo = await this.processImage(filePath, publicDir, includeDimensions);
|
|
294
|
+
images.push(imageInfo);
|
|
295
|
+
totalSize += imageInfo.size;
|
|
296
|
+
byExtension[imageInfo.extension] = (byExtension[imageInfo.extension] || 0) + 1;
|
|
297
|
+
const category = this.extractCategory(imageInfo.path);
|
|
298
|
+
if (!byCategory[category]) {
|
|
299
|
+
byCategory[category] = [];
|
|
300
|
+
}
|
|
301
|
+
byCategory[category].push(imageInfo);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.warn(`Failed to process image: ${filePath}`, error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
images.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
308
|
+
return {
|
|
309
|
+
images,
|
|
310
|
+
total: images.length,
|
|
311
|
+
byCategory,
|
|
312
|
+
byExtension,
|
|
313
|
+
totalSize,
|
|
314
|
+
scanDuration: Date.now() - startTime
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
318
|
+
// BUILD CATALOG
|
|
319
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
320
|
+
async buildCatalog(options = {}) {
|
|
321
|
+
const scanResult = await this.scan(options);
|
|
322
|
+
const byId = {};
|
|
323
|
+
for (const image of scanResult.images) {
|
|
324
|
+
byId[image.id] = image;
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
version: "1.0.0",
|
|
328
|
+
generatedAt: /* @__PURE__ */ new Date(),
|
|
329
|
+
count: scanResult.total,
|
|
330
|
+
categories: scanResult.byCategory,
|
|
331
|
+
images: scanResult.images,
|
|
332
|
+
byId
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
336
|
+
// FIND SPECIFIC IMAGES
|
|
337
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
338
|
+
async findByCategory(category) {
|
|
339
|
+
const scanResult = await this.scan();
|
|
340
|
+
return scanResult.byCategory[category] || [];
|
|
341
|
+
}
|
|
342
|
+
async findById(id) {
|
|
343
|
+
const scanResult = await this.scan();
|
|
344
|
+
return scanResult.images.find((img) => img.id === id);
|
|
345
|
+
}
|
|
346
|
+
async findByExtension(extension) {
|
|
347
|
+
const scanResult = await this.scan();
|
|
348
|
+
return scanResult.images.filter((img) => img.extension === extension);
|
|
349
|
+
}
|
|
350
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
351
|
+
// PRIVATE METHODS
|
|
352
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
353
|
+
async processImage(filePath, publicDir, includeDimensions) {
|
|
354
|
+
const stats = await fs__default.default.stat(filePath);
|
|
355
|
+
const filename = path2__default.default.basename(filePath);
|
|
356
|
+
const extension = path2__default.default.extname(filename).slice(1).toLowerCase();
|
|
357
|
+
const id = path2__default.default.basename(filename, path2__default.default.extname(filename));
|
|
358
|
+
const relativePath = path2__default.default.relative(publicDir, filePath).replace(/\\/g, "/");
|
|
359
|
+
const url = "/" + relativePath;
|
|
360
|
+
let width;
|
|
361
|
+
let height;
|
|
362
|
+
if (includeDimensions && extension !== "svg") {
|
|
363
|
+
try {
|
|
364
|
+
const metadata = await sharp__default.default(filePath).metadata();
|
|
365
|
+
width = metadata.width;
|
|
366
|
+
height = metadata.height;
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
id,
|
|
372
|
+
filename,
|
|
373
|
+
extension,
|
|
374
|
+
path: relativePath,
|
|
375
|
+
url,
|
|
376
|
+
size: stats.size,
|
|
377
|
+
width,
|
|
378
|
+
height,
|
|
379
|
+
createdAt: stats.birthtime,
|
|
380
|
+
modifiedAt: stats.mtime
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
extractCategory(imagePath) {
|
|
384
|
+
const parts = imagePath.split("/");
|
|
385
|
+
if (parts.length > 1) {
|
|
386
|
+
return parts[parts.length - 2];
|
|
387
|
+
}
|
|
388
|
+
return "root";
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
function formatBytes(bytes) {
|
|
392
|
+
if (bytes === 0) return "0 B";
|
|
393
|
+
const k = 1024;
|
|
394
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
395
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
396
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
397
|
+
}
|
|
398
|
+
function formatDuration(ms) {
|
|
399
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
400
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
401
|
+
}
|
|
402
|
+
var ConfigGenerator = class {
|
|
403
|
+
config;
|
|
404
|
+
scanner;
|
|
405
|
+
constructor(config) {
|
|
406
|
+
this.config = config;
|
|
407
|
+
this.scanner = new ImageScanner(config);
|
|
408
|
+
}
|
|
409
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
410
|
+
// GENERATE IMAGES.TS
|
|
411
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
412
|
+
async generate() {
|
|
413
|
+
const catalog = await this.scanner.buildCatalog();
|
|
414
|
+
const outputPath = path2__default.default.join(this.config.projectRoot, this.config.configOutputPath);
|
|
415
|
+
await fs__default.default.ensureDir(path2__default.default.dirname(outputPath));
|
|
416
|
+
const content = this.generateTypeScript(catalog);
|
|
417
|
+
await fs__default.default.writeFile(outputPath, content, "utf-8");
|
|
418
|
+
return outputPath;
|
|
419
|
+
}
|
|
420
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
421
|
+
// TYPESCRIPT GENERATION
|
|
422
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
423
|
+
generateTypeScript(catalog) {
|
|
424
|
+
const categories = Object.keys(catalog.categories).sort();
|
|
425
|
+
const allIds = catalog.images.map((img) => img.id).sort();
|
|
426
|
+
return `/**
|
|
427
|
+
* Auto-generated image catalog
|
|
428
|
+
* Generated: ${catalog.generatedAt.toISOString()}
|
|
429
|
+
* Total images: ${catalog.count}
|
|
430
|
+
*
|
|
431
|
+
* DO NOT EDIT - This file is auto-generated by @djangocfg/imgai
|
|
432
|
+
* Run \`imgai sync\` to regenerate
|
|
433
|
+
*/
|
|
434
|
+
|
|
435
|
+
// ============================================================================
|
|
436
|
+
// TYPES
|
|
437
|
+
// ============================================================================
|
|
438
|
+
|
|
439
|
+
export interface ImageData {
|
|
440
|
+
id: string;
|
|
441
|
+
filename: string;
|
|
442
|
+
url: string;
|
|
443
|
+
path: string;
|
|
444
|
+
extension: string;
|
|
445
|
+
width?: number;
|
|
446
|
+
height?: number;
|
|
447
|
+
size: number;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export type ImageId = ${allIds.length > 0 ? allIds.map((id) => `'${id}'`).join(" | ") : "string"};
|
|
451
|
+
export type ImageCategory = ${categories.length > 0 ? categories.map((c) => `'${c}'`).join(" | ") : "string"};
|
|
452
|
+
|
|
453
|
+
// ============================================================================
|
|
454
|
+
// IMAGE CATALOG
|
|
455
|
+
// ============================================================================
|
|
456
|
+
|
|
457
|
+
export const IMAGES: Record<ImageId, ImageData> = {
|
|
458
|
+
${catalog.images.map((img) => this.generateImageEntry(img)).join(",\n")}
|
|
459
|
+
} as const;
|
|
460
|
+
|
|
461
|
+
// ============================================================================
|
|
462
|
+
// BY CATEGORY
|
|
463
|
+
// ============================================================================
|
|
464
|
+
|
|
465
|
+
export const IMAGES_BY_CATEGORY: Record<ImageCategory, readonly ImageData[]> = {
|
|
466
|
+
${categories.map((cat) => this.generateCategoryEntry(cat, catalog.categories[cat] || [])).join(",\n")}
|
|
467
|
+
} as const;
|
|
468
|
+
|
|
469
|
+
// ============================================================================
|
|
470
|
+
// HELPERS
|
|
471
|
+
// ============================================================================
|
|
472
|
+
|
|
473
|
+
/** Get image by ID */
|
|
474
|
+
export function getImage(id: ImageId): ImageData | undefined {
|
|
475
|
+
return IMAGES[id];
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Get image URL by ID */
|
|
479
|
+
export function getImageUrl(id: ImageId): string | undefined {
|
|
480
|
+
return IMAGES[id]?.url;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** Get all images in category */
|
|
484
|
+
export function getImagesByCategory(category: ImageCategory): readonly ImageData[] {
|
|
485
|
+
return IMAGES_BY_CATEGORY[category] || [];
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** Get all image IDs */
|
|
489
|
+
export function getAllImageIds(): ImageId[] {
|
|
490
|
+
return Object.keys(IMAGES) as ImageId[];
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** Get all categories */
|
|
494
|
+
export function getAllCategories(): ImageCategory[] {
|
|
495
|
+
return Object.keys(IMAGES_BY_CATEGORY) as ImageCategory[];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/** Check if image exists */
|
|
499
|
+
export function hasImage(id: string): id is ImageId {
|
|
500
|
+
return id in IMAGES;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// METADATA
|
|
505
|
+
// ============================================================================
|
|
506
|
+
|
|
507
|
+
export const IMAGE_CATALOG_META = {
|
|
508
|
+
version: '${catalog.version}',
|
|
509
|
+
generatedAt: '${catalog.generatedAt.toISOString()}',
|
|
510
|
+
totalImages: ${catalog.count},
|
|
511
|
+
categories: ${JSON.stringify(categories)},
|
|
512
|
+
} as const;
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
generateImageEntry(img) {
|
|
516
|
+
const data = {
|
|
517
|
+
id: img.id,
|
|
518
|
+
filename: img.filename,
|
|
519
|
+
url: img.url,
|
|
520
|
+
path: img.path,
|
|
521
|
+
extension: img.extension,
|
|
522
|
+
size: img.size
|
|
523
|
+
};
|
|
524
|
+
if (img.width) data.width = img.width;
|
|
525
|
+
if (img.height) data.height = img.height;
|
|
526
|
+
return ` '${img.id}': ${JSON.stringify(data, null, 4).replace(/\n/g, "\n ").replace(/}$/, " }")}`;
|
|
527
|
+
}
|
|
528
|
+
generateCategoryEntry(category, images) {
|
|
529
|
+
const imageRefs = images.map((img) => `IMAGES['${img.id}']`);
|
|
530
|
+
return ` '${category}': [${imageRefs.join(", ")}]`;
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
// src/cli/index.ts
|
|
535
|
+
var ImageAICLI = class {
|
|
536
|
+
config;
|
|
537
|
+
generator;
|
|
538
|
+
scanner;
|
|
539
|
+
configGenerator;
|
|
540
|
+
constructor(config) {
|
|
541
|
+
this.config = config;
|
|
542
|
+
this.generator = new ImageGenerator(config);
|
|
543
|
+
this.scanner = new ImageScanner(config);
|
|
544
|
+
this.configGenerator = new ConfigGenerator(config);
|
|
545
|
+
}
|
|
546
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
547
|
+
// INTERACTIVE MODE
|
|
548
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
549
|
+
async interactive() {
|
|
550
|
+
this.printHeader();
|
|
551
|
+
while (true) {
|
|
552
|
+
try {
|
|
553
|
+
const { action } = await inquirer__default.default.prompt([
|
|
554
|
+
{
|
|
555
|
+
type: "list",
|
|
556
|
+
name: "action",
|
|
557
|
+
message: chalk__default.default.cyan("What would you like to do?"),
|
|
558
|
+
choices: [
|
|
559
|
+
{ name: `${chalk__default.default.green("\u{1F3A8}")} Generate image from prompt`, value: "generate" },
|
|
560
|
+
{ name: `${chalk__default.default.blue("\u2728")} Generate with AI-enhanced prompt`, value: "enhance" },
|
|
561
|
+
{ name: `${chalk__default.default.yellow("\u{1F4E6}")} Batch generate images`, value: "batch" },
|
|
562
|
+
new inquirer__default.default.Separator(),
|
|
563
|
+
{ name: `${chalk__default.default.magenta("\u{1F50D}")} Scan & catalog images`, value: "scan" },
|
|
564
|
+
{ name: `${chalk__default.default.cyan("\u26A1")} Sync images.ts config`, value: "sync" },
|
|
565
|
+
{ name: `${chalk__default.default.white("\u{1F4CA}")} Show statistics`, value: "stats" },
|
|
566
|
+
new inquirer__default.default.Separator(),
|
|
567
|
+
{ name: `${chalk__default.default.gray("\u2699\uFE0F")} Settings`, value: "settings" },
|
|
568
|
+
{ name: `${chalk__default.default.red("\u{1F6AA}")} Exit`, value: "exit" }
|
|
569
|
+
]
|
|
570
|
+
}
|
|
571
|
+
]);
|
|
572
|
+
switch (action) {
|
|
573
|
+
case "generate":
|
|
574
|
+
await this.promptGenerate();
|
|
575
|
+
break;
|
|
576
|
+
case "enhance":
|
|
577
|
+
await this.promptEnhance();
|
|
578
|
+
break;
|
|
579
|
+
case "batch":
|
|
580
|
+
await this.promptBatch();
|
|
581
|
+
break;
|
|
582
|
+
case "scan":
|
|
583
|
+
await this.runScan();
|
|
584
|
+
break;
|
|
585
|
+
case "sync":
|
|
586
|
+
await this.runSync();
|
|
587
|
+
break;
|
|
588
|
+
case "stats":
|
|
589
|
+
await this.showStats();
|
|
590
|
+
break;
|
|
591
|
+
case "settings":
|
|
592
|
+
await this.showSettings();
|
|
593
|
+
break;
|
|
594
|
+
case "exit":
|
|
595
|
+
console.log(chalk__default.default.cyan("\n\u{1F44B} Goodbye!\n"));
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
console.log("");
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (error instanceof Error && error.name === "ExitPromptError") {
|
|
601
|
+
console.log(chalk__default.default.cyan("\n\n\u{1F44B} Goodbye!\n"));
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
609
|
+
// GENERATE COMMANDS
|
|
610
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
611
|
+
async generate(options) {
|
|
612
|
+
const spinner = ora__default.default("Generating image...").start();
|
|
613
|
+
try {
|
|
614
|
+
const result = await this.generator.generate(options);
|
|
615
|
+
if (result.success) {
|
|
616
|
+
spinner.succeed(chalk__default.default.green("Image generated successfully!"));
|
|
617
|
+
console.log(chalk__default.default.gray(` Path: ${result.imagePath}`));
|
|
618
|
+
console.log(chalk__default.default.gray(` URL: ${result.imageUrl}`));
|
|
619
|
+
console.log(chalk__default.default.gray(` Time: ${formatDuration(result.duration || 0)}`));
|
|
620
|
+
} else {
|
|
621
|
+
spinner.fail(chalk__default.default.red(`Generation failed: ${result.error}`));
|
|
622
|
+
}
|
|
623
|
+
} catch (error) {
|
|
624
|
+
spinner.fail(chalk__default.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async scan(options = {}) {
|
|
628
|
+
const spinner = ora__default.default("Scanning images...").start();
|
|
629
|
+
try {
|
|
630
|
+
const result = await this.scanner.scan(options);
|
|
631
|
+
spinner.succeed(chalk__default.default.green(`Found ${result.total} images`));
|
|
632
|
+
console.log(chalk__default.default.gray(` Total size: ${formatBytes(result.totalSize)}`));
|
|
633
|
+
console.log(chalk__default.default.gray(` Scan time: ${formatDuration(result.scanDuration)}`));
|
|
634
|
+
console.log(chalk__default.default.cyan("\n Categories:"));
|
|
635
|
+
for (const [category, images] of Object.entries(result.byCategory)) {
|
|
636
|
+
console.log(chalk__default.default.gray(` ${category}: ${images.length} images`));
|
|
637
|
+
}
|
|
638
|
+
console.log(chalk__default.default.cyan("\n Extensions:"));
|
|
639
|
+
for (const [ext, count] of Object.entries(result.byExtension)) {
|
|
640
|
+
console.log(chalk__default.default.gray(` .${ext}: ${count} files`));
|
|
641
|
+
}
|
|
642
|
+
} catch (error) {
|
|
643
|
+
spinner.fail(chalk__default.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async sync() {
|
|
647
|
+
const spinner = ora__default.default("Syncing images.ts config...").start();
|
|
648
|
+
try {
|
|
649
|
+
const outputPath = await this.configGenerator.generate();
|
|
650
|
+
spinner.succeed(chalk__default.default.green("Config synced successfully!"));
|
|
651
|
+
console.log(chalk__default.default.gray(` Output: ${outputPath}`));
|
|
652
|
+
} catch (error) {
|
|
653
|
+
spinner.fail(chalk__default.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
657
|
+
// PRIVATE PROMPT METHODS
|
|
658
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
659
|
+
async promptGenerate() {
|
|
660
|
+
const answers = await inquirer__default.default.prompt([
|
|
661
|
+
{
|
|
662
|
+
type: "input",
|
|
663
|
+
name: "prompt",
|
|
664
|
+
message: "Enter image description:",
|
|
665
|
+
validate: (input) => input.trim() ? true : "Description is required"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
type: "input",
|
|
669
|
+
name: "filename",
|
|
670
|
+
message: "Filename (optional, auto-generated if empty):"
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
type: "input",
|
|
674
|
+
name: "category",
|
|
675
|
+
message: "Category/folder (default: general):",
|
|
676
|
+
default: "general"
|
|
677
|
+
}
|
|
678
|
+
]);
|
|
679
|
+
await this.generate({
|
|
680
|
+
prompt: answers.prompt,
|
|
681
|
+
filename: answers.filename || void 0,
|
|
682
|
+
category: answers.category
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
async promptEnhance() {
|
|
686
|
+
const answers = await inquirer__default.default.prompt([
|
|
687
|
+
{
|
|
688
|
+
type: "input",
|
|
689
|
+
name: "description",
|
|
690
|
+
message: "Describe what you want:",
|
|
691
|
+
validate: (input) => input.trim() ? true : "Description is required"
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
type: "input",
|
|
695
|
+
name: "context",
|
|
696
|
+
message: "Additional context (optional):"
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
type: "input",
|
|
700
|
+
name: "category",
|
|
701
|
+
message: "Category/folder (default: general):",
|
|
702
|
+
default: "general"
|
|
703
|
+
}
|
|
704
|
+
]);
|
|
705
|
+
const spinner = ora__default.default("Enhancing prompt with AI...").start();
|
|
706
|
+
try {
|
|
707
|
+
const enhanced = await this.generator.enhancePrompt(
|
|
708
|
+
answers.description,
|
|
709
|
+
answers.context || void 0
|
|
710
|
+
);
|
|
711
|
+
spinner.succeed("Prompt enhanced!");
|
|
712
|
+
console.log(chalk__default.default.cyan("\n Enhanced prompt:"));
|
|
713
|
+
console.log(chalk__default.default.gray(` ${enhanced.prompt}
|
|
714
|
+
`));
|
|
715
|
+
console.log(chalk__default.default.gray(` Filename: ${enhanced.filename}`));
|
|
716
|
+
console.log(chalk__default.default.gray(` Caption: ${enhanced.caption}
|
|
717
|
+
`));
|
|
718
|
+
const { confirm } = await inquirer__default.default.prompt([
|
|
719
|
+
{
|
|
720
|
+
type: "confirm",
|
|
721
|
+
name: "confirm",
|
|
722
|
+
message: "Generate image with this prompt?",
|
|
723
|
+
default: true
|
|
724
|
+
}
|
|
725
|
+
]);
|
|
726
|
+
if (confirm) {
|
|
727
|
+
await this.generate({
|
|
728
|
+
prompt: enhanced.prompt,
|
|
729
|
+
filename: enhanced.filename,
|
|
730
|
+
category: answers.category,
|
|
731
|
+
metadata: { caption: enhanced.caption }
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
} catch (error) {
|
|
735
|
+
spinner.fail(chalk__default.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
async promptBatch() {
|
|
739
|
+
console.log(chalk__default.default.cyan("\n Enter prompts (one per line, empty line to finish):"));
|
|
740
|
+
const prompts = [];
|
|
741
|
+
let lineNumber = 1;
|
|
742
|
+
while (true) {
|
|
743
|
+
const { prompt } = await inquirer__default.default.prompt([
|
|
744
|
+
{
|
|
745
|
+
type: "input",
|
|
746
|
+
name: "prompt",
|
|
747
|
+
message: ` ${lineNumber}.`
|
|
748
|
+
}
|
|
749
|
+
]);
|
|
750
|
+
if (!prompt.trim()) break;
|
|
751
|
+
prompts.push(prompt);
|
|
752
|
+
lineNumber++;
|
|
753
|
+
}
|
|
754
|
+
if (prompts.length === 0) {
|
|
755
|
+
console.log(chalk__default.default.yellow(" No prompts entered."));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
const { category, concurrency } = await inquirer__default.default.prompt([
|
|
759
|
+
{
|
|
760
|
+
type: "input",
|
|
761
|
+
name: "category",
|
|
762
|
+
message: "Category for all images:",
|
|
763
|
+
default: "batch"
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
type: "list",
|
|
767
|
+
name: "concurrency",
|
|
768
|
+
message: "Concurrent workers:",
|
|
769
|
+
choices: [
|
|
770
|
+
{ name: "1 (slow, safe)", value: 1 },
|
|
771
|
+
{ name: "2 (balanced)", value: 2 },
|
|
772
|
+
{ name: "3 (fast)", value: 3 }
|
|
773
|
+
],
|
|
774
|
+
default: 2
|
|
775
|
+
}
|
|
776
|
+
]);
|
|
777
|
+
console.log(chalk__default.default.cyan(`
|
|
778
|
+
Generating ${prompts.length} images...
|
|
779
|
+
`));
|
|
780
|
+
const result = await this.generator.generateBatch({
|
|
781
|
+
items: prompts.map((prompt, i) => ({
|
|
782
|
+
prompt,
|
|
783
|
+
category,
|
|
784
|
+
filename: `batch-${Date.now()}-${i + 1}`
|
|
785
|
+
})),
|
|
786
|
+
concurrency,
|
|
787
|
+
onProgress: (current, total, res) => {
|
|
788
|
+
const status = res.success ? chalk__default.default.green("\u2713") : chalk__default.default.red("\u2717");
|
|
789
|
+
console.log(` ${status} ${current}/${total}`);
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
console.log(chalk__default.default.cyan("\n Batch complete!"));
|
|
793
|
+
console.log(chalk__default.default.gray(` Success: ${result.success}`));
|
|
794
|
+
console.log(chalk__default.default.gray(` Failed: ${result.failed}`));
|
|
795
|
+
console.log(chalk__default.default.gray(` Time: ${formatDuration(result.duration)}`));
|
|
796
|
+
}
|
|
797
|
+
async runScan() {
|
|
798
|
+
await this.scan();
|
|
799
|
+
}
|
|
800
|
+
async runSync() {
|
|
801
|
+
await this.sync();
|
|
802
|
+
}
|
|
803
|
+
async showStats() {
|
|
804
|
+
const spinner = ora__default.default("Gathering statistics...").start();
|
|
805
|
+
try {
|
|
806
|
+
const result = await this.scanner.scan();
|
|
807
|
+
spinner.stop();
|
|
808
|
+
console.log(chalk__default.default.cyan("\n \u{1F4CA} Image Statistics\n"));
|
|
809
|
+
console.log(chalk__default.default.white(` Total images: ${result.total}`));
|
|
810
|
+
console.log(chalk__default.default.white(` Total size: ${formatBytes(result.totalSize)}`));
|
|
811
|
+
console.log(chalk__default.default.white(` Categories: ${Object.keys(result.byCategory).length}`));
|
|
812
|
+
console.log(chalk__default.default.cyan("\n By Category:"));
|
|
813
|
+
for (const [category, images] of Object.entries(result.byCategory).sort((a, b) => b[1].length - a[1].length)) {
|
|
814
|
+
const size = images.reduce((sum, img) => sum + img.size, 0);
|
|
815
|
+
console.log(chalk__default.default.gray(` ${category.padEnd(20)} ${images.length.toString().padStart(4)} images ${formatBytes(size).padStart(10)}`));
|
|
816
|
+
}
|
|
817
|
+
console.log(chalk__default.default.cyan("\n By Extension:"));
|
|
818
|
+
for (const [ext, count] of Object.entries(result.byExtension).sort((a, b) => b[1] - a[1])) {
|
|
819
|
+
console.log(chalk__default.default.gray(` .${ext.padEnd(6)} ${count} files`));
|
|
820
|
+
}
|
|
821
|
+
} catch (error) {
|
|
822
|
+
spinner.fail(chalk__default.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async showSettings() {
|
|
826
|
+
console.log(chalk__default.default.cyan("\n \u2699\uFE0F Current Settings\n"));
|
|
827
|
+
console.log(chalk__default.default.gray(` Provider: ${this.config.provider}`));
|
|
828
|
+
console.log(chalk__default.default.gray(` Size: ${this.config.size}`));
|
|
829
|
+
console.log(chalk__default.default.gray(` Quality: ${this.config.quality}`));
|
|
830
|
+
console.log(chalk__default.default.gray(` Output dir: ${this.config.outputDir}`));
|
|
831
|
+
console.log(chalk__default.default.gray(` Config path: ${this.config.configOutputPath}`));
|
|
832
|
+
if (this.config.resize) {
|
|
833
|
+
console.log(chalk__default.default.cyan("\n Resize Settings:"));
|
|
834
|
+
console.log(chalk__default.default.gray(` Width: ${this.config.resize.width || "auto"}`));
|
|
835
|
+
console.log(chalk__default.default.gray(` Height: ${this.config.resize.height || "auto"}`));
|
|
836
|
+
console.log(chalk__default.default.gray(` Format: ${this.config.resize.format}`));
|
|
837
|
+
console.log(chalk__default.default.gray(` Quality: ${this.config.resize.quality}`));
|
|
838
|
+
}
|
|
839
|
+
if (this.config.style) {
|
|
840
|
+
console.log(chalk__default.default.cyan("\n Style:"));
|
|
841
|
+
console.log(chalk__default.default.gray(` ${this.config.style.substring(0, 100)}...`));
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
845
|
+
// UI HELPERS
|
|
846
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
847
|
+
printHeader() {
|
|
848
|
+
console.log("");
|
|
849
|
+
console.log(chalk__default.default.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
850
|
+
console.log(chalk__default.default.cyan(" \u2551") + chalk__default.default.white.bold(" \u{1F3A8} IMGAI - Image Generator ") + chalk__default.default.cyan("\u2551"));
|
|
851
|
+
console.log(chalk__default.default.cyan(" \u2551") + chalk__default.default.gray(" AI-powered image generation & sync ") + chalk__default.default.cyan("\u2551"));
|
|
852
|
+
console.log(chalk__default.default.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
853
|
+
console.log("");
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
exports.ImageAICLI = ImageAICLI;
|
|
858
|
+
//# sourceMappingURL=index.cjs.map
|
|
859
|
+
//# sourceMappingURL=index.cjs.map
|