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 from moviepy.editor import ImageClip, AudioFileClip, TextClip, CompositeVideoClip # Inicializa a API app = FastAPI() # Modelo de dados que esperamos receber do GAS class VideoRequest(BaseModel): image_url: str audio_url: str # --- Funções Auxiliares --- def download_file(url, filename): """Baixa o arquivo da URL e salva localmente""" 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): """A lógica de edição (Whisper + MoviePy)""" print("Carregando modelo Whisper...") model = WhisperModel("tiny", device="cpu", compute_type="int8") segments, _ = model.transcribe(audio_path, language="pt") text_clips = [] # Configuração visual da legenda font_settings = { "fontsize": 30, "color": 'white', "font": 'Arial-Bold', "stroke_color": 'black', "stroke_width": 2, "method": 'caption', "size": (800, None) } print("Gerando legendas...") for segment in segments: txt_clip = TextClip(segment.text.strip(), **font_settings) txt_clip = txt_clip.set_start(segment.start).set_duration(segment.end - segment.start) txt_clip = txt_clip.set_position(('center', 'bottom')) text_clips.append(txt_clip) audio_clip = AudioFileClip(audio_path) image_clip = ImageClip(imagem_path).set_duration(audio_clip.duration).set_audio(audio_clip) final = CompositeVideoClip([image_clip] + text_clips) print("Renderizando vídeo...") final.write_videofile(output_path, fps=10, codec="libx264", audio_codec="aac", preset="ultrafast", threads=2) return output_path # --- O Endpoint da API (Onde o GAS conecta) --- @app.post("/gerar-video") async def gerar_video_endpoint(request: VideoRequest): try: # 1. Definir caminhos temporários temp_img = "temp_image.png" temp_audio = "temp_audio.mp3" output_video = "video_final.mp4" # 2. Baixar os assets que o GAS mandou os links print(f"Baixando imagem de: {request.image_url}") download_file(request.image_url, temp_img) print(f"Baixando áudio de: {request.audio_url}") download_file(request.audio_url, temp_audio) # 3. Rodar a mágica criar_video_logica(temp_img, temp_audio, output_video) # 4. Devolver o arquivo pronto para o GAS # O FileResponse envia o arquivo binário na resposta HTTP return FileResponse(output_video, media_type="video/mp4", filename="video_editado.mp4") except Exception as e: print(f"Erro: {e}") raise HTTPException(status_code=500, detail=str(e)) # Configuração para rodar no Hugging Face if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=7860)