# Project export: SynthTrial Studio

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Clinical data is slow and error-prone. SynthTrial Studio lets you generate realistic synthetic data, auto-enforce constraints, test YAML edit checks, run what-ifs, and auto-draft RBQM/CSR.
- Devpost: https://devpost.com/software/synthtrial-studio
- GitHub: https://github.com/nitishhrms/SyntheticTrialStudio
- Team: 1 GitHub contributor(s) — nitishhrms (2 commits)

## Devpost submission (written by the team)

### Overview

SynthTrial Studio — Constraint-aware synthetic EDC with auto-repair, what-if efficacy, RBQM & CSR Short description Spin up realistic clinical trial datasets (no PHI), validate & auto-repair, test YAML edit checks, explore what-ifs, and auto-draft RBQM/CSR docs—all in one Streamlit app. Elevator pitch (≤200 chars) Clinical data is slow and error-prone. SynthTrial Studio generates realistic synthetic data, enforces constraints, tests YAML checks, runs what-ifs, and drafts RBQM/CSR.

### Inspiration

Clinical data work is fragmented: generate plausible datasets, run edit checks, fix issues, monitor risk, then draft CSR snippets. We wanted a single workbench to do all of that safely with synthetic data only.

### What it does

SynthTrial Studio is a Streamlit app that lets you: Generate synthetic vitals under clinical constraints Rules-based generator MVN (multivariate normal) generator that preserves correlations per Visit×Arm DDPM diffusion (optional, PyTorch) small MLP denoiser for tabular sampling Guardrails: PHI lint blocks uploads that look like identifiers (synthetic-only). Validate & auto-repair: ranges, fever logic (Temp>38 needs HR≥67), unique keys, arm consistency, and snap Week-12 effect (Active − Placebo) to target. Power / stats tiles: means, effect, SE, p-value (Welch/approx), Cohen’s d. Oncology helper: simulate RECIST at Week-12 and compute ORR difference. Edit-Check Studio (YAML): define rules (range, regex, allowed values, required visits, uniqueness, constants) → raise EDC-style queries. RBQM dashboard: KRIs, site QTLs, queries per 100 rows, site roll-ups, AE signals. What-If Simulator: drag a slider to set target effect; preview validation & plots. Docs & exports: SDTM-like VS (TSV), CSR draft (Markdown), RBQM summary (Markdown), full ZIP with reports & docs. TMF helpers: SIV Log, Investigator DB placeholders to round out demos.

### How we built it

Frontend/App: Streamlit + Altair charts Data/Stats: NumPy, Pandas, SciPy (optional), custom Welch/normal approx fallback Generators: Rules-based (simple, fast) MVN per Visit×Arm: learn mean/cov, stabilize with εI, sample & clamp DDPM (prototype): tiny MLP ε-predictor with sinusoidal time embeddings; trains in minutes on CPU for demo-scale data LLM CSV mode (optional): OpenAI API to produce schema-locked CSV; post-validated and regenerated on failures Edit Checks: YAML via PyYAML → engine raises EDC-style queries Docs: Markdown builders for CSR & RBQM; ZIP packager for submission Architecture (at a glance) Data in: Generate (Rules/MVN/DDPM/LLM) or upload synthetic CSV/TSV → PHI lint. Validate: deterministic checks + report; Auto-repair if desired. Analyze: stats tiles, ORR helper, distribution checks vs pilot (KS & QQ). Monitor: YAML edit checks → RBQM KRIs/QTLs + site roll-ups. Export: SDTM VS, CSR draft, RBQM summary, and full ZIP. Why it’s different Constraint-aware from the start (schema-locked CSV, clinical ranges, fever logic). Multiple generators so teams can pick “speed vs realism”. Edit checks + RBQM are first-class, not an afterthought. What-if efficacy makes assumptions explicit and reproducible. Synthetic-only by design for safe demos and method prototyping.

### Challenges we ran into

Balancing realism vs. speed for hackathon-friendly training times. Making the LLM CSV path robust: we added a validate→feedback→regenerate loop. Packaging an end-to-end flow that still feels simple in Streamlit. Accomplishments we’re proud of A clean, judge-ready demo: generate → validate/repair → what-if → RBQM → export. A tiny DDPM that works on CPU for tabular vitals with Visit×Arm conditioning. Reusable YAML rule engine to mirror EDC queries.

### What we learned

Small, well-chosen constraints dramatically improve synthetic data quality. Site-level QTLs are easy to compute once you standardize queries & visits. Schema-locked LLM generation is viable with strict validation & feedback.

### What's next

Expand domains: labs, concomitant meds, dosing, more oncology endpoints. Add semi-synthetic mode (fit from user’s de-identified distributions only). Enrich RBQM: more KRIs (e.g., lag times, protocol deviations). One-click Streamlit Cloud deploy script + demo seed data. Optional GPU notebook for faster DDPM experimentation. Demo guide Generate / Load Try Rules (fast), MVN (correlated), or DDPM (after “Train DDPM”). Or upload your synthetic CSV/AE TSV (PHI lint will block obvious identifiers). Validate & Repair Review checks; click Auto-Repair; see effect, p-value, Cohen’s d tiles. Open Oncology ORR expander for CR/PR vs SD/PD helper. What-If Simulator Slide effect target to see how outcomes & validation change. Edit Checks (YAML) Run rules; inspect queries; download CSV of findings. RBQM Dashboard Inspect KRIs/QTLs and site roll-ups; download RBQM Markdown. Export Grab SDTM VS, CSR draft, RBQM summary, or the full submission ZIP. Built With python, streamlit, pandas, numpy, altair, scipy pyyaml, torch (CPU OK), openai (optional) Try it out Live demo: add your Streamlit Cloud link here GitHub: add your repo link here Video: coming soon Setup (local) pip install -r requirements.txt streamlit run app/app.py Optional LLM path: export OPENAI_API_KEY=... # or set in the UI Disclaimers All data is synthetic; do not use for clinical decisions. PHI lint is best-effort; always ensure uploads are de-identified.

## README (from the GitHub repository)

# SynthTrial Studio

Constraint-aware synthetic EDC for clinical trials—featuring data generation (rules/LLM/generative), YAML edit checks, auto-repair, what-if efficacy simulation, RBQM site roll-ups, TMF helpers, SDTM export, and CSR draft generation—all in a single Streamlit app.

> Demo preset: **Solid Tumor (Immuno-Oncology)** with optional oncology AEs & ORR helper.  
> All data is **synthetic-only** (uploads are linted to block likely PHI).

## ✨ Highlights

- **Synthetic EDC generation**
  - Rules-based generator with clinical constraints
  - LLM generator (OpenAI) with schema-locked CSV and auto-repair loop
  - Generative MVN sampler (learns per Visit×Arm mean/cov from pilot/current data)
  - (Prototype) Diffusion DDPM tabular model (code scaffold included; Torch optional)

- **Quality & safety**
  - YAML **Edit Check Studio**
  - **Auto-repair** for range and logic fixes
  - **PHI lint** on uploads

- **Analysis & reporting**
  - Week-12 efficacy tiles (means, effect, SE, p-value)
  - **What-If simulator**
  - **RBQM dashboard**
  - **CSR Draft** generator
  - **SDTM VS export**

- **TMF helpers**
  - Investigator DB and SIV Log renderers
  - One-click **submission ZIP** packaging

## 🧱 Project structure

```
.
├─ app/
│  └─ app.py
├─ data/
├─ docs/
├─ README.md
└─ LICENSE
```

## 🛠️ Installation

```bash
git clone https://github.com/<you>/synthtrial-studio.git
cd synthtrial-studio
python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt
```

## 🚀 Run

```bash
streamlit run app/app.py
```

## 📦 Requirements

See `requirements.txt` for the dependency list.

## ⚠️ Disclaimer

This project is for **development/demo** only. Data is synthetic; do **not** use for clinical decision-making or patient care.


## Detected evidence (automated analysis)

Indexed codebase: 12 recognized source files, 88 KB.
- Python (language) — detected in the code
- Streamlit (technology) — detected in the code

## Codebase structure (from repository index)

### Files (16 of 16)

```
app/app.py
checks/validate.py
constraints.md
data/pilot/ae.tsv
data/pilot/vitals.csv
docs/investigator_db.md
docs/PRD.md
docs/privacy.md
docs/SIV_log.md
LICENSE
README.md
requirements.txt
schemas/investigator_db_schema.md
schemas/sdtm_ae_schema.md
schemas/vitals_schema.md
scope.md
```

### Dependencies

- requirements.txt: faker, numpy, pandas, pydantic, scipy, streamlit

### Recent commits (newest first)

- README.md
- SynthTrialStudio

## Key source files (fetched from GitHub, selected and truncated for size)

### scope.md

```markdown
# Scope

Project: Constraint-aware synthetic clinical-trial data & TMF generator
Track: Regeneron “Tech” Prize — Health/biomed

## Trial Scenario (Demo)
- Indication: Rheumatoid Arthritis (autoimmune)
- Phase: 3
- Design: Parallel, double-blind; 2 arms (Active vs Placebo)
- Sample Size: Pilot N=10 (for iteration); Final N=100 (50/arm)
- Visits: Screening, Day 1, Week 4, Week 12
- Primary Endpoint: Change from baseline Systolic BP at Week 12
- Secondary Endpoints: Heart Rate by visit, Fever incidence (>38.0 °C), AE counts & outcomes

## Deliverables (for judges)
- `data/pilot/vitals.csv` and `data/final/vitals.csv` (if scaled)
- `data/pilot/ae.tsv` (SDTM AE domain)
- `docs/SIV_log.md` (TMF artifact)
- `docs/investigator_db.md` (15-row US site list)
- `checks/validation_report.md` (pass/fail with summary stats)
- Streamlit demo for generate → validate → download

## Out of Scope
- Real PHI/EHR; restricted datasets requiring approvals
- Medical imaging generation (GAN/diffusion) for diagnostics

```

### constraints.md

```markdown
# Constraints (copy-exact for generation & validation)

## Global / IDs / Visits
- `SubjectID`: RA###-### (e.g., RA001-001). Arm stays constant per subject.
- Each subject should have all scheduled visits (Screening, Day 1, Week 4, Week 12).
- Allow ≤1% missingness only if explicitly stated (default: none).

## Vitals (CSV)
Columns (exact): `SubjectID,VisitName,TreatmentArm,SystolicBP,DiastolicBP,HeartRate,Temperature`

Distributions & rules:
- SystolicBP (mmHg): Normal(mean=130, sd=10), **truncate [95, 200]**, integers
- DiastolicBP (mmHg): Normal(mean=80, sd=8), **truncate [55, 130]**, integers
- HeartRate (bpm): integers in **[60, 100]**; typical around 70–85
- Temperature (°C): Normal(mean=36.8, sd=0.3); **insert exactly 1–2 fever rows > 38.0**
- **Treatment effect (primary):** At **Week 12**, mean(SBP, Active) − mean(SBP, Placebo) ≈ **−5 mmHg**  
  - Acceptable tolerance for validation: **−7 ≤ effect ≤ −3**
- **Correlation rule:** If Temperature > 38.0 → increase HR on that row by **+7 to +10 bpm** from the subject’s typical range.

Output format:
- Single CSV code block with headers; no extra columns.

Validation acceptance:
- Columns present; ranges OK
- Fever count in {1, 2}
- For all fever rows, HR ≥ 67 bpm
- Week-12 SBP effect within [−7, −3] mmHg

## SDTM AE (TSV)
Columns (exact): `USUBJID  AETERM  AEBODSYS  AESER  AEREL  AEOUT`

Record targets:
- **20 total AE rows** for **≥15 distinct USUBJID**
- **Exactly 2** rows with `AESER='Y'` **and** `AEREL='Y'`
- **Exactly 1** row with `AEOUT='FATAL'`
- Remaining events: mild–moderate and plausible for a cardiac/autoimmune drug (e.g., Headache, Dizziness, Nausea, Palpitations, Hypertension, Syncope)
- Use realistic body systems: `Cardiac Disorders`, `Nervous System Disorders`, `Gastrointestinal Disorders`, `Vascular Disorders`, `General Disorders`
- Allowed outcomes: `RESOLVED`, `ONGOING`, `FATAL`

Validation acceptance:
- Column set exact
- Distinct USUBJID ≥ 15
- Counts match the exact serious/related and fatal constraints above

## Investigator / Site DB (Markdown)
Columns (exact):  
`InvestigatorName | SiteName | City | State | Affiliation | YearsExperience | TargetEnrollment | HistoricalScreenFailRate`

Distribution rules:
- 15 total rows; US cities **region-balanced** (Northeast, South, Midwest, West)
- `YearsExperience` in **[3, 20]**
- **Top performers (exactly 3 sites):** `TargetEnrollment > 10` **and** `HistoricalScreenFailRate < 20%`
- Remaining sites: TargetEnrollment 4–10; ScreenFail 20–40%
- Names look like US names; affiliations mix of University and Private Practice

## TMF — SIV Attendance Log (Markdown)
- 5–7 attendees with realistic roles: **PI, Sub-I, Study Coordinator, Pharmacist, CRA (Sponsor/CRO)**
- Columns: `Name | Role | Signature | Date/Time In | Date/Time Out`
- Signature field text: **"Synthetic Signature"**

## Acceptance (project-level)
- All validators pass on the latest generated datasets
- Streamlit demo can load, summarize, and show Week-12 effect & fever log
[truncated — 85 more characters]
```

### requirements.txt

```
pandas
numpy
scipy
streamlit
pydantic
faker

```

### checks/validate.py

```python
import pandas as pd
import sys

def validate_vitals(path: str) -> dict:
    df = pd.read_csv(path)
    report = {"file": path, "rows": len(df), "checks": []}
    required_cols = ["SubjectID","VisitName","TreatmentArm","SystolicBP","DiastolicBP","HeartRate","Temperature"]
    report["checks"].append(("columns_present", all(c in df.columns for c in required_cols)))
    # Ranges
    in_range = (
        df["SystolicBP"].between(95,200).all() and
        df["DiastolicBP"].between(55,130).all() and
        df["HeartRate"].between(50,120).all() and
        df["Temperature"].between(35.0,40.0).all()
    )
    report["checks"].append(("ranges_ok", in_range))
    # Fever count
    fevers = (df["Temperature"] > 38.0).sum()
    report["checks"].append(("fever_count_1_to_2", 1 <= fevers <= 2))
    # HR linkage: for fever rows, HR >= 67 (60 + 7)
    if fevers > 0:
        fever_hr_ok = df.loc[df["Temperature"] > 38.0, "HeartRate"].ge(67).all()
    else:
        fever_hr_ok = True
    report["checks"].append(("fever_hr_link_ok", fever_hr_ok))
    # Week 12 effect: mean SBP Active vs Placebo at Week 12
    wk12 = df[df["VisitName"] == "Week 12"]
    effect_ok = True
    effect = None
    if not wk12.empty and {"TreatmentArm","SystolicBP"}.issubset(wk12.columns):
        means = wk12.groupby("TreatmentArm")["SystolicBP"].mean().to_dict()
        if "Active" in means and "Placebo" in means:
            effect = means["Active"] - means["Placebo"]
            effect_ok = effect <= -3 and effect >= -7  # approx -5 ±2
    report["checks"].append(("week12_sbp_effect_approx_-5mmHg", effect_ok))
    report["week12_effect"] = effect
    return report

def main():
    path = sys.argv[1] if len(sys.argv) > 1 else "data/pilot/vitals.csv"
    r = validate_vitals(path)
    print(r)

if __name__ == "__main__":
    main()

```

[7 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]