diff --git a/lumni/src/apps/builtin/llm/prompt/src/app.rs b/lumni/src/apps/builtin/llm/prompt/src/app.rs index a55c403..f023141 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/app.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/app.rs @@ -25,9 +25,9 @@ use super::chat::{ PromptInstruction, ThreadedChatSession, }; use super::cli::{ - handle_db_subcommand, handle_profile_subcommand, parse_cli_arguments, + handle_db_subcommand, handle_profile_selection, handle_profile_subcommand, + parse_cli_arguments, }; -use super::server::{ModelServer, ServerTrait}; use crate::external as lumni; async fn create_prompt_instruction( @@ -42,26 +42,11 @@ async fn create_prompt_instruction( let mut profile_handler = db_conn.get_profile_handler(None); - // Handle --profile option - // if let Some(profile_name) = - // matches.and_then(|m| m.get_one::("profile")) - // { - // profile_handler.set_profile_name(profile_name.to_string()); - // } else { - // // Use default profile if set - // if let Some(default_profile) = - // profile_handler.get_default_profile().await? - // { - // profile_handler.set_profile_name(default_profile); - // } - // } - // - // // Check if a profile is set - // if profile_handler.get_profile_name().is_none() { - // return Err(ApplicationError::InvalidInput( - // "No profile set".to_string(), - // )); - // } + handle_profile_selection( + &mut profile_handler, + matches.and_then(|m| m.get_one::("profile")), + ) + .await?; // Get model_backend let model_backend = diff --git a/lumni/src/apps/builtin/llm/prompt/src/chat/db/user_profile/mod.rs b/lumni/src/apps/builtin/llm/prompt/src/chat/db/user_profile/mod.rs index 1297aef..dc99c1a 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/chat/db/user_profile/mod.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/chat/db/user_profile/mod.rs @@ -63,11 +63,6 @@ impl UserProfileDbHandler { pub async fn model_backend( &mut self, ) -> Result, ApplicationError> { - // TODO: - return Ok(Some(ModelBackend { - server: ModelServer::from_str("ollama")?, - model: None, - })); let user_profile = self.profile.clone(); if let Some(profile) = user_profile { @@ -76,18 +71,18 @@ impl UserProfileDbHandler { .await?; let model_server = settings - .get("__MODEL_SERVER") + .get("__TEMPLATE.__MODEL_SERVER") .and_then(|v| v.as_str()) .ok_or_else(|| { ApplicationError::InvalidInput( - "__MODEL_SERVER not found in profile".to_string(), + "MODEL_SERVER not found in profile".to_string(), ) })?; let server = ModelServer::from_str(model_server)?; let model = settings - .get("__MODEL_IDENTIFIER") + .get("__TEMPLATE.MODEL_IDENTIFIER") .and_then(|v| v.as_str()) .map(|identifier| ModelSpec::new_with_validation(identifier)) .transpose()?; diff --git a/lumni/src/apps/builtin/llm/prompt/src/cli/mod.rs b/lumni/src/apps/builtin/llm/prompt/src/cli/mod.rs index 7001cac..df66782 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/cli/mod.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/cli/mod.rs @@ -1,7 +1,9 @@ +mod select_profile; mod subcommands; use clap::{Arg, Command}; use lumni::api::spec::ApplicationSpec; +pub use select_profile::handle_profile_selection; use subcommands::db::create_db_subcommand; pub use subcommands::db::handle_db_subcommand; use subcommands::profile::create_profile_subcommand; @@ -27,7 +29,7 @@ pub fn parse_cli_arguments(spec: ApplicationSpec) -> Command { Arg::new("profile") .long("profile") .short('p') - .help("Use a specific profile"), + .help("Select a profile (format: name, name::id, or ::id)"), ) .arg( Arg::new("system") diff --git a/lumni/src/apps/builtin/llm/prompt/src/cli/select_profile.rs b/lumni/src/apps/builtin/llm/prompt/src/cli/select_profile.rs new file mode 100644 index 0000000..d7f5a82 --- /dev/null +++ b/lumni/src/apps/builtin/llm/prompt/src/cli/select_profile.rs @@ -0,0 +1,139 @@ +use std::str::FromStr; + +use lumni::api::error::ApplicationError; + +use super::UserProfileDbHandler; +use crate::external as lumni; + +pub async fn handle_profile_selection( + profile_handler: &mut UserProfileDbHandler, + profile_arg: Option<&String>, +) -> Result<(), ApplicationError> { + if let Some(profile_selector) = profile_arg { + let (name, id) = parse_profile_selector(profile_selector); + + match (name, id) { + (Some(name), Some(id)) => { + // Case: name::id + select_profile_by_name_and_id(profile_handler, name, id) + .await?; + } + (Some(name), None) => { + // Case: name + select_profile_by_name(profile_handler, name).await?; + } + (None, Some(id)) => { + // Case: ::id + select_profile_by_id(profile_handler, id).await?; + } + _ => { + return Err(ApplicationError::InvalidInput( + "Invalid profile selector format".to_string(), + )); + } + } + } else { + // Use default profile if set + if let Some(default_profile) = + profile_handler.get_default_profile().await? + { + profile_handler.set_profile(default_profile); + } else { + return Err(ApplicationError::InvalidInput( + "No profile set and no default profile available".to_string(), + )); + } + } + + // Check if a profile is set + if profile_handler.get_profile().is_none() { + return Err(ApplicationError::InvalidInput( + "No profile set".to_string(), + )); + } + + Ok(()) +} + +fn parse_profile_selector(selector: &str) -> (Option<&str>, Option) { + if selector.starts_with("::") { + // Case: ::id + let id_str = selector.trim_start_matches("::"); + return (None, i64::from_str(id_str).ok()); + } + + let parts: Vec<&str> = selector.split("::").collect(); + match parts.as_slice() { + [name, id] => (Some(name.trim()), i64::from_str(id.trim()).ok()), + [name] => (Some(name.trim()), None), + _ => (None, None), + } +} + +async fn select_profile_by_name_and_id( + profile_handler: &mut UserProfileDbHandler, + name: &str, + id: i64, +) -> Result<(), ApplicationError> { + if let Some(profile) = profile_handler.get_profile_by_id(id).await? { + if profile.name == name { + profile_handler.set_profile(profile); + Ok(()) + } else { + Err(ApplicationError::InvalidInput(format!( + "Profile with id {} does not match the name '{}'", + id, name + ))) + } + } else { + Err(ApplicationError::InvalidInput(format!( + "No profile found with id {}", + id + ))) + } +} + +async fn select_profile_by_name( + profile_handler: &mut UserProfileDbHandler, + name: &str, +) -> Result<(), ApplicationError> { + let profiles = profile_handler.get_profiles_by_name(name).await?; + match profiles.len() { + 0 => Err(ApplicationError::InvalidInput(format!( + "No profile found with name '{}'", + name + ))), + 1 => { + profile_handler.set_profile(profiles[0].clone()); + Ok(()) + } + _ => { + println!( + "Multiple profiles found with the name '{}'. Please specify \ + the id:", + name + ); + for profile in profiles { + println!(" ID: {}, Name: {}", profile.id, profile.name); + } + Err(ApplicationError::InvalidInput( + "Multiple profiles found. Please specify the id.".to_string(), + )) + } + } +} + +async fn select_profile_by_id( + profile_handler: &mut UserProfileDbHandler, + id: i64, +) -> Result<(), ApplicationError> { + if let Some(profile) = profile_handler.get_profile_by_id(id).await? { + profile_handler.set_profile(profile); + Ok(()) + } else { + Err(ApplicationError::InvalidInput(format!( + "No profile found with id {}", + id + ))) + } +}