
はじめに — 「画像があるだけで、ちゃんとしたサイトに見える」
ZERONOVA LABには93個の無料ツール、70以上のJournal記事、複数のFocus Blog記事があります。これらのコンテンツがTodayFeed(トップページのカードフィード)に並ぶとき、画像があるカードとないカードでは印象がまるで違います。
画像があるだけで「ちゃんとしたサイト」に見えるのは不思議だけど事実。Gemini でサクッと画像が作れるのも便利で、「この仕組みを別のサービスにできるのでは?」という発想が自然に出てきた。
2月28日のストーリーログにこう書きました。93個のツール、70以上の記事があり、すべてに手動でイラストを用意するのは現実的ではありません。かといって画像なしのカードが並ぶと、サイト全体が「作りかけ」に見えてしまう。
この問題を解決するために、npm run cardコマンド1つでGemini APIを呼び出し、コンテンツに合ったカード画像を自動生成するパイプラインを作りました。画像のテイストを統一しつつ、各コンテンツの特性に合ったイラストを生成する。簡単に聞こえますが、実際には予想外の落とし穴がいくつもありました。
最初のアプローチ — 参考画像をAIに見せる
最初に考えたのは「参考画像方式」でした。すでに手動で作った高品質なカード画像が何枚かあったので、それをGemini APIに送り、「このテイストで新しい画像を作って」と指示する方式です。
「AIに伝えるには画像が最強」と思っていました。テキストで「フラットなイラスト、ビビッドな色使い、可愛いロボット」と説明するより、実物を見せた方が確実に伝わるはずです。人間のコミュニケーションでは、百聞は一見に如かず。AIでも同じだろうと考えました。
実装は素直でした。2-3枚の参考画像をWebP圧縮してAPIリクエストに添付し、テキストプロンプトと一緒に送信する。--refオプションで参考画像を指定できるCLIインターフェースも用意しました。
理論上は完璧。しかし実際に動かすと、問題が次々と発生しました。
参考画像方式の破綻 — 3つの壁
1. 安全フィルターの誤爆
最初に発覚した問題は、Gemini APIの安全フィルターでした。
ツール名や説明文に「セキュリティ診断」「脆弱性チェック」といった単語が含まれると、画像生成がブロックされます。Vibe Auditのカード画像を生成しようとしたとき、HARM_CATEGORY_DANGEROUS_CONTENTに引っかかりました。
イラストを生成しているだけなのに、ツールの説明文が「危険なコンテンツ」として判定されてしまう。参考画像の存在がリクエスト全体の「リスクスコア」を押し上げている可能性もありました。
2. APIリクエストサイズの膨張
参考画像を2-3枚添付すると、APIリクエストのペイロードが大幅に増加します。WebP圧縮していてもBase64エンコード後は数百KB。テキストだけなら数KBで済むリクエストが、画像を添付するだけで100倍以上に膨れ上がります。
大量のカード画像を一括生成するときに、このペイロードサイズは無視できないコストになります。
3. レスポンス形式の不統一
これは参考画像方式に固有の問題ではありませんが、このタイミングで発見しました。Gemini APIのレスポンスで、同じフィールドがsnake_case(inline_data、mime_type)で返ってくる場合とcamelCase(inlineData、mimeType)で返ってくる場合がありました。
APIドキュメントと実際のレスポンスが一致しない。これは後述するテキストプロンプト方式でも対処が必要な問題でした。
ところが、実際に動かしてみると参考画像方式には問題が出た。安全フィルターが誤動作してイラスト生成がブロックされたり、APIリクエストサイズが膨らんだり。
2月28日のストーリーログの記述です。「AIに伝えるには画像が最強」という仮説は、API制約の現実の前に崩れました。
転換 — テキストプロンプト方式への全面書き換え
PM-AI 対話: 方式転換の判断
「画像で伝える」から「言葉で伝える」への転換。直感に反する判断でしたが、結果的にこれが正解でした。
テキストプロンプト方式の設計 — 3層のプロンプト構造
スタイルプロンプト(全画像共通)
すべての画像に共通するデザインルールを定義しました。
- カラフルなフラットイラスト、太い黒アウトライン(ベクタースタイル)
- ビビッドで高彩度のカラーパレット(ピンク、黄色、青、緑、オレンジ、紫)
- 背景はパステルグラデーション(暖色→寒色)
- キャラクターは可愛いロボットまたはシンプルな人物(大きな頭)
- 下部30%はドミナントカラーの明るいトーンへフェード
- テキスト・ウォーターマークは絶対に含めない
このスタイルプロンプトが「参考画像の代わり」として機能します。すべての画像に同じスタイル指示を適用することで、テイストの統一を実現しました。
カテゴリヒント(自動付与)
ツールのカテゴリに応じた視覚的メタファーを自動で付与する仕組みを作りました。
- デザイン系: 絵筆、カラーホイール、CSSコード、タイポグラフィ
- SEO系: 検索エンジンUI、虫眼鏡、ランキングチャート
- セキュリティ系: 錠前アイコン、シールドバッジ、鍵のシンボル
- コーディング系: ターミナルウィンドウ、コードブラケット、シンタックスハイライト
- 動画/メディア系: 動画プレイヤーUI、フィルムストリップ、再生ボタン
これにより、「OGPチェッカー」のカードにはSEO系のメタファーが、「パスワード生成ツール」にはセキュリティ系のメタファーが自動的に含まれます。個別にプロンプトを書く必要がありません。
安全フィルター対策
テキストプロンプト方式に切り替えた上で、安全設定も明示的に調整しました。
すべてのカテゴリでBLOCK_ONLY_HIGHを設定。これにより、「セキュリティ診断」のような正当な技術用語がイラスト生成をブロックすることを防ぎます。
APIレスポンスとの格闘 — snake_case vs camelCase
Gemini APIのレスポンス形式の不統一は、テキストプロンプト方式でも引き続き対処が必要でした。
同じフィールドが、あるリクエストではinline_dataで、別のリクエストではinlineDataで返ってくる。mime_typeとmimeTypeも同様です。APIのバージョンやリクエスト内容によって変わるのか、ランダムなのかすら判別できませんでした。
対策として、画像データの抽出処理で両方の形式をフォールバックとして処理するコードを書きました。
APIを使う開発は「ドキュメントを信じすぎない」のが大事
2月28日の開発日記の教訓です。APIドキュメントは「こう返すべき」を記述していますが、実際のレスポンスは必ずしもドキュメント通りではありません。防御的なパース処理が必須です。DEBUG環境変数で生のAPIレスポンスをダンプする機能も追加しました。
TodayFeedとの統合 — ドミナントカラー問題
生成した画像をTodayFeedに表示したとき、予想外の問題が発覚しました。
TodayFeedのカードは、カード画像からドミナントカラー(支配的な色)を自動抽出し、その色でグラデーション背景を生成する仕組みになっています。最初のプロンプトでは「下部を白にフェード」と指定していたため、ドミナントカラーが白に引きずられ、グラデーション背景が白っぽくなってしまいました。
画像の下部フェードも白固定からドミナントカラーのフェードに変更した。TodayFeed がカード画像からドミナントカラーを自動抽出してグラデーション背景を作る仕組みなので、白固定だとグラデーションが白に引きずられて統一感が崩れる。
この問題は「作って → 表示して → 直す」のサイクルの中で発見しました。テストや仕様書では見つからない、実際の統合環境でしか気づけない問題です。
プロンプトを修正し、「下部30%はイラストのドミナントカラーの明るいトーンへフェード」に変更。これでTodayFeedの背景グラデーションと自然に馴染むようになりました。
コスト管理 — 10枚で検証してからスケール
AIの画像生成APIは、コスト感覚を掴むのが難しいサービスの一つです。
コスト感覚がまだ掴めていないので、まず10枚だけ試し生成してダッシュボードで確認する方針にした。理論上は10枚で約$0.67。小さく試してからスケールするのは開発だけでなくAPIコスト管理でも大事。
2月28日の開発日記の記述です。Gemini APIの画像生成は1枚あたり約$0.067。他の主要なAI画像生成APIと比較すると、1/4〜1/20のコストです。93個のツールと70以上の記事すべてにカード画像を生成しても、$10程度で済みます。
ただし、これは「まず小さく試す」姿勢で確認した結果です。いきなり100枚一括生成していたら、予想外のAPI仕様変更や安全フィルターの問題で大量のエラーが発生し、無駄なコストが発生していたかもしれません。
環境変数の自動読み込み
開発中に地味だけれど重要な改善がありました。.env.localファイルの自動読み込みです。
npm run cardはNext.jsの外で動くスタンドアロンスクリプトです。Next.jsのprocess.env自動読み込みは使えません。最初は毎回export GEMINI_API_KEY=xxxを手動で実行していましたが、これでは運用に耐えません。
dotenvライブラリでNext.jsと同じ.env.localを自動読み込みするようにしました。小さな改善ですが、「APIキーの管理を1箇所にまとめる」というセキュリティの基本原則にも沿っています。
モデルのライフサイクル管理
開発途中で、使用していたGeminiモデルの非推奨化に気づきました。
最初に使っていたgemini-2.0-flash-preview-image-generationは、2026年6月1日に廃止予定。gemini-3.1-flash-image-preview(通称Nano Banana 2)にアップグレードしました。
AIモデルのライフサイクルは本当に速い。デフォルト値をハードコードしている箇所は定期的に見直す必要があると実感した。
2月28日の開発日記の記述です。AIモデルの世代交代は驚くほど速い。数ヶ月前にリリースされたモデルが、すでに「非推奨」になっている。このスピード感は、AIを活用した開発に固有のリスクです。
環境変数GEMINI_IMAGE_MODELでモデル名を外部化し、デフォルト値はgemini-3.1-flash-image-previewに設定。モデルの世代交代があっても、環境変数の変更だけで対応できるようにしました。本番環境の設定変更だけで済むので、コードの変更・デプロイは不要です。
自動化のパイプライン — CLIからデータ更新まで
最終的に完成したパイプラインは以下の流れで動きます。
- CLIでコンテンツを指定:
npm run card -- --tool ogp-checkerやnpm run card -- --journal vibe-audit-security-tool-development - メタデータを自動取得:
tools.tsやMarkdownフロントマターからタイトル・説明・カテゴリを抽出 - プロンプトを自動構築: スタイルプロンプト + コンテンツ情報 + カテゴリヒント
- Gemini APIで画像生成: 安全設定を明示、3回までリトライ
- 画像を保存: sharpでWebP(800×1000px)に変換して
public/以下に保存 - データファイルを自動更新:
tools.tsのimageフィールドやMarkdownフロントマターの画像パスを自動書き換え
--list-missingオプションで画像未設定のコンテンツ一覧を表示する機能も用意しました。手動のファイル編集は一切不要です。
PM-AI 対話: 商用展開の可能性
npm run cardから切り出してWordPressプラグインにできないかな。WordPressユーザーは画像付き記事の自動化に確実にニーズがある。npm run cardの安定運用を優先して、その知見を元にプラグイン化を検討しよう。学び — AI画像生成APIとの付き合い方
1. 「画像で伝える」より「言葉で伝える」方が安定する
直感に反する発見でした。参考画像を添付すると安全フィルターの誤爆やペイロード膨張が起きます。詳細なテキストプロンプトの方が再現性が高く、メンテナンスもしやすい。
2. APIのレスポンスは「両方のパターン」に備える
snake_caseとcamelCaseが混在するのは、Gemini APIに限った話ではないかもしれません。外部APIを使う開発では、ドキュメントを信じすぎず、防御的なパース処理を書くことが必須です。
3. 統合環境でしか見つからない問題がある
ドミナントカラー問題は、画像を単体で見ているときには気づきません。TodayFeedに実際に表示して初めて発覚しました。「作って → 表示して → 直す」のサイクルを回すことが品質を担保します。
4. コストは小さく試してからスケール
API画像生成のコスト感覚は、実際に10枚生成してダッシュボードを確認するまで掴めませんでした。いきなり100枚生成するのではなく、小さなバッチで検証する姿勢が重要です。
npm run cardは、ZERONOVA LABのコンテンツ運用を支える裏方ツールになりました。93個のツールと70以上の記事に、統一されたテイストのカード画像を自動生成する。AIの画像生成APIは「完璧」ではありませんが、「実用的」です。そのギャップを埋める設計判断の積み重ねが、このパイプラインの本質です。
参考画像方式の破綻、安全フィルターとの格闘、レスポンス形式の不統一、TodayFeedとの統合問題。どれも事前の設計書には書かれていない、実装して初めて直面する課題でした。AI画像生成APIとの付き合い方は、まだ確立されたベストプラクティスがありません。だからこそ、この試行錯誤の記録が、同じ道を歩む開発者の参考になれば幸いです。
関連記事:
Zeronova(ゼロノバ)
Product Manager / AI-Native Builder
Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。