No description
Find a file
Daniel d33d355627 feat: a streaming table renders as a table, and the wait says what it is doing
Measured against Open WebUI on the same question, sampling every 250ms:
it never showed a raw pipe. A real <table> appeared with 2 rows at
t+3.25s and grew to 4, then 6, as they arrived.

The blank-line rule alone cannot do that, and a table is the case it
serves worst: a markdown table contains no blank line, so the whole of
it stayed in the tail as plain text until the line *after* it landed,
then snapped into place. That is the markdown flash, on exactly the
content where it shows most.

So a table is now rendered while it is still arriving: once there is a
header, the |---| rule and one body row, the tail is rendered as
markdown rather than held as text, and every complete row that follows
joins it. A half-typed row is left out and appears a frame later, which
is what makes the table grow a row at a time.

Re-rendered each frame rather than appended, unlike a settled block: the
rows arriving next carry no header of their own, so they cannot be
parsed as a separate chunk. The tail is small, so the cost is small.

The status was the other half of that trace: Open WebUI keeps a skeleton
beside the streaming content until the answer is done. Ours removed the
status the instant the first token landed — the moment it becomes most
useful, because the answer is arriving *and* the assistant is still
working, drawing a figure or completing a cut-off reply. It now sits
above the partial answer, shimmering, until the final render replaces
the bubble.

And the wait itself says what is happening. Retrieval finishes before
the stream opens — deliberately, so a bad request still returns an error
rather than a stream — which makes that first line the only thing a
reader has during the slowest part. "Retrieving and synthesizing
references" described the software; "Searching the clinical library"
describes the work.

Mutation-tested: dropping the table rule, rendering the incomplete
trailing row, showing a table with no body row, or failing to restore
the status each frame all fail a test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-13 01:55:09 +02:00
.forgejo/workflows feat: the API describes itself, at /api/openapi.json 2026-09-13 00:52:55 +02:00
.github ci: fix the failing job, split deploy out, and drop the Android build 2026-09-12 23:30:52 +02:00
android Fix APK crash: replace XML splash with PNG, add real mipmap launcher icons 2026-03-29 11:07:10 +00:00
assets fix: the image settings card can save again; Learning Hub is out of the admin 2026-09-13 01:39:15 +02:00
docs ci: fix the failing job, split deploy out, and drop the Android build 2026-09-12 23:30:52 +02:00
e2e feat: the API describes itself, at /api/openapi.json 2026-09-13 00:52:55 +02:00
migrations test: e2e runs against its own throwaway database, not production's 2026-09-13 00:49:25 +02:00
monitoring Add Loki + Grafana monitoring stack, ntfy notifications, biometric auth 2026-04-11 03:00:52 +02:00
public feat: a streaming table renders as a table, and the wait says what it is doing 2026-09-13 01:55:09 +02:00
scripts fix: the image settings card can save again; Learning Hub is out of the admin 2026-09-13 01:39:15 +02:00
src fix: the image settings card can save again; Learning Hub is out of the admin 2026-09-13 01:39:15 +02:00
test feat: a streaming table renders as a table, and the wait says what it is doing 2026-09-13 01:55:09 +02:00
.dockerignore feat: ship reviewed prompt history, conversation limits and account protections 2026-09-07 04:01:01 +02:00
.env.example feat: sign in with a code emailed to you, offered beside the password 2026-09-11 20:12:03 +02:00
.gitignore chore: checkpoint before AAD binding and incremental streaming render 2026-09-12 21:17:35 +02:00
.gitmessage docs: add CONTRIBUTING.md + .gitmessage template for conventional commits 2026-04-14 23:51:09 +02:00
.node-pg-migraterc.json Add node-pg-migrate for versioned schema changes + better mobile UA labels 2026-04-14 05:06:19 +02:00
admin-cli.js v3.0.0: Auth, admin panel, security fixes, per-tab model selector 2026-03-21 19:25:51 -04:00
CONTRIBUTING.md ci: fix the failing job, split deploy out, and drop the Android build 2026-09-12 23:30:52 +02:00
docker-compose.e2e.yml test: e2e runs against its own throwaway database, not production's 2026-09-13 00:49:25 +02:00
docker-compose.local.yml feat: ship reviewed prompt history, conversation limits and account protections 2026-09-07 04:01:01 +02:00
docker-compose.monitoring.yml Update bilirubin to exact AAP 2022 values, add exchange transfusion 2026-04-11 05:50:19 +02:00
docker-compose.yml feat: My Resources — anyone can generate teaching material, privately 2026-09-11 14:50:54 +02:00
docker-entrypoint.sh test: e2e runs against its own throwaway database, not production's 2026-09-13 00:49:25 +02:00
Dockerfile feat: Word is built by python-docx from the same typed source as the deck 2026-09-11 21:58:53 +02:00
grafana-dashboard.json feat: neonatal calculator, DOCX/PPTX/ODT/EPUB support, gateway-agnostic URL helper, TTS/STT fixes 2026-04-19 02:17:06 +02:00
package-lock.json fix: slides shrink to fit, and an article is never offered as slides 2026-09-11 15:34:16 +02:00
package.json fix: slides shrink to fit, and an article is never offered as slides 2026-09-11 15:34:16 +02:00
README.md ci: fix the failing job, split deploy out, and drop the Android build 2026-09-12 23:30:52 +02:00
server.js feat: the API describes itself, at /api/openapi.json 2026-09-13 00:52:55 +02:00
TODO.md ci: fix the failing job, split deploy out, and drop the Android build 2026-09-12 23:30:52 +02:00

Ped-AI

Ped-AI is a pediatric clinical documentation, education, and bedside decision-support app. This fork has moved well beyond the original scribe app: it now combines encounter documentation, clinical workflows, private teaching material, admin controls, MCP-backed clinical assistant integration, Redis-backed operational state, and hardened deployment defaults.

The app runs as an authenticated Express/Postgres service with a browser frontend and optional integrations for LiteLLM, AWS, OpenAI-compatible APIs, Nextcloud WebDAV, S3-compatible storage, OpenBao, Redis, OIDC, TOTP, and Cloudflare Turnstile.

Current Scope

Clinical Documentation

  • Live encounter capture with structured pediatric HPI generation.
  • Dictation cleanup for narrative notes.
  • SOAP, sick visit, well visit, hospital course, chart review, precharting, and ED encounter workflows.
  • Parent-facing education handouts generated from clinician notes, with diagnosis, medication, emergency-care guidance, and preferred-language support.
  • Pediatric developmental milestone tooling.
  • Templates, physician memory, and per-tab model overrides.
  • Server-side speech-to-text routing through configured providers.

Bedside Tools

  • Pediatric calculators and emergency dosing helpers.
  • PE guide and clinical reference content.
  • Vaccines, catch-up schedules, growth/vitals, bilirubin, BSA, GCS, equipment, and resuscitation helpers.
  • Mobile-friendly PWA layout for bedside use.
  • Per-user phone extension and pager directory with soft-delete, search, ZIP export, and JSON/ZIP import for handoff between users.

My Resources

  • Private teaching material any signed-in user can generate for themselves — nobody else sees it.
  • Presentations are designed as slide decks (comparisons, tables, callouts, figures beside text), not written as markdown for a parser to guess at.
  • Grounded in the indexed clinical library, and optionally PubMed and the web, each admin-enabled.
  • Optional illustrations, several per resource, placed through the deck.
  • Revise in place, and download as PowerPoint, Word or PDF. See docs/my-resources.md.

Clinical Assistant

  • Optional MCP-backed clinical assistant integration.
  • Prompt suggestions backed by Redis operational cache.
  • No clinical answer response caching.
  • Designed to retrieve from indexed clinical material while keeping provider selection explicit.

Admin And Security

  • Sign in with a password or a six-digit code emailed to you — offered side by side, because a code depends on mail arriving and a password does not.
  • Role-based access, TOTP 2FA, OIDC/SSO, email verification, and optional Turnstile. Passwords are argon2id, with bcrypt rows rehashed on their next sign-in.
  • Registration can be open, closed, or invite-only with generated codes. A code can be revoked while live, and deleted only once it is spent.
  • Admin panel for users, settings, prompts, models, and logs.
  • Audit, API, access, and client-error logs with redaction hardening.
  • OpenBao secret loading support at container startup.
  • S3-compatible document storage support.

Removed Browser STT

Browser Whisper has been removed from the runtime. The app should not ship browser Whisper workers, browser-local Whisper model downloads, Transformers.js browser STT, or Browser Whisper setup docs.

Speech-to-text is handled server-side through configured providers such as Google/Gemini, AWS Transcribe, LiteLLM, or OpenAI Whisper. Browser-native Web Speech remains gated behind an explicit user setting when present in the browser — it is off unless a user turns it on, because Chrome and Edge send that audio to Google.

Quick Start

cp .env.example .env
./scripts/build-image.sh
docker compose up -d --no-build

The default compose exposes the app on 127.0.0.1:3552 and starts:

  • pediatric-ai-scribe for the Node app.
  • pedscribe-db for Postgres with pgvector.
  • ped-ai-redis for operational Redis state.

Health check:

curl -fsS http://127.0.0.1:3552/api/health

Prometheus metrics are exposed at GET /metrics with the ped_ai_ metric prefix.

The first registered user becomes an admin unless registration has already been configured differently.

Core Environment

Set real values in .env before production use.

APP_URL=https://your-domain.example
JWT_SECRET=<64-char-random-secret>
DB_PASSWORD=<strong-database-password>

AI_PROVIDER=litellm
LITELLM_API_BASE=https://your-litellm.example/v1
LITELLM_API_KEY=<key>

TRANSCRIBE_PROVIDER=litellm
LITELLM_STT_MODEL=whisper-1

REDIS_URL=redis://ped-ai-redis:6379

Supported text AI providers are LiteLLM, OpenRouter, AWS Bedrock, and Azure OpenAI. Speech-to-text and text-to-speech both route through LiteLLM, so the upstream speech vendor is a gateway configuration choice rather than an app one; browser-native Web Speech stays off unless a user opts in.

Admin CLI

docker exec pediatric-ai-scribe node admin-cli.js list-users
docker exec pediatric-ai-scribe node admin-cli.js create-admin admin@example.com password123 "Dr. Admin"
docker exec pediatric-ai-scribe node admin-cli.js make-admin user@example.com
docker exec pediatric-ai-scribe node admin-cli.js reset-password user@example.com newpassword
docker exec pediatric-ai-scribe node admin-cli.js toggle-registration
docker exec pediatric-ai-scribe node admin-cli.js stats

Maintenance

The app checks Postgres collation drift on startup and can reindex text indexes after image or OS-library changes.

docker exec pediatric-ai-scribe npm run maint:check
docker exec pediatric-ai-scribe npm run maint:reindex

Run the reindex command after major Postgres image changes, restoring a dump from another distro, or seeing lookup behavior that suggests collation/index drift.

Testing

Run the Node test suite:

npm test

Run syntax checks for touched files when doing focused backend work:

node --check server.js
node --check src/routes/transcribe.js

Run the Playwright smoke suite against the e2e compose stack:

docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d pediatric-scribe-e2e
npm run e2e

Deployment Notes

  • Put the app behind HTTPS before clinical use.
  • Use only AI/STT/TTS providers covered by your BAA and data-processing requirements.
  • Configure OIDC/SSO and 2FA for production users.
  • Keep JWT_SECRET, database credentials, provider keys, S3 keys, SMTP credentials, and OpenBao tokens out of git.
  • Treat logs as sensitive operational data even with redaction enabled.
  • Use the Caddy/reverse-proxy layer to expose only intended public routes.

Documentation

Primary references:

  • docs/architecture.md — system map, repository layout, request pipeline, and service boundaries.
  • docs/developer-guide.md — day-to-day code-change workflow, route and module reference.
  • docs/module-conventions.md — CommonJS, ESM, globals, and rendering rules.
  • docs/features-explained.md — what each feature is, in plain terms.
  • docs/api-reference.md — API routes.
  • docs/configuration.md — environment variables and live app_settings.
  • docs/database.md — every table, its columns, and what is encrypted.
  • docs/migrations.md — how schema changes are made and applied.
  • docs/authentication.md — auth, OIDC, sign-in codes, invites, rate limits.
  • docs/ai-providers.md — provider selection, prompts, injection hardening.
  • docs/clinical-assistant.md — MCP-backed assistant behavior and safety rules.
  • docs/retrieval-tuning.md — how much corpus each feature retrieves, and what it costs.
  • docs/global-prompt-administration.md — prompt overrides and the conversation budget.
  • docs/speech.md — STT, TTS, recording, and audio backups.
  • docs/my-resources.md — private teaching material, the slide renderer, and search sources.
  • docs/deployment.md — production deployment.
  • docs/scaling.md — scaling priorities and readiness work.
  • docs/openid-setup.md — OIDC provider setup.
  • docs/ops-docs-ped-ai-and-milvus.md — operational notes for the retrieval stack.
  • docs/improvements.md — the running list of what to improve next.
  • docs/logic/README.md — the deeper code walkthrough.

Some deep docs/logic/ files still describe historical implementation details. Prefer runtime code and tests when documentation conflicts with current behavior.

Clinical Safety

Ped-AI is documentation and education support software. It does not replace clinical judgment, local policy, medication verification, or attending review. Validate generated notes, calculations, and recommendations before use in patient care.