JARVIS/config/jarvis-voz.sh
sito 8e4bc8ad94 JARVIS: asistente de voz local para Linux
Nucleo propio: oye con whisper.cpp, piensa con un modelo de Ollama, habla
con Piper, y hace RAG sobre los apuntes del usuario. 100% local, sin
cuentas ni claves.

Escrito bajo una restriccion dura, 4 GB de VRAM: el cerebro y whisper
comparten tarjeta y solo caben porque estan dimensionados para ello. El
RAG usa embeddings estaticos con busqueda hibrida; la voz clonada se sirve
de una cache de frases.

Incluye instalador (install.sh), requisitos, y documentacion del stack,
del manejo de root y de las acciones. Los apuntes indexados y el diario NO
se incluyen: son privados y el .gitignore los bloquea.
2026-08-16 15:34:37 +02:00

46 lines
1.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# Voz de JARVIS con la clonada (XTTS-v2) servida desde cache.
#
# jarvis-voz.sh <fichero.wav> <texto>
#
# Si el texto esta pre-generado en cache_voz/, lo sirve al instante (un cp, sin
# tocar GPU). Si no, cae a Piper. La clave es sha1(texto normalizado), la misma
# que calcula generar_cache_voz.py -> los aciertos son exactos.
#
# El clon ya trae el tono correcto, asi que en un acierto NO se aplica el
# descenso de tono de Piper; solo se copia. En un fallo, Piper hace lo suyo
# (incluido su rubberband) como hasta ahora.
set -uo pipefail
# La raiz se deduce de donde esta este fichero, no del $HOME de nadie: asi el
# arbol se puede mover o clonar en otra maquina y sigue funcionando sin editar
# rutas. `cd -P` resuelve enlaces simbolicos, que el lanzador de escritorio
# puede invocarlo por uno.
RAIZ=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)
BASE=$RAIZ/voz
CACHE=$BASE/cache_voz
PIPER=$RAIZ/config/jarvis-piper.sh
SALIDA=${1:-}
TEXTO=${2:-}
[ -n "$SALIDA" ] || { echo "falta el fichero de salida" >&2; exit 1; }
[ -n "$TEXTO" ] || { echo "sin texto que decir" >&2; exit 1; }
# clave = sha1(texto con espacios colapsados y recortado), identica a la de
# Python: re.sub(r'\s+',' ',t).strip() -> sha1(utf-8)
T=$(printf '%s' "$TEXTO" | tr -s '[:space:]' ' ' | sed 's/^ //; s/ $//')
KEY=$(printf '%s' "$T" | sha1sum | cut -d' ' -f1)
HIT=$CACHE/$KEY.wav
if [ -f "$HIT" ]; then
cp -f "$HIT" "$SALIDA"
exit 0
fi
# fallo de cache -> registrar la frase (normalizada) para calentar la cache
# luego con la voz clonada, y de momento reescribir siglas + Piper.
printf '%s\n' "$T" >> "$BASE/misses.log" 2>/dev/null || true
TEXTO2=$(python3 "$BASE/pronuncia.py" "$TEXTO" 2>/dev/null)
[ -n "$TEXTO2" ] || TEXTO2=$TEXTO
exec "$PIPER" "$SALIDA" "$TEXTO2"