""" Metabolic Forensics — N-of-1 biosignal evidence engine. Skeleton on synthetic data. The deterministic evidence pipeline is real; the LLM narration layer is stubbed (plug in a local llama.cpp model where marked). No personal data ships in this repo — privacy by construction. """ import numpy as np import pandas as pd import gradio as gr # --------------------------------------------------------------------------- # Synthetic demo data — stands in for ~/Health/data/*.jsonl (CGM/HRV/recovery) # Real version: load the user's Ultrahuman OAuth metrics locally, never in repo. # --------------------------------------------------------------------------- def make_demo_data(days: int = 46, seed: int = 7) -> pd.DataFrame: rng = np.random.default_rng(seed) dates = pd.date_range("2026-04-19", periods=days, freq="D") late_meal = rng.random(days) < 0.35 # hidden "cause" glucose_spike = 110 + late_meal * 45 + rng.normal(0, 8, days) # mg/dL peak # next-day HRV suffers after a spike (with noise + counterexamples) hrv = 55 - late_meal * 9 + rng.normal(0, 6, days) recovery = np.clip(70 - late_meal * 18 + rng.normal(0, 10, days), 1, 100) alertness = np.clip(75 - late_meal * 15 + rng.normal(0, 12, days), 1, 100) return pd.DataFrame({ "date": dates, "late_meal": late_meal.astype(int), "glucose_peak": glucose_spike.round(0), "hrv": hrv.round(0), "recovery": recovery.round(0), "morning_alertness": alertness.round(0), }) DF = make_demo_data() # --------------------------------------------------------------------------- # THE EVIDENCE ENGINE (deterministic — this is the moat, not the model) # Detect an event, split days into event vs non-event, report the contrast # AND the counterexamples (days where the pattern breaks). # --------------------------------------------------------------------------- QUESTIONS = { "What precedes my low-recovery mornings?": ("recovery", "low", "late_meal"), "What precedes my glucose spikes?": ("glucose_peak", "high", "late_meal"), "What precedes my low-alertness mornings?":("morning_alertness", "low", "late_meal"), } def forensics(question: str): metric, direction, candidate = QUESTIONS[question] df = DF.copy() thr = df[metric].quantile(0.25 if direction == "low" else 0.75) event = df[metric] <= thr if direction == "low" else df[metric] >= thr with_cand = event & (df[candidate] == 1) base_rate = df[candidate].mean() event_rate = df.loc[event, candidate].mean() lift = (event_rate / base_rate) if base_rate else float("nan") # counterexamples: event days where the candidate cause was ABSENT counterex = df[event & (df[candidate] == 0)] evidence = { "question": question, "n_days": len(df), "n_event_days": int(event.sum()), "candidate_signal": candidate, "candidate_present_on_event_days_pct": round(100 * event_rate, 0), "candidate_baseline_pct": round(100 * base_rate, 0), "lift": round(lift, 2), "n_counterexamples": len(counterex), } # ---- LLM NARRATION LAYER (stub) ------------------------------------- # Real version: hand `evidence` to a local llama.cpp ≤32B model with a # strict prompt: narrate ONLY this evidence, surface the counterexamples, # propose ONE testable experiment. Cannot invent associations. narration = ( f"**Observed association** — on your {evidence['n_event_days']} " f"'{question.split('my ')[-1].rstrip('?')}' days, " f"`{candidate}` was present {evidence['candidate_present_on_event_days_pct']:.0f}% " f"of the time vs a {evidence['candidate_baseline_pct']:.0f}% baseline " f"(**{evidence['lift']}× lift**).\n\n" f"**Counterexamples** — but {evidence['n_counterexamples']} of those days had " f"NO `{candidate}`, so this is a tendency, not a law. Don't overfit.\n\n" f"**Next experiment** — deliberately vary `{candidate}` for 7 days and watch " f"whether '{metric}' separates. That turns correlation into something testable." ) plot_df = df[["date", metric]].rename(columns={metric: "value"}) return narration, plot_df, evidence with gr.Blocks(title="Metabolic Forensics", theme=gr.themes.Soft()) as demo: gr.Markdown( "# 🩸 Metabolic Forensics\n" "*N-of-1 biosignal **evidence engine** — forensics, not coaching. " "Running on synthetic demo data.*" ) q = gr.Dropdown(list(QUESTIONS), value=list(QUESTIONS)[0], label="Forensic question") btn = gr.Button("Investigate", variant="primary") out_md = gr.Markdown() out_plot = gr.LinePlot(x="date", y="value", label="Metric over your history") out_json = gr.JSON(label="Raw evidence (what the model is allowed to narrate)") btn.click(forensics, q, [out_md, out_plot, out_json]) if __name__ == "__main__": demo.launch()