docs align memory and audio backup behavior

This commit is contained in:
Daniel 2026-05-08 23:32:39 +02:00
parent 4a020fb7b0
commit 19c9e8ba1e
8 changed files with 46 additions and 67 deletions

View file

@ -124,9 +124,11 @@ Applied to: `soap.js`, `hpi.js`, `refine.js`, `sickVisit.js`, `wellVisit.js`,
### Physician memories
Saved corrections are injected into prompts as `[STYLE HINTS (low priority)]`
with 200-character snippets. The low-priority wording prevents smaller models
from hallucinating content from the correction examples into the current note.
Saved templates and prompt preferences are injected into prompts as
`[STYLE HINTS (low priority)]` when they belong to AI-context categories. The
low-priority wording prevents smaller models from hallucinating content from a
stored template into the current note. `custom` memories and legacy
`correction_*` rows are not prompt context.
## API call logging

View file

@ -844,36 +844,15 @@ Delete a memory.
### GET /api/memories/context
Retrieve all memories formatted for injection into AI generation prompts.
Retrieve AI-context template/preference rows formatted for injection into AI
generation prompts. `custom` rows and legacy `correction_*` rows are excluded.
- **Auth required:** Yes
- **Response:**
```json
{
"context": "string"
}
```
---
### POST /api/memories/correction
Automatically save a style correction as a memory. Used when the physician corrects AI output.
- **Auth required:** Yes
- **Request body:**
```json
{
"section": "string",
"original_snippet": "string",
"corrected_snippet": "string"
}
```
- **Response:**
```json
{
"success": true,
"id": "number"
"success": true,
"context": "string"
}
```

View file

@ -138,20 +138,23 @@ Draft/complete encounter workspace. Auto-expires (default 7 d,
### `user_memories`
Per-user clinical-style hints injected into AI prompts.
Per-user template and preference rows. Only selected categories are injected
into AI generation through `/api/memories/context`; `custom` rows are stored
for the user but not included in prompt context.
| Column | Type | Notes |
|---|---|---|
| id | SERIAL PK | |
| user_id | INTEGER FK users.id ON DELETE CASCADE | |
| category | TEXT NOT NULL DEFAULT 'custom' | `physical_exam`, `ros`, `encounter_format`, `custom`, `template_*`, `correction_*` |
| name | TEXT NOT NULL | |
| content | TEXT NOT NULL | |
| category | TEXT NOT NULL DEFAULT 'custom' | Valid categories: `physical_exam`, `ros`, `encounter_format`, `family_history`, `assessment_plan`, `custom`, `template_soap`, `template_hpi`, `template_wellvisit`, `template_sickvisit`, `template_ed`. Legacy `correction_*` rows may exist but are filtered out. |
| name | TEXT NOT NULL | Encrypted with `enc1:` for new rows |
| content | TEXT NOT NULL | Encrypted with `enc1:` for new rows |
| created_at, updated_at | TIMESTAMPTZ DEFAULT NOW() | |
### `audio_backups`
Retry store for failed-transcription audio.
Optional 24-hour encrypted recovery store for recordings when transcription
fails, so users can retry without re-recording.
| Column | Type | Notes |
|---|---|---|

View file

@ -278,7 +278,7 @@ Important keys:
Draft encounters (7-day auto-expiry). Columns: `label`, `enc_type`, `transcript`, `generated_note`, `partial_data` (JSON), `status`, `expires_at`.
#### `user_memories`
User templates fed into AI generation. `category` is one of: `physical_exam`, `ros`, `encounter_format`, `family_history`, `assessment_plan`, `custom`.
User templates and preferences. `/api/memories/context` injects only AI-context categories: `physical_exam`, `ros`, `encounter_format`, `family_history`, `assessment_plan`, `template_soap`, `template_hpi`, `template_wellvisit`, `template_sickvisit`, `template_ed`. `custom` rows are user-visible storage but are not prompt context. Legacy `correction_*` rows may exist but are filtered out.
### Learning Hub Tables

View file

@ -243,24 +243,19 @@ docker exec -w /app pediatric-ai-scribe npm run migrate:new -- add_my_table
3. Admin-editable automatically through `PUT /api/admin/config` which accepts
arbitrary keys.
## Physician memory / correction tracker
## Physician Templates And Preferences
1. On note generation, `trackAIOutput(elementId, text)` captures the original
output in memory.
2. User edits the note in a contenteditable field.
3. On Save, `saveCorrection(elementId, section)` diffs current vs. original.
4. If changed by > 2 words or > 20 characters, `POST /api/memories/correction`
stores the before/after in `user_memories` with category
`correction_{section}`.
5. Next generation: `GET /api/memories/context` fetches the 10 most recent per
category and `src/utils/prompts.js` injects them as
`[STYLE HINTS (low priority)]` 200-character snippets.
Tabs with correction capture: Live Encounter, SOAP, Dictation, Sick Visit,
Well Visit (Hospital Course and Chart Review save corrections when available
but don't always have a trackable single output element).
Maximum 20 corrections retained per category (oldest deleted).
1. Settings saves user templates/preferences through `/api/memories` into
`user_memories`.
2. New rows encrypt `name` and `content` with the shared `enc1:` string format.
3. `GET /api/memories/context` decrypts rows and returns only AI-context
categories: `physical_exam`, `ros`, `encounter_format`, `family_history`,
`assessment_plan`, `template_soap`, `template_hpi`, `template_wellvisit`,
`template_sickvisit`, and `template_ed`.
4. `custom` rows remain visible in settings but are not included in prompt
context.
5. Legacy `correction_*` rows from the removed correction-learning feature are
filtered out rather than deleted.
## Route reference

View file

@ -916,16 +916,15 @@ signatures are simple and the provider branches are well-isolated.
A worked example of how the layers compose. Tab: Sick Visit.
1. **Frontend collects inputs.** `sickVisit.js` reads:
- The transcript area (which holds either browser-whisper output or
the result of `transcribeAudio` after recording stop).
- The transcript area, populated by the configured transcription API or
the explicit opt-in browser speech-recognition fallback.
- The structured ROS / PE radio buttons (NORMAL / ABNORMAL / NOT
REVIEWED + free-text per-system notes).
- Patient age and chief complaint.
- The selected model (`getSelectedModel()` — tab-level dropdown wins
over global).
2. **Optional memory injection.** If user memories are enabled,
`getUserMemoryContext()` pulls saved style hints (with the
`[STYLE HINTS (low priority)]` framing — see `docs/ai-providers.md`).
2. **Optional template injection.** `getUserMemoryContext()` pulls saved
AI-context templates and preferences from `/api/memories/context`.
3. **POST to /api/sick-visit.** The route:
- Wraps every user-derived chunk in `<UNTRUSTED_*>` blocks via
`wrapUserText`.

View file

@ -744,7 +744,7 @@ From `server.js:229303`:
| `routes/refine.js` | `/api` | Take a draft note + correction prompt, return refined note |
| `routes/logs.js` | `/api` | Client-side error log ingest (`/api/logs/client-error`) |
| `routes/encounters.js` | `/api` | **Sacred.** Save / load / list / delete `saved_encounters`. Optimistic lock + idempotency. See section 13 |
| `routes/memories.js` | `/api` | CRUD on `user_memories` (style hints, templates) |
| `routes/memories.js` | `/api` | CRUD on `user_memories` (templates and prompt preferences) |
| `routes/notes.js` | `/api` | CRUD on `personal_notes` + voice-to-AI-note + trash/restore |
| `routes/documents.js` | `/api` | S3 doc upload / list / download / delete (metadata in `user_documents`) |
| `routes/audioBackups.js` | `/api` | Server-side audio retry store (encrypted gzip, 24h TTL) |
@ -979,9 +979,10 @@ Nextcloud or are exported.
Created via migration `1777003849000_add-personal-notes.js`, soft-delete
added via `1777090000000_notes-trash.js`.
**Distinct from `user_memories`.** Memories are AI prompt fuel
(templates / style hints) — they get injected into LLM calls. Notes
are pure clinician text that never goes to an AI. Both are encrypted.
**Distinct from `user_memories`.** Memories store user templates and
preferences. Only the AI-context categories are injected into LLM calls;
`custom` rows are stored but excluded from prompt context. Notes are pure
clinician text that never goes to an AI. Both are encrypted.
### `user_memories` — AI prompt fuel
@ -989,7 +990,7 @@ are pure clinician text that never goes to an AI. Both are encrypted.
| ------ | ---- | ----- |
| `id` | SERIAL PK | |
| `user_id` | INTEGER FK (CASCADE) | |
| `category` | TEXT NOT NULL DEFAULT 'custom' | `physical_exam`, `ros`, `encounter_format`, `family_history`, `assessment_plan`, `custom`, `template_soap`, `template_hpi`, `template_wellvisit`, `template_sickvisit`, `template_ed`, legacy `correction_*` (filtered out) |
| `category` | TEXT NOT NULL DEFAULT 'custom' | `physical_exam`, `ros`, `encounter_format`, `family_history`, `assessment_plan`, `custom`, `template_soap`, `template_hpi`, `template_wellvisit`, `template_sickvisit`, `template_ed`. Legacy `correction_*` rows may exist but are filtered out. |
| `name` | TEXT NOT NULL | **Encrypted** |
| `content` | TEXT NOT NULL | **Encrypted** |
| `created_at`, `updated_at` | TIMESTAMPTZ | |
@ -1030,7 +1031,7 @@ guardrail.
**Retention.** None — explicit. These tables grow forever. Disk
should be sized accordingly. A future migration is on the roadmap.
### `audio_backups`failed-transcription retry store
### `audio_backups`24-hour transcription recovery store
| Column | Type | Notes |
| ------ | ---- | ----- |
@ -1043,9 +1044,9 @@ should be sized accordingly. A future migration is on the roadmap.
| `created_at`, `expires_at` | TIMESTAMPTZ | 24h default |
**Who writes.** `routes/audioBackups.js` from the frontend
`audioBackup.js` lifecycle when a transcription call fails — the
client uploads the gzipped audio so the user can retry without
re-recording.
`audioBackup.js` lifecycle when a transcription call fails. The client
uploads encrypted gzipped audio so the user can retry without re-recording;
expired rows are deleted by the database cleanup job.
**Retention.** 24 hours via hourly cleanup. Audio is the most sensitive
PHI in the system; short retention is intentional.

View file

@ -1404,8 +1404,8 @@ reference shape.
router.post('/<your-endpoint>', authMiddleware, async function(req, res) {
try {
var { ..., physicianMemories, model } = req.body;
// Validate inputs, build context with wrapUserText() per field.
// Append style hints if physicianMemories.
// Validate inputs, build context with wrapUserText() per field.
// Append template preferences if physicianMemories.
var result = await callAI([
{ role: 'system', content: PROMPTS.<yourPromptKey> + INJECTION_GUARD },
{ role: 'user', content: context }