hmgill commited on
Commit
46544ed
Β·
verified Β·
1 Parent(s): dda77e2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -68
app.py CHANGED
@@ -19,7 +19,7 @@ from google.adk.runners import InMemoryRunner
19
  from google.genai import types
20
 
21
  # Project Imports
22
- # Wrap imports to prevent immediate crash if dependencies are missing or slow to load
23
  try:
24
  from cellemetry import root_agent
25
  from cellemetry.config import AnalysisDeps
@@ -178,7 +178,6 @@ async def run_analysis(image_path_str, user_prompt, session_id_state):
178
  # Lazy Load: Ensure model is loaded before inference
179
  if not MODEL_CACHE["loaded"]:
180
  yield [], None, None, [], None, waiting_df, waiting_df, waiting_df, *empty_slider_updates
181
- # Load model synchronously if triggered here
182
  load_models()
183
 
184
  if not image_path_str:
@@ -359,79 +358,106 @@ async def unified_chat_handler(message, history, session_id, current_img_path):
359
  yield history, session_id, current_img_path, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), *empty_slider_updates, None, gr.update(), gr.update(), gr.update()
360
 
361
  # --- UI Layout ---
362
- with gr.Blocks(title="Cellemetry Agent") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  session_id_state = gr.State(None)
364
  current_image_path = gr.State(None)
365
 
366
- with gr.Row():
367
- with gr.Column(scale=1):
368
- chatbot = gr.Chatbot(
369
- label="Agent Conversation",
370
- height=600,
371
- value=[{"role": "assistant", "content": "πŸ‘‹ Welcome to Cellemetry! Upload a microscopy image and describe what you'd like to analyze."}],
372
- show_label=True
373
- # REMOVED: type="messages" (This caused the TypeError on older Gradio versions)
374
- )
375
- chat_input = gr.MultimodalTextbox(
376
- file_types=["image"],
377
- placeholder="Upload an image and describe your analysis...",
378
- show_label=False,
379
- submit_btn="Send"
380
- )
381
-
382
- with gr.Column(scale=2):
383
- with gr.Column(visible=True, elem_id="welcome-overlay") as welcome_overlay:
384
- gr.HTML(f"""
385
- <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 780px; padding: 40px; background: #f8f9fa; border-radius: 8px; border: 2px solid #3498db;">
386
- <div style="text-align: center;">
387
- <div style='text-align: center;'>
388
- <img src="https://raw.githubusercontent.com/hmgill/Cellemetry/main/logo.png" alt="Logo" style="height:200px; display: block; margin: 0 auto;">
389
- </div>
390
- <h2 style="color: #333; margin: 20px 0 10px; font-weight: 600; font-size: 28px;">Welcome to Cellemetry</h2>
391
- <p style="color: #666; font-size: 16px; max-width: 400px; margin: 0 auto 30px; line-height: 1.6;">Upload a microscopy image to get started with AI-powered cell analysis and segmentation</p>
392
- <div style="padding: 20px; background: #fff; border-radius: 8px; border-left: 4px solid #3498db; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
393
- <p style="color: #555; margin: 0; font-size: 14px;">πŸ‘ˆ Use the chat on the left to begin</p>
 
 
 
 
 
 
 
 
394
  </div>
395
  </div>
396
- </div>
397
- """
398
- )
399
-
400
- with gr.Column(visible=False, elem_id="loading-overlay") as loading_overlay:
401
- gr.HTML("""
402
- <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 780px; background: rgba(255, 255, 255, 0.95); border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
403
- <div style="text-align: center;">
404
- <div style="border: 8px solid #f3f3f3; border-top: 8px solid #3498db; border-radius: 50%; width: 60px; height: 60px; animation: spin 1s linear infinite; margin: 0 auto 20px;"></div>
405
- <h3 style="color: #555; margin: 0;">βš™οΈ Analysis in Progress</h3>
406
- <p style="color: #888; margin-top: 10px;">Please wait while we process your microscopy image...</p>
 
 
407
  </div>
408
- <style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>
409
- </div>
410
- """)
411
-
412
- with gr.Tabs(visible=False) as results_tabs:
413
- with gr.Tab("πŸ” Segmentation"):
414
- with gr.Row():
415
- with gr.Column(scale=3):
416
- overlay_output = gr.Image(label="Segmentation Result", height=780, type="pil")
417
- with gr.Column(scale=1):
418
- gr.Markdown("**Layer Controls**")
419
- layer_checkboxes = gr.CheckboxGroup(label="Visible Layers", choices=[], value=[], interactive=True)
420
- gr.Markdown("**Opacity Controls**")
421
- opacity_slider_1 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 1 Opacity", visible=False)
422
- opacity_slider_2 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 2 Opacity", visible=False)
423
- opacity_slider_3 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 3 Opacity", visible=False)
424
- opacity_slider_4 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 4 Opacity", visible=False)
425
 
426
- with gr.Tab("πŸ“Š Quantitative Results"):
427
- download_btn = gr.File(label="Download Excel Report")
428
- with gr.Tabs():
429
- with gr.Tab("Morphology"):
430
- tbl_morph = gr.Dataframe(interactive=False, wrap=True)
431
- with gr.Tab("Spatial"):
432
- tbl_spatial = gr.Dataframe(interactive=False, wrap=True)
433
- with gr.Tab("Relational"):
434
- tbl_rel = gr.Dataframe(interactive=False, wrap=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
  def regenerate_overlay_with_opacity(img_path, selected_layers, op1, op2, op3, op4):
437
  if not img_path or not selected_layers: return None
 
19
  from google.genai import types
20
 
21
  # Project Imports
22
+ # Wrap imports to prevent immediate crash if dependencies are missing
23
  try:
24
  from cellemetry import root_agent
25
  from cellemetry.config import AnalysisDeps
 
178
  # Lazy Load: Ensure model is loaded before inference
179
  if not MODEL_CACHE["loaded"]:
180
  yield [], None, None, [], None, waiting_df, waiting_df, waiting_df, *empty_slider_updates
 
181
  load_models()
182
 
183
  if not image_path_str:
 
358
  yield history, session_id, current_img_path, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), *empty_slider_updates, None, gr.update(), gr.update(), gr.update()
359
 
360
  # --- UI Layout ---
361
+
362
+ # CSS to handle margins and width consistency
363
+ custom_css = """
364
+ /* 1. Global Margin Setting */
365
+ #main_container {
366
+ margin-left: 20% !important;
367
+ margin-right: 20% !important;
368
+ width: auto !important;
369
+ }
370
+
371
+ /* 2. Fix Tab Width Consistency (Right Panel) */
372
+ /* We enforce a minimum width so the panel doesn't shrink when switching to empty dataframes */
373
+ .right-panel {
374
+ min-width: 600px !important;
375
+ flex-grow: 2 !important;
376
+ }
377
+ """
378
+
379
+ with gr.Blocks(title="Cellemetry Agent", css=custom_css) as demo:
380
  session_id_state = gr.State(None)
381
  current_image_path = gr.State(None)
382
 
383
+ # WRAPPER to apply 20% margins
384
+ with gr.Column(elem_id="main_container"):
385
+
386
+ with gr.Row():
387
+ # --- LEFT COLUMN (Chat) ---
388
+ with gr.Column(scale=1, min_width=300):
389
+ chatbot = gr.Chatbot(
390
+ label="Agent Conversation",
391
+ height=600,
392
+ value=[{"role": "assistant", "content": "πŸ‘‹ Welcome to Cellemetry! Upload a microscopy image and describe what you'd like to analyze."}],
393
+ show_label=True
394
+ )
395
+ chat_input = gr.MultimodalTextbox(
396
+ file_types=["image"],
397
+ placeholder="Upload an image and describe your analysis...",
398
+ show_label=False,
399
+ submit_btn="Send"
400
+ )
401
+
402
+ # --- RIGHT COLUMN (Results) ---
403
+ # Added 'right-panel' class for CSS width enforcement
404
+ with gr.Column(scale=2, elem_classes=["right-panel"]):
405
+
406
+ # Welcome overlay
407
+ with gr.Column(visible=True, elem_id="welcome-overlay") as welcome_overlay:
408
+ gr.HTML(f"""
409
+ <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 780px; padding: 40px; background: #f8f9fa; border-radius: 8px; border: 2px solid #3498db;">
410
+ <div style="text-align: center;">
411
+ <div style='text-align: center;'>
412
+ <img src="https://raw.githubusercontent.com/hmgill/Cellemetry/main/logo.png" alt="Logo" style="height:200px; display: block; margin: 0 auto;">
413
+ </div>
414
+ <h2 style="color: #333; margin: 20px 0 10px; font-weight: 600; font-size: 28px;">Welcome to Cellemetry</h2>
415
+ <p style="color: #666; font-size: 16px; max-width: 400px; margin: 0 auto 30px; line-height: 1.6;">Upload a microscopy image to get started with AI-powered cell analysis and segmentation</p>
416
+ <div style="padding: 20px; background: #fff; border-radius: 8px; border-left: 4px solid #3498db; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
417
+ <p style="color: #555; margin: 0; font-size: 14px;">πŸ‘ˆ Use the chat on the left to begin</p>
418
+ </div>
419
  </div>
420
  </div>
421
+ """
422
+ )
423
+
424
+ # Loading overlay
425
+ with gr.Column(visible=False, elem_id="loading-overlay") as loading_overlay:
426
+ gr.HTML("""
427
+ <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 780px; background: rgba(255, 255, 255, 0.95); border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
428
+ <div style="text-align: center;">
429
+ <div style="border: 8px solid #f3f3f3; border-top: 8px solid #3498db; border-radius: 50%; width: 60px; height: 60px; animation: spin 1s linear infinite; margin: 0 auto 20px;"></div>
430
+ <h3 style="color: #555; margin: 0;">βš™οΈ Analysis in Progress</h3>
431
+ <p style="color: #888; margin-top: 10px;">Please wait while we process your microscopy image...</p>
432
+ </div>
433
+ <style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>
434
  </div>
435
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
 
437
+ # Results tabs
438
+ with gr.Tabs(visible=False) as results_tabs:
439
+ with gr.Tab("πŸ” Segmentation"):
440
+ with gr.Row():
441
+ with gr.Column(scale=3):
442
+ overlay_output = gr.Image(label="Segmentation Result", height=780, type="pil")
443
+ with gr.Column(scale=1):
444
+ gr.Markdown("**Layer Controls**")
445
+ layer_checkboxes = gr.CheckboxGroup(label="Visible Layers", choices=[], value=[], interactive=True)
446
+ gr.Markdown("**Opacity Controls**")
447
+ opacity_slider_1 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 1 Opacity", visible=False)
448
+ opacity_slider_2 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 2 Opacity", visible=False)
449
+ opacity_slider_3 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 3 Opacity", visible=False)
450
+ opacity_slider_4 = gr.Slider(minimum=0, maximum=1, value=0.6, step=0.1, label="Layer 4 Opacity", visible=False)
451
+
452
+ with gr.Tab("πŸ“Š Quantitative Results"):
453
+ download_btn = gr.File(label="Download Excel Report")
454
+ with gr.Tabs():
455
+ with gr.Tab("Morphology"):
456
+ tbl_morph = gr.Dataframe(interactive=False, wrap=True)
457
+ with gr.Tab("Spatial"):
458
+ tbl_spatial = gr.Dataframe(interactive=False, wrap=True)
459
+ with gr.Tab("Relational"):
460
+ tbl_rel = gr.Dataframe(interactive=False, wrap=True)
461
 
462
  def regenerate_overlay_with_opacity(img_path, selected_layers, op1, op2, op3, op4):
463
  if not img_path or not selected_layers: return None