Spaces:
Running
Running
File size: 9,299 Bytes
59abb4f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | // Empty string = relative URLs (Docker/HF Spaces: Nginx routes /api/* to FastAPI)
// "http://localhost:8000" = direct for local dev without Docker
const BASE = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000";
async function req<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
headers: { "Content-Type": "application/json" },
...options,
});
if (!res.ok) {
const err = await res.text();
throw new Error(`API ${res.status}: ${err}`);
}
return res.json();
}
// ββ Patients ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const getPatients = () => req<{ patients: any[]; total: number }>("/api/v1/patients");
export const getPatient = (id: string) => req<any>(`/api/v1/patients/${id}`);
export const getPatientFhir = (id: string) => req<any>(`/api/v1/patients/${id}/fhir`);
// ββ Trials ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const searchTrials = (condition: string, phase?: string, pageSize = 20) => {
const params = new URLSearchParams({ condition, page_size: String(pageSize) });
if (phase) params.set("phase", phase);
return req<{ trials: any[]; total: number; condition: string }>(`/api/v1/trials/search?${params}`);
};
export const getTrial = (nctId: string) => req<any>(`/api/v1/trials/${nctId}`);
export const getTrialEligiblePatients = (nctId: string) => req<any>(`/api/v1/trials/${nctId}/eligible-patients`);
export const getTrialIntelligence = (nctId: string) => req<any>(`/api/v1/trials/${nctId}/intelligence`);
// ββ Matching ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const matchPatientToTrials = (patientId: string, condition?: string, topN = 5) => {
const params = new URLSearchParams({ top_n: String(topN) });
if (condition) params.set("condition", condition);
return req<{ patient_id: string; matches: any[]; total: number }>(`/api/v1/patients/${patientId}/match-trials?${params}`);
};
export const screenPatient = (patientId: string, nctId: string) =>
req<any>(`/api/v1/patients/${patientId}/screen/${nctId}`, { method: "POST" });
// ββ A2A Workflow ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const runWorkflow = (patientId: string, nctId?: string, condition?: string) =>
req<any>("/api/v1/workflow/run", {
method: "POST",
body: JSON.stringify({ patient_id: patientId, nct_id: nctId, condition }),
});
export const getWorkflowStatus = (workflowId: string) => req<any>(`/api/v1/workflow/${workflowId}/status`);
export const listWorkflows = () => req<{ workflows: any[] }>("/api/v1/workflows");
// ββ Recruitment βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const getKanbanBoard = () => req<Record<string, any[]>>("/api/v1/recruitment/board");
export const getRecruitmentRecords = () => req<{ records: any[] }>("/api/v1/recruitment/records");
export const createRecruitmentRecord = (data: { patient_id: string; nct_id: string; trial_title: string; match_score: number }) =>
req<any>("/api/v1/recruitment/records", { method: "POST", body: JSON.stringify(data) });
export const updateRecordStatus = (recordId: string, status: string) =>
req<any>(`/api/v1/recruitment/records/${recordId}/status`, { method: "PATCH", body: JSON.stringify({ status }) });
export const generateOutreach = (data: { patient_id: string; nct_id: string; trial_title: string; channel: string }) =>
req<any>("/api/v1/recruitment/outreach", { method: "POST", body: JSON.stringify(data) });
// ββ Analytics βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const getKPIs = () => req<any>("/api/v1/analytics/kpi");
export const getEnrollmentFunnel = (trialId?: string) => {
const params = trialId ? `?trial_id=${trialId}` : "";
return req<{ funnel: any[] }>(`/api/v1/analytics/funnel${params}`);
};
export const getSitePerformance = () => req<{ sites: any[] }>("/api/v1/analytics/sites");
export const getDemographics = (trialId?: string) => {
const params = trialId ? `?trial_id=${trialId}` : "";
return req<any>(`/api/v1/analytics/demographics${params}`);
};
export const getTimeline = (days = 30) => req<{ timeline: any[] }>(`/api/v1/analytics/timeline?days=${days}`);
export const getMapData = () => req<{ sites: any[]; patient_clusters: any[] }>("/api/v1/map/data");
export const getGraphStats = () => req<any>("/api/v1/graph/stats");
export const getGraphPatients = (condition?: string, limit = 200) => {
const params = new URLSearchParams({ limit: String(limit) });
if (condition) params.set("condition", condition);
return req<{ patients: any[]; total: number }>(`/api/v1/graph/patients?${params}`);
};
// ββ Clinical Intake βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export interface IntakeLabs {
hemoglobin?: number; // g/dL
wbc?: number; // Γ10βΉ/L
anc?: number; // Γ10βΉ/L
platelets?: number; // Γ10βΉ/L
creatinine?: number; // ΞΌmol/L
egfr?: number; // mL/min/1.73mΒ²
bilirubin?: number; // ΞΌmol/L
alt?: number; // U/L
ast?: number; // U/L
albumin?: number; // g/dL
}
export interface IntakePayload {
condition: string;
age?: number;
sex?: string;
ecog?: number;
stage?: string;
biomarkers?: string[];
labs?: IntakeLabs;
prior_chemo?: boolean;
prior_radiation?: boolean;
prior_surgery?: boolean;
medications?: string[];
save_to_graph?: boolean;
}
export const submitIntake = (data: IntakePayload) =>
req<{ condition: string; matches: any[]; total: number; patient_id?: string }>(
"/api/v1/intake/match", { method: "POST", body: JSON.stringify(data) }
);
export const getBiomarkerRegistry = () =>
req<{ biomarkers: { id: string; label: string }[] }>("/api/v1/intake/biomarkers");
// ββ Graph RAG βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const graphQuery = (question: string) =>
req<{ response: string }>("/api/v1/graph/query", { method: "POST", body: JSON.stringify({ question }) });
// ββ Streaming A2A Workflow ββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const startWorkflow = (patientId: string, nctId?: string, condition?: string) =>
req<{ workflow_id: string; status: string; stream_url: string }>("/api/v1/workflow/start", {
method: "POST",
body: JSON.stringify({ patient_id: patientId, nct_id: nctId, condition }),
});
export const streamWorkflow = (workflowId: string, onEvent: (evt: any) => void, onDone: () => void) => {
const url = `${BASE}/api/v1/workflow/${workflowId}/stream`;
const es = new EventSource(url);
es.onmessage = (e) => {
if (e.data === "[DONE]") { es.close(); onDone(); return; }
try { onEvent(JSON.parse(e.data)); } catch {}
};
es.onerror = () => { es.close(); onDone(); };
return () => es.close();
};
// ββ Consent & Scheduling βββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const getConsents = (patientId?: string) => {
const params = patientId ? `?patient_id=${patientId}` : "";
return req<{ consents: any[] }>(`/api/v1/consent${params}`);
};
export const getConsentStats = () => req<any>("/api/v1/consent/stats");
export const updateConsentStatus = (consentId: string, status: string, notes?: string) =>
req<any>(`/api/v1/consent/${consentId}/status`, {
method: "PATCH",
body: JSON.stringify({ status, notes }),
});
export const getAppointments = (patientId?: string) => {
const params = patientId ? `?patient_id=${patientId}` : "";
return req<{ appointments: any[] }>(`/api/v1/appointments${params}`);
};
export const confirmAppointment = (apptId: string) =>
req<any>(`/api/v1/appointments/${apptId}/confirm`, { method: "PATCH" });
// ββ Health ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const getHealth = () => req<any>("/health");
|