Spaces:
Runtime error
Runtime error
File size: 3,403 Bytes
a45ece3 3da97ef a45ece3 3da97ef a45ece3 3da97ef a45ece3 3da97ef a45ece3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | import { useMemo } from 'react'
import { useAppStore } from '@/store/appStore'
import type { Evidence } from '@/lib/types'
export function EvidenceDrawer() {
const run = useAppStore((s) => s.runs.find((r) => r.id === s.currentRunId))
const isOpen = useAppStore((s) => s.ui.evidenceOpen)
const claimId = useAppStore((s) => s.ui.selectedClaimId)
const close = useAppStore((s) => s.closeEvidence)
const claim = useMemo(() => run?.report?.claims.find((c) => c.id === claimId), [run, claimId])
const verdict = useMemo(() => run?.report?.verdicts.find((v) => v.claim_id === claimId), [run, claimId])
const evidences = useMemo(() => {
if (!run?.report) return [] as Evidence[]
const report = run.report
// 1) Prefer cited evidence for this claim
const citedIds = verdict?.citation_ids || []
if (citedIds.length > 0) {
const cited = report.evidence.filter((e) => citedIds.includes(e.doc_id))
if (cited.length > 0) return cited
}
// 2) Fallback to per-claim retrieved evidence
const byClaim = report.evidence_by_claim?.[claimId ?? ''] || []
if (byClaim.length > 0) return byClaim
// 3) Final fallback: top-scored global evidence
const sorted = [...report.evidence].sort((a, b) => (b.score ?? 0) - (a.score ?? 0))
return sorted.slice(0, 5)
}, [run, verdict, claimId])
if (!isOpen) return null
return (
<div role="dialog" aria-modal="true" className="fixed inset-0 z-50">
<div className="absolute inset-0 bg-black/40" onClick={close} />
<div className="absolute top-0 right-0 h-full w-full sm:w-[420px] bg-card text-card-foreground border-l shadow-xl overflow-auto" tabIndex={-1} aria-labelledby="evidence-title">
<div className="p-4 border-b flex items-start justify-between">
<h3 id="evidence-title" className="font-semibold pr-4">Evidence & Rationale</h3>
<button className="text-sm px-2 py-1 rounded-md border hover:bg-muted" onClick={close}>Close</button>
</div>
<div className="p-4 space-y-4">
{claim && (
<div>
<div className="text-xs text-muted-foreground">Claim</div>
<div className="mt-1 text-sm">{claim.text}</div>
</div>
)}
<div>
<div className="text-xs text-muted-foreground">Top Evidence</div>
<ul className="mt-2 space-y-3">
{evidences.map((e, idx) => (
<li key={`${e.doc_id}-${idx}`} className="rounded-md border p-3">
<div className="text-xs text-muted-foreground">{e.source || e.doc_id} • score {(e.score ?? 0).toFixed(2)}</div>
<div className="mt-1 text-sm whitespace-pre-wrap">{e.snippet}</div>
{e.metadata && (
<pre className="mt-2 text-xs text-muted-foreground whitespace-pre-wrap">{JSON.stringify(e.metadata, null, 2)}</pre>
)}
</li>
))}
{evidences.length === 0 && <li className="text-sm text-muted-foreground">No evidence</li>}
</ul>
</div>
{verdict?.rationale && (
<div>
<div className="text-xs text-muted-foreground">Model Rationale</div>
<div className="mt-1 text-sm whitespace-pre-wrap">{verdict.rationale}</div>
</div>
)}
</div>
</div>
</div>
)
} |