diff --git a/Cargo.lock b/Cargo.lock index 2e4d41c..d7c2d66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1550,7 +1550,7 @@ dependencies = [ "hyper-util", "icalendar", "libdav", - "own_assist_common 0.3.0 (sparse+https://git.mboemer.de/api/packages/milan/cargo/)", + "own_assist_common 0.3.0", "rmcp", "serde", "thiserror 2.0.19", @@ -1576,7 +1576,7 @@ dependencies = [ "hyper-util", "icalendar", "libdav", - "own_assist_common 0.3.0 (sparse+https://git.mboemer.de/api/packages/milan/cargo/)", + "own_assist_common 0.3.0", "rmcp", "serde", "thiserror 2.0.19", @@ -1998,7 +1998,7 @@ dependencies = [ "log", "mcp_server_collection 0.2.2 (sparse+https://git.mboemer.de/api/packages/milan/cargo/)", "ollama-rs", - "own_assist_common 0.3.0 (sparse+https://git.mboemer.de/api/packages/milan/cargo/)", + "own_assist_common 0.3.0", "own_mcp 0.1.1 (sparse+https://git.mboemer.de/api/packages/milan/cargo/)", "rmcp", "rodio", @@ -2012,6 +2012,8 @@ dependencies = [ [[package]] name = "own_assist_common" version = "0.3.0" +source = "sparse+https://git.mboemer.de/api/packages/milan/cargo/" +checksum = "e4f114c598d4f9b1c26def3a047fbba893a202bb2a91be6f21d80881320ad872" dependencies = [ "log", "serde", @@ -2022,15 +2024,15 @@ dependencies = [ [[package]] name = "own_assist_common" -version = "0.3.0" -source = "sparse+https://git.mboemer.de/api/packages/milan/cargo/" -checksum = "e4f114c598d4f9b1c26def3a047fbba893a202bb2a91be6f21d80881320ad872" +version = "0.4.0" dependencies = [ "log", + "ollama-rs", "serde", "thiserror 2.0.19", "toml", "tracing-subscriber", + "url", ] [[package]] diff --git a/cli/src/config.rs b/cli/src/config.rs index 614f53e..b4b76bc 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -19,7 +19,7 @@ pub struct Config { ollama: OllamaConfig, audio: Option, #[serde(rename = "mcp-servers")] - mcp_servers: Vec, + mcp_servers: Vec, } impl Config { @@ -31,23 +31,6 @@ impl Config { &self.ollama } - pub fn ollama_instance(&self) -> Ollama { - let mut ollama_headers = HeaderMap::new(); - - if let Some(authorization_header) = &self.ollama.authorization { - ollama_headers.append( - "Authorization", - HeaderValue::from_str(authorization_header).unwrap(), - ); - } - - let ollama_default_url = Url::parse("http://127.0.0.1:11434").unwrap(); - let mut ollama = Ollama::from_url(self.ollama.url.clone().unwrap_or(ollama_default_url)); - ollama.set_headers(Some(ollama_headers)); - - ollama - } - pub fn audio_client(&self) -> Option { if let Some(audio_config) = &self.audio { let audio_server = &audio_config.server; @@ -118,36 +101,6 @@ pub struct AudioConfig { server: AudioServerConfig, } -#[derive(Debug, Deserialize)] -pub struct AudioServerConfig { - url: Url, - authorization: Option, -} - -#[derive(Debug, Deserialize)] -pub struct OllamaConfig { - pub url: Option, - pub model: OllamaModelConfig, - pub authorization: Option, -} - -#[derive(Debug, Deserialize)] -pub struct OllamaModelConfig { - #[serde(rename = "from-model")] - pub from_model: String, - pub name: String, - pub system_prompt: Option, - pub context_size: Option, - pub temperature: Option, -} - -#[derive(Debug, Deserialize)] -pub struct MCPServerConfig { - pub name: Option, - pub url: Url, - pub authorization: Option, // should probably implement oauth some time // actually, fuck oauth -} - #[derive(Debug, Deserialize)] pub struct PermissionConfig { #[serde(rename = "tool-name")] diff --git a/common/Cargo.toml b/common/Cargo.toml index 11d63ea..d295592 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "own_assist_common" -version = "0.3.0" +version = "0.4.0" edition = "2024" license = "GPL-3.0" [dependencies] thiserror = "2.0.18" toml = "1.1.2" -serde = "1.0.228" +serde = { version = "1.0.228", features = ["derive"] } log = "0.4.29" -tracing-subscriber = { version = "0.3.23", features = ["env-filter"]} \ No newline at end of file +tracing-subscriber = { version = "0.3.23", features = ["env-filter"]} +url = { version = "2.5.8", features = ["serde"] } +ollama-rs = { version = "0.3.6", features = ["headers"]} \ No newline at end of file diff --git a/common/src/config.rs b/common/src/config.rs new file mode 100644 index 0000000..2bf75b3 --- /dev/null +++ b/common/src/config.rs @@ -0,0 +1,93 @@ +use ollama_rs::error::OllamaError; +use ollama_rs::models::ModelOptions; +use ollama_rs::models::create::{CreateModelRequest, CreateModelStatus}; +use serde::Deserialize; +use url::Url; + +#[derive(Debug, Deserialize)] +pub struct AudioClientConfig { + pub url: Url, + pub authorization: Option, +} + +fn ollama_default_url() -> Url { + Url::parse("http://127.0.0.1:11434").unwrap() +} + +#[derive(Debug, Deserialize)] +pub struct OllamaConfig { + #[serde(default = "ollama_default_url")] + pub url: Url, + #[serde(rename = "model")] + pub model_config: OllamaModelConfig, + pub authorization: Option, +} + +impl OllamaConfig { + pub fn ollama(&self) -> ollama_rs::Ollama { + let mut ollama_headers = ollama_rs::headers::HeaderMap::new(); + + if let Some(authorization_header) = &self.authorization { + ollama_headers.append( + "Authorization", + ollama_rs::headers::HeaderValue::from_str(authorization_header.as_str()).unwrap(), + ); + } + + let ollama_default_url = Url::parse("http://127.0.0.1:11434").unwrap(); + let mut ollama = ollama_rs::Ollama::from_url(self.url.clone()); + ollama.set_headers(Some(ollama_headers)); + + ollama + } + + pub async fn create_model( + &self, + download_needed_message: Option, + ) -> Result { + let ollama = self.ollama(); + let model_config = &self.model_config; + + let model_options = ModelOptions::default() + .num_ctx(model_config.context_size.unwrap_or(2048)) // 2048 is the ollama default. + .temperature(model_config.temperature.unwrap_or(0.8)); // 0.8 is the ollama default + + // print message to warn user of long waiting times + if let Ok(models) = ollama.list_local_models().await + && !models.iter().any(|m| m.name == model_config.from_model) + && let Some(download_needed_message) = download_needed_message + { + log::info!("{}", download_needed_message); + println!("{}", download_needed_message); + } + + let mut create_model_request = CreateModelRequest::new(model_config.name.clone()) + .from_model(model_config.from_model.clone()) + .parameters(model_options); + + if let Some(system_prompt) = &model_config.system_prompt { + create_model_request = create_model_request.system(system_prompt.clone()); + } + + ollama + .create_model(create_model_request) + .await + } +} + +#[derive(Debug, Deserialize)] +pub struct OllamaModelConfig { + #[serde(rename = "from-model")] + pub from_model: String, + pub name: String, + pub system_prompt: Option, + pub context_size: Option, + pub temperature: Option, +} + +#[derive(Debug, Deserialize)] +pub struct MCPClientConfig { + pub name: Option, + pub url: Url, + pub authorization: Option, // should probably implement oauth some time // actually, fuck oauth +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 848825e..cad54b0 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod config_loader; mod exit_error; mod tracing_init;