KPrashanth commited on
Commit
fd8bc35
·
verified ·
1 Parent(s): 256b336

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -42
app.py CHANGED
@@ -2,8 +2,6 @@
2
 
3
  import gradio as gr
4
  from PIL import Image
5
- import numpy as np
6
-
7
 
8
  from pipeline import SmartCBC
9
 
@@ -13,44 +11,70 @@ from pipeline import SmartCBC
13
  cbc = SmartCBC() # loads YOLO + classifier once
14
 
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  # -------------------------------------------------
17
  # Core Gradio wrapper
18
  # -------------------------------------------------
19
  def analyze_images(images, age, gender, output_mode):
20
  """
21
- Wrapper for SmartCBC.analyze() or SmartCBC.analyze_batch()
22
- depending on whether 1 or multiple images are uploaded.
 
 
 
 
23
  """
 
24
  if images is None or len(images) == 0:
25
  return "Please upload at least one image.", None
26
 
27
- # Gradio Gallery sometimes returns list of tuples: (PIL.Image, metadata)
28
- def to_pil_list(img_list):
29
- pil_list = []
30
-
31
- for item in img_list:
32
- # Gallery may return (media, meta) or just media
33
- if isinstance(item, tuple):
34
- media = item[0]
35
- else:
36
- media = item
37
-
38
- # filepath string
39
- if isinstance(media, str):
40
- pil = Image.open(media).convert("RGB")
41
- # already a PIL Image
42
- elif isinstance(media, Image.Image):
43
- pil = media.convert("RGB")
44
- # numpy array
45
- elif isinstance(media, np.ndarray):
46
- pil = Image.fromarray(media).convert("RGB")
47
- else:
48
- raise ValueError(f"Unsupported gallery item type: {type(media)}")
49
-
50
- pil_list.append(pil)
51
-
52
- return pil_list
53
 
 
 
 
 
 
 
 
54
 
55
 
56
  # -------------------------------------------------
@@ -58,35 +82,40 @@ def analyze_images(images, age, gender, output_mode):
58
  # -------------------------------------------------
59
  with gr.Blocks(title="SmartCBC - Multimodal Blood Analysis") as demo:
60
 
61
- gr.Markdown("""
62
- # 🩸 SmartCBC — Multimodal AI Blood Smear Analysis
63
- Upload **one or multiple** peripheral smear FOV images and get:
 
 
64
  - RBC / WBC / Platelet counts
65
  - WBC subtype classification
66
  - Aggregated multi-FOV differential
67
  - Age-specific reference comparisons
68
  - Clinical insights (non-diagnostic)
69
- """)
 
70
 
71
  with gr.Row():
72
  img_in = gr.Gallery(
73
  label="Upload 1 or Multiple Blood Smear Images (FOVs)",
74
  columns=3,
75
  height="auto",
76
- allow_preview=True
 
 
77
  )
78
 
79
  with gr.Column():
80
  age_in = gr.Number(label="Age (years)", value=30)
81
  gender_in = gr.Dropdown(
82
- ["M", "F", ""],
83
  label="Gender (optional)",
84
  value=""
85
  )
86
  output_mode = gr.Radio(
87
  ["Text Report", "Structured JSON"],
88
  value="Text Report",
89
- label="Output Format"
90
  )
91
  btn = gr.Button("Analyze")
92
 
@@ -95,19 +124,19 @@ with gr.Blocks(title="SmartCBC - Multimodal Blood Analysis") as demo:
95
  label="Report (Human Readable)",
96
  visible=True,
97
  lines=30,
98
- interactive=False
99
  )
100
 
101
  json_out = gr.JSON(
102
  label="Structured Output (JSON)",
103
- visible=False
104
  )
105
 
106
- # Toggle visibility
107
  def toggle_output(mode):
108
  return (
109
  gr.update(visible=(mode == "Text Report")),
110
- gr.update(visible=(mode == "Structured JSON"))
111
  )
112
 
113
  output_mode.change(toggle_output, [output_mode], [txt_out, json_out])
@@ -116,7 +145,7 @@ with gr.Blocks(title="SmartCBC - Multimodal Blood Analysis") as demo:
116
  btn.click(
117
  analyze_images,
118
  inputs=[img_in, age_in, gender_in, output_mode],
119
- outputs=[txt_out, json_out]
120
  )
121
 
122
 
 
2
 
3
  import gradio as gr
4
  from PIL import Image
 
 
5
 
6
  from pipeline import SmartCBC
7
 
 
11
  cbc = SmartCBC() # loads YOLO + classifier once
12
 
13
 
14
+ # -------------------------------------------------
15
+ # Helper to normalize Gallery input
16
+ # -------------------------------------------------
17
+ def _normalize_gallery_images(images):
18
+ """
19
+ Gradio Gallery (type='pil') can return:
20
+ - list[PIL.Image]
21
+ - or list[(PIL.Image, metadata_dict)]
22
+
23
+ This function strips metadata if present and returns a flat list of images.
24
+ """
25
+ if images is None:
26
+ return []
27
+
28
+ normalized = []
29
+ for item in images:
30
+ # Sometimes (media, metadata), sometimes media only
31
+ if isinstance(item, tuple):
32
+ media = item[0]
33
+ else:
34
+ media = item
35
+ normalized.append(media)
36
+ return normalized
37
+
38
+
39
  # -------------------------------------------------
40
  # Core Gradio wrapper
41
  # -------------------------------------------------
42
  def analyze_images(images, age, gender, output_mode):
43
  """
44
+ Wrapper for SmartCBC.analyze().
45
+
46
+ - Accepts one or multiple images from a Gradio Gallery.
47
+ - Delegates to SmartCBC.analyze(), which auto-routes to analyze_batch()
48
+ if a list of images is provided.
49
+ - Returns either a human-readable text report or full JSON.
50
  """
51
+ # No images
52
  if images is None or len(images) == 0:
53
  return "Please upload at least one image.", None
54
 
55
+ # Normalize gallery output (strip metadata if any)
56
+ img_list = _normalize_gallery_images(images)
57
+
58
+ # If single image, send just that; if multiple, send list → analyze_batch
59
+ if len(img_list) == 1:
60
+ image_input = img_list[0]
61
+ else:
62
+ image_input = img_list
63
+
64
+ # Run SmartCBC pipeline
65
+ result = cbc.analyze(
66
+ image=image_input,
67
+ age=age,
68
+ gender=gender,
69
+ )
 
 
 
 
 
 
 
 
 
 
 
70
 
71
+ # Choose output mode
72
+ if output_mode == "Text Report":
73
+ # result["report_text"] is produced by build_api_response()
74
+ return result.get("report_text", "No report generated."), None
75
+ else:
76
+ # Show full structured JSON
77
+ return None, result
78
 
79
 
80
  # -------------------------------------------------
 
82
  # -------------------------------------------------
83
  with gr.Blocks(title="SmartCBC - Multimodal Blood Analysis") as demo:
84
 
85
+ gr.Markdown(
86
+ """
87
+ # 🩸 SmartCBC Multimodal AI Blood Smear Analysis
88
+
89
+ Upload **one or multiple** peripheral smear FOV images and get:
90
  - RBC / WBC / Platelet counts
91
  - WBC subtype classification
92
  - Aggregated multi-FOV differential
93
  - Age-specific reference comparisons
94
  - Clinical insights (non-diagnostic)
95
+ """
96
+ )
97
 
98
  with gr.Row():
99
  img_in = gr.Gallery(
100
  label="Upload 1 or Multiple Blood Smear Images (FOVs)",
101
  columns=3,
102
  height="auto",
103
+ allow_preview=True,
104
+ type="pil", # works with gradio==4.44.1
105
+ file_types=["image"] # ensure only images are selectable
106
  )
107
 
108
  with gr.Column():
109
  age_in = gr.Number(label="Age (years)", value=30)
110
  gender_in = gr.Dropdown(
111
+ ["", "M", "F"],
112
  label="Gender (optional)",
113
  value=""
114
  )
115
  output_mode = gr.Radio(
116
  ["Text Report", "Structured JSON"],
117
  value="Text Report",
118
+ label="Output Format",
119
  )
120
  btn = gr.Button("Analyze")
121
 
 
124
  label="Report (Human Readable)",
125
  visible=True,
126
  lines=30,
127
+ interactive=False,
128
  )
129
 
130
  json_out = gr.JSON(
131
  label="Structured Output (JSON)",
132
+ visible=False,
133
  )
134
 
135
+ # Toggle visibility based on output mode
136
  def toggle_output(mode):
137
  return (
138
  gr.update(visible=(mode == "Text Report")),
139
+ gr.update(visible=(mode == "Structured JSON")),
140
  )
141
 
142
  output_mode.change(toggle_output, [output_mode], [txt_out, json_out])
 
145
  btn.click(
146
  analyze_images,
147
  inputs=[img_in, age_in, gender_in, output_mode],
148
+ outputs=[txt_out, json_out],
149
  )
150
 
151