|
1
|
//! Tauri command: `chat_list_models` |
|
2
|
//! |
|
3
|
//! Returns the on-device models the user can switch between, sourced from the |
|
4
|
//! onde SDK's `SUPPORTED_MODEL_INFO` catalogue (filtered to the subset the |
|
5
|
//! engine can actually load), with the currently selected model flagged. |
|
6
|
|
|
7
|
use super::ModelInfo; |
|
8
|
|
|
9
|
/// Normalise a model description for Apple builds. |
|
10
|
/// |
|
11
|
/// The shared onde model catalogue is cross-platform and also names sibling |
|
12
|
/// products, so its descriptions mention Android/Windows/Linux and "siGit Code". |
|
13
|
/// Apple's App Store Review Guideline 2.3.10 (Accurate Metadata) forbids |
|
14
|
/// referencing other platforms in an iOS/macOS app's UI or metadata, so on |
|
15
|
/// Apple builds we drop those mentions before the text reaches Settings. We |
|
16
|
/// also neutralise the cross-product reference, which would only confuse a Siti |
|
17
|
/// user. Apple's own platforms (iOS, macOS, tvOS) are kept. |
|
18
|
#[cfg(any(target_os = "macos", target_os = "ios"))] |
|
19
|
fn sanitize_description(desc: &str) -> String { |
|
20
|
desc.replace("iOS & Android", "iOS") |
|
21
|
.replace("macOS & Android", "macOS") |
|
22
|
.replace("macOS, Linux, and Windows", "macOS") |
|
23
|
.replace(", Linux, and Windows", "") |
|
24
|
.replace(", Linux and Windows", "") |
|
25
|
.replace(" & Android", "") |
|
26
|
.replace(" and Android", "") |
|
27
|
.replace("siGit Code", "coding tasks") |
|
28
|
} |
|
29
|
|
|
30
|
/// On non-Apple builds the catalogue text is already accurate, so pass it through. |
|
31
|
#[cfg(any(target_os = "android", target_os = "windows"))] |
|
32
|
fn sanitize_description(desc: &str) -> String { |
|
33
|
desc.to_string() |
|
34
|
} |
|
35
|
|
|
36
|
/// List the supported on-device models, smallest first, with the currently |
|
37
|
/// selected model marked. Used to populate the Settings model dropdown. |
|
38
|
#[cfg(any( |
|
39
|
target_os = "macos", |
|
40
|
target_os = "ios", |
|
41
|
target_os = "android", |
|
42
|
target_os = "windows" |
|
43
|
))] |
|
44
|
#[tauri::command] |
|
45
|
pub async fn chat_list_models() -> Vec<ModelInfo> { |
|
46
|
use super::{config_for_model_id, is_model_downloaded, SELECTED_MODEL}; |
|
47
|
|
|
48
|
let selected = SELECTED_MODEL.lock().map(|g| g.clone()).unwrap_or_default(); |
|
49
|
|
|
50
|
let mut models: Vec<ModelInfo> = crate::inference::models::SUPPORTED_MODEL_INFO |
|
51
|
.iter() |
|
52
|
// Only include models the engine can build a loadable config for. |
|
53
|
.filter_map(|info| { |
|
54
|
config_for_model_id(info.id).map(|cfg| ModelInfo { |
|
55
|
id: info.id.to_string(), |
|
56
|
name: info.name.to_string(), |
|
57
|
org: info.org.to_string(), |
|
58
|
description: sanitize_description(info.description), |
|
59
|
approx_memory: cfg.approx_memory, |
|
60
|
size_bytes: Some(info.expected_size_bytes), |
|
61
|
is_downloaded: is_model_downloaded(info.id, info.expected_size_bytes), |
|
62
|
is_selected: info.id == selected, |
|
63
|
}) |
|
64
|
}) |
|
65
|
.collect(); |
|
66
|
|
|
67
|
// Gemma is not in onde's GGUF catalogue: mistral.rs's GGUF loader has no |
|
68
|
// Gemma architecture, so Gemma can only load via the ISQ (safetensors) |
|
69
|
// path, which is Metal-only. Offer it on macOS exclusively. |
|
70
|
#[cfg(target_os = "macos")] |
|
71
|
{ |
|
72
|
use super::{gemma2_2b_isq_config, GEMMA2_2B_IT_ISQ_ID}; |
|
73
|
const GEMMA2_2B_EXPECTED_BYTES: u64 = 5_228_717_512; |
|
74
|
let cfg = gemma2_2b_isq_config(); |
|
75
|
models.push(ModelInfo { |
|
76
|
id: GEMMA2_2B_IT_ISQ_ID.to_string(), |
|
77
|
name: "Gemma 2 2B (ISQ)".to_string(), |
|
78
|
org: "Google".to_string(), |
|
79
|
description: sanitize_description( |
|
80
|
"Google's Gemma 2 2B Instruct, quantised on-device to 4-bit (~1.6 GB). \ |
|
81
|
Loaded from safetensors via ISQ; requires 8+ GB RAM.", |
|
82
|
), |
|
83
|
approx_memory: cfg.approx_memory, |
|
84
|
// Full bf16 safetensors download before in-situ quantisation (~5.2 GB). |
|
85
|
size_bytes: Some(GEMMA2_2B_EXPECTED_BYTES), |
|
86
|
is_downloaded: is_model_downloaded(GEMMA2_2B_IT_ISQ_ID, GEMMA2_2B_EXPECTED_BYTES), |
|
87
|
is_selected: GEMMA2_2B_IT_ISQ_ID == selected, |
|
88
|
}); |
|
89
|
} |
|
90
|
|
|
91
|
// Smallest (most device-friendly) first. |
|
92
|
models.sort_by_key(|m| m.size_bytes.unwrap_or(u64::MAX)); |
|
93
|
models |
|
94
|
} |
|
95
|
|
|
96
|
#[cfg(not(any( |
|
97
|
target_os = "macos", |
|
98
|
target_os = "ios", |
|
99
|
target_os = "android", |
|
100
|
target_os = "windows" |
|
101
|
)))] |
|
102
|
#[tauri::command] |
|
103
|
pub async fn chat_list_models() -> Vec<ModelInfo> { |
|
104
|
log::debug!("On-device models are not supported on this platform."); |
|
105
|
Vec::new() |
|
106
|
} |