Spaces:
Running
Running
File size: 5,145 Bytes
a874986 |
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 |
import { CheckCircle, AlertCircle, Info } from 'lucide-react';
import { useState } from 'react';
import type { PreprocessingInfo } from '../lib/api';
interface PreprocessingBadgeProps {
info: PreprocessingInfo | null;
fileType?: 'dicom' | 'image' | null;
compact?: boolean;
}
const STEP_LABELS: Record<string, string> = {
dicom_parsing: 'DICOM Parsing',
us_region_extraction: 'US Region Extraction',
text_box_removal: 'Text Box Removal',
fan_extraction: 'Fan Extraction',
annotation_detection: 'Annotation Detection',
inpainting: 'Inpainting',
denoising: 'Denoising',
normalization: 'Normalization',
square_padding: 'Square Padding',
resize_512: 'Resize to 512×512',
rgb_conversion: 'RGB Conversion',
};
export function PreprocessingBadge({ info, fileType, compact = false }: PreprocessingBadgeProps) {
const [expanded, setExpanded] = useState(false);
// Show pending state when file is selected but not yet processed
if (!info && fileType) {
const isDicom = fileType === 'dicom';
return (
<div className={`rounded-xl border shadow-card ${isDicom ? 'border-nvidia-green/30 bg-nvidia-green/5' : 'border-accent-blue/30 bg-accent-blue/5'} ${compact ? 'px-3 py-2' : 'px-4 py-3'}`}>
<div className="flex items-center gap-2">
<div className={`w-2 h-2 rounded-full ${isDicom ? 'bg-nvidia-green' : 'bg-accent-blue'}`} />
<span className={`font-semibold ${isDicom ? 'text-nvidia-green' : 'text-accent-blue'} ${compact ? 'text-xs' : 'text-sm'}`}>
{isDicom ? 'DICOM' : 'PNG/JPEG'}
</span>
<span className={`text-text-secondary ${compact ? 'text-xs' : 'text-sm'}`}>
• {isDicom ? 'Full Pipeline' : 'Basic Pipeline'}
</span>
</div>
{!compact && (
<p className="text-xs text-text-muted mt-1">
{isDicom
? 'Will apply: Fan extraction, text removal, denoising'
: 'Will apply: Square padding only. For best accuracy, use DICOM files.'
}
</p>
)}
</div>
);
}
if (!info) return null;
const isDicom = info.type === 'dicom';
const isFull = info.pipeline === 'full';
return (
<div className={`rounded-xl border shadow-card ${isFull ? 'border-nvidia-green/30 bg-nvidia-green/5' : 'border-amber-500/30 bg-amber-500/5'} ${compact ? 'px-3 py-2' : 'px-4 py-3'}`}>
{/* Header */}
<button
onClick={() => setExpanded(!expanded)}
className="w-full flex items-center justify-between"
>
<div className="flex items-center gap-2">
<div className={`w-2 h-2 rounded-full ${isFull ? 'bg-nvidia-green' : 'bg-amber-500'}`} />
<span className={`font-semibold ${isFull ? 'text-nvidia-green' : 'text-amber-600'} ${compact ? 'text-xs' : 'text-sm'}`}>
{isDicom ? 'DICOM' : 'PNG/JPEG'}
</span>
<span className={`text-text-secondary ${compact ? 'text-xs' : 'text-sm'}`}>
• {isFull ? 'Full Pipeline' : 'Basic Pipeline'}
</span>
</div>
<Info className={`text-text-muted ${compact ? 'w-3 h-3' : 'w-4 h-4'}`} />
</button>
{/* Expanded Details */}
{expanded && (
<div className="mt-3 pt-3 border-t border-dark-border">
<p className="text-xs text-text-muted mb-2 font-medium">Steps Applied:</p>
<div className="space-y-1.5">
{info.steps_applied.map((step) => (
<div key={step} className="flex items-center gap-2">
<CheckCircle className="w-3.5 h-3.5 text-nvidia-green" />
<span className="text-xs text-text-primary">
{STEP_LABELS[step] || step}
</span>
</div>
))}
</div>
{/* Missing steps for basic pipeline */}
{!isFull && (
<div className="mt-3 pt-3 border-t border-dark-border">
<p className="text-xs text-text-muted mb-2 font-medium">Not Applied:</p>
<div className="space-y-1.5">
{['fan_extraction', 'annotation_detection', 'inpainting', 'denoising'].map((step) => (
<div key={step} className="flex items-center gap-2">
<AlertCircle className="w-3.5 h-3.5 text-amber-500" />
<span className="text-xs text-text-muted">
{STEP_LABELS[step] || step}
</span>
</div>
))}
</div>
<p className="text-xs text-amber-600 mt-2 font-medium">
⚠️ For best accuracy, use DICOM files from the ultrasound machine.
</p>
</div>
)}
{/* Metadata */}
{info.metadata.pixel_spacing && (
<div className="mt-3 pt-3 border-t border-dark-border">
<p className="text-xs text-text-muted">
Pixel Spacing: <span className="text-text-primary font-medium">{info.metadata.pixel_spacing.toFixed(3)} mm/px</span>
</p>
</div>
)}
</div>
)}
</div>
);
}
|