from fastapi import FastAPI, Request, HTTPException, Security, BackgroundTasks from fastapi.middleware.cors import CORSMiddleware from fastapi.security import APIKeyHeader from fastapi.responses import StreamingResponse from pydantic import BaseModel import comfy_engine import httpx import os app = FastAPI(title="Sparkling Vision Pro API - Backend Engine") # 🌐 CORS सेटअप: यह बहुत ज़रूरी है ताकि दूसरा स्पेस इसे कॉल कर सके! app.add_middleware( CORSMiddleware, allow_origins=["*"], # प्रोडक्शन में इसे अपने फ्रंटएंड URL से रिप्लेस कर देना allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 🛡️ सीक्रेट पासवर्ड API_KEY = os.getenv("VIVEN_API_KEY", "your_default_password") header_scheme = APIKeyHeader(name="X-API-Key") async def verify_key(key: str = Security(header_scheme)): if key != API_KEY: raise HTTPException(status_code=403, detail="Access Denied! Invalid API Key.") return key class VideoRequest(BaseModel): prompt: str aspect_ratio: str = "16:9" quality: str = "480p" frames: int = 81 fps: int = 16 # ========================================== # 🚀 FIRE-AND-FORGET API ENDPOINT # ========================================== @app.post("/api/generate") async def generate(req: VideoRequest, bg_tasks: BackgroundTasks, auth: str = Security(verify_key)): try: task_id, client_id, token, total_nodes = await comfy_engine.queue_prompt(req.dict()) comfy_engine.init_task(task_id, req.prompt) bg_tasks.add_task(comfy_engine.background_watcher, task_id, client_id, token, total_nodes) return {"status": "queued", "task_id": task_id, "message": "Task is running in the background."} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) # ========================================== # 🗂️ STATUS & HISTORY ENDPOINTS # ========================================== @app.get("/api/history") async def get_history(): return comfy_engine.load_history() @app.get("/api/video") async def proxy_video(request: Request): q = request.query_params target = f"http://{comfy_engine.COMFY_HOST}/view?{q}" async def stream(): async with httpx.AsyncClient() as client: async with client.stream("GET", target, timeout=60.0) as r: async for chunk in r.aiter_bytes(): yield chunk return StreamingResponse(stream(), media_type="video/mp4") @app.delete("/api/history/{task_id}") async def delete_history_item(task_id: str): import json, os if os.path.exists("history.json"): with open("history.json", "r", encoding="utf-8") as f: data = json.load(f) data = [item for item in data if item["id"] != task_id] with open("history.json", "w", encoding="utf-8") as f: json.dump(data, f, indent=4) return {"status": "deleted"} return {"status": "not found"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)