Files
João Henrique ee181360c8 feat: criado repositório jhonny-editor no Gitea
criado repositório jhonny-editor no Gitea
adicionado script admin/deploy.command com commit automático
atualizado admin/DEV-NOTES.md com template limpo

Resumo:
- 32 arquivos alterados
- 16 novos
- 15 modificados
- 0 removidos

 16 files changed, 638 insertions(+), 61 deletions(-)

Arquivos:
  - code/engine/skills/boas-praticas-oo.md -> .agents/skills/boas-praticas-oo/SKILL.md
  - AGENTS.md
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/cep-plugin/styles.css
  - code/engine/integracoes/visual/apple_vision.py
  - code/engine/integracoes/visual/apple_vision_runner.swift
  - code/engine/integracoes/visual/extrator_ffmpeg.py
  - code/engine/scanner/__init__.py
  - code/engine/scanner/configuracao_visual.py
  - code/engine/scanner/coordenacao/__init__.py
  - code/engine/scanner/retakes/adaptador_de_falas.py
  - code/engine/scanner/retakes/agrupador_de_takes.py
  - code/engine/scanner/retakes/detector_de_reinicios.py
  - code/engine/scanner/retakes/modelos_de_retakes.py
  - code/engine/scanner/visual.py
  - .jhonny/
  - .retakes/
  - CODING_STANDARDS.md
  - code/engine/executar_retakes.py
  - code/engine/persistencia/
  - code/engine/scanner/retakes/__init__.py
  - code/engine/scanner/retakes/carregador_de_artefatos.py
  - code/engine/scanner/retakes/classificador_de_retakes.py
  - code/engine/scanner/retakes/coordenador_de_retakes.py
  - code/engine/scanner/retakes/deteccao_de_retakes.py
  - code/engine/scanner/retakes/gerador_de_evidencias.py
  - code/engine/scanner/retakes/repositorio_de_retakes.py
  - code/engine/testes/test_consultas_de_persistencia.py
  - code/engine/testes/test_deteccao_de_retakes.py
  - code/engine/testes/test_persistencia_sqlite.py
  - code/relatorios/audio/arquivos/92f97877259a86a8095b1eecafdefe357212a12247d04b78df60e0c0ae38b2ea/
2026-09-08 17:13:19 -04:00

95 lines
3.3 KiB
Python

"""Detecção de sinais de reinício/recomeço de fala.
Analisa padrões de que a pessoa começou novamente uma ideia: repetição do
início de uma frase, pausas longas, marcadores explícitos ("não", "pera",
"vamos de novo", "desculpa") e repetição de palavras consecutivas.
"""
from __future__ import annotations
import re
from typing import Iterable
from .comparador_de_falas import ComparadorDeFalas
from .modelos_de_retakes import Fala, SinalDeReinicio
_MARCADORES = (
"não", "pera", "peraí", "pera ai", "espera", "vamos de novo", "de novo",
"vamos recomeçar", "recomeçar", "desculpa", "desculpe", "deixa eu ver",
"vou repetir", "esquece", "hmm", "hm", "uhm", "tá", "ta",
)
_RE_MARCADOR = re.compile(
r"\b(?:" + "|".join(re.escape(m) for m in _MARCADORES) + r")\b",
re.IGNORECASE,
)
_PAUSA_LONGA = 1.2 # segundos a partir dos quais a pausa sugere recomeço.
class DetectorDeReinicios:
"""Encontra ``SinalDeReinicio`` em cada fala em relação à anterior."""
def __init__(
self,
comparador: ComparadorDeFalas | None = None,
pausa_longa: float = _PAUSA_LONGA,
) -> None:
self.comparador = comparador or ComparadorDeFalas()
self.pausa_longa = pausa_longa
def detectar(self, falas: Iterable[Fala]) -> list[SinalDeReinicio]:
falas = list(falas)
sinais: list[SinalDeReinicio] = []
for indice, fala in enumerate(falas):
sinal = self._analisar(fala, falas[indice - 1] if indice > 0 else None)
if sinal:
sinais.append(sinal)
return sinais
def _analisar(self, fala: Fala, anterior: Fala | None) -> SinalDeReinicio | None:
evidencias: list[str] = []
intensidades: list[float] = []
palavras = fala.texto_normalizado.split()
# 1. Marcadores explícitos de recomeço no início.
if palavras and _RE_MARCADOR.match(palavras[0]):
evidencias.append("marcador explícito de recomeço")
intensidades.append(0.9)
if anterior is None:
if intensidades:
return SinalDeReinicio(fala.id, "reinicio_explicito",
round(max(intensidades), 3), evidencias)
return None
# 2. Pausa longa antes da fala.
pausa = fala.inicio - anterior.fim
if pausa >= self.pausa_longa:
evidencias.append(f"pausa de {pausa:.1f} segundos")
intensidades.append(min(1.0, 0.5 + pausa / 8.0))
# 3. Repetição do início da frase anterior.
prefixo = self.comparador.prefixo_comum_em_palavras(anterior.texto, fala.texto)
if prefixo >= 3:
evidencias.append(f"repetição das primeiras {prefixo} palavras")
intensidades.append(min(1.0, 0.4 + prefixo * 0.08))
if not evidencias:
return None
tem_marcador = any("marcador" in e for e in evidencias)
tem_repeticao = any("repetição" in e for e in evidencias)
if tem_marcador:
tipo = "reinicio_explicito"
elif tem_repeticao:
tipo = "repeticao_do_inicio"
else:
tipo = "reinicio_pos_pausa"
return SinalDeReinicio(
fala_id=fala.id,
tipo=tipo,
intensidade=round(min(1.0, max(intensidades)), 3),
evidencias=evidencias,
)