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.
This commit is contained in:
commit
8e4bc8ad94
125 changed files with 25033 additions and 0 deletions
94
config/demo_en_directo.sh
Executable file
94
config/demo_en_directo.sh
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env bash
|
||||
# Le da ordenes a JARVIS en directo, para verlo trabajar en la pantalla.
|
||||
#
|
||||
# Cada orden se dice EN VOZ ALTA con la voz activa (para oir como suena de
|
||||
# verdad, no en un banco de pruebas) y luego se ejecuta la accion que le
|
||||
# corresponde, igual que haria el asistente al oirte.
|
||||
#
|
||||
# No se ejecuta nada destructivo ni nada con root: eso pasa por un dialogo que
|
||||
# aprueba una persona, y aqui no hay persona delante del dialogo.
|
||||
#
|
||||
# ./demo_en_directo.sh las que salen por pantalla incluidas
|
||||
# ./demo_en_directo.sh --mudo sin voz, solo resultados
|
||||
set -uo pipefail
|
||||
RAIZ=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)
|
||||
MUDO=no; [ "${1:-}" = "--mudo" ] && MUDO=si
|
||||
|
||||
CATALOGO=$RAIZ/newelle/data/acciones/acciones.json
|
||||
TMPWAV=$(mktemp --suffix=.wav)
|
||||
trap 'rm -f "$TMPWAV"' EXIT
|
||||
|
||||
# La orden que se le diria, y la accion del catalogo que le toca.
|
||||
# Se eligen las que se VEN o las que contestan algo concreto.
|
||||
ORDENES=(
|
||||
"cuanto espacio queda|disco_libre"
|
||||
"cuanta memoria|memoria"
|
||||
"que temperatura hay|temperatura"
|
||||
"que procesos consumen mas|procesos_top"
|
||||
"cual es mi ip|red_ip"
|
||||
"cuanto lleva encendido|uptime"
|
||||
"busca el fichero README|buscar_fichero|README.md"
|
||||
"busca dentro JARVIS|grep_recursivo|JARVIS"
|
||||
"hazme una captura|captura_pantalla"
|
||||
"abre una terminal|terminal_abrir"
|
||||
"que peliculas tengo|videos_listar"
|
||||
"pon la pelicula screencast|pelicula_abrir|Screencast"
|
||||
"abre la carpeta de jarvis|abrir_carpeta|$RAIZ"
|
||||
)
|
||||
|
||||
dice() {
|
||||
[ "$MUDO" = si ] && return 0
|
||||
"$RAIZ/config/jarvis-voz.sh" "$TMPWAV" "$1" >/dev/null 2>&1 \
|
||||
|| JARVIS_PIPER_VOZ=es_ES-davefx-medium "$RAIZ/config/jarvis-piper.sh" "$TMPWAV" "$1" >/dev/null 2>&1
|
||||
[ -s "$TMPWAV" ] && { paplay "$TMPWAV" 2>/dev/null || aplay -q "$TMPWAV" 2>/dev/null; }
|
||||
}
|
||||
|
||||
campo() { # campo <id_accion> <clave>
|
||||
python3 -c "
|
||||
import json,sys
|
||||
d=json.load(open('$CATALOGO',encoding='utf-8'))
|
||||
for a in d.get('acciones', d if isinstance(d,list) else []):
|
||||
if a['id']==sys.argv[1]: print(a.get(sys.argv[2],'') or ''); break
|
||||
" "$1" "$2"
|
||||
}
|
||||
|
||||
for entrada in "${ORDENES[@]}"; do
|
||||
IFS='|' read -r frase accion argumento <<< "$entrada"
|
||||
comando=$(campo "$accion" comando)
|
||||
acuse=$(campo "$accion" acuse)
|
||||
respuesta=$(campo "$accion" respuesta)
|
||||
|
||||
if [ -z "$comando" ]; then
|
||||
printf '\n ── "%s" → accion %s NO EXISTE en el catalogo\n' "$frase" "$accion"
|
||||
continue
|
||||
fi
|
||||
|
||||
printf '\n ── tu dices: "%s"\n' "$frase"
|
||||
printf ' jarvis: %s\n' "${acuse:-...}"
|
||||
dice "${acuse:-Un momento}"
|
||||
|
||||
# sustituir el argumento igual que hace el motor
|
||||
real=${comando//\{argumento\}/$(printf '%q' "${argumento:-}")}
|
||||
salida=$(timeout 30 bash -lc "$real" 2>&1 | head -6)
|
||||
|
||||
if [ -n "$salida" ]; then
|
||||
printf ' resultado: %s\n' "$(echo "$salida" | head -1 | cut -c1-100)"
|
||||
echo "$salida" | tail -n +2 | sed 's/^/ /' | cut -c1-100
|
||||
else
|
||||
printf ' resultado: (hecho, sin salida que enseñar)\n'
|
||||
fi
|
||||
|
||||
# decir la respuesta con la plantilla, si la tiene y es corta
|
||||
if [ -n "$respuesta" ] && [ -n "$salida" ]; then
|
||||
ultima=$(echo "$salida" | tail -1)
|
||||
hablado=${respuesta//\{ultima\}/$ultima}
|
||||
hablado=${hablado//\{salida\}/$ultima}
|
||||
case "$hablado" in
|
||||
*"{"*) ;; # plantilla con campos que no sabemos
|
||||
*) [ ${#hablado} -lt 160 ] && { printf ' jarvis: %s\n' "$hablado"; dice "$hablado"; };;
|
||||
esac
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
printf '\n ── fin de la demostracion\n'
|
||||
Loading…
Add table
Add a link
Reference in a new issue