SabbaghCodes/Thulth

Thulth estimates whole‑body and organ biological ages, computes an Aging Rate Index (ARI), and turns insights into a simple weekly plan from three domain agents (General Doctor, Nutrition, Physical Activity). Guidance is non‑diagnostic, privacy‑respectful, and focused on tiny, realistic habits.

TypeScript

0

5 commits

updated Oct 28, 2025

See the code

README

Thulth: The AI‑integrated Wellness & Biological Age App

Thulth estimates whole‑body and organ biological ages, computes an Aging Rate Index (ARI), and turns insights into a simple weekly plan from three domain agents (General Doctor, Nutrition, Physical Activity). Guidance is non‑diagnostic, privacy‑respectful, and focused on tiny, realistic habits.

Highlights

  • Accurate, transparent estimates using GradientBoosting models (Cardio, Kidney, Global) with proper feature scaling
  • Coordinated, low‑friction recommendations from three agents; merged into a ≤5‑habit plan
  • Bilingual (AR/EN) with RTL support and supportive tone throughout
  • Mobile UX (bottom tabs): Home, Well‑being (tracking + plan), My File (profile/biomarkers)
  • Local plan/history persistence and simple progress visuals

Repository Layout

Thulth/
├─ app/                          # React Native (Expo) mobile app
│  ├─ package.json               # Expo deps + RN navigation
│  └─ src/
│     ├─ App.tsx                 # Navigation (tabs + stacks)
│     ├─ api/client.ts           # Fetchers (predict + agent routing)
│     ├─ i18n/                   # i18n provider + strings
│     ├─ components/             # UI components (Meter, OrganCard, etc.)
│     ├─ theme.ts                # Theme + color system
│     └─ screens/                # Screens (mobile + flow)
│        ├─ MobileHomeScreen.tsx
│        ├─ WellbeingScreen.tsx
│        ├─ MyFileScreen.tsx
│        ├─ RunOptionsScreen.tsx
│        ├─ ResultsScreen.tsx
│        ├─ PlanScreen.tsx
│        ├─ AgentChatScreen.tsx
│        └─ (EditProfileScreen, etc.)
├─ server/                       # FastAPI backend
│  ├─ main.py                    # Endpoints
│  ├─ models/schemas.py          # Pydantic schemas
│  ├─ services/
│  │  ├─ scoring_stub.py         # REAL inference (GB models) + mapping
│  │  ├─ coordinator.py          # Merge agents into plan (≤5, domain balance)
│  │  ├─ llm.py                  # Ollama client
│  │  └─ utils.py                # DEFAULT_USER, tone, helpers
│  └─ agents/                    # Agent runners (GD/NT/PA)
│     ├─ gd.py
│     ├─ nt.py
│     └─ pa.py
├─ model/                        # Training artifacts & weights
│  ├─ mpl_model.py               # Training script (reference)
│  ├─ weights/                   # *.pkl GB models (global/kidney/cardio)
│  ├─ data/                      # *healthy_* datasets for scaler fit
│  └─ data_cleaning/             # Data cleaning & population construction scripts
├─ thulth_logo.png               # Branding
└─ README.md                     # This file

Quickstart

1) Backend (FastAPI)

Requirements: Python 3.10+, virtualenv

cd server
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -r <(python - <<'PY'
from tomllib import load
import sys; import pathlib
p = pathlib.Path('pyproject.toml')
print("\n".join(load(p.open('rb'))['project']['dependencies']))
PY
)
# or install manually: fastapi uvicorn pydantic requests pandas numpy scikit-learn joblib scipy

python -m uvicorn main:app --reload --port 8000

Health checks

2) Mobile App (Expo)

Requirements: Node 18+, Expo CLI

cd app
npm i
npm run start
# iOS sim: press i   |  Android: a   |  Web: w

If running on a device, point the app’s API base (app/src/api/client.ts) to your machine IP instead of localhost.

Common Troubleshooting

  • EMFILE watcher error (macOS): install Watchman (brew install watchman) or raise ulimit -n 8192.
  • RN tabs missing: npm i @react-navigation/bottom-tabs @react-navigation/native @react-navigation/native-stack react-native-safe-area-context react-native-screens then npx expo start --clear.
  • Uvicorn not found: ensure your server venv is active and python -m pip install uvicorn.

Data Cleaning & Population Construction

The model/data_cleaning/ scripts generate the healthy / nonhealthy populations used for model pre‑fit, fine‑tuning, and testing.

Pipeline (per script comments):

  1. Combine lab tests from multiple sources into a unified table (row = person, column = test).
  2. Remove rows with missing age.
  3. Unit harmonization: convert blood test units to a canonical unit for each analyte (e.g., mg/dL, mmol/L) before modeling.
  4. Outlier removal: drop observations where (value − mean) > 3 × sd for each test.
  5. Healthy lab cohort: mark “healthy” if all tests fall within acceptable clinical ranges AND no existing conditions are present; remaining samples populate nonhealthy groups.

Outputs

  • model/data/*_healthy_non_saudi.txt — used to fit StandardScaler (global/cardio/kidney)
  • model/data/*_healthy_saudi.txt — fine‑tuning split
  • model/data/*_nonhealthy_saudi.txt — held‑out evaluation

Reproducibility (example)

cd model/data_cleaning
# 1) Merge + clean
python 01_merge_labs.py --input ./raw/ --out ../data/merged.tsv
# 2) Units harmonization
python 02_unit_harmonization.py --in ../data/merged.tsv --out ../data/merged_harmonized.tsv
# 3) Outlier removal (3*sd)
python 03_outlier_filter.py --in ../data/merged_harmonized.tsv --out ../data/filtered.tsv --z 3.0
# 4) Healthy/nonhealthy splits
python 04_define_populations.py --in ../data/filtered.tsv --healthy ../data/*_healthy_*.txt --nonhealthy ../data/*_nonhealthy_*.txt

Notes

  • Acceptable ranges are defined inside the scripts/config and should match the population under study; adjust for age/sex if available.
  • Keep a seed and log the final cohort sizes.

Data → Features Mapping

Server uses the same feature names from mpl_model.py and maps API payload keys to them.

DISPLAY_NAME_MAP keys used by the model (subset):

  • gender → M→0, F→1
  • Blood Pressure — Diastolic → diastolic (from DBP)
  • Blood Pressure — Systolic → systolic (from SBP)
  • Triglycerides → Triglyceride_result_value
  • Total Cholesterol → Cholesterol..in.Serum.or.Plasma_result_value
  • HDL Cholesterol → Cholesterol.in.HDL_result_value
  • Hemoglobin A1c (HbA1c) → Hemoglobin.A1c._result_value (accepts HbA1c/HBA1C/A1C synonyms)
  • Total Bilirubin → Bilirubin.total.[Mass/volume].in.Serum.or.Plasma_result_value
  • Serum Albumin → Albumin.[Mass/volume].in.Serum.or.Plasma_result_value
  • AST → Aspartate.aminotransferase.[Enzymatic.activity/volume].in.Serum.or.Plasma.by.With.P-5-P_result_value
  • Serum Creatinine → Creatinine..in.Serum.or.Plasma_result_value
  • Uric Acid → Uric.acid.in.Serum.or.Plasma_result_value
  • Serum Potassium → Potassium.in.Serum.or.Plasma_result_value (K)
  • Serum Sodium → Sodium.in.Serum.or.Plasma_result_value (Na)
  • TSH → Thyroid.Stimulating.Hormone.[TSH]_result_value
  • White Blood Cell Count (WBC) → WBC_result_value
  • Average Daily Steps → avg_daily_steps
  • Body Mass Index (BMI) → bmi (computed from height_cm, weight_kg)

Models & columns

  • Global: GLOBAL_COLS (~cardio‑metabolic + BMI)
  • Cardio: CARDIO_COLS (BP, lipids, A1c)
  • Kidney: KIDNEY_COLS (creatinine, uric acid, Na/K)

Scaling

  • We re‑fit a StandardScaler per system on *_healthy_non_saudi.txt to match training distribution; missing features are filled using the training means.

Backend Endpoints

  • GET /health → { ok: true }
  • GET /logo.png → branding
  • POST /predict/run → PredictionOut
    • Uses saved GB models to compute:
      • whole.bio_age (Global)
      • organs.cardio and organs.kidney values and drivers (top importances)
      • ari (aging rate index) from bio‑age gap
  • POST /agent/gd | /agent/nt | /agent/pa → AgentResponse (Ollama backed with resilient fallbacks)
  • POST /agent/route → CoordinatorOut (≤5 items, ≥1 per domain, Impact×Ease ordering)

Environment (optional)

  • OLLAMA_HOST (default http://localhost:11434)
  • OLLAMA_MODEL (default llama3.1:8b)

Agents & Coordinator

  • General Doctor: contextualizes ages, highlights 1–2 priorities, ends with a clarifying question
  • Nutrition: add‑ins only (≤10 minutes), culturally neutral
  • Physical Activity: short, stackable, gentle start
  • Coordinator: dedupe + cap + domain balance + sort by Impact×Ease

Prompts were engineered for empathy, brevity, and transparency; if prediction is missing, agents use DEFAULT_USER + fallbacks.


Mobile App UX

  • Tabs: Home, Well‑being, My File
  • Results: headline, ARI band, Cardio/Kidney cards, Start Today
  • Plan: 4‑week plan list; “Open in Well‑being” button
  • Well‑being: Today (steps), This Week’s Plan, trends, habits, hydration, BA progress chart
  • Agent Chat: ChatGPT‑style (intro + follow‑up), enter‑to‑send
  • Run Options: loader overlay during prediction and routing

Internationalization & RTL: AR/EN with I18nProvider and Dubai font
Theming: theme.ts primaryAccent + card style
Persistence: AsyncStorage for last result/plan, BA history, steps, etc.


Privacy, Safety, and Tone

  • Non‑diagnostic lifestyle guidance only
  • Privacy line: “Your data is private, encrypted, and never shared without permission.”
  • Supportive, respectful micro‑copy

Roadmap

  • HealthKit/Google Fit adapters
  • Cloud auth & sync
  • More organs, calibration improvements
  • Richer agent memory & nudges
  • Content feeds and notifications

Contributing

  • Feature branches, small PRs, bilingual copy, screenshots for UI

License & Notices

  • Internal prototype; not for clinical/diagnostic use
  • Third‑party assets per their licenses

Troubleshooting Cheatsheet

  • Expo “Unable to resolve @react-navigation/bottom-tabs” → npm i @react-navigation/bottom-tabs + npx expo start --clear
  • macOS “EMFILE: too many open files, watch” → brew install watchman or ulimit -n 8192
  • Uvicorn/venv mismatch → source server/.venv/bin/activate then python -m uvicorn main:app --reload --port 8000
  • Long inference time on first run → model/scaler warmup & joblib load; subsequent runs are faster

If you need help wiring a new data source or extending the plan logic, open an issue with sample payloads and desired UX.

SabbaghCodes/Thulth

Thulth estimates whole‑body and organ biological ages, computes an Aging Rate Index (ARI), and turns insights into a simple weekly plan from three domain agents (General Doctor, Nutrition, Physical Activity). Guidance is non‑diagnostic, privacy‑respectful, and focused on tiny, realistic habits.

TypeScript

0

5 commits

updated Oct 28, 2025

See the code

README

Thulth: The AI‑integrated Wellness & Biological Age App

Thulth estimates whole‑body and organ biological ages, computes an Aging Rate Index (ARI), and turns insights into a simple weekly plan from three domain agents (General Doctor, Nutrition, Physical Activity). Guidance is non‑diagnostic, privacy‑respectful, and focused on tiny, realistic habits.

Highlights

  • Accurate, transparent estimates using GradientBoosting models (Cardio, Kidney, Global) with proper feature scaling
  • Coordinated, low‑friction recommendations from three agents; merged into a ≤5‑habit plan
  • Bilingual (AR/EN) with RTL support and supportive tone throughout
  • Mobile UX (bottom tabs): Home, Well‑being (tracking + plan), My File (profile/biomarkers)
  • Local plan/history persistence and simple progress visuals

Repository Layout

Thulth/
├─ app/                          # React Native (Expo) mobile app
│  ├─ package.json               # Expo deps + RN navigation
│  └─ src/
│     ├─ App.tsx                 # Navigation (tabs + stacks)
│     ├─ api/client.ts           # Fetchers (predict + agent routing)
│     ├─ i18n/                   # i18n provider + strings
│     ├─ components/             # UI components (Meter, OrganCard, etc.)
│     ├─ theme.ts                # Theme + color system
│     └─ screens/                # Screens (mobile + flow)
│        ├─ MobileHomeScreen.tsx
│        ├─ WellbeingScreen.tsx
│        ├─ MyFileScreen.tsx
│        ├─ RunOptionsScreen.tsx
│        ├─ ResultsScreen.tsx
│        ├─ PlanScreen.tsx
│        ├─ AgentChatScreen.tsx
│        └─ (EditProfileScreen, etc.)
├─ server/                       # FastAPI backend
│  ├─ main.py                    # Endpoints
│  ├─ models/schemas.py          # Pydantic schemas
│  ├─ services/
│  │  ├─ scoring_stub.py         # REAL inference (GB models) + mapping
│  │  ├─ coordinator.py          # Merge agents into plan (≤5, domain balance)
│  │  ├─ llm.py                  # Ollama client
│  │  └─ utils.py                # DEFAULT_USER, tone, helpers
│  └─ agents/                    # Agent runners (GD/NT/PA)
│     ├─ gd.py
│     ├─ nt.py
│     └─ pa.py
├─ model/                        # Training artifacts & weights
│  ├─ mpl_model.py               # Training script (reference)
│  ├─ weights/                   # *.pkl GB models (global/kidney/cardio)
│  ├─ data/                      # *healthy_* datasets for scaler fit
│  └─ data_cleaning/             # Data cleaning & population construction scripts
├─ thulth_logo.png               # Branding
└─ README.md                     # This file

Quickstart

1) Backend (FastAPI)

Requirements: Python 3.10+, virtualenv

cd server
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -r <(python - <<'PY'
from tomllib import load
import sys; import pathlib
p = pathlib.Path('pyproject.toml')
print("\n".join(load(p.open('rb'))['project']['dependencies']))
PY
)
# or install manually: fastapi uvicorn pydantic requests pandas numpy scikit-learn joblib scipy

python -m uvicorn main:app --reload --port 8000

Health checks

2) Mobile App (Expo)

Requirements: Node 18+, Expo CLI

cd app
npm i
npm run start
# iOS sim: press i   |  Android: a   |  Web: w

If running on a device, point the app’s API base (app/src/api/client.ts) to your machine IP instead of localhost.

Common Troubleshooting

  • EMFILE watcher error (macOS): install Watchman (brew install watchman) or raise ulimit -n 8192.
  • RN tabs missing: npm i @react-navigation/bottom-tabs @react-navigation/native @react-navigation/native-stack react-native-safe-area-context react-native-screens then npx expo start --clear.
  • Uvicorn not found: ensure your server venv is active and python -m pip install uvicorn.

Data Cleaning & Population Construction

The model/data_cleaning/ scripts generate the healthy / nonhealthy populations used for model pre‑fit, fine‑tuning, and testing.

Pipeline (per script comments):

  1. Combine lab tests from multiple sources into a unified table (row = person, column = test).
  2. Remove rows with missing age.
  3. Unit harmonization: convert blood test units to a canonical unit for each analyte (e.g., mg/dL, mmol/L) before modeling.
  4. Outlier removal: drop observations where (value − mean) > 3 × sd for each test.
  5. Healthy lab cohort: mark “healthy” if all tests fall within acceptable clinical ranges AND no existing conditions are present; remaining samples populate nonhealthy groups.

Outputs

  • model/data/*_healthy_non_saudi.txt — used to fit StandardScaler (global/cardio/kidney)
  • model/data/*_healthy_saudi.txt — fine‑tuning split
  • model/data/*_nonhealthy_saudi.txt — held‑out evaluation

Reproducibility (example)

cd model/data_cleaning
# 1) Merge + clean
python 01_merge_labs.py --input ./raw/ --out ../data/merged.tsv
# 2) Units harmonization
python 02_unit_harmonization.py --in ../data/merged.tsv --out ../data/merged_harmonized.tsv
# 3) Outlier removal (3*sd)
python 03_outlier_filter.py --in ../data/merged_harmonized.tsv --out ../data/filtered.tsv --z 3.0
# 4) Healthy/nonhealthy splits
python 04_define_populations.py --in ../data/filtered.tsv --healthy ../data/*_healthy_*.txt --nonhealthy ../data/*_nonhealthy_*.txt

Notes

  • Acceptable ranges are defined inside the scripts/config and should match the population under study; adjust for age/sex if available.
  • Keep a seed and log the final cohort sizes.

Data → Features Mapping

Server uses the same feature names from mpl_model.py and maps API payload keys to them.

DISPLAY_NAME_MAP keys used by the model (subset):

  • gender → M→0, F→1
  • Blood Pressure — Diastolic → diastolic (from DBP)
  • Blood Pressure — Systolic → systolic (from SBP)
  • Triglycerides → Triglyceride_result_value
  • Total Cholesterol → Cholesterol..in.Serum.or.Plasma_result_value
  • HDL Cholesterol → Cholesterol.in.HDL_result_value
  • Hemoglobin A1c (HbA1c) → Hemoglobin.A1c._result_value (accepts HbA1c/HBA1C/A1C synonyms)
  • Total Bilirubin → Bilirubin.total.[Mass/volume].in.Serum.or.Plasma_result_value
  • Serum Albumin → Albumin.[Mass/volume].in.Serum.or.Plasma_result_value
  • AST → Aspartate.aminotransferase.[Enzymatic.activity/volume].in.Serum.or.Plasma.by.With.P-5-P_result_value
  • Serum Creatinine → Creatinine..in.Serum.or.Plasma_result_value
  • Uric Acid → Uric.acid.in.Serum.or.Plasma_result_value
  • Serum Potassium → Potassium.in.Serum.or.Plasma_result_value (K)
  • Serum Sodium → Sodium.in.Serum.or.Plasma_result_value (Na)
  • TSH → Thyroid.Stimulating.Hormone.[TSH]_result_value
  • White Blood Cell Count (WBC) → WBC_result_value
  • Average Daily Steps → avg_daily_steps
  • Body Mass Index (BMI) → bmi (computed from height_cm, weight_kg)

Models & columns

  • Global: GLOBAL_COLS (~cardio‑metabolic + BMI)
  • Cardio: CARDIO_COLS (BP, lipids, A1c)
  • Kidney: KIDNEY_COLS (creatinine, uric acid, Na/K)

Scaling

  • We re‑fit a StandardScaler per system on *_healthy_non_saudi.txt to match training distribution; missing features are filled using the training means.

Backend Endpoints

  • GET /health → { ok: true }
  • GET /logo.png → branding
  • POST /predict/run → PredictionOut
    • Uses saved GB models to compute:
      • whole.bio_age (Global)
      • organs.cardio and organs.kidney values and drivers (top importances)
      • ari (aging rate index) from bio‑age gap
  • POST /agent/gd | /agent/nt | /agent/pa → AgentResponse (Ollama backed with resilient fallbacks)
  • POST /agent/route → CoordinatorOut (≤5 items, ≥1 per domain, Impact×Ease ordering)

Environment (optional)

  • OLLAMA_HOST (default http://localhost:11434)
  • OLLAMA_MODEL (default llama3.1:8b)

Agents & Coordinator

  • General Doctor: contextualizes ages, highlights 1–2 priorities, ends with a clarifying question
  • Nutrition: add‑ins only (≤10 minutes), culturally neutral
  • Physical Activity: short, stackable, gentle start
  • Coordinator: dedupe + cap + domain balance + sort by Impact×Ease

Prompts were engineered for empathy, brevity, and transparency; if prediction is missing, agents use DEFAULT_USER + fallbacks.


Mobile App UX

  • Tabs: Home, Well‑being, My File
  • Results: headline, ARI band, Cardio/Kidney cards, Start Today
  • Plan: 4‑week plan list; “Open in Well‑being” button
  • Well‑being: Today (steps), This Week’s Plan, trends, habits, hydration, BA progress chart
  • Agent Chat: ChatGPT‑style (intro + follow‑up), enter‑to‑send
  • Run Options: loader overlay during prediction and routing

Internationalization & RTL: AR/EN with I18nProvider and Dubai font
Theming: theme.ts primaryAccent + card style
Persistence: AsyncStorage for last result/plan, BA history, steps, etc.


Privacy, Safety, and Tone

  • Non‑diagnostic lifestyle guidance only
  • Privacy line: “Your data is private, encrypted, and never shared without permission.”
  • Supportive, respectful micro‑copy

Roadmap

  • HealthKit/Google Fit adapters
  • Cloud auth & sync
  • More organs, calibration improvements
  • Richer agent memory & nudges
  • Content feeds and notifications

Contributing

  • Feature branches, small PRs, bilingual copy, screenshots for UI

License & Notices

  • Internal prototype; not for clinical/diagnostic use
  • Third‑party assets per their licenses

Troubleshooting Cheatsheet

  • Expo “Unable to resolve @react-navigation/bottom-tabs” → npm i @react-navigation/bottom-tabs + npx expo start --clear
  • macOS “EMFILE: too many open files, watch” → brew install watchman or ulimit -n 8192
  • Uvicorn/venv mismatch → source server/.venv/bin/activate then python -m uvicorn main:app --reload --port 8000
  • Long inference time on first run → model/scaler warmup & joblib load; subsequent runs are faster

If you need help wiring a new data source or extending the plan logic, open an issue with sample payloads and desired UX.