Spaces:
Sleeping
Sleeping
| """ | |
| FastAPI Backend for React Video Editor | |
| Handles video generation, image processing, and API integrations | |
| """ | |
| from fastapi import FastAPI, HTTPException, Request, Response | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import StreamingResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from contextlib import asynccontextmanager | |
| import uvicorn | |
| import os | |
| from dotenv import load_dotenv | |
| from api.video_generation import router as video_router | |
| from api.image_service import router as image_router | |
| from api.frame_extraction import router as frame_router | |
| from api.prompt_generation import router as prompt_router | |
| from api.video_export import router as export_router | |
| from api.replicate_service import router as replicate_router | |
| from api.whisper_service import router as whisper_router | |
| from api.auth import router as auth_router | |
| from utils.storage import cleanup_old_files | |
| # Load environment variables | |
| load_dotenv('.env.local') | |
| # Lifespan context manager for startup/shutdown | |
| async def lifespan(app: FastAPI): | |
| """Handle startup and shutdown events""" | |
| # Startup | |
| print("π Starting FastAPI server...") | |
| print(f"π Storage directory: {os.path.join(os.getcwd(), 'storage')}") | |
| # Create storage directory if it doesn't exist | |
| os.makedirs('storage/images', exist_ok=True) | |
| os.makedirs('storage/videos', exist_ok=True) | |
| # Check for API keys | |
| kie_api_key = os.getenv('KIE_API_KEY') | |
| if not kie_api_key: | |
| print("β οΈ Warning: KIE_API_KEY not set. Video generation will fail.") | |
| print(" Get your API key at: https://kie.ai/api-key") | |
| else: | |
| print("β KIE_API_KEY configured") | |
| gemini_api_key = os.getenv('VITE_GEMINI_API_KEY') | |
| if gemini_api_key: | |
| print("β GEMINI_API_KEY configured") | |
| openai_api_key = os.getenv('OPENAI_API_KEY') | |
| if openai_api_key: | |
| print("β OPENAI_API_KEY configured (GPT-4o prompt generation)") | |
| replicate_api_token = os.getenv('REPLICATE_API_TOKEN') | |
| if replicate_api_token: | |
| print("β REPLICATE_API_TOKEN configured") | |
| else: | |
| print("β οΈ Warning: REPLICATE_API_TOKEN not set. Replicate video generation will fail.") | |
| # Check environment mode | |
| environment = os.getenv('ENVIRONMENT', 'dev').lower() | |
| is_dev_mode = environment == 'dev' or environment == 'development' | |
| if is_dev_mode: | |
| print("π§ͺ DEV MODE: Segment generation limited to 2 segments") | |
| else: | |
| print("π PROD MODE: Generating all segments") | |
| yield | |
| # Shutdown | |
| print("π Shutting down FastAPI server...") | |
| cleanup_old_files() | |
| # Create FastAPI app | |
| app = FastAPI( | |
| title="React Video Editor API", | |
| description="Python backend for video generation and processing", | |
| version="1.0.0", | |
| lifespan=lifespan | |
| ) | |
| # CORS middleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], # In production, specify exact origins | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Include routers | |
| app.include_router(auth_router, prefix="/api") | |
| app.include_router(video_router, prefix="/api") | |
| app.include_router(image_router, prefix="/api") | |
| app.include_router(frame_router, prefix="/api") | |
| app.include_router(prompt_router, prefix="/api") | |
| app.include_router(export_router, prefix="/api") | |
| app.include_router(replicate_router, prefix="/api") | |
| app.include_router(whisper_router, prefix="/api") | |
| # Health check endpoints (must be before catch-all route) | |
| async def health_check(): | |
| """Health check endpoint""" | |
| environment = os.getenv('ENVIRONMENT', 'dev').lower() | |
| is_dev_mode = environment == 'dev' or environment == 'development' | |
| return { | |
| "status": "healthy", | |
| "environment": environment, | |
| "is_dev_mode": is_dev_mode, | |
| "max_segments": 2 if is_dev_mode else None, | |
| "kie_api_configured": bool(os.getenv('KIE_API_KEY')), | |
| "replicate_api_configured": bool(os.getenv('REPLICATE_API_TOKEN')), | |
| "gemini_api_configured": bool(os.getenv('VITE_GEMINI_API_KEY')), | |
| "openai_api_configured": bool(os.getenv('OPENAI_API_KEY')) | |
| } | |
| # Serve static files (frontend) in production | |
| frontend_dist_path = os.path.join(os.getcwd(), "frontend", "dist") | |
| if os.path.exists(frontend_dist_path): | |
| # Serve static files | |
| app.mount("/assets", StaticFiles(directory=os.path.join(frontend_dist_path, "assets")), name="assets") | |
| # Root endpoint - serve frontend or API info | |
| async def root(): | |
| """Root endpoint - serve frontend in production, API info in dev""" | |
| index_path = os.path.join(frontend_dist_path, "index.html") | |
| if os.path.exists(index_path): | |
| from fastapi.responses import FileResponse | |
| return FileResponse(index_path) | |
| # Fallback if frontend not built | |
| return { | |
| "status": "healthy", | |
| "service": "React Video Editor API", | |
| "version": "1.0.0" | |
| } | |
| # Serve frontend index.html for all non-API routes | |
| # This must be last to not interfere with API routes | |
| async def serve_frontend(full_path: str): | |
| """Serve frontend for all non-API routes""" | |
| # Don't serve frontend for API routes or docs - let FastAPI handle these | |
| if (full_path.startswith("api/") or | |
| full_path.startswith("docs") or | |
| full_path.startswith("redoc") or | |
| full_path.startswith("openapi.json") or | |
| full_path == "health"): | |
| raise HTTPException(status_code=404, detail="Not found") | |
| # Serve index.html for frontend routes | |
| index_path = os.path.join(frontend_dist_path, "index.html") | |
| if os.path.exists(index_path): | |
| from fastapi.responses import FileResponse | |
| return FileResponse(index_path) | |
| raise HTTPException(status_code=404, detail="Frontend not found") | |
| else: | |
| # Root endpoint when frontend not built | |
| async def root(): | |
| """Root endpoint - health check""" | |
| return { | |
| "status": "healthy", | |
| "service": "React Video Editor API", | |
| "version": "1.0.0" | |
| } | |
| if __name__ == "__main__": | |
| # Support both SERVER_PORT and PORT (Hugging Face uses PORT) | |
| port = int(os.getenv('PORT') or os.getenv('SERVER_PORT', 4000)) | |
| uvicorn.run( | |
| "main:app", | |
| host="0.0.0.0", | |
| port=port, | |
| reload=True, | |
| log_level="info" | |
| ) | |