ALYYAN commited on
Commit
c695a1d
·
unverified ·
1 Parent(s): b1f0ee6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -39
app.py CHANGED
@@ -1,29 +1,23 @@
1
- # app.py (The Definitive Final Version)
2
 
3
  import gradio as gr
4
  from pathlib import Path
5
  import asyncio
6
- from PIL import Image
7
 
8
- # Import backend components from the 'app' folder
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
- # Point to the locally cloned sample images directory from setup.sh
15
  SAMPLE_IMAGE_DIR = Path("sample_images")
16
  try:
17
  if SAMPLE_IMAGE_DIR.is_dir():
18
- # Separate the lists of images for the two-column layout
19
  NORMAL_SAMPLES = [str(p) for p in sorted(list((SAMPLE_IMAGE_DIR / 'NORMAL').glob('*.jpeg')))]
20
  PNEUMONIA_SAMPLES = [str(p) for p in sorted(list((SAMPLE_IMAGE_DIR / 'PNEUMONIA').glob('*.jpeg')))]
21
- else:
22
- raise FileNotFoundError
23
  except FileNotFoundError:
24
- print("Warning: 'sample_images' directory not found or is empty. Please check setup.sh. Samples will be unavailable.")
25
- NORMAL_SAMPLES, PNEUMONIA_SAMPLES = [], []
26
-
27
 
28
  # --- Core Logic (Async Functions) ---
29
  async def process_analysis(patient_name, patient_age, image_list):
@@ -71,12 +65,12 @@ async def refresh_history_table():
71
  css = """
72
  /* --- Professional Dark Theme & Fonts --- */
73
  :root { --primary-hue: 220 !important; --secondary-hue: 210 !important; --neutral-hue: 210 !important; --body-background-fill: #111827 !important; --block-background-fill: #1F2337 !important; --block-border-width: 1px !important; --border-color-accent: #374151 !important; --background-fill-secondary: #1F2937 !important;}
74
- /* --- Header & Title Styling --- */
75
- #app_header { text-align: center; max-width: 900px; margin: 0 auto; }
76
- #app_title { font-size: 3rem !important; font-weight: 800 !important; color: #FFFFFF !important; padding-top: 1rem; }
77
  #app_subtitle { font-size: 1.25rem !important; color: #9CA3AF !important; margin-bottom: 2rem; }
78
  /* --- Layout and Spacing --- */
79
- #main_container { gap: 2rem; max-width: 700px; margin: 0 auto; }
80
  #results_gallery .gallery-item { padding: 0.25rem !important; background-color: #374151; border: 1px solid #374151 !important; }
81
  #bottom_controls { max-width: 500px; margin: 2.5rem auto 1rem auto; }
82
  """
@@ -114,14 +108,12 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
114
  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.
115
 
116
  **Disclaimer:** This tool is for demonstration and educational purposes only and is **not a substitute for professional medical advice.**
117
-
118
  ---
119
-
120
  **Project Team:**
121
  * **Alyyan Ahmed** - ML Engineer & Developer
122
  * **Munim Akbar** - ML Engineer & Developer
123
  """
124
- )
125
  with gr.Row():
126
  samples_btn = gr.Button("Try Sample Images")
127
  history_btn = gr.Button("View Patient History")
@@ -133,48 +125,50 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="blue")
133
  refresh_history_btn = gr.Button("Refresh History")
134
  history_df = gr.DataFrame(headers=["Name", "Age", "Prediction", "Confidence", "Date"], row_count=10, interactive=False)
135
 
 
136
  with gr.Column(visible=False) as samples_page:
137
  gr.Markdown("# 🖼️ Sample Image Library", elem_classes="app_title")
138
- gr.Markdown("You can download these sample images to test the tool on the main page.")
139
  back_to_main_btn_samp = gr.Button("⬅️ Back to Main App")
140
 
141
  with gr.Row():
142
  with gr.Column():
143
  gr.Markdown("### Normal Cases")
144
- for img_path in NORMAL_SAMPLES:
145
- gr.File(value=img_path, label=Path(img_path).name, interactive=False)
 
 
 
 
 
 
146
 
147
  with gr.Column():
148
  gr.Markdown("### Pneumonia Cases")
149
- for img_path in PNEUMONIA_SAMPLES:
150
- gr.File(value=img_path, label=Path(img_path).name, interactive=False)
151
-
152
- # --- Event Handling Logic ---
 
 
 
 
153
 
154
- def show_patient_info(files):
155
- return gr.update(visible=True) if files else gr.update(visible=False)
156
  image_input.upload(fn=show_patient_info, inputs=image_input, outputs=patient_info_modal)
157
-
158
  async def submit_and_hide_modal(name, age, files):
159
- analysis_results = await process_analysis(name, age, files)
160
- return [*analysis_results, gr.update(visible=False)]
161
  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])
162
-
163
  cancel_btn.click(lambda: (gr.update(visible=False), None), None, [patient_info_modal, image_input])
164
  start_over_btn.click(fn=None, js="() => { window.location.reload(); }")
165
 
166
  all_pages = [main_app, history_page, samples_page]
167
-
168
  async def show_history_page_and_refresh():
169
- records_update = await refresh_history_table()
170
- return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), records_update]
171
-
172
- def show_samples_page():
173
- return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
174
 
175
- def show_main_page():
176
- return [gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)]
177
-
178
  history_btn.click(fn=show_history_page_and_refresh, outputs=all_pages + [history_df])
179
  samples_btn.click(fn=show_samples_page, outputs=all_pages)
180
  back_to_main_btn_hist.click(fn=show_main_page, outputs=all_pages)
 
1
+ # app.py (The Final Polished Version)
2
 
3
  import gradio as gr
4
  from pathlib import Path
5
  import asyncio
 
6
 
7
+ # Import backend components
8
  from app.prediction import PredictionPipeline
9
  from app.database import add_patient_record, get_all_records
10
 
11
  # --- Initialization ---
12
  prediction_pipeline = PredictionPipeline()
 
13
  SAMPLE_IMAGE_DIR = Path("sample_images")
14
  try:
15
  if SAMPLE_IMAGE_DIR.is_dir():
 
16
  NORMAL_SAMPLES = [str(p) for p in sorted(list((SAMPLE_IMAGE_DIR / 'NORMAL').glob('*.jpeg')))]
17
  PNEUMONIA_SAMPLES = [str(p) for p in sorted(list((SAMPLE_IMAGE_DIR / 'PNEUMONIA').glob('*.jpeg')))]
18
+ else: raise FileNotFoundError
 
19
  except FileNotFoundError:
20
+ print("Warning: 'sample_images' directory not found."); NORMAL_SAMPLES, PNEUMONIA_SAMPLES = [], []
 
 
21
 
22
  # --- Core Logic (Async Functions) ---
23
  async def process_analysis(patient_name, patient_age, image_list):
 
65
  css = """
66
  /* --- Professional Dark Theme & Fonts --- */
67
  :root { --primary-hue: 220 !important; --secondary-hue: 210 !important; --neutral-hue: 210 !important; --body-background-fill: #111827 !important; --block-background-fill: #1F2337 !important; --block-border-width: 1px !important; --border-color-accent: #374151 !important; --background-fill-secondary: #1F2937 !important;}
68
+ /* --- Header & Title Styling (THE FIX) --- */
69
+ #app_header { text-align: center; max-width: 1000px; margin: 0 auto; }
70
+ #app_title { font-size: 3.2rem !important; font-weight: 800 !important; color: #FFFFFF !important; padding-top: 1rem; }
71
  #app_subtitle { font-size: 1.25rem !important; color: #9CA3AF !important; margin-bottom: 2rem; }
72
  /* --- Layout and Spacing --- */
73
+ #main_container { gap: 2rem; max-width: 800px; margin: 0 auto; }
74
  #results_gallery .gallery-item { padding: 0.25rem !important; background-color: #374151; border: 1px solid #374151 !important; }
75
  #bottom_controls { max-width: 500px; margin: 2.5rem auto 1rem auto; }
76
  """
 
108
  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.
109
 
110
  **Disclaimer:** This tool is for demonstration and educational purposes only and is **not a substitute for professional medical advice.**
 
111
  ---
 
112
  **Project Team:**
113
  * **Alyyan Ahmed** - ML Engineer & Developer
114
  * **Munim Akbar** - ML Engineer & Developer
115
  """
116
+ ) # Professional description here
117
  with gr.Row():
118
  samples_btn = gr.Button("Try Sample Images")
119
  history_btn = gr.Button("View Patient History")
 
125
  refresh_history_btn = gr.Button("Refresh History")
126
  history_df = gr.DataFrame(headers=["Name", "Age", "Prediction", "Confidence", "Date"], row_count=10, interactive=False)
127
 
128
+ # --- SAMPLES PAGE (DEFINITIVE REDESIGN) ---
129
  with gr.Column(visible=False) as samples_page:
130
  gr.Markdown("# 🖼️ Sample Image Library", elem_classes="app_title")
131
+ gr.Markdown("You can right-click and 'Save Image As...' to download these samples for testing on the main page.")
132
  back_to_main_btn_samp = gr.Button("⬅️ Back to Main App")
133
 
134
  with gr.Row():
135
  with gr.Column():
136
  gr.Markdown("### Normal Cases")
137
+ # Use a Gallery to display the images visually
138
+ gr.Gallery(
139
+ value=NORMAL_SAMPLES,
140
+ label="Normal X-Rays",
141
+ columns=5,
142
+ object_fit="cover", # 'cover' often looks better for galleries
143
+ height="auto"
144
+ )
145
 
146
  with gr.Column():
147
  gr.Markdown("### Pneumonia Cases")
148
+ # Use a Gallery for the pneumonia samples as well
149
+ gr.Gallery(
150
+ value=PNEUMONIA_SAMPLES,
151
+ label="Pneumonia X-Rays",
152
+ columns=5,
153
+ object_fit="cover",
154
+ height="auto"
155
+ )
156
 
157
+ # --- Event Handling Logic (Unchanged and Correct) ---
158
+ def show_patient_info(files): return gr.update(visible=True) if files else gr.update(visible=False)
159
  image_input.upload(fn=show_patient_info, inputs=image_input, outputs=patient_info_modal)
 
160
  async def submit_and_hide_modal(name, age, files):
161
+ analysis_results = await process_analysis(name, age, files); return [*analysis_results, gr.update(visible=False)]
 
162
  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])
 
163
  cancel_btn.click(lambda: (gr.update(visible=False), None), None, [patient_info_modal, image_input])
164
  start_over_btn.click(fn=None, js="() => { window.location.reload(); }")
165
 
166
  all_pages = [main_app, history_page, samples_page]
 
167
  async def show_history_page_and_refresh():
168
+ records_update = await refresh_history_table(); return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), records_update]
169
+ def show_samples_page(): return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
170
+ def show_main_page(): 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)