Spaces:
Sleeping
Sleeping
| import { createContext, useContext, useEffect, useState, useCallback } from 'react' | |
| const DataContext = createContext(null) | |
| const KEYS = [ | |
| 'models', 'recs', 'ms', 'vol_salience', 'val_share', | |
| 'freq_anchors', 'ppa_mt', 'ppa_tt', 'comp_ms', | |
| 'vtm', 'interaction', 'growth_decomp', 'pgi', 'stats', | |
| 'trend', 'recs_full', | |
| ] | |
| async function fetchKey(key) { | |
| // 1. Try FastAPI backend (/api/data/{key}) — live pipeline-computed data | |
| try { | |
| const res = await fetch(`/api/data/${key}`) | |
| if (res.ok) return res.json() | |
| } catch (_) { | |
| // upload server not reachable — fall through to static fallback | |
| } | |
| // 2. Fallback: static pre-generated file served by Vite from public/data/ | |
| // Works when upload server is not running (e.g. first open, view-only mode) | |
| const res = await fetch(`/data/${key}.json`) | |
| if (!res.ok) throw new Error(`Failed to load ${key}: ${res.status}`) | |
| return res.json() | |
| } | |
| export function DataProvider({ children }) { | |
| const [data, setData] = useState({}) | |
| const [loading, setLoading] = useState(true) | |
| const [error, setError] = useState(null) | |
| const [progress, setProgress] = useState(0) | |
| const loadAll = useCallback(async () => { | |
| setLoading(true) | |
| setProgress(0) | |
| setError(null) | |
| let cancelled = false | |
| const results = {} | |
| const errors = [] | |
| for (let i = 0; i < KEYS.length; i++) { | |
| const key = KEYS[i] | |
| try { | |
| results[key] = await fetchKey(key) | |
| } catch (e) { | |
| results[key] = null | |
| errors.push(`${key}: ${e.message}`) | |
| } | |
| if (!cancelled) setProgress(Math.round(((i + 1) / KEYS.length) * 100)) | |
| } | |
| if (!cancelled) { | |
| setData(results) | |
| setLoading(false) | |
| if (errors.length === KEYS.length) { | |
| setError('All data failed to load. Is the server running?\n' + errors[0]) | |
| } | |
| } | |
| return () => { cancelled = true } | |
| }, []) | |
| useEffect(() => { | |
| const cleanup = loadAll() | |
| return () => { cleanup.then?.(fn => fn?.()) } | |
| }, [loadAll]) | |
| return ( | |
| <DataContext.Provider value={{ ...data, loading, error, progress, reload: loadAll }}> | |
| {children} | |
| </DataContext.Provider> | |
| ) | |
| } | |
| export function useData() { | |
| return useContext(DataContext) | |
| } | |