designkit-ai 1.1.0 → 1.1.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/bin/designkit.js CHANGED
@@ -76,6 +76,8 @@ 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 to use (run --list-models to see all)')
80
+ .option('--list-models', 'Show all available image models')
79
81
  .option('--aspect <ratio>', 'Aspect ratio: 1:1, 16:9, 9:16, 4:3, 3:4', '1:1')
80
82
  .option('--size <size>', 'DALL-E size: 1024x1024, 1792x1024, 1024x1792', '1024x1024')
81
83
  .option('--quality <quality>', 'DALL-E quality: standard, hd', 'standard')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "designkit-ai",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "502 HTML UI components + AI skills for designing and building web and mobile apps",
5
5
  "keywords": [
6
6
  "design-system",
@@ -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, dirname } from 'path'
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: 'Imagen 3 (Google Gemini)' },
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
 
@@ -22,10 +21,35 @@ function checkApiKey(provider) {
22
21
  return key
23
22
  }
24
23
 
24
+ const GEMINI_MODELS = [
25
+ { model: 'gemini-2.5-flash-image', type: 'gemini', note: 'Default — fast, good quality' },
26
+ { model: 'gemini-3.1-flash-image-preview', type: 'gemini', note: 'Newer flash preview' },
27
+ { model: 'gemini-3-pro-image-preview', type: 'gemini', note: 'Pro quality' },
28
+ { model: 'imagen-4.0-fast-generate-001', type: 'imagen', note: 'Imagen 4 Fast' },
29
+ { model: 'imagen-4.0-generate-001', type: 'imagen', note: 'Imagen 4 — high quality' },
30
+ { model: 'imagen-4.0-ultra-generate-001', type: 'imagen', note: 'Imagen 4 Ultra — best quality' },
31
+ ]
32
+
25
33
  export async function imagineCommand(prompt, options) {
26
34
  const provider = options.provider || 'gemini'
27
35
  const validProviders = Object.keys(PROVIDERS)
28
36
 
37
+ // --list-models: show available models and exit
38
+ if (options.listModels) {
39
+ console.log('\nGemini image models:\n')
40
+ console.log(' ' + 'Model'.padEnd(42) + 'Notes')
41
+ console.log(' ' + '─'.repeat(60))
42
+ for (const m of GEMINI_MODELS) {
43
+ console.log(` ${m.model.padEnd(42)}${m.note}`)
44
+ }
45
+ console.log('\nOpenAI image models:\n')
46
+ console.log(' dall-e-3 Standard or HD quality')
47
+ console.log('\nUsage:')
48
+ console.log(' designkit imagine "prompt" --model imagen-4.0-ultra-generate-001')
49
+ console.log('')
50
+ return
51
+ }
52
+
29
53
  if (!validProviders.includes(provider)) {
30
54
  console.error(`Error: Unknown provider "${provider}". Available: ${validProviders.join(', ')}`)
31
55
  process.exit(1)
@@ -37,19 +61,69 @@ export async function imagineCommand(prompt, options) {
37
61
 
38
62
  if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true })
39
63
 
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
64
  if (provider === 'gemini') {
46
- await generateWithGemini({ apiKey, prompt, count, outputDir, options })
65
+ const model = options.model || 'gemini-2.5-flash-image'
66
+ console.error(`\nModel: ${model}`)
67
+ console.error(`Prompt: ${prompt}`)
68
+ console.error(`Count: ${count}`)
69
+ console.error(`Output: ${outputDir}\n`)
70
+
71
+ // imagen-* models use generateImages API
72
+ // gemini-* models use generateContent with responseModalities
73
+ if (model.startsWith('imagen')) {
74
+ await generateWithImagen({ apiKey, model, prompt, count, outputDir, options })
75
+ } else {
76
+ await generateWithGeminiFlash({ apiKey, model, prompt, count, outputDir, options })
77
+ }
47
78
  } else if (provider === 'openai') {
79
+ console.error(`\nModel: ${DALLE_MODEL}`)
80
+ console.error(`Prompt: ${prompt}`)
81
+ console.error(`Count: ${count}`)
82
+ console.error(`Output: ${outputDir}\n`)
48
83
  await generateWithOpenAI({ apiKey, prompt, count, outputDir, options })
49
84
  }
50
85
  }
51
86
 
52
- async function generateWithGemini({ apiKey, prompt, count, outputDir, options }) {
87
+ // gemini-2.5-flash, gemini-2.0-flash-exp-image-generation, etc.
88
+ async function generateWithGeminiFlash({ apiKey, model, prompt, count, outputDir, options }) {
89
+ const ai = new GoogleGenAI({ apiKey })
90
+ console.error(`Generating images...`)
91
+
92
+ const saved = []
93
+ for (let i = 0; i < count; i++) {
94
+ const response = await ai.models.generateContent({
95
+ model,
96
+ contents: prompt,
97
+ config: {
98
+ responseModalities: ['image', 'text'],
99
+ }
100
+ })
101
+
102
+ const parts = response.candidates?.[0]?.content?.parts || []
103
+ const imagePart = parts.find(p => p.inlineData?.mimeType?.startsWith('image/'))
104
+
105
+ if (!imagePart?.inlineData?.data) {
106
+ console.error(`Warning: No image in response ${i + 1}`)
107
+ continue
108
+ }
109
+
110
+ const ext = imagePart.inlineData.mimeType === 'image/jpeg' ? 'jpg' : 'png'
111
+ const filename = count === 1
112
+ ? `${options.name || 'image'}.${ext}`
113
+ : `${options.name || 'image'}-${i + 1}.${ext}`
114
+
115
+ const outputPath = resolve(outputDir, filename)
116
+ const buffer = Buffer.from(imagePart.inlineData.data, 'base64')
117
+ writeFileSync(outputPath, buffer)
118
+ saved.push(outputPath)
119
+ console.error(`Saved: ${outputPath}`)
120
+ }
121
+
122
+ console.error(`\nDone — ${saved.length} image(s) generated`)
123
+ }
124
+
125
+ // imagen-3.0-generate-002
126
+ async function generateWithImagen({ apiKey, model, prompt, count, outputDir, options }) {
53
127
  const ai = new GoogleGenAI({ apiKey })
54
128
 
55
129
  const config = {
@@ -57,21 +131,13 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
57
131
  outputMimeType: 'image/png'
58
132
  }
59
133
 
60
- if (options.width && options.height) {
61
- config.aspectRatio = getAspectRatio(parseInt(options.width), parseInt(options.height))
62
- } else if (options.aspect) {
63
- config.aspectRatio = options.aspect
64
- }
134
+ if (options.aspect) config.aspectRatio = options.aspect
65
135
 
66
- console.error(`Generating with Imagen 3...`)
67
-
68
- const response = await ai.models.generateImages({
69
- model: IMAGEN_MODEL,
70
- prompt,
71
- config
72
- })
136
+ console.error(`Generating images...`)
73
137
 
138
+ const response = await ai.models.generateImages({ model, prompt, config })
74
139
  const images = response.generatedImages || []
140
+
75
141
  if (!images.length) {
76
142
  console.error('Error: No images generated')
77
143
  process.exit(1)
@@ -83,12 +149,11 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
83
149
  if (!imageData) continue
84
150
 
85
151
  const filename = count === 1
86
- ? (options.name || 'image') + '.png'
152
+ ? `${options.name || 'image'}.png`
87
153
  : `${options.name || 'image'}-${i + 1}.png`
88
154
 
89
155
  const outputPath = resolve(outputDir, filename)
90
- const buffer = Buffer.from(imageData, 'base64')
91
- writeFileSync(outputPath, buffer)
156
+ writeFileSync(outputPath, Buffer.from(imageData, 'base64'))
92
157
  saved.push(outputPath)
93
158
  console.error(`Saved: ${outputPath}`)
94
159
  }
@@ -98,13 +163,11 @@ async function generateWithGemini({ apiKey, prompt, count, outputDir, options })
98
163
 
99
164
  async function generateWithOpenAI({ apiKey, prompt, count, outputDir, options }) {
100
165
  const client = new OpenAI({ apiKey })
101
-
102
166
  const size = options.size || '1024x1024'
103
167
  const quality = options.quality || 'standard'
104
168
 
105
- console.error(`Generating with DALL-E 3...`)
169
+ console.error(`Generating images...`)
106
170
 
107
- // DALL-E 3 only supports n=1 at a time
108
171
  const saved = []
109
172
  for (let i = 0; i < count; i++) {
110
173
  const response = await client.images.generate({
@@ -120,24 +183,14 @@ async function generateWithOpenAI({ apiKey, prompt, count, outputDir, options })
120
183
  if (!imageData) continue
121
184
 
122
185
  const filename = count === 1
123
- ? (options.name || 'image') + '.png'
186
+ ? `${options.name || 'image'}.png`
124
187
  : `${options.name || 'image'}-${i + 1}.png`
125
188
 
126
189
  const outputPath = resolve(outputDir, filename)
127
- const buffer = Buffer.from(imageData, 'base64')
128
- writeFileSync(outputPath, buffer)
190
+ writeFileSync(outputPath, Buffer.from(imageData, 'base64'))
129
191
  saved.push(outputPath)
130
192
  console.error(`Saved: ${outputPath}`)
131
193
  }
132
194
 
133
195
  console.error(`\nDone — ${saved.length} image(s) generated`)
134
196
  }
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
- }