from dataclasses import dataclass from pathlib import Path import subprocess @dataclass(frozen=True) class ParteDeAudio: caminho: Path inicio: float fim: float class ExtracaoDeAudio: """Prepara mídia local para providers de transcrição.""" def __init__(self, ffmpeg: str = "ffmpeg", ffprobe: str = "ffprobe", duracao_da_parte: float = 600.0) -> None: self.ffmpeg = ffmpeg self.ffprobe = ffprobe self.duracao_da_parte = duracao_da_parte def duracao(self, arquivo: str | Path) -> float: caminho = self._validar(arquivo) resultado = subprocess.run( [self.ffprobe, "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", str(caminho)], check=True, capture_output=True, text=True, ) return float(resultado.stdout.strip()) def extrair(self, arquivo: str | Path, destino: str | Path) -> list[ParteDeAudio]: return self.extrair_intervalo(arquivo, destino, 0.0, None) def extrair_intervalo(self, arquivo: str | Path, destino: str | Path, inicio: float = 0.0, fim: float | None = None) -> list[ParteDeAudio]: origem = self._validar(arquivo) pasta = Path(destino) pasta.mkdir(parents=True, exist_ok=True) duracao_total = self.duracao(origem) inicio = max(0.0, inicio) fim = min(fim if fim is not None else duracao_total, duracao_total) total = fim partes: list[ParteDeAudio] = [] inicio = 0.0 indice = 0 while inicio < total: fim_da_parte = min(inicio + self.duracao_da_parte, total) saida = pasta / f"parte-{indice:04d}.wav" subprocess.run([ self.ffmpeg, "-y", "-ss", str(inicio), "-i", str(origem), "-t", str(fim_da_parte - inicio), "-vn", "-ac", "1", "-ar", "16000", "-c:a", "pcm_s16le", str(saida), ], check=True, capture_output=True, text=True) partes.append(ParteDeAudio(saida, inicio, fim_da_parte)) inicio = fim_da_parte indice += 1 return partes def _validar(self, arquivo: str | Path) -> Path: caminho = Path(arquivo) if not caminho.is_file(): raise FileNotFoundError(f"Arquivo de mídia não encontrado: {caminho}") return caminho