'use client' import React, { useState } from 'react' interface RAGSearchResult { text: string regulation_code: string regulation_name: string regulation_short: string category: string article?: string source_url?: string score: number } interface RAGSearchResponse { query: string results: RAGSearchResult[] count: number } export function RAGSearchPanel({ context, categories, onInsertText, }: { context: string categories?: string[] onInsertText?: (text: string) => void }) { const [isOpen, setIsOpen] = useState(false) const [query, setQuery] = useState('') const [isSearching, setIsSearching] = useState(false) const [results, setResults] = useState(null) const [error, setError] = useState(null) const [copiedId, setCopiedId] = useState(null) const buildQuery = () => { if (query.trim()) return query.trim() return context.substring(0, 200) } const handleSearch = async () => { const searchQuery = buildQuery() if (!searchQuery || searchQuery.length < 3) return setIsSearching(true) setError(null) try { const response = await fetch('/api/sdk/v1/rag/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: searchQuery, collection: 'bp_dsfa_corpus', top_k: 5, }), }) if (!response.ok) throw new Error(`Suche fehlgeschlagen (${response.status})`) const data: RAGSearchResponse = await response.json() setResults(data) } catch (err) { setError(err instanceof Error ? err.message : 'Suche fehlgeschlagen') setResults(null) } finally { setIsSearching(false) } } const handleInsert = (text: string, resultId: string) => { if (onInsertText) { onInsertText(text) } else { navigator.clipboard.writeText(text) } setCopiedId(resultId) setTimeout(() => setCopiedId(null), 2000) } if (!isOpen) { return ( ) } return (

DSFA-Wissenssuche (RAG)

{/* Search Input */}
setQuery(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()} placeholder={`Suchbegriff (oder leer fuer automatische Kontextsuche)...`} className="flex-1 px-3 py-2 text-sm border border-indigo-300 rounded-lg bg-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" />
{/* Error */} {error && (
{error}
)} {/* Results */} {results && results.results.length > 0 && (

{results.count} Ergebnis(se) gefunden

{results.results.map((r, idx) => { const resultId = `${r.regulation_code}-${idx}` return (
{r.regulation_name}{r.article ? ` — ${r.article}` : ''}

{r.text.length > 400 ? r.text.substring(0, 400) + '...' : r.text}

{r.regulation_short || r.regulation_code} ({(r.score * 100).toFixed(0)}%) {r.category && ( {r.category} )} {r.source_url && ( Quelle )}
) })}
)} {results && results.results.length === 0 && (
Keine Ergebnisse gefunden. Versuchen Sie einen anderen Suchbegriff.
)}
) }