1 //! Tauri command `chat_load_model`: loads the on-device chat model.
2 //!
3 //! Siti is fully offline: it loads the platform-default GGUF model directly.
4 //! There is no operator-assigned model and no app credentials involved. The
5 //! only network access is the one-time HuggingFace download of the model
6 //! weights into the shared App Group cache.
7
8 use tauri::AppHandle;
9
10 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
11 use {
12 super::{
13 emit_chat_status, fmt_duration, model_config, sampling_config, CHAT_SYSTEM_PROMPT, ENGINE,
14 },
15 crate::constants::ChatStatus,
16 log::{error, info},
17 };
18
19 /// Load the platform-default chat model into memory.
20 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
21 #[tauri::command]
22 pub async fn chat_load_model(app: AppHandle) -> Result<String, String> {
23 let config = model_config();
24 let display_name = config.display_name.clone();
25 info!("chat_load_model: loading on-device model {}", display_name);
26 emit_chat_status(&app, ChatStatus::Loading, Some(&display_name), None);
27
28 let elapsed = ENGINE
29 .load_gguf_model(
30 config,
31 Some(CHAT_SYSTEM_PROMPT.to_string()),
32 Some(sampling_config()),
33 )
34 .await
35 .map_err(|e| {
36 let msg = format!("Failed to load chat model: {}", e);
37 error!("{}", msg);
38 emit_chat_status(&app, ChatStatus::Error, Some(&display_name), Some(&msg));
39 msg
40 })?;
41
42 let msg = format!(
43 "Chat model {} loaded in {}",
44 display_name,
45 fmt_duration(elapsed)
46 );
47 info!("{}", msg);
48 emit_chat_status(&app, ChatStatus::Ready, Some(&display_name), None);
49 Ok(msg)
50 }
51
52 #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
53 #[tauri::command]
54 pub async fn chat_load_model(_app: AppHandle) -> Result<String, String> {
55 log::debug!("Chat model is only supported on macOS, iOS, and Android for now.");
56 Err("Chat model is only supported on macOS, iOS, and Android for now.".to_string())
57 }