Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 49s
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Android APK / Build signed APK (push) Successful in 2m2s
Forgejo Docker Build / Build Docker image (push) Successful in 9s
Forgejo Docker Build / Deploy to the host (push) Failing after 2s
Learning is moderator-owned: content published into categories that everyone sees, behind router.use(moderatorMiddleware). That is right for institutional material and wrong as the only way in — an ordinary user could not generate anything at all. So this is a separate pathway rather than a loosening of that one. Learning is untouched; the moderator gate stays exactly where it was. A signed-in user can generate a deck or an article for their own use, keep it, refine it and export it, and nobody else ever sees it. Private by construction. Every statement filters on the owner and there is no route that returns another person's work, which a test asserts statement by statement rather than trusting. The foreign key cascades, so deleting an account takes its drafts with it. There is no category, no publish state and no sharing: adding sharing later should be a deliberate feature, not something that leaks out of a forgotten WHERE clause. Markdown is the artifact. Every format is rendered from it on demand — pptx and docx by pandoc, both carrying the house reference deck, and PDF by Gotenberg, whose LibreOffice preserves a deck's layout in a way rendering from markdown would not. That is what makes "add a slide on when to admit" a text edit rather than a binary patch. Gotenberg was published on the host but on a network of its own, so reaching it from a container went out and back through the host gateway. It now joins danvics_convert, owned by danvics-net like the others. PDF is the one export allowed to fail: if that service is down, the deck and the document still download and the error says which. Verified end to end as a plain user: the moderator route still refuses with 403, generation returned a deck grounded on 12 corpus excerpts, the library lists only their own, pptx/docx/pdf all downloaded valid, "add a slide on when to admit" put the slide in the right place and left References last, and an unauthenticated request gets 401 while someone else's id gets 404. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
135 lines
5.4 KiB
YAML
135 lines
5.4 KiB
YAML
services:
|
|
pediatric-scribe:
|
|
build:
|
|
context: .
|
|
args:
|
|
GIT_REVISION: ${GIT_REVISION:-unknown}
|
|
# A deploy sets PED_AI_IMAGE to an immutable, revision-tagged image from the
|
|
# registry; a local build leaves it unset and uses the tag build-image.sh
|
|
# writes. Either way the running container can be asked what it is:
|
|
# /api/build returns the revision baked into it at build time.
|
|
image: ${PED_AI_IMAGE:-ped-ai-local:latest}
|
|
ports:
|
|
- "127.0.0.1:3552:3000"
|
|
env_file:
|
|
- .env
|
|
environment:
|
|
# clinical-mcp, not mcp: this host runs several MCP servers and the bare
|
|
# name said nothing about which. Same container, added alias.
|
|
CLINICAL_ASSISTANT_MCP_URL: http://clinical-mcp:8000/mcp
|
|
REDIS_URL: redis://ped-ai-redis:6379
|
|
LOKI_URL: http://monitoring-loki:3100
|
|
# LITELLM_API_BASE is intentionally not set here: OpenBao supplies
|
|
# https://llm.danvics.com and Compose env would override it. The public
|
|
# hostname is the deliberate choice for consistency across the estate.
|
|
# The cost is not speed (~19ms on calls taking hundreds) — it is that
|
|
# AI calls now depend on Caddy, public DNS and edge TLS being up.
|
|
# To pin ped-ai to the container network instead, set it here.
|
|
TTS_PROVIDER: litellm
|
|
LITELLM_TTS_MODEL: local-kokoro-tts
|
|
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
|
|
GENERATED_IMAGES_S3_ACCESS_KEY_FILE: /run/secrets/generated-images-access-key
|
|
GENERATED_IMAGES_S3_SECRET_KEY_FILE: /run/secrets/generated-images-secret-key
|
|
# Recordings are kept for 24 hours; the same MinIO, its own bucket. The
|
|
# app key carries a second policy covering only audio-backups, so these
|
|
# can reuse the mounted credentials (see scripts/enable-audio-backup-bucket.js).
|
|
AUDIO_BACKUPS_S3_ENDPOINT: http://assets:9000
|
|
AUDIO_BACKUPS_S3_REGION: us-east-1
|
|
AUDIO_BACKUPS_S3_BUCKET: audio-backups
|
|
AUDIO_BACKUPS_S3_ACCESS_KEY_FILE: /run/secrets/generated-images-access-key
|
|
AUDIO_BACKUPS_S3_SECRET_KEY_FILE: /run/secrets/generated-images-secret-key
|
|
volumes:
|
|
- scribe-logs:/app/data/logs
|
|
- clinical-assistant-mcp-data:/app/mcp-data:ro
|
|
- /home/danvics/docker/personal-assistant-storage-milvus/secrets/images-access-key:/run/secrets/generated-images-access-key:ro
|
|
- /home/danvics/docker/personal-assistant-storage-milvus/secrets/images-secret-key:/run/secrets/generated-images-secret-key:ro
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
container_name: pediatric-ai-scribe
|
|
networks:
|
|
- default
|
|
- danvics_mcp
|
|
- danvics_monitoring
|
|
- ped-ai-storage-assets
|
|
- danvics_translate
|
|
- danvics_convert
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 20s
|
|
|
|
postgres:
|
|
# Digest-pinned, so a rebuilt environment gets this exact Postgres. If a
|
|
# newer pg16 image ships a different ICU library, the startup drift check in
|
|
# src/db/database.js auto-REINDEXes and refreshes the collation version;
|
|
# pinning means that only happens when this line is deliberately changed.
|
|
image: pgvector/pgvector:pg16@sha256:00ba258a66dac104fd5171074a0084462a64a1369d8513f3d0a634e2f24d15bc
|
|
environment:
|
|
POSTGRES_DB: pedscribe
|
|
POSTGRES_USER: pedscribe
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-pedscribe}
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
restart: unless-stopped
|
|
container_name: pedscribe-db
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U pedscribe"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
redis:
|
|
image: redis:8-alpine@sha256:d146f83b1e0f02fc27c26a50cee39338c736674c5959db84363e6ae3cd9e02d2
|
|
command: redis-server --appendonly yes
|
|
restart: unless-stopped
|
|
container_name: ped-ai-redis
|
|
volumes:
|
|
- redis-data:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- default
|
|
- danvics_mcp
|
|
|
|
volumes:
|
|
pgdata:
|
|
scribe-logs:
|
|
redis-data:
|
|
clinical-assistant-mcp-data:
|
|
external: true
|
|
name: clinical-assist-data
|
|
|
|
networks:
|
|
danvics_mcp:
|
|
external: true
|
|
danvics_monitoring:
|
|
external: true
|
|
ped-ai-storage-assets:
|
|
external: true
|
|
name: personal-assistant-storage-milvus_assets
|
|
# LibreTranslate's own service network, owned by the libretranslate project.
|
|
# ped-ai used to join open-webui's stack network purely to resolve this one
|
|
# hostname, which coupled a clinical app to an unrelated stack's lifecycle.
|
|
danvics_translate:
|
|
external: true
|
|
# Gotenberg, for turning a generated deck or document into PDF. A convenience
|
|
# export: if this is unreachable the pptx and docx still download.
|
|
danvics_convert:
|
|
external: true
|