ALYYAN commited on
Commit
4f56e85
·
unverified ·
1 Parent(s): d8f7fc7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -40
app.py CHANGED
@@ -1,9 +1,10 @@
1
- # app.py (Final UI Polish Version)
2
 
3
  import gradio as gr
4
  from pathlib import Path
5
  from huggingface_hub import snapshot_download
6
  import asyncio
 
7
 
8
  from app.prediction import PredictionPipeline
9
  from app.database import add_patient_record, get_all_records
@@ -13,6 +14,7 @@ prediction_pipeline = PredictionPipeline()
13
  HF_DATASET_REPO = "ALYYAN/chest-xray-pneumonia-samples"
14
  try:
15
  SAMPLE_IMAGE_DIR = Path(snapshot_download(repo_id=HF_DATASET_REPO, repo_type="dataset"))
 
16
  SAMPLE_IMAGES = [str(p) for p in list(SAMPLE_IMAGE_DIR.glob('*/*.jpeg'))]
17
  except Exception as e:
18
  print(f"Could not download sample images: {e}")
@@ -20,7 +22,7 @@ except Exception as e:
20
 
21
  # --- Core Logic (Async Functions) ---
22
  async def process_analysis(patient_name, patient_age, image_list, is_sample=False):
23
- if not is_sample and (not patient_name or patient_age is None or str(patient_age).strip() == ""):
24
  raise gr.Error("Patient Name and Age are required.")
25
  if not image_list:
26
  raise gr.Error("At least one image is required.")
@@ -39,12 +41,13 @@ async def process_analysis(patient_name, patient_age, image_list, is_sample=Fals
39
  confidences[final_pred] = final_conf
40
  confidences["NORMAL" if final_pred == "PNEUMONIA" else "PNEUMONIA"] = 1 - final_conf
41
 
42
- return [
 
43
  gr.update(visible=False), # uploader_column
44
  gr.update(visible=True), # results_column
45
  gr.update(value=result["watermarked_images"]), # result_images
46
  gr.update(value=confidences) # result_label
47
- ]
48
 
49
  async def refresh_history_table():
50
  records = await get_all_records()
@@ -63,9 +66,7 @@ css = """
63
  #app_subtitle { font-size: 1.2rem !important; color: #9CA3AF !important; margin-bottom: 2rem; }
64
  /* --- Layout, Spacing, and Component Styling --- */
65
  #main_container { gap: 2rem; }
66
- #results_gallery { height: 350px !important; }
67
- #results_gallery .gallery-item { height: 330px !important; max-height: 330px !important; padding: 0.25rem !important; background-color: #374151; border: 1px solid #374151 !important; }
68
- #results_gallery .gallery-item img { object-fit: contain !important; }
69
  #bottom_controls { max-width: 600px; margin: 2.5rem auto 1rem auto; }
70
  #bottom_controls .gr-accordion > .gr-block-label { text-align: center !important; display: block !important; }
71
  """
@@ -75,15 +76,18 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
75
  with gr.Column(elem_id="app_header"):
76
  gr.Markdown("# 🩺 Pneumonia Detection AI", elem_id="app_title")
77
  gr.Markdown("An AI-powered tool to assist in the diagnosis of pneumonia.", elem_id="app_subtitle")
 
78
  with gr.Row(elem_id="main_container"):
79
  with gr.Column(scale=1) as uploader_column:
80
  gr.Markdown("### Upload Patient X-Rays")
81
  image_input = gr.File(label="Upload up to 3 Images", file_count="multiple", file_types=["image"], type="filepath")
 
82
  with gr.Column(scale=2, visible=False) as results_column:
83
  gr.Markdown("### Analysis Results")
84
  result_images = gr.Gallery(label="Analyzed Images", columns=3, object_fit="contain", height=350, elem_id="results_gallery")
85
  result_label = gr.Label(label="Overall Prediction", num_top_classes=2)
86
  start_over_btn = gr.Button("Start New Analysis", variant="secondary")
 
87
  with gr.Group(visible=False) as patient_info_modal:
88
  gr.Markdown("## Enter Patient Details", elem_classes="text-center")
89
  patient_name_modal = gr.Textbox(label="Patient Name", placeholder="e.g., John Doe")
@@ -91,84 +95,79 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
91
  with gr.Row():
92
  submit_analysis_btn = gr.Button("Analyze Images", variant="primary")
93
  cancel_btn = gr.Button("Cancel", variant="stop")
 
94
  with gr.Column(elem_id="bottom_controls"):
95
  with gr.Accordion("About this Tool", open=False):
96
  gr.Markdown(
97
  """
98
  ### MLOps-Powered Pneumonia Detection
99
-
100
- This application demonstrates a complete, end-to-end MLOps pipeline for medical image classification. It leverages a state-of-the-art **Vision Transformer (ViT)** model, fine-tuned on a public dataset of chest X-ray images to distinguish between Normal and Pneumonia cases.
101
-
102
  ---
103
-
104
- **Key Features & Technologies:**
105
-
106
- * **Model:** Google's `vit-base-patch16-224-in21k`, fine-tuned for high accuracy.
107
- * **MLOps Pipeline:** Reproducible workflow managed by **DVC** for data versioning and **MLflow** for experiment tracking.
108
- * **Database:** Patient and prediction data is stored and managed in a **MongoDB** database for scalability.
109
- * **Frontend:** A responsive and interactive user interface built with **Gradio**.
110
- * **Deployment Ready:** The entire project is containerized and ready for deployment on platforms like Hugging Face Spaces.
111
-
112
- **Disclaimer:** This tool is for demonstration and educational purposes only and is **not a substitute for professional medical advice.**
113
-
114
- ---
115
-
116
- **Project Team:**
117
-
118
- * **Alyyan Ahmed** - (roles)
119
- * **Munim Akbar** - (roles)
120
  """
121
  )
122
  with gr.Row():
123
  samples_btn = gr.Button("Try Sample Images")
124
  history_btn = gr.Button("View Patient History")
 
125
  with gr.Column(visible=False) as history_page:
126
  gr.Markdown("# 📜 Patient Record History", elem_classes="app_title")
127
  with gr.Row():
128
  back_to_main_btn_hist = gr.Button("⬅️ Back to Main App")
129
  refresh_history_btn = gr.Button("Refresh History")
130
  history_df = gr.DataFrame(headers=["Name", "Age", "Prediction", "Confidence", "Date"], row_count=10, interactive=False)
 
131
  with gr.Column(visible=False) as samples_page:
132
  gr.Markdown("# 🖼️ Sample Image Library", elem_classes="app_title")
133
  gr.Markdown("Click an image to run an anonymous analysis.")
134
  back_to_main_btn_samp = gr.Button("⬅️ Back to Main App")
 
135
  sample_gallery = gr.Gallery(value=SAMPLE_IMAGES, label="Sample Images", columns=5, height=400)
136
 
137
  # --- Event Handling Logic ---
 
138
  def show_patient_info(files):
139
  return gr.update(visible=True) if files else gr.update(visible=False)
140
  image_input.upload(fn=show_patient_info, inputs=image_input, outputs=patient_info_modal)
141
-
142
  async def submit_and_hide_modal(name, age, files):
143
  analysis_results = await process_analysis(name, age, files)
144
- return [
145
- *analysis_results,
146
- gr.update(visible=False) # Hide the modal
147
- ]
148
- 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])
 
 
149
 
150
  cancel_btn.click(lambda: (gr.update(visible=False), None), None, [patient_info_modal, image_input])
151
  start_over_btn.click(fn=None, js="() => { window.location.reload(); }")
152
-
153
  async def handle_sample_click(evt: gr.SelectData):
154
- selected_path = evt.value
155
- analysis_results = await process_analysis("Sample User", 0, [selected_path], is_sample=True)
156
  return [
157
  gr.update(visible=True), # main_app
158
  gr.update(visible=False), # samples_page
159
- *analysis_results
160
  ]
161
  sample_gallery.select(handle_sample_click, None, [main_app, samples_page, uploader_column, results_column, result_images, result_label])
162
 
163
  all_pages = [main_app, history_page, samples_page]
 
164
  async def show_history_page_and_refresh():
165
  records_update = await refresh_history_table()
166
- return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), records_update]
 
 
 
 
 
167
  def show_samples_page():
168
  return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
169
  def show_main_page():
170
  return [gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)]
171
-
172
  history_btn.click(fn=show_history_page_and_refresh, outputs=all_pages + [history_df])
173
  samples_btn.click(fn=show_samples_page, outputs=all_pages)
174
  back_to_main_btn_hist.click(fn=show_main_page, outputs=all_pages)
@@ -179,4 +178,4 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
179
 
180
  # --- Launch the App ---
181
  if __name__ == "__main__":
182
- demo.launch()
 
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
 
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}")
 
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.")
 
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()
 
66
  #app_subtitle { font-size: 1.2rem !important; color: #9CA3AF !important; margin-bottom: 2rem; }
67
  /* --- Layout, Spacing, and Component Styling --- */
68
  #main_container { gap: 2rem; }
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
  """
 
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
  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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  """
109
  )
110
  with gr.Row():
111
  samples_btn = gr.Button("Try Sample Images")
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")
118
  refresh_history_btn = gr.Button("Refresh History")
119
  history_df = gr.DataFrame(headers=["Name", "Age", "Prediction", "Confidence", "Date"], row_count=10, interactive=False)
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)
 
178
 
179
  # --- Launch the App ---
180
  if __name__ == "__main__":
181
+ demo.launch()