Initial commit: Any-LLM Gateway with Laravel Admin Interface

- Any-LLM Gateway setup with Docker Compose
- Laravel 11 admin interface with Livewire
- Dashboard with usage statistics and charts
- Gateway Users management with budget tracking
- API Keys management with revocation
- Budget templates with assignment
- Usage Logs with filtering and CSV export
- Model Pricing management with calculator
- PostgreSQL database integration
- Complete authentication system for admins
This commit is contained in:
wtrinkl
2025-11-16 12:38:05 +01:00
commit b1363aeab9
148 changed files with 23995 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Cost Calculator
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<p class="text-sm text-gray-600 mb-6">
Calculate the cost of API requests based on token usage and model pricing.
</p>
<div class="space-y-4">
<div>
<label for="calc_model" class="block text-sm font-medium text-gray-700 mb-1">
Select Model *
</label>
<select id="calc_model"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
<option value="">Choose a model...</option>
@foreach($models as $model)
<option value="{{ $model->model_key }}"
data-input-price="{{ $model->input_price_per_million }}"
data-output-price="{{ $model->output_price_per_million }}">
{{ $model->model_key }}
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label for="input_tokens" class="block text-sm font-medium text-gray-700 mb-1">
Input Tokens
</label>
<input type="number" id="input_tokens" value="1000" min="0"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="output_tokens" class="block text-sm font-medium text-gray-700 mb-1">
Output Tokens
</label>
<input type="number" id="output_tokens" value="500" min="0"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
</div>
<button onclick="calculateCost()"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded">
Calculate Cost
</button>
<div id="result" class="hidden">
<div class="bg-gray-50 rounded-lg p-6 space-y-3">
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">Model:</span>
<span id="result_model" class="text-sm font-medium text-gray-900"></span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">Input Tokens:</span>
<span id="result_input_tokens" class="text-sm font-medium text-gray-900"></span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">Output Tokens:</span>
<span id="result_output_tokens" class="text-sm font-medium text-gray-900"></span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">Total Tokens:</span>
<span id="result_total_tokens" class="text-sm font-medium text-gray-900"></span>
</div>
<div class="border-t pt-3 mt-3">
<div class="flex justify-between items-center">
<span class="text-lg font-semibold text-gray-900">Total Cost:</span>
<span id="result_cost" class="text-2xl font-bold text-green-600"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
<h4 class="font-semibold text-blue-900 mb-2">💡 Quick Reference</h4>
<p class="text-sm text-blue-800">
Prices are calculated per million tokens. For example, if input price is $3.00/M and you use 1,000 tokens,
the cost would be: (1,000 / 1,000,000) × $3.00 = $0.003
</p>
</div>
</div>
</div>
<script>
function calculateCost() {
const modelKey = document.getElementById('calc_model').value;
const inputTokens = parseInt(document.getElementById('input_tokens').value) || 0;
const outputTokens = parseInt(document.getElementById('output_tokens').value) || 0;
if (!modelKey) {
alert('Please select a model');
return;
}
// Get pricing from selected option
const select = document.getElementById('calc_model');
const option = select.options[select.selectedIndex];
const inputPrice = parseFloat(option.dataset.inputPrice);
const outputPrice = parseFloat(option.dataset.outputPrice);
// Calculate cost
const inputCost = (inputTokens / 1000000) * inputPrice;
const outputCost = (outputTokens / 1000000) * outputPrice;
const totalCost = inputCost + outputCost;
const totalTokens = inputTokens + outputTokens;
// Display results
document.getElementById('result_model').textContent = modelKey;
document.getElementById('result_input_tokens').textContent = inputTokens.toLocaleString();
document.getElementById('result_output_tokens').textContent = outputTokens.toLocaleString();
document.getElementById('result_total_tokens').textContent = totalTokens.toLocaleString();
document.getElementById('result_cost').textContent = '$' + totalCost.toFixed(6);
document.getElementById('result').classList.remove('hidden');
}
// Allow Enter key to calculate
document.getElementById('input_tokens').addEventListener('keypress', function(e) {
if (e.key === 'Enter') calculateCost();
});
document.getElementById('output_tokens').addEventListener('keypress', function(e) {
if (e.key === 'Enter') calculateCost();
});
</script>
</x-app-layout>