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:
@@ -39,6 +39,7 @@ class ConfiguracaoVisualDoScanner:
|
||||
faixas_de_video: tuple[int, ...] = ()
|
||||
faixas_de_audio: tuple[int, ...] = ()
|
||||
modo_de_analise: str = "ambos"
|
||||
metricas_de_fala: bool = False
|
||||
recursos_vision: frozenset[str] = RECURSOS_VISION
|
||||
detectar_cenas: bool = True
|
||||
analisar_continuidade: bool = True
|
||||
@@ -87,6 +88,7 @@ class ConfiguracaoVisualDoScanner:
|
||||
faixas_de_video=tuple(sorted(set(int(item) for item in dados.get("faixas_de_video", ())))),
|
||||
faixas_de_audio=tuple(sorted(set(int(item) for item in dados.get("faixas_de_audio", ())))),
|
||||
modo_de_analise=str(dados.get("modo_de_analise", "ambos")),
|
||||
metricas_de_fala=bool(dados.get("metricas_de_fala", False)),
|
||||
recursos_vision=frozenset(dados.get("recursos_vision", RECURSOS_VISION)),
|
||||
detectar_cenas=bool(dados.get("detectar_cenas", True)),
|
||||
analisar_continuidade=bool(dados.get("analisar_continuidade", True)),
|
||||
@@ -108,6 +110,7 @@ class ConfiguracaoVisualDoScanner:
|
||||
"faixas_de_video": list(self.faixas_de_video),
|
||||
"faixas_de_audio": list(self.faixas_de_audio),
|
||||
"modo_de_analise": self.modo_de_analise,
|
||||
"metricas_de_fala": self.metricas_de_fala,
|
||||
"recursos_vision": sorted(self.recursos_vision),
|
||||
"detectar_cenas": self.detectar_cenas,
|
||||
"analisar_continuidade": self.analisar_continuidade,
|
||||
|
||||
@@ -34,12 +34,14 @@ class TranscricaoDaTimeline:
|
||||
def __init__(self, provider: Any, extrator: ExtracaoDeAudio | None = None,
|
||||
diretoria_de_trabalho: str | Path = ".transcricao",
|
||||
analisador_de_emocao: Any | None = None,
|
||||
diarizador: Any | None = None) -> None:
|
||||
diarizador: Any | None = None,
|
||||
analisador_de_metricas_de_voz: Any | None = None) -> None:
|
||||
self.provider = provider
|
||||
self.extrator = extrator or ExtracaoDeAudio()
|
||||
self.diretoria_de_trabalho = Path(diretoria_de_trabalho)
|
||||
self.analisador_de_emocao = analisador_de_emocao
|
||||
self.diarizador = diarizador
|
||||
self.analisador_de_metricas_de_voz = analisador_de_metricas_de_voz
|
||||
|
||||
def executar(self, timeline: Any) -> list[TranscricaoDoClipe]:
|
||||
clipes: list[Any] = []
|
||||
@@ -113,15 +115,23 @@ class TranscricaoDaTimeline:
|
||||
dados = json.loads(cache.read_text(encoding="utf-8"))
|
||||
if all("palavras" in item and
|
||||
(self.analisador_de_emocao is None or
|
||||
("emocao" in item and "voz_aparente" in item))
|
||||
("emocao" in item and "voz_aparente" in item)) and
|
||||
(self.analisador_de_metricas_de_voz is None or
|
||||
"caracteristicas_acusticas" in item)
|
||||
for item in dados):
|
||||
return [self._segmento_do_json(item) for item in dados]
|
||||
partes = self.extrator.extrair(arquivo, pasta / "audio")
|
||||
segmentos: list[SegmentoDeTranscricao] = []
|
||||
fim_anterior: float | None = None
|
||||
for parte in partes:
|
||||
falas = self._diarizar(parte.caminho)
|
||||
for segmento in self.provider.transcrever(type("Audio", (), {"arquivo": str(parte.caminho)})()):
|
||||
analise = self._analisar_emocao(parte.caminho, segmento.inicio, segmento.fim)
|
||||
inicio_absoluto = parte.inicio + segmento.inicio
|
||||
metricas_de_voz = self._analisar_metricas_de_voz(
|
||||
parte.caminho, segmento.inicio, segmento.fim, segmento.palavras,
|
||||
inicio_absoluto, fim_anterior,
|
||||
)
|
||||
falante = self._falante_em(falas, segmento.inicio, segmento.fim)
|
||||
segmentos.append(SegmentoDeTranscricao(parte.inicio + segmento.inicio,
|
||||
parte.inicio + segmento.fim, segmento.texto, segmento.confianca,
|
||||
@@ -130,8 +140,9 @@ class TranscricaoDaTimeline:
|
||||
self._falante_em(falas, p.inicio, p.fim))
|
||||
for p in segmento.palavras),
|
||||
analise.get("emocao"), analise.get("confianca"),
|
||||
dict(analise.get("caracteristicas_acusticas", {})), falante,
|
||||
metricas_de_voz or dict(analise.get("caracteristicas_acusticas", {})), falante,
|
||||
analise.get("voz_aparente"), analise.get("confianca_voz")))
|
||||
fim_anterior = inicio_absoluto + segmento.fim - segmento.inicio
|
||||
pasta.mkdir(parents=True, exist_ok=True)
|
||||
cache.write_text(json.dumps([asdict(item) for item in segmentos], ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
(pasta / f"{prefixo}.txt").write_text(
|
||||
@@ -157,6 +168,16 @@ class TranscricaoDaTimeline:
|
||||
return {}
|
||||
return dict(self.analisador_de_emocao.analisar(arquivo, inicio, fim))
|
||||
|
||||
def _analisar_metricas_de_voz(self, arquivo: Path, inicio: float, fim: float,
|
||||
palavras: tuple[PalavraDeTranscricao, ...],
|
||||
inicio_absoluto: float,
|
||||
fim_anterior: float | None) -> dict[str, Any]:
|
||||
"""Calcula métricas acústicas somente quando foram solicitadas."""
|
||||
if self.analisador_de_metricas_de_voz is None:
|
||||
return {}
|
||||
return dict(self.analisador_de_metricas_de_voz.analisar(
|
||||
arquivo, inicio, fim, palavras, inicio_absoluto, fim_anterior))
|
||||
|
||||
def _diarizar(self, arquivo: Path) -> list[tuple[float, float, str]]:
|
||||
if self.diarizador is None:
|
||||
return []
|
||||
|
||||
Reference in New Issue
Block a user