关于 product-shots-image-gen
此技能将图像生成请求路由到 OpenAI 或 Gemini 系列 API,并将结果保存到磁盘,适用于产品图工作流。它会预处理参考图,处理模型专属参数,并在调用前检查 API 密钥配置。
主要功能
- 01按模型系列路由请求
- 02根据文本或参考图生成图像
- 03发送前调整参考图尺寸
- 04处理宽高比与负面约束
- 05在本地保存结果并返回路径
- 06调用前检查 API 密钥配置
适用场景
- 01根据提示词生成产品图
- 02利用参考文件生成图像变体
- 03通过兼容网关执行图像生成
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ motiful/ product-shots --skill product-shots-image-gen安装后在 Claude Code 中输入/product-shots-image-gen确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/error-handling.mdmodel-selection.mdparameter-spec.mdreference-image-handling.mdscripts/generate.pysetup.sh详细介绍
图像生成
产品图生态系统的图像生成引擎。提供单一的参数化入口:根据模型系列将请求路由到正确的 API 端点(OpenAI 的 /v1/images/generations 和 /v1/images/edits,或 Gemini 的多模态 /v1/chat/completions),预处理参考图像,并返回已保存的文件路径。
主要后端:OmniMaaS / Cloubic 图像网关——https://api.omnimaas.com/v1。该网关兼容 OpenAI SDK,通过一个身份验证令牌统一提供对 GPT image 2 和 Gemini Nano Banana 系列的访问。请参阅:
- 通过 OmniMaaS 使用 GPT image 2:https://docs.cloubic.com/docs/zh-CN/image-generation/image-openai
- 通过 OmniMaaS 使用 Gemini:https://docs.cloubic.com/docs/zh-CN/image-generation/image-gemini
**备用后端:**任何其他兼容 OpenAI SDK 的图像网关均可使用——设置 PRODUCT_SHOTS_IMAGEGEN_BASE_URL 和 PRODUCT_SHOTS_IMAGEGEN_API_KEY,或者在迁移后的安装中继续使用旧版 CANVASFLOW_IMAGEGEN_* 环境变量。
入门设置(首次使用)
**生成任何图像之前,此技能都必须确认已配置 API 网关。**如果缺少环境变量,请将以下说明原样展示给用户——绝不要静默回退到硬编码密钥,也不要要求用户复刻仓库或将密钥粘贴到聊天中。
检测逻辑
每次调用时都运行。按以下顺序解析:
OMNIMAAS_API_KEY(环境变量,优先使用——统一的 Cloubic / OmniMaaS 网关)PRODUCT_SHOTS_IMAGEGEN_API_KEY(环境变量,通用备用项)CANVASFLOW_IMAGEGEN_API_KEY(环境变量,旧版兼容项)~/.product_shots_imagegen_api_key(文件,权限设为 600,单行密钥)~/.canvasflow_imagegen_api_key(文件,旧版)
如果以上均未解析出密钥,停止并在下一节输出入门说明。不要尝试调用 API。
入门说明(缺少环境变量时原样展示给用户)
**此技能需要图像网关 API 密钥才能生成图像。**你尚未配置密钥——以下是 30 秒快速设置说明:
选项 A——临时设置(仅限当前终端):
export OMNIMAAS_API_KEY="sk-..." # 你的 OmniMaaS / Cloubic 令牌 # 可选:仅在你使用私有网关端点时设置 # export OMNIMAAS_BASE_URL="https://api.omnimaas.com/v1"选项 B——在多个会话中持续生效: 将相同的
export行添加到~/.zshrc(或~/.bashrc),然后运行source ~/.zshrc。选项 C——通过文件设置(无需环境变量):
echo "sk-..." > ~/.product_shots_imagegen_api_key chmod 600 ~/.product_shots_imagegen_api_key**获取密钥的方式:**访问 docs.cloubic.com——从 OmniMaaS / Cloubic 控制台获取令牌。同一个令牌可用于 OpenAI
gpt-image-2和 Geminigemini-3-pro-image-preview(Nano Banana Pro)。任何兼容 OpenAI SDK 的图像网关也都可以使用——将
OMNIMAAS_*替换为指向你的网关的PRODUCT_SHOTS_IMAGEGEN_BASE_URL和PRODUCT_SHOTS_IMAGEGEN_API_KEY。配置完成后,重新运行原始请求。
安全要求
- 绝不要回显完整密钥。确认检测到密钥时,只显示前 8 个字符(
sk-wPfH6K…)。 - 绝不要将密钥写入日志、标准输出或仓库内的任何文件。
- 绝不要指示用户复刻仓库、编辑技能源文件或将密钥粘贴到聊天中。密钥只能存放在环境变量或
~/.*_api_key文件中。 - API 密钥只能通过
Authorization: Bearer <key>标头传输。
本地代理绕过(中国用户)
ClashX / Shadowsocks / 类似的本地代理会将 ALL_PROXY=socks5://... 注入环境,从而导致 requests 出错(Missing dependencies for SOCKS support)。随附的 scripts/generate.py 已通过 Session.trust_env = False 处理此问题。如果你自行实现调用程序,请复现此模式。
交互原则
这些规则始终适用。执行前请阅读。
- 自动检测模型系列,绝不询问用户。 模型名称(例如
gpt-image-2与gemini-3-pro-image-preview)决定端点和请求格式。调用方指定模型;技能负责解析其所属系列。 - 调用方未指定模型时,默认使用
gemini-3-pro-image-preview。 它是单模型中表现最强的(Nano Banana Pro),并通过一个端点同时支持文生图和图生图。参见references/model-selection.md。 - 发送参考图前,最大尺寸必须 ≤1024px,且文件大小必须 ≤1MB。 否则自动调整大小。原因:大多数边缘代理会在约 100s 时超时;2.5MB 的 PNG 加上 base64 扩容和 Gemini 处理,通常会在该时限触发 HTTP 524。参见
references/reference-image-handling.md。 - 负向约束会以“避免:……”的形式附加到提示词中,绝不作为单独参数发送。 没有受支持的模型提供真正的
negative_prompt字段;这是 API 的设计如此,并非权宜之计。 - 不同系列的宽高比处理方式不同。 OpenAI:转换为像素
size参数。Gemini:附加到提示文本中(“宽高比:X:Y”),因为 chat-completions 没有尺寸字段。调用方传入--aspect-ratio;技能会分别处理。 - 始终将输出保存到磁盘并返回路径。 绝不向调用方返回 base64 或 URL——磁盘上的文件才是规范产物。默认位置使用时间戳;调用方可通过
--output覆盖。 - 每次调用都会记录费用和令牌用量。 调用方可据此进行预算。估算费率:gpt-image-2 ≈ ¥0.35/张,gemini-3-pro-image-preview ≈ ¥1/张,gemini-3.1-flash-image-preview ≈ ¥0.20/张。
- 图生图采用有限重试;其他情况一律快速失败。 图生图调用遇到可重试错误(HTTP 429、5xx、524、连接错误、读取超时)时,最多重试 3 次,并采用指数退避(每次尝试之间等待 1s、4s、16s)。文生图调用不重试。认证错误(401 / 403)会快速失败,绝不重试。参见
references/error-handling.md。 - API 密钥绝不会写入日志或标准输出。 按以下顺序加载:
OMNIMAAS_API_KEY(首选 — Cloubic / OmniMaaS 网关)→PRODUCT_SHOTS_IMAGEGEN_API_KEY(规范通用密钥)→RENDER_API_KEY(短别名)→CANVASFLOW_IMAGEGEN_API_KEY(旧版)→~/.product_shots_imagegen_api_key→~/.product_shots_render_api_key(兼容)→~/.canvasflow_imagegen_api_key(旧版)。仅通过Authorization标头传递。绝不回显。基础 URL 会自动解析(设置了OMNIMAAS_API_KEY且未显式设置OMNIMAAS_BASE_URL时,默认为https://api.omnimaas.com/v1)。
执行流程
请严格遵循此流程。每个步骤对应 scripts/generate.py 中的一个章节。
generate_image(prompt, model, [aspect_ratio], [negative_prompt],
[reference_images], [output_path]) → file_path
# Step 0 — Resolve API key + base URL (MUST come first)
api_key, key_source = load_api_key()
# 1. OMNIMAAS_API_KEY env var (preferred — OmniMaaS gateway)
# 2. PRODUCT_SHOTS_IMAGEGEN_API_KEY env var (canonical generic)
# 3. RENDER_API_KEY env var (short alias)
# 4. CANVASFLOW_IMAGEGEN_API_KEY env var (legacy)
# 5. ~/.product_shots_imagegen_api_key file
# 6. ~/.product_shots_render_api_key file (compat)
# 7. ~/.canvasflow_imagegen_api_key file (legacy)
# fail with clear message if none present
base_url, url_source = load_base_url()
# 1. OMNIMAAS_BASE_URL env var
# 2. PRODUCT_SHOTS_IMAGEGEN_BASE_URL env var (canonical generic)
# 3. RENDER_BASE_URL env var (short alias)
# 4. CANVASFLOW_IMAGEGEN_BASE_URL env var (legacy)
# 5. https://api.omnimaas.com/v1 (default when OMNIMAAS_API_KEY is set)
# Step 0a — Validate caller arguments + fill caller-context defaults
args = validate_args(args) # see references/parameter-spec.md
# rejects empty prompt, unknown model, invalid aspect_ratio
# auto-fills size for OpenAI from aspect_ratio
# warns when Gemini ignores --n / --size
args = lookup_caller_defaults(caller_skill, surface) | args
# caller-skill-specific defaults from parameter-spec.md §Family-Specific Defaults
# explicit args win over defaults (dict merge with args on the right)
# Step 1 — Resolve model + identify family
if not model:
model = select_default_model(use_case) # see references/model-selection.md
# use_case from caller brief: "text-overlay" / "photorealistic" /
# "creative" / "image-to-image" / "cost-sensitive" / "general" (default)
# ⚠ "text-overlay" WINS over all others — any caller whose prompt
# asks for on-image letters or digits (headlines, labels, CTAs,
# price chips, callouts) MUST pass "text-overlay" so the dispatcher
# routes to gpt-image-2. Gemini family garbles small text.
family = model_family(model) # see references/model-selection.md
# openai → {gpt-image-1, gpt-image-2, dall-e-3}
# gemini → {gemini-3-pro-image-preview, gemini-3.1-flash-image-preview, ...}
# unknown → exit with the supported model list
# Step 2 — Preprocess reference images (if any)
for img_path in reference_images:
img_path = maybe_resize(img_path, max_dim=1024, max_bytes=1MB)
# Pillow thumbnail → temp file
# passthrough if already within limits
# see references/reference-image-handling.md
# Step 3 — Compose effective prompt and size
final_prompt = compose_prompt(prompt, negative_prompt, aspect_ratio, family)
# Gemini: prompt + "(aspect ratio: X:Y)" + "Avoid: ..."
# OpenAI: prompt + "Avoid: ..." (aspect handled via size param instead)
if family == "openai":
size = OPENAI_SIZE_BY_RATIO[aspect_ratio] OR explicit --size OR "1024x1024"
# Step 4 — Dispatch
if family == "openai":
if reference_images:
response = POST <base_url>/images/edits (multipart, image[]=@file...)
else:
response = POST <base_url>/images/generations (JSON, {model, prompt, n, size})
elif family == "gemini":
response = POST <base_url>/chat/completions
body: {model, messages:[{role:"user", content:[
{type:"text", text: final_prompt},
{type:"image_url", image_url:{url: data_url_per_ref_image}}, ...
]}]}
if response.status != 200:
handle_http_error(family, response.status, response.body)
# see references/error-handling.md
# Step 5 — Parse response (family-specific)
if family == "openai":
first = response.body["data"][0]
if "b64_json" not in first and "url" not in first:
classify_response_error(family, response.body) # references/error-handling.md
image_bytes = base64_decode(first["b64_json"]) if "b64_json" in first else fetch(first["url"])
ext = "png"
elif family == "gemini":
content = response.body["choices"][0]["message"]["content"]
# content is a markdown string: 
if no "data:image/...;base64" pattern in content:
classify_response_error(family, response.body) # references/error-handling.md
image_bytes = base64_decode(extract_data_url(content))
ext = "jpeg"
# Step 6 — Save + log
out_path = output_path OR ./output-<unix_ts>.<ext>
write_bytes(out_path, image_bytes)
log(gateway_source, elapsed, file_size, total_tokens, out_path)
# Self-check
assert out_path.exists()
assert out_path.stat().st_size > 10_000 # tiny files = broken response
return out_path
模块文件目录
references/model-selection.md— 模型目录(此技能支持的图像模型)、系列路由规则,以及按使用场景选择合适模型的决策树(照片级真实感 / 文本渲染 / 低成本高速 / CJK 文本渲染)。references/parameter-spec.md—scripts/generate.py的所有 CLI 标志:名称、类型、默认值、适用的系列、有效范围。调用方可传入内容的唯一可信来源——包括完整的 API 密钥 / 基础 URL 解析顺序。references/reference-image-handling.md— 524 错误的发现、1024px / 1MB 上限、多参考图行为(Gemini 每次调用最多 ≤9 张图片)、直传规则,以及使用 Pillowthumbnail的原因(保留宽高比)。references/error-handling.md— 常见 API 故障模式(401 / 429 / 524 / 响应格式错误 / 连接超时),以及诊断消息和建议的调用方处理方式。524 → 调整大小并重试模式。
章节索引
Goal → SKILL.md intro paragraph
Engagement Principles → SKILL.md §Engagement Principles
Execution Procedure → SKILL.md §Execution Procedure
Model Selection → references/model-selection.md
Family Routing
Model Catalogue
Decision Tree
Parameter Spec → references/parameter-spec.md
CLI Flags
Aspect Ratio → OpenAI Size Mapping
API Key + Base URL Resolution
Reference Image Handling → references/reference-image-handling.md
The 524 Finding
Auto-Resize Rule
Multi-Reference Constraints
Error Handling → references/error-handling.md
Common Failure Modes
Retry Patterns
工具配置
scripts/generate.py— 参数化入口。仅使用标准库、requests和Pillow。无需主机功能支持。scripts/setup.sh— 幂等依赖安装程序(Python 3 + pip + requests + Pillow)。首次使用前运行一次。- 不调用子技能。此技能是叶节点,不会调用其他技能。
- 调用方(其他产品截图专用技能)通过 shell 调用。请从主机的技能目录解析脚本路径,而不要硬编码任何平台路径:
或通过直接导入 Python 中的# Path examples — pick whichever your harness uses; do NOT bake one in: # Claude Code: ~/.claude/skills/product-shots-image-gen/scripts/generate.py # Codex: ~/.agents/skills/product-shots-image-gen/scripts/generate.py # Cursor: ~/.cursor/skills/product-shots-image-gen/scripts/generate.py # Windsurf: ~/.codeium/windsurf/skills/product-shots-image-gen/scripts/generate.py # Copilot: ~/.copilot/skills/product-shots-image-gen/scripts/generate.py python <skill-dir>/scripts/generate.py \ --prompt "..." --model gemini-3-pro-image-preview --output ./out.jpeggenerate_openai/generate_gemini函数调用。
调用方约定
从产品截图生态系统中的其他技能调用时(例如,product-shots-main-image 执行 image = generate_image(prompt) 步骤),调用方会传入:
| 字段 | 必填 | 格式 | 技能行为 |
|---|---|---|---|
prompt | 是 | 字符串,≤4000 个字符 | 原样传递(并附加负面提示词和宽高比) |
model | 是 | 来自支持的集合 | 按系列路由到相应端点 |
aspect_ratio | 否 | "1:1" / "16:9" / "9:16" / "4:3" / "3:4" / "3:2" / "2:3" | OpenAI:→ size;Gemini:附加到提示词 |
reference_images | 否 | 文件路径列表 | 发送前自动调整大小至 ≤1024px / ≤1MB |
negative_prompt | 否 | 字符串 | 以 "Avoid: …" 的形式附加 |
output | 否 | 文件路径 | 默认为 ./output-<ts>.<png|jpeg> |
返回:磁盘上的文件路径(OpenAI 为 PNG,Gemini 为 JPEG)。调用方必须将该文件视为规范产物。
OmniMaaS 网关快速入门
# 1. Get an OmniMaaS / Cloubic API token from https://docs.cloubic.com
export OMNIMAAS_API_KEY="your-omnimaas-token"
# 2. (optional) Override the base URL if you have a private endpoint
# export OMNIMAAS_BASE_URL="https://api.omnimaas.com/v1"
# 3. Install dependencies
bash scripts/setup.sh
# 4. Test
python scripts/generate.py --prompt "a red apple on wood" \
--model gemini-3-pro-image-preview \
--output /tmp/test.jpeg
设置 OMNIMAAS_API_KEY 后,脚本会自动将基础 URL 默认设为 https://api.omnimaas.com/v1,无需额外配置。