cerebro-vip INEMA.CLUB
inícioINEMA.MUSICAL

Desenvolvimento de um pipeline local de dublagem automática de vídeos…

INEMA.MUSICAL · 2025-09-07 · ~21 min · ver no Telegram ↗

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

  1. Grave 8–12s de voz limpa.
  2. Converta para 24 kHz mono e corte silêncios.
  3. Rode localmente uma UI de clonagem do Bark (gradio) para gerar o arquivo .npz. (GitHub)
  4. Use esse .npz no seu script com a flag --voice.
  5. Ajuste temperatura e pós-processo se necessário. Obs.: a API do Bark aceita history_prompt apontando para um .npz ou para um preset como v2/pt_speaker_6. (Coqui Docs, Replicate)

Passo a passo local para gerar o .npz

  1. 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

  1. 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

  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)
  1. 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.6 e waveform_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_prompt você define o timbre. Presets como v2/pt_speaker_6 tendem 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_wav e é 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_prompt pronto (preset) → você escolhe um arquivo ou nome que já representa uma voz específica (ex.: v2/pt_speaker_6 costuma soar feminino em PT-BR).
  • com history_prompt criado 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_prompt a 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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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

  1. Entrada
  • Recebe vídeo (nei.mp4), idioma origem, idioma destino e motor TTS (Bark ou Coqui).
  1. Extração de áudio
  • ffmpeg gera audio_src.wav a partir do vídeo.
  1. Transcrição
  • faster-whisper cria asr.json e asr.srt com falas + timestamps.
  1. Tradução
  • Usamos facebook/m2m100_418M (estável) em vez do obsoleto opus-mt.
  • Gera asr_trad.json e asr_trad.srt.
  1. Preparação de segmentos
  • Divide texto em blocos ≤ 8–12s.
  • Cria segments.csv com tempo inicial, final e fala traduzida.
  1. Síntese de voz (TTS)
  • Se Bark → áudio realista.
  • Se Coqui → mais leve e rápido.
  • Salva seg_0001.wav, seg_0002.wav etc.
  1. Concatenação
  • Junta os segmentos em dub_raw.wav.
  1. Pós-processamento
  • ffmpeg normaliza (loudnorm), remove ruído (afftdn) e suaviza agudos (equalizer).
  • Gera dub_final.wav.
  1. Montagem Final (Mux)
  • ffmpeg substitui áudio original pelo novo.
  • Gera video_dublado.mp4.
  • Cria logs.json com 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

chatgpt.com ↗

1

Recursos

↑ voltar ao topo · ver no Telegram ↗