327 lines
12 KiB
Python
327 lines
12 KiB
Python
"""Multi-model AI API endpoints."""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from typing import Dict, Any, Optional
|
|
from enum import Enum
|
|
|
|
from ..services.multi_model_service import MultiModelService, get_multi_model_service
|
|
from ..services.ai_model_registry import ModelProvider, ModelSelectionStrategy
|
|
from ..services.ai_service import SummaryRequest, SummaryLength
|
|
from ..models.api_models import BaseResponse
|
|
|
|
router = APIRouter(prefix="/api/models", tags=["models"])
|
|
|
|
|
|
class ModelProviderEnum(str, Enum):
|
|
"""API enum for model providers."""
|
|
OPENAI = "openai"
|
|
ANTHROPIC = "anthropic"
|
|
DEEPSEEK = "deepseek"
|
|
|
|
|
|
class ModelStrategyEnum(str, Enum):
|
|
"""API enum for selection strategies."""
|
|
COST_OPTIMIZED = "cost_optimized"
|
|
QUALITY_OPTIMIZED = "quality_optimized"
|
|
SPEED_OPTIMIZED = "speed_optimized"
|
|
BALANCED = "balanced"
|
|
|
|
|
|
@router.get("/available", response_model=Dict[str, Any])
|
|
async def get_available_models(
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Get list of available AI models and their configurations.
|
|
|
|
Returns information about all configured models including capabilities,
|
|
pricing, and current availability status.
|
|
"""
|
|
try:
|
|
models = []
|
|
for provider_name in service.get_available_models():
|
|
provider = ModelProvider(provider_name)
|
|
config = service.registry.get_model_config(provider)
|
|
if config:
|
|
models.append({
|
|
"provider": provider_name,
|
|
"model": config.model_name,
|
|
"display_name": config.display_name,
|
|
"available": config.is_available,
|
|
"context_window": config.context_window,
|
|
"max_tokens": config.max_tokens,
|
|
"pricing": {
|
|
"input_per_1k": config.input_cost_per_1k,
|
|
"output_per_1k": config.output_cost_per_1k
|
|
},
|
|
"performance": {
|
|
"latency_ms": config.average_latency_ms,
|
|
"reliability": config.reliability_score,
|
|
"quality": config.quality_score
|
|
},
|
|
"capabilities": [cap.value for cap in config.capabilities],
|
|
"languages": config.supported_languages
|
|
})
|
|
|
|
return {
|
|
"status": "success",
|
|
"models": models,
|
|
"active_count": len([m for m in models if m["available"]])
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get models: {str(e)}")
|
|
|
|
|
|
@router.post("/summarize", response_model=Dict[str, Any])
|
|
async def generate_multi_model_summary(
|
|
request: SummaryRequest,
|
|
provider: Optional[ModelProviderEnum] = Query(None, description="Preferred model provider"),
|
|
strategy: Optional[ModelStrategyEnum] = Query(ModelStrategyEnum.BALANCED, description="Model selection strategy"),
|
|
max_cost: Optional[float] = Query(None, description="Maximum cost in USD"),
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Generate summary using multi-model system with intelligent selection.
|
|
|
|
Args:
|
|
request: Summary request with transcript and options
|
|
provider: Optional preferred provider
|
|
strategy: Model selection strategy
|
|
max_cost: Optional maximum cost constraint
|
|
|
|
Returns:
|
|
Summary result with model used and cost information
|
|
"""
|
|
try:
|
|
# Convert enums
|
|
model_provider = ModelProvider(provider.value) if provider else None
|
|
model_strategy = ModelSelectionStrategy(strategy.value)
|
|
|
|
# Generate summary
|
|
result, used_provider = await service.generate_summary(
|
|
request=request,
|
|
strategy=model_strategy,
|
|
preferred_provider=model_provider,
|
|
max_cost=max_cost
|
|
)
|
|
|
|
return {
|
|
"status": "success",
|
|
"summary": result.summary,
|
|
"key_points": result.key_points,
|
|
"main_themes": result.main_themes,
|
|
"actionable_insights": result.actionable_insights,
|
|
"confidence_score": result.confidence_score,
|
|
"model_used": used_provider.value,
|
|
"usage": {
|
|
"input_tokens": result.usage.input_tokens,
|
|
"output_tokens": result.usage.output_tokens,
|
|
"total_tokens": result.usage.total_tokens
|
|
},
|
|
"cost": result.cost_data,
|
|
"metadata": result.processing_metadata
|
|
}
|
|
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Summarization failed: {str(e)}")
|
|
|
|
|
|
@router.post("/compare", response_model=Dict[str, Any])
|
|
async def compare_models(
|
|
request: SummaryRequest,
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Compare summary results across different models.
|
|
|
|
Generates summaries using all available models and provides
|
|
a comparison of results, costs, and performance.
|
|
|
|
Args:
|
|
request: Summary request
|
|
|
|
Returns:
|
|
Comparison of results from different models
|
|
"""
|
|
try:
|
|
results = {}
|
|
|
|
# Generate summary with each available provider
|
|
for provider_name in service.get_available_models():
|
|
provider = ModelProvider(provider_name)
|
|
|
|
try:
|
|
result, _ = await service.generate_summary(
|
|
request=request,
|
|
preferred_provider=provider
|
|
)
|
|
|
|
results[provider_name] = {
|
|
"success": True,
|
|
"summary": result.summary[:500] + "..." if len(result.summary) > 500 else result.summary,
|
|
"key_points_count": len(result.key_points),
|
|
"confidence": result.confidence_score,
|
|
"cost": result.cost_data["total_cost"],
|
|
"processing_time": result.processing_metadata.get("processing_time", 0),
|
|
"tokens": result.usage.total_tokens
|
|
}
|
|
|
|
except Exception as e:
|
|
results[provider_name] = {
|
|
"success": False,
|
|
"error": str(e)
|
|
}
|
|
|
|
# Calculate statistics
|
|
successful = [r for r in results.values() if r.get("success")]
|
|
|
|
if successful:
|
|
avg_cost = sum(r["cost"] for r in successful) / len(successful)
|
|
avg_confidence = sum(r["confidence"] for r in successful) / len(successful)
|
|
|
|
return {
|
|
"status": "success",
|
|
"comparisons": results,
|
|
"statistics": {
|
|
"models_tested": len(results),
|
|
"successful": len(successful),
|
|
"average_cost": avg_cost,
|
|
"average_confidence": avg_confidence,
|
|
"cheapest": min(successful, key=lambda x: x["cost"])["cost"] if successful else 0,
|
|
"fastest": min(successful, key=lambda x: x["processing_time"])["processing_time"] if successful else 0
|
|
}
|
|
}
|
|
else:
|
|
return {
|
|
"status": "partial",
|
|
"comparisons": results,
|
|
"message": "No models succeeded"
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Comparison failed: {str(e)}")
|
|
|
|
|
|
@router.get("/metrics", response_model=Dict[str, Any])
|
|
async def get_model_metrics(
|
|
provider: Optional[ModelProviderEnum] = Query(None, description="Specific provider or all"),
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Get performance metrics for AI models.
|
|
|
|
Returns usage statistics, success rates, costs, and performance metrics
|
|
for the specified provider or all providers.
|
|
|
|
Args:
|
|
provider: Optional specific provider
|
|
|
|
Returns:
|
|
Metrics and statistics
|
|
"""
|
|
try:
|
|
if provider:
|
|
model_provider = ModelProvider(provider.value)
|
|
metrics = service.get_provider_metrics(model_provider)
|
|
else:
|
|
metrics = service.get_metrics()
|
|
|
|
return {
|
|
"status": "success",
|
|
"metrics": metrics
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get metrics: {str(e)}")
|
|
|
|
|
|
@router.post("/estimate-cost", response_model=Dict[str, Any])
|
|
async def estimate_cost(
|
|
transcript_length: int = Query(..., description="Transcript length in characters"),
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Estimate cost for summarization across different models.
|
|
|
|
Provides cost estimates and recommendations for model selection
|
|
based on transcript length.
|
|
|
|
Args:
|
|
transcript_length: Length of transcript in characters
|
|
|
|
Returns:
|
|
Cost estimates and recommendations
|
|
"""
|
|
try:
|
|
if transcript_length <= 0:
|
|
raise ValueError("Transcript length must be positive")
|
|
|
|
estimates = service.estimate_cost(transcript_length)
|
|
|
|
return {
|
|
"status": "success",
|
|
"data": estimates
|
|
}
|
|
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to estimate cost: {str(e)}")
|
|
|
|
|
|
@router.post("/reset-availability", response_model=Dict[str, Any])
|
|
async def reset_model_availability(
|
|
provider: Optional[ModelProviderEnum] = Query(None, description="Specific provider or all"),
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Reset model availability after errors.
|
|
|
|
Clears error states and marks models as available again.
|
|
|
|
Args:
|
|
provider: Optional specific provider to reset
|
|
|
|
Returns:
|
|
Reset confirmation
|
|
"""
|
|
try:
|
|
if provider:
|
|
model_provider = ModelProvider(provider.value)
|
|
service.reset_model_availability(model_provider)
|
|
message = f"Reset availability for {provider.value}"
|
|
else:
|
|
service.reset_model_availability()
|
|
message = "Reset availability for all models"
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": message
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to reset availability: {str(e)}")
|
|
|
|
|
|
@router.put("/strategy", response_model=Dict[str, Any])
|
|
async def set_default_strategy(
|
|
strategy: ModelStrategyEnum,
|
|
service: MultiModelService = Depends(get_multi_model_service)
|
|
) -> Dict[str, Any]:
|
|
"""Set default model selection strategy.
|
|
|
|
Args:
|
|
strategy: New default strategy
|
|
|
|
Returns:
|
|
Confirmation of strategy change
|
|
"""
|
|
try:
|
|
model_strategy = ModelSelectionStrategy(strategy.value)
|
|
service.set_default_strategy(model_strategy)
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": f"Default strategy set to {strategy.value}",
|
|
"strategy": strategy.value
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to set strategy: {str(e)}") |