pediatric-ai-scribe-v3/docs/ops-docs-ped-ai-and-milvus.md
Daniel ceccd18387
Some checks failed
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Docker Build / Build Docker image (push) Successful in 22s
Forgejo Docker Build / Deploy to the host (push) Failing after 1s
docs: take the Learning Hub out of the docs
The feature was removed; the docs still described it as live. Worst of
it was api-reference.md, which documented nine /api/learning endpoints
and fourteen /api/admin/learning CMS endpoints — routes that answer 404
— plus POST /api/user/webdav-path, whose column was dropped by
migration. Anyone reading them was reading fiction.

Checked against the running system rather than assumed: no learning
table exists, users.webdav_learning_path is gone, generated_image_links
is gone, and no route mounts /api/learning or /api/admin/learning.

Two things that look like Learning Hub and are not, so they stay:

- learningRetrieval.js is live — My Resources uses it. Its settings keep
  the learning.* names because renaming them would orphan whatever an
  administrator has already set. retrieval-tuning.md now says so instead
  of listing the rows under two different feature names.
- the moderator role is still assignable. It gated the CMS and now
  grants nothing; authentication.md says that rather than implying
  powers it does not have. moderatorMiddleware has no callers left,
  which is worth removing on its own.

auth-admin-learning.md is now auth-admin.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-12 22:24:29 +02:00

120 lines
5.2 KiB
Markdown

# Ped AI And Milvus
Last updated: 2026-09-11
What Ped-AI is, which Milvus is which, and where each kind of data lives. Written
for the operator handbook, so it says where things are rather than how they are
coded.
## What Ped-AI is
A clinical documentation assistant. Two halves:
- **Workspace** — encounter notes, dictation, SOAP, well and sick visits, ED,
hospital course, calculators, My Resources. Each generates text with an LLM
through the LiteLLM gateway.
- **Clinical Assistant** — a chat that answers only from an indexed medical
library, with numbered citations back to the source documents.
It runs as one container, `pediatric-ai-scribe`, on `127.0.0.1:3552` behind
Caddy. Postgres and Redis are its own; everything else it talks to belongs to
another stack.
## The two Milvus servers
They are easy to confuse, and both listen on 19530. Connecting to the wrong one
succeeds at the network level and then fails authentication, because each has
its own users — so a mistake here looks like a password problem.
| Which | Container | Database | Collection | Holds |
|---|---|---|---|---|
| **Clinical** | `nextcloud-mcp-server-milvus-1` | `default` | `mcp_bge_m3_1024` | The medical library Ped-AI answers from. ~1.8M chunks. |
| **Personal assistant** | `personal-assistant-storage-milvus-basic-milvus-1` | `basic` | `personal_assistant_bge_m3_1024` | Your Nextcloud mail, notes, tables and files. |
Both embed with **bge-m3** at 1024 dimensions, which is what the collection names
now say. Neither is reachable from the internet: the personal one publishes no
ports at all, the clinical one is bound to `127.0.0.1`.
Repositories, renamed 2026-09-11 to match what they hold:
- `personal-assistant-storage-milvus` — was `ped-ai-storage`
- `clinical-storage-milvus` — was `nextcloud-mcp-server`, and runs no MCP server,
only etcd, MinIO and Milvus
Container and volume prefixes still read `ped-ai-storage_*` on anything not yet
migrated; the project name is pinned deliberately, because changing it makes
Compose create empty volumes instead of finding the existing ones.
## How Milvus stores its data
Milvus keeps **segment files in MinIO**, not on a local disk, and its metadata in
etcd. That matters: `COMMON_STORAGETYPE=local` writes segments relative to the
working directory, so recreating the container destroys them while etcd still
references them, and the collection then hangs at `Loading` forever. Each Milvus
has its own MinIO and its own etcd container.
Access is per-database and per-collection. Renaming a collection revokes its
grants, because a grant names the collection — after any rename, re-run the
bootstrap that provisions the roles.
## Where each kind of data lives
| Data | Where |
|---|---|
| Accounts, notes, encounters, saved resources | Postgres (`pedscribe`) |
| Generated images | MinIO bucket `generated-images` |
| Voice recordings, kept 24 hours | MinIO bucket `audio-backups` |
| Medical library chunks | Clinical Milvus |
| Nextcloud mail, notes, tables, files | Personal assistant Milvus |
Quizzes are ordinary relational tables and use no vectors at all.
## How a question is answered
1. The browser posts to `/api/clinical-assistant/chat/stream`.
2. Ped-AI calls the MCP tool `clinical_semantic_search` on `mcp-server-mcp-1`.
3. That searches the clinical Milvus and returns passages with scores.
4. Ped-AI sends those passages to the chat model as the only permitted source.
5. The answer streams back with numbered citations; the Sources panel shows the
passages behind them.
If retrieval returns nothing, the assistant says so rather than answering from
the model's own knowledge.
## Recordings
Every recording is kept for 24 hours, whether or not its transcription
succeeded, gzipped and encrypted before storage. A recording holds a screen wake
lock while it runs, survives moving around the app, and is saved with the module
it came from if the session ends. Recordings can be downloaded from
Settings → Audio backups.
Transcription is a gateway model — currently `mistral-voxtral-mini-transcribe`.
The browser's own speech recognition is a separate, off-by-default setting; it
sends audio to the browser vendor and is not HIPAA-compliant.
## Indexing
| Index | Written by | Source |
|---|---|---|
| Clinical | `mcp-server-mcp-indexer-1` | The medical library. Text extraction via `unstructured`, PyMuPDF4LLM and Tesseract. |
| Personal assistant | `personal-assistant-storage-milvus-basic-indexer-1` | Nextcloud. Mail first, then notes, deck, tables, calendar, todos, collectives, cookbook, talk, contacts, and files. PDF text via PyMuPDF4LLM. |
The folder the personal indexer walks is `BASIC_INDEXING_DOCUMENTS_FOLDER`. It
takes one folder or several separated by commas, each walked recursively:
```
BASIC_INDEXING_DOCUMENTS_FOLDER=Personal assistant,Clinical Notes
```
A complete listing is the authority for deletion, so moving that setting to a
different folder removes the chunks of everything no longer under an indexed
root.
## Quick checks
```bash
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3552/api/health
docker ps --format '{{.Names}} {{.Status}}' | grep -E 'pediatric-ai-scribe|milvus|indexer'
docker logs --since 10m personal-assistant-storage-milvus-basic-indexer-1 | grep -c Indexed
```