/**
* OpenAI API Logs Panel Component
*
* Simple, clean panel to monitor OpenAI API calls:
* - Real-time log viewer (last 100 calls from memory)
* - Token usage statistics
* - Response time tracking
* - Operation breakdown
*/
import React, { useState, useEffect, useCallback } from 'react';
import {
Zap, RefreshCw, Clock, Brain, Trash2,
Check, XCircle, AlertTriangle, BarChart3,
Activity, Hash, Cpu, TrendingUp
} from 'lucide-react';
import { getToken } from '../../services/api';
const API_BASE = import.meta.env.VITE_API_URL || '';
// Status badge
const StatusBadge = ({ status }) => {
const isSuccess = status === 'success';
return (
{isSuccess ? : }
{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`}
);
};
function OpenAILogsPanel() {
const [logs, setLogs] = useState([]);
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [autoRefresh, setAutoRefresh] = useState(true);
// Fetch logs
const fetchLogs = useCallback(async () => {
setLoading(true);
setError(null);
try {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/openai-logs?limit=50`, {
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 OpenAI logs');
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, []);
// Clear logs
const clearLogs = async () => {
if (!window.confirm('Clear all OpenAI API logs from memory?')) return;
try {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/openai-logs`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
setLogs([]);
setStats(null);
}
} catch (err) {
setError(err.message);
}
};
useEffect(() => {
fetchLogs();
}, [fetchLogs]);
// Auto-refresh every 5 seconds
useEffect(() => {
if (!autoRefresh) return;
const interval = setInterval(fetchLogs, 5000);
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 */}
{/* Stats Cards */}
{stats && (
Success Rate
{stats.success_rate || 100}%
Total Tokens
{(stats.total_tokens || 0).toLocaleString()}
Avg Response
{stats.avg_response_time_ms || 0}ms
)}
{/* Operations Breakdown */}
{stats?.operations && Object.keys(stats.operations).length > 0 && (
Operations Breakdown
{Object.entries(stats.operations).map(([op, count]) => (
{op}: {count}
))}
)}
{/* Error display */}
{error && (
)}
{/* Logs Table */}
| Time |
Operation |
Model |
Tokens |
Time |
Status |
{logs.length === 0 ? (
|
No API calls logged yet
Logs appear here when the app makes OpenAI API calls
|
) : (
logs.map((log, idx) => (
|
{formatTime(log.timestamp)}
|
{log.operation}
|
{log.model}
|
{log.total_tokens ? (
{log.total_tokens.toLocaleString()}
) : '-'}
|
|
{log.error_message && (
{log.error_message}
)}
|
))
)}
{/* Footer Info */}
📊 Showing {logs.length} of last 100 calls (stored in-memory)
{autoRefresh && '🔄 Auto-refreshing every 5s'}
{/* Spinner styles */}
);
}
export default OpenAILogsPanel;