相棒AI開発の第1歩:FlaskベースのAPI実装
今回は、相棒AIプロジェクトの第1フェーズとして、FlaskベースのバックエンドAPIと、Tailwind CSSを使ったフロントエンドUIを構築しました。
「Flask?FastAPIじゃないの?」という声が聞こえてきそうですが、今回の目的はとにかく早く動くプロトタイプを完成させること。そのため、最小構成でAPI化できるFlaskを選択しました。
Flaskを選んだ理由 ― Node.jsやFastAPIとの比較から
今回の相棒AIのバックエンドには、Flaskを採用しました。
理由はシンプルで、「ローカルLLMを爆速で動かす」ことにおいて、Flaskが一番ストレスが少なかったからです。
もちろん、Node.jsやFastAPIも検討しましたが、それぞれ得意分野が異なります。ここでは、それらとの比較も交えつつFlaskのメリットを整理します。
Flaskの強み
- 最短で動く:
pip install flask
+数十行コードでAPI化可能。試作や検証が超スピーディー。 - Python生態系に直結:PyTorchやNumPyなどのMLライブラリをそのまま利用でき、前処理~推論~後処理がPythonだけで完結。
- 依存が少なく学習コストが低い:WSGIベースでシンプルな設計。小~中規模まで見通しが良い。
- 柔軟な拡張性:必要に応じてFlask-LoginやSQLAlchemyなどを追加可能。最小構成からのスケールアップが楽。
- ローカル開発に強い:GPU連携やファイルI/O主体のローカル完結型プロジェクトに相性抜群。
- デプロイが容易:gunicornやuWSGI+nginxの構成が定番で情報も豊富。Docker化も簡単。
FastAPIとの比較
FlaskとFastAPIはPythonベースのAPIフレームワークですが、性格がかなり違います。
- Flaskが優れる点:学習コストの低さ、小規模プロトタイプの実装速度。
- FastAPIが優れる点:ASGI+asyncによる高並行処理、自動ドキュメント生成、型安全な大規模開発体験。
相棒AIのように「まず動くものを作りたい」段階では、Flaskの軽量さが勝ちます。
逆にAPI仕様をしっかり固めた大規模開発なら、FastAPIが有利です。
Node.js(Express等)との比較
- Flaskが優れる点:PythonによるML・データ処理資産を即利用可能。数値処理や推論タスク中心なら圧倒的に便利。
- Node.jsが優れる点:リアルタイム性が求められる高並行I/O処理(WebSocketや大量同時接続)、JS/TSでのフルスタック開発。
相棒AIの用途は、WebSocketで大量の同時接続を捌くようなリアルタイム処理ではなく、ローカルでのAI推論処理がメインです。
この条件では、Node.jsよりFlaskのほうが「環境構築~推論コード実装」までの導線が短く、開発効率も高くなります。
Flaskは、小回りの利く軽量フレームワークでありながら、Pythonの強力なライブラリ群を最大限に活用できるのが魅力です。
特にローカルLLMやGPU推論など、AI寄りの開発では「作って動かすまでが早い」ことが生産性に直結します。
今回の相棒AI開発では、試作スピードを最優先した結果、Flaskが最適解でした。
バックエンド構成(app.py)
今回のapp.pyはこんな感じの流れです。
/
ルートでHTMLを返す(render_template
でindex.htmlを描画)/chat
エンドポイントでPOSTされたユーザーメッセージを受け取る- OllamaのローカルAPIにリクエスト送信(モデルは
gemma3:12b
を使用) - レスポンスをJSONでフロントに返す
特に便利なのは、モデルの切り替えが1行でできる点。payload["model"]
の部分を変えるだけで、雑談AIから画像生成モデルまで一瞬で差し替え可能です。
フロントエンド構成(index.html)
UIはTailwind CSSで構築しています。メリットはクラス名を書くだけで即デザイン反映できること。
UIの主な機能
- 左サイドバー:機能メニュー(ブログ記事生成、画像生成、動画台本など)
- キャラ選択ドロップダウン:話すAIキャラを切り替え
- 吹き出しUI:ユーザーは右側、AIは左側にアイコン付きで表示
- JavaScriptの
fetch
で/chat
に送信し、レスポンスを即表示
設計のポイント
- 役割分離:UIはHTML+JS、処理はFlask APIに集約
- モジュール化:フロントとバックエンドを疎結合にし、どちらかだけ更新可能
- ローカル完結:全通信を
http://127.0.0.1
内で閉じる設計 - 将来拡張:
/chat
以外にも/image
、/audio
など追加しやすい構造

フロントエンド構成(index.html)をもう少し詳しく
1) ファイル構成と読み込み
static/css/output.css
:Tailwind CSSビルド済み(PostCSS/Tailwindで事前ビルド)static/img/character_ui.png
:キャラアイコン- テンプレートは Flask の
render_template
で配信(static
を template_folder に指定)
Tailwindをクラス直書きで使うことで、「試作→調整→反映」を高速化しています。Sassを挟まずにユーティリティだけで完結。
2) レイアウトの骨格(左右2カラム)
<body class="flex h-screen bg-neutral-100 text-gray-900">
<aside class="w-64 bg-white shadow-md flex flex-col p-4 relative">...</aside>
<main class="flex-1 flex flex-col">...</main>
</body>
- aside:固定幅(
w-64
)のサイドバー - main:フレックス伸長(
flex-1
)でコンテンツ領域を確保 h-screen
とoverflow-auto
で「全高+スクロール」対応
3) サイドバーのUI設計
「相棒らしさ」を出すため、キャラ選択と吹き出しをサイドバーに集約。
- キャラアイコン:
rounded-full
+border
+hover:scale-105
で反応性UP - キャラ選択:
<select id="character-select">
(今後は選択値をAPIに渡す) - 吹き出し:
#ai-bubble
を absolute で重ね、3秒でフェードアウト
<img ... onclick="talkFromAI()" />
<div id="ai-bubble" class="hidden absolute top-14 left-0 ...">
<span id="bubble-text"></span>
</div>
まずは「クリックで喋る」最小体験を提供し、操作の楽しさを優先しています。
4) メインエリア(ヘッダー/表示領域/フッター)
- ヘッダー:モードや現在時刻などのステータス表示を想定
- 表示領域:各機能(ブログ生成、画像生成など)のUIを差し替え表示
- フッター:「ローカル実行中」明示でプライバシー安心感を演出
5) API通信フロー(fetchの最小実装)
<script>
async function sendMessageToAI(message) {
const res = await fetch('http://127.0.0.1:5000/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
});
const data = await res.json();
return data.reply;
}
async function talkFromAI() {
const aiReply = await sendMessageToAI("こんにちは");
const bubble = document.getElementById("ai-bubble");
document.getElementById("bubble-text").textContent = aiReply;
bubble.classList.remove("hidden");
setTimeout(() => bubble.classList.add("hidden"), 3000);
}
</script>
/chat
に JSON で投げ、{ reply }
を受け取るシンプル設計- 今後は 選択キャラ や タスク種別 を一緒に送ると分岐が作りやすい
6) 状態と拡張ポイント(次の一手)
- 入力フォーム+ログ:テキスト入力欄と会話履歴(スクロール固定)を追加
- エラーハンドリング:
try/catch
でネットワーク失敗時にトースト表示 - キャラ設定の反映:
#character-select
の値を/chat
ボディに同送body: JSON.stringify({ message, character: document.getElementById('character-select').value })
- ストリーミング対応:Flask側をSSE/WebSocketにすると長文でも“待たせない”UIに
- ローカル保存:
localStorage
で会話を端末に保存(完全ローカル運用と相性◎)
7) レスポンシブとアクセシビリティ
- スマホ最適化:サイドバーをスライド開閉(
md:hidden
+ドロワー) - フォーカスリング:
focus-visible:outline
を適用しキーボード操作に配慮 - ARIAラベル:アイコンには
aria-label
を付与(読上げ対応)<img ... role="button" aria-label="AIに話しかける">
8) デザイン方針(Tailwindのユーティリティ活用)
- ステートはクラスで表現:
hidden
/block
、opacity-0
/opacity-100
- アクセントカラー一貫:赤系(
text-red-600
/border-red-500
)で“相棒感”を統一 - 影と角丸:
shadow-md
+rounded-xl
でカードボックス調に
9) 今後のUIロードマップ
- チャット入力欄(Enter送信/Shift+Enter改行、送信中インジケーター)
- メッセージバブル(ユーザー右寄せ、AI左寄せ、時刻・既読風UI)
- 機能パネル切替(ブログ生成・画像生成・メモリ等をタブ/ルーターで)
- 設定モーダル(モデル選択、温度、最大トークン、キャラ口調プリセット)
ここまでくると「日常的に常駐させておく相棒UI」としての完成度が一段上がります。
まとめ
これで相棒AIのコア通信部分が完成しました。
次のステップは、キャラごとの性格データを追加して、雑談やタスクごとに最適なモデルを呼び出す構成に進めます。
Flask+Tailwindという組み合わせは、軽量・高速・拡張性の三拍子が揃っていて、ローカルAI開発には本当におすすめです。
コメント