ALYYAN commited on
Commit
ca67a6f
·
unverified ·
1 Parent(s): 6c03139

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -59
app.py CHANGED
@@ -1,55 +1,46 @@
1
- # app.py (Final Version for Deployment)
2
 
3
  import gradio as gr
4
  from pathlib import Path
5
- from huggingface_hub import snapshot_download
6
  import asyncio
7
- import os
8
 
9
  from app.prediction import PredictionPipeline
10
  from app.database import add_patient_record, get_all_records
11
 
12
  # --- Initialization ---
13
  prediction_pipeline = PredictionPipeline()
14
- HF_DATASET_REPO = "ALYYAN/chest-xray-pneumonia-samples"
 
15
  try:
16
- SAMPLE_IMAGE_DIR = Path(snapshot_download(repo_id=HF_DATASET_REPO, repo_type="dataset"))
17
- # The value for a Gallery should be a list of file paths
18
  SAMPLE_IMAGES = [str(p) for p in list(SAMPLE_IMAGE_DIR.glob('*/*.jpeg'))]
19
- except Exception as e:
20
- print(f"Could not download sample images: {e}")
 
 
21
  SAMPLE_IMAGES = []
22
 
23
- # --- Core Logic (Async Functions) ---
 
24
  async def process_analysis(patient_name, patient_age, image_list, is_sample=False):
25
- if not is_sample and (not patient_name or patient_age is None):
 
26
  raise gr.Error("Patient Name and Age are required.")
27
  if not image_list:
28
  raise gr.Error("At least one image is required.")
29
-
30
  result = prediction_pipeline.predict(image_list)
31
  if "error" in result:
32
  raise gr.Error(result["error"])
33
-
34
  final_pred = result["final_prediction"]
35
  final_conf = result["final_confidence"]
36
-
37
  if not is_sample:
38
  await add_patient_record(str(patient_name), int(patient_age), final_pred, final_conf)
39
-
40
  confidences = {"NORMAL": 0.0, "PNEUMONIA": 0.0}
41
  confidences[final_pred] = final_conf
42
  confidences["NORMAL" if final_pred == "PNEUMONIA" else "PNEUMONIA"] = 1 - final_conf
43
-
44
- # Return updates for each component individually
45
- return (
46
- gr.update(visible=False), # uploader_column
47
- gr.update(visible=True), # results_column
48
- gr.update(value=result["watermarked_images"]), # result_images
49
- gr.update(value=confidences) # result_label
50
- )
51
 
52
  async def refresh_history_table():
 
53
  records = await get_all_records()
54
  data_for_df = []
55
  if records:
@@ -69,25 +60,26 @@ css = """
69
  #results_gallery .gallery-item { padding: 0.25rem !important; background-color: #374151; border: 1px solid #374151 !important; }
70
  #bottom_controls { max-width: 600px; margin: 2.5rem auto 1rem auto; }
71
  #bottom_controls .gr-accordion > .gr-block-label { text-align: center !important; display: block !important; }
 
 
 
72
  """
73
  with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue"), css=css, title="Pneumonia Detection AI") as demo:
74
 
75
  with gr.Column() as main_app:
 
76
  with gr.Column(elem_id="app_header"):
77
  gr.Markdown("# 🩺 Pneumonia Detection AI", elem_id="app_title")
78
  gr.Markdown("An AI-powered tool to assist in the diagnosis of pneumonia.", elem_id="app_subtitle")
79
-
80
  with gr.Row(elem_id="main_container"):
81
  with gr.Column(scale=1) as uploader_column:
82
  gr.Markdown("### Upload Patient X-Rays")
83
  image_input = gr.File(label="Upload up to 3 Images", file_count="multiple", file_types=["image"], type="filepath")
84
-
85
  with gr.Column(scale=2, visible=False) as results_column:
86
  gr.Markdown("### Analysis Results")
87
  result_images = gr.Gallery(label="Analyzed Images", columns=3, object_fit="contain", height=350, elem_id="results_gallery")
88
  result_label = gr.Label(label="Overall Prediction", num_top_classes=2)
89
  start_over_btn = gr.Button("Start New Analysis", variant="secondary")
90
-
91
  with gr.Group(visible=False) as patient_info_modal:
92
  gr.Markdown("## Enter Patient Details", elem_classes="text-center")
93
  patient_name_modal = gr.Textbox(label="Patient Name", placeholder="e.g., John Doe")
@@ -95,13 +87,11 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
95
  with gr.Row():
96
  submit_analysis_btn = gr.Button("Analyze Images", variant="primary")
97
  cancel_btn = gr.Button("Cancel", variant="stop")
98
-
99
  with gr.Column(elem_id="bottom_controls"):
100
  with gr.Accordion("About this Tool", open=False):
101
- gr.Markdown(
102
  """
103
  ### MLOps-Powered Pneumonia Detection
104
- This application demonstrates a complete, end-to-end MLOps pipeline for medical image classification...
105
  (Your professional description here)
106
  ---
107
  **Project Team:** Alyyan Ahmed & Munim Akbar
@@ -112,6 +102,7 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
112
  history_btn = gr.Button("View Patient History")
113
 
114
  with gr.Column(visible=False) as history_page:
 
115
  gr.Markdown("# 📜 Patient Record History", elem_classes="app_title")
116
  with gr.Row():
117
  back_to_main_btn_hist = gr.Button("⬅️ Back to Main App")
@@ -120,59 +111,65 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
120
 
121
  with gr.Column(visible=False) as samples_page:
122
  gr.Markdown("# 🖼️ Sample Image Library", elem_classes="app_title")
123
- gr.Markdown("Click an image to run an anonymous analysis.")
124
- back_to_main_btn_samp = gr.Button("⬅️ Back to Main App")
125
- # FIX: The value for a gallery is a list of file paths.
126
- sample_gallery = gr.Gallery(value=SAMPLE_IMAGES, label="Sample Images", columns=5, height=400)
127
-
 
 
 
 
 
 
 
 
 
128
  # --- Event Handling Logic ---
129
-
130
  def show_patient_info(files):
131
  return gr.update(visible=True) if files else gr.update(visible=False)
132
  image_input.upload(fn=show_patient_info, inputs=image_input, outputs=patient_info_modal)
133
 
134
  async def submit_and_hide_modal(name, age, files):
135
  analysis_results = await process_analysis(name, age, files)
136
- # Unpack the list of updates and add the modal update
137
  return [*analysis_results, gr.update(visible=False)]
138
- submit_analysis_btn.click(
139
- fn=submit_and_hide_modal,
140
- inputs=[patient_name_modal, patient_age_modal, image_input],
141
- outputs=[uploader_column, results_column, result_images, result_label, patient_info_modal]
142
- )
143
-
144
  cancel_btn.click(lambda: (gr.update(visible=False), None), None, [patient_info_modal, image_input])
145
  start_over_btn.click(fn=None, js="() => { window.location.reload(); }")
146
 
147
- async def handle_sample_click(evt: gr.SelectData):
148
- analysis_results = await process_analysis("Sample User", 0, [evt.value], is_sample=True)
149
- return [
150
- gr.update(visible=True), # main_app
151
- gr.update(visible=False), # samples_page
152
- *analysis_results
153
- ]
154
- sample_gallery.select(handle_sample_click, None, [main_app, samples_page, uploader_column, results_column, result_images, result_label])
155
-
 
 
 
 
 
 
 
 
 
 
 
156
  all_pages = [main_app, history_page, samples_page]
157
-
158
  async def show_history_page_and_refresh():
159
  records_update = await refresh_history_table()
160
- return [
161
- gr.update(visible=False),
162
- gr.update(visible=True),
163
- gr.update(visible=False),
164
- records_update
165
- ]
166
  def show_samples_page():
167
  return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
168
  def show_main_page():
169
  return [gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)]
170
-
171
  history_btn.click(fn=show_history_page_and_refresh, outputs=all_pages + [history_df])
172
  samples_btn.click(fn=show_samples_page, outputs=all_pages)
173
  back_to_main_btn_hist.click(fn=show_main_page, outputs=all_pages)
174
  back_to_main_btn_samp.click(fn=show_main_page, outputs=all_pages)
175
-
176
  refresh_history_btn.click(fn=refresh_history_table, outputs=history_df)
177
  demo.load(fn=refresh_history_table, outputs=history_df)
178
 
 
1
+ # app.py (Final Version with Local Samples and UI Fixes)
2
 
3
  import gradio as gr
4
  from pathlib import Path
 
5
  import asyncio
 
6
 
7
  from app.prediction import PredictionPipeline
8
  from app.database import add_patient_record, get_all_records
9
 
10
  # --- Initialization ---
11
  prediction_pipeline = PredictionPipeline()
12
+ # --- FIX: Point to the locally cloned sample images directory ---
13
+ SAMPLE_IMAGE_DIR = Path("sample_images")
14
  try:
 
 
15
  SAMPLE_IMAGES = [str(p) for p in list(SAMPLE_IMAGE_DIR.glob('*/*.jpeg'))]
16
+ if not SAMPLE_IMAGES:
17
+ print("Warning: 'sample_images' directory found, but it's empty.")
18
+ except FileNotFoundError:
19
+ print("Warning: 'sample_images' directory not found. Samples will be unavailable.")
20
  SAMPLE_IMAGES = []
21
 
22
+
23
+ # --- Core Logic (Async Functions are Correct) ---
24
  async def process_analysis(patient_name, patient_age, image_list, is_sample=False):
25
+ # ... (no changes needed in this function)
26
+ if not is_sample and (not patient_name or patient_age is None or str(patient_age).strip() == ""):
27
  raise gr.Error("Patient Name and Age are required.")
28
  if not image_list:
29
  raise gr.Error("At least one image is required.")
 
30
  result = prediction_pipeline.predict(image_list)
31
  if "error" in result:
32
  raise gr.Error(result["error"])
 
33
  final_pred = result["final_prediction"]
34
  final_conf = result["final_confidence"]
 
35
  if not is_sample:
36
  await add_patient_record(str(patient_name), int(patient_age), final_pred, final_conf)
 
37
  confidences = {"NORMAL": 0.0, "PNEUMONIA": 0.0}
38
  confidences[final_pred] = final_conf
39
  confidences["NORMAL" if final_pred == "PNEUMONIA" else "PNEUMONIA"] = 1 - final_conf
40
+ return [gr.update(visible=False), gr.update(visible=True), gr.update(value=result["watermarked_images"]), gr.update(value=confidences)]
 
 
 
 
 
 
 
41
 
42
  async def refresh_history_table():
43
+ # ... (no changes needed in this function)
44
  records = await get_all_records()
45
  data_for_df = []
46
  if records:
 
60
  #results_gallery .gallery-item { padding: 0.25rem !important; background-color: #374151; border: 1px solid #374151 !important; }
61
  #bottom_controls { max-width: 600px; margin: 2.5rem auto 1rem auto; }
62
  #bottom_controls .gr-accordion > .gr-block-label { text-align: center !important; display: block !important; }
63
+ /* --- FIX: Style the sample gallery for a cleaner look --- */
64
+ #sample_gallery { background-color: transparent !important; border: none !important; }
65
+ #sample_gallery .gallery-item { box-shadow: 0 0 5px rgba(0,0,0,0.5); border-radius: 8px !important; }
66
  """
67
  with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue"), css=css, title="Pneumonia Detection AI") as demo:
68
 
69
  with gr.Column() as main_app:
70
+ # ... (main app layout is the same)
71
  with gr.Column(elem_id="app_header"):
72
  gr.Markdown("# 🩺 Pneumonia Detection AI", elem_id="app_title")
73
  gr.Markdown("An AI-powered tool to assist in the diagnosis of pneumonia.", elem_id="app_subtitle")
 
74
  with gr.Row(elem_id="main_container"):
75
  with gr.Column(scale=1) as uploader_column:
76
  gr.Markdown("### Upload Patient X-Rays")
77
  image_input = gr.File(label="Upload up to 3 Images", file_count="multiple", file_types=["image"], type="filepath")
 
78
  with gr.Column(scale=2, visible=False) as results_column:
79
  gr.Markdown("### Analysis Results")
80
  result_images = gr.Gallery(label="Analyzed Images", columns=3, object_fit="contain", height=350, elem_id="results_gallery")
81
  result_label = gr.Label(label="Overall Prediction", num_top_classes=2)
82
  start_over_btn = gr.Button("Start New Analysis", variant="secondary")
 
83
  with gr.Group(visible=False) as patient_info_modal:
84
  gr.Markdown("## Enter Patient Details", elem_classes="text-center")
85
  patient_name_modal = gr.Textbox(label="Patient Name", placeholder="e.g., John Doe")
 
87
  with gr.Row():
88
  submit_analysis_btn = gr.Button("Analyze Images", variant="primary")
89
  cancel_btn = gr.Button("Cancel", variant="stop")
 
90
  with gr.Column(elem_id="bottom_controls"):
91
  with gr.Accordion("About this Tool", open=False):
92
+ gr.Markdown(
93
  """
94
  ### MLOps-Powered Pneumonia Detection
 
95
  (Your professional description here)
96
  ---
97
  **Project Team:** Alyyan Ahmed & Munim Akbar
 
102
  history_btn = gr.Button("View Patient History")
103
 
104
  with gr.Column(visible=False) as history_page:
105
+ # ... (history page layout is the same)
106
  gr.Markdown("# 📜 Patient Record History", elem_classes="app_title")
107
  with gr.Row():
108
  back_to_main_btn_hist = gr.Button("⬅️ Back to Main App")
 
111
 
112
  with gr.Column(visible=False) as samples_page:
113
  gr.Markdown("# 🖼️ Sample Image Library", elem_classes="app_title")
114
+ gr.Markdown("Select up to 3 images, then click 'Analyze Selected Samples'.")
115
+
116
+ # --- FIX: The Gallery component now reliably shows the local images ---
117
+ sample_gallery = gr.Gallery(
118
+ value=SAMPLE_IMAGES if SAMPLE_IMAGES else ["https://placehold.co/400x400/2F3136/FFFFFF/png?text=Samples\nNot+Found"],
119
+ label="Sample Images",
120
+ columns=5, height=400,
121
+ elem_id="sample_gallery"
122
+ )
123
+
124
+ with gr.Row():
125
+ analyze_samples_btn = gr.Button("Analyze Selected Samples", variant="primary")
126
+ back_to_main_btn_samp = gr.Button("⬅️ Back to Main App")
127
+
128
  # --- Event Handling Logic ---
129
+ # ... (event handlers for upload, modal, start over, are the same)
130
  def show_patient_info(files):
131
  return gr.update(visible=True) if files else gr.update(visible=False)
132
  image_input.upload(fn=show_patient_info, inputs=image_input, outputs=patient_info_modal)
133
 
134
  async def submit_and_hide_modal(name, age, files):
135
  analysis_results = await process_analysis(name, age, files)
 
136
  return [*analysis_results, gr.update(visible=False)]
137
+ submit_analysis_btn.click(fn=submit_and_hide_modal, inputs=[patient_name_modal, patient_age_modal, image_input], outputs=[uploader_column, results_column, result_images, result_label, patient_info_modal])
 
 
 
 
 
138
  cancel_btn.click(lambda: (gr.update(visible=False), None), None, [patient_info_modal, image_input])
139
  start_over_btn.click(fn=None, js="() => { window.location.reload(); }")
140
 
141
+ # --- Sample Page Logic ---
142
+ async def handle_sample_analysis(selected_images: list):
143
+ if not selected_images:
144
+ raise gr.Error("Please select at least one sample image to analyze.")
145
+ if len(selected_images) > 3:
146
+ raise gr.Error("Please select no more than 3 sample images.")
147
+
148
+ analysis_results = await process_analysis("Sample User", 0, selected_images, is_sample=True)
149
+
150
+ return {
151
+ main_app: gr.update(visible=True),
152
+ samples_page: gr.update(visible=False),
153
+ uploader_column: analysis_results[0],
154
+ results_column: analysis_results[1],
155
+ result_images: analysis_results[2],
156
+ result_label: analysis_results[3],
157
+ }
158
+ analyze_samples_btn.click(fn=handle_sample_analysis, inputs=[sample_gallery], outputs=[main_app, samples_page, uploader_column, results_column, result_images, result_label])
159
+
160
+ # ... (Page Navigation is the same)
161
  all_pages = [main_app, history_page, samples_page]
 
162
  async def show_history_page_and_refresh():
163
  records_update = await refresh_history_table()
164
+ return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), records_update]
 
 
 
 
 
165
  def show_samples_page():
166
  return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
167
  def show_main_page():
168
  return [gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)]
 
169
  history_btn.click(fn=show_history_page_and_refresh, outputs=all_pages + [history_df])
170
  samples_btn.click(fn=show_samples_page, outputs=all_pages)
171
  back_to_main_btn_hist.click(fn=show_main_page, outputs=all_pages)
172
  back_to_main_btn_samp.click(fn=show_main_page, outputs=all_pages)
 
173
  refresh_history_btn.click(fn=refresh_history_table, outputs=history_df)
174
  demo.load(fn=refresh_history_table, outputs=history_df)
175