diff --git a/src-tauri/src/commands/hardware.rs b/src-tauri/src/commands/hardware.rs new file mode 100644 index 0000000..f91d98a --- /dev/null +++ b/src-tauri/src/commands/hardware.rs @@ -0,0 +1,69 @@ +use serde::Serialize; + +use kon_core::hardware::{self, Os}; +use kon_core::recommendation; + +#[derive(Serialize)] +pub struct SystemInfo { + pub ram_mb: u64, + pub cpu_brand: String, + pub cpu_cores: usize, + pub os: String, + pub gpu: Option, +} + +#[derive(Serialize)] +pub struct ModelRecommendation { + pub id: String, + pub display_name: &'static str, + pub disk_size_mb: u64, + pub ram_required_mb: u64, + pub description: &'static str, + pub score: f64, + pub reason: String, + pub is_downloaded: bool, +} + +/// Probe system hardware and return a summary. +#[tauri::command] +pub fn probe_system() -> Result { + let profile = hardware::probe_system(); + Ok(SystemInfo { + ram_mb: profile.ram.0, + cpu_brand: profile.cpu.brand, + cpu_cores: profile.cpu.core_count, + os: match profile.os { + Os::Windows => "Windows", + Os::Linux => "Linux", + Os::MacOs => "macOS", + Os::Ios => "iOS", + Os::Android => "Android", + } + .to_string(), + gpu: profile.gpu.map(|g| format!("{:?}", g.vendor)), + }) +} + +/// Rank models for the current system and return recommendations. +#[tauri::command] +pub fn rank_models() -> Result, String> { + let profile = hardware::probe_system(); + let ranked = recommendation::rank_recommendations(&profile); + + Ok(ranked + .into_iter() + .map(|scored| { + let downloaded = kon_transcription::is_downloaded(&scored.entry.id); + ModelRecommendation { + id: scored.entry.id.as_str().to_string(), + display_name: scored.entry.display_name, + disk_size_mb: scored.entry.disk_size.0, + ram_required_mb: scored.entry.ram_required.0, + description: scored.entry.description, + score: scored.score, + reason: scored.reason, + is_downloaded: downloaded, + } + }) + .collect()) +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 84316e2..91b362a 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -1,5 +1,6 @@ pub mod audio; pub mod clipboard; +pub mod hardware; pub mod llm; pub mod models; pub mod transcription; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 28d6603..6ab4dea 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -70,6 +70,9 @@ pub fn run() { commands::windows::open_viewer_window, // Clipboard commands::clipboard::copy_to_clipboard, + // Hardware + commands::hardware::probe_system, + commands::hardware::rank_models, // LLM stubs commands::llm::download_llm_model, commands::llm::check_llm_model, diff --git a/src/lib/pages/FirstRunPage.svelte b/src/lib/pages/FirstRunPage.svelte new file mode 100644 index 0000000..55aab82 --- /dev/null +++ b/src/lib/pages/FirstRunPage.svelte @@ -0,0 +1,170 @@ + + +
+ {#if probing} +
+ +

Setting up Kon

+

Detecting your hardware...

+
+ + {:else if ready} +
+ +

Ready to go

+

Starting Kon...

+
+ + {:else if downloading} +
+

Downloading model

+

{downloadingModel}

+
+
+
+

{downloadProgress}%

+
+ + {:else} +
+

Welcome to Kon

+

Think out loud

+ + {#if error} +
{error}
+ {/if} + + {#if systemInfo} +
+

Your system

+
+ RAM + {Math.round(systemInfo.ram_mb / 1024)} GB + CPU + {systemInfo.cpu_brand} + Cores + {systemInfo.cpu_cores} + OS + {systemInfo.os} +
+
+ {/if} + + {#if models.length > 0} +
+

Recommended models

+
+ {#each models as model, i} + + {/each} +
+
+ {/if} + + +
+ {/if} +
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 588eb67..853c9e9 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,6 +1,7 @@
- {#if page.current === "dictation"} + {#if page.current === "first-run"} + + {:else if page.current === "dictation"} {:else if page.current === "files"}