aboutsummaryrefslogtreecommitdiffstats
path: root/crates/asist-core/src/config.rs
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 /crates/asist-core/src/config.rs
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 'crates/asist-core/src/config.rs')
-rw-r--r--crates/asist-core/src/config.rs271
1 files changed, 133 insertions, 138 deletions
diff --git a/crates/asist-core/src/config.rs b/crates/asist-core/src/config.rs
index c2a9d55..0a8cc04 100644
--- a/crates/asist-core/src/config.rs
+++ b/crates/asist-core/src/config.rs
@@ -1,5 +1,5 @@
-//! Configuración del asistente: un TOML con valores por defecto que ya
-//! incorporan lo aprendido midiendo el pipeline (ver `docs/RENDIMIENTO.md`).
+//! Assistant configuration: a TOML file whose defaults already include what
+//! was learned by measuring the pipeline (see `docs/RENDIMIENTO.md`).
use std::path::{Path, PathBuf};
@@ -26,32 +26,31 @@ pub struct Config {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct General {
- /// Idioma de la conversación; se propaga a ASR y TTS.
+ /// Conversation language; propagated to ASR and TTS.
pub language: String,
- /// Instrucción de sistema. Pide frases cortas y sin markdown a propósito:
- /// el TTS lee literalmente los asteriscos y las viñetas.
+ /// System prompt. It asks for short sentences without markdown on purpose:
+ /// the TTS reads asterisks and bullets literally.
pub system_prompt: String,
- /// Instrucción de sistema de la pasada en que el modelo decide si usar
- /// una herramienta.
+ /// System prompt for the pass where the model decides whether to use a
+ /// tool.
///
- /// Va aparte, y **sustituye** a `system_prompt` en esa pasada, por una
- /// razón medida y no por gusto: con Qwen3.5-2B, añadir cualquier
- /// indicación de estilo a esta guía —en cualquier posición, incluso dos
- /// palabras— hace que el modelo deje de llamar a las herramientas y se
- /// invente el dato. Medido sobre 8 intentos: la guía sola acierta 8/8;
- /// con «Responde breve.» detrás, 1/8; con la persona de asistente de voz,
- /// 0/8. Ver docs/RENDIMIENTO.md.
+ /// It is separate, and **replaces** `system_prompt` in that pass, for a
+ /// measured reason rather than taste: with Qwen3.5-2B, adding any style
+ /// instruction to this guide (in any position, even two words) makes the
+ /// model stop calling tools and make the data up. Measured over 8 tries:
+ /// the guide alone gets 8/8; with «Responde breve.» after it, 1/8; with the
+ /// voice-assistant persona, 0/8. See docs/RENDIMIENTO.md.
pub tools_prompt: String,
- /// Se añade a `system_prompt` para redactar la respuesta cuando una
- /// herramienta ya ha devuelto su resultado.
+ /// Appended to `system_prompt` to write the answer once a tool has
+ /// returned its result.
///
- /// Aquí sí se puede añadir estilo sin miedo —la llamada ya ocurrió—, y
- /// hace falta: sin esta orden el modelo anuncia lo que acaba de hacer en
- /// vez de contar lo que averiguó.
+ /// Here style can be added safely (the call already happened), and it is
+ /// needed: without this instruction the model announces what it just did
+ /// instead of telling what it found out.
pub tool_result_prompt: String,
- /// Turnos de historial que se envían al modelo (0 = sin memoria).
+ /// History turns sent to the model (0 = no memory).
pub history_turns: usize,
- /// Imprime un resumen de latencias por turno al terminar cada respuesta.
+ /// Prints a per-turn latency summary at the end of each answer.
pub report_latency: bool,
}
@@ -89,14 +88,14 @@ impl Default for General {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct AudioConfig {
- /// Nombre (o subcadena) del dispositivo de entrada; vacío = el de por defecto.
+ /// Name (or substring) of the input device; empty = the default one.
pub input_device: String,
- /// Ídem para la salida.
+ /// Same for the output.
pub output_device: String,
- /// Segundos de audio que la reproducción mantiene en cola antes de
- /// arrancar. Amortigua los baches del TTS sin añadir latencia perceptible.
+ /// Seconds of audio playback keeps queued before starting. It absorbs
+ /// TTS hiccups without adding noticeable latency.
pub playback_prebuffer: f32,
- /// Ganancia aplicada a la reproducción.
+ /// Gain applied to playback.
pub output_gain: f32,
}
@@ -114,28 +113,28 @@ impl Default for AudioConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct VadConfig {
- /// Ventana de audio por decisión del detector.
+ /// Audio window per detector decision.
pub frame_seconds: f32,
- /// Audio conservado antes del inicio de voz para no cortar la primera sílaba.
+ /// Audio kept before speech onset so the first syllable is not cut.
pub preroll_seconds: f32,
- /// Silencio que cierra una intervención.
+ /// Silence that ends an utterance.
pub silence_hold: f32,
- /// Intervención más corta que merezca una transcripción final.
+ /// Shortest utterance worth a final transcription.
pub min_utterance: f32,
- /// Corte forzado, que acota el coste de la decodificación final.
+ /// Forced cut, which bounds the cost of the final decode.
pub max_utterance: f32,
- /// Múltiplo del suelo de ruido a partir del cual se considera voz.
+ /// Multiple of the noise floor above which audio counts as speech.
pub threshold_factor: f32,
pub min_threshold: f32,
pub max_threshold: f32,
- /// Permite hablar encima del asistente para cortarlo.
+ /// Lets the user talk over the assistant to interrupt it.
///
- /// Desactivado por defecto: con altavoces abiertos el micrófono se oye a sí
- /// mismo y el asistente se interrumpe solo. Actívalo con auriculares o con
- /// cancelación de eco del sistema.
+ /// Off by default: with open speakers the microphone hears itself and the
+ /// assistant interrupts itself. Turn it on with headphones or with system
+ /// echo cancellation.
pub barge_in: bool,
- /// Con barge-in activo, cuánto más fuerte que el umbral normal debe sonar
- /// la voz para cortar. Sube el listón frente al eco del altavoz.
+ /// With barge-in on, how much louder than the normal threshold the voice
+ /// must be to interrupt. Raises the bar against speaker echo.
pub barge_in_factor: f32,
}
@@ -159,23 +158,23 @@ impl Default for VadConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct AsrConfig {
- /// Carpeta del modelo Canary en ONNX.
+ /// Directory of the Canary ONNX model.
pub model_dir: PathBuf,
pub source_lang: String,
pub target_lang: String,
- /// Ventana deslizante de las transcripciones provisionales.
+ /// Sliding window for the partial transcriptions.
pub window: f32,
- /// Avance de la ventana entre decodificaciones.
+ /// Window step between decodes.
pub step: f32,
- /// Ventanas que deben coincidir para dar una palabra por estable.
+ /// Windows that must agree for a word to be considered stable.
pub stability: usize,
- /// Emitir transcripciones provisionales. Cuestan CPU y sólo sirven para
- /// verlas en pantalla: el turno se dispara con la final.
+ /// Emit partial transcriptions. They cost CPU and are only there to be
+ /// shown on screen: the turn is triggered by the final one.
pub partials: bool,
- /// Carga una segunda instancia del modelo para que las decodificaciones
- /// finales no bloqueen a las provisionales. Duplica la memoria.
+ /// Loads a second model instance so final decodes do not block the
+ /// partial ones. Doubles the memory.
pub dedicated_final_model: bool,
- /// Proveedor de ejecución de ONNX Runtime: `cpu`, `cuda`, ...
+ /// ONNX Runtime execution provider: `cpu`, `cuda`, ...
pub execution_provider: String,
pub inter_threads: usize,
pub intra_threads: usize,
@@ -192,8 +191,8 @@ impl Default for AsrConfig {
stability: 2,
partials: true,
dedicated_final_model: false,
- // CPU a propósito: la GPU de 4 GB está ocupada por el hablante del
- // TTS, y disputársela sale más caro que decodificar en CPU.
+ // CPU on purpose: the 4 GB GPU is taken by the TTS talker, and fighting
+ // over it costs more than decoding on the CPU.
execution_provider: "cpu".into(),
inter_threads: 2,
intra_threads: 4,
@@ -213,7 +212,7 @@ pub struct LlmConfig {
pub min_p: f32,
pub repeat_penalty: f32,
pub max_tokens: u32,
- /// Vueltas máximas del bucle de herramientas antes de rendirse.
+ /// Maximum rounds of the tool loop before giving up.
pub max_tool_rounds: usize,
pub request_timeout_secs: u64,
}
@@ -229,8 +228,8 @@ impl Default for LlmConfig {
top_k: 40,
min_p: 0.1,
repeat_penalty: 1.1,
- // Una respuesta hablada larga cansa; el recorte también acota el
- // coste de la síntesis, que es la etapa lenta.
+ // A long spoken answer is tiring; the cap also bounds the cost of
+ // synthesis, which is the slow stage.
max_tokens: 300,
max_tool_rounds: 4,
request_timeout_secs: 120,
@@ -243,9 +242,9 @@ impl Default for LlmConfig {
pub struct TtsConfig {
pub host: String,
pub port: u16,
- /// Voz registrada en el servidor, o una del modelo.
+ /// Voice registered on the server, or one of the model's.
pub voice: String,
- /// Voz clonada que se registra al arrancar, si se define.
+ /// Cloned voice registered at startup, if defined.
pub reference: Option<ReferenceVoice>,
pub language: String,
pub temperature: f32,
@@ -253,9 +252,8 @@ pub struct TtsConfig {
pub top_p: f32,
pub repetition_penalty: f32,
pub max_new_tokens: u32,
- /// Sintetiza una frase corta al arrancar. La primera petición paga la
- /// construcción de los grafos: ~3,5 s que conviene no gastar en el
- /// primer turno real.
+ /// Synthesizes a short sentence at startup. The first request pays for
+ /// building the graphs: ~3.5 s better not spent on the first real turn.
pub warmup: bool,
pub request_timeout_secs: u64,
}
@@ -279,52 +277,51 @@ impl Default for TtsConfig {
}
}
-/// Latentes de una voz clonada, tal y como los produce `qwen-codec --talker`.
+/// Latents of a cloned voice, as produced by `qwen-codec --talker`.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReferenceVoice {
- /// Nombre con el que se registra en el servidor.
+ /// Name it is registered under on the server.
pub name: String,
- /// Embedding del hablante (`.spk`).
+ /// Speaker embedding (`.spk`).
pub speaker: PathBuf,
- /// Códigos de referencia (`.rvq`), que activan el clonado ICL.
+ /// Reference codes (`.rvq`), which enable ICL cloning.
pub codes: PathBuf,
- /// Transcripción de la referencia (`.txt`).
+ /// Transcript of the reference (`.txt`).
pub transcript: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ToolsConfig {
- /// Deja que el modelo llame a herramientas.
+ /// Lets the model call tools.
pub enabled: bool,
- /// Usa `general.tools_prompt` en solitario para la pasada en que el
- /// modelo decide si llamar a una herramienta, y `general.system_prompt`
- /// sólo para redactar la respuesta hablada.
+ /// Uses `general.tools_prompt` alone for the pass where the model decides
+ /// whether to call a tool, and `general.system_prompt` only to write the
+ /// spoken answer.
///
- /// Es lo único que hace que las herramientas funcionen de verdad con este
- /// modelo (ver `tools_prompt`), a cambio de que las respuestas que no
- /// usan herramienta pierdan la guía de estilo. Se compensa en parte
- /// porque el limpiador de texto quita el markdown antes de hablar.
- /// Ponlo a `false` para priorizar el estilo sobre las herramientas.
+ /// It is the only thing that makes tools really work with this model (see
+ /// `tools_prompt`), at the cost of answers that use no tool losing the
+ /// style guide. That is partly offset by the text cleaner removing
+ /// markdown before speaking. Set it to `false` to favour style over tools.
pub dedicated_prompt: bool,
- /// Pronuncia una frase corta al empezar una herramienta lenta, para que la
- /// espera no se confunda con un cuelgue.
+ /// Says a short sentence when a slow tool starts, so the wait is not
+ /// mistaken for a hang.
pub spoken_ack: bool,
- /// Habilita la herramienta de ejecución de órdenes del sistema.
+ /// Enables the tool that runs system commands.
///
- /// Apagada por defecto 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, no una opción de comodidad.
+ /// Off by default on purpose: giving a shell to a model that obeys what
+ /// it hears through the microphone is a change of security posture, not a
+ /// convenience option.
pub shell: bool,
- /// Órdenes admitidas, comparadas contra el ejecutable (argv[0]).
- /// Una lista vacía deniega todo aunque `shell` esté activo.
+ /// Allowed commands, matched against the executable (argv[0]).
+ /// An empty list denies everything even if `shell` is on.
pub shell_allowlist: Vec<String>,
- /// Segundos que puede durar una orden antes de que se la mate.
+ /// Seconds a command may run before it is killed.
pub shell_timeout_secs: u64,
- /// Registra la orden pero no la ejecuta. Útil para estrenar la lista blanca.
+ /// Logs the command but does not run it. Useful to break in the allowlist.
pub shell_dry_run: bool,
- /// Directorio de trabajo de las órdenes; vacío = el del proceso.
+ /// Working directory of the commands; empty = the process one.
pub shell_working_dir: String,
}
@@ -349,29 +346,28 @@ impl Default for ToolsConfig {
}
}
-/// Búsqueda en internet.
+/// Web search.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct SearchConfig {
pub enabled: bool,
- /// `tavily` (necesita clave), `ddgs` (sin clave) o `searxng` (necesita
- /// una instancia propia).
+ /// `tavily` (needs a key), `ddgs` (no key) or `searxng` (needs your own
+ /// instance).
pub backend: String,
- /// Variable de entorno de la que se lee la clave.
+ /// Environment variable the key is read from.
///
- /// La clave se lee del entorno y no del fichero a propósito: la
- /// configuración se versiona y se comparte, y un secreto ahí dentro acaba
- /// en el historial de git.
+ /// The key comes from the environment and not from the file on purpose:
+ /// the configuration is versioned and shared, and a secret in it ends up in
+ /// the git history.
pub api_key_env: String,
- /// URL base de la instancia de SearXNG.
+ /// Base URL of the SearXNG instance.
pub base_url: String,
- /// Programa que ejecuta el backend `ddgs`, con sus argumentos.
+ /// Program that runs the `ddgs` backend, with its arguments.
///
- /// `{consulta}` y `{max}` se sustituyen antes de ejecutar. Tiene que
- /// escribir JSON por la salida estándar; se admiten tanto la lista suelta
- /// que devuelve ddgs como la forma `{answer, results}`. Cualquier otro
- /// programa que respete eso sirve igual, incluido un puente a un servidor
- /// MCP.
+ /// `{query}` and `{max}` are substituted before running. It must write
+ /// JSON to standard output; both the bare list ddgs returns and the
+ /// `{answer, results}` shape are accepted. Any other program that honours
+ /// that works too, including a bridge to an MCP server.
pub command: Vec<String>,
pub max_results: usize,
pub timeout_secs: u64,
@@ -385,35 +381,35 @@ impl Default for SearchConfig {
api_key_env: "TAVILY_API_KEY".into(),
base_url: String::new(),
command: vec![
- "scripts/buscar-ddgs.sh".into(),
- "{consulta}".into(),
+ "scripts/search-ddgs.sh".into(),
+ "{query}".into(),
"{max}".into(),
],
- // Cinco resultados llenan bien el contexto sin ahogar a un modelo
- // de 2B, que con más se pierde entre fuentes.
+ // Five results fill the context well without drowning a 2B model, which
+ // gets lost between sources with more.
max_results: 5,
timeout_secs: 20,
}
}
}
-/// Mirar por la cámara.
+/// Looking through the camera.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct CameraConfig {
- /// Si se apaga, la herramienta no llega a registrarse y el modelo ni
- /// sabe que existe. También se apaga sola si no hay dispositivo.
+ /// If off, the tool is never registered and the model does not even know
+ /// it exists. It also turns itself off if there is no device.
pub enabled: bool,
pub device: PathBuf,
- /// Resolución de captura. Manda mucho en la latencia: medido, el modelo
- /// tarda 1,3 s a 320x240, 2,9 s a 640x480 y 7,8 s a 1280x720.
+ /// Capture resolution. It weighs heavily on latency: measured, the model
+ /// takes 1.3 s at 320x240, 2.9 s at 640x480 and 7.8 s at 1280x720.
pub width: u32,
pub height: u32,
- /// Fotogramas descartados para que la exposición automática se asiente.
+ /// Frames discarded so auto-exposure can settle.
pub warmup_frames: u32,
pub timeout_secs: u64,
- /// Carpeta donde guardar cada fotograma capturado. Vacío = no se guarda
- /// ninguno, que es lo que corresponde por defecto.
+ /// Directory where each captured frame is saved. Empty = none is saved,
+ /// which is the right default.
pub save_dir: String,
}
@@ -431,28 +427,27 @@ impl Default for CameraConfig {
}
}
-/// Mirar la pantalla.
+/// Looking at the screen.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ScreenConfig {
pub enabled: bool,
- /// Programa de captura. `{ancho}` y `{salida}` se sustituyen antes de
- /// ejecutar, y tiene que escribir un JPEG por la salida estándar. Está
- /// fuera del binario para que añadir un compositor sea editar un guion.
+ /// Capture program. `{width}` and `{output}` are substituted before
+ /// running, and it must write a JPEG to standard output. It lives outside
+ /// the binary so supporting another compositor means editing a script.
pub command: Vec<String>,
- /// Ancho al que se reduce la captura antes de mandarla al modelo.
+ /// Width the capture is scaled down to before sending it to the model.
///
- /// **No lo bajes a la ligera.** Medido con tipografía de interfaz de 13 px
- /// y preguntando por datos concretos: a 1280 px acierta 3 de 3 en 7,6 s; a
- /// 960, 2 de 3; a 640, 1 de 3. Y cuando falla no dice que no lo lee: se
- /// inventa el contenido con aplomo.
+ /// **Do not lower it lightly.** Measured with 13 px UI type and asking for
+ /// specific details: at 1280 px it gets 3 of 3 in 7.6 s; at 960, 2 of 3;
+ /// at 640, 1 of 3. And when it fails it does not say it cannot read it: it
+ /// confidently makes the content up.
pub width: u32,
- /// Monitor concreto. Vacío = todo lo que haya.
+ /// A specific monitor. Empty = everything there is.
pub output: String,
pub timeout_secs: u64,
- /// Carpeta donde guardar las capturas. Vacío = no se guarda ninguna, que
- /// es lo que corresponde: en una captura caben contraseñas y mensajes
- /// privados.
+ /// Directory where captures are saved. Empty = none is saved, which is
+ /// right: a capture can hold passwords and private messages.
pub save_dir: String,
}
@@ -461,9 +456,9 @@ impl Default for ScreenConfig {
Self {
enabled: true,
command: vec![
- "scripts/capturar-pantalla.sh".into(),
- "{ancho}".into(),
- "{salida}".into(),
+ "scripts/capture-screen.sh".into(),
+ "{width}".into(),
+ "{output}".into(),
],
width: 1280,
output: String::new(),
@@ -476,9 +471,9 @@ impl Default for ScreenConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct SupervisorConfig {
- /// Lanza los servidores en lugar de suponer que ya están arriba.
+ /// Starts the servers instead of assuming they are already up.
pub manage: bool,
- /// Segundos de espera a que un servidor conteste a `/health`.
+ /// Seconds to wait for a server to answer `/health`.
pub startup_timeout_secs: u64,
pub llama: LlamaProcess,
pub tts: TtsProcess,
@@ -501,11 +496,11 @@ pub struct LlamaProcess {
pub binary: PathBuf,
pub model: PathBuf,
pub mmproj: PathBuf,
- /// Plantilla de chat que se pasa con `--chat-template-file`.
+ /// Chat template passed with `--chat-template-file`.
///
- /// La del modelo abre `<think>` sin cerrarlo nunca, y el asistente se pasa
- /// entonces varios segundos razonando antes de decir la primera palabra.
- /// Esta copia deja el bloque cerrado de entrada.
+ /// The model's own template opens `<think>` and never closes it, so the
+ /// assistant spends several seconds reasoning before saying the first
+ /// word. This copy starts with the block already closed.
pub chat_template: PathBuf,
pub extra_args: Vec<String>,
}
@@ -560,11 +555,11 @@ pub struct TtsProcess {
pub binary: PathBuf,
pub model: PathBuf,
pub codec: PathBuf,
- /// Segundos de audio que el codec acumula antes de decodificar un bloque.
+ /// Seconds of audio the codec accumulates before decoding a block.
///
- /// El valor de fábrica son 24 s, que en la práctica significa «no
- /// devuelvas nada hasta terminar la frase entera»: medido, baja el primer
- /// audio de 4,9 s a 0,6 s. Es el ajuste con más efecto de todo el sistema.
+ /// The stock value is 24 s, which in practice means «return nothing until
+ /// the whole sentence is done»: measured, it lowers the first audio from
+ /// 4.9 s to 0.6 s. It is the single most effective setting in the system.
pub codec_chunk_dur: f32,
pub extra_args: Vec<String>,
}
@@ -588,8 +583,8 @@ impl Config {
.map_err(|e| Error::Config(format!("no se pudo leer {}: {e}", path.display())))?;
let mut config: Config =
toml::from_str(&raw).map_err(|e| Error::Config(format!("{}: {e}", path.display())))?;
- // Las rutas relativas se resuelven contra la carpeta del TOML, no
- // contra el directorio desde el que se lanza el binario.
+ // Relative paths are resolved against the TOML directory, not against
+ // the directory the binary is launched from.
if let Some(base) = path.parent().filter(|p| !p.as_os_str().is_empty()) {
config.rebase(base);
}
@@ -597,7 +592,7 @@ impl Config {
Ok(config)
}
- /// Reinterpreta las rutas relativas respecto de `base`.
+ /// Reinterprets relative paths relative to `base`.
pub fn rebase(&mut self, base: &Path) {
let fix = |p: &mut PathBuf| {
if p.is_relative() {
@@ -667,7 +662,7 @@ impl Config {
));
}
}
- "ddgs" | "comando" => {
+ "ddgs" | "command" | "comando" => {
if self.search.command.is_empty() {
return Err(Error::Config(
"search.backend = «ddgs» necesita search.command".into(),