Skip to main content

第18章:AIボタンをUIに組み込む 🤖✨

この章では、管理画面の「詳細フォーム」に “AIで整形”ボタン を付けて、文章を読みやすく整えてから ユーザーが確認して反映 できるUIを作ります📝➡️🤖➡️✅ (※「AIの出力を勝手に保存しない」設計がポイントだよ〜😆)


0) まず知っておくと安心な考え方 🧠🛡️

なんで“ブラウザからGemini直呼び”は危ないの?😱

Direct API Call Risk

WebでGemini APIを直接呼ぶやり方は プロトタイプ向け で、キー露出や悪用 のリスクが出やすいです⚠️ 公式の学習資料でも「本番を見据えるなら Firebase AI Logic に移行してね」と案内されています。(Google for Developers)

そこで Firebase AI Logic が強い 💪🔥

Firebase AI Logic Architecture

Firebaseの Firebase AI Logic は、Web/モバイルのクライアントSDKからGemini/Imagenを呼べて、セキュリティ機能(App Check連携など)Firebase/Google Cloud 連携 がやりやすいのが売りです🧩✨(Firebase) さらに AIリクエストのゲートウェイ(プロキシ) を用意してくれて、Gemini APIキーをアプリのコードに埋めない 方向に寄せられます🔐(Firebase)


1) この章の完成イメージ 🏁✨

AI Suggestion Workflow

  • 詳細フォームに「🤖 AIで整形」ボタン
  • 押すと 整形案 が出る(保存しない)
  • ユーザーが「✅反映する」を押したらフォームに反映
  • 最後にいつもの「💾保存」ボタンでFirestoreへ保存(ここで初めてDB更新)

2) 読むパート:UIにAIを入れる時の“3点セット”📦✨

  1. 確認ステップを必ず入れる(AI案→人がOK)✅

  2. 状態管理loading / error / suggestion を揃える🔁

  3. 悪用対策:App Check + 乱用(レート)対策🛡️

    • AI Logic は App Check と一緒に使うのを強く推奨されています(Firebase)
    • さらに ユーザー単位のレート制限 も用意されています(デフォルト有効)(Firebase)

3) 手を動かすパート:実装していこう 🛠️🔥

Step 1) Firebase側で AI Logic を有効化する 🤖⚙️

Enable AI Logic UI

Firebase コンソールの AI Logic で「Get started」→ Gemini Developer API を選ぶのが入門におすすめです(必要なら後で Vertex AI 側にも切り替え可能)(Firebase) このとき Gemini APIキーが作られますが、アプリのコードに入れないでね と明確に書かれています🔑❌(Firebase)

ついでに:モデルは gemini-2.5-flash が手軽で速い系です⚡(公式の例でもこれ)(Firebase) ちなみに gemini-2.0-flash / gemini-2.0-flash-lite2026-03-31に廃止予定 と案内があります📅⚠️(Firebase)


Step 2) フロントにAI Logic SDKを入れる 📦

firebase を入れていればOKです(AI LogicはJS SDKの中に含まれるよ)(Firebase)

npm install firebase

Step 3) firebase.ts に “AIの出口” を追加する 🔌🤖

既にある firebase.ts(第10章のやつ)に、AIを足します✨ ポイントは モデルを1回作ってexport しておくこと!(呼び出し側が楽になる👍)

// src/firebase.ts
import { initializeApp } from "firebase/app";

// ここは既にある想定(Auth/Firestore/Storageなど)
export const app = initializeApp({
// ... your firebase config
});

// ✅ ここからAI Logic(Gemini Developer API backend)
import { getAI, getGenerativeModel, GoogleAIBackend } from "firebase/ai";

const ai = getAI(app, { backend: new GoogleAIBackend() });

// 迷ったらまずこれ(速い・安い寄り)
export const geminiModel = getGenerativeModel(ai, { model: "gemini-2.5-flash" });

この書き方(getAI / GoogleAIBackend / getGenerativeModel)は公式ガイドのWeb例そのままです🧠✨(Firebase) あと本番運用を意識するなら Remote Configでモデル名を後から変えられるように するのが推奨されています(将来のモデル変更に強い💪)(Firebase)


Step 4) AI整形の “呼び出し処理” を hook にする 🪝✨

AI Code Structure

UIから直接API叩くより、hookにすると見通しが良いです😆

// src/hooks/useAiPolishText.ts
import { useCallback, useState } from "react";
import { geminiModel } from "../firebase";

type UseAiPolishTextResult = {
loading: boolean;
error: string | null;
suggestion: string | null;
run: (input: string) => Promise<void>;
clear: () => void;
};

export function useAiPolishText(): UseAiPolishTextResult {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [suggestion, setSuggestion] = useState<string | null>(null);

const clear = useCallback(() => {
setError(null);
setSuggestion(null);
}, []);

const run = useCallback(async (input: string) => {
setLoading(true);
setError(null);
setSuggestion(null);

try {
const prompt = [
"あなたは文章の校正・整形アシスタントです。",
"次の文章を、意味を変えずに読みやすく整えてください。",
"条件:",
"・箇条書きOK",
"・敬語は丁寧すぎなくてOK",
"・長い文は短く",
"・出力は整形後の本文だけ",
"",
"【本文】",
input,
].join("\n");

const result = await geminiModel.generateContent(prompt);
const text = result.response.text();

setSuggestion(text);
} catch (e) {
console.error(e);
setError("AIの呼び出しに失敗しました😢 もう一度試してみてね");
} finally {
setLoading(false);
}
}, []);

return { loading, error, suggestion, run, clear };
}

Step 5) 詳細フォームに「🤖AIで整形」→「✅反映」UIを付ける 🧩

AI Editor Component

例として「記事本文(body)」を整形するUIを付けます📄✨

// src/components/PostBodyEditor.tsx
import { useMemo, useState } from "react";
import { useAiPolishText } from "../hooks/useAiPolishText";

type Props = {
initialBody: string;
onChange: (next: string) => void;
};

export function PostBodyEditor({ initialBody, onChange }: Props) {
const [body, setBody] = useState(initialBody);
const { loading, error, suggestion, run, clear } = useAiPolishText();

const canRun = useMemo(() => body.trim().length > 0 && !loading, [body, loading]);

return (
<div className="space-y-3">
<label className="block text-sm font-medium">本文</label>

<textarea
className="w-full rounded-lg border p-3"
rows={8}
value={body}
onChange={(e) => {
const next = e.target.value;
setBody(next);
onChange(next);
}}
placeholder="ここに本文..."
/>

<div className="flex items-center gap-2">
<button
className="rounded-lg border px-3 py-2 disabled:opacity-50"
disabled={!canRun}
onClick={() => run(body)}
>
{loading ? "🤖整形中..." : "🤖 AIで整形"}
</button>

<button
className="rounded-lg border px-3 py-2"
onClick={() => {
clear();
}}
>
🧹クリア
</button>
</div>

{error && <p className="text-sm text-red-600">⚠️ {error}</p>}

{suggestion && (
<div className="rounded-xl border p-3 space-y-2">
<div className="flex items-center justify-between">
<p className="font-medium">✨整形案(まだ保存しない)</p>
<button
className="rounded-lg border px-3 py-2"
onClick={() => {
setBody(suggestion);
onChange(suggestion);
clear();
}}
>
✅反映する
</button>
</div>

<pre className="whitespace-pre-wrap text-sm leading-6">{suggestion}</pre>

<p className="text-xs opacity-70">
📝ポイント:ここで“人が確認してOK”してからフォームに反映!そのあとに保存ボタンでFirestore更新だよ〜
</p>
</div>
)}
</div>
);
}

4) (重要)悪用対策:App Check をONにしよう 🛡️🔥

App Check Protection

AI Logicのガイドでも App Check を早めに入れるのが強く推奨 されています📌(Firebase) Webの場合、App Check を使うと「正規のアプリからの呼び出し」を判定しやすくなって、不正アクセスの抑止になります🧱✨

実装例(App Check Webの初期化)👇

// src/firebase.ts(例:必要ならここに追記)
import { initializeAppCheck, ReCaptchaV3Provider } from "firebase/app-check";
import { app } from "./firebase";

// reCAPTCHA site key はコンソールの案内で作る
initializeAppCheck(app, {
provider: new ReCaptchaV3Provider("YOUR_RECAPTCHA_SITE_KEY"),
isTokenAutoRefreshEnabled: true,
});

このAPI名(initializeAppCheck / ReCaptchaV3Provider / isTokenAutoRefreshEnabled)は公式のWebドキュメントに載っています📚(Firebase)


5) ミニ課題 🎯😆

次のどれか1つやってみよう!

  1. “トーン選択” を付ける(やさしい/ビジネス/短く)🎚️
  2. “JSONで返して” を試す({ title, body } みたいに)🧾
  3. 入力が短すぎる時はAIボタンを無効(5文字未満とか)🚧

6) チェックリスト ✅✅

  • AIの結果が 勝手に保存されてない(反映→保存の順になってる?)
  • loading 中にボタン連打できない?👆💥
  • 失敗時にユーザーが次の行動を取れるメッセージになってる?😇
  • App Check を入れた(または入れる予定が決まった)?🛡️(Firebase)

7) よくあるつまづき 💥😵‍💫

  • Q: result.response.text() が空っぽ A: セーフティ設定や入力が短すぎる/曖昧すぎる時に起きがち。入力の条件を少し足してみよう(例:「箇条書きOK」「出力は本文だけ」など)🧠

  • Q: AIがそれっぽい嘘を書く A: あるある!😆 今回は「整形」用途なので、“意味を変えずに” をプロンプトに入れて、しかも 人が確認して反映 で事故を潰そう✅


8) おまけ:Antigravity / Gemini CLIで“実装速度”を上げる 🛸⌨️✨

ここは第19章に近いけど、今でも超効くので軽く紹介!

  • Firebase MCP server を使うと、AIエージェントがFirebaseの情報(例:Firestoreやルール周り)にアクセスしやすくなります🧩(Firebase)
  • さらに Gemini CLI の Firebase拡張 を入れると、MCPツールとプロンプトがまとまって使える…という公式案内があります🚀(Firebase)
  • そして 2026-02-11に「Extension settings」 が入って、拡張の設定がかなり楽になったよ、という更新も出ています(地味に助かるやつ!)🧰✨(Google Developers Blog)

9) ちょい寄り道:サーバー側にAIを置きたくなったら?🏗️☁️

UIからの呼び出しだけじゃ足りない(重い処理・秘密情報・複雑なツール連携)となったら、次の逃げ道があるよ👇

  • Cloud Functions for Firebase(Node.js 22/20 など)(Firebase)
  • Cloud Functions for Firebase(Python 3.10/3.11 ランタイム)(Firebase)
  • .NETを使うなら Microsoft の .NET 10(LTS) が軸になりやすい📌(Microsoft)
  • ただし Python は 3.14.3 / 3.13.12(2026-02-03時点) みたいに新しいのも出てるので、用途によってはCloud Runなども視野👀(Python documentation)

次は「整形」だけじゃなくて、画像(Imagen)構造化出力(JSON) に繋げると、一気に“管理画面が賢くなる”感じが出ます🤖✨ 第18章の続きとして、あなたのアプリの「どのフォームにAIボタン付けたいか」(記事?ユーザープロフィール?)に合わせて、プロンプトとUIを最適化する版も作れるよ😆