feat: adicionadas métricas opcionais de fala ao Scanner com anális

- adicionadas métricas opcionais de fala ao Scanner com análise acústica na engine

Resumo:
- 7 arquivos alterados
- 2 novos
- 5 modificados
- 0 removidos

 5 files changed, 43 insertions(+), 6 deletions(-)

Arquivos:
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/engine/executar_scanner.py
  - code/engine/scanner/configuracao_visual.py
  - code/engine/scanner/transcricao_da_timeline.py
  - code/engine/integracoes/audio/
  - code/engine/testes/test_analisador_de_metricas_de_voz.py
This commit is contained in:
João Henrique
2026-09-09 17:17:55 -04:00
parent 89288d95f0
commit b03b175973
8 changed files with 241 additions and 6 deletions
@@ -0,0 +1,52 @@
"""Testes do cálculo de métricas acústicas do Scanner."""
import math
import tempfile
import unittest
import wave
from pathlib import Path
from types import SimpleNamespace
from engine.integracoes.audio import AnalisadorDeMetricasDeVoz
class TesteDoAnalisadorDeMetricasDeVoz(unittest.TestCase):
"""Verifica a interface pública do analisador de voz."""
def test_calcula_metricas_do_trecho_e_reaproveita_o_audio(self):
"""Calcula sinais básicos e mantém a pausa entre palavras."""
with tempfile.TemporaryDirectory() as pasta:
arquivo = Path(pasta) / "fala.wav"
self._criar_wav(arquivo)
palavras = (
SimpleNamespace(inicio=0.0, fim=0.25),
SimpleNamespace(inicio=0.5, fim=0.75),
)
analisador = AnalisadorDeMetricasDeVoz()
primeira = analisador.analisar(arquivo, 0.0, 1.0, palavras)
segunda = analisador.analisar(arquivo, 1.0, 2.0, (), 1.5, 1.0)
self.assertGreater(primeira["energy_rms"], 0)
self.assertIsNotNone(primeira["pitch_hz_median"])
self.assertAlmostEqual(primeira["speaking_rate_wps"], 2.0)
self.assertAlmostEqual(primeira["longest_internal_pause_s"], 0.25)
self.assertAlmostEqual(segunda["gap_before_s"], 0.5)
@staticmethod
def _criar_wav(caminho: Path) -> None:
"""Cria um WAV mono curto e determinístico para o teste."""
taxa = 16000
amostras = [
int(12000 * math.sin(2 * math.pi * 220 * indice / taxa))
for indice in range(taxa * 2)
]
with wave.open(str(caminho), "wb") as arquivo:
arquivo.setnchannels(1)
arquivo.setsampwidth(2)
arquivo.setframerate(taxa)
arquivo.writeframes(b"".join(int(amostra).to_bytes(2, "little", signed=True)
for amostra in amostras))
if __name__ == "__main__":
unittest.main()