""" Providers API Endpoints for provider registry and status """ from fastapi import APIRouter, HTTPException, Query from fastapi.responses import JSONResponse from typing import Optional, Dict, Any from datetime import datetime, timezone import logging from backend.services.provider_registry_service import get_registry_service from backend.services.registry_loader import get_registry_loader from backend.services.provider_fallback_manager import fallback_manager logger = logging.getLogger(__name__) router = APIRouter( prefix="/api/providers", tags=["Providers API"] ) registry_service = get_registry_service() registry_loader = get_registry_loader() @router.get("") async def get_providers( show_sources: bool = Query(False, description="Show source file information"), category: Optional[str] = Query(None, description="Filter by category") ): """ Get list of all providers Built from /mnt/data/all_apis_merged_2025.json and /mnt/data/api-config-complete.txt """ # Get providers from registry loader (parsed from all_apis_merged_2025.json) providers = registry_loader.providers # Also get from registry service (merged sources) registry = registry_service.build_registry() registry_providers = registry.get("providers", []) # Merge both sources (deduplicate by base_url) seen_urls = set() all_providers = [] # Add from registry_loader first for provider in providers: url_key = provider.get("base_url", "").lower().rstrip("/") if url_key and url_key not in seen_urls: seen_urls.add(url_key) all_providers.append(provider) # Add from registry_service for provider in registry_providers: url_key = provider.get("base_url", "").lower().rstrip("/") if url_key and url_key not in seen_urls: seen_urls.add(url_key) all_providers.append(provider) # Filter by category if specified if category: all_providers = [ p for p in all_providers if category in p.get("categories", []) or p.get("category") == category ] # Remove API keys and secrets safe_providers = [] for provider in all_providers: safe_provider = { "name": provider.get("name", "unknown"), "base_url": provider.get("base_url", ""), "category": provider.get("category", "generic"), "categories": provider.get("categories", [provider.get("category", "generic")]), "endpoints": provider.get("endpoints", {}), "free": provider.get("free", False), "priority": provider.get("priority", 10), "docs_url": provider.get("docs_url"), "has_api_key": bool(provider.get("api_key") or provider.get("auth_value")), "key_inline": bool(provider.get("auth_value")) } if show_sources: safe_provider["source_file"] = provider.get("source_file", "/mnt/data/all_apis_merged_2025.json") safe_provider["notes"] = provider.get("notes") safe_providers.append(safe_provider) return { "data": safe_providers, "meta": { "source": "registry", "generated_at": datetime.now(timezone.utc).isoformat(), "total_count": len(safe_providers), "free_count": sum(1 for p in safe_providers if p["free"]), "categories": list(set( cat for p in safe_providers for cat in p.get("categories", [p.get("category", "generic")]) )), "registry_files": [ "/mnt/data/all_apis_merged_2025.json", "/mnt/data/api-config-complete.txt" ] } } @router.get("/status") async def get_providers_status(): """Get status of all providers (circuit breakers, health, etc.)""" status = fallback_manager.get_provider_status() return { "data": status, "meta": { "source": "fallback_manager", "generated_at": datetime.now(timezone.utc).isoformat() } } @router.get("/health") async def get_providers_health(): """Get health check for all providers""" status = fallback_manager.get_provider_status() healthy = sum(1 for p in status["providers"] if p["is_available"]) total = status["total_providers"] return { "data": { "healthy": healthy, "total": total, "health_percentage": (healthy / total * 100) if total > 0 else 0, "providers": status["providers"] }, "meta": { "source": "fallback_manager", "generated_at": datetime.now(timezone.utc).isoformat() } }