Siyad798 commited on
Commit
3419cfb
·
verified ·
1 Parent(s): 36612f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -41
app.py CHANGED
@@ -11,21 +11,17 @@ import subprocess
11
  # ==========================================
12
  # 1. DEEPISLES SETUP (Environment Trickery)
13
  # ==========================================
14
- # nnU-Net requires specific env vars to find models.
15
- # We set them to temporary folders.
16
  os.environ['nnUNet_raw_data_base'] = '/tmp/nnUNet_raw_data_base'
17
  os.environ['nnUNet_preprocessed'] = '/tmp/nnUNet_preprocessed'
18
  os.environ['RESULTS_FOLDER'] = '/tmp/nnUNet_trained_models'
19
 
20
- # Define the rigid structure nnU-Net expects for the model
21
  TASK_NAME = "Task012_Ischemic_Stroke_TM_Fullset"
22
  TRAINER = "nnUNetTrainerV2_DDP__nnUNetPlansv2.1"
23
  MODEL_PATH_INTERNAL = os.path.join(os.environ['RESULTS_FOLDER'], "nnUNet", "3d_fullres", TASK_NAME, TRAINER, "fold_0")
24
 
25
  print("--- 🧠 Initializing DeepISLES Engine ---")
26
 
27
- # 1. Install Weights (Run once on startup)
28
- UPLOADED_WEIGHTS = "fold_0.zip" # <--- Expects this file in Space
29
 
30
  if os.path.exists(UPLOADED_WEIGHTS):
31
  if not os.path.exists(MODEL_PATH_INTERNAL):
@@ -44,7 +40,6 @@ else:
44
  # 2. FILE HANDLING
45
  # ==========================================
46
  def find_sequences(extract_dir):
47
- """Finds DWI (b1000) and ADC files."""
48
  dwi = None
49
  adc = None
50
  for root, _, files in os.walk(extract_dir):
@@ -55,29 +50,26 @@ def find_sequences(extract_dir):
55
  return dwi, adc
56
 
57
  def generate_overlay(dwi_path, mask_path):
58
- """Creates visual check."""
59
  try:
60
  img = nib.load(dwi_path)
61
  mask = nib.load(mask_path)
62
  dwi = img.get_fdata()
63
  seg = mask.get_fdata()
64
-
65
- # Rotate for display
66
  dwi = np.rot90(dwi, k=1, axes=(0, 1))
67
  seg = np.rot90(seg, k=1, axes=(0, 1))
68
-
69
- # Find best slice
70
  sums = np.sum(seg, axis=(0, 1))
71
  idx = np.argmax(sums) if np.max(sums) > 0 else dwi.shape[2]//2
72
-
73
  fig, ax = plt.subplots(figsize=(5, 5))
74
  ax.imshow(dwi[:, :, idx], cmap="gray")
75
  if np.max(seg) > 0:
76
  overlay = np.zeros((*seg.shape[:2], 4))
77
- overlay[seg[:, :, idx] > 0] = [1, 0, 0, 0.6] # Red
78
  ax.imshow(overlay)
79
  ax.axis("off")
80
-
81
  out_path = "/tmp/overlay.png"
82
  plt.savefig(out_path, bbox_inches='tight')
83
  plt.close()
@@ -90,34 +82,28 @@ def generate_overlay(dwi_path, mask_path):
90
  # ==========================================
91
  def segment_stroke(zip_file):
92
  if not zip_file: return {"error": "No file uploaded"}, None
93
-
94
- # Create temp workspace
95
  work_dir = tempfile.mkdtemp()
96
  input_dir = os.path.join(work_dir, "input")
97
  output_dir = os.path.join(work_dir, "output")
98
  os.makedirs(input_dir, exist_ok=True)
99
  os.makedirs(output_dir, exist_ok=True)
100
-
101
  try:
102
- # 1. Extract Patient
103
- # Gradio 5 passes file path as string, Gradio 4 passes object
104
- # We handle both safely
105
  file_path = zip_file.name if hasattr(zip_file, 'name') else zip_file
106
 
107
  with zipfile.ZipFile(file_path, 'r') as z:
108
  z.extractall(work_dir)
109
-
110
- # 2. Find Sequences
111
  dwi, adc = find_sequences(work_dir)
112
  if not dwi or not adc:
113
  return {"status": "FAILED", "error": "DWI or ADC missing in zip"}, None
114
-
115
- # 3. Format for nnU-Net (Crucial Step!)
116
- # nnU-Net expects: CASE_0000.nii.gz (DWI) and CASE_0001.nii.gz (ADC)
117
  shutil.copy(dwi, os.path.join(input_dir, "patient_0000.nii.gz"))
118
  shutil.copy(adc, os.path.join(input_dir, "patient_0001.nii.gz"))
119
-
120
- # 4. Run Prediction Command
121
  print("🚀 Running DeepISLES Inference...")
122
  cmd = [
123
  "nnUNet_predict",
@@ -128,35 +114,31 @@ def segment_stroke(zip_file):
128
  "-f", "0",
129
  "--save_npz"
130
  ]
131
-
132
- # We use subprocess to run the CLI command
133
  process = subprocess.run(cmd, capture_output=True, text=True)
134
-
135
  if process.returncode != 0:
136
  print("NNUNET ERROR:", process.stderr)
137
  return {"status": "FAILED", "error": "Model inference failed. See logs."}, None
138
-
139
- # 5. Process Result
140
  result_file = os.path.join(output_dir, "patient.nii.gz")
141
  if os.path.exists(result_file):
142
- # Calculate Volume
143
  mask_img = nib.load(result_file)
144
  mask_data = mask_img.get_fdata()
145
  zooms = mask_img.header.get_zooms()
146
  vol_ml = (np.sum(mask_data > 0) * np.prod(zooms)) / 1000.0
147
-
148
  risk = "LOW"
149
  if vol_ml > 70: risk = "HIGH (Futile Recanalization?)"
150
  elif vol_ml > 50: risk = "MODERATE"
151
-
152
  report = {
153
  "status": "SUCCESS",
154
  "core_volume_ml": round(vol_ml, 2),
155
  "risk_assessment": risk,
156
  "model_used": "DeepISLES (nnU-Net Ensembled)"
157
  }
158
-
159
- # Visualize
160
  overlay = generate_overlay(dwi, result_file)
161
  return report, overlay
162
  else:
@@ -168,13 +150,12 @@ def segment_stroke(zip_file):
168
  shutil.rmtree(work_dir, ignore_errors=True)
169
 
170
  # ==========================================
171
- # 4. UI (THEME REMOVED)
172
  # ==========================================
173
- # FIX: Removed theme argument here to prevent crash
174
  with gr.Blocks() as demo:
175
  gr.Markdown("# 👁️ Neuro-Triage: Vision Agent")
176
  gr.Markdown("Upload Patient ZIP (DWI + ADC). Calculates Infarct Core Volume.")
177
-
178
  with gr.Row():
179
  with gr.Column():
180
  inp = gr.File(label="Patient Data (.zip)", type="filepath")
@@ -182,7 +163,7 @@ with gr.Blocks() as demo:
182
  with gr.Column():
183
  out_json = gr.JSON(label="Clinical Report")
184
  out_img = gr.Image(label="Lesion Map")
185
-
186
  btn.click(segment_stroke, inputs=inp, outputs=[out_json, out_img])
187
 
188
  if __name__ == "__main__":
 
11
  # ==========================================
12
  # 1. DEEPISLES SETUP (Environment Trickery)
13
  # ==========================================
 
 
14
  os.environ['nnUNet_raw_data_base'] = '/tmp/nnUNet_raw_data_base'
15
  os.environ['nnUNet_preprocessed'] = '/tmp/nnUNet_preprocessed'
16
  os.environ['RESULTS_FOLDER'] = '/tmp/nnUNet_trained_models'
17
 
 
18
  TASK_NAME = "Task012_Ischemic_Stroke_TM_Fullset"
19
  TRAINER = "nnUNetTrainerV2_DDP__nnUNetPlansv2.1"
20
  MODEL_PATH_INTERNAL = os.path.join(os.environ['RESULTS_FOLDER'], "nnUNet", "3d_fullres", TASK_NAME, TRAINER, "fold_0")
21
 
22
  print("--- 🧠 Initializing DeepISLES Engine ---")
23
 
24
+ UPLOADED_WEIGHTS = "fold_0.zip"
 
25
 
26
  if os.path.exists(UPLOADED_WEIGHTS):
27
  if not os.path.exists(MODEL_PATH_INTERNAL):
 
40
  # 2. FILE HANDLING
41
  # ==========================================
42
  def find_sequences(extract_dir):
 
43
  dwi = None
44
  adc = None
45
  for root, _, files in os.walk(extract_dir):
 
50
  return dwi, adc
51
 
52
  def generate_overlay(dwi_path, mask_path):
 
53
  try:
54
  img = nib.load(dwi_path)
55
  mask = nib.load(mask_path)
56
  dwi = img.get_fdata()
57
  seg = mask.get_fdata()
58
+
 
59
  dwi = np.rot90(dwi, k=1, axes=(0, 1))
60
  seg = np.rot90(seg, k=1, axes=(0, 1))
61
+
 
62
  sums = np.sum(seg, axis=(0, 1))
63
  idx = np.argmax(sums) if np.max(sums) > 0 else dwi.shape[2]//2
64
+
65
  fig, ax = plt.subplots(figsize=(5, 5))
66
  ax.imshow(dwi[:, :, idx], cmap="gray")
67
  if np.max(seg) > 0:
68
  overlay = np.zeros((*seg.shape[:2], 4))
69
+ overlay[seg[:, :, idx] > 0] = [1, 0, 0, 0.6]
70
  ax.imshow(overlay)
71
  ax.axis("off")
72
+
73
  out_path = "/tmp/overlay.png"
74
  plt.savefig(out_path, bbox_inches='tight')
75
  plt.close()
 
82
  # ==========================================
83
  def segment_stroke(zip_file):
84
  if not zip_file: return {"error": "No file uploaded"}, None
85
+
 
86
  work_dir = tempfile.mkdtemp()
87
  input_dir = os.path.join(work_dir, "input")
88
  output_dir = os.path.join(work_dir, "output")
89
  os.makedirs(input_dir, exist_ok=True)
90
  os.makedirs(output_dir, exist_ok=True)
91
+
92
  try:
93
+ # Handle Gradio 5 file path string
 
 
94
  file_path = zip_file.name if hasattr(zip_file, 'name') else zip_file
95
 
96
  with zipfile.ZipFile(file_path, 'r') as z:
97
  z.extractall(work_dir)
98
+
 
99
  dwi, adc = find_sequences(work_dir)
100
  if not dwi or not adc:
101
  return {"status": "FAILED", "error": "DWI or ADC missing in zip"}, None
102
+
103
+ # Format for nnU-Net: 0000=DWI, 0001=ADC
 
104
  shutil.copy(dwi, os.path.join(input_dir, "patient_0000.nii.gz"))
105
  shutil.copy(adc, os.path.join(input_dir, "patient_0001.nii.gz"))
106
+
 
107
  print("🚀 Running DeepISLES Inference...")
108
  cmd = [
109
  "nnUNet_predict",
 
114
  "-f", "0",
115
  "--save_npz"
116
  ]
117
+
 
118
  process = subprocess.run(cmd, capture_output=True, text=True)
119
+
120
  if process.returncode != 0:
121
  print("NNUNET ERROR:", process.stderr)
122
  return {"status": "FAILED", "error": "Model inference failed. See logs."}, None
123
+
 
124
  result_file = os.path.join(output_dir, "patient.nii.gz")
125
  if os.path.exists(result_file):
 
126
  mask_img = nib.load(result_file)
127
  mask_data = mask_img.get_fdata()
128
  zooms = mask_img.header.get_zooms()
129
  vol_ml = (np.sum(mask_data > 0) * np.prod(zooms)) / 1000.0
130
+
131
  risk = "LOW"
132
  if vol_ml > 70: risk = "HIGH (Futile Recanalization?)"
133
  elif vol_ml > 50: risk = "MODERATE"
134
+
135
  report = {
136
  "status": "SUCCESS",
137
  "core_volume_ml": round(vol_ml, 2),
138
  "risk_assessment": risk,
139
  "model_used": "DeepISLES (nnU-Net Ensembled)"
140
  }
141
+
 
142
  overlay = generate_overlay(dwi, result_file)
143
  return report, overlay
144
  else:
 
150
  shutil.rmtree(work_dir, ignore_errors=True)
151
 
152
  # ==========================================
153
+ # 4. UI
154
  # ==========================================
 
155
  with gr.Blocks() as demo:
156
  gr.Markdown("# 👁️ Neuro-Triage: Vision Agent")
157
  gr.Markdown("Upload Patient ZIP (DWI + ADC). Calculates Infarct Core Volume.")
158
+
159
  with gr.Row():
160
  with gr.Column():
161
  inp = gr.File(label="Patient Data (.zip)", type="filepath")
 
163
  with gr.Column():
164
  out_json = gr.JSON(label="Clinical Report")
165
  out_img = gr.Image(label="Lesion Map")
166
+
167
  btn.click(segment_stroke, inputs=inp, outputs=[out_json, out_img])
168
 
169
  if __name__ == "__main__":