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>
  );
}