Files
playchat/docs/architecture.md
T
colcaroliandClaude Sonnet 4.6 4a08ba29fa Add system memory monitoring, Bedrock support, and Discord integrations
- Add CPU/GPU memory monitoring endpoint and frontend widget
- Add Amazon Bedrock model support (API key / inference profiles) plus model selector entries
- Add Discord weather/laundry notification job (JMA forecast + LLM-generated message)
- Add Discord bot that replies to mentions via the configured LLM, with weather-aware context
- Add scheduled "useless tips" job with separate webhook and quiet-hours skip
- Switch FastAPI startup to lifespan handler, log viewer, markdown rendering, and toast UI additions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 00:59:38 +09:00

5.3 KiB
Raw Blame History

アーキテクチャ概要

全体構成

フロントエンド (Vue 3 + TypeScript + Vite, :5173)
        ↕ REST + SSE (Vite dev proxy 経由)
バックエンド (FastAPI + Python, :8000)
        ↕ SQLAlchemy
   SQLite (playchat.db)
        ↕ LiteLLM
   OpenAI / Anthropic / Ollama など任意の LLM

バックエンド

ディレクトリ構成

backend/
├── app/
│   ├── main.py          # FastAPI インスタンス、CORS、ルーター登録、DB初期化
│   ├── api/
│   │   ├── chat.py      # チャット・セッション関連エンドポイント
│   │   ├── memory.py    # 長期メモリ参照・削除
│   │   └── logs.py      # API ログ参照・削除
│   ├── core/
│   │   ├── config.py    # .env 読み込み・定数定義
│   │   ├── llm.py       # LiteLLM ラッパー(ストリーミング・ログ記録)
│   │   └── memory.py    # メモリ読み書きロジック(要約・コンテキスト生成)
│   └── db/
│       ├── database.py  # SQLite 接続・セッションファクトリ・テーブル自動作成
│       └── models.py    # SQLAlchemy モデル定義
└── pyproject.toml

DB テーブル

テーブル 主なカラム 用途
sessions id (UUID), title, model, created_at, updated_at チャットセッション
messages id, session_id, role, content, created_at 会話メッセージ(短期メモリ)
memories id, session_id, summary, embedding_json, created_at 要約による長期メモリ
api_logs id, session_id, model, request_json, response_text, error, latency_ms, created_at LLM API 呼び出しログ

メモリ機構(core/memory.py)

  1. 短期メモリ: セッション内の全 messages をコンテキストとして送信
  2. 長期メモリ: メッセージ数が MEMORY_SUMMARIZE_THRESHOLD(デフォルト 20)を超えると、古い半分を LLM で要約して memories に保存しメッセージを削除
  3. コンテキスト合成: get_context_messages() が memories の要約をシステムメッセージとして先頭に付加し、残存メッセージと結合して返す

LLM 呼び出し(core/llm.py)

  • stream_chat() / complete() が LiteLLM を薄くラップ
  • _log_context で呼び出しを囲み、成功・失敗どちらも api_logs テーブルに記録
  • DEBUG=true で litellm._turn_on_debug() が有効になり詳細ログが出力される

SSE ストリーミング(api/chat.py)

POST /chat/stream は StreamingResponse で以下のイベントを順番に送出する:

data: {"type":"session_id","value":"<uuid>"}   # 新規セッション時のみ
data: {"type":"chunk","value":"テキスト断片"}   # 0回以上
data: {"type":"done"}                           # 正常完了
data: {"type":"error","value":"エラー内容"}     # 例外発生時

バッファリング防止のため Cache-Control: no-cache と X-Accel-Buffering: no を付与する。


フロントエンド

ディレクトリ構成

frontend/src/
├── api/
│   └── client.ts          # fetch ラッパー・SSE クライアント・型定義
├── stores/
│   └── chat.ts            # Pinia ストア(全アプリ状態)
├── components/
│   ├── SessionList.vue    # セッション一覧サイドバー
│   ├── ChatWindow.vue     # メッセージ表示エリア
│   ├── MessageInput.vue   # 入力欄・送信
│   ├── ModelSelector.vue  # LLM モデル切替セレクト
│   ├── MarkdownContent.vue # marked + DOMPurify によるレンダリング
│   ├── LogViewer.vue      # API ログ閲覧パネル
│   └── ToastList.vue      # エラートースト通知
└── App.vue                # ルートレイアウト

状態管理(stores/chat.ts)

状態 型 説明
sessions SessionInfo[] セッション一覧
currentSessionId string | null 選択中セッション
messages Message[] 表示中メッセージ
isStreaming boolean SSE 受信中フラグ
selectedModel string 選択中 LLM モデル
toasts Toast[] エラー通知キュー

SSE 受信フロー

  1. sendMessage() がユーザーメッセージと空のアシスタントメッセージを messages に追加
  2. streamChat() が fetch + ReadableStream で SSE を受信
  3. chunk イベント受信のたびに messages.value[msgIdx].content を更新(Vue reactive proxy 経由)
  4. done で pending フラグを解除
  5. error / ネットワークエラーは error フラグを立て赤バブル表示 + トースト通知

Markdown レンダリング(MarkdownContent.vue)

  • アシスタントメッセージのみ marked で HTML に変換後 DOMPurify でサニタイズ
  • ストリーミング中(pending=true)は未閉じのコードフェンス(```)を自動補完してから描画

Vite プロキシ設定

/chat、/memory、/logs、/health を http://localhost:8000 に転送。
/chat は SSE バッファリング無効化のため configure で x-accel-buffering: no を付与。