import { useState } from "react";
import { DownloadIcon, FileTextIcon, Loader2Icon } from "lucide-react";
import { ImageWithFallback } from "./ImageWithFallback";
import { ReportModal } from "./ReportModal";
import axios from "axios";
interface ResultsPanelProps {
uploadedImage: string | null;
result?: any;
loading?: boolean;
}
export function ResultsPanel({ uploadedImage, result, loading }: ResultsPanelProps) {
const [showReportModal, setShowReportModal] = useState(false);
const handleGenerateReport = async (formData: FormData) => {
try {
const baseURL = import.meta.env.MODE === "development"
? "http://127.0.0.1:7860"
: window.location.origin;
const response = await axios.post(`${baseURL}/reports/`, formData, {
headers: { "Content-Type": "multipart/form-data" },
});
if (response.data.html_url) {
// Open report in new tab
window.open(`${baseURL}${response.data.html_url}`, "_blank");
}
if (response.data.pdf_url) {
// Open PDF in new tab when available
window.open(`${baseURL}${response.data.pdf_url}`, "_blank");
}
setShowReportModal(false);
} catch (err: any) {
console.error("Failed to generate report:", err);
alert(err.response?.data?.error || "Failed to generate report");
}
};
if (loading) {
return (
);
}
if (!result) {
return (
No analysis result available yet.
);
}
const {
model_used,
detections,
annotated_image_url,
summary,
// prediction (not used here)
confidence,
} = result;
const handleDownload = () => {
if (annotated_image_url) {
const link = document.createElement("a");
link.href = annotated_image_url;
link.download = "analysis_result.jpg";
link.click();
}
};
return (
{/* Header */}
{model_used || "Analysis Result"}
Automated Image Analysis
{annotated_image_url && (
Download Image
)}
setShowReportModal(true)}
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
Generate Report
{/* Image */}
{/* Summary Section */}
{summary && (
AI Summary
Abnormal Cells: {summary.abnormal_cells}
Normal Cells: {summary.normal_cells}
Average Confidence: {summary.avg_confidence?.toFixed(2)}%
{summary.ai_interpretation || "No AI interpretation available."}
)}
{/* Detection list */}
{detections && detections.length > 0 && (
Detected Objects
{detections.map((det: any, i: number) => (
{det.name || "Object"} – {(det.confidence * 100).toFixed(1)}%
))}
)}
{/* Probability / MWT visualization */}
{confidence && (
Confidence Levels
{/* If MWT, CIN, or Histopathology classifier, show a visual bar for average confidence and per-class bars */}
{model_used && /mwt|cin|histopathology/i.test(model_used) ? (
{/* Average confidence bar */}
Average confidence
{summary?.avg_confidence ? `${summary.avg_confidence.toFixed(2)}%` : "-"}
{/* Per-class bars */}
{Object.entries(confidence).map(([cls, val]) => {
const num = Number(val as any) || 0;
const pct = (num * 100);
// Color coding: Positive/Malignant/High-grade = red, Negative/Benign/Low-grade = green
const isNegative = cls.toLowerCase().includes("negative") ||
cls.toLowerCase().includes("benign") ||
cls.toLowerCase().includes("low-grade");
return (
);
})}
{/* Mistral comment */}
{summary?.ai_interpretation || "No AI interpretation available."}
) : (
// Fallback display for non-MWT models
{JSON.stringify(confidence, null, 2)}
)}
)}
{/* Report Generation Modal */}
setShowReportModal(false)}
onSubmit={handleGenerateReport}
analysisId={annotated_image_url || ""}
analysisSummaryJson={summary ? JSON.stringify({ ...summary, model_used, confidence }) : "{}"}
/>
);
}