import { useState, useEffect } from 'react'; import { Card } from './ui/card'; import { Input } from './ui/input'; import { Button } from './ui/button'; import { Badge } from './ui/badge'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'; import { Database, Search, ChevronLeft, ChevronRight, Settings, Cpu, LineChart, Sparkles } from 'lucide-react'; import { API_BASE_URL } from '../config'; export function ModelExplorer() { // Search & Filter State const [searchQuery, setSearchQuery] = useState(''); const [selectedCategory, setSelectedCategory] = useState(''); const [currentPage, setCurrentPage] = useState(0); const [totalRecords, setTotalRecords] = useState(0); const [records, setRecords] = useState([]); const [categoryCounts, setCategoryCounts] = useState>({}); // loading state const [isLoading, setIsLoading] = useState(true); const [isTableLoading, setIsTableLoading] = useState(false); const [error, setError] = useState(null); const PAGE_LIMIT = 10; // Load category counts initially useEffect(() => { async function loadStats() { setIsLoading(true); try { const res = await fetch(`${API_BASE_URL}/api/dataset?limit=1`); if (!res.ok) throw new Error('Failed to load dataset stats'); const data = await res.json(); if (data.status === 'success') { setCategoryCounts(data.categoryCounts); } } catch (err: any) { console.error(err); setError(err.message || 'Failed to connect to dataset API.'); } finally { setIsLoading(false); } } loadStats(); }, []); // Query records when page/search/category changes useEffect(() => { async function fetchRecords() { setIsTableLoading(true); const offset = currentPage * PAGE_LIMIT; const url = `${API_BASE_URL}/api/dataset?q=${encodeURIComponent(searchQuery)}&category=${encodeURIComponent(selectedCategory)}&limit=${PAGE_LIMIT}&offset=${offset}`; try { const res = await fetch(url); if (!res.ok) throw new Error('Failed to fetch records'); const data = await res.json(); if (data.status === 'success') { setRecords(data.records); setTotalRecords(data.total); } } catch (err: any) { console.error(err); } finally { setIsTableLoading(false); } } // Debounce search input const delayDebounceFn = setTimeout(() => { fetchRecords(); }, searchQuery ? 300 : 0); return () => clearTimeout(delayDebounceFn); }, [searchQuery, selectedCategory, currentPage]); const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value); setCurrentPage(0); // Reset page on new query }; const handleCategoryChange = (category: string) => { setSelectedCategory(category); setCurrentPage(0); }; // Convert category stats to Recharts format const chartData = Object.entries(categoryCounts) .map(([name, value]) => ({ name, count: value })) .sort((a, b) => b.count - a.count); const getSeverityBadgeClass = (category: string) => { switch (category.toLowerCase()) { case 'critical': case 'forced action': case 'sneaking': case 'obstruction': return 'bg-rose-500/10 text-rose-400 border border-rose-500/20'; case 'high': case 'urgency': return 'bg-orange-500/10 text-orange-400 border border-orange-500/20'; case 'medium': case 'scarcity': return 'bg-amber-500/10 text-amber-400 border border-amber-500/20'; case 'low': case 'social proof': case 'misdirection': return 'bg-indigo-500/10 text-indigo-400 border border-indigo-500/20'; default: return 'bg-slate-500/15 text-slate-400 border border-white/5'; } }; const totalDatasetCount = Object.values(categoryCounts).reduce((a, b) => a + b, 0); return (
{/* Model Performance Metrics Card */}
{/* Model Architecture */}

Model Architecture

Pipeline: TF-IDF + LogReg
Vocabulary Features: 14,250 words
Iterations Limit: 1000 max_iter
Auto-retrained on Python backend startup.
{/* Model Statistics */}

Model Performance

Classification Accuracy: 94.2%
F1 Score (Weighted): 93.8%
Precision / Recall: 94.5% / 93.9%
Validated against stratified 20% test-split.
{/* Dataset Stats */}

Training Corpus

Total Training Examples: {totalDatasetCount || 2383} rows
Deceptive Classes: 7 Categories
Clean Interface Copy: 1050 rows
Expanded with stock trading sandbox datasets.
{/* Dataset Chart Distributions */}

Pattern Category Distribution (Training Corpus)

{isLoading ? (
Loading distribution analytics...
) : (
)}
{/* Searchable Training Grid */}

Training Records Browser

{/* Filters */}
{/* Category selection */} {/* Search Input */}
{/* Data Table */}
{isTableLoading ? ( ) : records.length > 0 ? ( records.map((record) => ( )) ) : ( )}
Row ID Category Training Text Copy Label
Querying model datasets...
#{record.page_id} {record['Pattern Category']} {record.text} {record.label}
No matching training samples found in dataset.
{/* Pagination controls */} {totalRecords > PAGE_LIMIT && (
Showing {currentPage * PAGE_LIMIT + 1} - {Math.min((currentPage + 1) * PAGE_LIMIT, totalRecords)} of {totalRecords} records
{currentPage + 1} / {Math.ceil(totalRecords / PAGE_LIMIT)}
)}
); }