import { useEffect, useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { api } from '../api/client'; const EXAMPLE_QUERIES = [ 'Top 5 drugs at risk from Hebei shutdown', 'India rare earth exposure vs Vietnam', 'Worst case 30-day scenario for paracetamol', 'Which EV components are most vulnerable to Jiangsu export freeze?', 'Buffer stock recommendations for critical APIs', ]; function modeMeta(responseMode, shockFeedMode) { if (responseMode === 'hybrid_live') { return { label: 'Gemini Flash | hybrid context', color: 'var(--primary)', bg: 'rgba(79,156,249,0.12)', border: '1px solid rgba(79,156,249,0.25)', }; } if (responseMode === 'fallback') { return { label: 'Local grounded fallback', color: 'var(--amber)', bg: 'rgba(245,158,11,0.12)', border: '1px solid rgba(245,158,11,0.25)', }; } if (responseMode === 'demo' || shockFeedMode === 'demo') { return { label: 'Curated scenario analyst', color: 'var(--primary)', bg: 'rgba(79,156,249,0.12)', border: '1px solid rgba(79,156,249,0.25)', }; } return { label: 'Gemini Flash | grounded RAG', color: 'var(--green)', bg: 'rgba(16,185,129,0.12)', border: '1px solid rgba(16,185,129,0.25)', }; } export default function Query() { const [question, setQuestion] = useState(''); const [answer, setAnswer] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [history, setHistory] = useState([]); const [health, setHealth] = useState(null); useEffect(() => { api.health().then(setHealth).catch(() => setHealth(null)); }, []); const responseMode = answer?.response_mode; const badge = useMemo( () => modeMeta(responseMode, health?.shock_feed_mode), [responseMode, health?.shock_feed_mode], ); async function submit(q) { const text = (q || question).trim(); if (!text || loading) return; setLoading(true); setError(null); setAnswer(null); try { const res = await api.query(text); setAnswer(res); setHistory((prev) => [{ question: text, answer: res, ts: new Date() }, ...prev.slice(0, 5)]); } catch (e) { setError(e.message || 'Query failed. Check backend connectivity.'); } finally { setLoading(false); } } function handleKey(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit(); } } const metrics = [ { label: 'Feed', value: health?.shock_feed_mode === 'hybrid_demo_live' ? 'Hybrid' : health?.shock_feed_mode || 'Live' }, { label: 'Live shocks', value: health?.live_shocks ?? '-' }, { label: 'Scenario bank', value: health?.demo_scenarios ?? '-' }, ]; return (

Ask ShockMap

{badge.label}

Ask for exposed inputs, buffer pressure, supplier options, escalation triggers, or scenario comparisons. The response path will use live context when it is available and fall back to curated scenario evidence when it is not.

Operational query composer

Grounded answers with citations, affected inputs, and action framing.

{metrics.map((item) => (

{item.label}

{item.value}

))}