Spaces:
Sleeping
Sleeping
File size: 3,941 Bytes
9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 4da758a 9583a19 | 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 | import os
import requests
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from faster_whisper import WhisperModel
# --- MUDANÇA CRÍTICA AQUI (Padrão MoviePy 2.0+) ---
# Não existe mais 'moviepy.editor'. Importamos dos módulos específicos.
from moviepy.video.io.ImageClip import ImageClip
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
from moviepy.video.VideoClip import TextClip
# Nota: Em algumas versões v2, o TextClip pode estar em moviepy.video.tools.subtitles
# ou exigir configuração explicita de fonte.
# Inicializa a API
app = FastAPI()
class VideoRequest(BaseModel):
image_url: str
audio_url: str
def download_file(url, filename):
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(filename, 'wb') as f:
for chunk in response.iter_content(1024):
f.write(chunk)
else:
raise Exception(f"Erro ao baixar {url}")
def criar_video_logica(imagem_path, audio_path, output_path):
print("Carregando modelo Whisper...")
model = WhisperModel("tiny", device="cpu", compute_type="int8")
segments, _ = model.transcribe(audio_path, language="pt")
text_clips = []
# Configurações de fonte (Ajustadas para v2)
# Na v2, as vezes é necessário apontar o caminho da fonte se o ImageMagick não achar
font_conf = {
"font_size": 30, # Mudou de fontsize para font_size em algumas builds v2
"color": 'white',
"font": 'Arial', # Garanta que essa fonte exista no Linux ou use "DejaVu-Sans"
"stroke_color": 'black',
"stroke_width": 2,
"method": 'caption',
"size": (800, None)
}
print("Gerando legendas...")
for segment in segments:
# TextClip na v2 pode ter assinatura diferente dependendo da sub-versão (alpha/beta/stable)
# Este é o padrão mais seguro:
txt_clip = TextClip(text=segment.text.strip(), **font_conf)
txt_clip = txt_clip.with_start(segment.start).with_duration(segment.end - segment.start)
# 'set_position' mudou para 'with_position' em muitas partes da v2 para encadear métodos
txt_clip = txt_clip.with_position(('center', 'bottom'))
text_clips.append(txt_clip)
print("Processando Áudio e Imagem...")
audio_clip = AudioFileClip(audio_path)
# set_duration -> with_duration / set_audio -> with_audio
image_clip = ImageClip(imagem_path).with_duration(audio_clip.duration).with_audio(audio_clip)
final = CompositeVideoClip([image_clip] + text_clips)
print("Renderizando vídeo...")
# write_videofile continua similar, mas 'preset' e 'threads' são geridos pelo ffmpeg
final.write_videofile(output_path, fps=10, codec="libx264", audio_codec="aac", preset="ultrafast", threads=2)
return output_path
@app.post("/gerar-video")
async def gerar_video_endpoint(request: VideoRequest):
try:
temp_img = "temp_image.jpg" # Ajustado para jpg pois o Gemini manda jpg
temp_audio = "temp_audio.mp3"
output_video = "video_final.mp4"
print(f"Baixando: {request.image_url}")
download_file(request.image_url, temp_img)
download_file(request.audio_url, temp_audio)
# Se for uma lista de imagens (lógica nova), precisa ajustar aqui.
# Mantendo simples para teste:
criar_video_logica(temp_img, temp_audio, output_video)
return FileResponse(output_video, media_type="video/mp4", filename="video_editado.mp4")
except Exception as e:
print(f"Erro: {e}")
# Retorna o erro na resposta para você ver no Apps Script
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860) |