/** * AI API Logs Panel Component * * Monitor OpenAI API calls with: * - Call list with filtering by provider * - Token usage statistics * - Response time tracking * - Error monitoring */ import React, { useState, useEffect, useCallback } from 'react'; import { Zap, RefreshCw, Filter, Clock, Brain, Bot, Check, XCircle, AlertTriangle, BarChart3, TrendingUp, Cpu, Activity, Hash } from 'lucide-react'; import { getToken } from '../../services/api'; const API_BASE = import.meta.env.VITE_API_URL || ''; // Provider badge (OpenAI) const ProviderBadge = ({ provider }) => { const config = { openai: { bg: '#dbeafe', color: '#2563eb', icon: '🤖', label: 'OpenAI' } }; const { bg, color, icon, label } = config[provider] || config.openai; return ( {icon} {label} ); }; // Status badge const StatusBadge = ({ status }) => { const config = { success: { bg: '#d1fae5', color: '#059669', icon: }, error: { bg: '#fee2e2', color: '#dc2626', icon: }, timeout: { bg: '#fef3c7', color: '#d97706', icon: } }; const { bg, color, icon } = config[status] || config.success; return ( {icon} {status} ); }; // Response time indicator const ResponseTimeIndicator = ({ ms }) => { if (!ms) return -; let color; if (ms < 1000) color = '#10b981'; else if (ms < 3000) color = '#f59e0b'; else color = '#ef4444'; return ( {ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`} ); }; // Token display const TokenDisplay = ({ tokens }) => { if (!tokens) return -; return ( {tokens.toLocaleString()} ); }; function AILogsPanel() { const [logs, setLogs] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Filters const [provider, setProvider] = useState(''); const [operation, setOperation] = useState(''); const [status, setStatus] = useState(''); const [hours, setHours] = useState(24); const [limit, setLimit] = useState(100); const [autoRefresh, setAutoRefresh] = useState(true); // Fetch logs const fetchLogs = useCallback(async () => { setLoading(true); setError(null); try { const token = getToken(); const params = new URLSearchParams({ limit: limit.toString(), hours: hours.toString() }); if (provider) params.append('provider', provider); if (operation) params.append('operation', operation); if (status) params.append('status', status); const response = await fetch(`${API_BASE}/api/admin/ai-logs?${params}`, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); if (response.ok) { const data = await response.json(); if (data.success) { setLogs(data.logs || []); setStats(data.stats || null); } } else { throw new Error('Failed to fetch AI logs'); } } catch (err) { setError(err.message); } finally { setLoading(false); } }, [provider, operation, status, hours, limit]); useEffect(() => { fetchLogs(); }, [fetchLogs]); // Auto-refresh every 10 seconds useEffect(() => { if (!autoRefresh) return; const interval = setInterval(fetchLogs, 10000); return () => clearInterval(interval); }, [autoRefresh, fetchLogs]); // Format timestamp const formatTime = (isoString) => { if (!isoString) return '-'; const date = new Date(isoString); return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); }; return (
{/* Header */}

AI API Logs

Monitor OpenAI API calls in real-time

{/* Stats Cards */} {stats && (
{stats.total_calls?.toLocaleString() || 0} Total Calls ({hours}h)
🌟
{stats.openai_calls?.toLocaleString() || 0} OpenAI Calls
âš¡
{stats.total_calls?.toLocaleString() || 0} Total Calls
{stats.success_rate || 100}% Success Rate
{stats.total_tokens?.toLocaleString() || 0} Total Tokens
{stats.avg_response_time_ms || 0}ms Avg Response
)} {/* Filters */}
Filters:
setOperation(e.target.value)} style={{ padding: '0.5rem', borderRadius: '6px', border: '1px solid rgba(255,255,255,0.1)', backgroundColor: 'rgba(0,0,0,0.3)', color: 'white', fontSize: '0.9rem', width: '150px' }} />
{/* Error display */} {error && (
{error}
)} {/* Logs Table */}
{loading && logs.length === 0 ? (

Loading AI logs...

) : logs.length === 0 ? (

No AI API logs found

AI calls will appear here once made

) : (
{logs.map((log, index) => ( e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.03)'} onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'transparent'} > ))}
Time Provider Operation Model Tokens Response Status
{formatTime(log.created_at)} {log.operation || '-'} {log.model || '-'}
)}
{/* Footer */}
Showing {logs.length} logs Last updated: {new Date().toLocaleTimeString()}
); } export default AILogsPanel;