AI Dev Lab
AI言い訳ジェネレーター

AI言い訳ジェネレーター ができるまで — バイラル狙いのエンタメAIの設計と実装

「遅刻した」「締切破った」をAIが爆笑言い訳に変換するサービスの企画背景・AIプロンプト設計・UX設計を全公開。

·decision保留·stage保留で観察

「遅刻したとき、どう言い訳する?」

誰もが一度は頭を抱えたこの問いに、AIが真剣に答えてくれたら?

それが AI言い訳ジェネレーター の出発点でした。単なるジョークツールに見えて、実は技術的にかなり面白い挑戦が詰まっています。この記事では、企画から実装まで全部お見せします。


🎭 なぜ「言い訳」なのか

コンセプトの背景

このサービスの開発テーマは「AIサービスで本当に収益化できるか検証すること」。そのためにはバイラル性が重要です。

実用系ツール(翻訳・要約など)は競合が多く、SNSで自然に拡散されにくい。一方で、

「AIが生成した爆笑言い訳」はシェアしたくなる

というユーザー行動は容易に想像できます。実際、Xで流れてくる「ChatGPTにXXさせてみた」系投稿は高エンゲージメントを叩き出しています。

ターゲット設定の考え方

設定理由
年齢層10代〜30代SNS利用率が高い。ネタコンテンツを楽しむ文化
利用シーン困ったとき・暇つぶし検索意図が明確(「遅刻 言い訳」など)
SNS親和性生成結果をそのままポスト可能
再訪率中〜高レベルやシナリオを変えると毎回違う結果

バイラル性と検索需要の両方を狙える、珍しいコンセプトです。


🏗️ システム設計

全体アーキテクチャ

ブラウザ
  │
  ├─ GenerateTab(Client Component)
  │     ├─ シナリオ選択(6種)
  │     ├─ レベルスライダー(1〜5)
  │     └─ POST /api/services/excuse-generator/generate
  │               └─ Claude Haiku(temperature: 0.9)
  │
  ├─ FeedTab(Client Component)
  │     └─ GET /api/services/excuse-generator/posts?sort=new
  │
  └─ RankingTab(Client Component)
        └─ GET /api/services/excuse-generator/posts?sort=likes

データモデル

model ExcuseGeneratorPost {
  id        String   @id @default(cuid())
  scenario  String          // "late" | "deadline" | ...
  level     Int             // 1〜5
  excuse    String          // 生成された言い訳テキスト
  likes     Int      @default(0)
  createdAt DateTime @default(now())

  @@index([createdAt(sort: Desc)])
  @@index([likes(sort: Desc)])
}

複数のサービスを同一DBで運用しているため、テーブル名はサービス名のプレフィックスを付けて名前空間を分離しています。

API設計

エンドポイントメソッドレート制限役割
/api/…/generatePOST10回/分AIで言い訳を生成
/api/…/postsGETなし投稿一覧取得
/api/…/postsPOST20回/分投稿を保存
/api/…/posts/[id]/likePOST30回/分いいねを加算

⚡ AIプロンプト設計

ここが一番の肝です。Claude Haiku に「面白い言い訳」を生成させるには、どうプロンプトを設計するかが全てです。

壮大さレベルの定義

Lvラベルプロンプト指示出力傾向
1ギリ信用される現実的、少しユニーク「電車が5分遅れて…」
2ちょっと怪しい盛り気味、なくはない「突然の雷雨で…」
3完全にフィクション明らかに嘘、でも面白い「タイムパラドックスで…」
4ハリウッド映画級映画のような展開「スパイに追われて…」
5宇宙規模SF・ファンタジー「銀河連邦から召集されて…」

実際のプロンプト構造

あなたは日本語の言い訳を作る専門家です。
以下の条件で言い訳を1つ生成してください。

シチュエーション: {scenarioLabel}({scenarioDescription})
壮大さレベル: {level}/5 - {levelLabel}
レベルの説明: {levelDescription}

要件:
- 日本語で200文字前後
- {level <= 2 ? "現実的で..." : "創造的で..."}
- 言い訳のみ出力(説明不要)

temperature: 0.9 は重要な設定です。0.7だと「それっぽいが面白くない」出力になりがちで、1.0以上だと文章が破綻します。0.9はクリエイティビティと一貫性のバランスが最も良い値でした。

A/Bテストの結果

プロンプトバリエーション面白さスコア(主観10回評価)採用
「嘘の言い訳を作って」4/10
「言い訳の専門家として」6/10
レベル定義を詳細に記述8/10
シナリオ文脈を英語で渡す5/10✗(英語出力が混入)

🎨 UX設計

タブ構成の理由

[ 生成する ] [ みんなの言い訳 ] [ ランキング ]

3タブ構成は意図的です。

  • 生成する: コア体験。すぐ使える
  • みんなの言い訳: UGCによる滞在時間延長
  • ランキング: 競争要素でリピート訪問を促す

「生成して終わり」ではなく、他人の面白い言い訳を見て笑い、自分の言い訳を投稿してリアクションを待つ——そのループを設計しています。

レベルスライダーのUX

設計要素決定内容理由
デフォルト値Lv3(完全にフィクション)面白い出力が出やすく、初回体験を最大化
スライダー色紫グロー(#8b5cf6)「AIっぽさ」「非日常感」を演出
バッジの色レベルで5色変化変化を視覚的にフィードバック
変更時の挙動結果をクリア混乱を防ぐ。「これどのレベルの結果?」をなくす

SNSシェアボタンの配置

┌─────────────────────────────────────┐
│  生成された言い訳テキスト              │
│                                     │
│  [𝕏 でポスト] [LINE で送る] [📋コピー] │
│                                     │
│  [📋 みんなに共有する] [🔄 再生成]    │
└─────────────────────────────────────┘

SNSシェアは2段構成にしました。上段は外部SNSへの直接シェア、下段はサービス内への投稿。どちらも1タップで完了します。

X(Twitter)のシェアURLにはハッシュタグ #AI言い訳ジェネレーター を自動付与しています。投稿が増えるとトレンドになる可能性があります(←希望的観測)。


🔒 スパム対策の設計

認証なしで動かすため、スパム・乱用対策を複数層で実装しています。

レート制限の実装

// src/lib/rate-limit.ts のラッパー
const limiter = rateLimit({ interval: 60_000, uniqueTokenPerInterval: 500 })

// 生成API: 10回/分
await limiter.check(res, 10, "GENERATE_" + ip)

// 投稿API: 20回/分
await limiter.check(res, 20, "POST_" + ip)

// いいねAPI: 30回/分
await limiter.check(res, 30, "LIKE_" + ip)

いいね重複防止

認証なしでいいね重複を防ぐのは難しい問題です。今回はシンプルに localStorageにいいね済みIDを保存 する方針を取りました。

方法メリットデメリット
localStorage実装が簡単シークレットモードで回避可能
Cookieより強固設定が面倒
IP + UserAgentサーバー側で完結プライバシー懸念、VPNで回避可能
認証必須完全に防止離脱率が上がる

エンタメ系サービスにおいて「いいね数の完全な正確性」より「ユーザー離脱ゼロ」の方が重要と判断しました。localstorage方式で十分です。


📊 期待するトラフィック経路

想定される流入パターン

Google検索
  「遅刻 言い訳 面白い」
  「仕事 休む 理由 ユニーク」
          │
          ▼
   サービスページ
          │
     生成 → SNSシェア
          │
    X / LINE 拡散
          │
    新規ユーザー流入

KPI設定(3ヶ月後目標)

指標目標根拠
月間PV5,000類似ジョーク系サービスの実績値
生成回数/DAU3回以上「レベルを変えてもう一回」行動
SNSシェア率15%面白い出力はシェアしたくなる
投稿数(累計)500件コミュニティ感の醸成に必要な最低ライン

😅 実装でハマったこと

1. Prismaマイグレーション中のファイルロック問題

開発サーバー(Next.js)が起動している状態で prisma generate を実行するとEPERMエラーが発生しました。Next.jsがPrismaクライアントのファイルをロックしているためです。

解決策: マイグレーション実行前に開発サーバーを停止する。シンプルですが、気づかないとハマります。

2. temperature 0.9 の「安定感」

最初は temperature: 1.0 で試していました。確かに面白い出力が出ることもあるのですが、時々日本語が破綻したり、意味不明なテキストが混入したりしました。

0.9 に下げた途端、「十分クリエイティブで、かつ読める日本語」に落ち着きました。この0.1の差は思った以上に大きいです。

3. ローカルストレージ×SSR

window.localStorage はサーバーサイドでは存在しません。FeedTabコンポーネント内でlocalStorageを直接参照するとハイドレーションエラーが発生しました。

解決策: useEffect 内でのみlocalStorageにアクセスするよう修正。SSR時は空配列を返します。

const [likedIds, setLikedIds] = useState<string[]>([])

useEffect(() => {
  const stored = localStorage.getItem(LIKED_KEY)
  if (stored) setLikedIds(JSON.parse(stored))
}, [])

📈 今後の展開

このサービスをどう育てていくか、いくつかアイデアがあります。

アイデア難易度期待効果
カスタムシナリオ入力★★☆ロングテール検索流入
言い訳の完成度スコア表示★★★ゲーミフィケーション強化
週間ランキングリセット★☆☆リピート訪問の動機付け
OG画像の動的生成★★☆SNSシェア時のクリック率向上
多言語対応(英語)★★★海外ユーザー獲得

💡 まとめ

AI言い訳ジェネレーターを作って気づいたことを一言で言うと:

「役に立つ」より「シェアしたくなる」の方が難しい

プロンプト設計、UX設計、SNS導線——全てを「これ、友達に送りたい!」という体験から逆算して決めました。

エンタメ系AIサービスは実用系と違い、**品質の評価軸が「笑えるか」「驚けるか」**にあります。これはAIの創造性と人間のセンスが交差する、面白い挑戦でした。

PVとシェア数の結果は、この記事の続編でご報告します。

[ ./next_action ]

読んだら、 AI言い訳ジェネレーター を実際に動かす。

この開発ログは AI言い訳ジェネレーター をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
ToonCast

ToonCast ができるまで — AnimeGANv2 をブラウザで動かす

AnimeGANv2 の小さな ONNX (約9MB) を onnxruntime-web (単一スレッド WASM=COOP/COEP不要、 color-revive で承認済みライブラリの再利用) で実行。 512x512・[-1,1] 正規化で推論し、 結果を元解像度に戻して表示する設計記録。 写真は端末内処理。

read log →
ColorRevive

ColorRevive ができるまで — onnxruntime-web で白黒写真をカラー化

DeOldify の量子化 ONNX を onnxruntime-web (CDN side-load・単一スレッド WASM=COOP/COEP不要) で実行。 256x256 でモデル推論し、 輝度は元写真・色だけ AI を YCbCr で再合成して輪郭を保つ設計記録。 写真は端末内処理。

read log →
PhotoTwin

PhotoTwin ができるまで — CLIP画像埋め込みで似た写真を見つける

CLIP (Xenova/clip-vit-base-patch32) の image-feature-extraction を transformers.js の CDN ESM で side-load し、 各写真を正規化ベクトル化。 cosine 類似度で重複・似た写真をブラウザ内で検出する設計記録 (新ライブラリ追加なし=what-cam と同じ CLIP の再利用)。

read log →
AkinFind

AkinFind ができるまで — 文章embeddingsで意味検索をブラウザ内に

多言語の文章埋め込みモデル (Xenova/multilingual-e5-small) を transformers.js の CDN ESM で side-load し、 各文を正規化ベクトル化。 cosine 類似度で意味検索と似ている文ペア検出を全て端末内で行う設計記録。

read log →
WhatCam

WhatCam ができるまで — CLIP のゼロショット画像分類をブラウザで動かす

CLIP (Xenova/clip-vit-base-patch32) を transformers.js の CDN ESM で side-load し、 写真と候補ラベルの近さをブラウザ内で計算。 日本語ラベルを英語プロンプトに変換し、 図鑑と自由入力の両モードで「これ何?」を判定する設計記録。

read log →
DepthCast

DepthCast ができるまで — 1枚の写真をAIの深度推定で立体にする

Depth Anything (transformers.js) を CDN ESM で side-load し、 1枚の写真から深度マップを推定。 WebGL2 フラグメントシェーダで深度に比例した視差 (iterative backward parallax) を作り、 赤青アナグリフ / WebM 書き出しまで端末内で完結させた設計記録。

read log →