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 --- crates/asist-tools/src/screen.rs | 88 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 45 deletions(-) (limited to 'crates/asist-tools/src/screen.rs') diff --git a/crates/asist-tools/src/screen.rs b/crates/asist-tools/src/screen.rs index dfed923..6fab402 100644 --- a/crates/asist-tools/src/screen.rs +++ b/crates/asist-tools/src/screen.rs @@ -1,21 +1,20 @@ -//! La pantalla como fuente de imágenes. +//! The screen as an image source. //! -//! Se diferencia de la cámara en lo único que de verdad importa aquí: **una -//! pantalla es texto**. Y con texto este modelo tiene un modo de fallo feo. -//! Medido sobre una captura con tipografía de interfaz de 13 px, preguntando -//! por datos concretos: +//! It differs from the camera in the only thing that really matters here: **a +//! screen is text**. And with text this model has an ugly failure mode. +//! Measured on a capture with 13 px UI type, asking for specific details: //! -//! | Ancho | Tiempo | Aciertos | Qué pasa cuando falla | -//! |------|--------|----------|-----------------------| -//! | 640 | 2,4 s | 1 de 3 | se inventa el contenido | -//! | 960 | 4,5 s | 2 de 3 | mezcla lo leído con lo supuesto | -//! | 1280 | 7,6 s | 3 de 3 | — | +//! | Width | Time | Hits | What happens when it fails | +//! |-------|-------|--------|----------------------------| +//! | 640 | 2.4 s | 1 of 3 | it makes the content up | +//! | 960 | 4.5 s | 2 of 3 | it mixes what it read with what it assumed | +//! | 1280 | 7.6 s | 3 of 3 | — | //! -//! A 640 px no dijo «no lo leo»: dijo que el error era «no se pudo abrir el -//! archivo involution» y que la reunión era «a las 10:00». Ninguna de las dos -//! cosas estaba en la imagen. De ahí que el valor por defecto sean 1280 px -//! aunque cueste el triple que la cámara: para un asistente de voz, decir una -//! hora equivocada con aplomo es peor que tardar cuatro segundos más. +//! At 640 px it did not say «I cannot read it»: it said the error was «no se +//! pudo abrir el archivo involution» and the meeting was «at 10:00». Neither +//! was in the image. Hence the 1280 px default even though it costs three +//! times the camera: for a voice assistant, confidently stating a wrong time +//! is worse than taking four more seconds. use std::path::PathBuf; use std::time::Duration; @@ -28,19 +27,18 @@ const TOOL: &str = "mirar_la_pantalla"; #[derive(Debug, Clone)] pub struct ScreenConfig { - /// Programa de captura y sus argumentos. `{ancho}` y `{salida}` se - /// sustituyen antes de ejecutar. Tiene que escribir un JPEG por la salida - /// estándar. + /// Capture program and its arguments. `{width}` and `{output}` are + /// substituted before running. It must write a JPEG to standard output. pub command: Vec, - /// 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. pub width: u32, - /// Monitor concreto; vacío = todo lo que haya. + /// A specific monitor; empty = everything there is. pub output: String, pub timeout: Duration, - /// Carpeta donde dejar las capturas. `None` = no se guarda ninguna. + /// Directory to leave captures in. `None` = none is saved. /// - /// Aquí pesa más que en la cámara: en una captura de pantalla caben - /// contraseñas, mensajes privados y correo abierto. + /// It weighs more here than for the camera: a screenshot can hold + /// passwords, private messages and open email. pub save_dir: Option, } @@ -48,9 +46,9 @@ impl Default for ScreenConfig { fn default() -> Self { Self { 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(), @@ -72,7 +70,7 @@ impl Screen { fn program(&self) -> Result<&String> { self.config.command.first().ok_or_else(|| Error::Tool { tool: TOOL.into(), - message: "screen.command está vacío".into(), + message: "screen.command is empty".into(), }) } } @@ -84,19 +82,19 @@ impl FrameSource for Screen { fn available(&self) -> Result<()> { let program = self.program()?; - // Un nombre suelto se resuelve por el PATH; una ruta tiene que existir. + // A bare name is resolved through PATH; a path must exist. if program.contains('/') && !std::path::Path::new(program).exists() { return Err(Error::Tool { tool: TOOL.into(), message: format!("no existe {program}"), }); } - // Sin entorno gráfico no hay nada que capturar, y más vale decirlo al - // arrancar que a mitad de una pregunta. + // Without a graphical environment there is nothing to capture, and + // better to say so at startup than in the middle of a question. if std::env::var_os("WAYLAND_DISPLAY").is_none() && std::env::var_os("DISPLAY").is_none() { return Err(Error::Tool { tool: TOOL.into(), - message: "no hay sesión gráfica (ni WAYLAND_DISPLAY ni DISPLAY)".into(), + message: "no graphical session (neither WAYLAND_DISPLAY nor DISPLAY)".into(), }); } Ok(()) @@ -108,8 +106,8 @@ impl FrameSource for Screen { let args: Vec = self.config.command[1..] .iter() .map(|arg| { - arg.replace("{ancho}", &self.config.width.to_string()) - .replace("{salida}", &self.config.output) + arg.replace("{width}", &self.config.width.to_string()) + .replace("{output}", &self.config.output) }) .collect(); @@ -127,30 +125,30 @@ mod tests { fn config() -> ScreenConfig { ScreenConfig { - command: vec!["/bin/echo".into(), "{ancho}".into(), "{salida}".into()], + command: vec!["/bin/echo".into(), "{width}".into(), "{output}".into()], ..Default::default() } } #[test] - fn el_ancho_por_defecto_es_el_minimo_medido_para_leer_texto() { + fn default_width_is_the_measured_minimum_to_read_text() { assert_eq!( ScreenConfig::default().width, 1280, - "por debajo de 1280 el modelo se inventa lo que pone en pantalla" + "below 1280 the model makes up what the screen says" ); } #[test] - fn por_defecto_no_se_guarda_ninguna_captura() { + fn no_capture_is_saved_by_default() { assert!( ScreenConfig::default().save_dir.is_none(), - "en una captura de pantalla caben contraseñas y mensajes privados" + "a screenshot can hold passwords and private messages" ); } #[test] - fn un_guion_inexistente_se_detecta_antes_de_registrar_la_herramienta() { + fn missing_script_is_detected_before_registering_the_tool() { let screen = Screen::new(ScreenConfig { command: vec!["/no/existe/captura.sh".into()], ..Default::default() @@ -163,7 +161,7 @@ mod tests { } #[test] - fn una_orden_vacia_se_rechaza() { + fn empty_command_is_rejected() { let screen = Screen::new(ScreenConfig { command: vec![], ..Default::default() @@ -172,16 +170,16 @@ mod tests { } #[test] - fn los_marcadores_se_sustituyen_antes_de_ejecutar() { - // /bin/echo devuelve los argumentos, así que la captura falla por no - // ser un JPEG; lo que se comprueba es que el mensaje trae el ancho ya - // sustituido, no el marcador. + fn placeholders_are_substituted_before_running() { + // /bin/echo returns the arguments, so the capture fails for not being + // a JPEG; what is checked is that the message carries the width already + // substituted, not the placeholder. let mut config = config(); config.width = 1280; config.output = "eDP-1".into(); let screen = Screen::new(config); if std::env::var_os("WAYLAND_DISPLAY").is_none() && std::env::var_os("DISPLAY").is_none() { - return; // sin sesión gráfica no hay nada que probar aquí + return; // without a graphical session there is nothing to test here } let err = screen.capture().unwrap_err().to_string(); assert!(err.contains("no devolvió un JPEG"), "{err}"); -- cgit v1.2.3