Spaces:
Sleeping
Sleeping
| import { Database, FileSliders, Search, Shield } from 'lucide-react'; | |
| import { Badge } from '@/components/ui/badge'; | |
| import { | |
| Card, | |
| CardContent, | |
| CardDescription, | |
| CardHeader, | |
| CardTitle, | |
| } from '@/components/ui/card'; | |
| import type { RagConfig } from '@/types/admin'; | |
| function valueOrDash(value: unknown): string { | |
| if (value === null || value === undefined || value === '') { | |
| return '-'; | |
| } | |
| if (typeof value === 'boolean') { | |
| return value ? 'Ya' : 'Tidak'; | |
| } | |
| return String(value); | |
| } | |
| function ConfigRows({ | |
| rows, | |
| }: { | |
| rows: Array<[label: string, value: unknown]>; | |
| }) { | |
| return ( | |
| <dl className="grid gap-3 text-sm"> | |
| {rows.map(([label, value]) => ( | |
| <div | |
| className="flex items-start justify-between gap-4 rounded-lg border border-(--lecturer-border) px-3 py-2" | |
| key={label} | |
| > | |
| <dt className="text-muted-foreground">{label}</dt> | |
| <dd className="max-w-[60%] text-right font-medium break-words"> | |
| {valueOrDash(value)} | |
| </dd> | |
| </div> | |
| ))} | |
| </dl> | |
| ); | |
| } | |
| export function AdminRagSummary({ | |
| ragConfig, | |
| }: { | |
| ragConfig?: RagConfig | null; | |
| }) { | |
| const llm = ragConfig?.llm_config ?? {}; | |
| const vectorDb = ragConfig?.vector_db ?? {}; | |
| const retrieval = ragConfig?.retrieval ?? {}; | |
| return ( | |
| <section className="grid gap-6 xl:grid-cols-2"> | |
| <Card className="border-(--lecturer-border) bg-(--lecturer-surface) xl:col-span-2"> | |
| <CardHeader className="gap-3"> | |
| <div className="flex items-center justify-between gap-3"> | |
| <span className="rounded-xl bg-[var(--lecturer-primary-soft)] p-3 text-[var(--lecturer-primary)]"> | |
| <FileSliders className="size-5" /> | |
| </span> | |
| <Badge variant="outline">RAG</Badge> | |
| </div> | |
| <div> | |
| <CardTitle>Konfigurasi RAG</CardTitle> | |
| <CardDescription> | |
| Path config: {ragConfig?.path ?? '-'} | |
| </CardDescription> | |
| </div> | |
| </CardHeader> | |
| </Card> | |
| <Card className="border-(--lecturer-border) bg-(--lecturer-surface)"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <Shield className="size-5 text-[var(--lecturer-primary)]" /> | |
| LLM | |
| </CardTitle> | |
| <CardDescription>Ringkasan model aktif.</CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <ConfigRows | |
| rows={[ | |
| ['Provider', llm.active_provider], | |
| ['Model', llm.active_model], | |
| ['Temperature', llm.temperature], | |
| ['Max Tokens', llm.max_tokens], | |
| ['Request Timeout', llm.request_timeout], | |
| ]} | |
| /> | |
| </CardContent> | |
| </Card> | |
| <Card className="border-(--lecturer-border) bg-(--lecturer-surface)"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <Database className="size-5 text-[var(--lecturer-primary)]" /> | |
| VectorDB | |
| </CardTitle> | |
| <CardDescription>Ringkasan embedding dan chunk.</CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <ConfigRows | |
| rows={[ | |
| ['Embedding Model', vectorDb.embedding_model], | |
| ['Persist Path', vectorDb.persist_path], | |
| ['Chunk Size', vectorDb.chunk_size], | |
| ['Chunk Overlap', vectorDb.chunk_overlap], | |
| ]} | |
| /> | |
| </CardContent> | |
| </Card> | |
| <Card className="border-(--lecturer-border) bg-(--lecturer-surface) xl:col-span-2"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <Search className="size-5 text-[var(--lecturer-primary)]" /> | |
| Retrieval | |
| </CardTitle> | |
| <CardDescription> | |
| Ringkasan bobot dan batas konteks retrieval. | |
| </CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <ConfigRows | |
| rows={[ | |
| ['Top K', retrieval.top_k], | |
| ['Max Context Chars', retrieval.max_context_chars], | |
| ['BM25 Weight', retrieval.bm25_weight], | |
| ['Dense Weight', retrieval.dense_weight], | |
| ['Lexical Weight', retrieval.lexical_weight], | |
| [ | |
| 'Similarity Threshold', | |
| retrieval.similarity_threshold, | |
| ], | |
| ['History Turns', retrieval.history_turns], | |
| [ | |
| 'Candidate Pool Size', | |
| retrieval.candidate_pool_size, | |
| ], | |
| ['Neighbor Window', retrieval.neighbor_window], | |
| ['Reranker Model', retrieval.reranker_model], | |
| ['Enable Reranker', retrieval.enable_reranker], | |
| ]} | |
| /> | |
| </CardContent> | |
| </Card> | |
| </section> | |
| ); | |
| } | |