Spaces:
Runtime error
Runtime error
| """ | |
| ARF API Control Plane - Main Application Entry Point | |
| With optional heavy dependencies and usage tracking. | |
| """ | |
| import logging | |
| import os | |
| import sys | |
| import json | |
| from contextlib import asynccontextmanager | |
| from typing import Dict | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| # Optional prometheus | |
| try: | |
| from prometheus_fastapi_instrumentator import Instrumentator | |
| PROMETHEUS_AVAILABLE = True | |
| except ImportError: | |
| PROMETHEUS_AVAILABLE = False | |
| Instrumentator = None | |
| # Optional slowapi | |
| try: | |
| from slowapi import _rate_limit_exceeded_handler | |
| from slowapi.errors import RateLimitExceeded | |
| from slowapi.middleware import SlowAPIMiddleware | |
| SLOWAPI_AVAILABLE = True | |
| except ImportError: | |
| SLOWAPI_AVAILABLE = False | |
| _rate_limit_exceeded_handler = None | |
| RateLimitExceeded = None | |
| SlowAPIMiddleware = None | |
| # Optional agentic_reliability_framework (risk engine, policy engine, etc.) | |
| try: | |
| from agentic_reliability_framework.core.governance.risk_engine import RiskEngine | |
| from agentic_reliability_framework.core.governance.policy_engine import PolicyEngine | |
| from agentic_reliability_framework.runtime.memory import create_faiss_index, RAGGraphMemory | |
| from agentic_reliability_framework.runtime.memory.constants import MemoryConstants | |
| ARF_AVAILABLE = True | |
| except ImportError: | |
| ARF_AVAILABLE = False | |
| RiskEngine = None | |
| PolicyEngine = None | |
| create_faiss_index = None | |
| RAGGraphMemory = None | |
| MemoryConstants = None | |
| # ===== USAGE TRACKER ===== | |
| from app.core.usage_tracker import init_tracker, tracker, Tier | |
| from app.api import ( | |
| routes_governance, | |
| routes_history, | |
| routes_incidents, | |
| routes_intents, | |
| routes_risk, | |
| routes_memory, | |
| routes_admin, | |
| routes_payments, | |
| webhooks, | |
| routes_users, | |
| ) | |
| from app.api.deps import limiter | |
| from app.core.config import settings | |
| logger = logging.getLogger("arf.api") | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", | |
| handlers=[logging.StreamHandler(sys.stdout)], | |
| ) | |
| async def lifespan(app: FastAPI): | |
| logger.info("🚀 Starting ARF API Control Plane") | |
| logger.debug(f"Python path: {sys.path}") | |
| if ARF_AVAILABLE: | |
| hmc_model_path = os.getenv("ARF_HMC_MODEL", "models/hmc_model.json") | |
| use_hyperpriors = os.getenv( | |
| "ARF_USE_HYPERPRIORS", | |
| "false").lower() == "true" | |
| logger.info( | |
| "Initializing RiskEngine – HMC model: %s, hyperpriors: %s", | |
| hmc_model_path, | |
| use_hyperpriors) | |
| try: | |
| app.state.risk_engine = RiskEngine( | |
| hmc_model_path=hmc_model_path, | |
| use_hyperpriors=use_hyperpriors, | |
| n0=1000, | |
| hyperprior_weight=0.3, | |
| ) | |
| logger.info("✅ RiskEngine initialized successfully.") | |
| except Exception as e: | |
| logger.exception("💥 Fatal error initializing RiskEngine") | |
| raise RuntimeError("RiskEngine initialization failed") from e | |
| try: | |
| app.state.policy_engine = PolicyEngine() | |
| logger.info("✅ PolicyEngine initialized successfully.") | |
| except Exception as e: | |
| logger.warning(f"PolicyEngine initialization failed: {e}") | |
| app.state.policy_engine = None | |
| try: | |
| faiss_index = create_faiss_index(dim=MemoryConstants.VECTOR_DIM) | |
| app.state.rag_graph = RAGGraphMemory(faiss_index) | |
| logger.info("✅ RAGGraphMemory initialized successfully.") | |
| except Exception as e: | |
| logger.warning(f"RAGGraphMemory initialization failed: {e}") | |
| app.state.rag_graph = None | |
| epistemic_model_name = os.getenv("EPISTEMIC_MODEL", "") | |
| if epistemic_model_name: | |
| try: | |
| from sentence_transformers import SentenceTransformer | |
| logger.info(f"Loading epistemic model: {epistemic_model_name}") | |
| app.state.epistemic_model = SentenceTransformer( | |
| epistemic_model_name) | |
| app.state.epistemic_tokenizer = app.state.epistemic_model.tokenizer | |
| logger.info("✅ Epistemic model loaded.") | |
| except ImportError: | |
| logger.warning( | |
| "sentence-transformers not installed; epistemic signals will be zeros.") | |
| app.state.epistemic_model = None | |
| app.state.epistemic_tokenizer = None | |
| except Exception as e: | |
| logger.warning(f"Failed to load epistemic model: {e}") | |
| app.state.epistemic_model = None | |
| app.state.epistemic_tokenizer = None | |
| else: | |
| logger.info( | |
| "EPISTEMIC_MODEL not set; epistemic signals will be zeros.") | |
| app.state.epistemic_model = None | |
| app.state.epistemic_tokenizer = None | |
| else: | |
| logger.warning( | |
| "agentic_reliability_framework not installed; risk engine, policy engine, RAG disabled.") | |
| # ===== USAGE TRACKER INITIALISATION ===== | |
| if os.getenv("ARF_USAGE_TRACKING", "false").lower() == "true": | |
| logger.info("Initialising usage tracker...") | |
| # HARDCODED WRITABLE PATH – fixes 503 error | |
| init_tracker( | |
| db_path="/tmp/arf_usage.db", # was os.getenv("ARF_USAGE_DB_PATH", "arf_usage.db") | |
| redis_url=os.getenv("ARF_REDIS_URL") | |
| ) | |
| # Seed initial API keys from environment variable (for testing / demo) | |
| api_keys_json = os.getenv("ARF_API_KEYS", "{}") | |
| try: | |
| api_keys = json.loads(api_keys_json) | |
| for key, tier_str in api_keys.items(): | |
| try: | |
| tier = Tier(tier_str.lower()) | |
| tracker.get_or_create_api_key(key, tier) | |
| logger.info(f"Seeded API key for tier {tier.value}") | |
| except ValueError: | |
| logger.warning(f"Invalid tier '{tier_str}' for key {key}, skipping") | |
| except json.JSONDecodeError: | |
| logger.warning("ARF_API_KEYS environment variable is not valid JSON; skipping seeding.") | |
| app.state.usage_tracker = tracker | |
| logger.info("✅ Usage tracker ready.") | |
| else: | |
| logger.info("Usage tracking disabled (ARF_USAGE_TRACKING not set to true).") | |
| app.state.usage_tracker = None | |
| yield | |
| logger.info("🛑 Shutting down ARF API") | |
| def create_app() -> FastAPI: | |
| app = FastAPI( | |
| title=settings.app_name, | |
| version="0.5.0", | |
| lifespan=lifespan, | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| description="Agentic Reliability Framework (ARF) API", | |
| ) | |
| allowed_origins = ["https://arf-frontend-sandy.vercel.app"] | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=allowed_origins, | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| logger.debug("CORS middleware configured") | |
| if SLOWAPI_AVAILABLE: | |
| app.state.limiter = limiter | |
| app.add_exception_handler( | |
| RateLimitExceeded, | |
| _rate_limit_exceeded_handler) | |
| app.add_middleware(SlowAPIMiddleware) | |
| logger.debug("Rate limiter middleware configured") | |
| else: | |
| logger.debug("Rate limiter disabled (slowapi not installed)") | |
| if PROMETHEUS_AVAILABLE: | |
| Instrumentator().instrument(app).expose(app) | |
| logger.debug("Prometheus instrumentator configured") | |
| else: | |
| logger.debug( | |
| "Prometheus instrumentator disabled (module not installed)") | |
| # Include routers | |
| app.include_router( | |
| routes_incidents.router, | |
| prefix="/api/v1", | |
| tags=["incidents"]) | |
| app.include_router(routes_risk.router, prefix="/api/v1", tags=["risk"]) | |
| app.include_router( | |
| routes_intents.router, | |
| prefix="/api/v1", | |
| tags=["intents"]) | |
| app.include_router( | |
| routes_history.router, | |
| prefix="/api/v1", | |
| tags=["history"]) | |
| app.include_router( | |
| routes_governance.router, | |
| prefix="/api/v1", | |
| tags=["governance"]) | |
| app.include_router( | |
| routes_memory.router, | |
| prefix="/v1/memory", | |
| tags=["memory"]) | |
| app.include_router( | |
| routes_admin.router, | |
| prefix="/api/v1", | |
| tags=["admin"]) | |
| app.include_router( | |
| routes_payments.router, | |
| prefix="/api/v1", | |
| tags=["payments"]) | |
| app.include_router( | |
| webhooks.router, | |
| tags=["webhooks"]) | |
| app.include_router( | |
| routes_users.router, | |
| prefix="/api/v1", | |
| tags=["users"]) | |
| logger.debug("All API routers included") | |
| async def health() -> Dict[str, str]: | |
| return {"status": "ok"} | |
| return app | |
| app = create_app() |