fix(kon): rename ramble refs, fix export extensions, use shared constants in DictationPage
- Rename custom event from ramble:toggle-recording to kon:toggle-recording - Change download filename prefix from ramble- to kon- - Fix export extension mapping: csv and html formats now produce correct file extensions instead of falling through to .txt - Add console.warn when PCM buffer exceeds 5-minute cap and gets truncated - Replace magic numbers with shared constants (MAX_PCM_SAMPLES, MIN_CHUNK_SAMPLES, CHUNK_INTERVAL_MS, FEEDBACK_TIMEOUT_MS) - Use shared pad() utility from time.js instead of inline reimplementation - Remove unused saveTasks import - Simplify redundant 3-branch append logic to 2 branches with clarifying comment - Use $derived.by to avoid double transcript.trim() in wordCount Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,13 @@
|
|||||||
import { onMount, onDestroy } from "svelte";
|
import { onMount, onDestroy } from "svelte";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { page, settings, templates, addToHistory, addTask, tasks, saveTasks } from "$lib/stores/page.svelte.js";
|
import { page, settings, templates, addToHistory, addTask, tasks } from "$lib/stores/page.svelte.js";
|
||||||
import Card from "$lib/components/Card.svelte";
|
import Card from "$lib/components/Card.svelte";
|
||||||
import ModelDownloader from "$lib/components/ModelDownloader.svelte";
|
import ModelDownloader from "$lib/components/ModelDownloader.svelte";
|
||||||
import { exportTranscript } from "$lib/utils/export.js";
|
import { exportTranscript } from "$lib/utils/export.js";
|
||||||
import { extractTasks } from "$lib/utils/taskExtractor.js";
|
import { extractTasks } from "$lib/utils/taskExtractor.js";
|
||||||
|
import { pad } from "$lib/utils/time.js";
|
||||||
|
import { MAX_PCM_SAMPLES, MIN_CHUNK_SAMPLES, CHUNK_INTERVAL_MS, FEEDBACK_TIMEOUT_MS } from "$lib/utils/constants.js";
|
||||||
|
|
||||||
let transcript = $state("");
|
let transcript = $state("");
|
||||||
let segments = $state([]);
|
let segments = $state([]);
|
||||||
@@ -62,14 +64,14 @@
|
|||||||
handleResult(result);
|
handleResult(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("ramble:toggle-recording", hotkeyHandler);
|
window.addEventListener("kon:toggle-recording", hotkeyHandler);
|
||||||
|
|
||||||
await checkModelState();
|
await checkModelState();
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if (unlisten) unlisten();
|
if (unlisten) unlisten();
|
||||||
window.removeEventListener("ramble:toggle-recording", hotkeyHandler);
|
window.removeEventListener("kon:toggle-recording", hotkeyHandler);
|
||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
clearInterval(chunkTimer);
|
clearInterval(chunkTimer);
|
||||||
if (page.recording) {
|
if (page.recording) {
|
||||||
@@ -106,9 +108,9 @@
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Append mode
|
// Append mode
|
||||||
if (transcript && result.chunk_id > 1) {
|
// First chunk (id=1) starts the transcript; subsequent chunks append to it.
|
||||||
transcript += " " + text;
|
// When transcript is empty, assign directly; otherwise prepend a space separator.
|
||||||
} else if (!transcript) {
|
if (!transcript) {
|
||||||
transcript = text;
|
transcript = text;
|
||||||
} else {
|
} else {
|
||||||
transcript += " " + text;
|
transcript += " " + text;
|
||||||
@@ -247,7 +249,7 @@
|
|||||||
page.status = "Recording...";
|
page.status = "Recording...";
|
||||||
page.statusColor = "#e87171";
|
page.statusColor = "#e87171";
|
||||||
timerInterval = setInterval(updateTimer, 1000);
|
timerInterval = setInterval(updateTimer, 1000);
|
||||||
chunkTimer = setInterval(sendChunk, 3000);
|
chunkTimer = setInterval(sendChunk, CHUNK_INTERVAL_MS);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = `Microphone access denied: ${err.message}`;
|
error = `Microphone access denied: ${err.message}`;
|
||||||
page.status = "Error";
|
page.status = "Error";
|
||||||
@@ -294,15 +296,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendChunk() {
|
async function sendChunk() {
|
||||||
if (pcmBuffer.length < 8000) return;
|
if (pcmBuffer.length < MIN_CHUNK_SAMPLES) return;
|
||||||
if (transcribing) return;
|
if (transcribing) return;
|
||||||
|
|
||||||
chunkId++;
|
chunkId++;
|
||||||
const currentChunkId = chunkId;
|
const currentChunkId = chunkId;
|
||||||
const samples = [...pcmBuffer];
|
const samples = [...pcmBuffer];
|
||||||
pcmBuffer = [];
|
pcmBuffer = [];
|
||||||
if (samples.length > 4_800_000) {
|
if (samples.length > MAX_PCM_SAMPLES) {
|
||||||
samples.length = 4_800_000;
|
console.warn(`PCM buffer truncated from ${samples.length} to ${MAX_PCM_SAMPLES} samples (~5 min at 16 kHz)`);
|
||||||
|
samples.length = MAX_PCM_SAMPLES;
|
||||||
}
|
}
|
||||||
transcribing = true;
|
transcribing = true;
|
||||||
|
|
||||||
@@ -404,9 +407,7 @@
|
|||||||
|
|
||||||
function updateTimer() {
|
function updateTimer() {
|
||||||
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
||||||
const mins = Math.floor(elapsed / 60).toString().padStart(2, "0");
|
page.timerText = `${pad(Math.floor(elapsed / 60))}:${pad(elapsed % 60)}`;
|
||||||
const secs = (elapsed % 60).toString().padStart(2, "0");
|
|
||||||
page.timerText = `${mins}:${secs}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyAll() {
|
function copyAll() {
|
||||||
@@ -427,12 +428,13 @@
|
|||||||
if (!transcript) return;
|
if (!transcript) return;
|
||||||
showExportMenu = false;
|
showExportMenu = false;
|
||||||
const content = exportTranscript(transcript, segments, format);
|
const content = exportTranscript(transcript, segments, format);
|
||||||
const ext = format === "vtt" ? "vtt" : format === "srt" ? "srt" : format === "md" ? "md" : "txt";
|
const extMap = { vtt: "vtt", srt: "srt", md: "md", csv: "csv", html: "html" };
|
||||||
|
const ext = extMap[format] || "txt";
|
||||||
const blob = new Blob([content], { type: "text/plain" });
|
const blob = new Blob([content], { type: "text/plain" });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = `ramble-${new Date().toISOString().slice(0, 10)}.${ext}`;
|
a.download = `kon-${new Date().toISOString().slice(0, 10)}.${ext}`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
@@ -484,14 +486,15 @@
|
|||||||
language: settings.language,
|
language: settings.language,
|
||||||
});
|
});
|
||||||
saved = true;
|
saved = true;
|
||||||
setTimeout(() => { saved = false; }, 3000);
|
setTimeout(() => { saved = false; }, FEEDBACK_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
let taskCount = $derived(tasks.filter((t) => !t.done).length);
|
let taskCount = $derived(tasks.filter((t) => !t.done).length);
|
||||||
|
|
||||||
let wordCount = $derived(
|
let wordCount = $derived.by(() => {
|
||||||
transcript.trim() ? transcript.trim().split(/\s+/).length : 0
|
const trimmed = transcript.trim();
|
||||||
);
|
return trimmed ? trimmed.split(/\s+/).length : 0;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col h-full animate-fade-in">
|
<div class="flex flex-col h-full animate-fade-in">
|
||||||
|
|||||||
Reference in New Issue
Block a user