import { useState } from "react"; import { trpc } from "@/lib/trpc"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Search, Loader2, ExternalLink, Image as ImageIcon, FileText, Download, AlertCircle, } from "lucide-react"; interface ResearchResult { title: string; url: string; snippet?: string; screenshotUrl?: string; extractedText?: string; } export function WebResearchPanel({ conversationId }: { conversationId: string }) { const [query, setQuery] = useState(""); const [maxResults, setMaxResults] = useState(5); const [includeScreenshots, setIncludeScreenshots] = useState(false); const [extractText, setExtractText] = useState(false); const [results, setResults] = useState([]); const [expandedResult, setExpandedResult] = useState(null); const searchMutation = trpc.research.search.useMutation(); const compileReportMutation = trpc.research.compileReport.useMutation(); const handleSearch = async () => { if (!query.trim()) return; try { const result = await searchMutation.mutateAsync({ query: query.trim(), maxResults, includeScreenshots, extractText, conversationId, }); if (result.success) { setResults(result.results); } } catch (error) { console.error("Search failed:", error); } }; const handleCompileReport = async () => { if (results.length === 0) return; try { const report = await compileReportMutation.mutateAsync({ results: [ { query, results, totalResults: results.length, executionTimeMs: 0, }, ], title: `Research Report: ${query}`, }); // Download report as markdown const element = document.createElement("a"); element.setAttribute( "href", "data:text/markdown;charset=utf-8," + encodeURIComponent(report) ); element.setAttribute("download", `research-${Date.now()}.md`); element.style.display = "none"; document.body.appendChild(element); element.click(); document.body.removeChild(element); } catch (error) { console.error("Report compilation failed:", error); } }; return (
{/* Search Input */}
setQuery(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSearch()} placeholder="Search the web..." className="text-xs h-8" disabled={searchMutation.isPending} />
{/* Options */}
setMaxResults(parseInt(e.target.value) || 5)} className="text-xs h-6 w-16" />
setIncludeScreenshots(checked as boolean)} />
setExtractText(checked as boolean)} />
{/* Results */} {results.length > 0 && (
{results.map((result, idx) => ( setExpandedResult(expandedResult === idx ? null : idx)} > {expandedResult === idx && ( {result.snippet && (

SNIPPET

{result.snippet}

)} {result.screenshotUrl && (

SCREENSHOT

Page screenshot
)} {result.extractedText && (

EXTRACTED TEXT

                            {result.extractedText}
                          
)}
)}
))}
)} {/* Error State */} {searchMutation.isError && (

{(searchMutation.error as any)?.message || "Search failed"}

)} {/* Empty State */} {!searchMutation.isPending && results.length === 0 && query && (

No results found

)}
); }