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)