AI Monitor plugin screenshot
Dark mode ready
Multilingual support
Supports v5.x

AI Monitor

Monitor AI API usage and costs across OpenAI, Anthropic, Gemini & Perplexity. Features include API key management, automatic cost calculation, per-user spending limits, and multi-tenancy support.

Tags: Panels Widget
Supported versions:
4.x
Israr Minhas avatar Author: Israr Minhas

Documentation

A Filament 4 plugin for monitoring AI API usage, costs, and managing API keys across multiple providers (OpenAI, Anthropic, Gemini, Perplexity).

#Features

  • Track AI API requests with token counts and automatic cost calculation
  • Manage API keys for multiple providers with priority-based rotation
  • Configure model-specific pricing with fallback support
  • Dashboard with usage analytics and cost trends
  • Per-user spending tracking and limits
  • Multi-tenancy support (works with tenant() helper)

#Requirements

  • PHP 8.2+
  • Laravel 11+
  • Filament 4.0+

#Installation

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"

#Register the Plugin

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(),
        ]);
}

#Helper Functions

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

#Using the Services

#AiUsageLogger

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([...]);

#AiKeyManager

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')) {
    // ...
}

#AiPricingService

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');

#AiUsageLimitService

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'
// ]

#Usage Examples

#OpenAI Integration

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(),
]);

#Anthropic Integration

$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(),
]);

#With Error Handling

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()],
    ]);
}

#User Spending Limits

#Add Columns to Users Table

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);
});

#Check Limits Before AI Calls

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
}

#Multi-Tenancy Support

The package automatically scopes data to the current tenant when tenant() helper is available (e.g., with Filament multi-tenancy or Stancl/Tenancy).

#Configuration

// config/ai-monitor.php
return [
    'tenant_support' => true, // Enable/disable tenant scoping
];

#How It Works

  • All models use the IsTenantScoped trait
  • When tenant() returns a tenant, tenant_id is automatically set on create
  • Queries are automatically scoped to the current tenant

#Dashboard Widgets

The 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

#License

MIT License. See LICENSE for details.

The author

Israr Minhas avatar Author: Israr Minhas

Israr Minhas is a full-stack web developer with experience in Laravel, Filament, Livewire, Vue, and modern PHP development. He has worked on SaaS platforms, dashboards, and multi-tenant systems, focusing on building reliable and easy-to-use web applications. He enjoys learning new technologies and creating practical solutions that simplify work for users and teams.

Plugins
1
Stars
13