From 8518a63f55153e7f45fd49ad6caff5555f4e374f Mon Sep 17 00:00:00 2001 From: elvis Date: Sat, 26 Sep 2026 20:20:19 -0300 Subject: Translate code, comments, logs and terminal UI to English; add English README; rename scripts --- README.es.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 README.es.md (limited to 'README.es.md') 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 `` 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 + -- cgit v1.2.3