post / main.py
ex510's picture
Upload 7 files
8f7c473 verified
"""
Video Showcase API
FastAPI โ€” ุจุชุจุนุชู„ู‡ ุจูŠุงู†ุงุช ุงู„ู…ู†ุชุฌุŒ ุจูŠุฑุฌุนู„ูƒ ููŠุฏูŠูˆ
"""
import os
import uuid
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
from typing import Optional
from templates import get_template, list_templates
from templates.base import RenderRequest
from renderer import render_video
app = FastAPI(
title="Video Showcase API",
description="ุจูŠุนู…ู„ ููŠุฏูŠูˆ Product Showcase ุชู„ู‚ุงุฆูŠ",
version="1.0.0"
)
OUTPUT_DIR = "/tmp/videos"
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ============================================================
# Models
# ============================================================
class VideoRequest(BaseModel):
# --- ู…ุทู„ูˆุจ ---
template: str = "showcase_arabic"
title: str
# --- ุงุฎุชูŠุงุฑูŠ ---
discount: Optional[str] = ""
badge: Optional[str] = ""
phone: Optional[str] = ""
website: Optional[str] = ""
image_path: Optional[str] = ""
music_path: Optional[str] = ""
bg_left: Optional[str] = ""
bg_right: Optional[str] = ""
duration: Optional[int] = 6
fps: Optional[int] = 30
width: Optional[int] = 1280
height: Optional[int] = 720
music_volume: Optional[float] = 0.20
# ============================================================
# Routes
# ============================================================
@app.get("/")
def root():
return {
"status": "running",
"message": "Video Showcase API ุดุบุงู„ โœ…",
"endpoints": {
"GET /templates": "ุดูˆู ุงู„ุชู…ุจู„ุชุณ ุงู„ู…ุชุงุญุฉ",
"POST /render": "ุงุนู…ู„ ููŠุฏูŠูˆ",
"GET /video/{video_id}": "ุญู…ู‘ู„ ุงู„ููŠุฏูŠูˆ",
"GET /health": "Health check"
}
}
@app.get("/health")
def health():
return {"status": "ok"}
@app.get("/templates")
def get_templates():
"""ุดูˆู ูƒู„ ุงู„ุชู…ุจู„ุชุณ ุงู„ู…ุชุงุญุฉ"""
return {
"templates": list_templates(),
"count": len(list_templates())
}
@app.post("/render")
def render(req: VideoRequest):
"""
ุงุนู…ู„ ููŠุฏูŠูˆ
ู…ุซุงู„ ู…ู† n8n:
POST /render
{
"template": "showcase_arabic",
"title": "ุงุญุฏุซ ุงุฌู‡ุฒุฉ\\nูƒู‡ุฑุจุงุฆูŠุฉ",
"discount": "ุฎุตู… 20ูช",
"image_path": "/tmp/product.png",
"music_path": "/tmp/music.mp3"
}
"""
# ุชุญู‚ู‚ ู…ู† ุงู„ุชู…ุจู„ุช
try:
template = get_template(req.template)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
# ID ูุฑูŠุฏ ู„ู„ููŠุฏูŠูˆ
video_id = str(uuid.uuid4())[:8]
output = os.path.join(OUTPUT_DIR, f"{video_id}.mp4")
# ุนู…ู„ ุงู„ู€ RenderRequest
render_req = RenderRequest(
title = req.title,
discount = req.discount or "",
badge = req.badge or "",
phone = req.phone or "",
website = req.website or "",
image_path = req.image_path or "",
music_path = req.music_path or "",
output_path = output,
bg_left = req.bg_left or "",
bg_right = req.bg_right or "",
duration = req.duration or 6,
fps = req.fps or 30,
width = req.width or 1280,
height = req.height or 720,
music_volume = req.music_volume or 0.20,
)
# Render
try:
final_path = render_video(template, render_req)
except Exception as e:
raise HTTPException(status_code=500, detail=f"ุฎุทุฃ ููŠ ุงู„ู€ render: {str(e)}")
size_mb = os.path.getsize(final_path) / 1024 / 1024
return {
"status": "success",
"video_id": video_id,
"download": f"/video/{video_id}",
"size_mb": round(size_mb, 2),
"template": req.template,
}
@app.get("/video/{video_id}")
def download_video(video_id: str):
"""ุญู…ู‘ู„ ุงู„ููŠุฏูŠูˆ"""
path = os.path.join(OUTPUT_DIR, f"{video_id}.mp4")
if not os.path.exists(path):
raise HTTPException(status_code=404, detail="ุงู„ููŠุฏูŠูˆ ู…ุด ู…ูˆุฌูˆุฏ ุฃูˆ ุงุชู…ุณุญ")
return FileResponse(
path,
media_type="video/mp4",
filename=f"showcase_{video_id}.mp4"
)