fix(kon): task sidebar overlay, Parakeet model management, conditional engine settings
TaskSidebar: - Changed from flex layout member to fixed overlay with backdrop - Click backdrop or press Escape to close - Content no longer shrinks when sidebar opens — buttons stay accessible - Positioned at z-50 over main content, top offset for titlebar Settings — Parakeet model management: - Added Parakeet model state: download, check, load status - New downloadParakeet() and loadParakeet() functions - Listens for parakeet-download-progress events - Parakeet section shows download/load/status controls Settings — conditional engine sections: - Whisper model selector only shows when engine === "whisper" - Parakeet model controls only show when engine === "parakeet" - Cleaner UI — only active engine's options visible Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,14 @@
|
||||
let downloadProgress = $state(0);
|
||||
let unlisten = null;
|
||||
|
||||
// Parakeet state
|
||||
let parakeetStatus = $state("Checking...");
|
||||
let parakeetOk = $state(false);
|
||||
let parakeetDownloaded = $state(false);
|
||||
let parakeetDownloading = $state(false);
|
||||
let parakeetProgress = $state(0);
|
||||
let unlistenParakeet = null;
|
||||
|
||||
// Profiles & Templates
|
||||
let showProfiles = $state(false);
|
||||
let showTemplates = $state(false);
|
||||
@@ -39,13 +47,27 @@
|
||||
downloadedModels = await invoke("list_models");
|
||||
} catch {}
|
||||
|
||||
// Parakeet status
|
||||
try {
|
||||
parakeetOk = await invoke("check_parakeet_engine");
|
||||
parakeetDownloaded = await invoke("check_parakeet_model", { name: "ctc-int8" });
|
||||
parakeetStatus = parakeetOk ? "Model loaded" : parakeetDownloaded ? "Downloaded (not loaded)" : "Not downloaded";
|
||||
} catch {
|
||||
parakeetStatus = "Engine not ready";
|
||||
}
|
||||
|
||||
unlisten = await listen("model-download-progress", (event) => {
|
||||
downloadProgress = event.payload.progress;
|
||||
downloadProgress = event.payload.percent || event.payload.progress || 0;
|
||||
});
|
||||
|
||||
unlistenParakeet = await listen("parakeet-download-progress", (event) => {
|
||||
parakeetProgress = event.payload.percent || event.payload.progress || 0;
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (unlisten) unlisten();
|
||||
if (unlistenParakeet) unlistenParakeet();
|
||||
});
|
||||
|
||||
// Auto-save on any change
|
||||
@@ -105,6 +127,33 @@
|
||||
Medium: "~1.5GB · best quality, slower",
|
||||
};
|
||||
|
||||
async function downloadParakeet() {
|
||||
parakeetDownloading = true;
|
||||
parakeetProgress = 0;
|
||||
try {
|
||||
await invoke("download_parakeet_model", { name: "ctc-int8" });
|
||||
parakeetDownloaded = true;
|
||||
parakeetDownloading = false;
|
||||
parakeetStatus = "Downloaded (not loaded)";
|
||||
} catch {
|
||||
parakeetDownloading = false;
|
||||
parakeetStatus = "Download failed";
|
||||
}
|
||||
}
|
||||
|
||||
async function loadParakeet() {
|
||||
parakeetStatus = "Loading...";
|
||||
parakeetOk = false;
|
||||
try {
|
||||
await invoke("load_parakeet_model", { name: "ctc-int8" });
|
||||
parakeetOk = true;
|
||||
parakeetStatus = "Model loaded";
|
||||
} catch (err) {
|
||||
parakeetOk = false;
|
||||
parakeetStatus = typeof err === "string" ? err : "Load failed";
|
||||
}
|
||||
}
|
||||
|
||||
// --- Profile management ---
|
||||
function createProfile() {
|
||||
if (!newProfileName.trim()) return;
|
||||
@@ -180,13 +229,13 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Whisper model -->
|
||||
<!-- Engine-specific model management -->
|
||||
{#if settings.engine === "whisper"}
|
||||
<div class="mb-6">
|
||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">Whisper Model</p>
|
||||
<SegmentedButton options={["Tiny", "Base", "Small", "Medium"]} bind:value={settings.modelSize} />
|
||||
<p class="text-[11px] text-text-tertiary mt-2">{modelDescriptions[settings.modelSize]}</p>
|
||||
|
||||
<!-- Model status per size -->
|
||||
<div class="flex items-center gap-2 mt-3">
|
||||
{#if isModelDownloaded(settings.modelSize)}
|
||||
<span class="inline-flex items-center gap-1.5 text-[11px] text-success">
|
||||
@@ -207,6 +256,37 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="mb-6">
|
||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">Parakeet Model</p>
|
||||
<p class="text-[11px] text-text-tertiary mb-3">Parakeet CTC 0.6B (int8) — ~613MB, near-instant transcription</p>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
{#if parakeetOk}
|
||||
<span class="inline-flex items-center gap-1.5 text-[11px] text-success">
|
||||
<span class="w-[6px] h-[6px] rounded-full bg-success"></span>
|
||||
Model loaded
|
||||
</span>
|
||||
{:else if parakeetDownloaded}
|
||||
<span class="inline-flex items-center gap-1.5 text-[11px] text-text-secondary">
|
||||
<span class="w-[6px] h-[6px] rounded-full bg-text-tertiary"></span>
|
||||
Downloaded
|
||||
</span>
|
||||
<button
|
||||
class="text-[11px] text-text-tertiary hover:text-accent"
|
||||
onclick={loadParakeet}
|
||||
>Load model</button>
|
||||
{:else if parakeetDownloading}
|
||||
<span class="text-[11px] text-warning">{parakeetProgress}% downloading...</span>
|
||||
{:else}
|
||||
<button
|
||||
class="text-[11px] text-accent hover:text-accent-hover"
|
||||
onclick={downloadParakeet}
|
||||
>Download Parakeet</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Compute device -->
|
||||
<div class="mb-6">
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window onmousemove={handleMouseMove} />
|
||||
<svelte:window onmousemove={handleMouseMove} onkeydown={(e) => { if (e.key === "Escape" && page.taskSidebarOpen) page.taskSidebarOpen = false; }} />
|
||||
|
||||
{#if page.recording}
|
||||
<div
|
||||
@@ -113,16 +113,27 @@
|
||||
{:else}
|
||||
<div class="flex flex-col h-screen w-screen overflow-hidden grain">
|
||||
<Titlebar />
|
||||
<div class="flex flex-1 min-h-0">
|
||||
<div class="flex flex-1 min-h-0 relative">
|
||||
{#if page.current !== "first-run"}
|
||||
<Sidebar />
|
||||
{/if}
|
||||
<div class="flex-1 overflow-hidden bg-bg">
|
||||
{@render children()}
|
||||
</div>
|
||||
{#if page.taskSidebarOpen && page.current !== "first-run"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Task sidebar as overlay — doesn't shrink main content -->
|
||||
{#if page.taskSidebarOpen && page.current !== "first-run" && !isSecondaryWindow}
|
||||
<!-- Backdrop -->
|
||||
<button
|
||||
class="fixed inset-0 bg-black/20 z-40"
|
||||
onclick={() => page.taskSidebarOpen = false}
|
||||
aria-label="Close task sidebar"
|
||||
></button>
|
||||
<!-- Sidebar panel -->
|
||||
<div class="fixed top-[36px] right-0 bottom-0 z-50 animate-slide-in-right">
|
||||
<TaskSidebar />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user