| from fastapi import FastAPI, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.staticfiles import StaticFiles |
| from pydantic import BaseModel |
| import subprocess |
| import os |
| import uuid |
| import shutil |
|
|
| app = FastAPI() |
|
|
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| os.makedirs("media", exist_ok=True) |
|
|
| |
| app.mount("/media", StaticFiles(directory="media"), name="media") |
|
|
| class RenderRequest(BaseModel): |
| code: str |
| scene_name: str |
| quality: str = "m" |
|
|
| @app.post("/render") |
| async def render_video(req: RenderRequest): |
| |
| run_id = str(uuid.uuid4()) |
| py_file = f"{run_id}.py" |
| |
| |
| with open(py_file, "w", encoding="utf-8") as f: |
| f.write(req.code) |
| |
| q_flag = f"-q{req.quality}" |
| out_dir = f"temp_{run_id}" |
| |
| |
| cmd = ["manim", q_flag, "--media_dir", out_dir, py_file, req.scene_name] |
| |
| try: |
| |
| result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) |
| |
| if result.returncode != 0: |
| raise Exception(result.stderr or result.stdout) |
| |
| |
| video_path = None |
| for root, dirs, files in os.walk(out_dir): |
| for file in files: |
| if file.endswith(".mp4"): |
| video_path = os.path.join(root, file) |
| break |
| |
| if not video_path: |
| raise Exception("Render xong nhưng không tìm thấy file MP4.") |
| |
| |
| final_url_path = f"/media/{run_id}.mp4" |
| shutil.copy(video_path, f".{final_url_path}") |
| |
| return {"video_url": final_url_path} |
| |
| except subprocess.TimeoutExpired: |
| raise HTTPException(status_code=408, detail={"stderr": "Render quá thời gian (Timeout 120s)."}) |
| except Exception as e: |
| raise HTTPException(status_code=400, detail={"stderr": str(e)}) |
| finally: |
| |
| if os.path.exists(py_file): |
| os.remove(py_file) |
| if os.path.exists(out_dir): |
| shutil.rmtree(out_dir) |
|
|
| @app.get("/") |
| def read_root(): |
| return {"status": "Manim Backend is running!"} |