try: import spaces except ImportError: class spaces: @staticmethod def GPU(func): return func import os import sys # Dynamic symlink and path configuration to support 'gemmasight' imports on Hugging Face Spaces _current_dir = os.path.dirname(os.path.abspath(__file__)) _symlink_path = os.path.join(_current_dir, "gemmasight") if not os.path.exists(_symlink_path): try: os.symlink(_current_dir, _symlink_path) except Exception: pass sys.path.insert(0, _current_dir) import gradio as gr import numpy as np from PIL import Image, ImageDraw from gemmasight.config import DATA_DIR from gemmasight.inference import GemmaSightInferencePipeline from gemmasight.utils.visualization import ( GRADIO_CUSTOM_CSS, SYSTEM_STATUS_CONSOLE, format_prediction_stat_html, format_retrieved_cases_html ) # 1. Initialize Pipeline # Run in Simulation/Fallback Mode by default to prevent OOM / missing gated weight crashes. # Will load real models if FORCE_SIMULATION is set to False in config.py or GPU is active. pipeline = GemmaSightInferencePipeline() # 2. Pre-generate interactive clinical examples EXAMPLES_DIR = os.path.join(DATA_DIR, "examples") os.makedirs(EXAMPLES_DIR, exist_ok=True) mss_example_path = os.path.join(EXAMPLES_DIR, "mss_example.png") msih_example_path = os.path.join(EXAMPLES_DIR, "msih_example.png") def generate_example_images(): """Generates two realistic looking synthetic H&E pathology images for demo purposes.""" if not os.path.exists(mss_example_path): # Create a pink/purple H&E stained looking patch (MSS) mss_img = Image.new("RGB", (224, 224), color=(220, 160, 200)) # Eosin pink base draw = ImageDraw.Draw(mss_img) # Draw some glandular/cellular structures for i in range(5): x, y = 30 + i*40, 40 + (i%2)*60 draw.ellipse([x, y, x+30, y+35], fill=(130, 80, 160), outline=(80, 40, 100), width=2) # Purple hematoxylin nuclei draw.ellipse([x+5, y+5, x+25, y+30], fill=(240, 210, 230)) # Lighter cytoplasm mss_img.save(mss_example_path) if not os.path.exists(msih_example_path): # Create a more hyper-cellular, infiltrated patch (MSI-High) msih_img = Image.new("RGB", (224, 224), color=(210, 150, 190)) draw = ImageDraw.Draw(msih_img) # Distorted glands for i in range(4): x, y = 20 + i*50, 30 + (i%3)*40 draw.ellipse([x, y, x+40, y+25], fill=(110, 60, 140), outline=(70, 30, 80), width=2) draw.ellipse([x+8, y+4, x+32, y+21], fill=(230, 190, 220)) # Draw tons of tiny dark purple dots representing Tumor-Infiltrating Lymphocytes (TILs) for _ in range(120): rx = np.random.randint(5, 219) ry = np.random.randint(5, 219) draw.ellipse([rx, ry, rx+3, ry+3], fill=(50, 20, 90)) # Deep blue/purple lymphocytes msih_img.save(msih_example_path) # Generate example patches generate_example_images() # 3. Main Gradio Inference Callback @spaces.GPU def run_clinical_pipeline(input_image): """ Inference callback triggered by Gradio. """ if input_image is None: return ( gr.update(value="

Error: Specimen image is required.

"), None, gr.update(value=""), "" ) try: # Run 5-phase diagnosis pipeline prob, label, heatmap, retrieved_cases, report = pipeline.run_diagnosis(input_image) # Format HTML widgets stat_html = format_prediction_stat_html(prob, label) retrieved_html = format_retrieved_cases_html(retrieved_cases) return stat_html, heatmap, retrieved_html, report except Exception as e: import traceback err_msg = f"Clinical Execution Error: {str(e)}\n\n{traceback.format_exc()}" print(err_msg) return ( gr.update(value=f"

Execution Error: {str(e)}

"), None, gr.update(value=""), f"An error occurred during pipeline execution:\n\n{str(e)}" ) # 4. Assemble Dashboard with gr.Blocks(title="GemmaSight - Clinical Multimodal Pathology Assistant", css=GRADIO_CUSTOM_CSS) as demo: # Title Header Block with gr.Row(elem_classes="clinical-header"): with gr.Column(): gr.HTML("

GemmaSight

") gr.HTML("

State-of-the-Art Multimodal AI Pathology Assistant for Colorectal Cancer MSI/MSS Status

") # System Status Console Bar gr.HTML(SYSTEM_STATUS_CONSOLE) # Main Body Layout (Sidebar + Two Result Columns) with gr.Row(): # LEFT COLUMN: Specimen Input & Settings with gr.Column(scale=1): gr.Markdown("### 📥 1. Specimen Acquisition") input_image = gr.Image( label="H&E-Stained Microscope Specimen Slide (224x224)", type="pil", sources=["upload", "clipboard"] ) run_btn = gr.Button("🔬 Run Multimodal Diagnosis", elem_classes="run-btn") # Interactive Examples Block gr.Examples( examples=[ [mss_example_path], [msih_example_path] ], inputs=input_image, label="Microscope Specimen Trays (Click to Analyze)" ) # Diagnostic explanation text with gr.Accordion("Clinical Parameters & Methods", open=False): gr.Markdown(""" - **Slide-Representative Patching**: Operates on a single 224×224 slide-representative patch at 20x magnification. In high-throughput settings, this aligns with standard Whole Slide Image (WSI) patching pipelines where individual patch embeddings are aggregated into a patient-level patient diagnosis. - **Dual-Encoder Fusion**: Fuses Google Path Foundation Model (384-dim ViT) with MedSigLIP (1152-dim vision-language encoder) to capture spatial and biochemical descriptors (1536-dim total). - **Classification Engine**: 3-layer regularized Multi-Layer Perceptron trained to predict MSI-High status. - **Explainability**: Sliding-window occlusion (40x40 stride=20) measures local prediction confidence drops, mapped to diagnostic hotspots (top 20%). - **MedGemma Report**: Integrates heatmap insights and FAISS reference matches to write the pathology brief. """) # MIDDLE COLUMN: Saliency Heatmap & Diagnostics with gr.Column(scale=1): gr.Markdown("### 📊 2. Decision Cognition") # Result Stats Card output_stats = gr.HTML( value="
Awaiting specimen acquisition and diagnostic run...
" ) # Heatmap Visualization output_heatmap = gr.Image( label="Diagnostic Hotspots: Saliency Heatmap (Top 20% Occulted Highlights)", type="pil", interactive=False ) # RIGHT COLUMN: Case Retrieval & Clinical Report with gr.Column(scale=1): gr.Markdown("### 📚 3. Clinical Evidence & Reporting") # FAISS Case Match List with gr.Tab("Historical Pathology Matches (FAISS)"): output_cases = gr.HTML( value="

Awaiting clinical reference search...

" ) # Generated Report Text Box with gr.Tab("Synthesized clinical diagnostic report"): output_report = gr.Markdown( value="*Report brief will be synthesized by MedGemma 4B-IT upon pipeline execution...*", elem_classes="report-card" ) # Bind Interactions run_btn.click( fn=run_clinical_pipeline, inputs=input_image, outputs=[output_stats, output_heatmap, output_cases, output_report], api_name="diagnose" ) # 5. Launcher if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860, show_api=False)