@@ -25,13 +25,22 @@ const DEFAULT_MODEL_ID: &str = "llama-3.2-3b-instruct-q4_k_m";
2525/// Filename used when downloading default model from URL (last segment of HuggingFace URL).
2626const DEFAULT_MODEL_DOWNLOAD_FILENAME : & str = "Llama-3.2-3B-Instruct-Q4_K_M.gguf" ;
2727
28+ /// URL for the default model (same as in setup-full-bundle.sh). Used for first-run auto-download.
29+ const DEFAULT_MODEL_URL : & str = "https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf" ;
30+
2831/// Relative path to bundled KB JSON in resources (same format as URL-loaded package: manifest, documents, embeddings).
2932const BUNDLED_KB_FILENAME : & str = "default_kb.json" ;
3033
3134#[ derive( Debug , Serialize ) ]
3235pub struct BundledDefaultsStatus {
3336 pub model_ready : bool ,
3437 pub kb_ready : bool ,
38+ /// When packaged and no model found: URL to download the default model on first run.
39+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
40+ pub default_model_download_url : Option < String > ,
41+ /// When packaged and no model found: path where the default model should be saved (app data).
42+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
43+ pub default_model_output_path : Option < String > ,
3544}
3645
3746/// Find project root (directory that contains "data" and ideally "desktop") for dev fallback.
@@ -80,6 +89,26 @@ fn resolve_bundled_model_path(app: &AppHandle) -> Option<PathBuf> {
8089 }
8190 }
8291 }
92+ // App data (e.g. after first-run auto-download or Settings download)
93+ if let Some ( base) = app. path ( ) . app_data_dir ( ) . ok ( ) {
94+ let models_dir = base. join ( "data" ) . join ( "models" ) ;
95+ let id_gguf = format ! ( "{}.gguf" , DEFAULT_MODEL_ID ) ;
96+ for name in [
97+ DEFAULT_MODEL_DOWNLOAD_FILENAME ,
98+ BUNDLED_MODEL_FILENAME ,
99+ id_gguf. as_str ( ) ,
100+ ] {
101+ let p = models_dir. join ( name) ;
102+ if p. exists ( ) {
103+ if let Ok ( metadata) = fs:: metadata ( & p) {
104+ let size_gb = metadata. len ( ) as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ;
105+ if size_gb >= 1.0 {
106+ return Some ( p) ;
107+ }
108+ }
109+ }
110+ }
111+ }
83112 // Dev fallback: use same location as Settings download (project data/models/)
84113 if let Some ( data_dir) = find_dev_data_dir ( ) {
85114 let models_dir = data_dir. join ( "models" ) ;
@@ -215,8 +244,25 @@ async fn ingest_kb_from_path(app: &AppHandle, path: &Path) -> Result<(), String>
215244 Ok ( ( ) )
216245}
217246
247+ /// When packaged (resource dir present) and no model exists, return (url, output_path) for first-run auto-download.
248+ fn default_model_download_info ( app : & AppHandle ) -> Option < ( String , PathBuf ) > {
249+ if resolve_bundled_model_path ( app) . is_some ( ) {
250+ return None ;
251+ }
252+ let resource_dir = app. path ( ) . resource_dir ( ) . ok ( ) ?;
253+ if !resource_dir. exists ( ) {
254+ return None ;
255+ }
256+ let base = app. path ( ) . app_data_dir ( ) . ok ( ) ?;
257+ let models_dir = base. join ( "data" ) . join ( "models" ) ;
258+ let _ = fs:: create_dir_all ( & models_dir) ;
259+ let output_path = models_dir. join ( DEFAULT_MODEL_DOWNLOAD_FILENAME ) ;
260+ Some ( ( DEFAULT_MODEL_URL . to_string ( ) , output_path) )
261+ }
262+
218263/// Ensure the default model and global KB are initialized from bundled resources when possible.
219264/// Call this once after loading; then check setup status (model_ready, kb_ready).
265+ /// When no model is found in a packaged build, returns default_model_download_url/output_path for first-run auto-download.
220266#[ tauri:: command]
221267pub async fn ensure_bundled_defaults_initialized ( app : AppHandle ) -> Result < BundledDefaultsStatus , String > {
222268 // 1. Model: if not loaded, try bundled model path
@@ -231,10 +277,11 @@ pub async fn ensure_bundled_defaults_initialized(app: AppHandle) -> Result<Bundl
231277 }
232278 }
233279 None => {
280+ #[ cfg( debug_assertions) ]
234281 if let Ok ( rd) = app. path ( ) . resource_dir ( ) {
235282 let expected = rd. join ( "models" ) . join ( BUNDLED_MODEL_FILENAME ) ;
236283 eprintln ! (
237- "[Confidant] No bundled model found. Expected at: {} ( add resources/models/default_model.gguf and rebuild) " ,
284+ "[Confidant] No bundled model. Auto-download on first run or add resources/models/default_model.gguf. Expected: {} " ,
238285 expected. display( )
239286 ) ;
240287 }
@@ -287,8 +334,18 @@ pub async fn ensure_bundled_defaults_initialized(app: AppHandle) -> Result<Bundl
287334 . map ( |n| n > 0 )
288335 . unwrap_or ( false ) ;
289336
337+ let ( default_model_download_url, default_model_output_path) = if !model_ready {
338+ default_model_download_info ( & app)
339+ . map ( |( url, path) | ( Some ( url) , Some ( path. to_string_lossy ( ) . to_string ( ) ) ) )
340+ . unwrap_or ( ( None , None ) )
341+ } else {
342+ ( None , None )
343+ } ;
344+
290345 Ok ( BundledDefaultsStatus {
291346 model_ready,
292347 kb_ready,
348+ default_model_download_url,
349+ default_model_output_path,
293350 } )
294351}
0 commit comments