From f7eeae8469fe0792f55628a32e99b1b5daed5262 Mon Sep 17 00:00:00 2001 From: KansaiGaijin <83641841+KansaiGaijin@users.noreply.github.com> Date: Thu, 30 Jul 2026 16:09:54 +1200 Subject: [PATCH] docs: update README with auth, campaigns, and CI/CD changes --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7fc38f8..0c3142b 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,30 @@ cd nat20-notes docker compose up -d --build ``` -Then open `http://:8020` (yes, that port reads "a d20") and follow the setup wizard: +Open `http://:8020` (d20 nod) and **log in** with the default +admin credentials (`admin` / `admin`, overridable via `NAT20_ADMIN_USERNAME` +and `NAT20_ADMIN_PASSWORD`). The first user is created automatically on +first startup — no separate registration step. + +Then follow the setup wizard: 1. Choose a Whisper model size based on your GPU's available VRAM (guidance shown in-app) -2. Choose local Ollama or a hosted API for summarization, and paste your HF token -3. Optionally paste campaign/world context (NPC names, places) so summaries recognize them correctly +2. Give your campaign a name +3. Choose local Ollama or a hosted API for summarization, and paste your HF token +4. Optionally paste campaign/world context (NPC names, places) so summaries recognise them correctly A reference compose file using named volumes only (no host paths) is at [`docker-compose.example.yml`](./docker-compose.example.yml). ## Using it -1. **Upload** a recording (audio or video — video is auto-converted, audio-only files skip that step and are much faster). Files over **90 MB** are auto-chunked with 3-way concurrent uploads. -2. **Transcribe** — runs in the background. On completion you're **automatically taken** to the speaker-naming screen. -3. **Name your speakers** — a waveform-style "session reel" shows each detected speaker's segments; click any point to jump the audio there and hear who's talking, then type in their name. Use the checkboxes to **merge** speakers (e.g. when diarization over-splits one person into `SPEAKER_00`, `SPEAKER_05`, etc.). -4. **Generate notes** — click "Done naming" and confirm; notes generation starts automatically and you're taken to the job progress screen. When finished, navigate to the notes viewer. -5. **Review & tweak** — regenerate notes, rename speakers, or delete jobs/sessions from the session detail page. +1. **Log in** with your username and password. Admins can create additional users at `/users`. +2. **Select a campaign** from the sidebar (or use the default). Each campaign has its own settings, sessions, and player recaps. +3. **Upload** a recording (audio or video — video is auto-converted, audio-only files skip that step and are much faster). Files over **90 MB** are auto-chunked with 3-way concurrent uploads. +4. **Transcribe** — runs in the background. On completion you're **automatically taken** to the speaker-naming screen. +5. **Name your speakers** — a waveform-style "session reel" shows each detected speaker's segments; click any point to jump the audio there and hear who's talking, then type in their name. Use the checkboxes to **merge** speakers (e.g. when diarization over-splits one person into `SPEAKER_00`, `SPEAKER_05`, etc.). +6. **Generate notes** — click "Done naming" and confirm; notes generation starts automatically and you're taken to the job progress screen. When finished, navigate to the notes viewer. +7. **Review & tweak** — regenerate notes, rename speakers, or delete jobs/sessions from the session detail page. ## Data layout @@ -47,7 +55,7 @@ The app stores everything under `/data` (inside the container): | `campaigns/{id}/audio/` | Uploaded recordings and extracted audio, organised per campaign | | `campaigns/{id}/transcriptions/` | Per-session transcript JSON files | | `campaigns/{id}/notes/` | Generated notes (GM log + player recap) | -| `app.db` | SQLite database (sessions, speakers, campaigns, settings, jobs) | +| `app.db` | SQLite database (users, campaigns, campaign_shares, sessions, speakers, campaign/global settings, jobs) | ## Configuration @@ -85,12 +93,37 @@ and Settings page can set them at runtime. | `NAT20_PLAYER_RECAP_STYLE` | Player recap format | `story` `diary` `bullets` `custom` | `story` | | | `NAT20_PLAYER_RECAP_CUSTOM_PROMPT` | Custom prompt (only when style is `custom`) | text | (none) | | +#### Auth + +| Variable | What it does | Values | Default | Notes | +|---|---|---|---|---| +| `NAT20_ADMIN_USERNAME` | Admin username | string | `admin` | Created on first startup if no users exist | +| `NAT20_ADMIN_PASSWORD` | Admin password | string | `admin` | | +| `NAT20_JWT_SECRET` | JWT signing key | string | (random) | Set to a fixed value so tokens survive restarts | + #### Setup wizard | Variable | What it does | Values | Default | Notes | |---|---|---|---|---| | `NAT20_ONBOARDING_COMPLETED` | Skip the setup wizard | `true` or `false` | `false` | Set to `"true"` after you finish the wizard once | +### Campaigns + +Campaigns organise sessions, settings, and context into separate silos. +On first run a **default** campaign is created automatically; you can +name it during the setup wizard and rename it later in Settings. + +Key features: + +- **Per-campaign settings** — each campaign has its own Whisper model, + LLM config, world context, and player recap style. Switch campaigns + in the sidebar to change which settings apply to new sessions. +- **Sharing** — the admin can share a campaign with other registered users + from the campaign's detail page. Shared users can upload sessions and + generate notes within that campaign. +- **User management** — admins can create additional users via the Users + page (`/users`). Every user authenticates with the same login form. + ### Campaign context You can paste context directly in the Settings page, or point to a file @@ -108,7 +141,16 @@ system overhead from other GPU-using services). ## Architecture -- `backend/` — FastAPI, SQLite (no external DB needed), WhisperX as a library (no nested Docker), in-process `ThreadPoolExecutor` background jobs (no Redis/Celery) -- `frontend/` — React 18 + Vite + Tailwind, served via nginx (listens on port **8020**) which proxies `/api` to the backend +- `backend/` — FastAPI, SQLite (no external DB needed), WhisperX as a library (no nested Docker), in-process `ThreadPoolExecutor` background jobs (no Redis/Celery). JWT auth with HMAC-SHA256 tokens, scrypt password hashing. +- `frontend/` — React 18 + Vite + Tailwind, served via nginx (listens on port **8020**) which proxies `/api` to the backend. Auth state managed via React context; global fetch interceptor adds `Authorization: Bearer` to all API calls. + +### CI/CD + +The backend is split into two Docker images for fast rebuilds: + +| Image | Build time | Contents | +|---|---|---| +| `whisperx-base` (`.deps`) | 5-10 min, only when `requirements.txt` changes | PyTorch 2.3.1 + cu121, WhisperX, ctranslate2, ffmpeg | +| `backend` (thin) | ~10 seconds | App code only (`FROM whisperx-base`) | Both run as standard Docker Compose services — no special orchestration needed beyond GPU passthrough for the backend.