diff options
Diffstat (limited to 'crates/asist-app/src')
| -rw-r--r-- | crates/asist-app/src/main.rs | 27 | ||||
| -rw-r--r-- | crates/asist-app/src/registry.rs | 67 |
2 files changed, 73 insertions, 21 deletions
diff --git a/crates/asist-app/src/main.rs b/crates/asist-app/src/main.rs index 7b00b1f..cc08e62 100644 --- a/crates/asist-app/src/main.rs +++ b/crates/asist-app/src/main.rs @@ -109,6 +109,17 @@ fn run(config: Config, args: &Args) -> Result<()> { // Las dos capacidades que tocan algo fuera del proceso se anuncian: una // enciende la cámara y la otra ejecuta órdenes. Quien lo arranca debería // saberlo sin tener que leerse la configuración. + if tools.get("mirar_la_pantalla").is_some() { + eprintln!( + "Captura de pantalla ACTIVA — a {} px{}", + config.screen.width, + if config.screen.save_dir.is_empty() { + String::new() + } else { + format!(", guardando en {}", config.screen.save_dir) + } + ); + } if tools.get("mirar_por_la_camara").is_some() { eprintln!( "Cámara ACTIVA — {} a {}x{}{}", @@ -320,6 +331,22 @@ fn check(config: &Config) -> Result<()> { } } + if !config.screen.enabled { + println!(" - pantalla desactivada en la configuración"); + } else { + match config.screen.command.first() { + Some(program) if !program.contains('/') || PathBuf::from(program).exists() => ok( + "pantalla", + format!("{} px · {}", config.screen.width, program), + ), + Some(program) => println!(" - pantalla no existe {program}"), + None => println!(" - pantalla screen.command está vacío"), + } + if std::env::var_os("WAYLAND_DISPLAY").is_none() && std::env::var_os("DISPLAY").is_none() { + println!(" - sesión gráfica no hay; la pantalla no se podrá capturar"); + } + } + if !config.camera.enabled { println!(" - cámara desactivada en la configuración"); } else if config.camera.device.exists() { diff --git a/crates/asist-app/src/registry.rs b/crates/asist-app/src/registry.rs index 13bbb75..a3a10ed 100644 --- a/crates/asist-app/src/registry.rs +++ b/crates/asist-app/src/registry.rs @@ -8,11 +8,12 @@ use std::sync::Arc; use std::time::Duration; -use asist_core::config::{CameraConfig, Config, SearchConfig}; +use asist_core::config::{self as cfg, Config, SearchConfig}; use asist_core::tools::ToolRegistry; use asist_llm::LlmClient; -use asist_tools::camera::CaptureConfig; -use asist_tools::{Camera, SearchBackend, WebSearch}; +use asist_tools::{ + Camera, CameraConfig, Screen, ScreenConfig, SearchBackend, VisionTool, WebSearch, +}; /// Lo que no se pudo activar y por qué, para decírselo al usuario al arrancar /// en vez de dejarlo en silencio. @@ -38,13 +39,16 @@ pub fn build(config: &Config, llm: &Arc<LlmClient>) -> (ToolRegistry, Vec<Skippe }), } - match camera_tool(&config.camera, llm) { - Ok(Some(tool)) => registry.register(Arc::new(tool)), - Ok(None) => {} - Err(reason) => skipped.push(Skipped { - tool: "mirar_por_la_camara", - reason, - }), + // Las dos que ven comparten forma, así que se registran igual. + for (result, tool) in [ + (camera_tool(&config.camera, llm), "mirar_por_la_camara"), + (screen_tool(&config.screen, llm), "mirar_la_pantalla"), + ] { + match result { + Ok(Some(vision)) => registry.register(Arc::new(vision)), + Ok(None) => {} + Err(reason) => skipped.push(Skipped { tool, reason }), + } } (registry, skipped) @@ -98,25 +102,46 @@ fn search_tool(config: &SearchConfig) -> Result<Option<WebSearch>, String> { ))) } -fn camera_tool(config: &CameraConfig, llm: &Arc<LlmClient>) -> Result<Option<Camera>, String> { +fn camera_tool( + config: &cfg::CameraConfig, + llm: &Arc<LlmClient>, +) -> Result<Option<VisionTool>, String> { if !config.enabled { return Ok(None); } - let capture = CaptureConfig { + let source = Camera::new(CameraConfig { device: config.device.clone(), width: config.width, height: config.height, warmup_frames: config.warmup_frames, timeout: Duration::from_secs(config.timeout_secs), save_dir: (!config.save_dir.is_empty()).then(|| config.save_dir.clone().into()), - }; - // Registrar una herramienta que va a fallar siempre es peor que no tenerla: - // el modelo la llamaría, se comería el error y gastaría un turno entero. - if !Camera::available(&capture) { - return Err(format!( - "no existe {}; comprueba con «v4l2-ctl --list-devices»", - capture.device.display() - )); + }); + finish(VisionTool::camera(Box::new(source), Arc::clone(llm))) +} + +fn screen_tool( + config: &cfg::ScreenConfig, + llm: &Arc<LlmClient>, +) -> Result<Option<VisionTool>, String> { + if !config.enabled { + return Ok(None); + } + let source = Screen::new(ScreenConfig { + command: config.command.clone(), + width: config.width, + output: config.output.clone(), + timeout: Duration::from_secs(config.timeout_secs), + save_dir: (!config.save_dir.is_empty()).then(|| config.save_dir.clone().into()), + }); + finish(VisionTool::screen(Box::new(source), Arc::clone(llm))) +} + +/// Registrar una herramienta que va a fallar siempre es peor que no tenerla: +/// el modelo la llamaría, se comería el error y gastaría un turno entero. +fn finish(tool: VisionTool) -> Result<Option<VisionTool>, String> { + match tool.available() { + Ok(()) => Ok(Some(tool)), + Err(err) => Err(err.to_string()), } - Ok(Some(Camera::new(capture, Arc::clone(llm)))) } |