pharma / app.py
gsstec's picture
Upload 5 files
d72e65e verified
Raw
History Blame Contribute Delete
6.38 kB
import numpy as np
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from scipy.integrate import solve_ivp
app = FastAPI(
title="Advanced PK/PD Physiological Simulation Engine",
description="Multi-compartment PBPK engine for vaccine visual tracking across specific organs",
version="2.0.0"
)
# Robust CORS configuration to allow your local desktop Electron client to talk to the cloud
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- MATHEMATICAL SCHEMAS ---
class OrganParameters(BaseModel):
name: str = Field(..., description="Name of target organ/tissue profile clicked")
volume: float = Field(..., description="Tissue compartment volume (V_organ) in Liters")
blood_flow: float = Field(..., description="Blood flow rate to the tissue (Q_organ) in L/min")
partition_coefficient: float = Field(1.2, description="Tissue-to-plasma partition ratio (Kp)")
class PKPDRequest(BaseModel):
initial_dose: float = Field(..., description="Administered vaccine amount/payload concentration")
organ: OrganParameters = Field(..., description="Anatomical structural metrics fetched from Cloudflare/HRA")
clearance_systemic: float = Field(0.2, description="Total metabolic clearance (Cl) in L/min")
e_max: float = Field(100.0, description="Maximum pharmacodynamic inflammatory threshold response")
ec_50: float = Field(10.0, description="Concentration causing 50% maximal effect parameter")
simulation_hours: int = Field(72, ge=1, le=336, description="Total simulation window limit")
# --- SIMULATION ENGINE ENGINE ---
def pbpk_ode_system(t, y, Q_org, V_org, Kp, Cl, V_central=5.0):
"""
Simulates a closed loop multi-compartment system:
y[0] = Amount of vaccine localized at the primary tissue site
y[1] = Amount of vaccine flowing through central vascular circulation
"""
A_org = y[0]
A_central = y[1]
# Deriving concentration states
C_org = A_org / V_org if V_org > 0 else 0
C_central = A_central / V_central
# ODE Mass Balance Equations
# Rate of change in target organ = Delivery from arterial flow - Venous drainage outward
dA_org_dt = Q_org * (C_central - (C_org / Kp))
# Rate of change in central system = Return from tissue - Clearance/Elimination
dA_central_dt = Q_org * ((C_org / Kp) - C_central) - (Cl * C_central)
return [dA_org_dt, dA_central_dt]
@app.post("/api/v1/simulate/pkpd")
async def execute_simulation(payload: PKPDRequest):
try:
# 1. Setup Time Matrix
t_span = (0, payload.simulation_hours)
# Generate 150 points for extra smooth 3D graph animations inside Three.js
t_eval = np.linspace(0, payload.simulation_hours, 150)
# 2. Extract Physiological parameters
Q_org = payload.organ.blood_flow
V_org = payload.organ.volume
Kp = payload.organ.partition_coefficient
Cl = payload.clearance_systemic
# 3. Set Initial Conditions
# Assume initial dose enters the specified local target tissue compartment immediately
initial_state = [payload.initial_dose, 0.0]
# 4. Numerical ODE Solver (Runge-Kutta 45 integration)
solution = solve_ivp(
pbpk_ode_system,
t_span,
initial_state,
args=(Q_org, V_org, Kp, Cl),
t_eval=t_eval,
method='RK45'
)
if not solution.success:
raise HTTPException(status_code=500, detail="The differential integration solver failed to converge.")
# 5. Extract Amounts & Calculate Concentrations
amounts_tissue = solution.y[0]
amounts_blood = solution.y[1]
concentrations_tissue = amounts_tissue / V_org
concentrations_blood = amounts_blood / 5.0 # Central Blood Volume constant
# 6. Calculate Pharmacodynamics (PD) / Vitals Impact
# Emax sigmoid mathematical function evaluating localized physiological shift
local_vitals_delta = (payload.e_max * concentrations_tissue) / (payload.ec_50 + concentrations_tissue)
# Systemic immune response representation (e.g., simulated temperature spike)
fever_metric = 37.0 + ((payload.e_max * 1.5 * concentrations_blood) / (payload.ec_50 + concentrations_blood))
return {
"status": "success",
"time_series_hours": solution.t.tolist(),
"kinetics": {
"organ_amount": amounts_tissue.tolist(),
"organ_concentration": concentrations_tissue.tolist(),
"blood_amount": amounts_blood.tolist(),
"blood_concentration": concentrations_blood.tolist()
},
"vitals_metrics": {
"localized_cellular_activation_percent": local_vitals_delta.tolist(),
"simulated_core_body_temperature": np.clip(fever_metric, 37.0, 41.5).tolist()
}
}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Simulation parameter error: {str(e)}")
@app.get("/")
@app.head("/")
async def status_ping():
return {
"status": "active",
"engine": "PBPK Math Engine V2",
"concurrency": "Multi-Worker Optimized"
}
@app.get("/ping")
@app.head("/ping")
async def uptime_ping():
"""
Endpoint for UptimeRobot monitoring
Supports both GET and HEAD requests for health checks
"""
return {
"status": "ok",
"service": "pharma-pkpd",
"timestamp": "active"
}
@app.get("/health")
@app.head("/health")
async def health_check():
"""
Detailed health check endpoint
Supports both GET and HEAD requests
"""
return {
"status": "healthy",
"service": "AEGIS Pharma PK/PD Engine",
"version": "2.0.0",
"endpoints": {
"simulation": "/api/v1/simulate/pkpd",
"status": "/",
"ping": "/ping",
"health": "/health"
}
}