niahere 0.2.89 → 0.2.90

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niahere",
3
- "version": "0.2.89",
3
+ "version": "0.2.90",
4
4
  "description": "A personal AI assistant daemon — chat, scheduled jobs, persona system, extensible via skills.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -14,12 +14,14 @@ General-purpose image generation skill supporting **OpenAI** (default) and **Gem
14
14
  ## Setup
15
15
 
16
16
  API keys in `~/.niahere/config.yaml`:
17
+
17
18
  ```yaml
18
19
  openai_api_key: sk-...
19
20
  gemini_api_key: AIza...
20
21
  ```
21
22
 
22
23
  Or set via CLI or environment variables:
24
+
23
25
  ```bash
24
26
  nia config set openai_api_key sk-...
25
27
  nia config set gemini_api_key AIza...
@@ -29,25 +31,39 @@ Keys are resolved in order: `--api-key` flag > env var (`$OPENAI_API_KEY` / `$GE
29
31
 
30
32
  ## Providers & Models
31
33
 
32
- | Provider | Default Model | Alternatives |
33
- |----------|--------------|--------------|
34
- | **OpenAI** (default) | `gpt-image-1.5` | `gpt-image-1`, `gpt-image-1-mini` |
35
- | **Gemini** | `gemini-3.1-flash-image-preview` | `gemini-3-pro-image-preview`, `gemini-2.5-flash-image` |
34
+ | Provider | Default Model | Alternatives |
35
+ | -------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- |
36
+ | **OpenAI** (default) | `gpt-image-2` | `gpt-image-1.5`, `gpt-image-1-mini` |
37
+ | **Gemini** | `gemini-3.1-flash-image-preview` (Nano Banana 2) | `gemini-3-pro-image-preview` (Nano Banana Pro), `gemini-2.5-flash-image` (GA) |
38
+
39
+ `gpt-image-2` (Apr 2026) is the current OpenAI flagship — native reasoning, up to 16 reference images, native 2K. `dall-e-2`/`dall-e-3` were shut off on the API on May 12, 2026.
36
40
 
37
- Note: `dall-e-2` and `dall-e-3` are deprecated (EOL May 2026). Use `gpt-image-1.5` instead.
41
+ ## Per-image pricing (May 2026)
42
+
43
+ | Model | Price |
44
+ | -------------------------------- | ------------------------------------------------------------------------------------ |
45
+ | `gpt-image-2` | ~$0.006 (low) → $0.053 (medium 1024) → $0.35 (high 4K). Token-based; Batch API −50%. |
46
+ | `gpt-image-1.5` | ~20% cheaper than gpt-image-1 across tiers |
47
+ | `gpt-image-1` | low $0.011, medium $0.042, high $0.167 (1024²) |
48
+ | `gemini-3-pro-image-preview` | $0.134 (1K/2K), $0.24 (4K) |
49
+ | `gemini-3.1-flash-image-preview` | $0.045 (512), $0.067 (1K), $0.101 (2K), $0.151 (4K) |
50
+ | `gemini-2.5-flash-image` | $0.039 standard, $0.0195 batch |
38
51
 
39
52
  ## Quick Reference
40
53
 
41
54
  ```bash
42
- SCRIPT="/Users/aman/.shared/skills/image-generation/scripts/generate_image.py"
55
+ SCRIPT="$(dirname "$0")/scripts/generate_image.py" # or the absolute path under your skills dir
43
56
 
44
- # Basic generation (OpenAI, default)
57
+ # Basic generation (OpenAI gpt-image-2, default)
45
58
  python3 $SCRIPT --prompt "A sunset over mountains"
46
59
 
47
60
  # High quality
48
61
  python3 $SCRIPT --prompt "Oil painting of a forest" --quality high
49
62
 
50
- # With aspect ratio
63
+ # 2K output (OpenAI gpt-image-2; Gemini 2K via --resolution)
64
+ python3 $SCRIPT --prompt "Detailed cityscape" --resolution 2K
65
+
66
+ # Aspect ratio
51
67
  python3 $SCRIPT --prompt "Portrait photo" --aspect-ratio 3:4
52
68
 
53
69
  # With reference image (OpenAI edit mode)
@@ -56,6 +72,10 @@ python3 $SCRIPT --prompt "Add a rainbow to this scene" --reference photo.png
56
72
  # Gemini provider
57
73
  python3 $SCRIPT --provider gemini --prompt "Watercolor sunset" --aspect-ratio 16:9
58
74
 
75
+ # Gemini 4K (use Pro — 3.1 Flash currently ignores 2K/4K and returns ~1K)
76
+ python3 $SCRIPT --provider gemini --model gemini-3-pro-image-preview \
77
+ --prompt "Cinematic landscape" --resolution 4K --aspect-ratio 16:9
78
+
59
79
  # Gemini with reference
60
80
  python3 $SCRIPT --provider gemini --reference face.png \
61
81
  --prompt "Same person sitting in a cafe, natural lighting" --aspect-ratio 9:16
@@ -66,17 +86,24 @@ python3 $SCRIPT --prompt "A cat" --output /path/to/output/
66
86
 
67
87
  ## Aspect Ratios
68
88
 
69
- | Use Case | Ratio | Notes |
70
- |----------|-------|-------|
71
- | Square / social | `1:1` | Default |
72
- | Portrait | `3:4` or `2:3` | Vertical |
73
- | Landscape | `4:3` or `16:9` | Wide |
74
- | Phone / story | `9:16` | Vertical tall |
75
- | Ultrawide | `21:9` | Cinematic |
89
+ | Use Case | Ratio | Notes |
90
+ | --------------- | --------------- | ------------- |
91
+ | Square / social | `1:1` | Default |
92
+ | Portrait | `3:4` or `2:3` | Vertical |
93
+ | Landscape | `4:3` or `16:9` | Wide |
94
+ | Phone / story | `9:16` | Vertical tall |
95
+ | Ultrawide | `21:9` | Cinematic |
96
+
97
+ OpenAI maps ratios to closest supported size. At `--resolution 1K` (default): `1024x1024`, `1024x1536`, `1536x1024`. At `--resolution 2K`: `2048x2048`, `1536x2048`, `2048x1536` (gpt-image-2 only; dims must be multiples of 16, max ~2048).
98
+
99
+ ## Resolution (`--resolution`)
76
100
 
77
- OpenAI maps ratios to closest supported size (`1024x1024`, `1024x1536`, `1536x1024`).
101
+ - OpenAI: `1K` (default) or `2K` (gpt-image-2 only).
102
+ - Gemini: `1K` (default), `2K`, or `4K`. **Caveat:** `gemini-3.1-flash-image-preview` currently ignores 2K/4K and returns ~1K — use `gemini-3-pro-image-preview` for true 2K/4K.
78
103
 
79
- ## OpenAI Quality (gpt-image-1 only)
104
+ ## OpenAI Quality (`--quality`)
105
+
106
+ Applies to all `gpt-image-*` models.
80
107
 
81
108
  - `auto` (default) — let the model decide
82
109
  - `high` — best quality, slower
@@ -100,6 +127,7 @@ For photorealistic results, use structured JSON prompts covering separate concer
100
127
  ```
101
128
 
102
129
  Key principles:
130
+
103
131
  1. **Separate concerns** — one aspect per block
104
132
  2. **Specify camera** — lens mm and aperture drive realism
105
133
  3. **Light direction** — "soft light from upper right" > "good lighting"
@@ -108,13 +136,14 @@ Key principles:
108
136
 
109
137
  ## Provider Selection Guide
110
138
 
111
- | Need | Use |
112
- |------|-----|
113
- | General image gen, highest quality | OpenAI `gpt-image-1.5` |
114
- | Budget-friendly | OpenAI `gpt-image-1-mini` |
115
- | Reference-based identity (same face) | Gemini (better at preserving identity from reference) |
116
- | Image editing / inpainting | OpenAI edit mode (`--reference`) |
117
- | Free tier / no OpenAI key | Gemini |
139
+ | Need | Use |
140
+ | ------------------------------------ | ------------------------------------------------------------ |
141
+ | General image gen, highest quality | OpenAI `gpt-image-2` |
142
+ | Budget-friendly | OpenAI `gpt-image-1-mini` or Gemini `gemini-2.5-flash-image` |
143
+ | Reference-based identity (same face) | Gemini (better at preserving identity from reference) |
144
+ | Image editing / inpainting | OpenAI edit mode (`--reference`) |
145
+ | 4K output | Gemini `gemini-3-pro-image-preview` (`--resolution 4K`) |
146
+ | Free tier / no OpenAI key | Gemini |
118
147
 
119
148
  ## Combining with Bella
120
149
 
@@ -3,21 +3,25 @@
3
3
  General-purpose image generation using OpenAI (default) or Gemini.
4
4
 
5
5
  Supports:
6
- - OpenAI: gpt-image-1.5 (default), gpt-image-1, gpt-image-1-mini
6
+ - OpenAI: gpt-image-2 (default), gpt-image-1.5, gpt-image-1-mini
7
7
  - Gemini: gemini-3.1-flash-image-preview (default), gemini-3-pro-image-preview, gemini-2.5-flash-image
8
8
 
9
9
  Usage:
10
10
  # OpenAI (default)
11
11
  python3 generate_image.py --prompt "A sunset over mountains"
12
12
 
13
+ # OpenAI 2K output (gpt-image-2 only)
14
+ python3 generate_image.py --prompt "Detailed cityscape" --resolution 2K
15
+
13
16
  # OpenAI with reference image (edit mode)
14
17
  python3 generate_image.py --prompt "Add a hot air balloon" --reference photo.png
15
18
 
16
19
  # Gemini
17
20
  python3 generate_image.py --provider gemini --prompt "A sunset over mountains"
18
21
 
19
- # Gemini with reference image
20
- python3 generate_image.py --provider gemini --prompt "Same person in a cafe" --reference face.png
22
+ # Gemini Pro at 4K
23
+ python3 generate_image.py --provider gemini --model gemini-3-pro-image-preview \\
24
+ --prompt "Cinematic landscape" --resolution 4K --aspect-ratio 16:9
21
25
  """
22
26
 
23
27
  from __future__ import annotations
@@ -40,17 +44,26 @@ NIA_CONFIG = NIA_HOME / "config.yaml"
40
44
  TIMESTAMP_FORMAT = "%Y%m%d_%H%M%S"
41
45
 
42
46
  # --- Provider defaults ---
43
- OPENAI_DEFAULT_MODEL = "gpt-image-1.5"
47
+ OPENAI_DEFAULT_MODEL = "gpt-image-2"
44
48
  GEMINI_DEFAULT_MODEL = "gemini-3.1-flash-image-preview"
45
49
 
46
50
  DEFAULT_ASPECT_RATIO = "1:1"
47
51
  ALLOWED_ASPECT_RATIOS = (
48
- "1:1", "3:4", "4:3", "9:16", "16:9",
49
- "2:3", "3:2", "4:5", "5:4", "21:9",
52
+ "1:1",
53
+ "3:4",
54
+ "4:3",
55
+ "9:16",
56
+ "16:9",
57
+ "2:3",
58
+ "3:2",
59
+ "4:5",
60
+ "5:4",
61
+ "21:9",
50
62
  )
51
63
 
52
- # OpenAI size mappings (closest match for aspect ratio)
53
- OPENAI_SIZE_MAP = {
64
+ # OpenAI size mappings per resolution (closest match for aspect ratio).
65
+ # 2K caps at 2048; dims must be multiples of 16. gpt-image-2 only.
66
+ OPENAI_SIZE_MAP_1K = {
54
67
  "1:1": "1024x1024",
55
68
  "3:4": "1024x1536",
56
69
  "4:3": "1536x1024",
@@ -62,10 +75,25 @@ OPENAI_SIZE_MAP = {
62
75
  "5:4": "1536x1024",
63
76
  "21:9": "1536x1024",
64
77
  }
78
+ OPENAI_SIZE_MAP_2K = {
79
+ "1:1": "2048x2048",
80
+ "3:4": "1536x2048",
81
+ "4:3": "2048x1536",
82
+ "9:16": "1536x2048",
83
+ "16:9": "2048x1536",
84
+ "2:3": "1536x2048",
85
+ "3:2": "2048x1536",
86
+ "4:5": "1536x2048",
87
+ "5:4": "2048x1536",
88
+ "21:9": "2048x1536",
89
+ }
65
90
 
66
- # OpenAI quality options
91
+ # OpenAI quality options (applies to all gpt-image-* models)
67
92
  OPENAI_QUALITIES = ("auto", "high", "medium", "low")
68
93
 
94
+ # Resolution choices. OpenAI: 1K|2K (2K requires gpt-image-2). Gemini: 1K|2K|4K.
95
+ ALLOWED_RESOLUTIONS = ("1K", "2K", "4K")
96
+
69
97
 
70
98
  def safe_mime(path: str) -> str:
71
99
  mime, _ = mimetypes.guess_type(path)
@@ -92,6 +120,7 @@ def read_config_key(key: str) -> str:
92
120
  return ""
93
121
  try:
94
122
  import importlib
123
+
95
124
  yaml = importlib.import_module("yaml")
96
125
  with NIA_CONFIG.open("r") as f:
97
126
  config = yaml.safe_load(f)
@@ -110,10 +139,7 @@ def resolve_api_key(provider: str, cli_key: str | None) -> str:
110
139
  return cli_key
111
140
 
112
141
  if provider == "openai":
113
- return (
114
- os.environ.get("OPENAI_API_KEY", "")
115
- or read_config_key("openai_api_key")
116
- )
142
+ return os.environ.get("OPENAI_API_KEY", "") or read_config_key("openai_api_key")
117
143
  else:
118
144
  return (
119
145
  os.environ.get("GEMINI_API_KEY", "")
@@ -124,6 +150,7 @@ def resolve_api_key(provider: str, cli_key: str | None) -> str:
124
150
 
125
151
  # --- OpenAI Generation ---
126
152
 
153
+
127
154
  def generate_openai(
128
155
  api_key: str,
129
156
  prompt: str,
@@ -139,18 +166,15 @@ def generate_openai(
139
166
  return _openai_generate(api_key, prompt, model, size, quality, n)
140
167
 
141
168
 
142
- def _openai_generate(
143
- api_key: str, prompt: str, model: str, size: str, quality: str, n: int
144
- ) -> tuple[bytes, str]:
169
+ def _openai_generate(api_key: str, prompt: str, model: str, size: str, quality: str, n: int) -> tuple[bytes, str]:
145
170
  url = "https://api.openai.com/v1/images/generations"
146
171
  payload: dict = {
147
172
  "model": model,
148
173
  "prompt": prompt,
149
174
  "n": n,
150
175
  "size": size,
151
- "response_format": "b64_json",
152
176
  }
153
- if model == "gpt-image-1":
177
+ if model.startswith("gpt-image-"):
154
178
  payload["quality"] = quality
155
179
 
156
180
  req = urllib.request.Request(
@@ -166,8 +190,7 @@ def _openai_generate(
166
190
 
167
191
 
168
192
  def _openai_edit(
169
- api_key: str, prompt: str, reference_path: str, model: str, size: str,
170
- quality: str, n: int
193
+ api_key: str, prompt: str, reference_path: str, model: str, size: str, quality: str, n: int
171
194
  ) -> tuple[bytes, str]:
172
195
  """Use OpenAI images/edits endpoint with a reference image."""
173
196
  import io
@@ -184,9 +207,7 @@ def _openai_edit(
184
207
  filename = Path(filepath).name
185
208
  mime = safe_mime(filepath)
186
209
  body.write(f"--{boundary}\r\n".encode())
187
- body.write(
188
- f'Content-Disposition: form-data; name="{name}"; filename="{filename}"\r\n'.encode()
189
- )
210
+ body.write(f'Content-Disposition: form-data; name="{name}"; filename="{filename}"\r\n'.encode())
190
211
  body.write(f"Content-Type: {mime}\r\n\r\n".encode())
191
212
  with open(filepath, "rb") as f:
192
213
  body.write(f.read())
@@ -197,7 +218,7 @@ def _openai_edit(
197
218
  add_field("model", model)
198
219
  add_field("n", str(n))
199
220
  add_field("size", size)
200
- if model == "gpt-image-1":
221
+ if model.startswith("gpt-image-"):
201
222
  add_field("quality", quality)
202
223
  body.write(f"--{boundary}--\r\n".encode())
203
224
 
@@ -220,9 +241,7 @@ def _openai_request(req: urllib.request.Request) -> tuple[bytes, str]:
220
241
  response = json.loads(resp.read().decode("utf-8"))
221
242
  except urllib.error.HTTPError as e:
222
243
  detail = e.read().decode("utf-8", errors="ignore")
223
- raise RuntimeError(
224
- f"OpenAI API error (HTTP {e.code}): {detail or e.reason}"
225
- ) from e
244
+ raise RuntimeError(f"OpenAI API error (HTTP {e.code}): {detail or e.reason}") from e
226
245
 
227
246
  data_list = response.get("data", [])
228
247
  if not data_list:
@@ -237,33 +256,40 @@ def _openai_request(req: urllib.request.Request) -> tuple[bytes, str]:
237
256
 
238
257
  # --- Gemini Generation ---
239
258
 
259
+
240
260
  def generate_gemini(
241
261
  api_key: str,
242
262
  prompt: str,
243
263
  model: str,
244
264
  aspect_ratio: str,
265
+ resolution: str = "1K",
245
266
  reference_path: str | None = None,
246
267
  ) -> tuple[bytes, str]:
247
268
  """Generate image via Gemini API."""
248
- url = (
249
- "https://generativelanguage.googleapis.com/"
250
- f"v1beta/models/{model}:generateContent?key={api_key}"
251
- )
269
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={api_key}"
252
270
 
253
271
  parts: list[dict] = []
254
272
  if reference_path and Path(reference_path).is_file():
255
- parts.append({
256
- "inlineData": {
257
- "mimeType": safe_mime(reference_path),
258
- "data": encode_file(reference_path),
273
+ parts.append(
274
+ {
275
+ "inlineData": {
276
+ "mimeType": safe_mime(reference_path),
277
+ "data": encode_file(reference_path),
278
+ }
259
279
  }
260
- })
280
+ )
261
281
  parts.append({"text": prompt})
262
282
 
283
+ image_config: dict = {"aspectRatio": aspect_ratio}
284
+ if resolution and resolution != "1K":
285
+ # gemini-3.1-flash-image-preview currently ignores this and returns ~1K (Google bug);
286
+ # gemini-3-pro-image-preview honors it. Send anyway so it works once Flash is fixed.
287
+ image_config["imageSize"] = resolution
288
+
263
289
  payload = {
264
290
  "contents": [{"parts": parts}],
265
291
  "generationConfig": {
266
- "imageConfig": {"aspectRatio": aspect_ratio},
292
+ "imageConfig": image_config,
267
293
  "responseModalities": ["TEXT", "IMAGE"],
268
294
  },
269
295
  }
@@ -280,9 +306,7 @@ def generate_gemini(
280
306
  response = json.loads(resp.read().decode("utf-8"))
281
307
  except urllib.error.HTTPError as e:
282
308
  detail = e.read().decode("utf-8", errors="ignore")
283
- raise RuntimeError(
284
- f"Gemini API error (HTTP {e.code}): {detail or e.reason}"
285
- ) from e
309
+ raise RuntimeError(f"Gemini API error (HTTP {e.code}): {detail or e.reason}") from e
286
310
 
287
311
  candidates = response.get("candidates", [])
288
312
  if not candidates:
@@ -298,13 +322,12 @@ def generate_gemini(
298
322
  if mime and img_data:
299
323
  return base64.b64decode(img_data), mime
300
324
 
301
- raise RuntimeError(
302
- f"No image in Gemini response: {json.dumps(response, indent=2)}"
303
- )
325
+ raise RuntimeError(f"No image in Gemini response: {json.dumps(response, indent=2)}")
304
326
 
305
327
 
306
328
  # --- CLI ---
307
329
 
330
+
308
331
  def main() -> None:
309
332
  parser = argparse.ArgumentParser(
310
333
  description="Generate images using OpenAI (default) or Gemini.",
@@ -319,39 +342,58 @@ Examples:
319
342
  """,
320
343
  )
321
344
  parser.add_argument(
322
- "--provider", choices=["openai", "gemini"], default="openai",
345
+ "--provider",
346
+ choices=["openai", "gemini"],
347
+ default="openai",
323
348
  help="Image generation provider. Default: openai.",
324
349
  )
325
350
  parser.add_argument(
326
- "--prompt", required=True,
351
+ "--prompt",
352
+ required=True,
327
353
  help="Text prompt describing the image to generate.",
328
354
  )
329
355
  parser.add_argument(
330
- "--reference", default=None,
356
+ "--reference",
357
+ default=None,
331
358
  help="Path to a reference image. OpenAI uses edit mode; Gemini includes it as context.",
332
359
  )
333
360
  parser.add_argument(
334
- "--model", default=None,
361
+ "--model",
362
+ default=None,
335
363
  help=f"Model override. Defaults: OpenAI={OPENAI_DEFAULT_MODEL}, Gemini={GEMINI_DEFAULT_MODEL}.",
336
364
  )
337
365
  parser.add_argument(
338
- "--aspect-ratio", default=DEFAULT_ASPECT_RATIO, choices=ALLOWED_ASPECT_RATIOS,
366
+ "--aspect-ratio",
367
+ default=DEFAULT_ASPECT_RATIO,
368
+ choices=ALLOWED_ASPECT_RATIOS,
339
369
  help=f"Aspect ratio. Default: {DEFAULT_ASPECT_RATIO}.",
340
370
  )
341
371
  parser.add_argument(
342
- "--quality", default="auto", choices=OPENAI_QUALITIES,
343
- help="OpenAI quality (gpt-image-1 only). Default: auto.",
372
+ "--quality",
373
+ default="auto",
374
+ choices=OPENAI_QUALITIES,
375
+ help="OpenAI quality (all gpt-image-* models). Default: auto.",
376
+ )
377
+ parser.add_argument(
378
+ "--resolution",
379
+ default="1K",
380
+ choices=ALLOWED_RESOLUTIONS,
381
+ help="Output resolution. OpenAI: 1K|2K (2K needs gpt-image-2). Gemini: 1K|2K|4K (2K/4K reliable on Pro only). Default: 1K.",
344
382
  )
345
383
  parser.add_argument(
346
- "--n", type=int, default=1,
384
+ "--n",
385
+ type=int,
386
+ default=1,
347
387
  help="Number of images (OpenAI only). Default: 1.",
348
388
  )
349
389
  parser.add_argument(
350
- "--output", default=None,
390
+ "--output",
391
+ default=None,
351
392
  help="Output path. Directory = timestamped file. Default: /tmp/.",
352
393
  )
353
394
  parser.add_argument(
354
- "--api-key", default=None,
395
+ "--api-key",
396
+ default=None,
355
397
  help="API key override. Otherwise reads from env var or ~/.niahere/config.yaml.",
356
398
  )
357
399
  args = parser.parse_args()
@@ -364,8 +406,7 @@ Examples:
364
406
  config_key = "openai_api_key" if provider == "openai" else "gemini_api_key"
365
407
  env_var = "OPENAI_API_KEY" if provider == "openai" else "GEMINI_API_KEY"
366
408
  raise SystemExit(
367
- f"Missing API key. Provide --api-key, set {env_var} in environment, "
368
- f"or add {config_key} to {NIA_CONFIG}."
409
+ f"Missing API key. Provide --api-key, set {env_var} in environment, or add {config_key} to {NIA_CONFIG}."
369
410
  )
370
411
 
371
412
  if args.reference and not Path(args.reference).expanduser().is_file():
@@ -375,15 +416,29 @@ Examples:
375
416
 
376
417
  try:
377
418
  if provider == "openai":
378
- size = OPENAI_SIZE_MAP.get(args.aspect_ratio, "1024x1024")
419
+ if args.resolution == "4K":
420
+ raise SystemExit("OpenAI does not support 4K via this script — use --provider gemini --resolution 4K.")
421
+ if args.resolution == "2K" and model != "gpt-image-2":
422
+ raise SystemExit(f"2K is only supported on gpt-image-2 (got --model {model}).")
423
+ size_map = OPENAI_SIZE_MAP_2K if args.resolution == "2K" else OPENAI_SIZE_MAP_1K
424
+ size = size_map.get(args.aspect_ratio, size_map["1:1"])
379
425
  image_data, mime = generate_openai(
380
- api_key=api_key, prompt=args.prompt, model=model,
381
- size=size, quality=args.quality, reference_path=ref, n=args.n,
426
+ api_key=api_key,
427
+ prompt=args.prompt,
428
+ model=model,
429
+ size=size,
430
+ quality=args.quality,
431
+ reference_path=ref,
432
+ n=args.n,
382
433
  )
383
434
  else:
384
435
  image_data, mime = generate_gemini(
385
- api_key=api_key, prompt=args.prompt, model=model,
386
- aspect_ratio=args.aspect_ratio, reference_path=ref,
436
+ api_key=api_key,
437
+ prompt=args.prompt,
438
+ model=model,
439
+ aspect_ratio=args.aspect_ratio,
440
+ resolution=args.resolution,
441
+ reference_path=ref,
387
442
  )
388
443
 
389
444
  ext = ".png" if "png" in mime else ".jpg"
@@ -391,7 +446,7 @@ Examples:
391
446
  out.parent.mkdir(parents=True, exist_ok=True)
392
447
  out.write_bytes(image_data)
393
448
  print(f"Saved: {out}")
394
- print(f"Provider: {provider} | Model: {model} | Size/Ratio: {args.aspect_ratio}")
449
+ print(f"Provider: {provider} | Model: {model} | Ratio: {args.aspect_ratio} | Resolution: {args.resolution}")
395
450
  except Exception as exc:
396
451
  print(f"Error: {exc}", file=sys.stderr)
397
452
  raise SystemExit(1) from exc