DHEIVER's picture
Update app.py
c58d9bb verified
import gradio as gr
from moviepy.editor import VideoFileClip, concatenate_videoclips
import numpy as np
from scipy.io import wavfile
import tempfile
import os
from pathlib import Path
def detect_silence(audio_array, sample_rate, threshold=0.01, min_silence_len=1000):
"""Detecta períodos de silêncio no áudio"""
# Converte o threshold para amplitude
amplitude_threshold = threshold * np.max(np.abs(audio_array))
# Calcula a energia do áudio
energy = np.abs(audio_array)
if len(energy.shape) > 1:
energy = np.mean(energy, axis=1)
# Encontra regiões não silenciosas
is_sound = energy > amplitude_threshold
# Converte frames para segundos
frame_length = int(sample_rate * (min_silence_len / 1000))
# Suaviza a detecção para evitar cortes muito curtos
sound_chunks = []
start = None
for i in range(len(is_sound)):
if start is None and is_sound[i]:
start = i
elif start is not None and not is_sound[i]:
if i - start > frame_length:
sound_chunks.append((start / sample_rate, i / sample_rate))
start = None
if start is not None:
sound_chunks.append((start / sample_rate, len(is_sound) / sample_rate))
return sound_chunks
def process_video(video_path, threshold=0.01, min_silence_len=1000):
"""Remove silêncio do vídeo"""
# Carrega o vídeo
video = VideoFileClip(video_path)
# Extrai o áudio para análise
audio_array = video.audio.to_soundarray()
sample_rate = video.audio.fps
# Detecta regiões não silenciosas
sound_chunks = detect_silence(audio_array, sample_rate, threshold, min_silence_len)
if not sound_chunks:
video.close()
return video_path
# Corta e concatena os segmentos não silenciosos
clips = []
for start, end in sound_chunks:
clip = video.subclip(start, end)
clips.append(clip)
# Concatena os clips
final_clip = concatenate_videoclips(clips)
# Salva o resultado
output_path = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
final_clip.write_videofile(output_path)
# Limpa os recursos
video.close()
final_clip.close()
for clip in clips:
clip.close()
return output_path
def remove_silence(video_input, silence_duration, silence_threshold):
"""Interface para remoção normal de silêncio"""
try:
if video_input is None:
raise ValueError("Por favor, faça upload de um vídeo")
# Converte o threshold de dB para amplitude relativa
amplitude_threshold = 10 ** (silence_threshold / 20)
return process_video(
video_input,
threshold=amplitude_threshold,
min_silence_len=int(silence_duration * 1000)
)
except Exception as e:
gr.Error(str(e))
return None
def remove_max_silence(video_input):
"""Interface para remoção máxima de silêncio"""
try:
if video_input is None:
raise ValueError("Por favor, faça upload de um vídeo")
# Configurações agressivas para máxima remoção
return process_video(
video_input,
threshold=0.05, # Mais sensível ao som
min_silence_len=100 # Remove silêncios mais curtos
)
except Exception as e:
gr.Error(str(e))
return None
# Interface Gradio
with gr.Blocks(title="Removedor de Silêncio de Vídeos") as app:
gr.Markdown("# Removedor de Silêncio de Vídeos")
with gr.Row():
with gr.Column():
video_input = gr.Video(
label="Selecione ou Arraste o Vídeo"
)
with gr.Row():
remove_max_btn = gr.Button("🔇 Remover 100% do Silêncio", variant="primary")
remove_custom_btn = gr.Button("Remover Silêncio Personalizado")
with gr.Group():
gr.Markdown("### Configurações Personalizadas")
silence_duration = gr.Slider(
minimum=0.1,
maximum=5.0,
value=1.0,
step=0.1,
label="Duração Mínima do Silêncio (segundos)"
)
silence_threshold = gr.Slider(
minimum=-60,
maximum=-20,
value=-40,
step=1,
label="Limite de Silêncio (dB)"
)
with gr.Row():
video_output = gr.Video(label="Vídeo Processado")
# Event handlers
remove_max_btn.click(
fn=remove_max_silence,
inputs=[video_input],
outputs=[video_output]
)
remove_custom_btn.click(
fn=remove_silence,
inputs=[
video_input,
silence_duration,
silence_threshold
],
outputs=[video_output]
)
if __name__ == "__main__":
app.launch(show_error=True)