File size: 4,487 Bytes
8f7c473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""
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"
    )