Biz Next.js Chatbot OpenRouter — ウェブサイトにAIチャットボットを1発導入 は何をしますか?
このスキルは、既存のNext.jsプロジェクトに AIチャットボット(フローティングウィジェット) を追加します。ウィジェットは画面 右下 に配置され、3つの画面サイズに完全対応。OpenRouter 経由でLLMを呼び出し、FAQ + コース/製品ドキュメントをナレッジベースとし、react-markdown + remark-gfm を使用してアシスタントの吹き出し内で Markdownをレンダリング(数値/価格の太字、箇条書き、クリック可能なリンク、インラインコード)し、チャット内でユーザーが十分な情報(名前+電話番号+メールアドレス)を提供すると、KV(Upstash Redis / Vercel KV)に 自動的にリードを抽出・保存 します。管理者は /admin ダッシュボードで確認できます。目的は、ランディングページ上で 24時間自動サポートボット + パッシブなリード獲得 を実現し、チャットで問い合わせた顧客を取り逃がさないことです。
精神: Next.jsのバージョン、App/Pages Router、TS/JS、Tailwind/CSSなど、可能な限りすべてを自動検出し、本当に必要な4つのことだけをユーザーに尋ねます:(1) 複数ある場合のプロジェクト選択、(2) FAQ、(3) 製品ドキュメント、(4) トーン/ブランド名。残りはコード生成 → 数分で稼働します。
いつ使用するか
ユーザーが以下を希望する場合:
- コース/サービス販売用のランディングページに、顧客サポートAIチャットボットを追加したい
- 繰り返しの質問(価格、ロードマップ、返金、対象者など)への回答負荷を軽減したい
- コンテンツを隠さない、右下のコンパクトなチャットウィジェットが必要
- チャットボットにコース/製品の内容を正確に理解させたい(FAQ駆動)
- 既存のNext.jsプロジェクトがある(
/biz-sales-page-layoutを実行した直後、または以前のプロジェクト)
使用すべきでない場合
- プロジェクトがNext.jsではない(素のReact Vite、Vue、Svelte、プレーンHTML)→ このスキルはNext.js専用です。適応は可能ですが最適ではありません。
- 数千ページのナレッジベースを持つRAG(検索拡張生成)チャットボットが必要 → ベクターDB(Pinecone/Supabase pgvector)が必要です。このスキルはシンプルなシステムプロンプトを使用し、最大20Kトークンの知識に適しています。
- 音声/マルチモーダル(画像送信)チャットボットが必要 → このスキルはテキストのみです。
- ユーザーごとのチャット履歴をDBに保存するチャットボットが必要 → このスキルはステートレス、エフェメラルセッションです。後で拡張可能です。
- バックエンドがVercelフレンドリーでない(ロングポーリング、永続的なWebSocketが必要)→ OpenRouterストリーミングはVercel Edgeで問題なく動作しますが、専用のWSが必要な場合は別です。
ユーザーが受け取る成果物
スキル実行後:
-
Next.jsプロジェクト内の新しいファイル:
components/Chatbot.tsx(または.jsx)— ウィジェットUI(react-markdown+remark-gfmでMarkdownをレンダリング)app/api/chat/route.ts(App Router)またはpages/api/chat.ts(Pages Router)— OpenRouterを呼び出し、ストリーム後にリードを自動抽出するAPIプロキシlib/chatbot-knowledge.ts(または.js)— ナレッジベースとシステムプロンプト(応答フォーマットブロック + 積極的リード収集ブロックを含む)lib/chat-lead.ts— プロジェクトにKV/Upstashがある場合のみ作成 — 抽出・保存、電話番号で重複排除、TTL 90日、名前空間chat-lead:{phone}- Markdownスタイル
.chatbot-mdをapp/globals.cssに追加(templates/chatbot-markdown-styles.cssより) .env.localを作成/追記しOPENROUTER_API_KEY=(プレースホルダー)を追加.env.example(まだない場合)で環境変数を文書化<Chatbot />をapp/layout.tsxまたはpages/_app.tsxにマウント
-
追加でインストールされるパッケージ(ロックファイルから検出されたパッケージマネージャー経由):
react-markdown— 安全にMarkdownをレンダリング(dangerouslySetInnerHTML不要)remark-gfm— GitHub Flavored Markdown(テーブル、自動リンク、取り消し線)
-
セッション終了時の明確な手順:
- ユーザーが自分で行うべき3ステップ:(a) OpenRouter APIキーを取得、(b)
.env.localに貼り付け、(c)npm run devでテスト - Gemini と Sonnet のモデル切り替え方法
- 後でナレッジベースを更新する方法
- ユーザーが自分で行うべき3ステップ:(a) OpenRouter APIキーを取得、(b)
ワークフロー
ステップ 1 — Next.jsプロジェクトの検出
Next.jsプロジェクトの候補を探します。実行:
# 依存関係に "next" を含むpackage.jsonを検索、最大深さ4
find /Users/tonyhoang/Documents/GitHub -maxdepth 4 -name "package.json" -not -path "*/node_modules/*" 2>/dev/null | xargs grep -l '"next"' 2>/dev/null | head -20
(ユーザーが特定のワーキングディレクトリにいる場合、cwd から下方向を優先して検索し、見つからなければ ~/Documents/GitHub にフォールバックします。)
分岐:
- 0 プロジェクト: ユーザーに報告して停止。「Next.jsプロジェクトはお持ちですか? もしお持ちでなければ、
/biz-sales-page-layoutで新しく作成してから戻ってきますか?」と提案。 - 1 プロジェクト: 進める前にパスを確認。「[path] にチャットボットをインストールします。よろしいですか?」
- ≥ 2 プロジェクト: パスと名前(package.jsonの
name)を番号付きリストで表示し、ユーザーに選択を促す。「N個のNext.jsプロジェクトが見つかりました。どれにインストールしますか?」
ステップ 2 — プロジェクトコンテキストの調査
ユーザーがプロジェクトを確認したら、以下を読み取ります:
-
package.json→ 確認:- TypeScript(
typescriptがdepsにあるか?) - Tailwind(
tailwindcssがdevDepsにあるか?) - パッケージマネージャー(ロックファイル:
pnpm-lock.yaml→ pnpm、yarn.lock→ yarn、デフォルトnpm) - Next.jsバージョン
- TypeScript(
-
ディレクトリ構造 → 確認:
app/ディレクトリが存在 → App Routerpages/ディレクトリが存在(かつapp/がない) → Pages Router- 両方存在 → 新しいファイルにはApp Routerを優先(Next.jsは移行中)
src/ラッパー → パスを調整(例:src/app/、src/components/)
-
tsconfig.json→ パスエイリアスを確認(@/*→./src/*か./*か) -
.env.local、.env.example→ 既に存在するか確認 -
KV/Upstash 利用可能性(自動リードキャプチャ用):
package.jsonに@upstash/redisまたは@vercel/kvがある → KVあり → chat-lead.ts をスキャフォールドしてルートに配線src/lib/kv.ts(またはlib/kv.ts)がkvをエクスポートしている → 既存のヘルパーをそのまま使用(キャンプパターン)- KVがない → chat-lead.ts のスキャフォールドをスキップし、ユーザーに報告:「プロジェクトにKVがありません — 自動リードキャプチャは有効になりません。
/biz-setup-sepay-paymentを実行してKVを先にインストールしてから戻ってきてリードキャプチャを有効にするか、スキップしてください。」
これらの観察結果 を小さな表にまとめて、後のステップで使用します。
ステップ 3 — ユーザーからのナレッジベース収集
ユーザーに4つの質問(1つのメッセージにまとめて、ユーザーが一度に回答できるようにし、往復を減らします):
チャットボットが正確に回答するために、4つの情報が必要です:
1. **FAQ** — よくある質問とその回答のリスト(価格、ロードマップ、返金、対象者、学習期間、受講後サポートなど)。
ここに直接貼り付けるか、ファイルパス(.md / .txt / .docx)を指定してください。
2. **製品/コースドキュメント** — コースの詳細な説明:名前、各モジュールの内容、成果、講師、特典、複数ある場合は価格帯。
同様に貼り付けるか、ファイルパスを指定してください。
3. **ブランド名 + トーン** — チャットボットが名乗るブランド/コース名(例:「AI Masteryのアシスタント」)。使用するトーン:親しみのある「お客様」(デフォルト)/ フォーマル / カジュアルな「あなた」.
4. **モデル** — デフォルトは `google/gemini-3-flash-preview`(高速、低コスト、サポートに十分)。`anthropic/claude-sonnet-4.6`(高品質、約10倍高価)を使用したい場合はお知らせください。初期段階では品質よりもコストを抑えたい場合はそのままで。
一度にまとめて回答していただけますか?
ユーザーが回答した場合:
- ファイルパスのみ指定 → Readツールでそのファイルを読み取ります。
- 直接内容を貼り付け → その内容を使用します。
- 「代わりにプレースホルダーを生成して」と言われた場合 → 汎用的なFAQプレースホルダーを作成し、
// TODO: user fill inとマークして、ユーザーが更新する必要があることを示します。 - ブランド名がない場合 → デフォルトで「AIアシスタント」、トーンは「お客様」.
ステップ 4 — プロジェクトへのファイル生成
このスキルの templates/ にあるテンプレートを読み取り、プロジェクトに 適応させます。テンプレート一覧:
templates/chatbot-knowledge.ts— ナレッジベースとsystemPromptをエクスポートするモジュール。FAQ、製品情報、ブランド名、トーンをここに注入します。応答フォーマットブロック(Markdownルール)+ 積極的リード収集ブロック(バイヤーシグナル時にLLMに名前/電話番号/メールアドレスを尋ねるように指示し、ユーザーが提供した場合は感謝+確認し、「データベースに保存しました」とは言わない)が組み込まれています。templates/Chatbot.tsx— ウィジェットコンポーネント、Tailwind優先。react-markdown+remark-gfmをインポート済みで、アシスタントメッセージを<ReactMarkdown remarkPlugins={[remarkGfm]}>でレンダリング(アシスタントのみ — ユーザーメッセージは引き続きプレーンなwhitespace-pre-wrap)。プロジェクトにTailwindがない場合 →templates/Chatbot-noTailwind.tsx+templates/chatbot.module.cssにフォールバック。templates/chat-route-app.ts— App Router用APIルート(app/api/chat/route.ts)。ストリームクローズ後にファイア・アンド・フォーゲットで実行されるpersistLeadIfReadyフックが組み込まれており、応答をブロックしません。templates/chat-route-pages.ts— Pages Router用APIルート(pages/api/chat.ts)。templates/chat-lead.ts— プロジェクトにKV/Upstashがある場合のみスキャフォールド — ベトナム電話番号+メールアドレス+名前を抽出する正規表現(「tên X」/「tôi là X」/「tên: X」などのパターン)、電話番号で重複排除するsaveChatLead、TTL 90日、キー名前空間chat-lead:{電話番号}。templates/chatbot-markdown-styles.css—.chatbot-mdクラス用のCSSスニペット。app/globals.css(またはsrc/app/globals.css/styles/globals.css)の末尾に必ず追加します。追加前に、プロジェクトのブランドパレットに合わせてアクセントカラー(#fde68a/#f59e0b)を変更します。templates/env-instructions.md— OpenRouterキー取得手順のスニペット。最終ステップで使用します。
テンプレート適応時のルール:
-
TS vs JS: プロジェクトにJSしかない場合、拡張子
.ts/.tsxを.js/.jsxに変更し、型アノテーションを削除します(ファイル名を変更するだけではありません)。サンプルファイルを読み取り、パースし、型を削除して書き出します。 -
パスエイリアス:
tsconfigが@/*→./src/*とマップしている場合、テンプレート内のインポートは@/lib/chatbot-knowledgeを使用し、ファイルはsrc/lib/に配置します。エイリアスがない場合は、相対パスを使用します。 -
モデル: プレースホルダー
__MODEL_ID__をユーザーが選択したモデル(google/gemini-3-flash-previewまたはanthropic/claude-sonnet-4.6)に置き換えます。 -
ブランド:
__BRAND_NAME__、__BRAND_TONE__を置き換えます。 -
ナレッジ: FAQ + 製品情報から、明確な構造の
systemPromptを構築します(テンプレート参照)。systemPrompt内の 応答フォーマットブロックはそのまま維持します — これはLLMに小さなチャット吹き出しに適したMarkdown(見出しの代わりに太字、1行の短い箇条書き)を出力させるためのものです。 -
Markdownレンダリングパッケージのインストール(必須 — スキップすると吹き出し内で生の
**bold**が表示され、太字になりません):# ロックファイルを検出 → 正しいパッケージマネージャーを選択 npm install react-markdown remark-gfm # または: pnpm add react-markdown remark-gfm # または: yarn add react-markdown remark-gfm -
Markdownスタイルの追加:
templates/chatbot-markdown-styles.cssを読み取り、プロジェクトのブランドパレットに合わせてアクセントカラーを変更し(globals.cssで--color-primaryなどをチェック)、app/globals.css(またはsrc/app/globals.css/styles/globals.css)の末尾に追加します。 -
ウィジェットのマウント:
- App Router:
app/layout.tsx(またはsrc/app/layout.tsx)を編集し、import Chatbot from '@/components/Chatbot'と<Chatbot />を</body>の直前に追加します。編集前に現在の layout.tsx を読み取り、メタデータ、フォント、プロバイダーをそのまま維持します。 - Pages Router:
pages/_app.tsxを編集し、return をラップします:<><Component {...pageProps} /><Chatbot /></>。既存の_appを読み取り、既存のプロバイダーを保持します。
- App Router:
-
自動リードキャプチャの配線(ステップ2でKVを検出した場合のみ実行):
templates/chat-lead.tsをlib/chat-lead.ts(またはsrc/lib/chat-lead.ts)にコピーします。- プロジェクトにまだ
lib/kv.tsがない場合 → 作成:import { Redis } from "@upstash/redis"; export const kv = Redis.fromEnv(); - ルートハンドラーでインポート:
import { extractLeadFromMessages, saveChatLead } from "@/lib/chat-lead" - ストリームループ内:
assistantText(デルタを蓄積)を追跡し、ストリームが閉じたときにpersistLeadIfReady(history, assistantText)を呼び出します(ファイア・アンド・フォーゲット、応答パス内でawaitしない)。 - システムプロンプト:
chatbot-knowledge.ts内に 積極的リード収集ブロック が含まれていることを確認します(テンプレートに既に含まれています)。 - ユーザーに確認: 「自動リードキャプチャを有効にしました — 顧客がチャットに名前/電話番号/メールを貼り付けると、システムが自動的にKV名前空間
chat-lead:{電話番号}に保存します。リードは/admin(/biz-admin-leads-dashboardをインストールしている場合)で確認できます。」
ステップ 5 — .env.local + .gitignore のセットアップ
-
.env.localが存在するか確認:- まだない場合: 新規作成:
# OpenRouter APIキー — https://openrouter.ai/keys で取得 OPENROUTER_API_KEY= # オプション: OpenRouterがリファラーを追跡するためのサイトURL(レート制限が向上する可能性があります) NEXT_PUBLIC_SITE_URL=http://localhost:3000 - 既にある場合: 上記2つの変数がまだなければ追加し、既存の変数は上書きしません。
- まだない場合: 新規作成:
-
.env.exampleを更新(まだなければ新規作成):OPENROUTER_API_KEY=sk-or-v1-xxxxx NEXT_PUBLIC_SITE_URL=https://your-domain.com -
.gitignoreに.env.localが含まれているか確認。含まれていない場合 →.env.localと.env*.localを追加。
ステップ 6 — ユーザーへのレポート
4つのセクションからなる 明確な要約メッセージ を出力します:
✅ [プロジェクト名] にチャットボットのインストールが完了しました
📁 作成したファイル:
- components/Chatbot.tsx(react-markdown + remark-gfm でMarkdownをレンダリング)
- app/api/chat/route.ts
- lib/chatbot-knowledge.ts
- app/globals.css(Markdownスタイル .chatbot-md を追加)
- .env.local(プレースホルダー)
📦 インストールしたパッケージ: react-markdown, remark-gfm
🔑 チャットボットを動かすために必要な3ステップ:
1. OpenRouter APIキーを取得:
- https://openrouter.ai にアクセス → サインアップ(Googleログイン可)
- https://openrouter.ai/keys にアクセス → Create Key
- クレジットをチャージ(https://openrouter.ai/credits) — Gemini 3 Flashは低コスト、$5で数千回のチャットが可能
- `sk-or-v1-xxxxx` 形式のキーをコピー
2. `.env.local` ファイルに貼り付け:
OPENROUTER_API_KEY=sk-or-v1-xxxxx-paste-vào-đây
3. テスト実行:
[npm/pnpm/yarn] run dev
http://localhost:3000 を開く → 右下のバブルをクリック
🔄 Gemini ↔ Sonnet のモデル切り替え:
`app/api/chat/route.ts` を開き、ファイル先頭の `model:` 変数を編集。
- `google/gemini-3-flash-preview`(デフォルト、$0.075/100万入力トークン、高速)
- `anthropic/claude-sonnet-4.6`(高品質、約$3/100万入力トークン、より良い応答品質)
📚 後でナレッジベースを更新:
`lib/chatbot-knowledge.ts` を編集 — FAQとproductInfoを追加/修正し、保存するとホットリロードされます。
モバイルファースト レスポンシブデザイン
ウィジェットは 3つのブレークポイントを満たす必要があります:
| ブレークポイント | 動作 |
|---|---|
| ≤ 640px(モバイル) | バブルをクリック → 全画面オーバーレイ(z-index 9999)を開き、ヘッダーにX閉じるボタン。入力欄はキーボードに隠れないよう safe-area-inset で下部にドッキング。 |
| 641–1023px(タブレット) | パネル 380px × 70vh、右下に16pxマージンで固定。 |
| ≥ 1024px(デスクトップ) | パネル 400px × 600px、右下に24pxマージンで固定。バブルは丸形60px。 |