youtube-summarizer/backend/api/cache.py

166 lines
5.4 KiB
Python

"""Cache management API endpoints."""
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import Dict, Any, Optional
from ..services.enhanced_cache_manager import EnhancedCacheManager, CacheConfig
from ..models.api_models import BaseResponse
router = APIRouter(prefix="/api/cache", tags=["cache"])
# Global instance of enhanced cache manager
_cache_manager_instance: Optional[EnhancedCacheManager] = None
async def get_enhanced_cache_manager() -> EnhancedCacheManager:
"""Get or create enhanced cache manager instance."""
global _cache_manager_instance
if not _cache_manager_instance:
config = CacheConfig(
redis_url="redis://localhost:6379/0", # TODO: Get from environment
transcript_ttl_hours=168, # 7 days
summary_ttl_hours=72, # 3 days
enable_analytics=True
)
_cache_manager_instance = EnhancedCacheManager(config)
await _cache_manager_instance.initialize()
return _cache_manager_instance
@router.get("/analytics", response_model=Dict[str, Any])
async def get_cache_analytics(
cache_manager: EnhancedCacheManager = Depends(get_enhanced_cache_manager)
) -> Dict[str, Any]:
"""Get comprehensive cache analytics and metrics.
Returns cache performance metrics, hit rates, memory usage, and configuration.
"""
try:
analytics = await cache_manager.get_cache_analytics()
return {
"status": "success",
"data": analytics
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to get cache analytics: {str(e)}")
@router.post("/invalidate", response_model=Dict[str, Any])
async def invalidate_cache(
pattern: Optional[str] = Query(None, description="Optional pattern to match cache keys"),
cache_manager: EnhancedCacheManager = Depends(get_enhanced_cache_manager)
) -> Dict[str, Any]:
"""Invalidate cache entries.
Args:
pattern: Optional pattern to match cache keys. If not provided, clears all cache.
Returns:
Number of entries invalidated.
"""
try:
count = await cache_manager.invalidate_cache(pattern)
return {
"status": "success",
"message": f"Invalidated {count} cache entries",
"count": count
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to invalidate cache: {str(e)}")
@router.get("/stats", response_model=Dict[str, Any])
async def get_cache_stats(
cache_manager: EnhancedCacheManager = Depends(get_enhanced_cache_manager)
) -> Dict[str, Any]:
"""Get basic cache statistics.
Returns cache hit rate, total operations, and error count.
"""
try:
metrics = cache_manager.metrics.to_dict()
return {
"status": "success",
"data": {
"hit_rate": metrics["hit_rate"],
"total_hits": metrics["hits"],
"total_misses": metrics["misses"],
"total_operations": metrics["total_operations"],
"average_response_time_ms": metrics["average_response_time_ms"],
"errors": metrics["errors"]
}
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to get cache stats: {str(e)}")
@router.post("/warm", response_model=Dict[str, Any])
async def warm_cache(
video_ids: list[str],
cache_manager: EnhancedCacheManager = Depends(get_enhanced_cache_manager)
) -> Dict[str, Any]:
"""Warm cache for specific video IDs.
Args:
video_ids: List of YouTube video IDs to warm cache for.
Returns:
Status of cache warming operation.
"""
try:
# TODO: Implement cache warming logic
# This would fetch transcripts and generate summaries for the provided video IDs
return {
"status": "success",
"message": f"Cache warming initiated for {len(video_ids)} videos",
"video_count": len(video_ids)
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to warm cache: {str(e)}")
@router.get("/health", response_model=Dict[str, Any])
async def cache_health_check(
cache_manager: EnhancedCacheManager = Depends(get_enhanced_cache_manager)
) -> Dict[str, Any]:
"""Check cache system health.
Returns health status of cache components.
"""
try:
health = {
"status": "healthy",
"components": {
"memory_cache": True,
"redis": False,
"background_tasks": cache_manager._initialized
}
}
# Check Redis connection
if cache_manager.redis_client:
try:
await cache_manager.redis_client.ping()
health["components"]["redis"] = True
except:
health["components"]["redis"] = False
# Check hit rate threshold
if cache_manager.metrics.hit_rate < cache_manager.config.hit_rate_alert_threshold:
health["warnings"] = [
f"Hit rate ({cache_manager.metrics.hit_rate:.2%}) below threshold ({cache_manager.config.hit_rate_alert_threshold:.2%})"
]
return health
except Exception as e:
return {
"status": "unhealthy",
"error": str(e)
}