diff --git a/docker-compose.yml b/docker-compose.yml index 0b7e515c..f91a95f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,8 @@ services: LITELLM_TTS_VOICE: sherpa/kokoro:am_adam LITELLM_TTS_VOICES: sherpa/kokoro:am_adam,sherpa/kokoro:am_michael,sherpa/kokoro:af_bella,sherpa/kokoro:af_nicole,sherpa/kokoro:bf_emma,sherpa/kokoro:bm_lewis CLINICAL_ASSISTANT_PROMPT_POOL_TARGET: 1000 + LIBRETRANSLATE_URL: ${LIBRETRANSLATE_URL:-http://libretranslate:5000} + DEEPL_API_BASE: ${DEEPL_API_BASE:-https://api.deepl.com/v2} GENERATED_IMAGES_S3_ENDPOINT: http://assets:9000 GENERATED_IMAGES_S3_REGION: us-east-1 GENERATED_IMAGES_S3_BUCKET: generated-images @@ -42,6 +44,7 @@ services: - danvics_monitoring - danvics_speech - ped-ai-storage-assets + - openwebui_openwebui healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"] interval: 30s @@ -103,3 +106,6 @@ networks: ped-ai-storage-assets: external: true name: ped-ai-storage_assets + openwebui_openwebui: + external: true + name: openwebui_openwebui-network diff --git a/docs/CLINICAL_ASSISTANT.md b/docs/CLINICAL_ASSISTANT.md index 9b09f9f1..3a4a24c6 100644 --- a/docs/CLINICAL_ASSISTANT.md +++ b/docs/CLINICAL_ASSISTANT.md @@ -74,14 +74,23 @@ Clinical answer response caching is intentionally disabled. Redis can support pr ## Image Attachments -Users can attach up to 4 images (PNG, JPEG, WebP) to an outgoing clinical question. Attachments are **input-only**: +Users can attach up to 4 images (PNG, JPEG, WebP) to an outgoing clinical question. Attachments **ride the outgoing question only for inference** and **persist with the saved chat** once the question is sent: - They are validated client-side and authoritatively on the server (MIME allowlist, canonical base64, ≤ 5 MiB per image, ≤ 4 images, ≤ 10 MiB decoded total). Invalid input is rejected with 400 before any retrieval or provider call. -- They are sent **only** with the outgoing clinical question, never with handoff summaries, image generation, saved chats, downloads or transcripts. +- They are sent **only** with the outgoing clinical question for inference. Attaching images never disables retrieval: RAG/includeContext runs exactly as without images. - The conversation budget counts text only: images are excluded from the UTF-16 code-unit count. The server still validates every request. +- Once sent, the message's attachments are stored in the saved chat payload (same bounded limits, re-validated on every save) and restored as thumbnails on load. - Only OpenAI-compatible providers (LiteLLM, OpenRouter, Azure) receive them as multimodal content parts (`text` + `image_url` data URIs) on the latest user message; the system/retrieval/history structure is unchanged. Legacy direct adapters (Bedrock/Vertex) refuse with a clear 400 before contacting the provider. - Attachments clear on a successful send and on New chat; a rejected send keeps them for correction. +## Autosave, titles and saved-chat updates + +After each completed assistant turn (and on any change to the conversation), the chat is autosaved with an 800 ms debounce to `POST /api/clinical-assistant/chats`. New chats get a title derived from the first user message (first 60 characters); later saves include the chat `id` and update the same row in place. Failures surface once per change and never block chat flow; oversized saves keep the 8 MiB / 400 / 413 semantics and are retried only on the next change, never truncated. The raw transcript stays canonical. The generated sidebar image and per-message image jobs persist with the chat again. + +## Translation + +Every message offers Translate with a target-language picker and a provider choice. The default provider is the local LibreTranslate container (`LIBRETRANSLATE_URL`, default `http://libretranslate:5000`); DeepL is an admin-configured alternative (`DEEPL_API_KEY` + `DEEPL_API_BASE`, default `https://api.deepl.com/v2`, `api-free.deepl.com` also allowed). The admin default lives in `clinical_assistant.translate_provider` (libretranslate|deepl). Responses are cached per provider+message+lang; transient provider failures fall back to the other configured provider once; validation failures never fall back. No patient data leaves the local network unless the admin explicitly configures DeepL. + ## Settings Important settings include: @@ -93,6 +102,7 @@ Important settings include: | `clinical_assistant.search_limit` | Number of MCP results requested | | `clinical_assistant.context_chars` | Context characters requested from MCP | | `clinical_assistant.system_behavior` | Admin-editable assistant behavior guidance | +| `clinical_assistant.translate_provider` | Default translation provider: `libretranslate` or `deepl` | ## Testing Priorities @@ -101,8 +111,10 @@ Add or update tests when changing: - citation rendering, - source title cleanup, - named-source provenance behavior, -- table rendering, +- table rendering and table copy/CSV actions, - image intent routing, -- image attachment validation and multimodal payload shape, +- image attachment validation, multimodal payload shape and saved-chat roundtrips, +- autosave debounce, title derivation and saved-chat updates, +- translation validation, caching and provider fallback, - MCP result normalization, - model discovery or settings behavior. diff --git a/public/components/admin.html b/public/components/admin.html index df7600d1..fdb227f6 100644 --- a/public/components/admin.html +++ b/public/components/admin.html @@ -313,6 +313,13 @@ +
Loading server budget metadata...
diff --git a/public/components/assistant.html b/public/components/assistant.html index c20dbc52..7a2742f1 100644 --- a/public/components/assistant.html +++ b/public/components/assistant.html @@ -1,5 +1,6 @@ -