File size: 2,321 Bytes
373030b | 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 | import { useState } from "react";
import { IconChevron, IconQuote } from "../lib/icons";
import { highlightMatch } from "../lib/highlight";
import { EmptyState, LoadingState } from "./ui/States";
function EvidenceItem({ citation, rank, defaultOpen }) {
const [open, setOpen] = useState(defaultOpen);
const meta = [
citation.page != null ? `page ${citation.page}` : null,
`chunk #${citation.chunk_index}`,
]
.filter(Boolean)
.join(" · ");
return (
<div className="evidence-item">
<button
className="evidence-item-head"
onClick={() => setOpen((o) => !o)}
aria-expanded={open}
aria-label={`Evidence ${rank} from ${citation.document_name}`}
>
<span className="evidence-rank">{rank}</span>
<span style={{ flex: 1, minWidth: 0 }}>
<span className="evidence-doc">{citation.document_name}</span>
<div className="evidence-meta">{meta}</div>
</span>
<span className={`chevron ${open ? "open" : ""}`}>
<IconChevron />
</span>
</button>
{open && (
<div className="evidence-body">
{highlightMatch(citation.excerpt, citation.match_text)}
{citation.score != null && (
<span className="evidence-score">relevance {citation.score}</span>
)}
</div>
)}
</div>
);
}
export default function EvidencePanel({ citations, loading }) {
return (
<div className="evidence-panel">
<div className="evidence-top">
<h3>Evidence</h3>
{citations?.length > 0 && (
<span className="evidence-meta">{citations.length} sources</span>
)}
</div>
<div className="evidence-list">
{loading ? (
<div style={{ padding: 8 }}>
<LoadingState lines={4} />
</div>
) : citations && citations.length > 0 ? (
citations.map((c, i) => (
<EvidenceItem
key={i}
citation={c}
rank={i + 1}
defaultOpen={i === 0}
/>
))
) : (
<EmptyState title="No evidence yet" icon={<IconQuote />}>
Ask a question — the source passages behind each answer appear here.
</EmptyState>
)}
</div>
</div>
);
}
|