designkit-ai 1.1.0 → 1.1.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/bin/designkit.js +1 -0
- package/package.json +1 -1
- package/src/commands/imagine.js +68 -40
package/bin/designkit.js
CHANGED
|
@@ -76,6 +76,7 @@ program
|
|
|
76
76
|
.option('-o, --output <dir>', 'Output directory', '.')
|
|
77
77
|
.option('-n, --name <name>', 'Output filename (without extension)', 'image')
|
|
78
78
|
.option('-c, --count <n>', 'Number of images to generate (1–4)', '1')
|
|
79
|
+
.option('-m, --model <model>', 'Gemini model (default: gemini-2.5-flash, or imagen-3.0-generate-002)')
|
|
79
80
|
.option('--aspect <ratio>', 'Aspect ratio: 1:1, 16:9, 9:16, 4:3, 3:4', '1:1')
|
|
80
81
|
.option('--size <size>', 'DALL-E size: 1024x1024, 1792x1024, 1024x1792', '1024x1024')
|
|
81
82
|
.option('--quality <quality>', 'DALL-E quality: standard, hd', 'standard')
|
package/package.json
CHANGED
package/src/commands/imagine.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { GoogleGenAI } from '@google/genai'
|
|
2
2
|
import OpenAI from 'openai'
|
|
3
3
|
import { writeFileSync, existsSync, mkdirSync } from 'fs'
|
|
4
|
-
import { resolve
|
|
4
|
+
import { resolve } from 'path'
|
|
5
5
|
|
|
6
|
-
const IMAGEN_MODEL = 'imagen-3.0-generate-002'
|
|
7
6
|
const DALLE_MODEL = 'dall-e-3'
|
|
8
7
|
|
|
9
8
|
const PROVIDERS = {
|
|
10
|
-
gemini: { envKey: 'GEMINI_API_KEY', label: '
|
|
9
|
+
gemini: { envKey: 'GEMINI_API_KEY', label: 'Gemini (Google)' },
|
|
11
10
|
openai: { envKey: 'OPENAI_API_KEY', label: 'DALL-E 3 (OpenAI)' }
|
|
12
11
|
}
|
|
13
12
|
|
|
@@ -37,19 +36,69 @@ export async function imagineCommand(prompt, options) {
|
|
|
37
36
|
|
|
38
37
|
if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true })
|
|
39
38
|
|
|
40
|
-
console.error(`\nProvider: ${PROVIDERS[provider].label}`)
|
|
41
|
-
console.error(`Prompt: ${prompt}`)
|
|
42
|
-
console.error(`Count: ${count}`)
|
|
43
|
-
console.error(`Output: ${outputDir}\n`)
|
|
44
|
-
|
|
45
39
|
if (provider === 'gemini') {
|
|
46
|
-
|
|
40
|
+
const model = options.model || 'gemini-2.5-flash'
|
|
41
|
+
console.error(`\nModel: ${model}`)
|
|
42
|
+
console.error(`Prompt: ${prompt}`)
|
|
43
|
+
console.error(`Count: ${count}`)
|
|
44
|
+
console.error(`Output: ${outputDir}\n`)
|
|
45
|
+
|
|
46
|
+
// imagen-* models use generateImages API
|
|
47
|
+
// gemini-* models use generateContent with responseModalities
|
|
48
|
+
if (model.startsWith('imagen')) {
|
|
49
|
+
await generateWithImagen({ apiKey, model, prompt, count, outputDir, options })
|
|
50
|
+
} else {
|
|
51
|
+
await generateWithGeminiFlash({ apiKey, model, prompt, count, outputDir, options })
|
|
52
|
+
}
|
|
47
53
|
} else if (provider === 'openai') {
|
|
54
|
+
console.error(`\nModel: ${DALLE_MODEL}`)
|
|
55
|
+
console.error(`Prompt: ${prompt}`)
|
|
56
|
+
console.error(`Count: ${count}`)
|
|
57
|
+
console.error(`Output: ${outputDir}\n`)
|
|
48
58
|
await generateWithOpenAI({ apiKey, prompt, count, outputDir, options })
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
|
|
62
|
+
// gemini-2.5-flash, gemini-2.0-flash-exp-image-generation, etc.
|
|
63
|
+
async function generateWithGeminiFlash({ apiKey, model, prompt, count, outputDir, options }) {
|
|
64
|
+
const ai = new GoogleGenAI({ apiKey })
|
|
65
|
+
console.error(`Generating images...`)
|
|
66
|
+
|
|
67
|
+
const saved = []
|
|
68
|
+
for (let i = 0; i < count; i++) {
|
|
69
|
+
const response = await ai.models.generateContent({
|
|
70
|
+
model,
|
|
71
|
+
contents: prompt,
|
|
72
|
+
config: {
|
|
73
|
+
responseModalities: ['image', 'text'],
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const parts = response.candidates?.[0]?.content?.parts || []
|
|
78
|
+
const imagePart = parts.find(p => p.inlineData?.mimeType?.startsWith('image/'))
|
|
79
|
+
|
|
80
|
+
if (!imagePart?.inlineData?.data) {
|
|
81
|
+
console.error(`Warning: No image in response ${i + 1}`)
|
|
82
|
+
continue
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ext = imagePart.inlineData.mimeType === 'image/jpeg' ? 'jpg' : 'png'
|
|
86
|
+
const filename = count === 1
|
|
87
|
+
? `${options.name || 'image'}.${ext}`
|
|
88
|
+
: `${options.name || 'image'}-${i + 1}.${ext}`
|
|
89
|
+
|
|
90
|
+
const outputPath = resolve(outputDir, filename)
|
|
91
|
+
const buffer = Buffer.from(imagePart.inlineData.data, 'base64')
|
|
92
|
+
writeFileSync(outputPath, buffer)
|
|
93
|
+
saved.push(outputPath)
|
|
94
|
+
console.error(`Saved: ${outputPath}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.error(`\nDone — ${saved.length} image(s) generated`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// imagen-3.0-generate-002
|
|
101
|
+
async function generateWithImagen({ apiKey, model, prompt, count, outputDir, options }) {
|
|
53
102
|
const ai = new GoogleGenAI({ apiKey })
|
|
54
103
|
|
|
55
104
|
const config = {
|
|
@@ -57,21 +106,13 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
|
|
|
57
106
|
outputMimeType: 'image/png'
|
|
58
107
|
}
|
|
59
108
|
|
|
60
|
-
if (options.
|
|
61
|
-
config.aspectRatio = getAspectRatio(parseInt(options.width), parseInt(options.height))
|
|
62
|
-
} else if (options.aspect) {
|
|
63
|
-
config.aspectRatio = options.aspect
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
console.error(`Generating with Imagen 3...`)
|
|
109
|
+
if (options.aspect) config.aspectRatio = options.aspect
|
|
67
110
|
|
|
68
|
-
|
|
69
|
-
model: IMAGEN_MODEL,
|
|
70
|
-
prompt,
|
|
71
|
-
config
|
|
72
|
-
})
|
|
111
|
+
console.error(`Generating images...`)
|
|
73
112
|
|
|
113
|
+
const response = await ai.models.generateImages({ model, prompt, config })
|
|
74
114
|
const images = response.generatedImages || []
|
|
115
|
+
|
|
75
116
|
if (!images.length) {
|
|
76
117
|
console.error('Error: No images generated')
|
|
77
118
|
process.exit(1)
|
|
@@ -83,12 +124,11 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
|
|
|
83
124
|
if (!imageData) continue
|
|
84
125
|
|
|
85
126
|
const filename = count === 1
|
|
86
|
-
?
|
|
127
|
+
? `${options.name || 'image'}.png`
|
|
87
128
|
: `${options.name || 'image'}-${i + 1}.png`
|
|
88
129
|
|
|
89
130
|
const outputPath = resolve(outputDir, filename)
|
|
90
|
-
|
|
91
|
-
writeFileSync(outputPath, buffer)
|
|
131
|
+
writeFileSync(outputPath, Buffer.from(imageData, 'base64'))
|
|
92
132
|
saved.push(outputPath)
|
|
93
133
|
console.error(`Saved: ${outputPath}`)
|
|
94
134
|
}
|
|
@@ -98,13 +138,11 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
|
|
|
98
138
|
|
|
99
139
|
async function generateWithOpenAI({ apiKey, prompt, count, outputDir, options }) {
|
|
100
140
|
const client = new OpenAI({ apiKey })
|
|
101
|
-
|
|
102
141
|
const size = options.size || '1024x1024'
|
|
103
142
|
const quality = options.quality || 'standard'
|
|
104
143
|
|
|
105
|
-
console.error(`Generating
|
|
144
|
+
console.error(`Generating images...`)
|
|
106
145
|
|
|
107
|
-
// DALL-E 3 only supports n=1 at a time
|
|
108
146
|
const saved = []
|
|
109
147
|
for (let i = 0; i < count; i++) {
|
|
110
148
|
const response = await client.images.generate({
|
|
@@ -120,24 +158,14 @@ async function generateWithOpenAI({ apiKey, prompt, count, outputDir, options })
|
|
|
120
158
|
if (!imageData) continue
|
|
121
159
|
|
|
122
160
|
const filename = count === 1
|
|
123
|
-
?
|
|
161
|
+
? `${options.name || 'image'}.png`
|
|
124
162
|
: `${options.name || 'image'}-${i + 1}.png`
|
|
125
163
|
|
|
126
164
|
const outputPath = resolve(outputDir, filename)
|
|
127
|
-
|
|
128
|
-
writeFileSync(outputPath, buffer)
|
|
165
|
+
writeFileSync(outputPath, Buffer.from(imageData, 'base64'))
|
|
129
166
|
saved.push(outputPath)
|
|
130
167
|
console.error(`Saved: ${outputPath}`)
|
|
131
168
|
}
|
|
132
169
|
|
|
133
170
|
console.error(`\nDone — ${saved.length} image(s) generated`)
|
|
134
171
|
}
|
|
135
|
-
|
|
136
|
-
function getAspectRatio(width, height) {
|
|
137
|
-
const ratio = width / height
|
|
138
|
-
if (ratio >= 1.7) return '16:9'
|
|
139
|
-
if (ratio >= 1.3) return '4:3'
|
|
140
|
-
if (ratio >= 0.95) return '1:1'
|
|
141
|
-
if (ratio >= 0.7) return '3:4'
|
|
142
|
-
return '9:16'
|
|
143
|
-
}
|