File size: 3,896 Bytes
cbd23a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { createContext, useContext, useState, ReactNode, useCallback } from 'react';
import { ClassificationResult } from './api';

export interface ImageState {
    // Current image
    file: File | null;
    preview: string | null;
    processedImage: string | null;

    // Classification results
    classificationResults: ClassificationResult[] | null;

    // View (corrected takes priority)
    predictedView: string | null;
    correctedView: string | null;

    // Session ID for feedback
    sessionId: string;
}

interface ImageContextType extends ImageState {
    // Actions
    setFile: (file: File | null, preview: string | null) => void;
    setClassificationResults: (results: ClassificationResult[] | null, processedImage?: string | null) => void;
    setCorrectedView: (view: string | null) => void;
    resetState: () => void;

    // Computed
    currentView: string | null; // Returns correctedView if set, otherwise topPrediction
    isViewGAEligible: boolean;
}

// GA-eligible views (match keys from prompt_fetal_view.json)
export const GA_ELIGIBLE_VIEWS = [
    "brain",    // Head Circumference
    "abdomen",  // Abdominal Circumference
    "femur",    // Femur Length
];

// Display names for GA biometry types
export const GA_BIOMETRY_LABELS: Record<string, string> = {
    "brain": "Head Circumference (HC)",
    "abdomen": "Abdominal Circumference (AC)",
    "femur": "Femur Length (FL)",
};

const generateSessionId = () => {
    return Math.random().toString(36).substring(2, 10);
};

const initialState: ImageState = {
    file: null,
    preview: null,
    processedImage: null,
    classificationResults: null,
    predictedView: null,
    correctedView: null,
    sessionId: generateSessionId(),
};

const ImageContext = createContext<ImageContextType | null>(null);

export function ImageProvider({ children }: { children: ReactNode }) {
    const [state, setState] = useState<ImageState>(initialState);

    const setFile = useCallback((file: File | null, preview: string | null) => {
        setState(prev => ({
            ...prev,
            file,
            preview,
            processedImage: null,
            classificationResults: null,
            predictedView: null,
            correctedView: null,
        }));
    }, []);

    const setClassificationResults = useCallback((
        results: ClassificationResult[] | null,
        processedImage: string | null = null
    ) => {
        setState(prev => ({
            ...prev,
            classificationResults: results,
            processedImage: processedImage || prev.processedImage,
            predictedView: results && results.length > 0 ? results[0].label : null,
        }));
    }, []);

    const setCorrectedView = useCallback((view: string | null) => {
        setState(prev => ({
            ...prev,
            correctedView: view,
        }));
    }, []);

    const resetState = useCallback(() => {
        setState({
            ...initialState,
            sessionId: generateSessionId(),
        });
    }, []);

    // Computed: current view (corrected takes priority)
    const currentView = state.correctedView || state.predictedView;

    // Computed: is view eligible for GA estimation
    const isViewGAEligible = currentView ? GA_ELIGIBLE_VIEWS.includes(currentView) : false;

    return (
        <ImageContext.Provider
            value={{
                ...state,
                setFile,
                setClassificationResults,
                setCorrectedView,
                resetState,
                currentView,
                isViewGAEligible,
            }}
        >
            {children}
        </ImageContext.Provider>
    );
}

export function useImageContext() {
    const context = useContext(ImageContext);
    if (!context) {
        throw new Error('useImageContext must be used within an ImageProvider');
    }
    return context;
}