AIサムネイル生成 UXモック(SSEストリーミング前提)

Brain Market · UX Mock · 2026-07-17 · rev.7

AIサムネイル生成機能 — 体験フローモック

実現方式はSSEストリーミングを前提としています。OpenAI の Images API(gpt-image-1.5)は stream: true + partial_images生成途中の画像を段階的に配信できるため、Rails でその partial 画像をブラウザへ中継し、著者は「画像が徐々に鮮明になる」様子を見られます。

記事編集画面(/a/[id]/edit)での体験

実際の編集画面にUIを組み込んだ状態です。「成功Ver / 失敗Ver」を切り替え、「▶ フローを自動再生」を押すか、タブで各ステップに移動してください。

アイキャッチ未設定エリアに「AIでサムネイルを生成」ボタンが追加された編集画面

State × Event

UXステートとSSEイベントの対応

1本のSSE接続で流れてくるイベントを受けて、上のモックの各ステートを遷移させます。partial は OpenAI の image_generation.partial_image を中継したもので、受信のたびに生成中の画像を差し替えます。OpenAI 側のイベントに案の識別子は無いため、どのストリーム由来かは Rails 側で candidate_index を付与して区別します。

UXステート画面表示遷移トリガー(受信イベント)
1. 生成ボタン編集画面のアイキャッチ未設定エリア著者のクリック → 確認モーダル表示
2. 解析中 〜2秒モーダル:プログレス1段目SSE接続確立 → event: prompt(組み立てた prompt を同梱)
3. 生成中(だんだん鮮明に) 5〜15秒モーダル:3案がぼやけ→鮮明へ更新event: partial を受信するたびに candidate_index の案の画像を差し替え(partial 1〜3回 × 3案)
4. 候補から選択3案が確定表示event: completedcandidate_index ごとに計3回)→ 3案揃ったら接続クローズ
5. 適用後アイキャッチ反映 + スナックバーPATCH 成功(こちらは通常の同期リクエスト)
4'. 生成失敗モーダル内エラー + 再試行ボタンevent: failed / 接続断 / クライアント側タイムアウト

「だんだん鮮明に」の文言切り替えは実装可能(時間ではなくイベント駆動)

モーダル下部の文言(「画像を生成しています…」等)は経過時間ではなく、partial イベントに含まれる partial_image_index で切り替えます。総数は送信時の partial_images で確定しているため、「いま何合目か」を推測ではなく受信データから確定できます。

受信イベント画像チップ文言
partial index: 0強くぼやけた状態で表示画像を生成しています…
partial index: 1ぼかしが弱まるもう少しで完成します…
partial index: 2ほぼ鮮明に仕上げています…
completed確定画像を表示チップを消す

For Backend

想定シーケンス(SSEストリーミング・v2 API・エンドポイント名は仮)

sequenceDiagram
    participant A as 著者(ブラウザ)
    participant F as brain_market_front(Nuxt 3)
    participant B as brain_market_api(Rails / ActionController::Live)
    participant O as OpenAI Images API

    A->>F: 「3案を生成する」クリック
    F->>B: POST /v2/articles/:id/ai_thumbnails/stream
    Note over F,B: SSE受信は fetch + ReadableStream
    B->>B: タイトル・本文から image prompt 組み立て
    B-->>F: event: prompt(組み立てた prompt)
    F-->>A: 「解析中」→「生成中」へ

    B->>O: images.generate(model: gpt-image-1.5, stream: true, partial_images: 2〜3, n: 1) × 3本並列
    Note over B,O: partial イベントに案の識別子が無いため
n:3 の1本ではなく n:1 を3本張り、
Rails 側で candidate_index を付与して1本のSSEに多重化 loop partial 画像を都度中継(3ストリーム分) O-->>B: image_generation.partial_image B-->>F: event: partial(candidate_index + partial_image_index + 部分画像) F-->>A: 該当案の画像を差し替え(ぼやけ→鮮明) end O-->>B: image_generation.completed(ストリームごと・計3回) B->>B: ActiveStorage で S3 に attach B-->>F: event: completed(candidate_index + 確定URL) F-->>A: 確定した案から順に鮮明化 B->>B: 3案完了 → 接続クローズ F-->>A: 3案を確定表示 A->>F: 1案を選択して「使用する」 F->>B: PATCH 選択画像をアイキャッチに設定 B-->>F: 200 OK F-->>A: アイキャッチ反映+完了通知 Note over A,B: failed / 接続断 / タイムアウト時はモーダル内でエラー表示・再試行へ