JARVIS/verde/pruebas/08_escucha.sh
sito 1e3e5ca20d carril verde (Hermes Agent): documentacion, panel, voz local y RAG
Rama JARVIS-GREEN, independiente de master (el nucleo naranja queda intacto).

- README propio del carril verde con diagrama de arquitectura y capturas del panel.
- verde/: arranque, panel web, puente de voz (escucha local con faster-whisper +
  habla con la voz del naranja), pruebas (07 voz, 08 escucha), config y notas.
- Integracion RAG: nucleo/saber/busca_cli.py + skill buscar-en-apuntes, para que
  el agente consulte el mismo indice que el nucleo.
- Todo local (127.0.0.1); sin datos personales (rutas y modelo de GPU scrubeados).
2026-08-18 11:26:42 +02:00

73 lines
3.1 KiB
Bash
Executable file

#!/usr/bin/env bash
# Que el verde ESCUCHE, y en local. El complemento del 07 (que hable).
#
# El TUI de Hermes no tiene microfono, y su STT nativo es para notas de voz de
# mensajeria —que saldrian de la maquina—. El puente escucha-verde.sh cierra el
# hueco con faster-whisper local (el mismo 'small' en espanol que ya declara la
# seccion stt: del config.yaml), en CPU para no pelear por la VRAM con el 4B.
#
# La prueba no necesita microfono: hace un BUCLE. Genera voz con el mismo TTS del
# verde (voz-verde.sh, 07), la transcribe con escucha_transcribe.py, y comprueba
# que el texto vuelve entero. Si el oido funciona, lo que entro por el altavoz
# sale por el transcriptor.
cd "$(dirname "$0")" && . ./comun.sh
PY=$RAIZ/nucleo/venv/bin/python
[ -x "$PY" ] || PY=$(command -v python3)
TRANS=$VERDE/escucha_transcribe.py
titulo "Las piezas"
afirma "existe escucha_transcribe.py" test -f "$TRANS"
afirma "existe el puente escucha-verde.sh" test -x "$VERDE/escucha-verde.sh"
afirma "faster-whisper importa" "$PY" -c "import faster_whisper"
afirma "el TTS del verde existe (para el bucle)" test -x "$VERDE/voz-verde.sh"
# quita acentos y baja a minusculas, para comparar sin depender de la tilde
_norm() { "$PY" -c "import sys,unicodedata as u; t=u.normalize('NFD',sys.stdin.read().lower()); print(''.join(c for c in t if u.category(c)!='Mn'))"; }
titulo "El bucle voz -> texto"
# (frase dicha, palabras clave que TIENEN que volver). Se evita 'jarvis' a
# proposito: es un nombre raro y whisper lo oye 'harvis'; eso no mide el oido.
probar_frase() {
local frase=$1 claves=$2
local wav=$TMP/oir.wav txt=$TMP/oir.txt
printf '%s' "$frase" > "$txt"
rm -f "$wav"
"$VERDE/voz-verde.sh" "$wav" "$txt" >/dev/null 2>&1
if [ ! -s "$wav" ]; then
echo " $(rojo FALLO) no se genero el WAV para: $frase"; _fallo=$((_fallo+1)); return
fi
local ini out norm falta=""
ini=$(date +%s.%N)
out=$(timeout 120 "$PY" "$TRANS" "$wav" 2>/dev/null)
local tardo; tardo=$(awk "BEGIN{printf \"%.1f\", $(date +%s.%N) - $ini}")
norm=$(printf '%s' "$out" | _norm)
local c
for c in $claves; do
printf '%s' "$norm" | grep -q "$c" || falta="$falta $c"
done
if [ -z "$falta" ]; then
printf ' %s escucho: "%s" (%ss)\n' "$(verde OK)" "$out" "$tardo"; _ok=$((_ok+1))
else
printf ' %s faltan [%s] en: "%s"\n' "$(rojo FALLO)" "$falta" "$out"; _fallo=$((_fallo+1))
fi
}
probar_frase "cuanto espacio libre queda en el disco" "espacio disco"
probar_frase "abre el navegador y busca el tiempo en madrid" "navegador tiempo madrid"
probar_frase "apaga las luces del salon a las diez" "luces salon"
titulo "Local de verdad"
# El transcriptor no debe abrir ningun socket a la nube: se comprueba que el
# codigo no importa clientes de APIs de STT de pago.
if grep -qiE "openai|groq|mistral|requests\.post|urllib.*http" "$TRANS"; then
echo " $(rojo FALLO) el transcriptor referencia una API remota"; _fallo=$((_fallo+1))
else
echo " $(verde OK) el transcriptor no llama a ninguna API remota"; _ok=$((_ok+1))
fi
resumen