import React, { useEffect, useRef, useState } from "react"; import { submitQuery } from "../api/client"; import type { QueryResponse } from "../types"; interface Props { onResponse: (r: QueryResponse) => void; onPending?: (query: string) => void; onSettled?: () => void; initialQuery?: string; vizEnabled?: boolean; onVizToggle?: (v: boolean) => void; } const EXAMPLE_QUERIES = [ "What are the key differences between BERT and GPT architectures?", "Compare LoRA vs full fine-tuning on common benchmarks", "How does RAG improve factual accuracy?", "Effect of model scale on few-shot learning?", ]; export default function QueryInterface({ onResponse, onPending, onSettled, initialQuery = "", vizEnabled = false, onVizToggle, }: Props) { const [query, setQuery] = useState(initialQuery); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const textareaRef = useRef(null); useEffect(() => { if (initialQuery) setQuery(initialQuery); }, [initialQuery]); // Auto-grow textarea useEffect(() => { const el = textareaRef.current; if (!el) return; el.style.height = "auto"; el.style.height = `${Math.min(el.scrollHeight, 200)}px`; }, [query]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); const trimmed = query.trim(); if (!trimmed) return; setError(""); setLoading(true); onPending?.(trimmed); try { const result = await submitQuery(trimmed, vizEnabled); setQuery(""); onResponse(result); } catch (err: unknown) { const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail ?? "Query failed — please try again."; setError(String(msg)); onSettled?.(); } finally { setLoading(false); } } return (
{/* Textarea */}