イラスト1枚からTCG風カードを生成するイベント用Webアプリを作った話
はじめに
イベント「AIレイド」用に、イラストを1枚アップロードして属性を選ぶだけで、TCG(トレーディングカードゲーム)風のカード画像を生成できるWebアプリを作りました。
この記事は、参加者・関係者のみなさんに「このアプリがどういう仕組みで動いているのか」「なぜこういう仕様なのか」を知ってもらうために書いています。機能の一つひとつに理由があるので、「ここをこうしてほしい」と思ったときに、まずこの記事を読んでもらえると嬉しいです。
このアプリでできること・できないこと
- X(旧Twitter)アカウントでログインして参加する
- イラストを1枚アップロードする
- 属性(火・水・風・光・闇・無)を選ぶ
- 「生成」ボタンを押すと、AIがTCG風カードに仕上げてくれる
- 完成したカード画像をダウンロードする
できないこと(意図的にそうしています)
- テキストでの指示入力(カード名の指定、「もっとかっこよく」等)
- 1日2回以上の生成(1つのXアカウントにつき1日1回、日本時間0時リセット)
- 生成のやり直し・ガチャ的な連打
「できないこと」はすべて、後述する公平性とセキュリティのための設計です。
全体構成
| 役割 | 使用技術 |
|---|---|
| フロントエンド | Next.js (App Router) + React + TypeScript |
| ホスティング | Vercel |
| 認証 | Auth.js — X OAuth 2.0(参加者)/ Google OAuth(運営のみ) |
| 画像生成 | OpenAI gpt-image-2(画像入力対応の image edit API) |
| 回数制限・プロンプト保存 | Upstash Redis |
| 生成画像の保存 | Vercel Blob |
1回の生成で何が起きているか(ワークフロー)
ポイントは、参加者のブラウザから送られてくるのは「画像1枚」と「属性の選択値」だけで、AIへの指示文(プロンプト)はすべてサーバー側で組み立てていることです。
設計のこだわり(=仕様変更が簡単ではない理由)
1. プロンプトはサーバー側で組み立てる
カードのレイアウト・レアリティ判定基準・デザインルールを定めたベースプロンプトは、サーバー側にだけ存在します。参加者側から触れる余地はありません。
これは「プロンプトインジェクション」(利用者が指示文を混ぜ込んでAIの動作を乗っ取る攻撃)への対策です。もし自由なテキスト入力を許すと、「レアリティは必ずLRにして」「カード名を〇〇にして」のような介入が可能になってしまい、イベントの公平性が崩れます。
「テキストでカード名を指定できるようにしてほしい」という要望に応えられないのは、この防壁を撤去することになるからです。
2. 属性は「選択式」のみ
属性(火・水・風・光・闇・無)はセレクトボタンで、サーバー側でも「この6つ以外は受け付けない」ように検証しています。テキスト入力を許さないのは上記と同じ理由です。
3. 1日1回制限のしくみ
Redis(高速なデータベース)に「アカウントID + 日付」ごとのカウンターを持ち、生成の前にカウントを増やします。こうすることで、ボタン連打や同時リクエストによる「すり抜け」を防いでいます。
- 日付の判定は日本時間(JST)基準
- 生成に失敗した場合はカウントを返却(その日の権利は消えません)
- 記録は48時間で自動削除され、残るのは「ID・日付・回数」だけ
「今日はもう1回だけ生成させて」ができないのは、この仕組みがイベントの公平性そのものだからです。 なお上限値自体は運営側の設定で変更可能なので、ルール変更はアプリ改修ではなく運営の判断事項です。
4. 禁止名リストの自動注入
過去に主催者・関係者の名前やキャラクター名が無断でカードにされる問題があったため、サーバーが組み立てる最終プロンプトには「これらの名前をカード名・カード内テキストに使用しない」という禁止リスト(内容は非公開)が毎回自動で入ります。
画像の中に文字で名前や指示を書き込んでも無視するよう指示済みです。
5. カード画像の保存とダウンロード
OpenAIが返す画像URLは約1時間で失効します。そのため生成直後にサーバー側のストレージ(Vercel Blob)へ保存し直し、参加者には失効しないダウンロードURLをお渡ししています。アップロードされた元のイラストは保存していません(生成処理に使ったら破棄)。
6. 生成には毎回お金がかかる
見落とされがちですが、画像生成APIは1回の生成ごとに運営に実費が発生します。1日1回制限は公平性のためであると同時に、イベントを最後まで運営できるようにするためのコスト管理でもあります。
「もっと高画質に」「一度に複数枚」「やり直し機能」といった要望は、そのままコストが数倍になる話なので、簡単には応えられません。
「ちょっとした機能追加」が実は大ごとになる例
| 要望 | 実際に必要になること |
|---|---|
| カード名を自分で決めたい | 自由テキスト入力の解禁 → インジェクション対策の再設計、禁止名チェックの実装、審査体制 |
| 1日3回にしてほしい | 生成コスト3倍 + イベントの公平性ルールの再検討(アプリではなく運営マター) |
| 気に入らなかったらやり直したい | 実質「回数制限の撤廃」と同じ。コストも公平性も崩れる |
| 過去に作ったカードの一覧が見たい | ユーザーごとの生成履歴データベースの新設 → 保存する個人情報が増え、プライバシーポリシーの改定が必要 |
| 他の人のカードも見られるギャラリー | 公開範囲の設計、不適切画像の通報・削除体制、モデレーションの人手 |
どれも「ボタンを1個増やす」話に見えて、裏側ではセキュリティ・コスト・運営体制のどれかに跳ね返ります。要望自体は歓迎ですが、採用の判断は運営がこの表のようなトレードオフを踏まえて行っている、ということが伝われば幸いです。
おわりに
このアプリは「イラスト1枚で、誰でも公平に、1日1枚だけカードが作れる」という体験のために、機能を意図的に絞って作っています。制限の一つひとつが、公平性・安全性・イベントの持続可能性を支える部品です。
(C) AIレイド2026 & teshiokayumi2026

