690519:1631 224 to 226 AI #01
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
// File: components/ai/intent-classification/analytics/analytics-summary-cards.tsx
|
||||
// Change Log
|
||||
// - 2026-05-19: สร้าง Summary Cards สำหรับ Analytics Dashboard (T036, US3).
|
||||
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import type { ClassificationAnalytics } from '@/lib/services/ai-intent.service';
|
||||
|
||||
interface AnalyticsSummaryCardsProps {
|
||||
data: ClassificationAnalytics;
|
||||
}
|
||||
|
||||
/**
|
||||
* แสดงสรุปสถิติหลักในรูปแบบ Cards
|
||||
* Total Requests, Pattern Hit Rate, Avg Confidence, Avg Latency
|
||||
*/
|
||||
export function AnalyticsSummaryCards({ data }: AnalyticsSummaryCardsProps) {
|
||||
const cards = [
|
||||
{
|
||||
title: 'Total Requests',
|
||||
value: data.totalRequests.toLocaleString(),
|
||||
subtitle: `${data.successCount} สำเร็จ / ${data.failedCount} ล้มเหลว`,
|
||||
color: 'text-blue-600',
|
||||
},
|
||||
{
|
||||
title: 'Pattern Hit Rate',
|
||||
value: `${data.patternHitRate}%`,
|
||||
subtitle: 'เป้าหมาย: 70-80%',
|
||||
color: data.patternHitRate >= 70 ? 'text-green-600' : 'text-amber-600',
|
||||
},
|
||||
{
|
||||
title: 'Avg Confidence',
|
||||
value: data.avgConfidence.toFixed(2),
|
||||
subtitle: 'เป้าหมาย: ≥ 0.70',
|
||||
color: data.avgConfidence >= 0.7 ? 'text-green-600' : 'text-amber-600',
|
||||
},
|
||||
{
|
||||
title: 'Avg Latency',
|
||||
value: `${data.avgLatencyMs.toFixed(1)}ms`,
|
||||
subtitle: 'Pattern < 10ms, LLM < 2000ms',
|
||||
color: data.avgLatencyMs < 100 ? 'text-green-600' : 'text-amber-600',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{cards.map((card) => (
|
||||
<Card key={card.title}>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">
|
||||
{card.title}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className={`text-2xl font-bold ${card.color}`}>
|
||||
{card.value}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{card.subtitle}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// File: components/ai/intent-classification/analytics/intent-breakdown-table.tsx
|
||||
// Change Log
|
||||
// - 2026-05-19: สร้าง Intent Breakdown Table สำหรับ Analytics Dashboard (T036, US3).
|
||||
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import type { IntentStats } from '@/lib/services/ai-intent.service';
|
||||
|
||||
interface IntentBreakdownTableProps {
|
||||
data: IntentStats[];
|
||||
}
|
||||
|
||||
/**
|
||||
* ตารางแสดงสถิติแยกตาม intent code พร้อม bar แสดง pattern vs llm
|
||||
*/
|
||||
export function IntentBreakdownTable({ data }: IntentBreakdownTableProps) {
|
||||
if (data.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">ยังไม่มีข้อมูล</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Intent Code</TableHead>
|
||||
<TableHead className="text-right">Total</TableHead>
|
||||
<TableHead className="text-right">Pattern</TableHead>
|
||||
<TableHead className="text-right">LLM</TableHead>
|
||||
<TableHead className="text-right">Avg Confidence</TableHead>
|
||||
<TableHead className="w-[120px]">Pattern Rate</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((row) => {
|
||||
const patternRate =
|
||||
row.count > 0 ? (row.patternHits / row.count) * 100 : 0;
|
||||
return (
|
||||
<TableRow key={row.intentCode}>
|
||||
<TableCell className="font-mono text-sm">
|
||||
{row.intentCode}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">{row.count}</TableCell>
|
||||
<TableCell className="text-right">{row.patternHits}</TableCell>
|
||||
<TableCell className="text-right">{row.llmHits}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{row.avgConfidence.toFixed(2)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-2">
|
||||
<Progress value={patternRate} className="h-2" />
|
||||
<span className="text-xs text-muted-foreground w-10 text-right">
|
||||
{patternRate.toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// File: components/ai/intent-classification/analytics/method-breakdown-table.tsx
|
||||
// Change Log
|
||||
// - 2026-05-19: สร้าง Method Breakdown Table สำหรับ Analytics Dashboard (T036, US3).
|
||||
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import type { MethodStats } from '@/lib/services/ai-intent.service';
|
||||
|
||||
interface MethodBreakdownTableProps {
|
||||
data: MethodStats[];
|
||||
}
|
||||
|
||||
/** แปลงชื่อ method เป็น label + สี */
|
||||
function methodBadge(method: string) {
|
||||
switch (method) {
|
||||
case 'pattern':
|
||||
return <Badge variant="default">Pattern Match</Badge>;
|
||||
case 'llm_fallback':
|
||||
return <Badge variant="secondary">LLM Fallback</Badge>;
|
||||
case 'semaphore_overflow':
|
||||
return <Badge variant="destructive">Semaphore Overflow</Badge>;
|
||||
case 'llm_error':
|
||||
return <Badge variant="destructive">LLM Error</Badge>;
|
||||
default:
|
||||
return <Badge variant="outline">{method}</Badge>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ตารางแสดงสถิติแยกตาม method (pattern, llm_fallback, etc.)
|
||||
*/
|
||||
export function MethodBreakdownTable({ data }: MethodBreakdownTableProps) {
|
||||
if (data.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">ยังไม่มีข้อมูล</p>;
|
||||
}
|
||||
|
||||
const total = data.reduce((sum, d) => sum + d.count, 0);
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Method</TableHead>
|
||||
<TableHead className="text-right">Count</TableHead>
|
||||
<TableHead className="text-right">%</TableHead>
|
||||
<TableHead className="text-right">Avg Confidence</TableHead>
|
||||
<TableHead className="text-right">Avg Latency</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((row) => (
|
||||
<TableRow key={row.method}>
|
||||
<TableCell>{methodBadge(row.method)}</TableCell>
|
||||
<TableCell className="text-right">{row.count}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{total > 0 ? ((row.count / total) * 100).toFixed(1) : 0}%
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{row.avgConfidence.toFixed(2)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{row.avgLatencyMs.toFixed(1)}ms
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// File: components/ai/intent-classification/analytics/recalibration-panel.tsx
|
||||
// Change Log
|
||||
// - 2026-05-19: สร้าง Recalibration Panel สำหรับ Analytics Dashboard (T036, US3).
|
||||
|
||||
'use client';
|
||||
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import type { RecalibrationRecommendation } from '@/lib/services/ai-intent.service';
|
||||
|
||||
interface RecalibrationPanelProps {
|
||||
data: RecalibrationRecommendation[];
|
||||
}
|
||||
|
||||
/**
|
||||
* แสดงคำแนะนำ Intent ที่ควรเพิ่ม pattern เพื่อลด LLM Calls
|
||||
* ตาม SC-001: เป้าหมาย Pattern Hit Rate 70-80%
|
||||
*/
|
||||
export function RecalibrationPanel({ data }: RecalibrationPanelProps) {
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Alert>
|
||||
<AlertTitle>ไม่มีคำแนะนำ</AlertTitle>
|
||||
<AlertDescription>
|
||||
ยังไม่มี Intent ที่ต้องเพิ่ม Pattern — Pattern Hit Rate อยู่ในระดับดี
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<Alert variant="destructive">
|
||||
<AlertTriangle className="h-4 w-4" />
|
||||
<AlertTitle>ควรเพิ่ม Pattern</AlertTitle>
|
||||
<AlertDescription>
|
||||
Intent ด้านล่างถูก classify ด้วย LLM บ่อย — การเพิ่ม keyword/regex pattern
|
||||
จะช่วยลดภาระ LLM และเพิ่มความเร็ว
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Intent Code</TableHead>
|
||||
<TableHead className="text-right">LLM Calls</TableHead>
|
||||
<TableHead className="text-right">Avg Confidence</TableHead>
|
||||
<TableHead className="text-right">Priority</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((row) => (
|
||||
<TableRow key={row.intentCode}>
|
||||
<TableCell className="font-mono text-sm">
|
||||
{row.intentCode}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">{row.llmCallCount}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{row.avgConfidence.toFixed(2)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right font-medium text-amber-600">
|
||||
{row.priority}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user