""" SPARKNET FastAPI Backend Provides RESTful API for Patent Wake-Up workflows. """ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from pathlib import Path from loguru import logger # Global state for application lifecycle app_state = {} @asynccontextmanager async def lifespan(app: FastAPI): """Initialize SPARKNET components on startup""" logger.info("🚀 Starting SPARKNET API...") try: # Import here to avoid circular dependencies from src.llm.langchain_ollama_client import get_langchain_client from src.workflow.langgraph_workflow import create_workflow from src.agents.planner_agent import PlannerAgent from src.agents.critic_agent import CriticAgent from src.agents.memory_agent import create_memory_agent from src.agents.vision_ocr_agent import VisionOCRAgent # Initialize LangChain client logger.info("Initializing LangChain Ollama client...") app_state["llm_client"] = get_langchain_client( default_complexity='standard', enable_monitoring=False ) # Initialize agents logger.info("Initializing agents...") app_state["planner"] = PlannerAgent(llm_client=app_state["llm_client"]) app_state["critic"] = CriticAgent(llm_client=app_state["llm_client"]) app_state["memory"] = create_memory_agent( llm_client=app_state["llm_client"] ) # Initialize VisionOCR agent if llava model is available try: logger.info("Initializing VisionOCR agent...") vision_ocr = VisionOCRAgent(model_name="llava:7b") if vision_ocr.is_available(): app_state["vision_ocr"] = vision_ocr logger.success("✅ VisionOCR agent initialized with llava:7b") else: app_state["vision_ocr"] = None logger.warning("⚠️ llava:7b model not available, OCR features disabled") except Exception as e: logger.warning(f"⚠️ Failed to initialize VisionOCR: {e}, OCR features disabled") app_state["vision_ocr"] = None # Initialize workflow logger.info("Creating LangGraph workflow...") app_state["workflow"] = create_workflow( llm_client=app_state["llm_client"], planner_agent=app_state["planner"], critic_agent=app_state["critic"], memory_agent=app_state["memory"], vision_ocr_agent=app_state.get("vision_ocr"), quality_threshold=0.80, max_iterations=3 ) # Storage for active workflows and patents app_state["workflows"] = {} app_state["patents"] = {} # Ensure directories exist Path("uploads/patents").mkdir(parents=True, exist_ok=True) Path("outputs").mkdir(parents=True, exist_ok=True) Path("data/vector_store").mkdir(parents=True, exist_ok=True) logger.success("✅ SPARKNET API initialized successfully!") except Exception as e: logger.error(f"❌ Failed to initialize SPARKNET: {e}") raise yield # Cleanup on shutdown logger.info("Shutting down SPARKNET API...") app_state.clear() # Create FastAPI application app = FastAPI( title="SPARKNET API", description="AI-Powered Research Valorization Platform", version="1.0.0", lifespan=lifespan, docs_url="/api/docs", redoc_url="/api/redoc" ) # CORS middleware for frontend app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost:3000", # Next.js dev server "http://localhost:3001", "http://localhost:3002", "http://127.0.0.1:3000", "http://127.0.0.1:3001", "http://127.0.0.1:3002", "http://172.24.50.21:3000", # Server IP "http://172.24.50.21:3001", "http://172.24.50.21:3002" ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Import and include routers from api.routes import patents, workflows app.include_router(patents.router, prefix="/api/patents", tags=["Patents"]) app.include_router(workflows.router, prefix="/api/workflows", tags=["Workflows"]) @app.get("/") async def root(): """Root endpoint - health check""" return { "status": "operational", "service": "SPARKNET API", "version": "1.0.0", "message": "Welcome to SPARKNET - AI-Powered Research Valorization", "docs": "/api/docs" } @app.get("/api/health") async def health(): """Detailed health check endpoint""" components_healthy = { "llm_client": app_state.get("llm_client") is not None, "workflow": app_state.get("workflow") is not None, "planner": app_state.get("planner") is not None, "critic": app_state.get("critic") is not None, "memory": app_state.get("memory") is not None } all_healthy = all(components_healthy.values()) return { "status": "healthy" if all_healthy else "degraded", "components": components_healthy, "statistics": { "active_workflows": len(app_state.get("workflows", {})), "processed_patents": len(app_state.get("patents", {})) } } if __name__ == "__main__": import uvicorn uvicorn.run( "api.main:app", host="0.0.0.0", port=8000, reload=True, log_level="info" )