docs align memory and audio backup behavior
This commit is contained in:
parent
4a020fb7b0
commit
19c9e8ba1e
8 changed files with 46 additions and 67 deletions
|
|
@ -124,9 +124,11 @@ Applied to: `soap.js`, `hpi.js`, `refine.js`, `sickVisit.js`, `wellVisit.js`,
|
||||||
|
|
||||||
### Physician memories
|
### Physician memories
|
||||||
|
|
||||||
Saved corrections are injected into prompts as `[STYLE HINTS (low priority)]`
|
Saved templates and prompt preferences are injected into prompts as
|
||||||
with 200-character snippets. The low-priority wording prevents smaller models
|
`[STYLE HINTS (low priority)]` when they belong to AI-context categories. The
|
||||||
from hallucinating content from the correction examples into the current note.
|
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
|
## API call logging
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -844,36 +844,15 @@ Delete a memory.
|
||||||
|
|
||||||
### GET /api/memories/context
|
### 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
|
- **Auth required:** Yes
|
||||||
- **Response:**
|
- **Response:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"context": "string"
|
"success": true,
|
||||||
}
|
"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"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,20 +138,23 @@ Draft/complete encounter workspace. Auto-expires (default 7 d,
|
||||||
|
|
||||||
### `user_memories`
|
### `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 |
|
| Column | Type | Notes |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| id | SERIAL PK | |
|
| id | SERIAL PK | |
|
||||||
| user_id | INTEGER FK users.id ON DELETE CASCADE | |
|
| user_id | INTEGER FK users.id ON DELETE CASCADE | |
|
||||||
| category | TEXT NOT NULL DEFAULT 'custom' | `physical_exam`, `ros`, `encounter_format`, `custom`, `template_*`, `correction_*` |
|
| 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 | |
|
| name | TEXT NOT NULL | Encrypted with `enc1:` for new rows |
|
||||||
| content | TEXT NOT NULL | |
|
| content | TEXT NOT NULL | Encrypted with `enc1:` for new rows |
|
||||||
| created_at, updated_at | TIMESTAMPTZ DEFAULT NOW() | |
|
| created_at, updated_at | TIMESTAMPTZ DEFAULT NOW() | |
|
||||||
|
|
||||||
### `audio_backups`
|
### `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 |
|
| Column | Type | Notes |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|
|
||||||
|
|
@ -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`.
|
Draft encounters (7-day auto-expiry). Columns: `label`, `enc_type`, `transcript`, `generated_note`, `partial_data` (JSON), `status`, `expires_at`.
|
||||||
|
|
||||||
#### `user_memories`
|
#### `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
|
### Learning Hub Tables
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
3. Admin-editable automatically through `PUT /api/admin/config` which accepts
|
||||||
arbitrary keys.
|
arbitrary keys.
|
||||||
|
|
||||||
## Physician memory / correction tracker
|
## Physician Templates And Preferences
|
||||||
|
|
||||||
1. On note generation, `trackAIOutput(elementId, text)` captures the original
|
1. Settings saves user templates/preferences through `/api/memories` into
|
||||||
output in memory.
|
`user_memories`.
|
||||||
2. User edits the note in a contenteditable field.
|
2. New rows encrypt `name` and `content` with the shared `enc1:` string format.
|
||||||
3. On Save, `saveCorrection(elementId, section)` diffs current vs. original.
|
3. `GET /api/memories/context` decrypts rows and returns only AI-context
|
||||||
4. If changed by > 2 words or > 20 characters, `POST /api/memories/correction`
|
categories: `physical_exam`, `ros`, `encounter_format`, `family_history`,
|
||||||
stores the before/after in `user_memories` with category
|
`assessment_plan`, `template_soap`, `template_hpi`, `template_wellvisit`,
|
||||||
`correction_{section}`.
|
`template_sickvisit`, and `template_ed`.
|
||||||
5. Next generation: `GET /api/memories/context` fetches the 10 most recent per
|
4. `custom` rows remain visible in settings but are not included in prompt
|
||||||
category and `src/utils/prompts.js` injects them as
|
context.
|
||||||
`[STYLE HINTS (low priority)]` 200-character snippets.
|
5. Legacy `correction_*` rows from the removed correction-learning feature are
|
||||||
|
filtered out rather than deleted.
|
||||||
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).
|
|
||||||
|
|
||||||
## Route reference
|
## Route reference
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
A worked example of how the layers compose. Tab: Sick Visit.
|
||||||
|
|
||||||
1. **Frontend collects inputs.** `sickVisit.js` reads:
|
1. **Frontend collects inputs.** `sickVisit.js` reads:
|
||||||
- The transcript area (which holds either browser-whisper output or
|
- The transcript area, populated by the configured transcription API or
|
||||||
the result of `transcribeAudio` after recording stop).
|
the explicit opt-in browser speech-recognition fallback.
|
||||||
- The structured ROS / PE radio buttons (NORMAL / ABNORMAL / NOT
|
- The structured ROS / PE radio buttons (NORMAL / ABNORMAL / NOT
|
||||||
REVIEWED + free-text per-system notes).
|
REVIEWED + free-text per-system notes).
|
||||||
- Patient age and chief complaint.
|
- Patient age and chief complaint.
|
||||||
- The selected model (`getSelectedModel()` — tab-level dropdown wins
|
- The selected model (`getSelectedModel()` — tab-level dropdown wins
|
||||||
over global).
|
over global).
|
||||||
2. **Optional memory injection.** If user memories are enabled,
|
2. **Optional template injection.** `getUserMemoryContext()` pulls saved
|
||||||
`getUserMemoryContext()` pulls saved style hints (with the
|
AI-context templates and preferences from `/api/memories/context`.
|
||||||
`[STYLE HINTS (low priority)]` framing — see `docs/ai-providers.md`).
|
|
||||||
3. **POST to /api/sick-visit.** The route:
|
3. **POST to /api/sick-visit.** The route:
|
||||||
- Wraps every user-derived chunk in `<UNTRUSTED_*>` blocks via
|
- Wraps every user-derived chunk in `<UNTRUSTED_*>` blocks via
|
||||||
`wrapUserText`.
|
`wrapUserText`.
|
||||||
|
|
|
||||||
|
|
@ -744,7 +744,7 @@ From `server.js:229–303`:
|
||||||
| `routes/refine.js` | `/api` | Take a draft note + correction prompt, return refined note |
|
| `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/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/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/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/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) |
|
| `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
|
Created via migration `1777003849000_add-personal-notes.js`, soft-delete
|
||||||
added via `1777090000000_notes-trash.js`.
|
added via `1777090000000_notes-trash.js`.
|
||||||
|
|
||||||
**Distinct from `user_memories`.** Memories are AI prompt fuel
|
**Distinct from `user_memories`.** Memories store user templates and
|
||||||
(templates / style hints) — they get injected into LLM calls. Notes
|
preferences. Only the AI-context categories are injected into LLM calls;
|
||||||
are pure clinician text that never goes to an AI. Both are encrypted.
|
`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
|
### `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 | |
|
| `id` | SERIAL PK | |
|
||||||
| `user_id` | INTEGER FK (CASCADE) | |
|
| `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** |
|
| `name` | TEXT NOT NULL | **Encrypted** |
|
||||||
| `content` | TEXT NOT NULL | **Encrypted** |
|
| `content` | TEXT NOT NULL | **Encrypted** |
|
||||||
| `created_at`, `updated_at` | TIMESTAMPTZ | |
|
| `created_at`, `updated_at` | TIMESTAMPTZ | |
|
||||||
|
|
@ -1030,7 +1031,7 @@ guardrail.
|
||||||
**Retention.** None — explicit. These tables grow forever. Disk
|
**Retention.** None — explicit. These tables grow forever. Disk
|
||||||
should be sized accordingly. A future migration is on the roadmap.
|
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 |
|
| 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 |
|
| `created_at`, `expires_at` | TIMESTAMPTZ | 24h default |
|
||||||
|
|
||||||
**Who writes.** `routes/audioBackups.js` from the frontend
|
**Who writes.** `routes/audioBackups.js` from the frontend
|
||||||
`audioBackup.js` lifecycle when a transcription call fails — the
|
`audioBackup.js` lifecycle when a transcription call fails. The client
|
||||||
client uploads the gzipped audio so the user can retry without
|
uploads encrypted gzipped audio so the user can retry without re-recording;
|
||||||
re-recording.
|
expired rows are deleted by the database cleanup job.
|
||||||
|
|
||||||
**Retention.** 24 hours via hourly cleanup. Audio is the most sensitive
|
**Retention.** 24 hours via hourly cleanup. Audio is the most sensitive
|
||||||
PHI in the system; short retention is intentional.
|
PHI in the system; short retention is intentional.
|
||||||
|
|
|
||||||
|
|
@ -1404,8 +1404,8 @@ reference shape.
|
||||||
router.post('/<your-endpoint>', authMiddleware, async function(req, res) {
|
router.post('/<your-endpoint>', authMiddleware, async function(req, res) {
|
||||||
try {
|
try {
|
||||||
var { ..., physicianMemories, model } = req.body;
|
var { ..., physicianMemories, model } = req.body;
|
||||||
// Validate inputs, build context with wrapUserText() per field.
|
// Validate inputs, build context with wrapUserText() per field.
|
||||||
// Append style hints if physicianMemories.
|
// Append template preferences if physicianMemories.
|
||||||
var result = await callAI([
|
var result = await callAI([
|
||||||
{ role: 'system', content: PROMPTS.<yourPromptKey> + INJECTION_GUARD },
|
{ role: 'system', content: PROMPTS.<yourPromptKey> + INJECTION_GUARD },
|
||||||
{ role: 'user', content: context }
|
{ role: 'user', content: context }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue