- adicionadas métricas opcionais de fala ao Scanner com análise acústica na engine - corrigido o progresso da transcrição do Scanner durante o processamento do Whisper - refatorado o runner Swift do Apple Vision para executar requests em lote com retry CPU-only, corrigindo falhas de CVPixelBuffer/ANE/OCR - documentado o fluxo de edição de vídeo por voz integrado ao Scanner, banco e engine - formalizado o protocolo de edição por chat com perfil editorial e consultas progressivas Resumo: - 10 arquivos alterados - 5 novos - 5 modificados - 0 removidos 5 files changed, 367 insertions(+), 95 deletions(-) Arquivos: - .jhonny/analises.db - code/engine/executar_scanner.py - code/engine/integracoes/visual/apple_vision_runner.swift - code/engine/integracoes/whisper/provider_de_transcricao_local.py - code/engine/testes/test_provider_de_transcricao_local.py - .jhonny/analises.db-shm - .jhonny/analises.db-wal - apple_vision_runner - code/relatorios/teste-enquadramento-20s.json - docs/
99 lines
3.8 KiB
Python
99 lines
3.8 KiB
Python
"""Testes do provider local de transcrição em lote."""
|
|
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import unittest
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest.mock import patch
|
|
|
|
from engine.integracoes.whisper import ProviderDeTranscricaoLocal
|
|
|
|
|
|
class TesteDoProviderDeTranscricaoLocal(unittest.TestCase):
|
|
"""Verifica a configuração e a conversão dos segmentos do provider."""
|
|
|
|
def test_usa_pipeline_em_lote_com_vad_e_timestamps_de_palavras(self):
|
|
"""Mantém as opções de qualidade ao usar inferência em lote."""
|
|
chamadas = {}
|
|
|
|
class ModeloFalso:
|
|
"""Representa o modelo externo durante o teste."""
|
|
|
|
def __init__(self, *argumentos, **opcoes):
|
|
chamadas["modelo"] = (argumentos, opcoes)
|
|
|
|
class PipelineFalso:
|
|
"""Representa o pipeline em lote durante o teste."""
|
|
|
|
def __init__(self, model):
|
|
chamadas["pipeline_modelo"] = model
|
|
|
|
def transcribe(self, *argumentos, **opcoes):
|
|
chamadas["transcricao"] = (argumentos, opcoes)
|
|
palavra = SimpleNamespace(word="Olá", start=0.0, end=0.5, probability=0.99)
|
|
segmento = SimpleNamespace(start=0.0, end=0.5, text=" Olá ", words=[palavra])
|
|
return iter([segmento]), SimpleNamespace(duration=0.5)
|
|
|
|
modulo_falso = types.SimpleNamespace(
|
|
BatchedInferencePipeline=PipelineFalso,
|
|
WhisperModel=ModeloFalso,
|
|
)
|
|
with tempfile.TemporaryDirectory() as pasta:
|
|
arquivo = Path(pasta) / "audio.wav"
|
|
arquivo.write_bytes(b"audio")
|
|
with patch.dict(sys.modules, {"faster_whisper": modulo_falso}):
|
|
provider = ProviderDeTranscricaoLocal("small", tamanho_do_lote=8)
|
|
resultado = provider.transcrever(SimpleNamespace(arquivo=str(arquivo)))
|
|
|
|
self.assertEqual(resultado[0].texto, "Olá")
|
|
self.assertEqual(chamadas["transcricao"][1]["batch_size"], 8)
|
|
self.assertTrue(chamadas["transcricao"][1]["vad_filter"])
|
|
self.assertTrue(chamadas["transcricao"][1]["word_timestamps"])
|
|
|
|
def test_rejeita_tamanho_de_lote_invalido(self):
|
|
"""Impede configuração silenciosa de um lote inválido."""
|
|
with self.assertRaises(ValueError):
|
|
ProviderDeTranscricaoLocal("small", tamanho_do_lote=0)
|
|
|
|
def test_emite_progresso_conforme_os_segmentos_processados(self):
|
|
"""Atualiza o chamador enquanto o gerador do Whisper entrega segmentos."""
|
|
progresso = []
|
|
|
|
class ModeloFalso:
|
|
"""Representa o modelo externo durante o teste."""
|
|
|
|
def __init__(self, *argumentos, **opcoes):
|
|
pass
|
|
|
|
class PipelineFalso:
|
|
"""Entrega dois segmentos para simular um áudio em processamento."""
|
|
|
|
def __init__(self, model):
|
|
pass
|
|
|
|
def transcribe(self, *argumentos, **opcoes):
|
|
segmentos = [
|
|
SimpleNamespace(start=0.0, end=2.0, text=" um", words=[]),
|
|
SimpleNamespace(start=2.0, end=4.0, text=" dois", words=[]),
|
|
]
|
|
return iter(segmentos), SimpleNamespace(duration=4.0)
|
|
|
|
modulo_falso = types.SimpleNamespace(
|
|
BatchedInferencePipeline=PipelineFalso,
|
|
WhisperModel=ModeloFalso,
|
|
)
|
|
with tempfile.TemporaryDirectory() as pasta:
|
|
arquivo = Path(pasta) / "audio.wav"
|
|
arquivo.write_bytes(b"audio")
|
|
with patch.dict(sys.modules, {"faster_whisper": modulo_falso}):
|
|
provider = ProviderDeTranscricaoLocal("small", ao_progresso=progresso.append)
|
|
provider.transcrever(SimpleNamespace(arquivo=str(arquivo)))
|
|
|
|
self.assertEqual(progresso, [50.0, 99.0, 100.0])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|