AI開発収益化ラボ
AI言い訳ジェネレーター

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

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

誰もが一度は頭を抱えたこの問いに、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とシェア数の結果は、この記事の続編でご報告します。