"use client"; import { Markdown } from "@copilotkit/react-ui"; import { useCallback, useState } from "react"; interface VisualGroundingState { isOpen: boolean; chunkId: string | null; images: string[]; loading: boolean; error: string | null; } interface Citation { document_id: string; chunk_id: string; document_uri: string; document_title?: string; page_numbers: number[]; headings?: string[]; content: string; } interface SearchAnswer { query: string; answer: string; confidence: number; cited_chunks: string[]; citations: Citation[]; } interface ResearchContext { original_question: string; sub_questions: string[]; qa_responses: SearchAnswer[]; } interface EvaluationResult { new_questions: string[]; confidence_score: number; is_sufficient: boolean; reasoning: string; } interface ResearchReport { title: string; executive_summary: string; main_findings: string[]; conclusions: string[]; limitations: string[]; recommendations: string[]; sources_summary: string; } interface ResearchState { context: ResearchContext; iterations: number; max_iterations: number; confidence_threshold: number; max_concurrency: number; last_eval: EvaluationResult | null; result?: ResearchReport; current_activity?: string; current_activity_message?: string; } interface StateDisplayProps { state: ResearchState; } export default function StateDisplay({ state }: StateDisplayProps) { const [expandedSections, setExpandedSections] = useState< Record >({ questions: true, report: true, }); const [expandedQuestions, setExpandedQuestions] = useState< Record >({}); const [visualGrounding, setVisualGrounding] = useState({ isOpen: false, chunkId: null, images: [], loading: false, error: null, }); const fetchVisualGrounding = useCallback(async (chunkId: string) => { setVisualGrounding({ isOpen: true, chunkId, images: [], loading: true, error: null, }); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"}/api/visualize/${chunkId}`, ); const data = await response.json(); if (!response.ok) { throw new Error(data.error || "Failed to fetch visual grounding"); } setVisualGrounding((prev) => ({ ...prev, images: data.images || [], loading: false, error: data.images?.length === 0 ? data.message : null, })); } catch (err) { setVisualGrounding((prev) => ({ ...prev, loading: false, error: err instanceof Error ? err.message : "Unknown error", })); } }, []); const closeVisualGrounding = useCallback(() => { setVisualGrounding({ isOpen: false, chunkId: null, images: [], loading: false, error: null, }); }, []); const toggleSection = (section: string) => { setExpandedSections((prev) => ({ ...prev, [section]: !prev[section], })); }; const toggleQuestion = (questionId: string) => { setExpandedQuestions((prev) => ({ ...prev, [questionId]: !prev[questionId], })); }; // Calculate research progress based on iterations const researchProgress = state.max_iterations > 0 ? (state.iterations / state.max_iterations) * 100 : 0; const confidence = state.last_eval?.confidence_score || 0; return (
{/* Question */} {state.context?.original_question && (
Question
{state.context.original_question}
)} {/* Research Progress - only show when research is in progress (not when complete) */} {(state.iterations > 0 || state.current_activity) && !state.result && (
{/* Current Activity */} {state.current_activity && (
0 ? "1rem" : 0, }} >
{state.current_activity .replace(/_/g, " ") .replace(/\b\w/g, (c) => c.toUpperCase())}
{state.current_activity_message && (
{state.current_activity_message}
)}
)} {/* Iteration Progress Bar */} {state.iterations > 0 && (
Iterations {state.iterations}/{state.max_iterations}
)}
)} {/* Confidence Meter */} {confidence > 0 && (
Confidence
0.8 ? "#48bb78" : confidence > 0.5 ? "#ed8936" : "#f56565", transition: "width 0.3s ease", }} />
0.8 ? "#48bb78" : confidence > 0.5 ? "#ed8936" : "#f56565", }} > {(confidence * 100).toFixed(0)}%
{state.last_eval?.reasoning && (
)}
)} {/* Answers */} {state.context?.qa_responses && state.context.qa_responses.length > 0 && (
{expandedSections.questions && (
{/* Show all qa_responses (each has query + answer) */} {state.context.qa_responses.map((qaResponse, idx) => { const questionId = `q-${idx}`; return (
{/* QA Response nested inside question */} {expandedQuestions[questionId] && (
Answer
{/* Citations with visual grounding info */} {qaResponse.citations && qaResponse.citations.length > 0 && (
Citations ({qaResponse.citations.length})
{qaResponse.citations.map((citation, citIdx) => (
{citation.document_title || citation.document_uri}
{citation.page_numbers && citation.page_numbers.length > 0 && (
{citation.page_numbers.length === 1 ? `p. ${citation.page_numbers[0]}` : `pp. ${citation.page_numbers[0]}-${citation.page_numbers[citation.page_numbers.length - 1]}`}
)}
{citation.headings && citation.headings.length > 0 && (
{citation.headings.join(" › ")}
)}
{citation.content.slice(0, 200)} {citation.content.length > 200 && "…"}
))}
)}
)}
); })}
)}
)} {/* Final Report */} {state.result && (
{expandedSections.report && (

{state.result.title}

Executive Summary

Main Findings

    {state.result.main_findings.map((finding, idx) => (
  • ))}

Conclusions

    {state.result.conclusions.map((conclusion, idx) => (
  • ))}
{state.result.recommendations.length > 0 && (

Recommendations

    {state.result.recommendations.map((rec, idx) => (
  • ))}
)} {state.result.limitations.length > 0 && (

Limitations

    {state.result.limitations.map((lim, idx) => (
  • ))}
)}

Sources

)}
)} {/* Visual Grounding Modal */} {visualGrounding.isOpen && (
e.stopPropagation()} >

Visual Grounding

{visualGrounding.loading && (
Loading...
)} {visualGrounding.error && (
{visualGrounding.error}
)} {!visualGrounding.loading && !visualGrounding.error && visualGrounding.images.length > 0 && (
{visualGrounding.images.map((img, idx) => (
Page {idx + 1} of {visualGrounding.images.length}
{`Page
))}
)}
)}
); }