54 lines
1.6 KiB
Python
54 lines
1.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""aviso.py — Aviso por voz local (RF-14, RF-15).
|
|
|
|
Emite un aviso sonoro local (reutiliza `scripts/aviso_sonoro.py` del repo de negocio)
|
|
solo cuando el resumen del ciclo contiene elementos que requieren atencion, o cuando
|
|
la IA fallo (RF-13). Nunca envia nada fuera del equipo (Regla 5).
|
|
|
|
El runner es inyectable para poder testear sin reproducir audio.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from typing import Callable
|
|
|
|
from . import config
|
|
|
|
import infra_paths
|
|
|
|
|
|
def _script_aviso():
|
|
"""Ruta del script de aviso sonoro (repo de negocio)."""
|
|
return infra_paths.biblioteca_repo() / "scripts" / "aviso_sonoro.py"
|
|
|
|
|
|
def _runner_default(tipo: str) -> None:
|
|
"""Reproduce el aviso sonoro lanzando el script en un subproceso."""
|
|
subprocess.run([sys.executable, str(_script_aviso()), tipo], check=False)
|
|
|
|
|
|
def avisar(resumen: dict, cfg: dict | None = None, _runner: Callable[[str], None] | None = None) -> bool:
|
|
"""Emite el aviso por voz si procede. Devuelve True si aviso.
|
|
|
|
- Si `aviso.voz` esta desactivado en config -> no hace nada.
|
|
- Avisa si `fallo_ia` o si hay elementos en `requiere_atencion`.
|
|
"""
|
|
cfg = cfg or config.cargar()
|
|
if not cfg.get("aviso", {}).get("voz", True):
|
|
return False
|
|
|
|
fallo_ia = bool(resumen.get("fallo_ia"))
|
|
atencion = bool(resumen.get("requiere_atencion"))
|
|
if not (fallo_ia or atencion):
|
|
return False
|
|
|
|
tipo = "fin" if atencion else "error"
|
|
runner = _runner or _runner_default
|
|
try:
|
|
runner(tipo)
|
|
except Exception:
|
|
pass
|
|
return True
|