import React, { useState, useEffect, useMemo, useRef } from 'react';
import {
Search, Plus, Minus, Zap, Image as ImageIcon, Loader2, Sparkles,
Command, Activity, FileText, ArrowRight, Award, BrainCircuit,
ScanEye, SplitSquareHorizontal, Info, Sliders, Gauge,
X, Globe, Check, Link as LinkIcon, Lightbulb, BookOpen, Layers,
Network, GraduationCap, ChevronLeft, MonitorPlay, Database, Wand2,
AlignLeft, Share2, Infinity as InfinityIcon, MousePointerClick, Maximize2, Flame,
ArrowDown, Play, Youtube, ExternalLink
} from 'lucide-react';
import { motion, AnimatePresence, useScroll, useTransform, useSpring } from 'framer-motion';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
const API_URL = "https://migueldiaz1-mirage-backend.hf.space";
const PROJECT_URL = "https://arxiv.org/abs/2400.00000";
const KAGGLE_URL = "https://www.kaggle.com/code/migueldazbenito/mirage";
const YOUTUBE_VIDEO_ID = "GlPMrBWtZoQ";
const MEDICAL_PROMPTS = [
{ title: "Glioblastoma Multiforme", text: "MRI of the brain showing a large necrotic glioblastoma in the frontal lobe with edema." },
{ title: "Liver Metastasis", text: "CT scan of the abdomen showing multiple hypodense metastatic lesions in the liver." },
{ title: "Pleural Effusion", text: "Chest radiograph showing blunting of the costophrenic angle indicating pleural effusion." }
];
const DUAL_ARITHMETIC_EXAMPLES = [
{ title: "Bone Suppression", query: "Chest X-Ray", add: "Soft Tissue", sub: "Bones", desc: "Isolates lung tissue by subtracting bone structures." },
{ title: "Infection Highlight", query: "Lungs X-Ray", add: "Pneumonia", sub: "Clear Lungs", desc: "Visualizes the difference between healthy and infected tissue." },
{ title: "Cardiac Pacemaker", query: "Chest X-ray", add: "Pacemaker generator and leads", sub: "No foreign bodies", desc: "Add a pacemaker to the chest X-ray." }
];
function cn(...inputs) {
return twMerge(clsx(inputs));
}
const RichText = ({ text, className }) => {
if (!text) return null;
const parts = text.split(/(\*\*.*?\*\*)/g);
return (
{parts.map((part, i) => {
if (part.startsWith('**') && part.endsWith('**')) {
return {part.slice(2, -2)} ;
}
return part;
})}
);
};
const pageTransition = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] }
};
const staggerContainer = {
hidden: { opacity: 0 },
show: { opacity: 1, transition: { staggerChildren: 0.1 } }
};
const cardVariant = {
hidden: { opacity: 0, y: 20, scale: 0.98 },
show: { opacity: 1, y: 0, scale: 1, transition: { type: "spring", stiffness: 40, damping: 10 } }
};
const OpticalGradient = () => {
return (
);
};
const BreathingTitle = () => {
const phrase = [
{ char: "M", type: "standard" }, { char: "I", type: "standard" }, { char: "R", type: "standard" },
{ char: "A", type: "standard" }, { char: "G", type: "standard" }, { char: "E", type: "standard" },
{ char: "\u00A0", type: "space" },
{ char: "O", type: "highlight" }, { char: "S", type: "highlight" },
];
return (
{phrase.map((item, index) => (
{item.char}
))}
);
};
const BrainstormingBackground = () => {
const MEDICAL_TERMS = [
"Pneumonia", "Atelectasis", "Cardiomegaly", "Effusion", "Infiltration", "Mass", "Nodule",
"Pneumothorax", "Consolidation", "Edema", "Emphysema", "Fibrosis", "Hernia", "Fracture"
];
const colors = ["bg-orange-500/20 text-orange-200 border-orange-500/30", "bg-red-500/20 text-red-200 border-red-500/30"];
const floatingWords = useMemo(() => MEDICAL_TERMS.map((term, i) => ({
text: term,
x: Math.random() * 80 - 40,
y: Math.random() * 80 - 40,
scale: Math.random() * 0.4 + 0.8,
delay: Math.random() * 20,
colorClass: colors[i % colors.length]
})), []);
return (
{floatingWords.map((word, i) => (
{word.text}
))}
);
};
const KaggleLogo = ({ className }) => (
);
const PaperExplanation = ({ onBack }) => {
const containerRef = useRef(null);
const { scrollYProgress } = useScroll({ container: containerRef });
const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 });
const FigurePlaceholder = ({ label, className, src, imageClassName }) => (
{src ? (
) : (
{label}
Drag or insert figure here
)}
);
const AppleSection = ({ children, className, gradient = "none" }) => (
{gradient === "hero" && (
)}
{gradient === "subtle" && (
)}
{gradient === "amber" && (
)}
{children}
);
return (
{/* 01. HERO */}
MIRAGE
Redefining medical education through Multimodal Artificial Intelligence .
{/* 02. PROBLEM: ATLASES */}
The Static Trap.
Traditional medical atlases are the gold standard for accuracy, yet they fail in the modern era. They are prohibitively expensive, cumbersome to update, and present only a single, idealized view of pathologies.
Fixed viewpoints, no 3D rotation.
Limited rare case examples.
Zero interactivity for students.
{/* 03. PROBLEM: INTERNET */}
The Reliability Gap.
Turning to Google Images provides speed but sacrifices trust. Results are often mislabeled, lack clinical context, or originate from unverified sources, posing a risk for medical education.
{/* 04. THE ARCHITECTURE */}
Unified Architecture
CLIP + ROCO + Stable Diffusion. Orchestrated in a shared latent space.
{[
{ title: "Retrieval", sub: "CLIP MedICaT", icon: Search, color: "orange" },
{ title: "Generation", sub: "Prompt2MedImage", icon: Wand2, color: "red" },
{ title: "Description", sub: "Dolly-v2 LLM", icon: AlignLeft, color: "amber" }
].map((item, i) => (
{item.title}
{item.sub}
))}
{/* 05. DUAL SEARCH */}
Key Feature
Latent Arithmetic
We enable users to "subtract" concepts (like bones) and "add" others (like soft tissue) mathematically.
Query-Bones +Tissue = Result
{/* 06. CALL TO ACTION */}
VIDEO
Experience the full MIRAGE pipeline with zero setup cost using Kaggle's free GPU infrastructure. Reproduce our MICCAI 2025 results instantly.
Open Notebook
Return to App
);
};
const WelcomeScreen = ({ onStart, onOpenPaper }) => {
return (
The Fourth Workshop on Applications of Medical AI (AMAI) | MICCAI 2025
Retrieval and Generation of Multimodal Images & Texts for Medical Education
FAST INFERENCE
Visual Only Retrieval
Optimized for speed. Retrieves medical imagery using pure visual vector similarity (CLIP).
ROCO DATASET
Radiology Optimized
Built on a foundation of thousands of annotated radiology images form PubMed.
Explain Paper
Enter System
);
};
const ParameterSlider = ({ icon: Icon, label, value, onChange, min, max, step, description, formatValue }) => {
return (
{label}
{formatValue ? formatValue(value) : value}
{description &&
{description}
}
);
};
const TopKCounter = ({ value, onChange, disabled }) => {
return (
!disabled && onChange(Math.max(1, value - 1))}
disabled={disabled}
className="w-8 h-8 flex items-center justify-center rounded-md bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white transition-colors disabled:pointer-events-none"
>
Retrieval Count
K={value}
!disabled && onChange(Math.min(10, value + 1))}
disabled={disabled}
className="w-8 h-8 flex items-center justify-center rounded-md bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white transition-colors disabled:pointer-events-none"
>
);
};
const CheckboxTile = ({ icon: Icon, label, checked, onChange, color = "orange", description, infoTitle, infoDesc }) => {
const [showInfo, setShowInfo] = useState(false);
const styles = {
rose: { active: "bg-rose-500/10 border-rose-500/50", icon: "text-rose-500", checkbox: "bg-rose-500 border-rose-500", info: "border-rose-500/30 text-rose-400" },
orange: { active: "bg-orange-500/10 border-orange-500/50", icon: "text-orange-500", checkbox: "bg-orange-500 border-orange-500", info: "border-orange-500/30 text-orange-400" },
amber: { active: "bg-amber-500/10 border-amber-500/50", icon: "text-amber-500", checkbox: "bg-amber-500 border-amber-500", info: "border-amber-500/30 text-amber-400" },
default: { active: "bg-zinc-800 border-zinc-600", icon: "text-zinc-500", checkbox: "bg-zinc-500 border-zinc-500", info: "border-zinc-700 text-zinc-400" }
};
const currentStyle = styles[color] || styles.default;
return (
onChange(!checked)}
className={cn("relative flex-1 rounded-xl border p-3 cursor-pointer transition-all duration-300", checked ? currentStyle.active : "bg-zinc-900/60 border-zinc-800 hover:border-zinc-600")}
>
{infoTitle && (
setShowInfo(!showInfo)}
className={cn(
"p-2 rounded-lg border bg-zinc-900/40 hover:bg-zinc-900 transition-colors",
showInfo ? currentStyle.info + " bg-zinc-900" : "border-zinc-800 text-zinc-600 hover:text-zinc-400"
)}
>
)}
{showInfo && infoTitle && (
{infoTitle}
{infoDesc}
)}
);
};
const InputField = ({ icon: Icon, value, onChange, placeholder, color = "orange", label }) => {
const textareaRef = useRef(null);
useEffect(() => {
if (textareaRef.current) {
textareaRef.current.style.height = 'auto';
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
}
}, [value]);
const gradients = {
red: "bg-[conic-gradient(transparent,rgba(239,68,68,1),transparent,rgba(239,68,68,1),transparent)]",
rose: "bg-[conic-gradient(transparent,rgba(244,63,94,1),transparent,rgba(244,63,94,1),transparent)]",
orange: "bg-[conic-gradient(transparent,rgba(249,115,22,1),transparent,rgba(249,115,22,1),transparent)]",
amber: "bg-[conic-gradient(transparent,rgba(245,158,11,1),transparent,rgba(245,158,11,1),transparent)]",
}
return (
);
};
const Column = ({ title, query, color, children }) => (
);
const ResultCard = ({ item, isSynth, label }) => {
if(!item) return null;
const url = isSynth ? item.url : (item.url?.startsWith('http') ? item.url : `${API_URL}${item.url}`);
return (
{isSynth ? (
Synthetic Generation
Created by Diffusion Model
) : (
Findings
{item.score && (
)}
{item.caption || "No caption available for this image."}
)}
);
};
const DescriptionBox = ({ text, title }) => {
if(!text || text === "LLM generation skipped.") return null;
return (
);
};
const MainInterface = ({ onBack }) => {
const [query, setQuery] = useState('');
const [topK, setTopK] = useState(1);
const [isDualSearch, setIsDualSearch] = useState(false);
const [loadDescription, setLoadDescription] = useState(false);
const [generateSynthetic, setGenerateSynthetic] = useState(false);
const isHeavyComputation = isDualSearch || loadDescription || generateSynthetic;
useEffect(() => {
if (isHeavyComputation) {
setTopK(1);
}
}, [isHeavyComputation]);
const [showMedicalInspiration, setShowMedicalInspiration] = useState(false);
const [showDualInspiration, setShowDualInspiration] = useState(false);
const [guidanceScale, setGuidanceScale] = useState(7.5);
const [inferenceSteps, setInferenceSteps] = useState(35);
const [addConcept, setAddConcept] = useState('');
const [subConcept, setSubConcept] = useState('');
const [loading, setLoading] = useState(false);
const [results, setResults] = useState(null);
const [error, setError] = useState(null);
const isDualSearchValid = !isDualSearch || (addConcept.trim() !== '' && subConcept.trim() !== '');
const canExecute = !loading && query.trim() !== '' && isDualSearchValid;
const handleExecute = async () => {
if (!canExecute) return;
setLoading(true);
setResults(null);
setError(null);
try {
const payload = {
original_text: query,
sub_concept: isDualSearch ? subConcept : null,
add_concept: isDualSearch ? addConcept : null,
top_k: topK,
gen_text: loadDescription,
gen_image: generateSynthetic,
guidance_scale: generateSynthetic ? guidanceScale : undefined,
num_inference_steps: generateSynthetic ? inferenceSteps : undefined,
};
const res = await fetch(`${API_URL}/generate_comparison`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!res.ok) throw new Error("API Error");
const data = await res.json();
setResults(data);
} catch (e) {
console.error(e);
setError("Connection Error. Please try again.");
} finally {
setLoading(false);
}
};
const handleSetMedicalExample = (text) => {
setQuery(text);
setShowMedicalInspiration(false);
};
const handleSetDualExample = (ex) => {
setQuery(ex.query);
setAddConcept(ex.add);
setSubConcept(ex.sub);
setIsDualSearch(true);
setShowDualInspiration(false);
};
return (
{/* SIDEBAR */}
{/* INPUT SECTION (RED SPECTRUM) */}
Medical Query
setShowMedicalInspiration(!showMedicalInspiration)}
className="text-[9px] text-red-400/80 hover:text-red-300 transition-colors flex items-center gap-1 uppercase tracking-wide font-medium"
>
Need inspiration?
{/* Inspiration Panel (Medical) */}
{showMedicalInspiration && (
Select a query:
{MEDICAL_PROMPTS.map((item, idx) => (
handleSetMedicalExample(item.text)}
className="w-full text-left p-2 rounded hover:bg-red-500/10 border border-transparent hover:border-red-500/30 transition-all group"
>
{item.title}
{item.text}
))}
)}
{/* CONTROLS */}
{/* DUAL SEARCH (ROSE/PINK SPECTRUM) */}
{isDualSearch && (
setShowDualInspiration(!showDualInspiration)}
className="ml-2 text-[9px] text-rose-400/80 hover:text-rose-300 transition-colors flex items-center gap-1 uppercase tracking-wide font-medium whitespace-nowrap"
>
Examples
)}
{isDualSearch && showDualInspiration && (
Try vector arithmetic:
{DUAL_ARITHMETIC_EXAMPLES.map((item, idx) => (
handleSetDualExample(item)}
className="w-full text-left p-2 rounded hover:bg-rose-500/10 border border-transparent hover:border-rose-500/30 transition-all group"
>
{item.title}
{item.query}
+ {item.add}
- {item.sub}
))}
)}
{isDualSearch && (
{(!addConcept || !subConcept) && (
* Both concepts required for calculation
)}
)}
{/* LLM CONTEXT (ORANGE SPECTRUM) */}
{/* SYNTHETIC (AMBER SPECTRUM) */}
{generateSynthetic && (
)}
{loading ? : }
{loading ? "Processing Vectors..." : "Execute Operation"}
{/* MAIN CONTENT */}
{/* Background Elements */}
{/* CONTENT WRAPPER */}
{loading && (
{/* STANDARD LOADER */}
Navigating Latent Space...
)}
{!loading && !results && (
SYSTEM IDLE
Ready to navigate high-dimensional medical latent spaces.
)}
{!loading && results && (
{Array.isArray(results.original.real_match)
? results.original.real_match.map((item, i) => )
:
}
{results.original.synthetic.image_base64 && (
)}
{results.modified && (
{Array.isArray(results.modified.real_match)
? results.modified.real_match.map((item, i) => )
:
}
{results.modified.synthetic.image_base64 && (
)}
)}
)}
);
};
export default function App() {
const [mode, setMode] = useState('welcome'); // States available: 'welcome', 'app', 'paper'
return (
{mode === 'welcome' && (
setMode('app')}
onOpenPaper={() => setMode('paper')}
/>
)}
{mode === 'app' && (
setMode('welcome')} />
)}
{/* RENDERIZADO DE PÁGINA DEL PAPER (EN ESPAÑOL) */}
{mode === 'paper' && (
setMode('welcome')} />
)}
);
}