diff --git a/extensions/llamacpp-extension/settings.json b/extensions/llamacpp-extension/settings.json index 46c4995ffd..5f7fd1ca98 100644 --- a/extensions/llamacpp-extension/settings.json +++ b/extensions/llamacpp-extension/settings.json @@ -10,7 +10,18 @@ "recommended": "" } }, - + { + "key": "llamacpp_env", + "title": "Environmental variables", + "description": "Environmental variables for llama.cpp(KEY=VALUE), separated by ';'", + "controllerType": "input", + "controllerProps": { + "value": "none", + "placeholder": "Eg, GGML_VK_VISIBLE_DEVICES='0,1'", + "type": "text", + "textAlign": "right" + } + }, { "key": "auto_update_engine", "title": "Auto update engine", diff --git a/extensions/llamacpp-extension/src/index.ts b/extensions/llamacpp-extension/src/index.ts index bf03024a0e..d33b5041e3 100644 --- a/extensions/llamacpp-extension/src/index.ts +++ b/extensions/llamacpp-extension/src/index.ts @@ -39,6 +39,7 @@ type LlamacppConfig = { version_backend: string auto_update_engine: boolean auto_unload: boolean + llamacpp_env: string chat_template: string n_gpu_layers: number offload_mmproj: boolean @@ -146,6 +147,7 @@ const logger = { export default class llamacpp_extension extends AIEngine { provider: string = 'llamacpp' autoUnload: boolean = true + llamacpp_env: string = '' readonly providerId: string = 'llamacpp' private config: LlamacppConfig @@ -175,6 +177,7 @@ export default class llamacpp_extension extends AIEngine { this.config = loadedConfig as LlamacppConfig this.autoUnload = this.config.auto_unload + this.llamacpp_env = this.config.llamacpp_env // This sets the base directory where model files for this provider are stored. this.providerPath = await joinPath([ @@ -801,6 +804,8 @@ export default class llamacpp_extension extends AIEngine { closure() } else if (key === 'auto_unload') { this.autoUnload = value as boolean + } else if (key === 'llamacpp_env') { + this.llamacpp_env = value as string } } @@ -1133,6 +1138,27 @@ export default class llamacpp_extension extends AIEngine { } } + private parseEnvFromString( + target: Record, + envString: string + ): void { + envString + .split(';') + .filter((pair) => pair.trim()) + .forEach((pair) => { + const [key, ...valueParts] = pair.split('=') + const cleanKey = key?.trim() + + if ( + cleanKey && + valueParts.length > 0 && + !cleanKey.startsWith('LLAMA') + ) { + target[cleanKey] = valueParts.join('=').trim() + } + }) + } + override async load( modelId: string, overrideSettings?: Partial, @@ -1221,6 +1247,9 @@ export default class llamacpp_extension extends AIEngine { const api_key = await this.generateApiKey(modelId, String(port)) envs['LLAMA_API_KEY'] = api_key + // set user envs + this.parseEnvFromString(envs, this.llamacpp_env) + // model option is required // NOTE: model_path and mmproj_path can be either relative to Jan's data folder or absolute path const modelPath = await joinPath([ @@ -1596,6 +1625,9 @@ export default class llamacpp_extension extends AIEngine { `Invalid version/backend format: ${cfg.version_backend}. Expected format: /` ) } + // set envs + const envs: Record = {} + this.parseEnvFromString(envs, this.llamacpp_env) // Ensure backend is downloaded and ready before proceeding await this.ensureBackendReady(backend, version) @@ -1606,6 +1638,7 @@ export default class llamacpp_extension extends AIEngine { const dList = await invoke('plugin:llamacpp|get_devices', { backendPath, libraryPath, + envs, }) return dList } catch (error) { diff --git a/src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs b/src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs index 35dc35c5e9..a25d7825f5 100644 --- a/src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs +++ b/src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs @@ -265,8 +265,9 @@ pub async fn unload_llama_model( pub async fn get_devices( backend_path: &str, library_path: Option<&str>, + envs: HashMap ) -> ServerResult> { - get_devices_from_backend(backend_path, library_path).await + get_devices_from_backend(backend_path, library_path, envs).await } /// Generate API key using HMAC-SHA256 diff --git a/src-tauri/plugins/tauri-plugin-llamacpp/src/device.rs b/src-tauri/plugins/tauri-plugin-llamacpp/src/device.rs index 2855472092..2bb2b6f92f 100644 --- a/src-tauri/plugins/tauri-plugin-llamacpp/src/device.rs +++ b/src-tauri/plugins/tauri-plugin-llamacpp/src/device.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::process::Stdio; use std::time::Duration; use tokio::process::Command; @@ -19,6 +20,7 @@ pub struct DeviceInfo { pub async fn get_devices_from_backend( backend_path: &str, library_path: Option<&str>, + envs: HashMap, ) -> ServerResult> { log::info!("Getting devices from server at path: {:?}", backend_path); @@ -27,6 +29,7 @@ pub async fn get_devices_from_backend( // Configure the command to run the server with --list-devices let mut command = Command::new(backend_path); command.arg("--list-devices"); + command.envs(envs); // Set up library path setup_library_path(library_path, &mut command);