Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Clinic Triage & Resolution Engine

A runnable version of the clinic customer-service triage system: classify an incoming message, resolve it automatically where the rules allow, or escalate to staff with a short case summary. FastAPI backend, SQLite storage, single-page web UI.

How the decision logic is split

Money, VIP status, and slot availability are never left to an LLM to decide. The system is split into three layers:

  1. Classification (backend/app/classify.py) - picks one of pricing_inquiry, new_booking, vip_cancellation, billing_dispute, urgent_complaint, other. Uses Claude if ANTHROPIC_API_KEY is set (better at reading intent), otherwise falls back to keyword matching. Either way, only a category label comes out of this step.
  2. Business rules (backend/app/rules.py) - the actual decision. Checks the VIP list, refund limit, transaction history, and slot table directly in the database and decides resolved-or-escalated, priority, refund amounts, reference numbers, etc. This part runs identically whether or not an API key is configured, so money and identity decisions are always deterministic and auditable.
  3. Phrasing (backend/app/phrasing.py) - turns the decision into the actual customer-facing text and staff summary. If Claude is available it's asked to word things naturally, but it's given the already-decided facts and told not to invent anything beyond them. Plain-English templates are the fallback (and are what runs by default with no API key), so the app works fully offline.

This means: no API key -> the whole thing still works, just with templated wording instead of Claude's phrasing. Add a key and the classification and wording both get noticeably better, without changing what gets refunded or who gets treated as VIP.

Setup

cd backend
python3 -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env          # optional: add your ANTHROPIC_API_KEY here

Run

cd backend
uvicorn app.main:app --reload --port 8000

Then open http://localhost:8000 for the UI, or http://localhost:8000/docs for the interactive API docs.

Troubleshooting: "disk I/O error" on startup. This happens if SQLite can't get a proper file lock on clinic.db, which can occur when the project folder sits inside a cloud-synced directory (OneDrive, Dropbox, etc.) that intercepts file locks. If you hit this, set DATABASE_URL in .env (or as an environment variable) to a path outside the synced folder, e.g. DATABASE_URL=sqlite:///C:/clinic-data/clinic.db on Windows, and re-run.

On first run the database is empty. Click "Load demo data" in the UI (or POST /api/seed-demo) to seed the scenario this was designed around: 3 slots today, a BHD 50 refund limit, a 4-name VIP list, a 3-item pricing KB, and a duplicate BHD 40 charge on Sara Ahmed's account for testing the billing-dispute flow.

Using it

The New customer message panel on the left is the main entry point: type a message, optionally give a name and customer type, and hit Run triage. You'll get back the classification, priority, whether it was resolved automatically, the exact customer reply, and (if escalated) the staff case summary.

The right column is the editable clinic state: today's slots, refund limit, VIP list, and pricing KB. Edit these and re-run messages to see the decisions change (e.g. drop the refund limit to BHD 30 and re-run the billing dispute test case to see it escalate instead of auto-resolving).

The Staff queue shows every case still needing a human, sorted by priority (urgent complaints first), with a one-click "Mark resolved."

API

Endpoint What it does
POST /api/triage Submit a message, get back the full decision
GET /api/state Current slots, refund limit, VIP list, pricing KB
PUT /api/state/refund-limit Change the refund approval limit
POST /api/vips / DELETE /api/vips/{id} Manage the VIP list
POST /api/pricing / DELETE /api/pricing/{id} Manage pricing KB
POST /api/slots / DELETE /api/slots/{id} Manage today's slots
POST /api/transactions / GET /api/transactions Add/view transaction history
GET /api/cases List cases (?status=open for the staff queue)
POST /api/cases/{id}/resolve Mark a case as handled
POST /api/seed-demo Reset and reload the demo scenario

Test cases baked into the demo seed

These match the five scenarios this system was originally spec'd against:

  1. VIP cancellation - "Hi, I need to cancel my 11am appointment today, something came up." with name "Layla Hassan" (or any seeded VIP) -> cancels, offers remaining slots, flags a staff follow-up call.
  2. New booking - "I'd like to book the earliest slot you have today please." -> books the earliest open slot.
  3. Billing dispute - "I was charged twice for my last visit, BHD 80 came out of my account instead of 40." with name "Sara Ahmed" -> finds the duplicate BHD 40 charge, refunds it (under the BHD 50 limit), returns a reference number.
  4. Pricing inquiry - "How much is a full consultation and does it include follow up?" -> answers from the pricing KB.
  5. Urgent complaint - "This is the second time my appointment got pushed with no warning... leaving a 1 star review..." -> never auto-resolved, escalated as priority 1, sends an acknowledgment without p

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages