# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## プロジェクト概要 Python (FastAPI) バックエンド + Vue 3 (TypeScript) フロントエンドのチャットアプリ。 LLM は LiteLLM 経由で OpenAI / Anthropic / Ollama など任意のプロバイダーを統一 API で扱い、会話履歴とメモリは SQLite に永続化する。 ## コマンド ### バックエンド ```powershell Set-Location backend # 依存インストール (SSL プロキシ環境では --native-tls が必要) uv sync --native-tls # 開発サーバー起動 uv run uvicorn app.main:app --reload # テスト pytest pytest tests/test_chat.py # 単一ファイル ``` ### フロントエンド ```powershell Set-Location frontend # 依存インストール npm install # 開発サーバー起動 (port 5173) npm run dev # ビルド npm run build # 型チェック npm run type-check ``` ### 環境設定 ```powershell Set-Location backend Copy-Item .env.example .env # .env を編集して API キーとモデル名を設定 ``` ## アーキテクチャ 詳細は `docs/architecture.md` を参照。 ``` frontend (Vue3 + Pinia, :5173) ↕ REST + SSE (Vite proxy) backend (FastAPI, :8000) ├── app/api/ チャット・メモリ・ノート・ログ のルーター ├── app/core/ LLM ラッパー・メモリロジック・共有ノート・設定 └── app/db/ SQLAlchemy モデル・DB 接続 ↕ SQLite (playchat.db) + LiteLLM → 任意の LLM ``` ### メモリ機構 - **短期**: セッション内の全メッセージをコンテキストに含める - **長期**: メッセージ数が `MEMORY_SUMMARIZE_THRESHOLD`(デフォルト 20)を超えると古い半分を LLM で要約 → `memories` テーブルに保存 → 次回以降のシステムプロンプトに注入 ### 共有ノート ユーザーと AI が共同編集するノート。`note_pages` テーブルに 1 ページ 1 行で保存し、UI ではタブとして切り替える。 - **モデルから見える範囲**: システムプロンプトに入るのは**ページのタイトル一覧**(と本文の先頭 40 文字程度のプレビュー)だけ。本文全体は含めない - **モデルによる読み書き**: `read_note` / `write_note` ツール(`app/core/notes.py`)で行う。`write_note` は存在しないタイトルを指定するとページを新規作成し、`mode` が `append`(既定)なら追記、`replace` なら全置換 - **ツール実行の流れ**: `llm.resolve_tool_calls()` が本番の応答生成前にツール呼び出しを解決する。`web_search` と共通の仕組みで、ノート系ツールは `db` が渡されたときだけモデルに提示される - **UI への反映**: AI がノートを書き換えた場合、SSE で `notes_updated` を送ってフロント側のノートパネルを再読み込みさせる - **編集の衝突回避**: フロントは未保存の編集があるページ(`dirtyIds`)をサーバーの値で上書きしない ### SSE ストリーミング `POST /chat/stream` が SSE を返す。イベント種別: `session_id`(新規セッション ID)/ `chunk`(テキスト断片)/ `sources`(Web 検索の出典)/ `notes_updated`(AI が共有ノートを更新)/ `done`(完了)/ `error`(エラー)。 フロントは `src/api/client.ts` の `streamChat()` で fetch + ReadableStream により受信し、`messages.value[msgIdx]` を reactive proxy 経由で更新する。 ### Markdown レンダリング アシスタントメッセージは `marked` + `DOMPurify` でレンダリング。ストリーミング中の未閉じコードフェンスは自動補完してから描画する(`MarkdownContent.vue`)。 ### モデル切替 `.env` の `DEFAULT_MODEL` またはリクエストの `model` フィールドで指定。 ローカル Ollama は `ollama/llama3` 形式、`OLLAMA_API_BASE` でエンドポイントを設定。 `DEBUG=true` で LiteLLM の詳細ログが有効になる。 ## ローカル開発環境メモ - このマシンでは PostgreSQL がポート 8080 で起動している(本アプリの `DATABASE_URL` には使用していないが、ポート競合時は確認すること) - このマシンには TLS 監視プロキシらしき設定があり、環境変数 `SSLKEYLOGFILE` が名前付きパイプ(`nllMonFltProxy`)を指している。これが原因で `litellm`(OpenSSL を直接ロード)や `pyright`(内部で Node.js サブプロセスを起動)が `OPENSSL_Uplink` エラーでクラッシュすることがある。発生した場合は当該コマンド実行時のみ `SSLKEYLOGFILE` を unset すると回避できる ```powershell Remove-Item Env:\SSLKEYLOGFILE uv run pyright ``` ## 環境変数(backend/.env) | 変数 | デフォルト | 説明 | |---|---|---| | `DEFAULT_MODEL` | `gpt-5.4` | デフォルト LLM モデル | | `DATABASE_URL` | `sqlite:///./playchat.db` | DB 接続先 | | `MEMORY_SUMMARIZE_THRESHOLD` | `20` | 長期メモリ化するメッセージ数の閾値 | | `CORS_ORIGINS` | `http://localhost:5173` | 許可する CORS オリジン | | `DEBUG` | `false` | LiteLLM デバッグログの有効化 | | `OPENAI_API_KEY` | — | OpenAI API キー | | `ANTHROPIC_API_KEY` | — | Anthropic API キー | | `OLLAMA_API_BASE` | `http://localhost:11434` | Ollama エンドポイント | | `NOTES_TOOL_CONTENT_LIMIT` | `4000` | `read_note` が 1 回に返す本文の最大文字数 | | `SITE_PASSWORD` | — | サイト全体を保護する共有パスワード(未設定なら無認証) | | `SESSION_SECRET_KEY` | 起動毎に自動生成 | ログインセッション Cookie の署名鍵 |