Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
sito
28a6a6e935 azul: la captura del panel real en vez de la imagen de ejemplo
La que habia era la promocional de Newelle, con un proveedor en la nube en la
barra de titulo y ningun rastro de JARVIS. Ahora es el panel a pantalla
completa corriendo en local: reactor, estado de la maquina, catalogo de
acciones y las tarjetas de lo hecho. Las rutas de los resultados van
desenfocadas, como en las del carril verde.
2026-08-18 12:08:06 +02:00
sito
38a8daf9ab carril azul (Newelle): documentacion, diagrama y captura
Rama JARVIS-BLUE, independiente de master. Documenta el primer carril de JARVIS,
montado sobre Newelle (GNOME, GPL) y hoy congelado en favor del nucleo naranja.

- README propio del carril azul con diagrama de arquitectura y captura del interfaz.
- azul/docs/: el grafico (tema azul) y la captura de Newelle.
- Explica el stack, lo que JARVIS puso encima y por que se congelo.
2026-08-18 11:37:21 +02:00
3 changed files with 121 additions and 168 deletions

200
README.md
View file

@ -1,184 +1,48 @@
# JARVIS # JARVIS-AZUL 🔵
Asistente de voz **100 % local** para Linux. Ni el micrófono, ni las El **primer** carril de JARVIS, montado sobre **[Newelle](https://github.com/qwersyk/Newelle)** (el asistente de escritorio para GNOME, GPL). Hoy está **congelado**: sirvió para arrancar rápido y aprender qué se quería, y esas lecciones dieron pie al núcleo naranja. Esta rama lo documenta; el `master` es el núcleo naranja.
conversaciones, ni el modelo salen de la máquina. Sin cuentas, sin claves, sin
nube. Núcleo propio, en castellano, que corre en **cualquier Linux** —de un
portátil modesto a una torre— y aprovecha la GPU si la hay, o la CPU si no.
![Linux](https://img.shields.io/badge/Linux-cualquier%20distro-FCC624?logo=linux&logoColor=black) ![Arquitectura del carril azul](azul/docs/arquitectura.svg)
![Python](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)
![Ollama](https://img.shields.io/badge/Ollama-qwen3.5%3A4b-000000?logo=ollama&logoColor=white)
![GPU](https://img.shields.io/badge/GPU-opcional%20(NVIDIA%2FAMD%2FCPU)-76B900)
![whisper.cpp](https://img.shields.io/badge/whisper.cpp-STT-555555)
![Piper](https://img.shields.io/badge/Piper-TTS-555555)
![License](https://img.shields.io/badge/licencia-GPL--3.0-blue)
![Arquitectura de JARVIS](docs/stack.svg) ## Para qué sirvió
![El panel de JARVIS](docs/panel.png) JARVIS tiene tres carriles: **azul** (Newelle, este, congelado), **naranja** (el núcleo propio) y **verde** (Hermes Agent). El azul fue el punto de partida: en vez de escribir un asistente desde cero, se cogió Newelle —una app de GNOME que ya trae chat con LLM local, RAG de documentos, memoria, TTS, búsqueda web y extensiones— y se le puso encima la identidad de JARVIS.
*El panel: telemetría del sistema, el reactor, lo que oye y hace, el catálogo de Fue la forma más rápida de tener algo que funcionara y, sobre todo, de **descubrir qué faltaba**. Lo que se aprendió aquí es lo que define hoy al naranja.
acciones, y las métricas de rendimiento del propio asistente. Hay un
[vídeo de ejemplo](docs/demo.webm) (47 s) en `docs/`.* ## El interfaz
![El panel del carril azul](azul/docs/panel.png)
*El panel a pantalla completa: el reactor, el estado de la máquina a la izquierda, el catálogo de acciones a la derecha y las tarjetas de lo ya hecho. Todo en local —Ollama en `127.0.0.1`—. Las rutas de los resultados van tapadas.*
## El stack ## El stack
| Capa | Pieza | Papel | | Capa | Pieza | Licencia | ¿Nube? |
|---|---|---| |---|---|---|---|
| Oír | whisper.cpp | STT en castellano (GPU si hay, si no CPU) | | Front-end | Newelle (GNOME, Flatpak) | GPL | no |
| Pensar | Ollama · `qwen3.5:4b` | el cerebro, con tool-calling | | Cerebro | Ollama · modelo `qwen` local | Apache-2.0 | **no**`127.0.0.1` |
| Saber | model2vec + búsqueda híbrida | RAG sobre los apuntes del usuario | | Hablar | Piper (voz clonada) | MIT | **no** |
| Hablar | Piper (o voz clonada con XTTS) | TTS local | | Oír | Whisper local | MIT | **no** |
| Cara | panel web · WebSocket · Canvas | el HUD, con el reactor y las métricas | | Saber | Documentos locales de Newelle (RAG) | — | **no** |
| Manos | catálogo de acciones + shell | lo que ejecuta en la máquina |
Todo corre en `127.0.0.1`. No hay ninguna llamada a la nube en el uso normal; lo ## Lo que JARVIS le puso encima
único que puede salir es una búsqueda web si el modelo decide usarla, y se avisa.
## Portabilidad Newelle es genérico; JARVIS lo personalizó (los ficheros viven en `config/` del núcleo):
Diseñado para correr en **cualquier Linux**, no en un equipo concreto: - **Persona y prompt** propios (`set_persona.py`).
- **Voz** por Piper, la misma cadena de audio que usa el naranja (`jarvis-piper.sh`, `jarvis-voz.sh`).
- **Modelo** local afinado (`qwen3.5-4b-jarvis.Modelfile`, `apuntar_modelo_jarvis.py`).
- **Herramientas** propias.
- **Panel a pantalla completa** (`jarvis_full`): reactor, estado de la máquina,
catálogo de acciones y el registro de lo hecho, sin pasar por el chat.
| | | ## Por qué se congeló
|---|---|
| Distro | cualquiera. `install.sh` detecta apt / dnf / pacman / zypper |
| GPU | **opcional**. Ollama reparte el modelo entre GPU y CPU solo: va con NVIDIA (CUDA), AMD (ROCm) o **solo CPU**. Ningún parámetro está atado a una tarjeta |
| Escritorio | GNOME, KDE, lo que sea. Las acciones de **ventanas** necesitan X11 + `xdotool`; en Wayland esas órdenes se desactivan solas y el resto funciona igual |
| Audio | PipeWire, PulseAudio o ALSA. El micro prueba `pw-record`, `parec` y `arecord`, la primera que haya; la voz prueba `paplay`, `pw-play` y `aplay` |
| whisper | el binario se toma del build local o del `PATH`. Los modelos se buscan solos, o los fijas con `JARVIS_WHISPER_MODELOS=/ruta` |
**Requisito real:** que quepa el modelo. `qwen3.5:4b` va cómodo desde ~4 GB de Newelle es potente, pero va empaquetado como **Flatpak sobre GNOME**, y ese sandbox limita lo que el asistente puede tocar en la máquina. Se quería más: **control total del núcleo** —latencia baja, acciones rápidas que no pasan por el modelo, root gestionado a demanda, un panel que no dependa del ciclo de vida de la app—. Nada de eso encajaba bien dentro de la app de escritorio de otro.
VRAM; con menos, usa un modelo más pequeño (`qwen3.5:2b`) o tira de CPU (hay RAM
de sobra). whisper.cpp se compila para tu plataforma —CUDA, ROCm, Metal o CPU—;
la guía está en [`config/README_whisper_gpu.md`](config/README_whisper_gpu.md).
### Ajuste en tarjetas pequeñas (4 GB) Así que el azul se congeló y nació el **carril naranja**, un núcleo escrito a medida. El azul se queda como referencia y como reconocimiento: fue el que enseñó el camino.
Solo si vas MUY justo de VRAM y el cerebro y whisper se pelean por ella: fijar ---
`num_gpu 24` en el `Modelfile` reserva sitio a whisper. Está explicado en los
comentarios del propio `Modelfile`. En una torre con una tarjeta normal **no
hace falta tocar nada**.
## Instalación Newelle es de [@qwersyk](https://github.com/qwersyk/Newelle) (GPL). Este carril es esa base con la capa de JARVIS encima. Para el núcleo actual, ver la rama `master`; para el banco de pruebas agéntico, la rama `JARVIS-GREEN`.
Necesita, en la máquina: [Ollama](https://ollama.com), whisper.cpp (compilado
para tu plataforma, ver [`config/README_whisper_gpu.md`](config/README_whisper_gpu.md))
y [Piper](https://github.com/rhasspy/piper).
```bash
git clone https://gitea.laenre.net/hacklab/JARVIS.git
cd JARVIS
./install.sh # comprueba servicios, crea el venv y el modelo de Ollama
```
`install.sh` no descarga modelos pesados ni toca el sistema sin avisar: solo
prepara el entorno de Python y crea `qwen3.5:4b-jarvis` a partir del `Modelfile`.
Después:
```bash
./nucleo/saber/indexa.py # (opcional) indexa tus apuntes para el RAG
./nucleo/arranca.sh # el asistente y el panel, en 127.0.0.1
```
El RAG funciona nada más clonar: el repo trae un índice público pre-construido, así
que no hace falta indexar para que sepa de metodología, comandos y herramientas.
### Comprobar el RAG
Si la búsqueda de conocimiento no responde bien, este diagnóstico revisa la cadena
entera y marca en verde/rojo cada eslabón —dependencias, índice, embedder,
búsqueda y Ollama— con una línea de qué hacer si algo falla:
```bash
./probar_rag.sh # comprobaciones rápidas
./probar_rag.sh --eval # además mide la calidad de recuperación (hit@k)
./probar_rag.sh --verboso # enseña el primer resultado de cada búsqueda
```
No necesita nada arrancado y sale con código distinto de cero si hay algún fallo
duro, así que sirve también para CI.
## Qué le puedes pedir
Habla en castellano, natural. **150 acciones** en el catálogo, agrupadas:
| Grupo | Nº | Ejemplos |
|---|---|---|
| sistema | 59 | "cuánto espacio queda", "la memoria", "la carga de CPU", "la temperatura" |
| firefox | 54 | "abre el Gmail", "abre YouTube", "abre el GitHub", "abre Maps" |
| ventanas | 12 | "manda la ventana a la izquierda", "maximiza", "centra la ventana" |
| ficheros | 11 | "busca un fichero llamado…", "lee el fichero…", "cuánto ocupa la carpeta…" |
| pentest | 8 | "escanea la red", "los puertos del host…", "resuelve el dominio…", "el whois de…" |
| oasis | 6 | "está corriendo Oasis", "cuántas conexiones tiene" |
Si lo que pides no está en el catálogo, el modelo lo resuelve con un **comando de
shell** (de solo lectura por defecto). Y si pregunta *cómo* se hace algo técnico,
puede **buscar en tus apuntes** (RAG) antes de responder.
El RAG es lo que hace que el asistente dé el comando que **tú ya has probado** en
vez de inventarse los flags. Y no es un adorno: medido sobre un conjunto de
preguntas de pentesting, la recuperación sube de **hit@1 48 % → 82 %** y
**hit@5 77 % → 95 %**. El método, el pipeline y esos números están en
[docs/rag.md](docs/rag.md).
Y **JARVIS elige su propio cerebro**: si una pregunta es más dura de lo normal
puede cambiar a un modelo más potente (`elegir_modelo`), y volver al rápido para
lo simple. Dile "usa un modelo más potente" o fija uno con `JARVIS_MODELO`.
## Órdenes con root — importante
Algunas órdenes que gestionan el sistema (instalar un paquete, reiniciar un
servicio, montar un disco) necesitan `sudo`. Conviene saber cómo se maneja,
porque es donde un asistente de voz puede hacer daño:
- **No pide la contraseña al arrancar.** Molestar de entrada echa para atrás, y
la mayoría de lo que se le pide no necesita root. Arranca y funciona sin nada.
- **Se pide solo cuando hace falta, y una vez.** La primera vez que una orden
necesita `sudo`, aparece un diálogo pidiendo tu contraseña. La tecleas, la
repites, y a partir de ahí el permiso queda abierto para la sesión.
- **Caduca a los 15 minutos** de inactividad, y al cerrar el panel. No es un
"root para siempre".
- La contraseña **nunca se escribe en disco**: vive solo en la memoria del
proceso mientras dura la sesión, y se pasa a `sudo -S` por la entrada estándar.
- **La voz no puede autoaprobar root.** El permiso de sesión ahorra re-teclear
la contraseña, nunca salta el pedirla la primera vez.
Si prefieres el modo seguro (bloquear el panel y pedir la contraseña al abrir,
para que nadie que pase por delante dé órdenes), arranca con `--candado`.
## Privacidad
Es la premisa, y se verifica. Ver [PRIVACIDAD.md](PRIVACIDAD.md). Este
repositorio **no incluye** los apuntes indexados ni el diario de conversación:
son del usuario, y el `.gitignore` los bloquea.
## Estructura
```
nucleo/ el asistente (oido, cerebro, boca, manos, cara, saber)
config/ configuración: modelo, voz, whisper
voz/ clonado de voz con XTTS y caché de frases
entrena/ fine-tuning con QLoRA
install.sh el instalador
```
## Estado y limitaciones
Proyecto en desarrollo. En el radar: acabar de generalizar los scripts de `voz/`
(algunos aún asumen la disposición del autor), las acciones de ventanas sobre
**Wayland** (hoy solo X11), y el fine-tuning de `entrena/`, pendiente de un
ajuste para modelos multimodales.
## Contribuir
Se agradecen los commits: es software libre y hay mucho por hacer. Las ideas
acotadas están en [ROADMAP.md](ROADMAP.md) (más gestores de ventanas, más
acciones, probar otros modelos, el RAG...) y cómo empezar en
[CONTRIBUTING.md](CONTRIBUTING.md). No hay que compilar nada: es Python, bash y
una página web.
## Licencia
[GPL-3.0](LICENSE). Software libre y copyleft: si lo modificas y lo distribuyes,
el resultado sigue siendo libre.

View file

@ -0,0 +1,89 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1060 700" font-family="'DejaVu Sans',Verdana,sans-serif">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0a1c33"/><stop offset="1" stop-color="#071224"/>
</linearGradient>
<marker id="ar" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto">
<path d="M0,0 L7,3 L0,6 Z" fill="#38bdf8"/>
</marker>
</defs>
<rect width="1060" height="700" rx="16" fill="url(#bg)"/>
<rect x="1" y="1" width="1058" height="698" rx="16" fill="none" stroke="#1e3a5f" stroke-width="2"/>
<text x="40" y="52" fill="#eef4fb" font-size="30" font-weight="bold">JARVIS · carril azul</text>
<text x="40" y="78" fill="#38bdf8" font-size="16" font-weight="bold">Newelle</text>
<text x="140" y="78" fill="#7f9bbf" font-size="15">— el primer carril, sobre una app de escritorio GNOME</text>
<!-- sello congelado -->
<g transform="translate(830,38)">
<rect x="0" y="0" width="190" height="46" rx="10" fill="#12233d" stroke="#5b6b86" stroke-width="1.5"/>
<text x="16" y="22" fill="#a9c2e0" font-size="13" font-weight="bold">❄ CONGELADO</text>
<text x="16" y="39" fill="#6f8bb0" font-size="11">reemplazado por el naranja</text>
</g>
<!-- TU -->
<text x="40" y="128" fill="#7f9bbf" font-size="13" font-weight="bold" letter-spacing="1"></text>
<g>
<rect x="40" y="140" width="200" height="86" rx="10" fill="#0d2340" stroke="#22d3ee" stroke-width="1.5"/>
<text x="60" y="170" fill="#eef4fb" font-size="15" font-weight="bold">Voz y texto</text>
<text x="60" y="192" fill="#a9c2e0" font-size="12.5">en la ventana de Newelle</text>
<text x="60" y="210" fill="#7089aa" font-size="11.5">chat GTK · micrófono</text>
</g>
<!-- NEWELLE -->
<rect x="300" y="120" width="440" height="470" rx="14" fill="#0b2138" stroke="#38bdf8" stroke-width="2"/>
<text x="320" y="150" fill="#38bdf8" font-size="18" font-weight="bold">NEWELLE (GNOME)</text>
<text x="320" y="171" fill="#7f9bbf" font-size="12.5">app de escritorio · orquesta el asistente</text>
<text x="320" y="205" fill="#7dd3fc" font-size="13" font-weight="bold">Sus funciones (interruptores)</text>
<g fill="#0f2b47" stroke="#1d4166" font-size="11.5">
<rect x="320" y="214" width="188" height="26" rx="6"/><text x="330" y="231" fill="#cfe0f2">Documentos locales (RAG)</text>
<rect x="516" y="214" width="200" height="26" rx="6"/><text x="526" y="231" fill="#cfe0f2">Memoria de largo plazo</text>
<rect x="320" y="246" width="120" height="26" rx="6"/><text x="330" y="263" fill="#cfe0f2">TTS</text>
<rect x="448" y="246" width="268" height="26" rx="6"/><text x="458" y="263" fill="#cfe0f2">Virtualización de comandos</text>
<rect x="320" y="278" width="180" height="26" rx="6"/><text x="330" y="295" fill="#cfe0f2">Búsqueda web</text>
<rect x="508" y="278" width="208" height="26" rx="6"/><text x="518" y="295" fill="#cfe0f2">Extensiones (Python)</text>
</g>
<text x="320" y="340" fill="#7dd3fc" font-size="13" font-weight="bold">Lo que puso JARVIS encima</text>
<g font-size="11.5">
<rect x="320" y="349" width="188" height="26" rx="6" fill="#123350" stroke="#38bdf8"/><text x="330" y="366" fill="#bfe3fb">Persona + prompt propio</text>
<rect x="516" y="349" width="200" height="26" rx="6" fill="#123350" stroke="#38bdf8"/><text x="526" y="366" fill="#bfe3fb">Voz clonada (Piper)</text>
<rect x="320" y="381" width="188" height="26" rx="6" fill="#123350" stroke="#38bdf8"/><text x="330" y="398" fill="#bfe3fb">Modelo qwen local</text>
<rect x="516" y="381" width="200" height="26" rx="6" fill="#123350" stroke="#38bdf8"/><text x="526" y="398" fill="#bfe3fb">Herramientas propias</text>
</g>
<!-- por que se congelo -->
<rect x="320" y="430" width="396" height="142" rx="10" fill="#0e2036" stroke="#294a70" stroke-width="0"/>
<rect x="320" y="430" width="396" height="142" rx="10" fill="#0e2036" stroke="#294a70"/>
<text x="336" y="456" fill="#f0d488" font-size="13" font-weight="bold">Por qué se congeló</text>
<text x="336" y="480" fill="#b9cbe2" font-size="11.5">Newelle es potente y va sobre GNOME + Flatpak. Pero el</text>
<text x="336" y="498" fill="#b9cbe2" font-size="11.5">sandbox limita lo que el asistente puede tocar en la</text>
<text x="336" y="516" fill="#b9cbe2" font-size="11.5">máquina, y se quería control total del núcleo: latencia,</text>
<text x="336" y="534" fill="#b9cbe2" font-size="11.5">acciones rápidas sin pasar por el modelo, el HUD propio.</text>
<text x="336" y="558" fill="#7dd3fc" font-size="11.5" font-weight="bold">→ nació el carril naranja (núcleo a medida).</text>
<!-- EN TU MAQUINA -->
<text x="800" y="128" fill="#7f9bbf" font-size="13" font-weight="bold" letter-spacing="1">EN TU MÁQUINA</text>
<g>
<rect x="800" y="140" width="220" height="92" rx="10" fill="#0d2340" stroke="#22d3ee" stroke-width="1.5"/>
<text x="820" y="170" fill="#eef4fb" font-size="15" font-weight="bold">Cerebro</text>
<text x="820" y="192" fill="#a9c2e0" font-size="12.5">Ollama · qwen local</text>
<text x="820" y="211" fill="#7089aa" font-size="11.5">127.0.0.1 · sin nube</text>
</g>
<g>
<rect x="800" y="248" width="220" height="92" rx="10" fill="#0d2340" stroke="#22d3ee" stroke-width="1.5"/>
<text x="820" y="278" fill="#eef4fb" font-size="15" font-weight="bold">Voz</text>
<text x="820" y="300" fill="#a9c2e0" font-size="12.5">Piper (habla) · Whisper (oye)</text>
<text x="820" y="319" fill="#7089aa" font-size="11.5">local, la misma cadena de audio</text>
</g>
<g stroke="#38bdf8" stroke-width="2" fill="none" marker-end="url(#ar)">
<path d="M240,183 L296,220"/>
<path d="M740,186 L796,186"/>
<path d="M740,300 L796,294"/>
</g>
<text x="530" y="632" fill="#38bdf8" font-size="13" font-weight="bold" text-anchor="middle">Software libre (GPL) · corría 100 % en local</text>
<text x="530" y="656" fill="#7089aa" font-size="12" text-anchor="middle">el punto de partida: rápido de montar, con RAG, memoria y voz de serie</text>
<text x="530" y="680" fill="#546c8c" font-size="11" text-anchor="middle">la lección que se llevó el naranja: buenas ideas, pero el sandbox y la latencia pedían un núcleo propio</text>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
azul/docs/panel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB