안녕하세요, 저는 HolySheep AI의 시니어 엔지니어입니다. 이번 튜토리얼에서는 AI API 사용량을 추적하고 팀별, 프로젝트별, 기능별로 비용을 정확히 배분하는 시스템을 구축하는 방법을 다루겠습니다. HolySheep AI를 사용하면 단일 API 키로 여러 모델을 통합 관리할 수 있어, 비용 추적과 할당 작업이 한결 수월해집니다.

왜 AI API 사용량 추적과 비용 배분이 중요한가

AI API 비용은 예측하기 어렵습니다. 토큰 소비량은 입력/출력 길이, 모델 선택, 프롬프트 최적화 여부에 따라 수 배까지 달라질 수 있습니다. HolySheep AI의 대시보드에서는 실시간 사용량을 확인 가능하지만, 복잡한 마이크로서비스 환경에서는 팀 단위, 기능 단위의 세밀한 비용 배분이 필요합니다.

본 가이드에서 구축할 시스템은:

아키텍처 설계

비용 추적 시스템의 핵심은 미들웨어 패턴입니다. 모든 API 호출이 프록시를 통해 라우팅되며, 호출 정보가 비동기적으로 로그 시스템에 기록됩니다.

시스템 구성 요소

┌─────────────────────────────────────────────────────────────────────┐
│                         HolySheep AI Gateway                         │
│                    https://api.holysheep.ai/v1                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐      │
│   │  Team A  │    │  Team B  │    │  Team C  │    │ Internal │      │
│   │ (Marketing)│   │ (R&D)    │    │ (Support)│    │ Services │      │
│   └────┬─────┘    └────┬─────┘    └────┬─────┘    └────┬─────┘      │
│        │               │               │               │              │
│        └───────────────┴───────┬───────┴───────────────┘              │
│                                │                                      │
│                    ┌───────────▼───────────┐                         │
│                    │   Usage Tracking       │                         │
│                    │   Middleware Layer     │                         │
│                    └───────────┬───────────┘                         │
│                                │                                      │
│         ┌──────────────────────┼──────────────────────┐               │
│         │                      │                      │               │
│         ▼                      ▼                      ▼               │
│   ┌──────────┐         ┌──────────┐          ┌──────────────┐        │
│   │PostgreSQL│         │   Redis   │          │Analytics DB  │        │
│   │(Storage) │         │ (Cache)  │          │ (TimescaleDB)│        │
│   └──────────┘         └──────────┘          └──────────────┘        │
│                                                               │
│   ┌──────────────────────────────────────────────────────────┐        │
│   │              Cost Allocation Dashboard                    │        │
│   └──────────────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────────────┘

핵심 구현: HolySheep AI 비용 추적 미들웨어

먼저 HolySheep AI API 호출을 래핑하는 비용 추적 클래스를 구현하겠습니다. HolySheep AI의 단일 엔드포인트로 여러 모델을 호출하므로, 모델별 가격 정책이 자동으로 적용됩니다.

import httpx
import asyncio
import time
import json
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from typing import Optional, Dict, List, Any
from contextlib import asynccontextmanager
import hashlib

HolySheep AI 모델별 가격 (USD per 1M tokens)

HOLYSHEEP_MODEL_PRICES = { "gpt-4.1": {"input": 8.00, "output": 8.00}, "gpt-4.1-mini": {"input": 0.40, "output": 1.60}, "claude-sonnet-4-5": {"input": 15.00, "output": 15.00}, "claude-sonnet-4": {"input": 5.00, "output": 15.00}, "gemini-2.5-flash": {"input": 2.50, "output": 10.00}, "gemini-2.0-flash": {"input": 0.10, "output": 0.40}, "deepseek-v3.2": {"input": 0.42, "output": 0.42}, "deepseek-chat": {"input": 0.27, "output": 1.10}, } @dataclass class UsageRecord: """단일 API 호출의 사용량 기록""" timestamp: datetime model: str team_id: str project_id: str feature: str input_tokens: int output_tokens: int request_id: str latency_ms: float cost_usd: float = 0.0 metadata: Dict[str, Any] = field(default_factory=dict) def calculate_cost(self) -> float: """HolySheep AI 가격 정책 기반 비용 계산""" prices = HOLYSHEEP_MODEL_PRICES.get(self.model, {"input": 0, "output": 0}) input_cost = (self.input_tokens / 1_000_000) * prices["input"] output_cost = (self.output_tokens / 1_000_000) * prices["output"] self.cost_usd = round(input_cost + output_cost, 6) return self.cost_usd class HolySheepCostTracker: """ HolySheep AI API용 비용 추적 시스템 특징: - 태그 기반 비용 배분 (team_id, project_id, feature) - 실시간 비용 계산 - 비동기 배치 저장로직 - 예산 초과 자동 알림 """ def __init__( self, api_key: str, base_url: str = "https://api.holysheep.ai/v1", storage_batch_size: int = 100, flush_interval_seconds: int = 30 ): self.api_key = api_key self.base_url = base_url self.batch_size = storage_batch_size self.flush_interval = flush_interval_seconds self._usage_buffer: List[UsageRecord] = [] self._buffer_lock = asyncio.Lock() self._client = httpx.AsyncClient( base_url=base_url, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, timeout=httpx.Timeout(60.0, connect=10.0) ) # Budget configuration self._budgets: Dict[str, Dict] = {} self._budget_alerts: Dict[str, Dict] = {} # Start background flush task self._flush_task: Optional[asyncio.Task] = None self._running = False async def start(self): """배경 플러시 태스크 시작""" self._running = True self._flush_task = asyncio.create_task(self._periodic_flush()) async def stop(self): """ Graceful shutdown """ self._running = False if self._flush_task: self._flush_task.cancel() try: await self._flush_task except asyncio.CancelledError: pass await self._flush_buffer() # 최종 플러시 await self._client.aclose() @asynccontextmanager async def track( self, team_id: str, project_id: str, feature: str, model: str = "deepseek-v3.2" ): """ 컨텍스트 매니저로 API 호출 추적 Usage: async with tracker.track("team_alpha", "chatbot", "user_response"): response = await self._client.post("/chat/completions", json=payload) """ start_time = time.perf_counter() request_id = hashlib.sha256( f"{time.time()}{team_id}{feature}".encode() ).hexdigest()[:16] record = UsageRecord( timestamp=datetime.utcnow(), model=model, team_id=team_id, project_id=project_id, feature=feature, input_tokens=0, output_tokens=0, request_id=request_id, latency_ms=0 ) try: yield record finally: record.latency_ms = (time.perf_counter() - start_time) * 1000 async def record_usage( self, team_id: str, project_id: str, feature: str, model: str, input_tokens: int, output_tokens: int, latency_ms: float, metadata: Optional[Dict] = None ) -> UsageRecord: """사용량 기록 - HolySheep AI 응답 파싱 후 호출""" record = UsageRecord( timestamp=datetime.utcnow(), model=model, team_id=team_id, project_id=project_id, feature=feature, input_tokens=input_tokens, output_tokens=output_tokens, request_id=hashlib.sha256( f"{time.time()}{team_id}{feature}".encode() ).hexdigest()[:16], latency_ms=latency_ms, metadata=metadata or {} ) record.calculate_cost() # 버퍼에 추가 async with self._buffer_lock: self._usage_buffer.append(record) # 버퍼 크기 도달 시 플러시 if len(self._usage_buffer) >= self.batch_size: await self._flush_buffer() # 예산 체크 await self._check_budget(record) return record async def chat_completion( self, messages: List[Dict], team_id: str, project_id: str, feature: str, model: str = "deepseek-v3.2", **kwargs ) -> Dict: """ HolySheep AI 채팅 완성 API 호출 및 사용량 추적 모델 선택 가이드: - 비용 최적화: deepseek-v3.2 ($0.42/MTok) - 균형 잡힌 성능: gemini-2.5-flash ($2.50/MTok) - 최고 품질: claude-sonnet-4.5 ($15/MTok) """ start_time = time.perf_counter() payload = { "model": model, "messages": messages, **kwargs } # 토큰 수 추정 input_tokens = self._estimate_tokens(messages) try: response = await self._client.post("/chat/completions", json=payload) response.raise_for_status() data = response.json() # 실제 토큰 사용량 추출 (HolySheep AI 응답) usage = data.get("usage", {}) actual_input_tokens = usage.get("prompt_tokens", input_tokens) actual_output_tokens = usage.get("completion_tokens", 0) latency_ms = (time.perf_counter() - start_time) * 1000 # 사용량 기록 await self.record_usage( team_id=team_id, project_id=project_id, feature=feature, model=model, input_tokens=actual_input_tokens, output_tokens=actual_output_tokens, latency_ms=latency_ms, metadata={ "model_alias": data.get("model"), "finish_reason": usage.get("finish_reason") } ) return data except httpx.HTTPStatusError as e: # 재시도 로직 if e.response.status_code == 429: await asyncio.sleep(2 ** kwargs.get("retries", 0)) return await self.chat_completion( messages, team_id, project_id, feature, model, retries=kwargs.get("retries", 0) + 1 ) raise def _estimate_tokens(self, messages: List[Dict]) -> int: """토큰 수 추정 (gpt-3.5-turbo 기준 근사치)""" total = 0 for msg in messages: total += len(msg.get("content", "").split()) * 1.3 return int(total) async def _flush_buffer(self): """버퍼 내용을 저장소로 플러시""" async with self._buffer_lock: if not self._usage_buffer: return records_to_store = self._usage_buffer.copy() self._usage_buffer.clear() # 실제 환경에서는 PostgreSQL/TimescaleDB에 저장 # 예: await self._db.insert_usage_records(records_to_store) total_cost = sum(r.cost_usd for r in records_to_store) print(f"[CostTracker] Flushed {len(records_to_store)} records, " f"total cost: ${total_cost:.4f}") async def _periodic_flush(self): """정기적 플러시 태스크""" while self._running: await asyncio.sleep(self.flush_interval) await self._flush_buffer() # ===== 예산 관리 ===== def set_budget( self, identifier: str, monthly_limit_usd: float, alert_threshold: float = 0.8, webhook_url: Optional[str] = None ): """ 예산 설정 identifier 형식: "team:{team_id}" 또는 "project:{project_id}" """ self._budgets[identifier] = { "monthly_limit": monthly_limit_usd, "alert_threshold": alert_threshold, "webhook_url": webhook_url, "period_start": datetime.utcnow().replace(day=1, hour=0, minute=0, second=0) } async def _check_budget(self, record: UsageRecord): """예산 초과 체크""" identifiers = [ f"team:{record.team_id}", f"project:{record.project_id}", f"feature:{record.feature}" ] for identifier in identifiers: if identifier not in self._budgets: continue budget = self._budgets[identifier] current_spend = await self._get_period_spend(identifier) if current_spend >= budget["monthly_limit"]: await self._trigger_budget_alert(identifier, current_spend, budget) async def _get_period_spend(self, identifier: str) -> float: """기간 내 총 지출 조회""" # 실제 환경에서는 DB 쿼리 # 임시 구현: 버퍼 내 레코드 합산 total = 0.0 async with self._buffer_lock: for record in self._usage_buffer: if identifier in [ f"team:{record.team_id}", f"project:{record.project_id}", f"feature:{record.feature}" ]: total += record.cost_usd return total async def _trigger_budget_alert( self, identifier: str, current: float, budget: Dict ): """예산 초과 알림 발송""" if budget["webhook_url"]: async with httpx.AsyncClient() as client: await client.post(budget["webhook_url"], json={ "alert": "Budget Exceeded", "identifier": identifier, "current_spend": current, "limit": budget["monthly_limit"] }) print(f"[ALERT] Budget exceeded for {identifier}: ${current:.2f}") # ===== 비용 분석 ===== async def get_cost_breakdown( self, team_id: Optional[str] = None, project_id: Optional[str] = None, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None ) -> Dict: """비용 분해 조회""" # 실제 환경에서는 DB 쿼리 breakdown = { "by_model": {}, "by_feature": {}, "total_cost": 0.0, "total_tokens": {"input": 0, "output": 0}, "request_count": 0, "avg_latency_ms": 0.0 } # ... DB 쿼리 로직 return breakdown def suggest_model_optimization(self, current_spend: float) -> List[Dict]: """비용 최적화 제안""" suggestions = [] if current_spend > 1000: # 월 $1000 이상 사용 시 suggestions.append({ "priority": "high", "action": "Consider Gemini 2.5 Flash", "savings_potential": "60-80%", "reason": "Gemini 2.5 Flash는 DeepSeek V3.2 대비 6배 저렴" }) suggestions.append({ "priority": "medium", "action": "Implement caching layer", "savings_potential": "20-40%", "reason": "반복 질문에 대한 캐싱으로 중복 API 호출 제거" }) return suggestions

===== 사용 예시 =====

async def main(): # HolySheep AI 초기화 tracker = HolySheepCostTracker( api_key="YOUR_HOLYSHEEP_API_KEY", base_url="https://api.holysheep.ai/v1" ) await tracker.start() # 예산 설정 tracker.set_budget( identifier="team:marketing", monthly_limit_usd=500.0, alert_threshold=0.8, webhook_url="https://your-app.com/webhooks/budget-alert" ) try: # 마케팅팀 - 고객 응답 생성 response = await tracker.chat_completion( messages=[ {"role": "system", "content": "당신은 친절한 고객 서비스 담당자입니다."}, {"role": "user", "content": "배송 조회를 하고 싶습니다."} ], team_id="marketing", project_id="customer-service", feature="user_response", model="deepseek-v3.2", temperature=0.7, max_tokens=500 ) print(f"Response: {response['choices'][0]['message']['content']}") print(f"Usage: {response['usage']}") # R&D팀 - 코드 리뷰 response = await tracker.chat_completion( messages=[ {"role": "user", "content": "다음 코드를 리뷰해주세요: " + "x = 1" * 1000} ], team_id="rd", project_id="code-review", feature="auto_review", model="claude-sonnet-4", temperature=0.1 ) finally: await tracker.stop() if __name__ == "__main__": asyncio.run(main())

비용 배분 대시보드 구축

수집된 사용량 데이터를 시각화하는 대시보드를 구축하겠습니다. 이 대시보드는 팀별, 프로젝트별, 모델별 비용을 실시간으로 추적합니다.

import asyncio
from dataclasses import dataclass
from typing import List, Dict, Optional
from datetime import datetime, timedelta
import asyncpg
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from collections import defaultdict

app = FastAPI(title="HolySheep AI Cost Allocation Dashboard")
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

===== 데이터베이스 스키마 =====

CREATE_TABLES_SQL = """ -- 사용량 로그 테이블 CREATE TABLE IF NOT EXISTS usage_logs ( id BIGSERIAL PRIMARY KEY, timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(), team_id VARCHAR(50) NOT NULL, project_id VARCHAR(50) NOT NULL, feature VARCHAR(100) NOT NULL, model VARCHAR(50) NOT NULL, input_tokens INTEGER NOT NULL, output_tokens INTEGER NOT NULL, total_tokens INTEGER GENERATED ALWAYS AS (input_tokens + output_tokens) STORED, cost_usd DECIMAL(12, 6) NOT NULL, latency_ms DECIMAL(10, 2) NOT NULL, request_id VARCHAR(32) UNIQUE NOT NULL, metadata JSONB ); -- 시계열 최적화를 위한 인덱스 CREATE INDEX IF NOT EXISTS idx_usage_logs_timestamp ON usage_logs (timestamp DESC); CREATE INDEX IF NOT EXISTS idx_usage_logs_team ON usage_logs (team_id, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_usage_logs_project ON usage_logs (project_id, timestamp DESC); -- Hypertable 생성 (TimescaleDB 사용 시) -- SELECT create_hypertable('usage_logs', 'timestamp', if_not_exists => TRUE); -- 예산 테이블 CREATE TABLE IF NOT EXISTS budgets ( id SERIAL PRIMARY KEY, identifier VARCHAR(100) UNIQUE NOT NULL, -- team:{id}, project:{id}, feature:{id} monthly_limit_usd DECIMAL(12, 2) NOT NULL, alert_threshold DECIMAL(3, 2) DEFAULT 0.8, webhook_url VARCHAR(500), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 예산 알림 로그 CREATE TABLE IF NOT EXISTS budget_alerts ( id BIGSERIAL PRIMARY KEY, budget_id INTEGER REFERENCES budgets(id), triggered_at TIMESTAMPTZ DEFAULT NOW(), current_spend_usd DECIMAL(12, 2), percentage DECIMAL(5, 2), notification_sent BOOLEAN DEFAULT FALSE ); """

===== API 응답 모델 =====

@dataclass class CostBreakdown: """비용 분해 데이터""" team_id: str project_id: str total_cost: float total_tokens: int request_count: int avg_latency_ms: float by_model: Dict[str, Dict] class DashboardSummary(BaseModel): period: str start_date: datetime end_date: datetime total_cost_usd: float total_requests: int total_input_tokens: int total_output_tokens: int avg_cost_per_request: float teams: List[Dict] top_models: List[Dict] cost_trend: List[Dict] class TeamCostDetail(BaseModel): team_id: str projects: List[Dict] total_cost: float budget_status: Optional[Dict]

===== 데이터베이스 연결 =====

class DatabaseManager: def __init__(self, dsn: str): self.dsn = dsn self.pool: Optional[asyncpg.Pool] = None async def connect(self): self.pool = await asyncpg.create_pool(self.dsn, min_size=5, max_size=20) async def disconnect(self): if self.pool: await self.pool.close() async def init_schema(self): """테이블 초기화""" async with self.pool.acquire() as conn: await conn.execute(CREATE_TABLES_SQL) async def get_dashboard_summary( self, start_date: datetime, end_date: datetime ) -> DashboardSummary: """대시보드 요약 조회""" async with self.pool.acquire() as conn: # 전체 요약 summary = await conn.fetchrow(""" SELECT COUNT(*) as total_requests, COALESCE(SUM(input_tokens), 0) as total_input, COALESCE(SUM(output_tokens), 0) as total_output, COALESCE(SUM(cost_usd), 0) as total_cost, COALESCE(AVG(latency_ms), 0) as avg_latency FROM usage_logs WHERE timestamp BETWEEN $1 AND $2 """, start_date, end_date) # 팀별 분해 team_breakdown = await conn.fetch(""" SELECT team_id, COUNT(*) as requests, COALESCE(SUM(cost_usd), 0) as cost, COALESCE(SUM(total_tokens), 0) as tokens FROM usage_logs WHERE timestamp BETWEEN $1 AND $2 GROUP BY team_id ORDER BY cost DESC """, start_date, end_date) # 모델별 분해 model_breakdown = await conn.fetch(""" SELECT model, COUNT(*) as requests, COALESCE(SUM(cost_usd), 0) as cost, COALESCE(SUM(total_tokens), 0) as tokens, COALESCE(AVG(latency_ms), 0) as avg_latency FROM usage_logs WHERE timestamp BETWEEN $1 AND $2 GROUP BY model ORDER BY cost DESC LIMIT 10 """, start_date, end_date) # 일별 비용 추이 daily_trend = await conn.fetch(""" SELECT DATE(timestamp) as date, COALESCE(SUM(cost_usd), 0) as cost, COUNT(*) as requests FROM usage_logs WHERE timestamp BETWEEN $1 AND $2 GROUP BY DATE(timestamp) ORDER BY date """, start_date, end_date) return DashboardSummary( period=f"{start_date.date()} ~ {end_date.date()}", start_date=start_date, end_date=end_date, total_cost_usd=float(summary['total_cost']), total_requests=summary['total_requests'], total_input_tokens=summary['total_input'], total_output_tokens=summary['total_output'], avg_cost_per_request=( float(summary['total_cost']) / summary['total_requests'] if summary['total_requests'] > 0 else 0 ), teams=[ { "team_id": r['team_id'], "requests": r['requests'], "cost_usd": float(r['cost']), "tokens": r['tokens'] } for r in team_breakdown ], top_models=[ { "model": r['model'], "requests": r['requests'], "cost_usd": float(r['cost']), "tokens": r['tokens'], "avg_latency_ms": float(r['avg_latency']) } for r in model_breakdown ], cost_trend=[ { "date": r['date'].isoformat(), "cost_usd": float(r['cost']), "requests": r['requests'] } for r in daily_trend ] ) async def get_team_detail( self, team_id: str, start_date: datetime, end_date: datetime ) -> TeamCostDetail: """팀별 상세 비용""" async with self.pool.acquire() as conn: # 프로젝트별 분해 project_breakdown = await conn.fetch(""" SELECT project_id, COUNT(*) as requests, COALESCE(SUM(cost_usd), 0) as cost, COALESCE(SUM(total_tokens), 0) as tokens, jsonb_object_agg( feature, jsonb_build_object( 'cost', COALESCE(SUM(cost_usd) FILTER (WHERE feature = f.feature), 0), 'requests', COUNT(*) FILTER (WHERE feature = f.feature) ) ) as features FROM usage_logs CROSS JOIN LATERAL unnest(ARRAY[feature]) AS f(feature) WHERE team_id = $1 AND timestamp BETWEEN $2 AND $3 GROUP BY project_id ORDER BY cost DESC """, team_id, start_date, end_date) # 예산 상태 budget = await conn.fetchrow(""" SELECT * FROM budgets WHERE identifier = $1 """, f"team:{team_id}") current_spend = await conn.fetchval(""" SELECT COALESCE(SUM(cost_usd), 0) FROM usage_logs WHERE team_id = $1 AND timestamp >= DATE_TRUNC('month', NOW()) """, team_id) budget_status = None if budget: percentage = (float(current_spend) / float(budget['monthly_limit_usd'])) * 100 budget_status = { "limit": float(budget['monthly_limit_usd']), "current": float(current_spend), "remaining": float(budget['monthly_limit_usd']) - float(current_spend), "percentage": round(percentage, 2), "status": "exceeded" if percentage >= 100 else "warning" if percentage >= 80 else "normal" } return TeamCostDetail( team_id=team_id, projects=[ { "project_id": r['project_id'], "requests": r['requests'], "cost_usd": float(r['cost']), "tokens": r['tokens'] } for r in project_breakdown ], total_cost=sum(float(r['cost']) for r in project_breakdown), budget_status=budget_status ) async def get_cost_optimization_report( self, start_date: datetime, end_date: datetime ) -> Dict: """비용 최적화 보고서""" async with self.pool.acquire() as conn: # 모델별 사용량 및 비용 model_usage = await conn.fetch(""" SELECT model, COUNT(*) as requests, COALESCE(SUM(input_tokens), 0) as input_tokens, COALESCE(SUM(output_tokens), 0) as output_tokens, COALESCE(SUM(cost_usd), 0) as total_cost FROM usage_logs WHERE timestamp BETWEEN $1 AND $2 GROUP BY model """, start_date, end_date) recommendations = [] total_cost = sum(float(r['total_cost']) for r in model_usage) for record in model_usage: model = record['model'] cost = float(record['total_cost']) cost_percentage = (cost / total_cost * 100) if total_cost > 0 else 0 # Claude Sonnet 사용 시 Gemini Flash 권장 if "claude-sonnet" in model and cost_percentage > 30: recommendations.append({ "current_model": model, "recommended_model": "gemini-2.5-flash", "reason": "Gemini 2.5 Flash는 동일한 품질 대비 6배 저렴", "estimated_savings": round(cost * 0.7, 2), "savings_percentage": "70%", "priority": "high" }) # GPT-4.1 사용 시 DeepSeek 권장 if "gpt-4.1" in model and cost_percentage > 20: recommendations.append({ "current_model": model, "recommended_model": "deepseek-v3.2", "reason": "DeepSeek V3.2는 GPT-4.1 대비 19배 저렴", "estimated_savings": round(cost * 0.95, 2), "savings_percentage": "95%", "priority": "high" }) # 반복 호출 감지 repeat_requests = await conn.fetchval(""" SELECT COUNT(*) / COUNT(DISTINCT request_id) FROM usage_logs WHERE model = $1 AND timestamp BETWEEN $2 AND $3 """, model, start_date, end_date) if repeat_requests > 1.5: recommendations.append({ "issue": "High repeat request rate", "suggestion": "Implement semantic caching layer", "potential_savings": round(cost * 0.25, 2), "priority": "medium" }) return { "total_current_cost": round(total_cost, 2), "potential_savings": sum( r.get('estimated_savings', 0) for r in recommendations ), "recommendations": recommendations }

===== FastAPI 엔드포인트 =====

db: Optional[DatabaseManager] = None @app.on_event("startup") async def startup(): global db db = DatabaseManager( dsn="postgresql://user:pass@localhost:5432/holysheep_costs" ) await db.connect() await db.init_schema() @app.on_event("shutdown") async def shutdown(): if db: await db.disconnect() @app.get("/api/dashboard/summary") async def get_summary( days: int = 30, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None ): """대시보드 요약""" if not start_date: end_date = datetime.utcnow() start_date = end_date - timedelta(days=days) return await db.get_dashboard_summary(start_date, end_date) @app.get("/api/teams/{team_id}/costs") async def get_team_costs( team_id: str, days: int = 30, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None ): """팀별 비용 상세""" if not start_date: end_date = datetime.utcnow() start_date = end_date - timedelta(days=days) return await db.get_team_detail(team_id, start_date, end_date) @app.get("/api/optimization/report") async def get_optimization_report(days: int = 30): """비용 최적화 보고서""" end_date = datetime.utcnow() start_date = end_date - timedelta(days=days) return await db.get_cost_optimization_report(start_date, end_date) @app.post("/api/budgets") async def create_budget( identifier: str, monthly_limit_usd: float, alert_threshold: float = 0.8, webhook_url: Optional[str] = None ): """예산 생성""" async with db.pool.acquire() as conn: await conn.execute(""" INSERT INTO budgets (identifier, monthly_limit_usd, alert_threshold, webhook_url) VALUES ($1, $2, $3, $4) ON CONFLICT (identifier) DO UPDATE SET monthly_limit_usd = EXCLUDED.monthly_limit_usd, alert_threshold = EXCLUDED.alert_threshold, webhook_url = EXCLUDED.webhook_url, updated_at = NOW() """, identifier, monthly_limit_usd, alert_threshold, webhook_url) return {"status": "success", "identifier": identifier}

===== 실행 =====

uvicorn main:app --host 0.0.0.0 --port 8000

print(""" ================================================================================ HolySheep AI 비용 추적 대시보드 API 시작 ================================================================================ 프론트엔드 연동 예시: fetch('/api/dashboard/summary?days=30') .then(r => r.json()) .then(data => { // Chart.js로 시각화 new Chart(ctx, { type: 'line', data: { labels: data.cost_trend.map(d => d.date), datasets: [{ label: '일별 비용