Spaces:
Runtime error
Runtime error
| # 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`](https://huggingface.co/spaces/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: | |
| ```yaml | |
| --- | |
| title: CarePath | |
| sdk: docker | |
| app_port: 7860 | |
| --- | |
| ``` | |
| 3. 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`. | |
| 4. Set these Space secrets: | |
| ```text | |
| 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: | |
| ```text | |
| 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 | |
| ```powershell | |
| 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): | |
| ```powershell | |
| docker run --rm -p 7860:7860 ` | |
| -e ASR_PROVIDER=mock -e ALLOW_MOCK_ASR=true -e LLM_PROVIDER=offline ` | |
| carepath | |
| ``` | |
| In another terminal: | |
| ```powershell | |
| 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: | |
| ```text | |
| 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. | |
| 3. 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: | |
| ```text | |
| 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. | |