GemmaSight / app.py
TouseefAhmad's picture
Upload folder using huggingface_hub
8dcd06b verified
Raw
History Blame Contribute Delete
8.47 kB
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="<p style='color: #ef4444;'>Error: Specimen image is required.</p>"),
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"<p style='color: #ef4444;'>Execution Error: {str(e)}</p>"),
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("<h1>GemmaSight</h1>")
gr.HTML("<p>State-of-the-Art Multimodal AI Pathology Assistant for Colorectal Cancer MSI/MSS Status</p>")
# 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="<div style='text-align: center; padding: 24px; border-radius: 14px; background: rgba(15, 23, 42, 0.25); border: 1px solid rgba(255,255,255,0.05); color: #64748b;'>Awaiting specimen acquisition and diagnostic run...</div>"
)
# 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="<p style='color: #64748b; padding: 16px;'>Awaiting clinical reference search...</p>"
)
# 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)