| """ |
| 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) |
|
|
|
|
| |
| |
| |
| 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 |
|
|
|
|
| |
| |
| |
|
|
| @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)) |
|
|
| |
| video_id = str(uuid.uuid4())[:8] |
| output = os.path.join(OUTPUT_DIR, f"{video_id}.mp4") |
|
|
| |
| 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, |
| ) |
|
|
| |
| 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" |
| ) |
|
|