Files
musadaq-saas/app/Core/AiUsageLogger.php
2026-05-08 00:26:40 +03:00

103 lines
3.3 KiB
PHP

<?php
/**
* AI Usage Logger Service
* Records every AI API call with token counts and estimated cost.
*/
namespace App\Core;
class AiUsageLogger
{
/**
* Cost per 1M tokens (input/output) for each model.
* Update these when pricing changes.
*/
private const MODEL_PRICING = [
'gemini-1.5-flash' => [
'input' => 0.075, // $0.075 per 1M input tokens
'output' => 0.30, // $0.30 per 1M output tokens
],
'gemini-2.0-flash' => [
'input' => 0.10,
'output' => 0.40,
],
'gemini-1.5-pro' => [
'input' => 1.25,
'output' => 5.00,
],
'grok-2' => [
'input' => 2.00,
'output' => 10.00,
],
'whisper-large-v3' => [
'input' => 0.111, // $0.111 per 1M input tokens (Groq)
'output' => 0.0,
],
];
/**
* Log an AI usage event.
*
* @param string $tenantId
* @param string $actionType One of: invoice_extraction, voice_transcribe, voice_intent, report_generation, chatbot
* @param string $modelName e.g. gemini-1.5-flash
* @param int $promptTokens
* @param int $completionTokens
* @param string|null $userId
* @param string|null $companyId
* @param array|null $metadata Any extra info (invoice_id, etc.)
*/
public static function log(
string $tenantId,
string $actionType,
string $modelName,
int $promptTokens,
int $completionTokens,
?string $userId = null,
?string $companyId = null,
?array $metadata = null,
): void {
$totalTokens = $promptTokens + $completionTokens;
$estimatedCost = self::estimateCost($modelName, $promptTokens, $completionTokens);
try {
$db = Database::getInstance();
$stmt = $db->prepare(
"INSERT INTO ai_usage_log
(tenant_id, user_id, company_id, action_type, model_name,
prompt_tokens, completion_tokens, total_tokens, estimated_cost,
request_metadata, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())"
);
$stmt->execute([
$tenantId,
$userId,
$companyId,
$actionType,
$modelName,
$promptTokens,
$completionTokens,
$totalTokens,
$estimatedCost,
$metadata ? json_encode($metadata, JSON_UNESCAPED_UNICODE) : null,
]);
} catch (\Exception $e) {
// Logging should never break the main flow
error_log('[AiUsageLogger] Failed to log: ' . $e->getMessage());
}
}
/**
* Estimate cost in USD based on model pricing.
*/
private static function estimateCost(string $model, int $inputTokens, int $outputTokens): float
{
$pricing = self::MODEL_PRICING[$model] ?? ['input' => 0.10, 'output' => 0.40];
$inputCost = ($inputTokens / 1_000_000) * $pricing['input'];
$outputCost = ($outputTokens / 1_000_000) * $pricing['output'];
return round($inputCost + $outputCost, 6);
}
}