Update: 2026-05-08 00:26:39
This commit is contained in:
102
app/Core/AiUsageLogger.php
Normal file
102
app/Core/AiUsageLogger.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user