相棒AI開発の進捗報告[01]

ブログ生成

相棒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はこんな感じの流れです。

  1. / ルートでHTMLを返す(render_templateでindex.htmlを描画)
  2. /chat エンドポイントでPOSTされたユーザーメッセージを受け取る
  3. OllamaのローカルAPIにリクエスト送信(モデルはgemma3:12bを使用)
  4. レスポンスをJSONでフロントに返す

特に便利なのは、モデルの切り替えが1行でできる点。
payload["model"]の部分を変えるだけで、雑談AIから画像生成モデルまで一瞬で差し替え可能です。

フロントエンド構成(index.html)

UIはTailwind CSSで構築しています。メリットはクラス名を書くだけで即デザイン反映できること。

UIの主な機能

  • 左サイドバー:機能メニュー(ブログ記事生成、画像生成、動画台本など)
  • キャラ選択ドロップダウン:話すAIキャラを切り替え
  • 吹き出しUI:ユーザーは右側、AIは左側にアイコン付きで表示
  • JavaScriptのfetch/chatに送信し、レスポンスを即表示

設計のポイント

  1. 役割分離:UIはHTML+JS、処理はFlask APIに集約
  2. モジュール化:フロントとバックエンドを疎結合にし、どちらかだけ更新可能
  3. ローカル完結:全通信をhttp://127.0.0.1内で閉じる設計
  4. 将来拡張/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-screenoverflow-auto で「全高+スクロール」対応

3) サイドバーのUI設計

「相棒らしさ」を出すため、キャラ選択と吹き出しをサイドバーに集約。

  • キャラアイコン:rounded-fullborderhover:scale-105 で反応性UP
  • キャラ選択:<select id="character-select">(今後は選択値をAPIに渡す)
  • 吹き出し:#ai-bubble を absolute で重ね、3秒でフェードアウト
&lt;img ... onclick="talkFromAI()" /&gt;
&lt;div id="ai-bubble" class="hidden absolute top-14 left-0 ..."&gt;
  &lt;span id="bubble-text"&gt;&lt;/span&gt;
&lt;/div&gt;

まずは「クリックで喋る」最小体験を提供し、操作の楽しさを優先しています。

4) メインエリア(ヘッダー/表示領域/フッター)

  • ヘッダー:モードや現在時刻などのステータス表示を想定
  • 表示領域:各機能(ブログ生成、画像生成など)のUIを差し替え表示
  • フッター:「ローカル実行中」明示でプライバシー安心感を演出

5) API通信フロー(fetchの最小実装)

&lt;script&gt;
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(() =&gt; bubble.classList.add("hidden"), 3000);
}
&lt;/script&gt;
  • /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 / blockopacity-0 / opacity-100
  • アクセントカラー一貫:赤系(text-red-600border-red-500)で“相棒感”を統一
  • 影と角丸shadow-mdrounded-xl でカードボックス調に

9) 今後のUIロードマップ

  1. チャット入力欄(Enter送信/Shift+Enter改行、送信中インジケーター)
  2. メッセージバブル(ユーザー右寄せ、AI左寄せ、時刻・既読風UI)
  3. 機能パネル切替(ブログ生成・画像生成・メモリ等をタブ/ルーターで)
  4. 設定モーダル(モデル選択、温度、最大トークン、キャラ口調プリセット)

ここまでくると「日常的に常駐させておく相棒UI」としての完成度が一段上がります。

まとめ

これで相棒AIのコア通信部分が完成しました。
次のステップは、キャラごとの性格データを追加して、雑談やタスクごとに最適なモデルを呼び出す構成に進めます。

Flask+Tailwindという組み合わせは、軽量・高速・拡張性の三拍子が揃っていて、ローカルAI開発には本当におすすめです。

コメント

タイトルとURLをコピーしました