brat-api / main.py
FarelDeveloper's picture
Update main.py
f46a634 verified
Raw
History Blame Contribute Delete
4.51 kB
from fastapi import FastAPI, Query
from fastapi.responses import FileResponse, JSONResponse
from playwright.async_api import async_playwright
import os, uuid, asyncio, shutil, stat
app = FastAPI(
title="Brat-Api Farel",
description="Free BRAT Image & Video Generator API",
version="1.0.0",
)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def ensure_dir(path: str):
os.makedirs(path, exist_ok=True)
os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
return path
OUTPUT_DIR = ensure_dir(os.path.join(BASE_DIR, "output"))
TMP_DIR = ensure_dir(os.path.join(BASE_DIR, "tmp"))
async def delete_later(path: str, delay: int = 300):
await asyncio.sleep(delay)
if os.path.exists(path):
os.remove(path)
# =========================
# ROOT → index.html
# =========================
@app.get("/")
async def root():
html = os.path.join(BASE_DIR, "index.html")
if not os.path.exists(html):
return JSONResponse(status_code=404, content={"error": "index.html not found"})
return FileResponse(html, media_type="text/html")
# =========================
# BRAT IMAGE (INLINE VIEW)
# =========================
@app.get("/api/brat")
async def brat_image(text: str = Query(...)):
text = text.strip()
if not text:
return JSONResponse(status_code=400, content={"error": "text is required"})
filepath = os.path.join(OUTPUT_DIR, f"brat-{uuid.uuid4().hex}.png")
async with async_playwright() as p:
browser = await p.chromium.launch(args=["--no-sandbox"])
page = await (await browser.new_context(
viewport={"width": 1536, "height": 695}
)).new_page()
await page.goto("https://www.bratgenerator.com/", wait_until="domcontentloaded")
try:
await page.click("text=Accept", timeout=3000)
except:
pass
await page.click("#toggleButtonWhite")
await page.click("#textOverlay")
await page.fill("#textInput", text)
await asyncio.sleep(0.4)
el = await page.query_selector("#textOverlay")
box = await el.bounding_box()
img = await page.screenshot(
clip={"x": box["x"], "y": box["y"], "width": 500, "height": 440}
)
with open(filepath, "wb") as f:
f.write(img)
await browser.close()
asyncio.create_task(delete_later(filepath))
# ⬅️ INLINE (preview di browser)
return FileResponse(filepath, media_type="image/png")
# =========================
# BRAT VIDEO (INLINE VIEW)
# =========================
@app.get("/api/bratvid")
async def brat_video(text: str = Query(...)):
text = text.strip()
if not text:
return JSONResponse(status_code=400, content={"error": "text is required"})
words = text.split()
temp_dir = ensure_dir(os.path.join(TMP_DIR, uuid.uuid4().hex))
async with async_playwright() as p:
browser = await p.chromium.launch(args=["--no-sandbox"])
page = await (await browser.new_context(
viewport={"width": 1536, "height": 695}
)).new_page()
await page.goto("https://www.bratgenerator.com/", wait_until="domcontentloaded")
try:
await page.click("text=Accept", timeout=3000)
except:
pass
await page.click("#toggleButtonWhite")
await page.click("#textOverlay")
for i in range(len(words)):
await page.fill("#textInput", " ".join(words[:i+1]))
await asyncio.sleep(0.2)
el = await page.query_selector("#textOverlay")
box = await el.bounding_box()
img = await page.screenshot(
clip={"x": box["x"], "y": box["y"], "width": 500, "height": 440}
)
with open(os.path.join(temp_dir, f"frame{i:03d}.png"), "wb") as f:
f.write(img)
await browser.close()
output = os.path.join(OUTPUT_DIR, f"bratvid-{uuid.uuid4().hex}.mp4")
await asyncio.create_subprocess_exec(
"ffmpeg", "-y",
"-framerate", "1.4",
"-i", os.path.join(temp_dir, "frame%03d.png"),
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,fps=30",
"-pix_fmt", "yuv420p",
output,
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL
)
shutil.rmtree(temp_dir, ignore_errors=True)
asyncio.create_task(delete_later(output))
# ⬅️ INLINE VIDEO (play langsung)
return FileResponse(output, media_type="video/mp4")