fix: auto-discover localllm binary in target/release and PATH
This commit is contained in:
1 parent
2cac674cba
commit
f5a4a9ee97
1 file changed
+71
-4
@@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::Mutex;
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
@@ -47,6 +47,56 @@ fn query_gpu() -> Result<GpuInfo, String> {
|
||||
|
||||
// ─── Server lifecycle ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Locate the `localllm` binary by searching several well-known locations:
|
||||
/// 1. Workspace `target/release/` relative to the Tauri app's source tree
|
||||
/// 2. Next to the running executable (for installed/bundled builds)
|
||||
/// 3. System PATH
|
||||
fn find_localllm_binary() -> Option<PathBuf> {
|
||||
let exe_name = if cfg!(target_os = "windows") { "localllm.exe" } else { "localllm" };
|
||||
|
||||
// 1. Workspace target/release — works when running `npm run tauri dev` from tauri-app/
|
||||
// The Tauri dev binary lives at tauri-app/src-tauri/target/debug/forgelm-chat.exe
|
||||
// so we walk up to find the workspace root and look for target/release/localllm.exe
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
// Walk up from the current exe looking for target/release/localllm.exe
|
||||
let mut dir = exe.parent();
|
||||
while let Some(d) = dir {
|
||||
let candidate = d.join("target").join("release").join(exe_name);
|
||||
if candidate.exists() {
|
||||
return Some(candidate);
|
||||
}
|
||||
// Also check sibling: if we're inside target/debug, go up two levels
|
||||
let candidate2 = d.join(exe_name);
|
||||
if candidate2.exists() {
|
||||
return Some(candidate2);
|
||||
}
|
||||
dir = d.parent();
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Relative to CWD (useful when launched from repo root)
|
||||
let cwd_candidate = PathBuf::from("target").join("release").join(exe_name);
|
||||
if cwd_candidate.exists() {
|
||||
return Some(cwd_candidate);
|
||||
}
|
||||
|
||||
// 3. System PATH
|
||||
if let Ok(output) = Command::new(if cfg!(target_os = "windows") { "where" } else { "which" })
|
||||
.arg("localllm")
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
let path_str = String::from_utf8_lossy(&output.stdout);
|
||||
let first_line = path_str.lines().next().unwrap_or("").trim();
|
||||
if !first_line.is_empty() {
|
||||
return Some(PathBuf::from(first_line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn start_server(
|
||||
state: State<ServerState>,
|
||||
@@ -60,15 +110,20 @@ fn start_server(
|
||||
return Err("Server is already running".into());
|
||||
}
|
||||
|
||||
let binary = if cfg!(target_os = "windows") { "localllm.exe" } else { "localllm" };
|
||||
let binary_path = find_localllm_binary()
|
||||
.ok_or_else(|| {
|
||||
"localllm binary not found. Build it with: cargo build --release -p inference-server\n\
|
||||
Then ensure the binary is in one of: target/release/, PATH, or next to this app."
|
||||
.to_string()
|
||||
})?;
|
||||
|
||||
let child = Command::new(binary)
|
||||
let child = Command::new(&binary_path)
|
||||
.env("LOCALLLM_MODEL", &model_path)
|
||||
.env("LOCALLLM_ADDR", &addr)
|
||||
.env("LOCALLLM_GPU_LAYERS", gpu_layers.to_string())
|
||||
.env("LOCALLLM_CTX", ctx_size.to_string())
|
||||
.spawn()
|
||||
.map_err(|e| format!("Failed to start server: {e}"))?;
|
||||
.map_err(|e| format!("Failed to start server ({}): {e}", binary_path.display()))?;
|
||||
|
||||
let pid = child.id();
|
||||
*guard = Some(child);
|
||||
@@ -275,6 +330,17 @@ fn load_config(app: AppHandle) -> Result<AppConfig, String> {
|
||||
serde_json::from_str(&json).map_err(|e| format!("Parse error: {e}"))
|
||||
}
|
||||
|
||||
/// Returns the resolved path to the localllm binary (useful for debugging).
|
||||
#[tauri::command]
|
||||
fn find_server_binary() -> Result<String, String> {
|
||||
find_localllm_binary()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.ok_or_else(|| {
|
||||
"localllm binary not found. Build with: cargo build --release -p inference-server"
|
||||
.to_string()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the app data directory path (useful for debugging).
|
||||
#[tauri::command]
|
||||
fn get_app_data_dir(app: AppHandle) -> Result<String, String> {
|
||||
@@ -304,6 +370,7 @@ pub fn run() {
|
||||
save_config,
|
||||
load_config,
|
||||
get_app_data_dir,
|
||||
find_server_binary,
|
||||
])
|
||||
.setup(|app| {
|
||||
#[cfg(debug_assertions)]
|
||||
|
||||
Reference in new issue
Block a user