Spaces:
Sleeping
Sleeping
| 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) --- | |
| 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) |