Datavision / backend /api /v1 /endpoints /monitoring.py
DataVision CI/CD Bot
release: clean production build for HuggingFace Space
ee7d7b9
Raw
History Blame Contribute Delete
3.34 kB
from fastapi import APIRouter, HTTPException, Depends
from typing import Dict, Any, Optional
from pydantic import BaseModel
import pandas as pd
from api.deps import get_current_user_id
from ml.model_deployer import get_model_deployer
from ml.model_monitor import ModelMonitor
from ml.model_persistence import get_model_persistence_manager
from utils.paths import get_user_paths
import json
router = APIRouter(prefix="/monitoring", tags=["Monitoring"])
@router.get("/{deploy_id}/metrics")
async def get_model_metrics(
deploy_id: str,
user_id: str = Depends(get_current_user_id)
):
"""Get time-series metrics (latency, usage) for a deployed model"""
deployer = get_model_deployer()
if deploy_id not in deployer.registry:
raise HTTPException(status_code=404, detail="Deployment not found")
deployment = deployer.registry[deploy_id]
if deployment["user_id"] != user_id:
raise HTTPException(status_code=403, detail="Access denied")
try:
metrics = ModelMonitor.get_metrics(deploy_id)
# Attach deployment metadata
metrics["model_name"] = deployment.get("model_name", "Unknown Model")
metrics["task_type"] = deployment.get("task_type", "unknown")
metrics["created_at"] = deployment.get("created_at")
metrics["status"] = deployment.get("status")
return {"success": True, "data": metrics}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/{deploy_id}/drift")
async def get_model_drift(
deploy_id: str,
user_id: str = Depends(get_current_user_id)
):
"""Calculate data drift for a deployed model"""
deployer = get_model_deployer()
if deploy_id not in deployer.registry:
raise HTTPException(status_code=404, detail="Deployment not found")
deployment = deployer.registry[deploy_id]
if deployment["user_id"] != user_id:
raise HTTPException(status_code=403, detail="Access denied")
try:
# Load training dataset stats if possible
# For full accuracy we'd need the original dataframe, but we'll try to load it from the user's workspace
# if we know the target column, or use the model's persistence manager.
pm = get_model_persistence_manager()
state = pm.load_model(user_id, version=deployment.get("version"))
# We need the original feature columns to do this properly.
# If we have the training dataframe path, we load it.
# To avoid blocking, we will just use dummy logic if the dataframe isn't found.
# In a real system, the training dataset distribution (means, stds) would be saved with the model state.
# Simulated dataframe with random distributions if state is missing
# In this implementation, we will use the telemetry data against a simulated baseline for demonstration.
alerts = ModelMonitor.calculate_drift(deploy_id)
# If no alerts, and we want to demo the feature, we can simulate drift if requested?
# Let's just return what ModelMonitor gives, which handles empty training_df gracefully (returns []).
return {"success": True, "alerts": alerts}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))