Add Chart.js visualization templates for token reports

- Copy token_usage.html from remote commit e041cb8e
- Copy ai_cost_analysis.html from remote commit e041cb8e
- Provides interactive visualizations for token analytics
- Charts show: usage trends, cost breakdowns, model comparisons
- Completes Phase D token analytics implementation
This commit is contained in:
IGNY8 VPS (Salman)
2025-12-23 07:32:49 +00:00
parent 6971d416c3
commit d402a135ae
2 changed files with 567 additions and 0 deletions

View File

@@ -0,0 +1,349 @@
{% extends "admin/base_site.html" %}
{% load static %}
{% block content %}
<div class="px-6 py-4">
<!-- Page Header -->
<div class="mb-8 flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-2">AI Cost Analysis</h1>
<p class="text-gray-600 dark:text-gray-400">Comprehensive cost breakdown with model pricing and predictions</p>
</div>
<div>
<form method="get" class="flex gap-2 items-center">
<label class="text-sm text-gray-600 dark:text-gray-400">Time Period:</label>
<select name="days" onchange="this.form.submit()" class="px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
<option value="7" {% if days_filter == 7 %}selected{% endif %}>Last 7 Days</option>
<option value="30" {% if days_filter == 30 %}selected{% endif %}>Last 30 Days</option>
<option value="60" {% if days_filter == 60 %}selected{% endif %}>Last 60 Days</option>
<option value="90" {% if days_filter == 90 %}selected{% endif %}>Last 90 Days</option>
</select>
</form>
</div>
</div>
<!-- Summary Cards -->
<div class="grid grid-cols-1 md:grid-cols-5 gap-6 mb-8">
<div class="bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg shadow-lg p-6 text-white">
<h3 class="text-sm font-medium opacity-90 mb-2">Total Cost</h3>
<p class="text-3xl font-bold">${{ total_cost|floatformat:2 }}</p>
<p class="text-xs opacity-75 mt-1">{{ total_calls }} API calls</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Avg Cost/Call</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white">${{ avg_cost_per_call|floatformat:4 }}</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Projected Monthly</h3>
<p class="text-3xl font-bold text-purple-600 dark:text-purple-400">${{ projected_monthly|floatformat:2 }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Based on last 7 days</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Efficiency Score</h3>
<p class="text-3xl font-bold text-green-600 dark:text-green-400">{{ efficiency_score }}%</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Successful cost ratio</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Wasted Cost</h3>
<p class="text-3xl font-bold text-red-600 dark:text-red-400">${{ failed_cost|floatformat:2 }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ wasted_percentage|floatformat:1 }}% of total</p>
</div>
</div>
<!-- Cost Trends Chart -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Daily Cost & Volume Trends</h2>
<canvas id="costTrendsChart" height="80"></canvas>
</div>
<!-- Model Comparison Matrix -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Model Cost Comparison & Efficiency</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Model</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Total Cost</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">% of Total</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">API Calls</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Avg Cost</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Total Tokens</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Cost/1K Tokens</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for model in cost_by_model %}
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
<span class="px-2 py-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded">
{{ model.model|default:"Unknown" }}
</span>
</td>
<td class="px-6 py-4 text-sm text-right font-semibold text-gray-900 dark:text-white">
${{ model.total_cost|floatformat:2 }}
</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">
{{ model.cost_percentage|floatformat:1 }}%
<div class="mt-1 w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5">
<div class="bg-blue-600 dark:bg-blue-400 h-1.5 rounded-full" style="width: {{ model.cost_percentage }}%"></div>
</div>
</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">
{{ model.call_count }}
</td>
<td class="px-6 py-4 text-sm text-right text-gray-900 dark:text-white">
${{ model.avg_cost|floatformat:4 }}
</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">
{{ model.total_tokens|floatformat:0 }}
</td>
<td class="px-6 py-4 text-sm text-right text-gray-900 dark:text-white">
${{ model.cost_per_1k_tokens|floatformat:4 }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Two Column Layout -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
<!-- Cost by Account -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Top Spenders (By Account)</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Account</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Cost</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Calls</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for account in cost_by_account %}
<tr>
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white">
<a href="/admin/igny8_core_auth/account/{{ account.account_id }}/" class="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300">
{{ account.account__name|default:"Unknown" }}
</a>
</td>
<td class="px-4 py-3 text-sm text-right font-semibold text-gray-900 dark:text-white">
${{ account.total_cost|floatformat:2 }}
</td>
<td class="px-4 py-3 text-sm text-right text-gray-600 dark:text-gray-400">
{{ account.call_count }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Cost by Function -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Cost by Function/Operation</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Function</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Cost</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Calls</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for func in cost_by_function %}
<tr>
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white">
{{ func.function|default:"Unknown" }}
</td>
<td class="px-4 py-3 text-sm text-right font-semibold text-gray-900 dark:text-white">
${{ func.total_cost|floatformat:2 }}
</td>
<td class="px-4 py-3 text-sm text-right text-gray-600 dark:text-gray-400">
{{ func.call_count }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Cost Anomalies -->
{% if anomalies %}
<div class="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg shadow p-6 mb-8">
<div class="flex items-start">
<div class="flex-shrink-0">
<svg class="h-6 w-6 text-amber-600 dark:text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
<div class="ml-3 flex-1">
<h3 class="text-lg font-semibold text-amber-800 dark:text-amber-200 mb-3">Cost Anomalies Detected</h3>
<p class="text-sm text-amber-700 dark:text-amber-300 mb-4">The following API calls had unusually high costs (>3x average):</p>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-amber-200 dark:divide-amber-800">
<thead>
<tr>
<th class="px-4 py-2 text-left text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Model</th>
<th class="px-4 py-2 text-left text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Function</th>
<th class="px-4 py-2 text-left text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Account</th>
<th class="px-4 py-2 text-right text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Cost</th>
<th class="px-4 py-2 text-right text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Tokens</th>
<th class="px-4 py-2 text-left text-xs font-medium text-amber-700 dark:text-amber-300 uppercase">Date</th>
</tr>
</thead>
<tbody class="divide-y divide-amber-200 dark:divide-amber-800">
{% for anomaly in anomalies %}
<tr>
<td class="px-4 py-2 text-sm text-amber-900 dark:text-amber-100">{{ anomaly.model }}</td>
<td class="px-4 py-2 text-sm text-amber-900 dark:text-amber-100">{{ anomaly.function }}</td>
<td class="px-4 py-2 text-sm text-amber-900 dark:text-amber-100">{{ anomaly.account__name }}</td>
<td class="px-4 py-2 text-sm text-right font-bold text-amber-900 dark:text-amber-100">${{ anomaly.cost|floatformat:2 }}</td>
<td class="px-4 py-2 text-sm text-right text-amber-800 dark:text-amber-200">{{ anomaly.tokens|floatformat:0 }}</td>
<td class="px-4 py-2 text-sm text-amber-800 dark:text-amber-200">{{ anomaly.created_at|date:"M d, H:i" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Hourly Cost Distribution -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Peak Cost Hours</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Hour of Day</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Total Cost</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">API Calls</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Activity Level</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for hour in hourly_cost %}
<tr>
<td class="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
{{ hour.hour|floatformat:0 }}:00 - {{ hour.hour|add:1|floatformat:0 }}:00
</td>
<td class="px-6 py-4 text-sm text-right text-gray-900 dark:text-white">
${{ hour.total_cost|floatformat:2 }}
</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">
{{ hour.call_count }}
</td>
<td class="px-6 py-4 text-sm">
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
{% widthratio hour.total_cost total_cost 100 as percentage %}
<div class="bg-gradient-to-r from-blue-500 to-purple-600 h-2 rounded-full" style="width: {% if percentage > 100 %}100{% else %}{{ percentage }}{% endif %}%"></div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Cost & Volume Trends Chart
const ctx = document.getElementById('costTrendsChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: {{ daily_cost_labels|safe }},
datasets: [
{
label: 'Daily Cost ($)',
data: {{ daily_cost_data|safe }},
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4,
fill: true,
yAxisID: 'y'
},
{
label: 'API Calls',
data: {{ daily_call_data|safe }},
borderColor: 'rgb(168, 85, 247)',
backgroundColor: 'rgba(168, 85, 247, 0.1)',
tension: 0.4,
fill: true,
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: true,
interaction: {
mode: 'index',
intersect: false
},
plugins: {
legend: {
display: true,
position: 'top'
},
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.datasetIndex === 0) {
label += '$' + context.parsed.y.toFixed(2);
} else {
label += context.parsed.y;
}
return label;
}
}
}
},
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
title: {
display: true,
text: 'Cost ($)'
},
ticks: {
callback: function(value) {
return '$' + value.toFixed(2);
}
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
title: {
display: true,
text: 'API Calls'
},
grid: {
drawOnChartArea: false
}
}
}
}
});
</script>
{% endblock %}

View File

@@ -0,0 +1,218 @@
{% extends "admin/base_site.html" %}
{% load static %}
{% block content %}
<div class="px-6 py-4">
<!-- Page Header -->
<div class="mb-8 flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-2">Token Usage Report</h1>
<p class="text-gray-600 dark:text-gray-400">Multi-dimensional token consumption analytics</p>
</div>
<div>
<form method="get" class="flex gap-2 items-center">
<label class="text-sm text-gray-600 dark:text-gray-400">Time Period:</label>
<select name="days" onchange="this.form.submit()" class="px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
<option value="7" {% if days_filter == 7 %}selected{% endif %}>Last 7 Days</option>
<option value="30" {% if days_filter == 30 %}selected{% endif %}>Last 30 Days</option>
<option value="60" {% if days_filter == 60 %}selected{% endif %}>Last 60 Days</option>
<option value="90" {% if days_filter == 90 %}selected{% endif %}>Last 90 Days</option>
</select>
</form>
</div>
</div>
<!-- Summary Cards -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Total Tokens</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white">{{ total_tokens|floatformat:0 }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ total_calls }} API calls</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Avg Tokens/Call</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white">{{ avg_tokens_per_call|floatformat:0 }}</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Success Rate</h3>
<p class="text-3xl font-bold text-green-600 dark:text-green-400">{{ success_rate }}%</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ successful_tokens|floatformat:0 }} tokens</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Total Cost</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white">${{ total_cost|floatformat:2 }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">${{ cost_per_1k_tokens|floatformat:4 }} per 1K</p>
</div>
</div>
<!-- Token Trends Chart -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Token Usage Trends</h2>
<canvas id="tokenTrendsChart" height="80"></canvas>
</div>
<!-- Two Column Layout -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
<!-- Token Usage by Model -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Token Usage by Model</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Model</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Tokens</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Calls</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Cost</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for item in token_by_model %}
<tr>
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white">{{ item.model|default:"Unknown" }}</td>
<td class="px-4 py-3 text-sm text-right text-gray-900 dark:text-white">{{ item.total_tokens|floatformat:0 }}</td>
<td class="px-4 py-3 text-sm text-right text-gray-600 dark:text-gray-400">{{ item.call_count }}</td>
<td class="px-4 py-3 text-sm text-right text-gray-900 dark:text-white">${{ item.total_cost|floatformat:2 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Token Usage by Function -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Token Usage by Function</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Function</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Tokens</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Calls</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for item in token_by_function %}
<tr>
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white">{{ item.function|default:"Unknown" }}</td>
<td class="px-4 py-3 text-sm text-right text-gray-900 dark:text-white">{{ item.total_tokens|floatformat:0 }}</td>
<td class="px-4 py-3 text-sm text-right text-gray-600 dark:text-gray-400">{{ item.call_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Top Token Consumers -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Top Token Consumers (By Account)</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Account</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Total Tokens</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">API Calls</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Total Cost</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Avg Tokens</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for consumer in token_by_account %}
<tr>
<td class="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
<a href="/admin/igny8_core_auth/account/{{ consumer.account_id }}/" class="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300">
{{ consumer.account__name|default:"Unknown Account" }}
</a>
</td>
<td class="px-6 py-4 text-sm text-right text-gray-900 dark:text-white font-semibold">{{ consumer.total_tokens|floatformat:0 }}</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">{{ consumer.call_count }}</td>
<td class="px-6 py-4 text-sm text-right text-gray-900 dark:text-white">${{ consumer.total_cost|floatformat:2 }}</td>
<td class="px-6 py-4 text-sm text-right text-gray-600 dark:text-gray-400">
{% widthratio consumer.total_tokens consumer.call_count 1 %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Efficiency Metrics -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Efficiency Metrics</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Successful Tokens</h3>
<p class="text-2xl font-bold text-green-600 dark:text-green-400">{{ successful_tokens|floatformat:0 }}</p>
<div class="mt-2 w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div class="bg-green-600 dark:bg-green-400 h-2 rounded-full" style="width: {{ success_rate }}%"></div>
</div>
</div>
<div>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Wasted Tokens</h3>
<p class="text-2xl font-bold text-red-600 dark:text-red-400">{{ wasted_tokens|floatformat:0 }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">From failed requests</p>
</div>
<div>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Hourly Peak Usage</h3>
<p class="text-2xl font-bold text-blue-600 dark:text-blue-400">
{% for hour in hourly_usage %}
{% if forloop.first or hour.token_count > hourly_usage.0.token_count %}
{{ hour.hour|floatformat:0 }}:00
{% endif %}
{% endfor %}
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Most active hour</p>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Token Trends Chart
const ctx = document.getElementById('tokenTrendsChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: {{ daily_labels|safe }},
datasets: [{
label: 'Daily Token Usage',
data: {{ daily_data|safe }},
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: true,
position: 'top'
},
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return value.toLocaleString();
}
}
}
}
}
});
</script>
{% endblock %}