From 5458b338188994e79820ea09cecd89775a656e64 Mon Sep 17 00:00:00 2001 From: kylethedeveloper <8023096+kylethedeveloper@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:16:46 -0400 Subject: [PATCH 1/2] feat: add language selection option --- .github/workflows/build.yml | 6 +++--- TODO.md | 2 +- src-tauri/src/lib.rs | 2 ++ src-tauri/src/transcriber.rs | 11 ++++++++++- src/index.html | 33 +++++++++++++++++++++++++++++++++ src/main.js | 2 ++ src/styles.css | 8 +++++--- 7 files changed, 56 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b18ff3..7a68839 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Build OratioText on: push: - branches: [ master, develop ] - pull_request: - branches: [ master ] + branches: [ develop ] + # pull_request: + # branches: [ master ] jobs: build-macos-arm64: diff --git a/TODO.md b/TODO.md index 391f644..ce3a6c4 100644 --- a/TODO.md +++ b/TODO.md @@ -3,8 +3,8 @@ - [x] Add a progress bar for the download of the Whisper model (with cancel option) - [x] Add an icon - [x] Build for Windows and macOS (see [BUILD.md](./BUILD.md)) +- [x] Add language selection option (or detect automatically) - [ ] Add a help menu - [ ] Add an about menu (feedback, donate, etc) - [ ] Build for Linux -- [ ] Add language selection option (or detect automatically) - [ ] Add history of transcriptions \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 17e5dd8..2401391 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -94,6 +94,7 @@ async fn download_model( async fn transcribe( file_path: String, model_name: String, + language: String, state: State<'_, AppState>, app: tauri::AppHandle, ) -> Result { @@ -126,6 +127,7 @@ async fn transcribe( let result = t .transcribe_with_progress( &file_path, + Some(language), move |stage, percent| { let _ = app_for_callback.emit( "transcription-progress", diff --git a/src-tauri/src/transcriber.rs b/src-tauri/src/transcriber.rs index 976fa07..5b2deca 100644 --- a/src-tauri/src/transcriber.rs +++ b/src-tauri/src/transcriber.rs @@ -50,6 +50,7 @@ impl Transcriber { pub fn transcribe_with_progress( &self, audio_path: &str, + language: Option, on_progress: F, cancel_flag: Arc, ) -> Result> @@ -80,7 +81,15 @@ impl Transcriber { // Configure whisper parameters let mut params = FullParams::new(SamplingStrategy::Greedy { best_of: 1 }); - params.set_language(None); + if let Some(ref lang) = language { + if lang == "auto" { + params.set_language(Some("auto")); + } else { + params.set_language(Some(lang.as_str())); + } + } else { + params.set_language(Some("auto")); + } params.set_print_progress(false); params.set_print_realtime(false); params.set_print_timestamps(false); diff --git a/src/index.html b/src/index.html index bda5c74..0d930c6 100644 --- a/src/index.html +++ b/src/index.html @@ -48,6 +48,39 @@

OratioText

+
+ +
diff --git a/src/main.js b/src/main.js index b78e242..e57ced6 100644 --- a/src/main.js +++ b/src/main.js @@ -25,6 +25,7 @@ const downloadProgress = document.getElementById("download-progress"); const progressFill = document.getElementById("progress-fill"); const progressText = document.getElementById("progress-text"); const modelInfo = document.getElementById("model-info"); +const languageSelect = document.getElementById("language-select"); const generateBtn = document.getElementById("generate-btn"); const stopBtn = document.getElementById("stop-btn"); const timestampsToggle = document.getElementById("timestamps-toggle"); @@ -217,6 +218,7 @@ async function startTranscription() { transcriptionResult = await invoke("transcribe", { filePath: selectedFilePath, modelName, + language: languageSelect.value }); updateTranscriptionDisplay(); diff --git a/src/styles.css b/src/styles.css index 76f3fe5..56a9572 100644 --- a/src/styles.css +++ b/src/styles.css @@ -75,7 +75,7 @@ body { display: flex; flex-direction: column; height: 100vh; - padding: var(--spacing-lg); + padding: var(--spacing-md); gap: var(--spacing-md); } @@ -437,7 +437,9 @@ body { } @keyframes spin { - to { transform: rotate(360deg); } + to { + transform: rotate(360deg); + } } /* ========================================================================== @@ -533,4 +535,4 @@ body { font-weight: 600; color: var(--color-text-muted); font-variant-numeric: tabular-nums; -} +} \ No newline at end of file From e37d03d9fb158488ca0b162a11bcf3fbc276319f Mon Sep 17 00:00:00 2001 From: kylethedeveloper <8023096+kylethedeveloper@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:38:01 -0400 Subject: [PATCH 2/2] feat: add hamburger menu; Home, History, About --- TODO.md | 1 - src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/lib.rs | 6 +++++ src-tauri/tauri.conf.json | 2 +- src/index.html | 55 +++++++++++++++++++++++++++++++++++--- src/main.js | 54 +++++++++++++++++++++++++++++++++++++ src/styles.css | 56 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 170 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index ce3a6c4..f8fcc16 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ - [x] Add an icon - [x] Build for Windows and macOS (see [BUILD.md](./BUILD.md)) - [x] Add language selection option (or detect automatically) -- [ ] Add a help menu - [ ] Add an about menu (feedback, donate, etc) - [ ] Build for Linux - [ ] Add history of transcriptions \ No newline at end of file diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ddc1a5b..650482d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2372,7 +2372,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "oratiotext" -version = "1.0.0" +version = "1.0.1" dependencies = [ "dirs", "futures-util", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8912f0b..8e0143b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oratiotext" -version = "1.0.0" +version = "1.0.1" description = "A cross-platform desktop application for converting speech to text using Whisper" authors = ["kylethedeveloper"] edition = "2021" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2401391..2e0177f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -42,6 +42,11 @@ struct ModelInfo { downloaded: bool, } +#[tauri::command] +fn get_app_version(app: tauri::AppHandle) -> String { + app.package_info().version.to_string() +} + #[tauri::command] fn get_system_info() -> SystemInfo { use sysinfo::System; @@ -185,6 +190,7 @@ pub fn run() { transcribe, stop_transcription, save_file, + get_app_version, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e6651cb..d43bb98 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json", "productName": "OratioText", - "version": "1.0.0", + "version": "1.0.1", "identifier": "com.oratiotext.app", "build": { "frontendDist": "../src" diff --git a/src/index.html b/src/index.html index 0d930c6..b84c003 100644 --- a/src/index.html +++ b/src/index.html @@ -1,17 +1,44 @@ + OratioText +
+ + + +
OratioText @@ -20,7 +47,7 @@

OratioText

Speech to Text — runs entirely on your computer

-
+
@@ -119,8 +146,28 @@

OratioText

+ +
+
+ +

History is empty for now.

+
+
+ +
+
+

Loading + version...

+

OratioText is a speech to text application that runs entirely on your local + machine, ensuring + full privacy.
It uses the whisper.cpp models under the hood.

+ GitHub Repository +
+
- + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index e57ced6..a531066 100644 --- a/src/main.js +++ b/src/main.js @@ -36,15 +36,38 @@ const statusText = document.getElementById("status-text"); const languageInfo = document.getElementById("language-info"); const languageText = document.getElementById("language-text"); +// ---- Navigation Elements -------------------------------------------------- +const menuToggle = document.getElementById("menu-toggle"); +const navDropdown = document.getElementById("nav-dropdown"); +const navItems = document.querySelectorAll(".nav-item"); +const pages = { + home: document.getElementById("page-home"), + history: document.getElementById("page-history"), + about: document.getElementById("page-about"), +}; + // ---- Initialization ------------------------------------------------------- document.addEventListener("DOMContentLoaded", async () => { await loadModels(); + await loadAppVersion(); setupEventListeners(); setupDownloadProgressListener(); setupTranscriptionProgressListener(); }); +async function loadAppVersion() { + try { + const version = await invoke("get_app_version"); + const appVersionEl = document.getElementById("app-version"); + if (appVersionEl) { + appVersionEl.textContent = `Version ${version}`; + } + } catch (err) { + console.error("Failed to load app version:", err); + } +} + async function loadModels() { try { const [models, sysInfo] = await Promise.all([ @@ -100,6 +123,37 @@ function setupEventListeners() { saveBtn.addEventListener("click", saveTranscription); timestampsToggle.addEventListener("change", updateTranscriptionDisplay); modelSelect.addEventListener("change", updateModelUI); + + // Navigation events + menuToggle.addEventListener("click", () => { + navDropdown.classList.toggle("hidden"); + }); + + document.addEventListener("click", (e) => { + if (!menuToggle.contains(e.target) && !navDropdown.contains(e.target)) { + navDropdown.classList.add("hidden"); + } + }); + + navItems.forEach((btn) => { + btn.addEventListener("click", () => { + const targetPage = btn.dataset.page; + navDropdown.classList.add("hidden"); + + // Update active button + navItems.forEach((b) => b.classList.remove("active")); + btn.classList.add("active"); + + // Show target page, hide others + Object.keys(pages).forEach((page) => { + if (page === targetPage) { + pages[page].classList.remove("hidden"); + } else { + pages[page].classList.add("hidden"); + } + }); + }); + }); } function setupDownloadProgressListener() { diff --git a/src/styles.css b/src/styles.css index 56a9572..96e4172 100644 --- a/src/styles.css +++ b/src/styles.css @@ -144,6 +144,62 @@ body { margin-top: var(--spacing-xs); } +/* ========================================================================== + Navigation Menu + ========================================================================== */ + +.nav-dropdown { + position: absolute; + top: 44px; + left: 0; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + padding: var(--spacing-xs); + display: flex; + flex-direction: column; + gap: 2px; + z-index: 100; + min-width: 150px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); +} + +[data-theme="light"] .nav-dropdown { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +.nav-item { + background: none; + border: none; + color: var(--color-text); + font-family: var(--font-family); + font-size: 0.9rem; + padding: 8px 12px; + text-align: left; + border-radius: 4px; + cursor: pointer; + transition: all var(--transition); +} + +.nav-item:hover { + background: var(--color-surface-hover); +} + +.nav-item.active { + background: var(--color-primary-glow); + color: var(--color-primary-hover); + font-weight: 600; +} + +.about-section { + text-align: center; + padding: var(--spacing-xl); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + /* ========================================================================== Main content ========================================================================== */