Files
openproxy/dashboard/components/MetricsOverview.tsx
Claude b88fc8ead7 feat: add Next.js metrics dashboard for real-time visualization
Add a lightweight Next.js dashboard to visualize OpenProxy metrics in real-time. The dashboard provides comprehensive insights into LLM API usage, costs, and performance.

Features:
- Real-time metrics overview (requests, tokens, costs, response times)
- Model breakdown with usage statistics
- Hourly trends visualization with charts
- Recent requests table with detailed information
- Auto-refresh every 30 seconds
- Configurable time ranges (1h, 6h, 24h, 7d)

Technical details:
- Built with Next.js 14 and React 18
- Uses Recharts for data visualization
- Connects directly to PostgreSQL database
- Runs on port 3008 by default
- TypeScript for type safety
- Minimal dependencies for lightweight deployment

The dashboard complements the proxy server by providing a user-friendly interface for monitoring and analyzing LLM API usage patterns.
2025-11-19 00:04:28 +00:00

104 lines
2.2 KiB
TypeScript

interface MetricsOverviewProps {
summary: {
totalRequests: number;
totalTokens: number;
totalCost: number;
avgResponseTime: number;
uniqueModels: number;
uniqueClients: number;
};
}
export default function MetricsOverview({ summary }: MetricsOverviewProps) {
const metrics = [
{
label: 'Total Requests',
value: summary.totalRequests.toLocaleString(),
icon: '📊',
},
{
label: 'Total Tokens',
value: summary.totalTokens.toLocaleString(),
icon: '🔢',
},
{
label: 'Total Cost',
value: `$${summary.totalCost.toFixed(4)}`,
icon: '💰',
},
{
label: 'Avg Response Time',
value: `${Math.round(summary.avgResponseTime)}ms`,
icon: '⚡',
},
{
label: 'Unique Models',
value: summary.uniqueModels.toString(),
icon: '🤖',
},
{
label: 'Unique Clients',
value: summary.uniqueClients.toString(),
icon: '👥',
},
];
return (
<div style={styles.container}>
<h2 style={styles.title}>Overview</h2>
<div style={styles.grid}>
{metrics.map((metric) => (
<div key={metric.label} style={styles.card}>
<div style={styles.icon}>{metric.icon}</div>
<div style={styles.content}>
<div style={styles.label}>{metric.label}</div>
<div style={styles.value}>{metric.value}</div>
</div>
</div>
))}
</div>
</div>
);
}
const styles = {
container: {
marginBottom: '2rem',
},
title: {
fontSize: '1.5rem',
marginBottom: '1.5rem',
color: '#2c3e50',
},
grid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
gap: '1rem',
},
card: {
backgroundColor: '#fff',
padding: '1.5rem',
borderRadius: '8px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
display: 'flex',
gap: '1rem',
alignItems: 'center',
},
icon: {
fontSize: '2rem',
},
content: {
flex: 1,
},
label: {
fontSize: '0.9rem',
color: '#7f8c8d',
marginBottom: '0.25rem',
},
value: {
fontSize: '1.5rem',
fontWeight: 600,
color: '#2c3e50',
},
};