Add metrics logging for chat completion requests (#195)

- Add token and performance metrics  for v1/chat/completions 
- Add Activity Page in UI
- Add /api/metrics endpoint

Contributed by @g2mt
This commit is contained in:
g2mt
2025-07-21 22:19:55 -07:00
committed by GitHub
parent 307e619521
commit 87dce5f8f6
15 changed files with 576 additions and 31 deletions

108
ui/src/pages/Activity.tsx Normal file
View File

@@ -0,0 +1,108 @@
import { useState, useEffect } from 'react';
import { useAPI } from '../contexts/APIProvider';
const ActivityPage = () => {
const { metrics, enableAPIEvents } = useAPI();
const [error, setError] = useState<string | null>(null);
useEffect(() => {
enableAPIEvents(true);
return () => {
enableAPIEvents(false);
};
}, []);
useEffect(() => {
if (metrics.length > 0) {
setError(null);
}
}, [metrics]);
const formatTimestamp = (timestamp: string) => {
return new Date(timestamp).toLocaleString();
};
const formatSpeed = (speed: number) => {
return speed.toFixed(2) + ' t/s';
};
const formatDuration = (ms: number) => {
return (ms / 1000).toFixed(2) + 's';
};
if (error) {
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">Activity</h1>
<div className="bg-red-50 border border-red-200 rounded-md p-4">
<p className="text-red-800">{error}</p>
</div>
</div>
);
}
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">Activity</h1>
{metrics.length === 0 ? (
<div className="text-center py-8">
<p className="text-gray-600">No metrics data available</p>
</div>
) : (
<div className="overflow-x-auto">
<table className="min-w-full divide-y">
<thead>
<tr>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Timestamp
</th>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Model
</th>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Input Tokens
</th>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Output Tokens
</th>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Processing Speed
</th>
<th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
Duration
</th>
</tr>
</thead>
<tbody className="divide-y">
{metrics.map((metric, index) => (
<tr key={`${metric.id}-${index}`}>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{formatTimestamp(metric.timestamp)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{metric.model}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{metric.input_tokens.toLocaleString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{metric.output_tokens.toLocaleString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{formatSpeed(metric.tokens_per_second)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
{formatDuration(metric.duration_ms)}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
);
};
export default ActivityPage;