carepath-api / docs /deploy.md
tranth3truong's picture
Deploy CP-UX-17: public demo hub, same-origin API, one design world
aacc29a
|
Raw
History Blame Contribute Delete
8.41 kB

CarePath Unified Deploy

Use https://carepath-medicaltranslation.vercel.app as the public Scribe site. One Hugging Face Space runs the Scribe tool at /ghi-chep-lam-sang/, the Scribe API at /api/v1/*, and the retained Interpreter API at /api/* + /ws/*. /phien-dich-y-khoa/* and /console/* are intentionally public 404s while the Interpreter remains in development.

Hugging Face Space

Reuse the existing Docker Space tranth3truong/carepath-api, served at https://tranth3truong-carepath-api.hf.space. Deploy this unified repository there; it retains the Interpreter API but does not serve the unfinished Interpreter browser workflow.

  1. Rebuild the existing tranth3truong/carepath-api Space with Docker as the SDK. Create a replacement only if that Space is no longer available.
  2. Copy README.hf-space.md to the Space as README.md so the Space has:
---
title: CarePath
sdk: docker
app_port: 7860
---
  1. Push this repo to the Space. The root Dockerfile builds scribe/frontend/ in a node stage (that build enforces the Vietnamese diacritics gate), installs both API packages, pre-downloads the Gipformer int8 ONNX files, and starts Uvicorn on port 7860.
  2. Set these Space secrets:
LLM_PROVIDER=ckey
LLM_API_KEY=<your CKey key>
LLM_MODEL=gpt-5.4
TEAM_CODE=<shared internal demo code>
SOAP_RATE_LIMIT_PER_IP_HOUR=3
SOAP_RATE_LIMIT_PER_IP_DAY=10
SOAP_RATE_LIMIT_GLOBAL_DAY=100
APP_ENV=prod
CORS_ORIGINS=https://carepath-medicaltranslation.vercel.app

The interpreter defaults to mock mode, which returns [vi->en] … echoes. For /kham-song-ngu/ to actually translate on the deployed Space, add one more secret:

PROVIDER_MODE=ckey

It reuses LLM_BASE_URL, LLM_API_KEY and LLM_MODEL above — one CKey account configures both modules. Measured latency across 50 turns: median 15s, p90 54s, max 206s, so a live visitor waits. PROVIDER_MODE=demo is the offline scripted scenario for the pitch laptop, not for a public URL, because anything off-script falls back to a visible placeholder.

The public demo hub at /thu-nghiem/ is built for both cases and reads GET /api/health to decide what it may honestly offer:

provider_mode What the hub shows
ckey Everything: the scripted sample, own-document upload, and the two-way conversation.
demo The scripted sample only. Own-upload and the conversation panel are hidden, because in this mode read_document ignores the uploaded bytes and the canned map covers nothing a visitor would actually type. This is what makes demo safe on a public URL.
mock or unreachable Nothing runnable, and a notice saying so. It never invents output.

The sample path sends X-CarePath-Sample: 1, which forces scripted mode for that one request, so samples stay instant and free even on ckey. Own-uploads and conversation turns on ckey bill real tokens, capped at five runs per IP per day by the /api/demo/* functions.

The cloud mode (Anthropic/OpenAI direct) additionally needs ANTHROPIC_API_KEY, OPENAI_API_KEY, and a non-default ADMIN_TOKEN (startup refuses change-me in cloud mode).

The Vercel site uploads Scribe audio directly to the Space, so its exact origin must be present in CORS_ORIGINS. Add local Vite origins as comma-separated values only when testing local frontends against the deployed API.

Requests with header X-Team-Code: <TEAM_CODE> bypass the SOAP rate limits for internal doctor-comparison runs. Limited requests return HTTP 429, Retry-After, and JSON body {"detail":{"message":"...","retry_after_seconds":3600}} — the Scribe tool surfaces that message to the user.

Local Docker Check

docker build -t carepath .
docker run --rm -p 7860:7860 `
  -e LLM_PROVIDER=ckey `
  -e "LLM_API_KEY=$env:LLM_API_KEY" `
  -e LLM_MODEL=gpt-5.4 `
  -e APP_ENV=prod `
  carepath

Keyless variant (mock ASR + offline LLM + mock interpreter — must also work):

docker run --rm -p 7860:7860 `
  -e ASR_PROVIDER=mock -e ALLOW_MOCK_ASR=true -e LLM_PROVIDER=offline `
  carepath

In another terminal:

curl.exe http://127.0.0.1:7860/api/v1/health
curl.exe http://127.0.0.1:7860/api/health
curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/
curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/ghi-chep-lam-sang/
curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/phien-dich-y-khoa/
curl.exe -X POST http://127.0.0.1:7860/api/v1/soap-notes `
  -F "audio=@C:\path\to\demo.wav" `
  -F "encounter_context=Phòng khám nội tổng quát"

Canonical Vercel site

The scribe/frontend/ directory is the static marketing deployment at https://carepath-medicaltranslation.vercel.app:

  1. In the Vercel project settings, change Root Directory from the removed apps/web-next to scribe/frontend (framework/build/output come from scribe/frontend/vercel.json).
  2. Set these Vercel environment variables:
VITE_API_BASE=
VITE_WS_BASE=https://tranth3truong-carepath-api.hf.space
DEMO_API_BASE=https://tranth3truong-carepath-api.hf.space
VITE_LEAD_ENDPOINT=<optional lead endpoint>
VITE_LEAD_EMAIL=<pilot contact email>

VITE_API_BASE is empty on purpose (DEC-0021). vercel.json rewrites /api/* to the Space, so the browser calls its own origin and no CORS_ORIGINS entry stands between the site and the backend. Setting it to an absolute origin restores the cross-origin coupling that took both tool routes down when the domain moved to carepath-medicaltranslation.vercel.app while the Space still allowed only carepath-omega.vercel.app.

VITE_WS_BASE is required whenever VITE_API_BASE is empty: a Vercel rewrite will not carry a websocket upgrade to an external host, so /ws/* still goes direct. That is safe — the origin check in scribe/carepath/main.py is HTTP middleware and never runs for a websocket scope.

DEMO_API_BASE is read server-side by the /api/demo/* functions, so the API host no longer appears in the client bundle.

  1. Earlier guidance here said not to add Vercel API rewrites because the Space owns those routes. That is superseded: the /api/* rewrite is what makes the API same-origin. It excludes /api/demo/*, which are Vercel functions.

The Vercel build runs npm run validate:deploy before compiling. It fails when VITE_API_BASE is set but invalid, does not use HTTPS, contains a query/fragment, or is not the bare / pathname; when both VITE_API_BASE and VITE_WS_BASE are empty; or when an SPA route in src/App.tsx has no matching rewrite in vercel.json — without one, a direct visit to that route is a hard 404. Local and combined-service builds still use same-origin fallbacks because the normal npm run build skips this deployment-only check.

The interpreter console was deleted once /kham-song-ngu/ replaced it; its backend stays on the Space for the WebSocket API, and /phien-dich-y-khoa/ and /console/ return an explicit 404. The pilot form remains client-side unless VITE_LEAD_ENDPOINT is configured.

Keep-Alive

The workflow in .github/workflows/keepalive.yml pings the Space every 12 hours. Set the GitHub repository variable:

SPACE_URL=https://tranth3truong-carepath-api.hf.space

Then run Actions > Keep HF Space Awake > Run workflow once and confirm the job succeeds.

Final Smoke

  1. Open the Space URL: the landing renders, Vietnamese by default, and the English resolves under each prescription line within about two seconds.
  2. Open /kham-song-ngu/, consent, start a visit, and type a Vietnamese dose. Confirm the turn is gated and the patient pane shows nothing until you confirm it.
  3. Open /ghi-chep-lam-sang/, upload a short clip, and verify the SOAP draft renders with the review banner.
  4. Confirm /phien-dich-y-khoa/ and /console/ return HTTP 404.
  5. Confirm GET /api/v1/health reports llm_provider: ckey and asr_ready: true, and GET /api/health reports provider_mode: ckey.

Note the deploy commit shape: the Space's README.md carries the sdk: docker frontmatter, so a plain branch push would overwrite it with the repository README and break the Space's build configuration. Deploy by building a commit that copies README.hf-space.md over README.md first.