aboutsummaryrefslogtreecommitdiffstats
path: root/Cargo.toml
diff options
context:
space:
mode:
authorelvis <elvis@claros.ar>2026-09-06 19:21:16 -0300
committerelvis <elvis@claros.ar>2026-09-06 19:23:37 -0300
commitf8f98e83481e7376a235fb305a095552433f79ab (patch)
tree6d0ecddb26bef8430a086431de40f8ce9b1039e6 /Cargo.toml
downloadasist-p-f8f98e83481e7376a235fb305a095552433f79ab.tar.gz
asist-p-f8f98e83481e7376a235fb305a095552433f79ab.zip
Local voice assistant on top of Canary, llama.cpp and qwentts
Pipeline en Rust de hilos y canales que une los tres motores: el micrófono alimenta un segmentador con VAD, las intervenciones cerradas van al reconocedor, la transcripción al modelo y cada frase que este cierra sale hacia el sintetizador sin esperar al resto de la respuesta. Dos reglas sostienen el diseño: ninguna etapa bloquea a la anterior —quien va sobrado descarta trabajo en lugar de acumular retraso— y todo lo que viaja por los canales lleva el turno al que pertenece, así que interrumpir es subir el contador y levantar dos banderas de cancelación. Seis crates: core (configuración, eventos, HTTP, telemetría, herramientas), audio (cpal, VAD, anillo de reproducción), asr, llm, tts y app (supervisor de procesos y orquestador). Los motores van como submódulos fijados a un commit, con los cambios locales en vendor/patches. Midiendo el pipeline aparecieron tres cuellos de botella de configuración que valieron más que cualquier cambio de código, todos documentados en docs/RENDIMIENTO.md: - tts-server decodificaba el audio en bloques de 24 s, de modo que el modo «streaming» llegaba de una pieza: 4948 ms -> 585 ms hasta el primer audio. - La plantilla de chat del modelo abre <think> y no lo cierra nunca, sin variable que lo apague: 8630 ms -> 413 ms hasta el primer token, con una copia de la plantilla que deja el bloque cerrado de entrada. - Cualquier indicación de estilo junto a la guía de herramientas hace que este modelo de 2B deje de llamarlas y se invente el dato (8/8 aciertos con la guía sola, 0/8 con la persona de asistente de voz). El turno alterna ahora entre dos instrucciones de sistema. La ejecución de órdenes del sistema queda implementada y apagada, tras cuatro barreras: lista blanca sobre el ejecutable, rutas rechazadas, sin shell que interprete metacaracteres y plazo máximo. 68 pruebas unitarias sin modelos, más seis de integración que se saltan solas si no hay servidores y se turnan la GPU: en paralelo, los dos servidores no caben en 4 GB y miden contención en vez de latencia. Claude-Session: https://claude.ai/code/session_01FNxz5cSdQSscJH9H7b8uGU
Diffstat (limited to 'Cargo.toml')
-rw-r--r--Cargo.toml58
1 files changed, 58 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..1ef3f34
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,58 @@
+[workspace]
+resolver = "2"
+members = [
+ "crates/asist-core",
+ "crates/asist-audio",
+ "crates/asist-asr",
+ "crates/asist-llm",
+ "crates/asist-tts",
+ "crates/asist-app",
+]
+# Los submódulos son dependencias por ruta, no miembros del workspace: sin esto
+# cargo los adopta por estar dentro del directorio, y `cargo test` acabaría
+# ejecutando las pruebas de integración de canary-rs, que esperan un modelo en
+# su propia ruta por defecto y fallan aquí.
+exclude = ["vendor"]
+
+[workspace.package]
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.85"
+license = "MIT"
+repository = "https://github.com/elvis/asist-p"
+
+[workspace.dependencies]
+asist-core = { path = "crates/asist-core" }
+asist-audio = { path = "crates/asist-audio" }
+asist-asr = { path = "crates/asist-asr" }
+asist-llm = { path = "crates/asist-llm" }
+asist-tts = { path = "crates/asist-tts" }
+
+canary-rs = { path = "vendor/canary-rs", default-features = false, features = ["cpu", "ort-defaults"] }
+# canary-rs pide "2.0.0-rc.12", que en semver de prelanzamientos también admite
+# rc.13 — y ahí el módulo CoreML pasó a estar tras una feature, así que sus
+# reexportaciones incondicionales dejan de compilar. Se fija la versión contra
+# la que canary-rs se construye de verdad.
+ort = "=2.0.0-rc.12"
+
+anyhow = "1"
+base64 = "0.22"
+cpal = "0.17"
+crossbeam-channel = "0.5"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+thiserror = "2"
+toml = "0.8"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
+
+[profile.release]
+opt-level = 3
+lto = "thin"
+codegen-units = 1
+debug = 1 # keep frame pointers/line info: perf profiling of the audio path needs them
+
+# The pipeline is unusable in a debug build (Canary decodes ~10x slower), so the
+# heavy dependencies are optimised even when the workspace itself is not.
+[profile.dev.package."*"]
+opt-level = 3