diff --git a/scripts/init-env.js b/scripts/init-env.js index 2c51a7b..62a1c91 100644 --- a/scripts/init-env.js +++ b/scripts/init-env.js @@ -23,4 +23,21 @@ console.warn('⚠️ .env.example not found. Skipping initialization.'); } -console.log('--- Environment Initialization Complete ---\n'); +console.log('\n--- Syncing Resources ---'); +const resourceDir = path.join(projectRoot, 'resources'); +if (!fs.existsSync(resourceDir)) { + fs.mkdirSync(resourceDir, { recursive: true }); +} + +// vec0.dll のコピー (インストーラー用同梱アセット) +const dllSrc = path.join(projectRoot, 'node_modules', 'sqlite-vec-windows-x64', 'vec0.dll'); +const dllDest = path.join(resourceDir, 'vec0.dll'); + +if (fs.existsSync(dllSrc)) { + fs.copyFileSync(dllSrc, dllDest); + console.log('✅ Synced vec0.dll to resources/'); +} else { + console.warn('⚠️ vec0.dll not found in node_modules. Make sure to run "bun install" first.'); +} + +console.log('--- Setup Script Complete ---\n'); diff --git a/src/backend/src/lib.rs b/src/backend/src/lib.rs index 7155490..51f5968 100644 --- a/src/backend/src/lib.rs +++ b/src/backend/src/lib.rs @@ -42,31 +42,38 @@ app.handle().plugin(tauri_plugin_shell::init())?; // Spawn llama-server sidecar - let _model_path = env::var("LLAMA_CPP_MODEL_PATH").ok(); - // サイドカーの起動 (std::process::Command を使用してDLL問題を確実に回避) - let mut sidecar_path = std::env::current_dir().unwrap_or_default(); - println!("Current working directory: {:?}", sidecar_path); + let model_path_env = env::var("LLAMA_CPP_MODEL_PATH").ok(); + + // 1. Resolve Sidecar Path (Robustly) + let sidecar_exe = if cfg!(debug_assertions) { + // Development: Use project root bin + let mut p = env::current_dir().unwrap_or_default(); + if p.ends_with(format!("src{}backend", std::path::MAIN_SEPARATOR)) { + p.pop(); p.pop(); + } + p.join("bin").join("llama-server-x86_64-pc-windows-msvc.exe") + } else { + // Production: Use sidecar resolving from Tauri + // Note: We use Command for sidecars to handle DLL path envs if needed + app_handle.path().resource_dir().unwrap_or_default() + .join("_up_").join("_up_").join("bin") // Tauri installs binaries in a specific nested struct + .join("llama-server-x86_64-pc-windows-msvc.exe") + }; - // src/backend フォルダの中にいる場合は2つ上がる (src/backend -> root) - if sidecar_path.ends_with(format!("src{}backend", std::path::MAIN_SEPARATOR)) { - sidecar_path.pop(); - sidecar_path.pop(); - } else if sidecar_path.ends_with("src-tauri") { - // 念のため古い名前も残しておく - sidecar_path.pop(); - } + // 2. Resolve Model Path + let model_abs_path = if let Some(p) = model_path_env { + PathBuf::from(p) + } else { + let mut p = env::current_dir().unwrap_or_default(); + if p.ends_with(format!("src{}backend", std::path::MAIN_SEPARATOR)) { + p.pop(); p.pop(); + } + p.join("models").join("embeddinggemma-300m-q4_0.gguf") + }; - let project_root = sidecar_path.clone(); - sidecar_path.push("src"); - sidecar_path.push("backend"); - sidecar_path.push("bin"); - let sidecar_exe = sidecar_path.join("llama-server-x86_64-pc-windows-msvc.exe"); + println!("Sidecar: {:?}", sidecar_exe); + println!("Model: {:?}", model_abs_path); - println!("Calculated sidecar path: {:?}", sidecar_exe); - - // モデルパスもルートからの絶対パスに変換 - let model_rel_path = env::var("LLAMA_CPP_MODEL_PATH").unwrap_or_default(); - let model_abs_path = project_root.join(&model_rel_path); let args = vec![ "--model".to_string(), model_abs_path.to_string_lossy().to_string(), @@ -79,51 +86,66 @@ let mut cmd = std::process::Command::new(&sidecar_exe); cmd.args(&args); - cmd.current_dir(&sidecar_path); // DLLのあるディレクトリをカレントにする - - // PATHにも追加 - let mut current_path = env::var("PATH").unwrap_or_default(); - current_path = format!("{};{}", sidecar_path.display(), current_path); - cmd.env("PATH", current_path); + + // DLL問題回避のため、バイナリのあるディレクトリをPATHに含める + if let Some(bin_dir) = sidecar_exe.parent() { + let current_path = env::var("PATH").unwrap_or_default(); + cmd.env("PATH", format!("{};{}", bin_dir.display(), current_path)); + cmd.current_dir(bin_dir); + } match cmd.spawn() { Ok(child) => { - println!("llama-server started with PID: {}", child.id()); - // アプリ終了時にプロセスを殺すためのハンドルを保持(簡易実装) + println!("llama-server started (PID: {})", child.id()); let pid = child.id(); std::thread::spawn(move || { - // 子プロセスの終了を待機 let _ = child.wait_with_output(); println!("llama-server (PID {}) exited", pid); }); } Err(e) => { - eprintln!("Failed to spawn llama-server: {}", e); + eprintln!("Failed to spawn llama-server at {:?}: {}", sidecar_exe, e); } } tauri::async_runtime::block_on(async move { - let db_path = env::var("DB_PATH").unwrap_or_else(|_| "data/vector.db".to_string()); + // 1. Resolve DB Path (AppData for Prod, current_dir for Dev) + let db_path = env::var("DB_PATH").unwrap_or_else(|_| { + if cfg!(debug_assertions) { + "data/vector.db".to_string() + } else { + let mut p = app_handle.path().app_data_dir().expect("App data dir not found"); + p.push("data"); + std::fs::create_dir_all(&p).ok(); + p.push("vector.db"); + p.to_string_lossy().to_string() + } + }); - // 拡張機能 (vec0.dll) のパスを動的に解決する + // 2. Resolve DLL Path (ResourceDir for Prod, candidates for Dev) let exe_dir = env::current_exe() .map(|p| p.parent().unwrap().to_path_buf()) .unwrap_or_else(|_| env::current_dir().unwrap()); - let candidates = [ - exe_dir.join("vec0.dll"), // 実行ファイルと同階層 - exe_dir.join("../node_modules/sqlite-vec-windows-x64/vec0.dll"), // Tauri dev (target/debug/..) - exe_dir.join("../../node_modules/sqlite-vec-windows-x64/vec0.dll"), - exe_dir.join("../../../node_modules/sqlite-vec-windows-x64/vec0.dll"), - exe_dir.join("../../../../node_modules/sqlite-vec-windows-x64/vec0.dll"), // src/backend 分1階層深い - PathBuf::from("node_modules/sqlite-vec-windows-x64/vec0.dll"), // root + let mut candidates = vec![ + exe_dir.join("vec0.dll"), + exe_dir.join("../node_modules/sqlite-vec-windows-x64/vec0.dll"), + exe_dir.join("../../node_modules/sqlite-vec-windows-x64/vec0.dll"), + exe_dir.join("../../../node_modules/sqlite-vec-windows-x64/vec0.dll"), + exe_dir.join("../../../../node_modules/sqlite-vec-windows-x64/vec0.dll"), + PathBuf::from("node_modules/sqlite-vec-windows-x64/vec0.dll"), ]; + // Add Resource dir candidate (Prod) + if let Ok(res_dir) = app_handle.path().resource_dir() { + candidates.insert(0, res_dir.join("vec0.dll")); + } + let mut extension_path = candidates[0].to_str().unwrap().to_string(); for cand in &candidates { if cand.exists() { extension_path = cand.to_str().unwrap().to_string(); - println!("Found sqlite-vec at: {}", extension_path); + println!("Found extension at: {}", extension_path); break; } }