File size: 3,711 Bytes
c4f0411 837227b 1303dea 2ce54f6 cd0a3ca c4f0411 1303dea e5c3fa4 cd0a3ca c4f0411 1303dea e5c3fa4 1303dea e5c3fa4 1303dea e5c3fa4 2ce54f6 e5c3fa4 2ce54f6 e5c3fa4 2ce54f6 837227b 1303dea 2ce54f6 837227b 2ce54f6 837227b 2ce54f6 837227b 2ce54f6 837227b 1303dea 2ce54f6 1303dea 2ce54f6 1303dea 2ce54f6 1303dea c4f0411 2ce54f6 1303dea |
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 |
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from playwright.async_api import async_playwright
from typing import Optional
import tempfile
import os
app = FastAPI()
# Configura CORS para permitir requisições do frontend
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Em produção, especifique os domínios permitidos
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Modelo para criar posts (gerar imagem a partir de HTML)
class PostRequest(BaseModel):
html: str
width: Optional[int] = 1080 # Largura padrão para posts (Instagram)
height: Optional[int] = 1350 # Altura padrão para posts (Instagram)
@app.get("/")
def greet_json():
return {"Hello": "World!"}
@app.post("/create-post")
async def create_post(request: PostRequest):
"""
Cria uma imagem a partir de HTML para posts.
Recebe HTML e retorna uma imagem PNG.
Exemplo de uso:
{
"html": "<div>Conteúdo do post</div>",
"width": 1080,
"height": 1350
}
"""
html_file = None
try:
# Garantir que o HTML está completo
html_content = request.html
# Se o HTML não tiver estrutura completa, adicionar
if "<!DOCTYPE" not in html_content and "<html" not in html_content:
html_content = f"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
{html_content}
</body>
</html>"""
# Criar arquivo temporário para o HTML
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:
f.write(html_content)
html_file = f.name
try:
# Usar Playwright Async API para renderizar HTML e gerar screenshot
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page(viewport={'width': request.width, 'height': request.height})
# Carrega o HTML do arquivo temporário
await page.goto(f'file://{html_file}')
# Espera o conteúdo carregar (especialmente imagens base64)
await page.wait_for_timeout(2000) # Aguarda 2 segundos para garantir que imagens e fontes carreguem
# Tira screenshot
screenshot_bytes = await page.screenshot(full_page=True, type='png')
await browser.close()
# Remove arquivo temporário
if os.path.exists(html_file):
os.unlink(html_file)
html_file = None
# Retorna a imagem
return Response(
content=screenshot_bytes,
media_type="image/png",
headers={
"Content-Disposition": "attachment; filename=post.png"
}
)
except Exception as e:
# Remove arquivo temporário em caso de erro
if html_file and os.path.exists(html_file):
os.unlink(html_file)
raise e
except Exception as e:
# Garantir limpeza do arquivo temporário
if html_file and os.path.exists(html_file):
try:
os.unlink(html_file)
except:
pass
raise HTTPException(status_code=500, detail=f"Erro ao gerar imagem do post: {str(e)}") |