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

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

AI 言い訳ジェネレーターの開発ログ。 遅刻や締切遅れの状況を入れると笑える言い訳が返るサービスについて、 企画の狙い、 AI への指示文の設計、 外しても不快にならないための工夫をまとめました。

·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

#データモデル

prisma
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言い訳ジェネレーター を自動付与しています。投稿が増えるとトレンドになる可能性があります(←希望的観測)。


#🔒 スパム対策の設計

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

#レート制限の実装

typescript
// 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時は空配列を返します。

typescript
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 →
ShadowTwin

立体パズルの別解を作る:同じ影と最少の積み木

ShadowTwinの開発記録。3方向の図から別々の最少配置を2つ探す仕組み、5問の独立全探索、スマホの横並び比較、保存・再編集と入力検査を解説します。実照明の計算や能力診断ではありません。

read log →
SlitCard

スリットアニメーションを作る:4コマの合成と透明原稿の設計

SlitCardの開発記録。4コマの帯を交互に合成し、すき間と黒帯で別のコマを見せる仕組みを解説。同縮尺の台紙・透明シートSVG、50mm確認線、手動プレビュー・初期非表示、再編集と実出力検査を整理します。

read log →
WindowLight

日当たりシミュレーションを作る:窓の光を床へ投影する幾何モデル

WindowLightの開発記録。太陽位置近似から窓の4隅を床へ投影し、凸多角形を部屋で切り取る設計を解説。国立天文台の16時刻との限定照合、大気差・低高度・実際の採光との違い、SVGと設定の再編集を整理します。

read log →
GridLights

電源構成の比較を作る:割合と実量を100個の電球で読み解く

電源構成比較GridLightsの開発記録。12か国の年次発電データを最大剰余法で100個の電球に変換し、割合とTWhを比較する設計を解説。欠損を0補完しない7分類、予想と実値、出典付きSVGと実データ検証を整理します。

read log →
SoundLoom

音のお絵かきを作る:実WAVから絵を測り直す設計

音のお絵かきの開発記録。描画を正弦波のPCMとWAVへ変換し、保存音声の周波数をGoertzel法で測って比較する仕組みを解説。音量・測定窓・量子化の限界と、編集・離脱時の古い結果を抑止する検証を整理します。

read log →
MazeLoom

宝探し迷路を作る:寄り道まで含めた最短ルートの探索

宝探し迷路の開発記録。通路を木として生成し、現在地と3つの宝の取得状態を組み合わせて最短ルートを探す仕組みを解説。問題コードの版固定、画面と解答付きPDFの一致、手数と印刷の検証を整理します。

read log →