"""Adapta o faster-whisper para a transcrição local do Scanner.""" from pathlib import Path from typing import Any, Callable from ...scanner.modelos import PalavraDeTranscricao, SegmentoDeTranscricao class ProviderDeTranscricaoLocal: """Executa transcrição local em lote, sem transmitir a mídia.""" def __init__(self, modelo: str, dispositivo: str = "cpu", tipo_de_calculo: str = "int8", idioma: str = "pt", tamanho_do_lote: int = 16, ao_progresso: Callable[[float], None] | None = None) -> None: """Carrega o modelo local e configura o tamanho do lote de inferência.""" if tamanho_do_lote < 1: raise ValueError("O tamanho do lote deve ser maior que zero.") self.nome_do_modelo = Path(modelo).name if "faster-whisper-" in modelo: self.nome_do_modelo = modelo.split("faster-whisper-", 1)[1].split("/", 1)[0] from faster_whisper import BatchedInferencePipeline, WhisperModel self.modelo = WhisperModel(modelo, device=dispositivo, compute_type=tipo_de_calculo) self.pipeline = BatchedInferencePipeline(model=self.modelo) self.idioma = idioma self.tamanho_do_lote = tamanho_do_lote self.ao_progresso = ao_progresso def transcrever(self, clipe: Any) -> list[SegmentoDeTranscricao]: """Transcreve o áudio com VAD, timestamps e inferência em lote.""" arquivo = Path(clipe.arquivo) if not arquivo.is_file(): raise FileNotFoundError(f"Arquivo de áudio não encontrado: {arquivo}") segmentos, informacoes = self.pipeline.transcribe( str(arquivo), language=self.idioma, vad_filter=True, word_timestamps=True, batch_size=self.tamanho_do_lote, ) duracao = float(getattr(informacoes, "duration", 0.0) or 0.0) resultado: list[SegmentoDeTranscricao] = [] for segmento in segmentos: resultado.append(SegmentoDeTranscricao( float(segmento.start), float(segmento.end), segmento.text.strip(), None, tuple(PalavraDeTranscricao( palavra.word.strip(), float(palavra.start), float(palavra.end), getattr(palavra, "probability", None) ) for palavra in (segmento.words or []) if palavra.word.strip()) )) if self.ao_progresso and duracao > 0: self.ao_progresso(min(99.0, max(0.0, float(segmento.end) / duracao * 100))) if self.ao_progresso: self.ao_progresso(100.0) return resultado