Installation:
composer require israrminhas/filament-aimonitor
php artisan vendor:publish --tag="ai-monitor-migrations"
php artisan migrate
Register Plugin:
Add to app/Providers/Filament/AdminPanelProvider.php:
->plugins([
AiMonitorPlugin::make(),
])
First Use Case: Log an AI request in your service:
ai_log([
'provider' => 'openai',
'model' => 'gpt-4o',
'prompt_tokens' => 150,
'completion_tokens' => 50,
'status' => 'success',
]);
php artisan vendor:publish --tag="ai-monitor-config") to customize pricing rules./ai-monitor in your Filament admin panel to view the dashboard.Service Integration: Wrap AI API calls in a service layer to log requests:
class OpenAIService {
public function call(string $model, string $prompt) {
$response = OpenAI::call($model, $prompt);
ai_log([
'provider' => 'openai',
'model' => $model,
'prompt_tokens' => strlen($prompt) / 4, // Approximate
'completion_tokens' => $response['usage']['completion_tokens'],
'status' => 'success',
]);
return $response;
}
}
Middleware: Use middleware to log requests globally:
public function handle(Request $request, Closure $next) {
$response = $next($request);
if ($request->routeIs('ai.*')) {
ai_log([
'provider' => $request->route('provider'),
'model' => $request->route('model'),
'tokens' => $response->tokens,
'status' => $response->status,
]);
}
return $response;
}
Dynamic Key Rotation:
Configure priority-based keys in config/ai-monitor.php:
'providers' => [
'openai' => [
'keys' => [
'sk-live-123' => ['priority' => 1],
'sk-backup-456' => ['priority' => 2],
],
'default_key' => 'sk-live-123',
],
],
Use the helper to fetch the active key:
$key = ai_get_active_key('openai');
Key Validation: Validate keys via the plugin’s API:
$isValid = ai_validate_key('openai', 'sk-test-789');
Custom Pricing Rules: Override default pricing in config:
'pricing' => [
'openai' => [
'gpt-4o' => 0.005, // $0.005 per 1K tokens
'gpt-3.5-turbo' => 0.0005,
],
'anthropic' => [
'claude-3' => 0.01,
],
],
Fallback to provider defaults if missing.
Budget Alerts:
Subscribe to events in EventServiceProvider:
protected $listen = [
\Filament\AiMonitor\Events\BudgetExceeded::class => [
\App\Actions\NotifyBudgetExceeded::class,
],
];
Custom Widgets: Extend the dashboard with Filament widgets:
use Filament\AiMonitor\Widgets\AiUsageStats;
public function getWidgets(): array {
return [
AiUsageStats::class,
// Custom widget
class extends Widget {
protected static string $view = 'ai-monitor.custom-widget';
},
];
}
Export Data: Use the built-in exporter for analytics:
$data = AiMonitor::get()->export();
Excel::download(new AiMonitorExport($data), 'ai_usage.xlsx');
strlen($prompt)/4) may misalign with provider billing.
Fix: Use provider-specific tokenizers or log raw payloads for post-hoc calculation:
ai_log([
'raw_prompt' => $prompt, // Store for later processing
'provider' => 'openai',
// ...
]);
cache()->lock():
$lock = cache()->lock('ai-key-rotation-openai', 10);
if ($lock->get()) {
$newKey = ai_rotate_key('openai');
$lock->release();
}
ai_log([
'tenant_id' => tenant()->id,
'provider' => 'openai',
// ...
]);
Override tenant-specific config in config/ai-monitor.php:
'tenants' => [
'acme' => [
'pricing' => [
'openai' => [
'gpt-4o' => 0.003, // Custom rate for Acme
],
],
],
],
// Async logging via queue
AiMonitorLog::dispatch([
'provider' => 'openai',
'model' => 'gpt-4o',
// ...
]);
config('ai-monitor.pricing.providers.openai');
Add missing models to avoid null cost calculations.BudgetExceeded are not fired by default. Ensure listeners are registered in EventServiceProvider./ai-monitor route requires view ai monitor permission. Grant via:
$user->givePermissionTo('view ai monitor');
class CustomProviderService extends ServiceProvider {
public function register() {
AiMonitor::extend('custom-provider', function () {
return new CustomProviderManager();
});
}
}
use Filament\AiMonitor\Facades\AiMonitor;
AiMonitor::webhookReceived([
'provider' => 'openai',
'event' => 'usage_alert',
'data' => $payload,
]);
AiMonitor::hook('calculate_tokens', function ($payload) {
if ($payload['provider'] === 'gemini') {
return strlen($payload['prompt']) / 3; // Custom logic
}
});
AiMonitor::hook('get_pricing', function ($provider, $model) {
if ($provider === 'openai') {
return Cache::remember("ai-pricing-openai-{$model}", now()->addHours(1), function () {
return json_decode(file_get_contents('https://api.openai.com/pricing'), true);
});
}
});
How can I help you explore Laravel packages today?