HealthBot / README.md
tirtho149's picture
Deploy SyndemicGPS HealthBot β€” geography-conditioned syndemic reasoning
34d29ef verified
|
Raw History Blame Contribute Delete
8.69 kB
---
title: HealthBot
emoji: 🧭
colorFrom: indigo
colorTo: purple
sdk: gradio
sdk_version: 5.50.0
app_file: app.py
python_version: "3.12"
pinned: false
short_description: Geography-conditioned syndemic health reasoning
license: mit
---
# 🧭 SyndemicGPS β€” HealthBot
**Same person, different place.**
The same health profile should not automatically produce the same support pathway everywhere in the world.
But geography should influence the reasoning only through explicit, evidence-backed contextual variables β€”
never through country-name stereotypes.
HealthBot holds one student's syndemic profile fixed, moves them between places, and reports exactly which
evidence-gated contextual factor changed the support pathway, at what geographic resolution, and from which
reporting year β€” or refuses to use a factor at all when the evidence is too weak or too old.
---
## What it does
| Operation | Ask it | What happens |
|---|---|---|
| **Analyze** | *What interacting problems do you see?* | Describes the individual syndemic graph `G_I` |
| **Contextualize** | *How does living in Dhaka affect this case?* | Gates one place's context into `G_S` |
| **Compare** | *Move this person from Bangladesh to Sweden.* | Same person, two places, and the flip taxonomy between them |
| **Explain** | *Why did your answer change?* | Attributes the difference to specific gated nodes |
| **Counterfactual** | *Keep them in Bangladesh but improve mental-health services.* | Moves one structural variable, person and place fixed |
| **Ablate** | *Answer without using geography.* | `C_g* = βˆ…` β€” the individual-only baseline |
| **Uncertainty** | *What do you not know?* | `U = [U_I, U_G, U_K, U_T]` and every abstention |
### The five flip types (`GIF(u,a,b) = D(Ο€_a, Ο€_b)`)
- **priority** β€” the order of support actions changes
- **pathway** β€” an action appears or disappears entirely
- **feasibility** β€” the same goal is delivered by a different route
- **confidence** β€” certainty moves because local evidence quality differs
- **escalation** β€” the verified crisis resource changes
---
## Architecture
```
user message
β”‚
β”œβ”€β–Ί LLM role 1 parse intent β†’ {op, place_a, place_b, factor} (regex parser as fallback + safety veto)
β”‚
β”œβ”€β–Ί DETERMINISTIC ENGINE syndemic/engine.py
β”‚ individual graph G_I Β· geographic context C_g = [E,H,S,D,R]
β”‚ evidence gate z_i = 1[Ev(c_i) β‰₯ Ο„]
β”‚ resolution ladder city β†’ subnational β†’ national β†’ cross-border region β†’ global
β”‚ fusion G_S Β· support planner Ο€ Β· GIF Β· uncertainty Β· V(u,g)
β”‚
└─► LLM role 3 verbalise the FACTS block only
```
**The model never produces a number.** Every prevalence, index, year, resolution level and service name in an
answer is computed by the engine and handed to the model inside a `FACTS` block, under a system prompt that
forbids inventing, extrapolating or rounding anything. If the model is unreachable the app degrades to
deterministic mode and still returns the full structured answer.
Three guardrails are enforced outside the model:
1. **Safety veto** β€” a self-harm pattern match routes to the safety template before the LLM parse is consulted.
Geography may change *which* resource is named; it never moves the threshold.
2. **Abstention** β€” a factor below `Ο„`, or too stale, is excluded rather than replaced by a weaker proxy.
3. **Service-capacity floor** β€” mental-health workforce, referral capacity, campus services and crisis pathways
may not back off to a global mean. A missing local service is reported as unknown, never as available.
---
## Configuration
The app reads its LLM credentials from the environment. On the Space these are **secrets**, never files in
the repo.
| Variable | Default | Meaning |
|---|---|---|
| `LLM_API_KEY` | β€” | Dialagram / OpenAI-compatible key. Without it the app runs deterministically. |
| `LLM_BASE_URL` | `https://dialagram.me/router/v1` | OpenAI-compatible endpoint |
| `LLM_MODEL` | `qwen-3.8-max-thinking` | Default writer model; all 16 switchable in the UI |
| `LLM_PARSER_MODEL` | `qwen-3.6-plus` | Model that parses intent into an operation |
Run locally:
```bash
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # fill in LLM_API_KEY
export $(grep -v '^#' .env | xargs)
python app.py # http://localhost:7860
```
Deploy (from a machine holding a HF write token):
```bash
python deploy.py --repo tirtho149/HealthBot
```
`deploy.py` uploads the app and pushes `LLM_API_KEY` / `LLM_BASE_URL` / `LLM_MODEL` into the Space's encrypted
secret store. It refuses to upload `.env`.
---
## Where the data comes from β€” retrieval, not a lookup table
Name **any place on earth** β€” a country, a state, a district, a refugee camp β€” and four live sources are
retrieved for it. No API keys anywhere.
| Stage | Source | What it gives |
|---|---|---|
| Resolve | OpenStreetMap **Nominatim** | any place name β†’ coordinates, admin area, country (states and districts, not just cities) |
| Measure | **Open-Meteo** CAMS + ERA5 | PM2.5 and days above 35 Β°C **at those coordinates** β€” genuine city-resolution observations |
| Indicators | **World Bank** Open Data | national series with indicator codes and reporting years |
| Passages | **Wikipedia** + BM25 | prose about the health system, ranked against this person's own active factors |
The resolution ladder is therefore real: a point measurement enters at `city` level, and the gate only backs off
to the World Bank's `national` series when the point query returns nothing β€” and it says so.
The two halves of RAG are kept strictly apart, and the prompt enforces it: **every number comes from the gated
indicators; retrieved passages may only supply narrative context and must be attributed.** A passage can never
introduce a statistic.
| Factor | Indicator |
|---|---|
| PM2.5 | `EN.ATM.PM25.MC.M3` |
| Safely managed sanitation | `SH.STA.SMSS.ZS` |
| UHC service coverage | `SH.UHC.SRVS.CV.XD` |
| Out-of-pocket health cost | `SH.XPD.OOPC.CH.ZS` |
| Food insecurity | `SN.ITK.MSFI.ZS` |
| Poverty at $3.65/day | `SI.POV.LMIC` |
| Youth unemployment | `SL.UEM.1524.ZS` |
| Diabetes prevalence | `SH.STA.DIAB.ZS` |
| Referral capacity *(proxy)* | `SH.MED.BEDS.ZS` |
| Communicable-disease burden *(proxy)* | `SH.DTH.COMM.ZS` |
| PM2.5, city level | Open-Meteo CAMS, 90-day mean at the coordinates |
| Extreme-heat days, city level | Open-Meteo ERA5 daily maxima at the coordinates |
Evidence scores are derived from the reporting year, so an old series is penalised and can fall below Ο„.
**What is deliberately NOT fetched.** Mental-health workforce, depression prevalence, extreme-heat days, campus
services and verified crisis lines have no World Bank indicator. The system does **not** substitute a proxy for
them β€” it abstains, and says so. Every seeded placeholder has now been removed: all
contextual values come from a live source or the factor abstains. Only the last-resort global fallback rows
remain illustrative, and they are labelled `illustrative global baseline` in the provenance panel.
**Describing yourself works too.** First-person messages ("I live in Iowa, I have gained weight, I don't sleep
well") are recognised as case descriptions, not questions.
**The case is live too.** Describe any person in the conversation and `X_u` is parsed from that description into
the factor catalogue; the graph, the interactions, and the whole pathway rebuild around them. Nothing about the
person is hard-coded β€” the GREC pilot student is just one example scenario.
## Claim boundary
Ο€ is a *contextual support pathway*, not an optimal treatment policy, a causal effect estimate, or a clinically
validated recommendation. Graph edges are association-level. Structural counterfactuals are reasoning probes,
not forecasts. Population statistics are evidence about a place, never facts about a person. Country membership
is never used as a proxy for individual behaviour, belief, or preference. **No reinforcement-learning policy is
trained or claimed** β€” the RL direction is preserved as future work, requiring prospective longitudinal outcome
data and a defensible reward design.
This is a research prototype for support and hypothesis generation. It does not diagnose, treat, or replace
professional care. If you are in danger, contact your local emergency services.
---
Built on the SyndemicGPS concept paper, which extends the GREC university-student syndemic framework
(Bangladesh, pilot n = 32) into a worldwide, geography-conditioned reasoning architecture.