Saicharan21 commited on
Commit
207f36e
·
verified ·
1 Parent(s): 0197f27

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +174 -22
app.py CHANGED
@@ -95,9 +95,9 @@ def voice_chat(audio, history):
95
  history.append({"role":"assistant","content":"Voice error: "+str(e)})
96
  return history
97
 
98
- def analyze_piv_csv(file):
99
  if file is None:
100
- return None, "Please upload a PIV CSV file first."
101
  try:
102
  df = pd.read_csv(file.name)
103
  cols = [c.lower().strip() for c in df.columns]
@@ -214,11 +214,103 @@ def analyze_piv_csv(file):
214
  ai_text = chr(10)+"━"*25+chr(10)+"AI ANALYSIS:"+chr(10)+resp.choices[0].message.content
215
  except: pass
216
 
217
- return img, "PIV CSV LOADED: "+str(len(df))+" rows, "+str(len(df.columns))+" columns"+chr(10)+"Columns: "+", ".join(df.columns.tolist())+ai_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  except Exception as e:
219
- return None, "Error: "+str(e)
220
 
221
- def analyze_tgt_csv(file):
222
  if file is None:
223
  return None, "Please upload a TGT CSV file first."
224
  try:
@@ -299,9 +391,59 @@ def analyze_tgt_csv(file):
299
  ai_text = chr(10)+"━"*25+chr(10)+"AI ASSESSMENT:"+chr(10)+resp.choices[0].message.content
300
  except: pass
301
 
302
- return img, "TGT CSV LOADED: "+str(len(df))+" rows"+chr(10)+"Columns: "+", ".join(df.columns.tolist())+ai_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  except Exception as e:
304
- return None, "Error: "+str(e)
305
 
306
  def analyze_upad_photo(image):
307
  if image is None: return None, "Upload a uPAD photo first."
@@ -398,28 +540,38 @@ with gr.Blocks(title="CardioLab AI", css=CSS) as demo:
398
  search_input.submit(quick_search, inputs=search_input, outputs=search_output)
399
 
400
  with gr.Tab("PIV CSV"):
401
- gr.Markdown("### Upload PIV CSV file — AI generates 4 charts + clinical analysis")
402
  gr.Markdown("CSV columns: **time, velocity, shear_stress** (any column names work)")
403
  with gr.Row():
404
- with gr.Column(scale=1):
405
- piv_file = gr.File(label="CLICK HERE TO UPLOAD PIV CSV", file_types=[".csv"])
406
- piv_btn = gr.Button("Analyze PIV Data", variant="primary")
407
- piv_result = gr.Textbox(label="AI Analysis", lines=10)
408
- with gr.Column(scale=2):
409
- piv_chart = gr.Image(label="PIV Charts", type="pil")
410
- piv_btn.click(analyze_piv_csv, inputs=piv_file, outputs=[piv_chart, piv_result])
 
 
 
 
 
411
 
412
  with gr.Tab("TGT CSV"):
413
  gr.Markdown("### Upload TGT CSV file — AI generates blood biomarker charts + thrombogenicity assessment")
414
  gr.Markdown("CSV columns: **time, TAT, PF12, hemoglobin, platelets** (any column names work)")
415
  with gr.Row():
416
- with gr.Column(scale=1):
417
- tgt_file = gr.File(label="CLICK HERE TO UPLOAD TGT CSV", file_types=[".csv"])
418
- tgt_btn = gr.Button("Analyze TGT Data", variant="primary")
419
- tgt_result = gr.Textbox(label="AI Assessment", lines=10)
420
- with gr.Column(scale=2):
421
- tgt_chart = gr.Image(label="TGT Blood Charts", type="pil")
422
- tgt_btn.click(analyze_tgt_csv, inputs=tgt_file, outputs=[tgt_chart, tgt_result])
 
 
 
 
 
423
 
424
  with gr.Tab("uPAD Photo"):
425
  gr.Markdown("### Upload uPAD Photo — Instant CKD diagnosis from Jaffe reaction color")
 
95
  history.append({"role":"assistant","content":"Voice error: "+str(e)})
96
  return history
97
 
98
+ def analyze_piv_csv(file, theme="White"):
99
  if file is None:
100
+ return None, None, None, None, "Please upload a PIV CSV file first."
101
  try:
102
  df = pd.read_csv(file.name)
103
  cols = [c.lower().strip() for c in df.columns]
 
214
  ai_text = chr(10)+"━"*25+chr(10)+"AI ANALYSIS:"+chr(10)+resp.choices[0].message.content
215
  except: pass
216
 
217
+ # Generate 4 separate charts
218
+ bg = "#ffffff" if theme=="White" else "#0a1628"
219
+ fg = "#1a202c" if theme=="White" else "white"
220
+ grid_color = "#e2e8f0" if theme=="White" else "#2d4a8a"
221
+ ax_color = "#4a5568" if theme=="White" else "#a8b2d8"
222
+ plot_bg = "#f7fafc" if theme=="White" else "#132340"
223
+
224
+ def make_single_chart(plot_fn, title):
225
+ fig2, ax = plt.subplots(figsize=(8, 5))
226
+ fig2.patch.set_facecolor(bg)
227
+ ax.set_facecolor(plot_bg)
228
+ plot_fn(ax)
229
+ ax.set_title(title, color=fg, fontweight="bold", fontsize=14, pad=10)
230
+ ax.tick_params(colors=ax_color, labelsize=11)
231
+ ax.grid(True, alpha=0.3, color=grid_color, linestyle="--")
232
+ for spine in ["top","right"]: ax.spines[spine].set_visible(False)
233
+ for spine in ["bottom","left"]: ax.spines[spine].set_color(grid_color)
234
+ plt.tight_layout()
235
+ buf2 = io.BytesIO()
236
+ plt.savefig(buf2, format="png", facecolor=bg, bbox_inches="tight", dpi=130)
237
+ buf2.seek(0)
238
+ result = Image.open(buf2).copy()
239
+ plt.close()
240
+ return result
241
+
242
+ x = np.arange(len(df))
243
+ vel_col2 = next((c for c in cols if any(k in c for k in ["vel","speed","v_mag"])), num_cols[0] if num_cols else None)
244
+ shear_col2 = next((c for c in cols if any(k in c for k in ["shear","stress","tau","wss"])), num_cols[1] if len(num_cols)>1 else None)
245
+ time_col2 = next((c for c in cols if "time" in c or "frame" in c), None)
246
+ x_vals2 = df[time_col2] if time_col2 else x
247
+
248
+ def plot_velocity(ax):
249
+ if vel_col2:
250
+ ax.plot(x_vals2, df[vel_col2], color="#e63946", linewidth=2.5, marker="o", markersize=5)
251
+ ax.fill_between(x_vals2, df[vel_col2], alpha=0.2, color="#e63946")
252
+ ax.axhline(y=2.0, color="#f59e0b", linestyle="--", linewidth=2, label="Risk: 2.0 m/s")
253
+ ax.set_ylabel("Velocity (m/s)", color=ax_color, fontsize=12)
254
+ ax.set_xlabel(time_col2 or "Sample", color=ax_color, fontsize=12)
255
+ ax.legend(fontsize=10, labelcolor=fg, facecolor=plot_bg)
256
+
257
+ def plot_shear(ax):
258
+ if shear_col2:
259
+ xp = x_vals2.values if time_col2 else x
260
+ ax.plot(xp, df[shear_col2], color="#4361ee", linewidth=2.5, marker="s", markersize=5)
261
+ ax.fill_between(xp, df[shear_col2], alpha=0.2, color="#4361ee")
262
+ ax.axhline(y=5, color="#f59e0b", linestyle="--", linewidth=2, label="Caution: 5 Pa")
263
+ ax.axhline(y=10, color="#e63946", linestyle="--", linewidth=2, label="High risk: 10 Pa")
264
+ ax.set_ylabel("Shear Stress (Pa)", color=ax_color, fontsize=12)
265
+ ax.set_xlabel(time_col2 or "Sample", color=ax_color, fontsize=12)
266
+ ax.legend(fontsize=10, labelcolor=fg, facecolor=plot_bg)
267
+
268
+ def plot_scatter(ax):
269
+ if vel_col2 and shear_col2:
270
+ sc = ax.scatter(df[vel_col2], df[shear_col2], c=x, cmap="RdYlGn_r", s=100, edgecolors=fg, linewidth=0.5, zorder=5)
271
+ cb = plt.colorbar(sc, ax=ax, label="Time")
272
+ cb.ax.yaxis.label.set_color(fg)
273
+ cb.ax.tick_params(colors=ax_color)
274
+ ax.axvline(x=2.0, color="#f59e0b", linestyle="--", linewidth=2, label="Vel risk: 2.0")
275
+ ax.axhline(y=10, color="#e63946", linestyle="--", linewidth=2, label="Shear risk: 10")
276
+ ax.set_xlabel("Velocity (m/s)", color=ax_color, fontsize=12)
277
+ ax.set_ylabel("Shear Stress (Pa)", color=ax_color, fontsize=12)
278
+ ax.legend(fontsize=10, labelcolor=fg, facecolor=plot_bg)
279
+
280
+ def plot_summary(ax):
281
+ ax.axis("off")
282
+ risk = []
283
+ stats = "CLINICAL SUMMARY"+chr(10)+"━"*22+chr(10)+chr(10)
284
+ for col in num_cols[:3]:
285
+ mn = round(df[col].mean(),3)
286
+ mx = round(df[col].max(),3)
287
+ mn_v = round(df[col].min(),3)
288
+ stats += col[:14]+":"+chr(10)+" Mean: "+str(mn)+chr(10)+" Max: "+str(mx)+chr(10)+" Min: "+str(mn_v)+chr(10)+chr(10)
289
+ if "vel" in col and mx > 2.0: risk.append("HIGH VELOCITY (>2.0 m/s)")
290
+ if "shear" in col and mx > 10: risk.append("HIGH SHEAR (>10 Pa)")
291
+ stats += "━"*22+chr(10)
292
+ if risk:
293
+ stats += "RISK FLAGS:"+chr(10)
294
+ for r in risk: stats += " ⚠ "+r+chr(10)
295
+ stats += chr(10)+"OVERALL: HIGH RISK"
296
+ border_color = "#e63946"
297
+ else:
298
+ stats += "STATUS: All values normal"+chr(10)+"OVERALL: LOW RISK"
299
+ border_color = "#2ecc71"
300
+ ax.text(0.05, 0.97, stats, transform=ax.transAxes, color=fg, fontsize=11,
301
+ va="top", fontfamily="monospace",
302
+ bbox=dict(boxstyle="round,pad=0.8", facecolor=plot_bg, edgecolor=border_color, linewidth=2.5))
303
+
304
+ img1 = make_single_chart(plot_velocity, "Velocity Profile")
305
+ img2 = make_single_chart(plot_shear, "Wall Shear Stress")
306
+ img3 = make_single_chart(plot_scatter, "Velocity vs Shear Stress")
307
+ img4 = make_single_chart(plot_summary, "Clinical Summary")
308
+
309
+ return img1, img2, img3, img4, "PIV CSV LOADED: "+str(len(df))+" rows | Columns: "+", ".join(df.columns.tolist())+ai_text
310
  except Exception as e:
311
+ return None, None, None, None, "Error: "+str(e)
312
 
313
+ def analyze_tgt_csv(file, theme="White"):
314
  if file is None:
315
  return None, "Please upload a TGT CSV file first."
316
  try:
 
391
  ai_text = chr(10)+"━"*25+chr(10)+"AI ASSESSMENT:"+chr(10)+resp.choices[0].message.content
392
  except: pass
393
 
394
+ bg = "#ffffff" if theme=="White" else "#0a1628"
395
+ fg = "#1a202c" if theme=="White" else "white"
396
+ grid_color = "#e2e8f0" if theme=="White" else "#2d4a8a"
397
+ ax_color = "#4a5568" if theme=="White" else "#a8b2d8"
398
+ plot_bg = "#f7fafc" if theme=="White" else "#132340"
399
+
400
+ def make_tgt_chart(data_col, color, ylabel, limit, limit_label, title, chart_type="line"):
401
+ fig2, ax = plt.subplots(figsize=(8, 5))
402
+ fig2.patch.set_facecolor(bg)
403
+ ax.set_facecolor(plot_bg)
404
+ if data_col and data_col in df.columns:
405
+ xp = df[time_col].values if time_col else range(len(df))
406
+ yp = df[data_col].values
407
+ if chart_type == "bar":
408
+ bars = ax.bar(range(len(yp)), yp, color=color, alpha=0.85, edgecolor=bg, width=0.6)
409
+ for bar, val in zip(bars, yp):
410
+ ax.text(bar.get_x()+bar.get_width()/2, bar.get_height()+0.5, str(round(val,1)),
411
+ ha="center", va="bottom", color=fg, fontsize=10, fontweight="bold")
412
+ else:
413
+ ax.plot(xp, yp, color=color, linewidth=3, marker="o", markersize=8)
414
+ ax.fill_between(xp, yp, alpha=0.2, color=color)
415
+ for i,(xi,yi) in enumerate(zip(xp,yp)):
416
+ ax.annotate(str(round(yi,1)), (xi,yi), textcoords="offset points",
417
+ xytext=(0,10), ha="center", color=fg, fontsize=10, fontweight="bold")
418
+ ax.axhline(y=limit, color="#f59e0b", linestyle="--", linewidth=2.5, label=limit_label)
419
+ ax.legend(fontsize=11, labelcolor=fg, facecolor=plot_bg)
420
+ ax.set_ylabel(ylabel, color=ax_color, fontsize=12)
421
+ ax.set_xlabel(time_col or "Sample", color=ax_color, fontsize=12)
422
+ mean_val = round(float(np.mean(yp)),2)
423
+ max_val = round(float(np.max(yp)),2)
424
+ status = "HIGH" if max_val > limit else "NORMAL"
425
+ ax.set_title(title+chr(10)+"Mean: "+str(mean_val)+" Max: "+str(max_val)+" Status: "+status,
426
+ color=fg, fontweight="bold", fontsize=12, pad=8)
427
+ ax.tick_params(colors=ax_color, labelsize=11)
428
+ ax.grid(True, alpha=0.3, color=grid_color, linestyle="--")
429
+ for spine in ["top","right"]: ax.spines[spine].set_visible(False)
430
+ for spine in ["bottom","left"]: ax.spines[spine].set_color(grid_color)
431
+ plt.tight_layout()
432
+ buf2 = io.BytesIO()
433
+ plt.savefig(buf2, format="png", facecolor=bg, bbox_inches="tight", dpi=130)
434
+ buf2.seek(0)
435
+ result = Image.open(buf2).copy()
436
+ plt.close()
437
+ return result
438
+
439
+ img1 = make_tgt_chart(tat_col, "#e63946", "TAT (ng/mL)", 8, "Normal limit: 8 ng/mL", "Thrombin-Antithrombin (TAT)")
440
+ img2 = make_tgt_chart(pf_col, "#4361ee", "PF1.2 (nmol/L)", 2.0, "Normal limit: 2.0", "Prothrombin Fragment PF1.2")
441
+ img3 = make_tgt_chart(hemo_col, "#2ecc71", "Free Hemoglobin (mg/L)", 20, "Normal limit: 20 mg/L", "Free Hemoglobin - Hemolysis", "bar")
442
+ img4 = make_tgt_chart(plt_col, "#e67e22", "Platelet Count (10³/μL)", 150, "Normal minimum: 150", "Platelet Count")
443
+
444
+ return img1, img2, img3, img4, "TGT CSV LOADED: "+str(len(df))+" rows | Columns: "+", ".join(df.columns.tolist())+ai_text
445
  except Exception as e:
446
+ return None, None, None, None, "Error: "+str(e)
447
 
448
  def analyze_upad_photo(image):
449
  if image is None: return None, "Upload a uPAD photo first."
 
540
  search_input.submit(quick_search, inputs=search_input, outputs=search_output)
541
 
542
  with gr.Tab("PIV CSV"):
543
+ gr.Markdown("### Upload PIV CSV file — AI generates separate charts + clinical analysis")
544
  gr.Markdown("CSV columns: **time, velocity, shear_stress** (any column names work)")
545
  with gr.Row():
546
+ piv_file = gr.File(label="CLICK HERE TO UPLOAD PIV CSV", file_types=[".csv"], scale=3)
547
+ piv_theme = gr.Radio(["Dark", "White"], value="White", label="Chart Theme", scale=1)
548
+ piv_btn = gr.Button("Analyze PIV Data", variant="primary")
549
+ piv_result = gr.Textbox(label="AI Clinical Analysis", lines=6)
550
+ gr.Markdown("### Charts")
551
+ with gr.Row():
552
+ piv_chart1 = gr.Image(label="Velocity Profile", type="pil")
553
+ piv_chart2 = gr.Image(label="Shear Stress", type="pil")
554
+ with gr.Row():
555
+ piv_chart3 = gr.Image(label="Velocity vs Shear", type="pil")
556
+ piv_chart4 = gr.Image(label="Clinical Summary", type="pil")
557
+ piv_btn.click(analyze_piv_csv, inputs=[piv_file, piv_theme], outputs=[piv_chart1, piv_chart2, piv_chart3, piv_chart4, piv_result])
558
 
559
  with gr.Tab("TGT CSV"):
560
  gr.Markdown("### Upload TGT CSV file — AI generates blood biomarker charts + thrombogenicity assessment")
561
  gr.Markdown("CSV columns: **time, TAT, PF12, hemoglobin, platelets** (any column names work)")
562
  with gr.Row():
563
+ tgt_file = gr.File(label="CLICK HERE TO UPLOAD TGT CSV", file_types=[".csv"], scale=3)
564
+ tgt_theme = gr.Radio(["Dark", "White"], value="White", label="Chart Theme", scale=1)
565
+ tgt_btn = gr.Button("Analyze TGT Data", variant="primary")
566
+ tgt_result = gr.Textbox(label="AI Thrombogenicity Assessment", lines=6)
567
+ gr.Markdown("### Charts")
568
+ with gr.Row():
569
+ tgt_chart1 = gr.Image(label="TAT Over Time", type="pil")
570
+ tgt_chart2 = gr.Image(label="PF1.2 Over Time", type="pil")
571
+ with gr.Row():
572
+ tgt_chart3 = gr.Image(label="Free Hemoglobin", type="pil")
573
+ tgt_chart4 = gr.Image(label="Platelet Count", type="pil")
574
+ tgt_btn.click(analyze_tgt_csv, inputs=[tgt_file, tgt_theme], outputs=[tgt_chart1, tgt_chart2, tgt_chart3, tgt_chart4, tgt_result])
575
 
576
  with gr.Tab("uPAD Photo"):
577
  gr.Markdown("### Upload uPAD Photo — Instant CKD diagnosis from Jaffe reaction color")