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 = { "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(null); export function ImageProvider({ children }: { children: ReactNode }) { const [state, setState] = useState(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 ( {children} ); } export function useImageContext() { const context = useContext(ImageContext); if (!context) { throw new Error('useImageContext must be used within an ImageProvider'); } return context; }