Spaces:
Sleeping
Sleeping
File size: 4,125 Bytes
bf5da6b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
import { DownloadIcon, InfoIcon, Loader2Icon } from "lucide-react";
interface ResultsPanelProps {
uploadedImage: string | null;
result?: any;
loading?: boolean;
}
export function ResultsPanel({ uploadedImage, result, loading }: ResultsPanelProps) {
if (loading) {
return ( <div className="bg-white rounded-lg shadow-sm p-6 flex flex-col items-center justify-center"> <Loader2Icon className="w-10 h-10 text-blue-600 animate-spin mb-3" /> <p className="text-gray-600 font-medium">Analyzing image...</p> </div>
);
}
if (!result) {
return ( <div className="bg-white rounded-lg shadow-sm p-6 text-center text-gray-500">
No analysis result available yet. </div>
);
}
const {
prediction,
confidence,
probabilities,
detections,
summary,
annotated_image_url,
model_name,
analysis_type,
} = 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 ( <div className="bg-white rounded-lg shadow-sm p-6">
{/* Header */} <div className="flex items-center justify-between mb-6"> <div> <h2 className="text-2xl font-bold text-gray-800">
{model_name ? model_name.toUpperCase() : "Analysis Result"} </h2> <p className="text-sm text-gray-500 capitalize">
{analysis_type || "Test Type"} </p> </div>
{annotated_image_url && ( <button
onClick={handleDownload}
className="flex items-center gap-2 bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors"
> <DownloadIcon className="w-4 h-4" />
Download Image </button>
)} </div>
{/* Image */}
<div className="relative mb-6 rounded-lg overflow-hidden border border-gray-200">
<img
src={annotated_image_url || uploadedImage || "/ui.jpg"}
alt="Analysis Result"
className="w-full h-64 object-cover"
/>
</div>
{/* Results Summary */}
<div className="mb-6">
{prediction && (
<h3
className={`text-3xl font-bold ${
prediction.toLowerCase().includes("malignant") ||
prediction.toLowerCase().includes("abnormal")
? "text-red-600"
: "text-green-600"
}`}
>
{prediction}
</h3>
)}
{confidence && (
<div className="mt-2">
<div className="flex items-center justify-between mb-1">
<span className="font-semibold text-gray-900">
Confidence: {(confidence * 100).toFixed(2)}%
</span>
<InfoIcon className="w-4 h-4 text-gray-400" />
</div>
<div className="w-full h-3 bg-gray-200 rounded-full overflow-hidden">
<div
className={`h-full ${
confidence > 0.7
? "bg-green-500"
: confidence > 0.4
? "bg-yellow-500"
: "bg-red-500"
}`}
style={{ width: `${confidence * 100}%` }}
/>
</div>
</div>
)}
{summary && (
<p className="mt-4 text-gray-700 text-sm leading-relaxed">
{summary}
</p>
)}
</div>
{/* Detections / Probabilities */}
{detections && detections.length > 0 && (
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3">
Detected Regions:
</h4>
<ul className="text-sm text-gray-700 list-disc list-inside space-y-1">
{detections.map((det: any, i: number) => (
<li key={i}>
{det.name || "object"} – {(det.confidence * 100).toFixed(1)}%
</li>
))}
</ul>
</div>
)}
{probabilities && (
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3">
Class Probabilities:
</h4>
<pre className="bg-gray-100 rounded-lg p-3 text-sm">
{JSON.stringify(probabilities, null, 2)}
</pre>
</div>
)}
{/* Report Button */}
<button className="w-full bg-blue-600 text-white py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors flex items-center justify-center gap-2">
<DownloadIcon className="w-5 h-5" />
Generate Report
</button>
</div>
);
} |