| Install | |
|---|---|
composer require israrminhas/filament-aimonitor |
|
| PHP: | ^8.2 |
A Filament 4 plugin for monitoring AI API usage, costs, and managing API keys across multiple providers (OpenAI, Anthropic, Gemini, Perplexity).
tenant() helper)composer require israrminhas/filament-aimonitor
Publish and run migrations:
php artisan vendor:publish --tag="ai-monitor-migrations"
php artisan migrate
Publish config (optional):
php artisan vendor:publish --tag="ai-monitor-config"
Add the plugin to your Filament panel in app/Providers/Filament/AdminPanelProvider.php:
use Filament\AiMonitor\AiMonitorPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
AiMonitorPlugin::make(),
]);
}
The package provides three global helper functions:
ai_log() - Log AI Requests// Log any AI request
ai_log([
'provider' => 'openai',
'model' => 'gpt-4o',
'request_type' => 'chat',
'prompt_tokens' => 150,
'completion_tokens' => 50,
'status' => 'success',
'user_id' => auth()->id(),
]);
Cost is automatically calculated from your pricing configuration. The total_tokens and occurred_at are auto-filled if not provided.
ai_key() - Get API Key// Get the highest priority active API key for a provider
$apiKey = ai_key('openai');
$apiKey = ai_key('anthropic');
$apiKey = ai_key('gemini');
ai_cost() - Calculate Cost// Calculate cost for tokens without logging
$cost = ai_cost('openai', 'gpt-4o', 1000, 500);
// Returns cost in USD based on your pricing config
use Filament\AiMonitor\Services\AiUsageLogger;
$logger = app(AiUsageLogger::class);
// Generic log
$logger->log([
'provider' => 'openai',
'model' => 'gpt-4o',
'prompt_tokens' => 100,
'completion_tokens' => 50,
'status' => 'success',
'user_id' => auth()->id(),
'meta' => ['conversation_id' => 123],
]);
// Provider-specific shortcuts
$logger->logOpenAi([...]);
$logger->logAnthropic([...]);
$logger->logGemini([...]);
$logger->logPerplexity([...]);
use Filament\AiMonitor\Services\AiKeyManager;
$keyManager = app(AiKeyManager::class);
// Get single key (highest priority)
$key = $keyManager->getKey('openai');
// Get all active keys for a provider
$keys = $keyManager->getAllKeys('openai');
// Check if provider has any active keys
if ($keyManager->hasProvider('anthropic')) {
// ...
}
use Filament\AiMonitor\Services\AiPricingService;
$pricing = app(AiPricingService::class);
// Get pricing for a model
$rates = $pricing->getPricing('openai', 'gpt-4o');
// Returns: ['input_per_1k' => 0.005, 'output_per_1k' => 0.015]
// Check if pricing exists
if ($pricing->hasPricing('anthropic', 'claude-3-opus')) {
// ...
}
// Calculate cost
$cost = $pricing->calculateCost('openai', 'gpt-4o', 1000, 500);
// Get all configured providers
$providers = $pricing->getProviders();
// Get models for a provider
$models = $pricing->getModelsForProvider('openai');
use Filament\AiMonitor\Services\AiUsageLimitService;
$limitService = app(AiUsageLimitService::class);
// Get user's monthly spend
$spent = $limitService->getUserMonthlySpend($userId);
// Get full limit status
$status = $limitService->getUserLimitStatus($user);
// Returns:
// [
// 'limit' => 100.00,
// 'spent' => 45.50,
// 'remaining' => 54.50,
// 'percent_used' => 45.5,
// 'state' => 'ok', // 'ok', 'warning', 'over', 'no-limit'
// ]
use OpenAI\Laravel\Facades\OpenAI;
$response = OpenAI::chat()->create([
'model' => 'gpt-4o',
'messages' => [
['role' => 'user', 'content' => 'Hello!'],
],
]);
// Log the request
ai_log([
'provider' => 'openai',
'model' => $response->model,
'request_type' => 'chat',
'prompt_tokens' => $response->usage->promptTokens,
'completion_tokens' => $response->usage->completionTokens,
'status' => 'success',
'user_id' => auth()->id(),
]);
$response = Http::withHeaders([
'x-api-key' => ai_key('anthropic'),
'anthropic-version' => '2023-06-01',
])->post('https://api.anthropic.com/v1/messages', [
'model' => 'claude-3-5-sonnet-20241022',
'max_tokens' => 1024,
'messages' => [['role' => 'user', 'content' => 'Hello!']],
]);
$data = $response->json();
ai_log([
'provider' => 'anthropic',
'model' => $data['model'],
'request_type' => 'chat',
'prompt_tokens' => $data['usage']['input_tokens'],
'completion_tokens' => $data['usage']['output_tokens'],
'status' => $response->successful() ? 'success' : 'failed',
'user_id' => auth()->id(),
]);
try {
$response = OpenAI::chat()->create([...]);
ai_log([
'provider' => 'openai',
'model' => 'gpt-4o',
'prompt_tokens' => $response->usage->promptTokens,
'completion_tokens' => $response->usage->completionTokens,
'status' => 'success',
'user_id' => auth()->id(),
]);
} catch (\Exception $e) {
ai_log([
'provider' => 'openai',
'model' => 'gpt-4o',
'prompt_tokens' => 0,
'completion_tokens' => 0,
'status' => 'failed',
'user_id' => auth()->id(),
'meta' => ['error' => $e->getMessage()],
]);
}
php artisan make:migration add_ai_limits_to_users_table
Schema::table('users', function (Blueprint $table) {
$table->decimal('ai_monthly_limit_usd', 10, 4)->nullable();
$table->integer('ai_alert_threshold_percent')->default(80);
});
use Filament\AiMonitor\Services\AiUsageLimitService;
$limitService = app(AiUsageLimitService::class);
$status = $limitService->getUserLimitStatus(auth()->user());
if ($status['state'] === 'over') {
throw new \Exception('Monthly AI spending limit reached.');
}
if ($status['state'] === 'warning') {
// Notify user they're approaching limit
}
The package automatically scopes data to the current tenant when tenant() helper is available (e.g., with Filament multi-tenancy or Stancl/Tenancy).
// config/ai-monitor.php
return [
'tenant_support' => true, // Enable/disable tenant scoping
];
IsTenantScoped traittenant() returns a tenant, tenant_id is automatically set on createThe plugin includes these dashboard widgets:
| Widget | Description |
|---|---|
| Stats Overview | Total requests, tokens, cost, success rate |
| Cost & Request Trends | 30-day line chart |
| Cost by Provider | Doughnut chart breakdown |
| Top Models by Cost | Table of most expensive models |
| Usage by User | Table of user spending |
| Recent Requests | Latest API calls with details |
MIT License. See LICENSE for details.