Skip to content

Commit 79c3429

Browse files
committed
fix(generate_image): enhance image handling and output path resolution in generate_image script
1 parent b8bbc75 commit 79c3429

1 file changed

Lines changed: 32 additions & 39 deletions

File tree

skills/nano-banana-pro-openrouter/scripts/generate_image.py

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import os
1616
from pathlib import Path
1717

18+
from openai import OpenAI
19+
1820

1921
# Configuration
2022
MAX_INPUT_IMAGES = 3
@@ -56,24 +58,25 @@ def require_api_key():
5658
def encode_image_to_data_url(path: Path) -> str:
5759
if not path.exists():
5860
raise SystemExit(f"Input image not found: {path}")
59-
mime, _ = mimetypes.guess_type(path.name)
61+
mime, _ = mimetypes.guess_type(str(path))
6062
if not mime:
6163
mime = "image/png"
6264
data = path.read_bytes()
6365
encoded = base64.b64encode(data).decode("utf-8")
6466
return f"data:{mime};base64,{encoded}"
6567

6668

67-
def build_message_content(prompt: str, input_images):
68-
content = [{"type": "text", "text": prompt}]
69+
def build_message_content(prompt: str, input_images: list[str]) -> list[dict]:
70+
content: list[dict] = [{"type": "text", "text": prompt}]
6971
for image_path in input_images:
7072
data_url = encode_image_to_data_url(Path(image_path))
7173
content.append({"type": "image_url", "image_url": {"url": data_url}})
7274
return content
7375

74-
def parse_data_url(data_url: str):
76+
77+
def parse_data_url(data_url: str) -> tuple[str, bytes]:
7578
if not data_url.startswith("data:") or ";base64," not in data_url:
76-
raise ValueError("Image URL is not a base64 data URL.")
79+
raise SystemExit("Image URL is not a base64 data URL.")
7780
header, encoded = data_url.split(",", 1)
7881
mime = header[5:].split(";", 1)[0]
7982
try:
@@ -83,35 +86,27 @@ def parse_data_url(data_url: str):
8386
return mime, raw
8487

8588

86-
def resolve_output_paths(filename: str, image_count: int, mime: str):
87-
output_path = Path(filename)
88-
suffix = output_path.suffix
89-
90-
# Validate/correct suffix matches MIME type
91-
expected_suffix = MIME_TO_EXT.get(mime, ".png")
92-
if suffix and suffix.lower() != expected_suffix.lower():
93-
print(f"Warning: filename extension '{suffix}' doesn't match returned MIME type '{mime}'. Using '{expected_suffix}' instead.")
94-
suffix = expected_suffix
95-
elif not suffix:
96-
suffix = expected_suffix
97-
98-
output_path = output_path.with_suffix(suffix)
89+
def resolve_output_path(filename: str, image_index: int, total_count: int, mime: str) -> Path:
90+
output_path = Path(filename)
91+
suffix = output_path.suffix
9992

100-
# Create parent directory if it doesn't exist (for paths with parent directories, absolute or relative)
101-
if output_path.parent and str(output_path.parent) != '.':
102-
output_path.parent.mkdir(parents=True, exist_ok=True)
93+
# Validate/correct suffix matches MIME type
94+
expected_suffix = MIME_TO_EXT.get(mime, ".png")
95+
if suffix and suffix.lower() != expected_suffix.lower():
96+
print(f"Warning: filename extension '{suffix}' doesn't match returned MIME type '{mime}'. Using '{expected_suffix}' instead.")
97+
suffix = expected_suffix
98+
elif not suffix:
99+
suffix = expected_suffix
103100

104-
if image_count == 1:
105-
return [output_path]
101+
# Single image: use original stem + corrected suffix
102+
if total_count <= 1:
103+
return output_path.with_suffix(suffix)
106104

107-
paths = []
108-
for index in range(image_count):
109-
numbered = output_path.with_name(f"{output_path.stem}-{index + 1}{suffix}")
110-
paths.append(numbered)
111-
return paths
105+
# Multiple images: append numbering
106+
return output_path.with_name(f"{output_path.stem}-{image_index + 1}{suffix}")
112107

113108

114-
def extract_image_url(image):
109+
def extract_image_url(image: dict | object) -> str | None:
115110
if isinstance(image, dict):
116111
return image.get("image_url", {}).get("url") or image.get("url")
117112
return None
@@ -123,7 +118,7 @@ def load_system_prompt():
123118
template_path = script_dir / "assets" / "SYSTEM_TEMPLATE"
124119

125120
if template_path.exists():
126-
content = template_path.read_text().strip()
121+
content = template_path.read_text(encoding="utf-8").strip()
127122
if content:
128123
return content
129124
return None
@@ -135,9 +130,8 @@ def main():
135130
if len(args.input_image) > MAX_INPUT_IMAGES:
136131
raise SystemExit(f"Too many input images: {len(args.input_image)} (max {MAX_INPUT_IMAGES}).")
137132

138-
image_size = args.resolution or "1K"
133+
image_size = args.resolution
139134

140-
from openai import OpenAI
141135
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=require_api_key())
142136

143137
# Build messages with optional system prompt
@@ -173,19 +167,18 @@ def main():
173167
if not images:
174168
raise SystemExit("No images returned by the API.")
175169

176-
first_url = extract_image_url(images[0])
177-
if not first_url:
178-
raise SystemExit("Image payload missing image_url.url.")
179-
first_mime, _ = parse_data_url(first_url)
180-
output_paths = resolve_output_paths(args.filename, len(images), first_mime)
170+
# Create output directory once before processing images
171+
output_base_path = Path(args.filename)
172+
if output_base_path.parent and str(output_base_path.parent) != '.':
173+
output_base_path.parent.mkdir(parents=True, exist_ok=True)
181174

182175
saved_paths = []
183176
for idx, image in enumerate(images):
184177
image_url = extract_image_url(image)
185178
if not image_url:
186179
raise SystemExit("Image payload missing image_url.url.")
187-
_, raw = parse_data_url(image_url)
188-
output_path = output_paths[idx]
180+
mime, raw = parse_data_url(image_url)
181+
output_path = resolve_output_path(args.filename, idx, len(images), mime)
189182
output_path.write_bytes(raw)
190183
saved_paths.append(output_path.resolve())
191184

0 commit comments

Comments
 (0)