docs(CLAUDE.md): update with current architecture, podman, settings, deployment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
70
CLAUDE.md
70
CLAUDE.md
@@ -4,54 +4,96 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
**Build and run (Docker):**
|
**Build and run (Podman) — must run as root:**
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env # first time only
|
cp .env.example .env # first time only
|
||||||
docker compose up -d --build
|
sudo podman compose up -d --build
|
||||||
```
|
```
|
||||||
UI available at `http://127.0.0.1:8094/`
|
UI available at `http://127.0.0.1:8094/` and `https://voicelog.aquantico.lan` (via Traefik).
|
||||||
|
|
||||||
**Run locally without Docker:**
|
**Restart after code changes:**
|
||||||
|
```bash
|
||||||
|
sudo podman rm -f diarization-ui
|
||||||
|
sudo podman compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Run locally without Podman:**
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
API_BASE=http://... OLLAMA_BASE_URL=http://... DB_PATH=./ui.db uvicorn app:app --host 0.0.0.0 --port 8094 --reload
|
API_BASE=http://... OLLAMA_BASE_URL=http://... DB_PATH=./ui.db uvicorn app:app --host 0.0.0.0 --port 8094 --reload
|
||||||
```
|
```
|
||||||
|
|
||||||
**Publish container:**
|
**Publish container to registry:**
|
||||||
```bash
|
```bash
|
||||||
docker build -t registry.aquantico.lan/claw/diarization-ui:latest .
|
podman build -t registry.aquantico.lan/claw/diarization-ui:latest .
|
||||||
docker push registry.aquantico.lan/claw/diarization-ui:latest
|
podman push registry.aquantico.lan/claw/diarization-ui:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logs:**
|
||||||
|
```bash
|
||||||
|
sudo podman logs -f diarization-ui
|
||||||
```
|
```
|
||||||
|
|
||||||
There are no tests and no linter configured.
|
There are no tests and no linter configured.
|
||||||
|
|
||||||
|
> **Important:** This system uses `podman` / `sudo podman compose`, not `docker`. Always use `sudo` for podman compose commands — the container runs as root.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Detailed docs live in `doc/`:
|
||||||
|
- `doc/architecture.md` — data model, background jobs, DB schema
|
||||||
|
- `doc/api.md` — all HTTP endpoints
|
||||||
|
- `doc/interfaces.md` — Transcription-API and Ollama request/response details
|
||||||
|
- `doc/configuration.md` — env vars and runtime settings
|
||||||
|
- `doc/deployment.md` — build, deploy, backup, Traefik setup
|
||||||
|
|
||||||
|
**Keep `doc/` up to date** whenever routes, DB schema, settings keys, or external interfaces change.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
The entire application lives in a single file: `app.py` (~1550 lines). There are no templates, no separate frontend build, and no additional modules.
|
The entire application lives in a single file: `app.py` (~2000 lines). There are no templates, no separate frontend build, and no additional modules.
|
||||||
|
|
||||||
### Request handling
|
### Request handling
|
||||||
All routes are FastAPI endpoints. HTML is returned as server-rendered Python f-strings using Bootstrap 5.3 (CDN) for layout. Inline `<script>` blocks handle client-side interactivity. The `layout()` function wraps every page with the sidebar navigation, topbar, shared CSS, and the global modal/JS helpers (`window.showModal`, `window.uiPrompt`, `window.uiConfirm`, `window.uiSelect`).
|
All routes are FastAPI endpoints. HTML is returned as server-rendered Python f-strings using Bootstrap 5.3 (CDN) for layout. Inline `<script>` blocks handle client-side interactivity. The `layout()` function wraps every page with the sidebar navigation, topbar, shared CSS, and the global modal/JS helpers (`window.showModal`, `window.uiPrompt`, `window.uiConfirm`, `window.uiSelect`).
|
||||||
|
|
||||||
### Data model (SQLite)
|
### Data model (SQLite)
|
||||||
The DB is a single SQLite file at `DB_PATH` (default `/data/ui.db`). Four tables:
|
The DB is a single SQLite file at `DB_PATH` (default `/data/ui.db`). Five tables:
|
||||||
- **projects** — named groupings for documents
|
- **projects** — named groupings for documents
|
||||||
- **prompts** — reusable LLM prompt templates
|
- **prompts** — reusable LLM prompt templates; each prompt can optionally override LLM parameters (`llm_use_default`, `llm_model`, `llm_think`, `llm_num_ctx`, `llm_num_predict`, `llm_repeat_penalty`, `llm_repeat_last_n`)
|
||||||
- **documents** — stored content; `kind` is either `transcript` (raw transcription output) or `analysis` (LLM result). An analysis document links back to its source via `source_document_id` and `prompt_id`.
|
- **documents** — stored content; `kind` is either `transcript` (raw transcription output) or `analysis` (LLM result). An analysis document links back to its source via `source_document_id` and `prompt_id`.
|
||||||
- **jobs** — background task queue; `kind` is `upload` or `analysis`; `status` cycles through `queued → running → done|error|cancelled`.
|
- **jobs** — background task queue; `kind` is `upload` or `analysis`; `status` cycles through `queued → running → done|error|cancelled`.
|
||||||
|
- **settings** — key/value store for runtime configuration (persists Ollama settings set via `/settings` page)
|
||||||
|
|
||||||
Schema migrations are handled inline in `init_db()` with `ALTER TABLE … ADD COLUMN` wrapped in `try/except`.
|
Schema migrations are handled inline in `init_db()` with `ALTER TABLE … ADD COLUMN` wrapped in `try/except`.
|
||||||
|
|
||||||
### Background job processing
|
### Background job processing
|
||||||
Jobs are processed by a `ThreadPoolExecutor(max_workers=2)`. `enqueue_job()` inserts a row and submits the worker function. Workers check for `cancelled` status at each checkpoint before making external calls.
|
Jobs are processed by a `ThreadPoolExecutor(max_workers=2)`. `enqueue_job()` inserts a row and submits the worker function. Workers check for `cancelled` status at each checkpoint before making external calls.
|
||||||
|
|
||||||
- **upload job** (`_process_upload_job`): POSTs the audio file to `{API_BASE}/transcribe-diarize`, stores `formatted_text` from the response as a `transcript` document.
|
- **upload job** (`_process_upload_job`): POSTs the audio/video file to `{API_BASE}/transcribe-diarize`, stores `formatted_text` from the response as a `transcript` document.
|
||||||
- **analysis job** (`_process_analysis_job`): POSTs to Ollama's `/api/generate` with the transcript content and selected prompt, stores the response as an `analysis` document.
|
- **analysis job** (`_process_analysis_job`): POSTs to Ollama's `/api/generate` with the transcript content and selected prompt, stores the response as an `analysis` document. LLM parameters are read from the prompt's own settings if `llm_use_default=0`, otherwise from the `settings` table, falling back to env vars.
|
||||||
|
|
||||||
The jobs page auto-polls `/jobs/data` every 3 s when active jobs exist, 10 s otherwise.
|
The jobs page auto-polls `/jobs/data` every 3 s when active jobs exist, 10 s otherwise.
|
||||||
|
|
||||||
|
### LLM settings priority
|
||||||
|
```
|
||||||
|
Prompt-specific (llm_use_default=0) → prompts.llm_* columns
|
||||||
|
Global (llm_use_default=1, default) → settings table
|
||||||
|
Fallback → env vars (OLLAMA_MODEL, OLLAMA_THINK, …)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime settings (settings table)
|
||||||
|
Configurable via `/settings` page: `ollama_model`, `ollama_think`, `ollama_num_ctx` (`auto` or fixed size), `ollama_num_predict`, `ollama_repeat_penalty`, `ollama_repeat_last_n`.
|
||||||
|
|
||||||
### External dependencies
|
### External dependencies
|
||||||
- **`API_BASE`** — the `transcribe-diarize` service (audio → transcript JSON with `formatted_text`)
|
- **`API_BASE`** — the `transcribe-diarize` service; accepts audio and video files, returns JSON with `formatted_text`
|
||||||
- **`OLLAMA_BASE_URL` / `OLLAMA_MODEL`** — Ollama instance for LLM analysis (default model `qwen3.5:9b`)
|
- **`OLLAMA_BASE_URL`** — Ollama instance for LLM analysis; also queried at `GET /api/tags` for the model list (lazy-loaded on `/settings` and `/prompts` pages)
|
||||||
|
|
||||||
### PWA
|
### PWA
|
||||||
The app serves `/manifest.webmanifest`, `/icon.svg`, and `/sw.js` directly from route handlers to support installable PWA on mobile.
|
The app serves `/manifest.webmanifest`, `/icon.svg`, and `/sw.js` directly from route handlers to support installable PWA on mobile.
|
||||||
|
|
||||||
|
## Deployment notes
|
||||||
|
|
||||||
|
- The active data volume is `diarization-ui_diarization_ui_data` (mounted at `/data`). Never delete this volume.
|
||||||
|
- There is also an older, unused volume `voicelog_diarization_ui_data` (legacy name) — leave it alone.
|
||||||
|
- Traefik network is `traefik` (external). The app is exposed at `voicelog.aquantico.lan` via the `websecure` entrypoint with TLS.
|
||||||
|
- Git remote: `https://gitea.aquantico.lan/claw/diarization-ui.git`
|
||||||
|
|||||||
Reference in New Issue
Block a user