aboutsummaryrefslogtreecommitdiffstats
path: root/README.es.md
diff options
context:
space:
mode:
authorelvis <elvis@claros.ar>2026-09-26 20:20:19 -0300
committerelvis <elvis@claros.ar>2026-09-26 20:20:19 -0300
commit8518a63f55153e7f45fd49ad6caff5555f4e374f (patch)
tree636684eea3fa6f35d78282ab95eb687ef49154af /README.es.md
parent69de76dc9cbedc6092d1e5ce84094a8030de1470 (diff)
downloadasist-p-8518a63f55153e7f45fd49ad6caff5555f4e374f.tar.gz
asist-p-8518a63f55153e7f45fd49ad6caff5555f4e374f.zip
Translate code, comments, logs and terminal UI to English; add English README; rename scriptsHEADmain
Diffstat (limited to 'README.es.md')
-rw-r--r--README.es.md217
1 files changed, 217 insertions, 0 deletions
diff --git a/README.es.md b/README.es.md
new file mode 100644
index 0000000..3bd21ac
--- /dev/null
+++ b/README.es.md
@@ -0,0 +1,217 @@
+# asist-p — asistente de voz local
+
+[English](README.md)
+
+Escucha por el micrófono, piensa y contesta hablando. Todo corre en la
+máquina; sólo la búsqueda en internet, que es opcional, sale a la red.
+
+Une tres motores que ya existían —**Canary** para oír, **llama.cpp** para
+pensar y **qwentts.cpp** para hablar— en un pipeline de hilos y canales en
+Rust donde ninguna etapa espera a la siguiente.
+
+```
+ micrófono ──muestras──> segmentador ──intervención──> ASR ──texto──┐
+ (cpal, tiempo real) (VAD, turnos) (Canary) │
+ v
+ altavoz <──muestras── síntesis <──frases── conversación <──────────┘
+ (cpal, anillo) (qwentts) (llama.cpp + herramientas)
+```
+
+Cada caja es un hilo; cada flecha, un canal. Dos decisiones sostienen el
+resto:
+
+- **Nada bloquea al que va delante.** El micrófono nunca espera al
+ reconocedor, y el modelo nunca espera al sintetizador. Quien va sobrado
+ descarta trabajo en lugar de acumular retraso.
+- **Se responde por frases, no por respuestas.** Cada frase sale hacia el
+ sintetizador en cuanto se cierra, así que el asistente empieza a hablar
+ mientras el modelo sigue escribiendo. Es lo que separa medio segundo de
+ cinco.
+
+## Puesta en marcha
+
+```bash
+git clone --recursive https://git.all.ar/pub/asist-p.git && cd asist-p
+scripts/bootstrap.sh # submódulos, parches, binarios y modelos
+cargo run --release -- check # comprueba que está todo en su sitio
+cargo run --release -- run # a hablar
+```
+
+`bootstrap.sh` es idempotente y no copia modelos: los enlaza desde donde ya
+estén (`~/GIT-MIRRO`, `~/HF`). Si no encuentra los motores construidos, los
+construye, y eso sí tarda.
+
+```bash
+cargo run --release -- devices # listar dispositivos de audio
+cargo run --release -- run --barge-in # permitir cortar al asistente
+cargo run --release -- run --shell # habilitar órdenes del sistema
+cargo run --release -- run --no-manage # no lanzar los servidores
+```
+
+Durante el desarrollo conviene dejar los servidores levantados aparte —cargar
+los modelos cuesta más de un minuto— y reiniciar sólo el binario de Rust:
+
+```bash
+scripts/servers.sh start
+cargo run --release -- run --no-manage
+```
+
+## Cómo está organizado
+
+| Crate | De qué se ocupa |
+|---|---|
+| `asist-core` | Configuración, eventos, errores, cliente HTTP, telemetría y el registro de herramientas |
+| `asist-audio` | Captura y reproducción con cpal, detección de voz, troceado en turnos |
+| `asist-asr` | Canary en ONNX: ventana deslizante y transcripción final |
+| `asist-llm` | llama-server: streaming SSE, historial, llamadas a herramientas |
+| `asist-tts` | qwentts: síntesis en streaming y voces clonadas |
+| `asist-tools` | Buscar en internet, mirar por la cámara y ver la pantalla |
+| `asist-app` | Supervisor de procesos, orquestador y binario `asistente` |
+
+Los tres motores viven en `vendor/` como submódulos fijados a un commit
+concreto. Los cambios locales sobre ellos están en `vendor/patches/`, y
+`bootstrap.sh` los aplica: sin ellos el reconocedor no se comporta como el
+que se midió.
+
+## Configuración
+
+Todo está en [`config/asistente.toml`](config/asistente.toml), comentado. Los
+valores que llevan una cifra en el comentario salen de una medición concreta,
+no de una suposición; el detalle está en
+[docs/RENDIMIENTO.md](docs/RENDIMIENTO.md).
+
+Lo que más se toca:
+
+```toml
+[vad]
+silence_hold = 0.8 # cuánto silencio cierra tu intervención
+barge_in = false # cortar al asistente hablando encima
+
+[general]
+history_turns = 8 # memoria de la conversación
+system_prompt = "..." # carácter y estilo
+
+[tools]
+shell = false # ejecutar órdenes del sistema
+```
+
+## Interrumpir y el eco del altavoz
+
+Por defecto el asistente es **media dúplex**: mientras habla, el micrófono
+está cerrado. No es pereza: con altavoces abiertos el micrófono se oye a sí
+mismo, el asistente se transcribe y se responde solo.
+
+Con auriculares, `--barge-in` deja hablar encima para cortarlo. El umbral se
+eleva (`vad.barge_in_factor`) para que el eco no baste y una voz de verdad sí.
+
+## Latencia
+
+Un turno real, medido de punta a punta:
+
+| Etapa | Tiempo |
+|---|---|
+| Reconocimiento (2,5 s de voz) | 200 ms |
+| Modelo, primer token | 1660 ms |
+| Modelo, resto | 1362 ms |
+| Herramientas | 1 ms |
+| **Del final de tu frase al primer audio** | **3213 ms** |
+
+El binario mide esto en cada turno y señala la etapa más lenta. Tres ajustes
+de configuración valieron más que cualquier cambio de código:
+
+- El TTS decodificaba en bloques de 24 s: **4948 ms → 585 ms** al primer audio.
+- La plantilla del modelo dejaba `<think>` abierto: **8630 ms → 413 ms** al
+ primer token.
+- El prompt de estilo anulaba las llamadas a herramientas: **0/8 → 8/8**.
+- La cámara capturaba a 720p: **7,8 s → 2,9 s** por imagen a 640x480.
+- Las herramientas se ejecutaban en silencio: **~8,4 s → 4,1 s** hasta oír algo.
+- La pantalla a 640 px inventaba el texto: **1 de 3 aciertos → 3 de 3** a 1280 px.
+
+Todos, con el porqué y cómo se midieron, en
+[docs/RENDIMIENTO.md](docs/RENDIMIENTO.md).
+
+## Herramientas
+
+El asistente puede llamar a funciones. Vienen cuatro:
+
+| Herramienta | Qué hace | Coste medido |
+|---|---|---|
+| `hora_actual` | Fecha y hora del sistema | 0 ms |
+| `buscar_en_internet` | Busca y resume | 0,5–3,6 s |
+| `mirar_por_la_camara` | Hace una foto y responde sobre lo que ve | 4,1–5,2 s |
+| `mirar_la_pantalla` | Captura la pantalla y responde sobre lo que hay | 7,6–12,4 s |
+| `ejecutar_comando` | Órdenes del sistema, **apagada** por defecto | — |
+
+Mientras una herramienta trabaja, el asistente dice «Déjame que lo busque» o
+«Voy a mirar». No es adorno: sin eso el turno pasa seis segundos en silencio y
+se lee como un cuelgue. Con el acuse, el primer audio llega en 3–4 s.
+
+**Buscar** admite tres buscadores: `tavily` (con clave, devuelve una respuesta
+ya redactada), `ddgs` (sin clave, la misma librería que hay bajo
+`duckduckgo-mcp`) y `searxng`. El de comando ejecuta un guion que escriba JSON,
+así que meter otro es escribir un guion, no tocar Rust.
+
+**Ver** —cámara y pantalla— aprovecha que el servidor ya carga el proyector
+multimodal: el mismo modelo que conversa describe la imagen. Ni la foto ni la
+captura se guardan en disco, y no entran en el historial.
+
+La pantalla usa 1280 px y la cámara 640, y la diferencia importa: una escena se
+entiende, pero un texto hay que leerlo. Medido, a 640 px el modelo no dice que
+no lee la pantalla, **se inventa lo que pone** —contestó que la reunión era «a
+las 10:00» cuando ponía 15:30—. Por eso el triple de coste.
+
+`ejecutar_comando` está apagada a conciencia: darle una shell a un modelo que
+obedece a lo que oye por el micrófono es un cambio de postura de seguridad.
+Cuando se enciende, sólo pasan las órdenes de una lista blanca, sin shell que
+interprete metacaracteres y con un plazo máximo.
+
+Añadir una propia son unas veinte líneas:
+[docs/EXTENDER.md](docs/EXTENDER.md).
+
+## Pruebas
+
+Más de cien pruebas unitarias que no necesitan ni modelos ni micrófono, y
+pruebas de integración contra los servidores de verdad.
+
+```bash
+cargo test # unitarias, sin modelos
+scripts/servers.sh start
+cargo test --release -p asist-app --test integration -- --nocapture
+cargo test --release -p asist-app --test integration -- --ignored # bucle completo
+```
+
+Las de integración se saltan solas si no hay servidores escuchando, y se
+turnan la GPU con un mutex: los dos servidores comparten una tarjeta de 4 GB y
+en paralelo miden contención en vez de latencia.
+
+La prueba marcada `--ignored` cierra el bucle sin micrófono: sintetiza una
+frase y comprueba que el reconocedor la recupera.
+
+## Requisitos
+
+- Rust 1.85 o posterior
+- CUDA para los motores en C++ (funcionan en CPU, pero muy justos)
+- PipeWire o ALSA
+- ~6 GB de disco para los modelos
+- `ffmpeg` para la cámara y para reducir las capturas
+- Para la pantalla: `grim` (Wayland) o `maim`/ImageMagick (X11)
+- Para buscar: una clave de Tavily en `$TAVILY_API_KEY`, o `uv tool install ddgs`
+
+## Voz
+
+El repositorio no trae ninguna voz clonada: una voz es de alguien. Para que el
+asistente hable con una, grabá unos segundos de audio con su transcripción y
+extraé los latentes:
+
+```bash
+scripts/clone-voice.sh grabacion.wav transcripcion.txt
+```
+
+Quedan en `assets/voices/` (fuera de git). Sin voz clonada, quitá la sección
+`[tts.reference]` de `config/asistente.toml` y el asistente usa una voz del
+propio modelo.
+
+## Licencia
+
+MIT
+