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,187 @@
<?php
namespace App\Http\Controllers;
use App\Models\UsageLog;
use App\Models\GatewayUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class UsageLogController extends Controller
{
/**
* Display a listing of usage logs with filters
*/
public function index(Request $request)
{
$query = UsageLog::with(['gatewayUser', 'apiKey']);
// Date Range Filter
if ($request->filled('date_from')) {
$query->where('timestamp', '>=', $request->date_from . ' 00:00:00');
}
if ($request->filled('date_to')) {
$query->where('timestamp', '<=', $request->date_to . ' 23:59:59');
}
// User Filter
if ($request->filled('user_id')) {
$query->where('user_id', $request->user_id);
}
// Provider Filter
if ($request->filled('provider')) {
$query->where('provider', $request->provider);
}
// Model Filter
if ($request->filled('model')) {
$query->where('model', $request->model);
}
// Status Filter
if ($request->filled('status')) {
if ($request->status === 'success') {
$query->success();
} elseif ($request->status === 'failed') {
$query->failed();
}
}
// Get filter options for dropdowns
$users = GatewayUser::select('user_id', 'alias')
->orderBy('alias')
->get();
$providers = UsageLog::select('provider')
->distinct()
->whereNotNull('provider')
->orderBy('provider')
->pluck('provider');
$models = UsageLog::select('model')
->distinct()
->whereNotNull('model')
->orderBy('model')
->pluck('model');
// Get summary statistics for current filter
$summary = $query->clone()
->selectRaw('
COUNT(*) as total_requests,
SUM(CASE WHEN status = \'success\' THEN 1 ELSE 0 END) as successful_requests,
SUM(prompt_tokens) as total_prompt_tokens,
SUM(completion_tokens) as total_completion_tokens,
SUM(total_tokens) as total_tokens,
SUM(cost) as total_cost
')
->first();
// Paginate results
$logs = $query->orderByDesc('timestamp')
->paginate(50)
->withQueryString(); // Preserve query parameters
return view('usage-logs.index', compact(
'logs',
'users',
'providers',
'models',
'summary'
));
}
/**
* Export usage logs to CSV
*/
public function export(Request $request)
{
$query = UsageLog::with(['gatewayUser', 'apiKey']);
// Apply same filters as index
if ($request->filled('date_from')) {
$query->where('timestamp', '>=', $request->date_from . ' 00:00:00');
}
if ($request->filled('date_to')) {
$query->where('timestamp', '<=', $request->date_to . ' 23:59:59');
}
if ($request->filled('user_id')) {
$query->where('user_id', $request->user_id);
}
if ($request->filled('provider')) {
$query->where('provider', $request->provider);
}
if ($request->filled('model')) {
$query->where('model', $request->model);
}
if ($request->filled('status')) {
if ($request->status === 'success') {
$query->success();
} elseif ($request->status === 'failed') {
$query->failed();
}
}
// Limit export to 10,000 records for performance
$logs = $query->orderByDesc('timestamp')
->limit(10000)
->get();
$filename = 'usage-logs-' . now()->format('Y-m-d-His') . '.csv';
$headers = [
'Content-Type' => 'text/csv',
'Content-Disposition' => "attachment; filename=\"{$filename}\"",
];
$callback = function() use ($logs) {
$file = fopen('php://output', 'w');
// CSV Header
fputcsv($file, [
'Timestamp',
'User ID',
'User Alias',
'API Key',
'Provider',
'Model',
'Endpoint',
'Prompt Tokens',
'Completion Tokens',
'Total Tokens',
'Cost',
'Status',
'Error Message'
]);
// CSV Rows
foreach ($logs as $log) {
fputcsv($file, [
$log->timestamp->format('Y-m-d H:i:s'),
$log->user_id,
$log->gatewayUser?->alias ?? 'N/A',
$log->api_key_id,
$log->provider,
$log->model,
$log->endpoint,
$log->prompt_tokens,
$log->completion_tokens,
$log->total_tokens,
$log->cost,
$log->status,
$log->error_message ?? ''
]);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
}