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
114
config/recorrido.sh
Executable file
114
config/recorrido.sh
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env bash
|
||||
# Recorre el catalogo grupo por grupo, en voz alta y a ritmo de mirar.
|
||||
#
|
||||
# Distinto de demo_en_directo.sh: aquel probaba once acciones sueltas; este
|
||||
# recorre TODOS los grupos con una muestra representativa de cada uno, anuncia
|
||||
# el grupo antes de entrar, y deja pausas para que se pueda seguir en pantalla.
|
||||
#
|
||||
# Lo destructivo y lo que pide root no se ejecuta: en uso normal eso pasa por
|
||||
# un dialogo que aprueba una persona.
|
||||
#
|
||||
# ./recorrido.sh todo, con voz
|
||||
# ./recorrido.sh --mudo sin voz
|
||||
# ./recorrido.sh sistema solo un grupo
|
||||
set -uo pipefail
|
||||
RAIZ=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)
|
||||
CATALOGO=$RAIZ/newelle/data/acciones/acciones.json
|
||||
MUDO=no; SOLO=""
|
||||
for a in "$@"; do
|
||||
case "$a" in --mudo) MUDO=si;; *) SOLO=$a;; esac
|
||||
done
|
||||
WAV=$(mktemp --suffix=.wav); trap 'rm -f "$WAV"' EXIT
|
||||
|
||||
dice() {
|
||||
[ "$MUDO" = si ] && { sleep 0.4; return 0; }
|
||||
"$RAIZ/config/jarvis-voz.sh" "$WAV" "$1" >/dev/null 2>&1
|
||||
# < /dev/null: si no, se comen la entrada del bucle que los llama
|
||||
[ -s "$WAV" ] && { paplay "$WAV" </dev/null 2>/dev/null || aplay -q "$WAV" </dev/null 2>/dev/null; }
|
||||
}
|
||||
|
||||
campo() { 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"; }
|
||||
|
||||
# grupo|id|frase que se diria|argumento
|
||||
RECORRIDO='
|
||||
sistema|disco_libre|cuanto espacio queda|
|
||||
sistema|memoria|cuanta memoria|
|
||||
sistema|temperatura|que temperatura hay|
|
||||
sistema|uptime|cuanto lleva encendido|
|
||||
sistema|procesos_top|que esta consumiendo|
|
||||
sistema|red_ip|cual es mi ip|
|
||||
sistema|red_wifi|a que wifi estoy conectado|
|
||||
sistema|gpu_procesos|que usa la grafica|
|
||||
sistema|pantallas|cuantas pantallas hay|
|
||||
sistema|captura_pantalla|hazme una captura|
|
||||
sistema|terminal_abrir|abre una terminal|
|
||||
sistema|videos_listar|que peliculas tengo|
|
||||
ficheros|buscar_fichero|busca el fichero README|README.md
|
||||
ficheros|grep_recursivo|busca la palabra JARVIS|JARVIS
|
||||
ficheros|tamano_carpeta|cuanto ocupa la carpeta config|'"$RAIZ"'/config
|
||||
ficheros|descargas_listar|que hay en descargas|
|
||||
oasis|oasis_corriendo|esta oasis funcionando|
|
||||
oasis|oasis_conexiones|cuantos pubs hay conectados|
|
||||
pentest|mis_puertos|que puertos tengo abiertos yo|
|
||||
ventanas|ventanas_listar|que ventanas tengo abiertas|
|
||||
ventanas|ventana_izquierda|pon la ventana a la izquierda|
|
||||
ventanas|ventana_derecha|manda la ventana a la derecha|
|
||||
ventanas|ventana_centrar|centra la ventana activa|
|
||||
ventanas|ventana_maximizar|maximiza la ventana activa|
|
||||
ventanas|ventana_restaurar|restaura la ventana activa|
|
||||
ventanas|ventana_a_pantalla|manda la ventana a la pantalla uno|uno
|
||||
'
|
||||
|
||||
grupo_actual=""
|
||||
n=0
|
||||
while IFS='|' read -r -u 3 grupo id frase argumento; do
|
||||
[ -z "${grupo:-}" ] && continue
|
||||
[ -n "$SOLO" ] && [ "$SOLO" != "$grupo" ] && continue
|
||||
|
||||
if [ "$grupo" != "$grupo_actual" ]; then
|
||||
grupo_actual=$grupo
|
||||
printf '\n\n\033[1m ══ grupo: %s ══\033[0m\n' "$grupo"
|
||||
dice "Grupo $grupo, señor."
|
||||
sleep 0.6
|
||||
fi
|
||||
|
||||
comando=$(campo "$id" comando)
|
||||
[ -z "$comando" ] && { printf ' (%s no existe en el catalogo)\n' "$id"; continue; }
|
||||
acuse=$(campo "$id" acuse)
|
||||
plantilla=$(campo "$id" respuesta)
|
||||
|
||||
n=$((n+1))
|
||||
printf '\n %2d. tu: "%s"\n' "$n" "$frase"
|
||||
printf ' jarvis: %s\n' "$acuse"
|
||||
dice "$acuse"
|
||||
|
||||
real=${comando//\{argumento\}/$(printf '%q' "${argumento:-}")}
|
||||
salida=$(timeout 40 bash -lc "$real" </dev/null 2>&1 | head -6)
|
||||
|
||||
if [ -n "$salida" ]; then
|
||||
echo "$salida" | sed 's/^/ /' | cut -c1-104
|
||||
else
|
||||
printf ' (hecho, sin salida)\n'
|
||||
fi
|
||||
|
||||
# decir la respuesta si la plantilla se puede resolver
|
||||
if [ -n "$plantilla" ] && [ -n "$salida" ]; then
|
||||
ultima=$(echo "$salida" | tail -1); primera=$(echo "$salida" | head -1)
|
||||
lineas=$(echo "$salida" | wc -l)
|
||||
h=${plantilla//\{ultima\}/$ultima}; h=${h//\{primera\}/$primera}
|
||||
h=${h//\{lineas\}/$lineas}; h=${h//\{salida\}/$salida}
|
||||
case "$h" in
|
||||
*"{"*) ;;
|
||||
*) [ ${#h} -lt 170 ] && { printf ' jarvis: %s\n' "$h"; dice "$h"; };;
|
||||
esac
|
||||
fi
|
||||
sleep 1.5
|
||||
done 3<<< "$RECORRIDO"
|
||||
|
||||
printf '\n\n ── %d acciones mostradas ──\n' "$n"
|
||||
dice "Recorrido terminado, señor."
|
||||
Loading…
Add table
Add a link
Reference in a new issue