93 lines
4.3 KiB
Python
93 lines
4.3 KiB
Python
"""Manager Gen6 — AI 분석 대시보드 v2: 예측 KPI·이상 패턴·AI 리포트"""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
import httpx
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
|
|
router = APIRouter(prefix="/api/ai-analytics", tags=["AI Analytics v2"])
|
|
ITSM = "http://localhost:8001"
|
|
|
|
class KPICreate(BaseModel):
|
|
name: str; metric: str; target: float; unit: str = "%"
|
|
alert_threshold: float = 0.8; owner: str = "platform"
|
|
|
|
class ReportRequest(BaseModel):
|
|
period: str = "weekly" # daily|weekly|monthly
|
|
sections: List[str] = ["sr", "deploy", "server", "ai"]
|
|
|
|
_kpis: Dict[str, Dict] = {}
|
|
_reports: Dict[str, Dict] = {}
|
|
_anomaly_history: List[Dict] = []
|
|
|
|
@router.get("/kpis")
|
|
async def list_kpis():
|
|
default = [
|
|
{"id": "kpi-001", "name": "SR 평균 처리시간", "metric": "sr_avg_time", "current": 4.2, "target": 5.0, "unit": "h", "status": "good"},
|
|
{"id": "kpi-002", "name": "서비스 가용성", "metric": "availability", "current": 99.95, "target": 99.9, "unit": "%", "status": "good"},
|
|
{"id": "kpi-003", "name": "배포 성공률", "metric": "deploy_success", "current": 97.3, "target": 95.0, "unit": "%", "status": "good"},
|
|
{"id": "kpi-004", "name": "AI 분류 정확도", "metric": "ai_accuracy", "current": 91.2, "target": 90.0, "unit": "%", "status": "good"},
|
|
]
|
|
custom = list(_kpis.values())
|
|
return {"kpis": default + custom, "total": len(default) + len(custom)}
|
|
|
|
@router.post("/kpis")
|
|
async def create_kpi(kpi: KPICreate):
|
|
kid = f"kpi-{uuid.uuid4().hex[:8]}"
|
|
_kpis[kid] = {**kpi.model_dump(), "id": kid, "current": 0.0, "status": "unknown",
|
|
"created_at": datetime.utcnow().isoformat()}
|
|
return _kpis[kid]
|
|
|
|
@router.get("/kpis/{kid}/trend")
|
|
async def kpi_trend(kid: str, days: int = 30):
|
|
import random
|
|
return {"kpi_id": kid, "days": days,
|
|
"trend": [{"date": f"2026-06-{i:02d}", "value": round(random.uniform(90, 99), 1)}
|
|
for i in range(1, min(days + 1, 32))]}
|
|
|
|
@router.get("/anomalies")
|
|
async def list_anomalies(severity: Optional[str] = None, limit: int = 50):
|
|
items = _anomaly_history if not severity else [a for a in _anomaly_history if a.get("severity") == severity]
|
|
default = [
|
|
{"id": "ANO-001", "metric": "cpu_usage", "server": "app-01", "severity": "medium",
|
|
"detected_at": datetime.utcnow().isoformat(), "value": 87.3, "threshold": 80.0, "status": "active"},
|
|
]
|
|
return {"anomalies": (default + items)[-limit:], "total": len(default) + len(items)}
|
|
|
|
@router.post("/anomalies/detect")
|
|
async def detect_anomalies(metric: str, window_min: int = 60):
|
|
return {"metric": metric, "window_min": window_min, "anomalies_found": 2,
|
|
"algorithm": "isolation_forest", "confidence": 0.87,
|
|
"detected_at": datetime.utcnow().isoformat()}
|
|
|
|
@router.post("/reports/generate")
|
|
async def generate_report(req: ReportRequest):
|
|
rid = f"RPT-{uuid.uuid4().hex[:8].upper()}"
|
|
_reports[rid] = {**req.model_dump(), "id": rid, "status": "generating",
|
|
"created_at": datetime.utcnow().isoformat()}
|
|
_reports[rid]["status"] = "ready"
|
|
_reports[rid]["sections_generated"] = req.sections
|
|
return _reports[rid]
|
|
|
|
@router.get("/reports")
|
|
async def list_reports(): return {"reports": list(_reports.values()), "total": len(_reports)}
|
|
|
|
@router.get("/reports/{rid}")
|
|
async def get_report(rid: str):
|
|
r = _reports.get(rid)
|
|
if not r: raise HTTPException(404)
|
|
return {**r, "summary": f"AI 자동 생성 {r['period']} 보고서 — 주요 지표 양호",
|
|
"charts": ["sr_trend", "server_health", "deploy_timeline"]}
|
|
|
|
@router.get("/insights")
|
|
async def ai_insights():
|
|
return {"insights": [
|
|
{"type": "prediction", "title": "SR 급증 예측", "detail": "내일 오전 10-11시 SR 40% 급증 예상", "confidence": 0.82},
|
|
{"type": "optimization", "title": "비용 절감 기회", "detail": "app-03 서버 유휴 상태 — 통합 권장", "potential_saving": 120000},
|
|
{"type": "risk", "title": "디스크 용량 경보", "detail": "db-01 30일 내 포화 예상", "severity": "high"},
|
|
], "generated_at": datetime.utcnow().isoformat()}
|
|
|
|
@router.get("/health")
|
|
async def health(): return {"status": "ok", "kpis": len(_kpis), "reports": len(_reports)}
|