Spaces:
Running
Running
| 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> | |
| ); | |
| } | |