mcpField
P
product-shots-image-gen

product-shots-image-gen

github.com/motifulクリエイティブ・メディア121137 回インストール20 週間前に更新
リポジトリ

product-shots-image-gen について

画像生成リクエストをOpenAI系またはGemini系のAPIに振り分け、生成画像をディスクに保存するスキルです。プロダクトショットのワークフロー向けに、参照画像の前処理やモデル別パラメーター、APIキー設定の確認を行います。

主な機能

  1. 01モデルファミリー別のリクエスト振り分け
  2. 02テキストや参照画像から画像生成
  3. 03送信前の参照画像リサイズ
  4. 04アスペクト比とネガティブ制約の適用
  5. 05出力をローカル保存してパスを返却
  6. 06APIキー設定の事前確認

活用シーン

  1. 01プロンプトからプロダクト画像を生成
  2. 02参照ファイルを使った画像バリエーション作成
  3. 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.md
model-selection.md
parameter-spec.md
reference-image-handling.md
scripts/
generate.py
setup.sh

詳細

Image Gen

product-shots エコシステムの画像生成エンジンです。パラメーター指定可能な単一のエントリーポイントとして、モデルファミリーに基づいて適切な API エンドポイントにリクエストを振り分けます(OpenAI の /v1/images/generations と /v1/images/edits、Gemini の /v1/chat/completions マルチモーダル)。参照画像を前処理し、保存したファイルパスを返します。

主なバックエンド:OmniMaaS / Cloubic 画像ゲートウェイ — https://api.omnimaas.com/v1。このゲートウェイは OpenAI SDK と互換性があり、1 つの認証トークンで GPT image 2 と Gemini Nano Banana ファミリーへのアクセスを一元化します。以下を参照してください。

フォールバックバックエンド: OpenAI SDK と互換性のあるほかの画像ゲートウェイも利用できます。PRODUCT_SHOTS_IMAGEGEN_BASE_URL と PRODUCT_SHOTS_IMAGEGEN_API_KEY を設定するか、移行済みのインストールでは従来の CANVASFLOW_IMAGEGEN_* 環境変数をそのまま使用してください。

オンボーディング(初回セットアップ)

画像を生成する前に、このスキルは API ゲートウェイが設定されていることを必ず確認する必要があります。 環境変数が設定されていない場合は、以下の手順をそのままユーザーに表示してください。ハードコードされたキーに暗黙的にフォールバックしたり、リポジトリをフォークするよう求めたり、チャットにキーを貼り付けるよう求めたりしてはいけません。

検出ロジック

呼び出しのたびに実行します。解決順序は次のとおりです。

  1. OMNIMAAS_API_KEY(環境変数、優先 — Cloubic / OmniMaaS 共通ゲートウェイ)
  2. PRODUCT_SHOTS_IMAGEGEN_API_KEY(環境変数、汎用フォールバック)
  3. CANVASFLOW_IMAGEGEN_API_KEY(環境変数、従来との互換性)
  4. ~/.product_shots_imagegen_api_key(ファイル、chmod 600、キーを1行で記載)
  5. ~/.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 と Gemini の gemini-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 を使用してこの問題に対処しています。独自の呼び出し処理を実装する場合も、このパターンを再現してください。

エンゲージメントの原則

以下のルールは常に適用されます。実行する前にお読みください。

  1. モデルファミリーを自動検出します。ユーザーには決して尋ねません。 モデル名(例:gpt-image-2 と gemini-3-pro-image-preview)によって、エンドポイントとリクエスト形式が決まります。呼び出し元がモデルを指定し、スキルがファミリーを判別します。
  2. 呼び出し元がモデルを指定しない場合、デフォルトで gemini-3-pro-image-preview を使用します。 これは単一モデルとして最も高い性能を発揮し(Nano Banana Pro)、1つのエンドポイントでテキストから画像への生成と画像から画像への生成の両方をサポートします。references/model-selection.md を参照してください。
  3. 参照画像は送信前に、最大辺を1024px以下、かつファイルサイズを1MB以下にする必要があります。 そうでない場合は、自動的にサイズを変更します。その理由は、ほとんどのエッジプロキシが約100秒でタイムアウトするためです。2.5MBのPNGは、Base64への変換によるサイズ増加とGeminiの処理が加わると、この上限でHTTP 524を確実に引き起こします。references/reference-image-handling.md を参照してください。
  4. 否定制約は独立したパラメーターとして送信せず、「Avoid: …」としてプロンプトに追加します。 サポート対象モデルのうち、真の negative_prompt フィールドを公開しているものはありません。これは回避策ではなく、APIの設計によるものです。
  5. アスペクト比の処理はファミリーによって異なります。 OpenAIでは、ピクセル単位の size パラメーターに変換します。Geminiでは、chat-completionsにサイズフィールドがないため、プロンプトテキストに「aspect ratio: X:Y」として追加します。呼び出し元は --aspect-ratio を渡し、スキルが両方の処理に対応します。
  6. 出力は必ずディスクに保存し、パスを返します。 Base64やURLを呼び出し元に返してはいけません。ディスク上のファイルが正式な成果物です。デフォルトの保存場所にはタイムスタンプが使用されます。呼び出し元は --output で上書きできます。
  7. すべての呼び出しで、コストとトークン使用量を記録します。 呼び出し元は予算を管理できます。推定料金:gpt-image-2 ≈ 1枚あたり¥0.35、gemini-3-pro-image-preview ≈ 1枚あたり¥1、gemini-3.1-flash-image-preview ≈ 1枚あたり¥0.20。
  8. 画像から画像への生成では回数を制限して再試行し、それ以外ではすべて即時に失敗させます。 画像から画像への呼び出しでは、再試行可能なエラー(HTTP 429、5xx、524、接続エラー、読み取りタイムアウト)が発生した場合に、指数バックオフ(試行間隔は1秒、4秒、16秒)で最大3回再試行します。テキストから画像への呼び出しでは再試行しません。認証エラー(401/403)は即時に失敗させ、再試行しません。references/error-handling.md を参照してください。
  9. 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: ![image](data:image/jpeg;base64,...)
    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では1回の呼び出しにつき最大9枚)、そのまま渡すルール、Pillowの thumbnail を使用する理由(アスペクト比を維持)。
  • 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)。初回使用前に一度実行してください。
  • サブスキルの呼び出しはありません。 このスキルはリーフであり、ほかのスキルを呼び出しません。
  • 呼び出し元(ほかの product-shots スペシャリスト)はシェル経由で呼び出します。プラットフォーム固有のパスをハードコードするのではなく、ホストのスキルディレクトリからスクリプトのパスを解決してください。
    # 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.jpeg
    
    または、generate_openai / generate_gemini 関数を Python から直接インポートしてください。

呼び出し元との契約

product-shots エコシステム内の別のスキルから呼び出される場合(例: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 に自動設定します。追加の設定は不要です。

コメント