File size: 5,990 Bytes
53a811b
1e5ae4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53a811b
1e5ae4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45e7f4a
1e5ae4b
 
 
 
 
53a811b
1e5ae4b
 
53a811b
1e5ae4b
 
 
 
 
 
 
 
 
 
 
 
 
53a811b
1e5ae4b
 
53a811b
1e5ae4b
 
 
 
 
 
 
45e7f4a
 
1e5ae4b
 
 
 
 
 
 
 
53a811b
1e5ae4b
 
53a811b
1e5ae4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53a811b
1e5ae4b
 
53a811b
1e5ae4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53a811b
 
 
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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>
    );
}