AlexandreScriptsMT commited on
Commit
8a6b746
·
verified ·
1 Parent(s): 52618fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -135
app.py CHANGED
@@ -1,145 +1,63 @@
1
  import gradio as gr
2
- import json
3
- import base64
4
- import tempfile
5
  import os
6
- import wave
7
- from moviepy import *
8
- from moviepy.video.fx import FadeIn, FadeOut
9
-
10
- # Configurações de áudio padrão
11
- SAMPLE_RATE = 24000
12
- NUM_CHANNELS = 1
13
- SAMPWIDTH = 2
14
-
15
- def pcm_to_wav(pcm_base64, output_path):
16
- """Converte PCM Base64 para WAV."""
17
- try:
18
- pcm_bytes = base64.b64decode(pcm_base64)
19
- with wave.open(output_path, 'wb') as wav_file:
20
- wav_file.setnchannels(NUM_CHANNELS)
21
- wav_file.setsampwidth(SAMPWIDTH)
22
- wav_file.setframerate(SAMPLE_RATE)
23
- wav_file.writeframes(pcm_bytes)
24
- return True
25
- except Exception as e:
26
- print(f"Erro Audio: {e}")
27
- return False
28
-
29
- def base64_to_image(image_base64, output_path):
30
- """Salva imagem Base64 em arquivo."""
31
- try:
32
- with open(output_path, "wb") as f:
33
- f.write(base64.b64decode(image_base64))
34
- return True
35
- except Exception as e:
36
- print(f"Erro Imagem: {e}")
37
- return False
38
-
39
- def generate_video(project_json):
40
- print("--- INICIANDO RENDERIZAÇÃO (V2 - BLOCKS) ---")
41
 
42
- # Criar pasta temporária para processamento
43
- temp_dir_obj = tempfile.TemporaryDirectory()
44
- temp_dir = temp_dir_obj.name
45
-
46
- try:
47
- # Tratamento do input JSON
48
- if isinstance(project_json, str):
49
- try:
50
- data = json.loads(project_json)
51
- except:
52
- raise gr.Error("Erro: O texto fornecido não é um JSON válido.")
53
- else:
54
- data = project_json
55
-
56
- scenes_data = data.get("scenes", [])
57
- if not scenes_data:
58
- raise gr.Error("O JSON não contém a lista de cenas ('scenes').")
59
-
60
- clips = []
61
- scenes_data.sort(key=lambda x: x.get("id", 0))
62
-
63
- for i, scene in enumerate(scenes_data):
64
- print(f"Processando cena {i}...")
65
-
66
- img_path = os.path.join(temp_dir, f"scene_{i}.jpg")
67
- audio_path = os.path.join(temp_dir, f"scene_{i}.wav")
68
-
69
- img_b64 = scene.get("image_data_base64")
70
- audio_b64 = scene.get("audio_data_base64")
71
-
72
- if not img_b64 or not audio_b64:
73
- print(f"Pulando cena {i}: Falta audio ou imagem.")
74
- continue
75
 
76
- if not base64_to_image(img_b64, img_path): continue
77
- if not pcm_to_wav(audio_b64, audio_path): continue
78
-
79
- try:
80
- # --- SINTAXE MOVIEPY 2.0 ---
81
- audio_clip = AudioFileClip(audio_path)
82
-
83
- # Definir duração da imagem = audio + 0.1s
84
- duration = audio_clip.duration + 0.1
85
- video_clip = ImageClip(img_path).with_duration(duration)
86
-
87
- # Juntar Audio
88
- video_clip = video_clip.with_audio(audio_clip)
89
-
90
- # Aplicar Fade In
91
- video_clip = video_clip.with_effects([FadeIn(duration=0.5)])
92
-
93
- clips.append(video_clip)
94
-
95
- except Exception as e_clip:
96
- print(f"Erro na montagem do clipe {i}: {e_clip}")
97
 
98
- if not clips:
99
- raise gr.Error("Nenhum clipe foi gerado. Verifique os dados Base64.")
100
-
101
- print(f"Concatenando {len(clips)} cenas...")
102
-
103
- final_video = concatenate_videoclips(clips, method="compose")
104
-
105
- output_path = os.path.join(temp_dir, "output_final.mp4")
 
 
 
 
106
 
107
- final_video.write_videofile(
108
- output_path,
109
- fps=24,
110
- codec="libx264",
111
- audio_codec="aac",
112
- preset="ultrafast",
113
- logger=None
114
- )
115
 
116
- print("Vídeo gerado com sucesso!")
117
  return output_path
118
-
119
- except Exception as e:
120
- error_msg = f"Erro fatal no backend: {str(e)}"
121
- print(error_msg)
122
- raise gr.Error(error_msg)
123
-
124
- # --- AQUI ESTA A MUDANÇA ---
125
- # Usamos Blocks para ter controle total sobre o nome da API
126
- with gr.Blocks(title="Renderizador AI V2") as demo:
127
- gr.Markdown("# Renderizador AI Backend")
128
-
129
- with gr.Row():
130
- input_component = gr.JSON(label="JSON do Projeto")
131
- output_component = gr.Video(label="Vídeo Final")
132
-
133
- btn = gr.Button("Renderizar", variant="primary")
134
-
135
- # O parametro api_name="predict" ABAIXO é o segredo.
136
- # Ele obriga o Gradio a expor a rota /predict que seu App procura.
137
- btn.click(
138
- fn=generate_video,
139
- inputs=input_component,
140
- outputs=output_component,
141
- api_name="predict"
142
- )
143
 
144
  if __name__ == "__main__":
145
- demo.launch()
 
 
 
 
 
 
 
1
  import gradio as gr
 
 
 
2
  import os
3
+ import subprocess
4
+
5
+ def convert_webm_to_mp4(video_file):
6
+ """
7
+ Função simples que recebe um caminho de arquivo de vídeo,
8
+ converte para MP4 usando FFmpeg e retorna o novo caminho.
9
+ """
10
+ print(f"Recebido arquivo: {video_file}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ if video_file is None:
13
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # Define nomes de arquivo
16
+ input_path = video_file
17
+ # Cria um nome de saída garantindo a extensão .mp4
18
+ output_path = os.path.splitext(input_path)[0] + "_converted.mp4"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ try:
21
+ # Comando FFmpeg otimizado para velocidade (ultrafast) e compatibilidade (libx264)
22
+ # O flag -y sobrescreve se o arquivo já existir
23
+ command = [
24
+ "ffmpeg", "-y",
25
+ "-i", input_path,
26
+ "-c:v", "libx264",
27
+ "-preset", "ultrafast", # Converte rápido para não dar timeout
28
+ "-crf", "23", # Qualidade balanceada
29
+ "-c:a", "aac", # Audio padrão MP4
30
+ output_path
31
+ ]
32
 
33
+ print(f"Executando FFmpeg: {' '.join(command)}")
34
+ subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
 
 
 
 
 
35
 
36
+ print(f"Conversão concluída: {output_path}")
37
  return output_path
38
+
39
+ except subprocess.CalledProcessError as e:
40
+ print(f"Erro no FFmpeg: {e}")
41
+ return None
42
+ except Exception as ex:
43
+ print(f"Erro geral: {ex}")
44
+ return None
45
+
46
+ # Interface simples: Entrada de Vídeo -> Saída de Vídeo
47
+ # allow_flagging="never" remove botões desnecessários que podem causar erros
48
+ iface = gr.Interface(
49
+ fn=convert_webm_to_mp4,
50
+ inputs=gr.Video(label="Input WebM"),
51
+ outputs=gr.Video(label="Output MP4"),
52
+ allow_flagging="never",
53
+ title="API Conversor WebM para MP4"
54
+ )
 
 
 
 
 
 
 
 
55
 
56
  if __name__ == "__main__":
57
+ # O SEGREDO DO SUCESSO: cors_allowed_origins=["*"]
58
+ # Isso permite que o Preview do nosso editor envie arquivos para seu servidor.
59
+ iface.launch(
60
+ server_name="0.0.0.0",
61
+ server_port=7860,
62
+ cors_allowed_origins=["*"]
63
+ )