Files
sam-api/app/Services/AiTokenUsageService.php
김보곤 427e585236 feat: [settings] AI 토큰사용량 조회 API 추가
- GET /settings/ai-token-usage: 목록 + 통계 조회
- GET /settings/ai-token-usage/pricing: 단가 설정 조회 (읽기 전용)
- AiTokenHelper: Gemini/Claude/R2/STT 사용량 기록 헬퍼
- AiPricingConfig 캐시에 cloudflare-r2 provider 추가
2026-03-18 11:25:19 +09:00

73 lines
2.4 KiB
PHP

<?php
namespace App\Services;
use App\Models\Tenants\AiPricingConfig;
use App\Models\Tenants\AiTokenUsage;
class AiTokenUsageService extends Service
{
/**
* 토큰 사용량 목록 + 통계
*/
public function list(array $params): array
{
$tenantId = $this->tenantId();
$query = AiTokenUsage::where('tenant_id', $tenantId)
->when($params['start_date'] ?? null, fn ($q, $d) => $q->whereDate('created_at', '>=', $d))
->when($params['end_date'] ?? null, fn ($q, $d) => $q->whereDate('created_at', '<=', $d))
->when($params['menu_name'] ?? null, fn ($q, $m) => $q->where('menu_name', $m));
// 통계 (페이지네이션 전 전체 집계)
$stats = (clone $query)->selectRaw('
COUNT(*) as total_count,
COALESCE(SUM(prompt_tokens), 0) as total_prompt_tokens,
COALESCE(SUM(completion_tokens), 0) as total_completion_tokens,
COALESCE(SUM(total_tokens), 0) as total_total_tokens,
COALESCE(SUM(cost_usd), 0) as total_cost_usd,
COALESCE(SUM(cost_krw), 0) as total_cost_krw
')->first();
// 목록 (페이지네이션)
$items = $query->with('creator:id,name')
->orderByDesc('created_at')
->paginate($params['per_page'] ?? 20);
// 메뉴명 필터 옵션
$menuNames = AiTokenUsage::where('tenant_id', $tenantId)
->select('menu_name')
->distinct()
->orderBy('menu_name')
->pluck('menu_name');
return [
'items' => $items,
'stats' => [
'total_count' => (int) $stats->total_count,
'total_prompt_tokens' => (int) $stats->total_prompt_tokens,
'total_completion_tokens' => (int) $stats->total_completion_tokens,
'total_total_tokens' => (int) $stats->total_total_tokens,
'total_cost_usd' => (float) $stats->total_cost_usd,
'total_cost_krw' => (float) $stats->total_cost_krw,
],
'menu_names' => $menuNames,
];
}
/**
* 단가 설정 조회 (읽기 전용)
*/
public function getPricing(): array
{
$configs = AiPricingConfig::where('is_active', true)
->orderBy('provider')
->get();
return [
'pricing' => $configs,
'exchange_rate' => AiPricingConfig::getExchangeRate(),
];
}
}