Desenvolvimento de um pipeline local de dublagem automática de vídeos…
INEMA
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_1
Perfeito — dá para criar um history_prompt (.npz) a partir de uma gravação curta e usar no seu dublar.py com o Bark. Abaixo está o passo a passo objetivo, com comandos e exemplos.
Resumo rápido⌗
- Grave 8–12s de voz limpa.
- Converta para 24 kHz mono e corte silêncios.
- Rode localmente uma UI de clonagem do Bark (gradio) para gerar o arquivo .npz. (GitHub)
- Use esse .npz no seu script com a flag
--voice. - Ajuste temperatura e pós-processo se necessário.
Obs.: a API do Bark aceita
history_promptapontando para um .npz ou para um preset como v2/pt_speaker_6. (Coqui Docs, Replicate)
Passo a passo local para gerar o .npz⌗
- Prepare a gravação (8–12s, sem ruído, sem música).
ffmpeg -y -i minha_voz_original.wav -ac 1 -ar 24000 -vn -af silenceremove=1:0:-35dB minha_voz_24k.wav
- Crie um ambiente separado (para evitar conflitos).
conda create -n bark-clone python=3.10 -y
conda activate bark-clone
pip install --index-url https://download.pytorch.org/whl/cpu torch==2.5.1
- Baixe e rode uma UI de clonagem do Bark (com Gradio).
git clone https://github.com/KevinWang676/Bark-Voice-Cloning
cd Bark-Voice-Cloning
pip install -r requirements.txt
python app.py
A UI abre no navegador. Faça:
- Upload de
minha_voz_24k.wav - Clique em Create Voice
- Escolha Voice = file (para usar a voz clonada)
- Exporte/salve o arquivo gerado
speaker.npz(o history_prompt) Esses passos estão descritos no próprio repositório da UI. (GitHub)
- Use o .npz no seu dublar.py
conda activate voz-bark
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice C:\caminho\para\speaker.npz
A aceitação de history_prompt pelo Bark é parte da API pública. (Coqui Docs)
Alternativas e observações⌗
- Se você não quiser clonar, use presets prontos do Bark como
v2/pt_speaker_0..6:
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_6
- Projetos comunitários também permitem gerar npz via HuBERT-quantizer; são úteis, mas podem exigir mais setups e variar entre versões. (GitHub, Hugging Face)
Dicas de qualidade⌗
- Grave perto do microfone, ambiente silencioso, sem música.
- Use 8–12s com fala natural e variação leve de prosódia.
- No Bark, comece com
text_temp=0.6ewaveform_temp=0.6; combine com seu pós-processo (loudnorm/denoise/EQ) que você já tem no dublar.py. - Se a voz sair metálica, reduza ainda mais as temperaturas e verifique o áudio de referência.
Perguntas rápidas com respostas⌗
-
Posso escolher masculino/feminino? Sim, indiretamente. Com
history_promptvocê define o timbre. Presets comov2/pt_speaker_6tendem a soar femininos; com o seu .npz, o timbre segue a gravação. -
Posso fazer tudo offline? Sim. O fluxo acima roda local. O Bark aceita um .npz local como
history_prompt. (Coqui Docs) -
Dá para usar outra ferramenta se o Bark for complicado? Sim. Coqui TTS/XTTS aceita
speaker_wave é mais direto para clonagem; mas como você pediu Bark, mantive o processo específico.
Se quiser, eu te mando um mini-script que gera automaticamente vários testes com a sua voz clonada (.npz) lendo 2–3 frases típicas, salvando os .wav lado a lado para você comparar rapidamente.
boa 👌 — no Bark você não “escolhe” masculino ou feminino como num menu, ele define a voz de acordo com o history_prompt que você passa.
como a voz é definida⌗
- sem
history_prompt→ o Bark gera uma voz aleatória (pode variar de tom e gênero entre execuções). - com
history_promptpronto (preset) → você escolhe um arquivo ou nome que já representa uma voz específica (ex.:v2/pt_speaker_6costuma soar feminino em PT-BR). - com
history_promptcriado de uma gravação → você clona o estilo de uma voz real (pode ser sua própria voz).
exemplos práticos no seu script⌗
```# voz aleatória (padrão do Bark) python dublar.py --in video.mp4 --src en --tgt pt --tts bark
força uma voz feminina pré-treinada⌗
python dublar.py --in video.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_6
força uma voz masculina pré-treinada⌗
python dublar.py --in video.mp4 --src en --tgt pt --tts bark --voice v2/en_speaker_1
clona uma voz a partir de um history que você mesmo criou⌗
python dublar.py --in video.mp4 --src en --tgt pt --tts bark --voice minha_voz.npz```
ou seja:
- se você quer só masculino/feminino, usa um preset pronto do Bark.
- se quer a voz de alguém específico, precisa criar o
history_prompta partir de uma amostra de áudio.
quer que eu te mostre o passo a passo de como gerar o seu próprio history_prompt npz a partir de uma gravação curta?
boa! vamos esclarecer:
🌱 o que é o history no Bark⌗
- o Bark (da Suno) não é só um TTS simples; ele gera voz, entonação e até efeitos (respiração, risada etc).
- para manter consistência de voz entre várias frases, ele usa algo chamado history prompt.
- o history é um arquivo
.npz(um pacote de embeddings) que guarda informações sobre timbre, tom e estilo de uma voz.
🔊 como funciona⌗
- sem history → cada segmento de texto pode sair com uma voz ligeiramente diferente (mais robótico/aleatório).
- com history → você carrega um arquivo ou preset (
v2/pt_speaker_6, por exemplo), e o Bark mantém a mesma voz durante todo o áudio. - se você tiver uma gravação curta de uma pessoa, pode gerar o history a partir dela → isso se aproxima de clonagem de voz.
🧩 exemplos de uso no script⌗
```# voz padrão (sem history) python dublar.py --in nei.mp4 --src en --tgt pt --tts bark
voz consistente usando um preset pronto do Bark⌗
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_6
clonagem: se você tiver seu próprio arquivo npz (treinado)⌗
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice minha_voz.npz```
✅ vantagens⌗
- mantém mesma voz do início ao fim do vídeo.
- pode dar “personalidade” à dublagem.
- permite (se você preparar os npz) aproximar a voz do original (masculina ou feminina).
quer que eu te mostre como criar o seu próprio history_prompt npz a partir de uma gravação curta da sua voz?
dest="inp", required=True, help="vídeo de entrada, ex: video.mp4") ap.add_argument("--out", dest="out", default="video_dublado.mp4", help="arquivo MP4 de saída") ap.add_argument("--src", required=True, help="idioma origem, ex: en") ap.add_argument("--tgt", required=True, help="idioma destino, ex: pt") ap.add_argument("--tts", choices=["bark", "coqui"], default="bark", help="motor TTS") ap.add_argument("--voice", default=None, help="bark: history_prompt (.npz ou preset). coqui: nome do speaker (quando suportado).") ap.add_argument("--rate", type=int, default=24000, help="sample rate final (Hz)") ap.add_argument("--bitrate", default="192k", help="bitrate AAC, ex: 192k") args = ap.parse_args()
ensure_ffmpeg()
workdir = Path("dub_work")
workdir.mkdir(exist_ok=True)
video_in = Path(args.inp).resolve()
if not video_in.exists():
print("Arquivo de entrada não encontrado:", video_in)
sys.exit(1)
# 2) extrair áudio
audio_src = Path(workdir, "audio_src.wav")
sh(["ffmpeg", "-y", "-i", str(video_in), "-vn", "-ac", "1", "-ar", "48000", "-c:a", "pcm_s16le", str(audio_src)])
# 3) transcrever
asr_json, asr_srt, segs = transcribe_faster_whisper(audio_src, workdir, args.src)
# 4) traduzir
segs_trad, trad_json, trad_srt = translate_segments_m2m100(segs, args.src, args.tgt, workdir)
# 5/6) TTS
if args.tts == "bark":
seg_files, sr_segs = tts_bark(segs_trad, workdir, text_temp=0.6, wave_temp=0.6, history_prompt=args.voice)
else:
seg_files, sr_segs = tts_coqui(segs_trad, workdir, args.tgt, speaker=args.voice)
# 7) concatenar
dub_raw = concat_segments(seg_files, workdir, sr_segs)
# 8) pós-processo
dub_final = postprocess_audio(dub_raw, workdir, args.rate)
# 9) mux no vídeo
out_mp4 = Path(args.out)
mux_video(video_in, dub_final, out_mp4, args.bitrate)
# 10) logs
logs = {
"input_video": str(video_in),
"output_video": str(out_mp4),
"asr_json": str(asr_json),
"asr_srt": str(asr_srt),
"trad_json": str(trad_json),
"trad_srt": str(trad_srt),
"samples_dir": str(workdir),
"tts": args.tts,
"src": args.src,
"tgt": args.tgt,
"voice": args.voice
}
with open(Path(workdir, "logs.json"), "w", encoding="utf-8") as f:
json.dump(logs, f, ensure_ascii=False, indent=2)
print("\nConcluído.")
print("Saídas principais:")
print(" -", out_mp4)
print(" -", trad_srt)
print(" -", Path(workdir, "logs.json"))
print("Intermediários em:", workdir)
if name == "main": main()
exemplos rápidos
- bark padrão: python dublar.py --in nei.mp4 --src en --tgt pt --tts bark
- bark com history prompt: python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_6
- coqui com speaker: python dublar.py --in nei.mp4 --src en --tgt pt --tts coqui --voice female-pt-4
se quiser, adiciono depois a opção de gerar duas faixas no mesmo vídeo (original + dublada).
import write history = None if history_prompt: try: from bark.generation import load_history_prompt history = load_history_prompt(history_prompt) except Exception: history = history_prompt # se for um preset string seg_files = [] tsv = Path(workdir, "segments.csv") with open(tsv, "w", encoding="utf-8", newline="") as fcsv: w = csv.writer(fcsv) w.writerow(["t_in", "t_out", "texto_trad", "file"]) for i, s in enumerate(segments, 1): txt = s.get("text_trad", "") out = Path(workdir, f"seg_{i:04d}.wav") if not txt.strip(): dur = max(0.05, s["end"] - s["start"]) sh(["ffmpeg", "-y", "-f", "lavfi", "-i", f"anullsrc=r={SAMPLE_RATE}:cl=mono", "-t", f"{dur:.3f}", out.name], cwd=workdir) else: audio = generate_audio(txt, text_temp=text_temp, waveform_temp=wave_temp, history_prompt=history) write(out, SAMPLE_RATE, audio) seg_files.append(out) w.writerow([s["start"], s["end"], txt, out.name]) return seg_files, 24000 # SAMPLE_RATE
def tts_coqui(segments, workdir, tgt_lang, speaker=None): from TTS.api import TTS # modelos single-speaker por padrão lang = (tgt_lang or "en").lower() if lang in ("pt", "pt-br", "pt_pt"): model_name = "tts_models/pt/cv/vits" sample_rate = 22050 elif lang in ("en", "en-us", "en-gb"): model_name = "tts_models/en/ljspeech/tacotron2-DDC" sample_rate = 22050 else: model_name = "tts_models/en/ljspeech/tacotron2-DDC" sample_rate = 22050
tts = TTS(model_name, gpu=False)
seg_files = []
from scipy.io.wavfile import write
tsv = Path(workdir, "segments.csv")
with open(tsv, "w", encoding="utf-8", newline="") as fcsv:
w = csv.writer(fcsv)
w.writerow(["t_in", "t_out", "texto_trad", "file"])
for i, s in enumerate(segments, 1):
txt = s.get("text_trad", "")
out = Path(workdir, f"seg_{i:04d}.wav")
if not txt.strip():
dur = max(0.05, s["end"] - s["start"])
sh(["ffmpeg", "-y", "-f", "lavfi", "-i", f"anullsrc=r={sample_rate}:cl=mono", "-t", f"{dur:.3f}", out.name], cwd=workdir)
else:
if speaker:
try:
tts.tts_to_file(text=txt, file_path=str(out), speaker=speaker, language=tgt_lang)
except Exception:
tts.tts_to_file(text=txt, file_path=str(out))
else:
tts.tts_to_file(text=txt, file_path=str(out))
seg_files.append(out)
w.writerow([s["start"], s["end"], txt, out.name])
return seg_files, sample_rate
def concat_segments(seg_files, workdir, samplerate): # grava apenas os nomes; executa ffmpeg dentro de workdir lst = Path(workdir, "list.txt") with open(lst, "w", encoding="utf-8") as f: for p in seg_files: f.write(f"file '{p.name}'\n") out = Path(workdir, "dub_raw.wav") sh([ "ffmpeg","-y", "-f","concat","-safe","0", "-i", lst.name, "-c:a","pcm_s16le", "-ar",str(samplerate),"-ac","1", out.name ], cwd=workdir) return out
def postprocess_audio(wav_in, workdir, samplerate): out = Path(workdir, "dub_final.wav") filters = "loudnorm=I=-16:TP=-1.5:LRA=11,afftdn=nf=-25,equalizer=f=6500:t=h:width=2000:g=-4" sh(["ffmpeg", "-y", "-i", wav_in.name, "-af", filters, "-ar", str(samplerate), "-ac", "1", out.name], cwd=workdir) return out
def mux_video(video_in, wav_in, out_mp4, bitrate): sh([ "ffmpeg", "-y", "-i", str(video_in), "-i", str(wav_in), "-map", "0:v:0", "-map", "1:a:0", "-c:v", "copy", "-c:a", "aac", "-b:a", bitrate, str(out_mp4) ])
def main(): ap = argparse.ArgumentParser(description="Dublagem local com Whisper + M2M100 + Bark/Coqui") ap.add_argument("--in",
perfeito. segue o dublar.py revisado, já com:
- correção do list.txt e concatenação (sem caminho duplicado)
-
opção de voz via parâmetro --voice
-
coqui: passa speaker quando suportado
- bark: aceita history_prompt (caminho .npz ou preset)
- tradução direto com m2m100
- função sh com suporte a cwd
uso rápido: python dublar.py --in nei.mp4 --src en --tgt pt --tts bark python dublar.py --in nei.mp4 --src en --tgt pt --tts bark --voice v2/pt_speaker_6 python dublar.py --in nei.mp4 --src en --tgt pt --tts coqui --voice female-pt-4
código completo:
## dublar.py
## Pipeline local de dublagem:
## 1) extrai áudio do vídeo
## 2) transcreve (faster-whisper)
## 3) traduz (facebook/m2m100_418M)
## 4) sintetiza TTS por segmento (bark ou coqui)
## 5) concatena, pós-processa e faz mux com o vídeo original
import os, sys, json, csv, argparse, subprocess, shutil
from pathlib import Path
def sh(cmd, cwd=None):
print(">>", " ".join(map(str, cmd)))
subprocess.run(cmd, check=True, cwd=cwd)
def ensure_ffmpeg():
if not shutil.which("ffmpeg"):
print("ffmpeg não encontrado no PATH.")
sys.exit(1)
def ts_stamp(t):
h = int(t // 3600)
m = int((t % 3600) // 60)
s = t % 60
return f"{h:02d}:{m:02d}:{s:06.3f}".replace(".", ",")
def transcribe_faster_whisper(wav_path, workdir, src_lang):
from faster_whisper import WhisperModel
model = WhisperModel("medium", device="auto")
segments, info = model.transcribe(str(wav_path), language=src_lang, vad_filter=True)
segs = []
for s in segments:
segs.append({
"start": float(s.start),
"end": float(s.end),
"text": (s.text or "").strip()
})
srt_path = Path(workdir, "asr.srt")
json_path = Path(workdir, "asr.json")
with open(srt_path, "w", encoding="utf-8") as f:
for i, s in enumerate(segs, 1):
f.write(f"{i}\n{ts_stamp(s['start'])} --> {ts_stamp(s['end'])}\n{s['text']}\n\n")
with open(json_path, "w", encoding="utf-8") as f:
json.dump({"language": src_lang, "segments": segs}, f, ensure_ascii=False, indent=2)
return json_path, srt_path, segs
def translate_segments_m2m100(segs, src, tgt, workdir):
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
model_name = "facebook/m2m100_418M"
tok = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
src = (src or "en").lower()
tgt = (tgt or "pt").lower()
if hasattr(tok, "lang_code_to_id"):
if src not in tok.lang_code_to_id: src = "en"
if tgt not in tok.lang_code_to_id: tgt = "pt"
out, batch, idxs = [], [], []
max_batch = 8
def flush():
nonlocal out, batch, idxs
if not batch:
return
tok.src_lang = src
enc = tok(batch, return_tensors="pt", padding=True, truncation=True)
gen = model.generate(
enc,
forced_bos_token_id=tok.get_lang_id(tgt),
max_new_tokens=200
)
texts = tok.batch_decode(gen, skip_special_tokens=True)
for j, txt in enumerate(texts):
i = idxs[j]
item = dict(segs[i])
item["text_trad"] = txt.strip()
out.append(item)
batch.clear()
idxs.clear()
for i, s in enumerate(segs):
batch.append(s.get("text", ""))
idxs.append(i)
if len(batch) >= max_batch:
flush()
flush()
srt_t = Path(workdir, "asr_trad.srt")
json_t = Path(workdir, "asr_trad.json")
with open(srt_t, "w", encoding="utf-8") as f:
for i, s in enumerate(out, 1):
f.write(f"{i}\n{ts_stamp(s['start'])} --> {ts_stamp(s['end'])}\n{s['text_trad']}\n\n")
with open(json_t, "w", encoding="utf-8") as f:
json.dump({"language": tgt, "segments": out}, f, ensure_ascii=False, indent=2)
return out, json_t, srt_t
def tts_bark(segments, workdir, text_temp=0.6, wave_temp=0.6, history_prompt=None):
from bark import generate_audio, SAMPLE_RATE
from scipy.io.wavfile import
boa pergunta 👌
no modelo atual que montamos (`dublar.py`), a **voz do destino não depende da voz da origem**. funciona assim:
* **Bark**
* Ele consegue gerar vozes realistas, mas no nosso script usamos a versão **default**, sem clonagem da voz original.
* Resultado: sempre sai uma voz neutra, sem preservar tom, gênero ou estilo da origem.
* Bark tem suporte a “history prompts” (amostras de voz), que poderiam clonar estilo/entonação, mas isso não ativamos.
* **Coqui TTS**
* O modelo que usamos (`vits` ou `tacotron2`) também é **voz fixa** (uma locutora ou um locutor).
* Existem modelos multi-speaker (que aceitam `speaker_wav` para copiar o timbre), mas não foram configurados aqui.
---
## 🔎 Em resumo
* **Hoje:** o script sempre gera **uma voz padrão** (masculina ou feminina, dependendo do modelo escolhido).
* **Não preserva** automaticamente se a fala original era de homem ou mulher.
* Para preservar, precisaríamos:
1. Detectar o **gênero/estilo** na transcrição (via análise de áudio original).
2. Mapear para um **speaker correspondente** no TTS.
3. (Opcional) Usar clonagem de voz via `speaker_wav` (Coqui) ou `history_prompt` (Bark).
---
quer que eu ajuste o `dublar.py` para já ter um **parâmetro `--voice`** (ex.: `male` ou `female`) e forçar a saída com esse tipo de voz?
aqui vai o resumo final do projeto, dividido em três blocos: propósito, instalação e execução, com considerações no fim.
---
## 🎯 Propósito
O objetivo foi criar uma **ferramenta local de dublagem automática** que:
1. Extrai o áudio de um vídeo.
2. Transcreve o conteúdo (faster-whisper).
3. Traduz para outro idioma (facebook/m2m100\_418M).
4. Gera voz sintética (Bark ou Coqui).
5. Substitui o áudio original pelo novo, mantendo o vídeo.
Assim, você pode entregar um **vídeo dublado em outro idioma** de forma totalmente offline/open-source.
---
## ⚙️ Instalação
1. Criar ambiente isolado:
``` conda create -n voz-bark python=3.11 -y
conda activate voz-bark
```
2. Instalar PyTorch estável (compatível com Bark):
* CPU:
``` pip install --index-url https://download.pytorch.org/whl/cpu torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1
``` * GPU (CUDA 12.4):
``` pip install --index-url https://download.pytorch.org/whl/cu124 torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1
```3. Instalar pacotes do pipeline:
```pip install transformers==4.41.2 sentencepiece sacremoses scipy
pip install faster-whisper bark==0.1.5
4```. Checar ffmpeg no PATH (necessário).
---
## ▶️ Execução
Rodar o script de dublagem (dublar.py):
pyth```on dublar.py --in meu_video.mp4 --src en --tgt pt --tts bark
Pa```râmetros principais:
* --in `→ ví`deo de entrada.
* --src` → id`ioma original (ex: en).
* --tgt` → id`ioma destino (ex: pt).
* --tts` → mo`tor de voz (`bark` = mais realista, coqui` = ma`is leve).
* --out` → no`me do vídeo final (opcional).
Saídas geradas:
* video`_dublado.mp4 → ví`deo final.
* dub_w`ork/ → pa`sta com intermediários (`asr.srt`, asr_t`rad.srt, seg`_0`00X.wav, dub`_f`inal.wav, `lo`gs.json`).
---
## 📝 Considerações
* Probl**emas resolvidos:
*** Pacote Argos falhou no Windows → trocado por M2M10**0.
*** PyTorch 2.6 quebrou Bark → fixamos 2.5.1**.
*** Modelo opus-mt-en-pt inexistente → migramos para faceb**ook/m2m100\_418M.
*** Voz metalizada → ajustamos parâmetros + pós-processo de áudio.
* Dependências conflitantes → isolamos o ambiente voz-b`ark.
* `Recom**endações:
*** Use Bark quando quiser quali**dade natural, mas** prepare-se para maior uso de GPU/CPU.
* Use Coqui quando precisar de veloc**idade e me**nos consumo.
* Sempre rode em ambiente isolado para evitar conflitos de versões.
* Os intermediários ficam salvos para fácil auditoria ou reuso.
---
quer que eu monte esse resumo em um PDF a**utomático (com** seções claras: propósito, instalação, execução, considerações) para você usar como guia rápido?
metalizado
causa: parâmetros padrão e texto longo.
solução: ajustar text\_temp/waveform\_temp para 0.6, segmentar texto e pós-processo com ffmpeg (loudnorm, afftdn, equalizer).
6. bark falhando com PyTorch 2.6 (UnpicklingError)
causa: mudança de default em torch.load (weights\_only=True).
solução: usar PyTorch 2.5.1 (CPU ou cu124) no ambiente voz-bark.
7. conflitos de dependências (numpy/networkx/numba)
causa: tentar usar tudo no mesmo ambiente.
solução: separar ambientes (voz-bark para Bark).
8. modelo de tradução opus-mt-en-pt 404
causa: identificador não disponível.
solução: fixar transformers 4.41.2 e migrar para facebook/m2m100\_418M.
9. ModuleNotFoundError faster\_whisper
causa: pacote não instalado no ambiente correto.
solução: pip install faster-whisper no voz-bark.
validação final
1. setup\_bark.ps1 executado com sucesso no ambiente voz-bark.
2. validate\_install.py gera bark\_validate.wav, traduz uma frase com M2M100 e roda faster-whisper em 1s de silêncio.
3. dublar.py roda de ponta a ponta com:
python dublar.py --in seu\_video.mp4 --src en --tgt pt --tts bark
quer que eu reenvie o dublar.py completo aqui novamente, já com comentários numerando cada fase (1–9) no próprio código?
segue o que você pediu: um script de instalação/validação e um relatório curto dos problemas encontrados e como resolvemos.
script 1 – setup\_bark.ps1 (PowerShell, cria o ambiente e instala tudo)
```# setup_bark.ps1
## uso:
## powershell -ExecutionPolicy Bypass -File .\setup_bark.ps1
## após terminar:
## conda activate voz-bark
$ErrorActionPreference = "Stop"
## 1) criar ambiente
conda create -n voz-bark python=3.11 -y
## 2) ativar ambiente
conda activate voz-bark
## 3) instalar PyTorch estável (escolha UMA das linhas)
## CPU:
pip install --index-url https://download.pytorch.org/whl/cpu torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1
## GPU NVIDIA (CUDA 12.4) — use ESTA em vez da CPU se tiver GPU compatível:
## pip install --index-url https://download.pytorch.org/whl/cu124 torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1
## 4) pacotes do pipeline
pip install --upgrade --quiet transformers==4.41.2 sentencepiece sacremoses scipy
pip install --quiet faster-whisper
pip install --quiet bark==0.1.5
## 5) checagens rápidas
python - << "PY"
import shutil, sys
print("python ok:", sys.version)
import torch; print("torch", torch.__version__, "cuda:", torch.cuda.is_available())
import transformers; print("transformers", transformers.__version__)
import sentencepiece, sacremoses, scipy; print("sentencepiece/sacremoses/scipy ok")
from faster_whisper import WhisperModel; print("faster-whisper ok")
from bark import generate_audio; print("bark ok")
print("ffmpeg no PATH:", bool(shutil.which("ffmpeg")))
PY```
script 2 – validate\_install.py (testes funcionais mínimos)
#``` validate_install.py
## uso:
## conda activate voz-bark
## python validate_install.py
import os, shutil
from pathlib import Path
## 1) checar ffmpeg
assert shutil.which("ffmpeg"), "ffmpeg não encontrado no PATH"
## 2) checar torch e cuda
import torch
print("torch:", torch.__version__, "cuda disponível:", torch.cuda.is_available())
## 3) teste bark – gera fala curta
from bark import generate_audio, SAMPLE_RATE
from scipy.io.wavfile import write
audio = generate_audio("Olá! Teste curto do Bark para validação.")
out_bark = Path("bark_validate.wav")
write(out_bark.as_posix(), SAMPLE_RATE, audio)
print("bark ok ->", out_bark)
## 4) teste tradução com M2M100
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tok = AutoTokenizer.from_pretrained("facebook/m2m100_418M")
model = AutoModelForSeq2SeqLM.from_pretrained("facebook/m2m100_418M")
tok.src_lang = "en"
enc = tok(["Hello, this is a quick translation test."], return_tensors="pt", padding=True)
gen = model.generate(enc, forced_bos_token_id=tok.get_lang_id("pt"), max_new_tokens=60)
print("m2m100 ok ->", tok.batch_decode(gen, skip_special_tokens=True)[0])
## 5) teste transcrição com faster-whisper (cria 1s de silêncio só para validar pipeline)
tmp_wav = Path("silencio.wav")
os.system(f'ffmpeg -y -f lavfi -i anullsrc=r=48000:cl=mono -t 1 {tmp_wav}')
from faster_whisper import WhisperModel
wm = WhisperModel("medium", device="auto")
segs, _ = wm.transcribe(tmp_wav.as_posix(), language="en")
print("faster-whisper ok -> segmentos lidos:", len(list(segs)))
print("validação concluída")
arquivo dublar.py final (igual ao já enviado, com M2M100). se quiser, eu reenvio aqui de novo.
relatório curto da instalação e validação
-
erro: sentencepiece ao instalar argos no windows causa: build a partir do fonte e wheels incompatíveis. solução: optamos por não usar argos no windows e migramos para Marian/M2M100 via transformers.
-
erro: comandos pip colados com texto a mais (ex.: TTSpip, barkpip) causa: erro de digitação. solução: corrigido para pip install TTS e pip install bark.
-
coqui tts exigindo speaker e language causa: modelo your_tts é multi-speaker e multilíngue. solução: passamos speaker exato e language=pt-br; alternativamente, usamos modelo single-speaker tts_models/pt/cv/vits.
-
coqui tts KeyError em speaker com ‘\n’ causa: nomes retornavam com quebra de linha. solução: usar exatamente a string de tts.speakers ou trocar para modelo single-speaker.
-
bark com som
python teste_voz_bark.py
python dublar.py --in nei.mp4 --src en --tgt pt --tts bark
🚀 Resumo do Projeto de Dublagem⌗
Estrutura em 9 fases⌗
- Entrada
- Recebe vídeo (
nei.mp4), idioma origem, idioma destino e motor TTS (Bark ou Coqui).
- Extração de áudio
ffmpeggeraaudio_src.wava partir do vídeo.
- Transcrição
- faster-whisper cria
asr.jsoneasr.srtcom falas + timestamps.
- Tradução
- Usamos facebook/m2m100_418M (estável) em vez do obsoleto opus-mt.
- Gera
asr_trad.jsoneasr_trad.srt.
- Preparação de segmentos
- Divide texto em blocos ≤ 8–12s.
- Cria
segments.csvcom tempo inicial, final e fala traduzida.
- Síntese de voz (TTS)
- Se Bark → áudio realista.
- Se Coqui → mais leve e rápido.
- Salva
seg_0001.wav,seg_0002.wavetc.
- Concatenação
- Junta os segmentos em
dub_raw.wav.
- Pós-processamento
ffmpegnormaliza (loudnorm), remove ruído (afftdn) e suaviza agudos (equalizer).- Gera
dub_final.wav.
- Montagem Final (Mux)
ffmpegsubstitui áudio original pelo novo.- Gera
video_dublado.mp4. - Cria
logs.jsoncom caminhos de todos os arquivos.
📂 Arquivos Gerados⌗
audio_src.wav→ áudio extraído.asr.json/asr.srt→ transcrição original.asr_trad.json/asr_trad.srt→ tradução.seg_XXXX.wav→ falas sintetizadas.dub_raw.wav→ áudio concatenado.dub_final.wav→ áudio tratado.video_dublado.mp4→ vídeo final com dublagem.logs.json→ log do processo.
Projeto de Dublagem Local V1
1