Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f3af98bfa | ||
|
|
77f9a8b518 | ||
|
|
2a7e6229f4 | ||
|
|
64e7baad66 | ||
|
|
804d451bfa | ||
|
|
a29e60b47d | ||
|
|
969ed6022e |
@@ -1,3 +1,7 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img src="bonus/clippy-says-hej.png" alt="WhispAssist logo with friendly Clippy saying hi there showing open source, private, note taker, and meeting advisor">
|
||||||
|
</p>
|
||||||
|
|
||||||
# WhispAssist (WA)
|
# WhispAssist (WA)
|
||||||
|
|
||||||
**A privacy-first, Windows-native meeting assistant that runs entirely on-device.**
|
**A privacy-first, Windows-native meeting assistant that runs entirely on-device.**
|
||||||
@@ -7,7 +11,7 @@ on-device acceleration (**NPU → GPU → CPU**), labels speakers, structures th
|
|||||||
Markdown notes, and optionally augments them with a locally hosted LLM (Ollama). Audio and
|
Markdown notes, and optionally augments them with a locally hosted LLM (Ollama). Audio and
|
||||||
transcripts **never leave the machine** unless you explicitly configure a destination.
|
transcripts **never leave the machine** unless you explicitly configure a destination.
|
||||||
|
|
||||||
> **Status: working application (v0.4.0).** Capture (system audio **+ your microphone**, with a
|
> **Status: working application (v0.5.2).** Capture (system audio **+ your microphone**, with a
|
||||||
> live **dual level meter**), transcription (CPU / Intel NPU / Vulkan GPU) with a **fluid live
|
> live **dual level meter**), transcription (CPU / Intel NPU / Vulkan GPU) with a **fluid live
|
||||||
> transcript**, speaker diarization, storage + crash recovery, local-LLM summaries, AI tags,
|
> transcript**, speaker diarization, storage + crash recovery, local-LLM summaries, AI tags,
|
||||||
> opt-in recording with **in-app playback**, at-rest encryption, self-hosted sync, **Outlook
|
> opt-in recording with **in-app playback**, at-rest encryption, self-hosted sync, **Outlook
|
||||||
@@ -27,6 +31,7 @@ transcripts **never leave the machine** unless you explicitly configure a destin
|
|||||||
| **NPU / GPU auto-acceleration** | n/a (cloud) | ⚠️ CPU/GPU, manual | ✅ **NPU→NVIDIA→AMD→Intel→CPU** ladder, one binary |
|
| **NPU / GPU auto-acceleration** | n/a (cloud) | ⚠️ CPU/GPU, manual | ✅ **NPU→NVIDIA→AMD→Intel→CPU** ladder, one binary |
|
||||||
| **Speaker diarization** | ✅ cloud | ⚠️ limited | ✅ offline (sherpa-onnx) |
|
| **Speaker diarization** | ✅ cloud | ⚠️ limited | ✅ offline (sherpa-onnx) |
|
||||||
| **Summaries / notes AI** | ☁️ cloud LLM | ✅ local (Ollama) / BYO | ✅ local (Ollama, localhost **or LAN**) + optional hosted |
|
| **Summaries / notes AI** | ☁️ cloud LLM | ✅ local (Ollama) / BYO | ✅ local (Ollama, localhost **or LAN**) + optional hosted |
|
||||||
|
| **Interface localization (UI language)** | ⚠️ English-only UI (multilingual transcription) | ⚠️ English-only UI (more planned) | ✅ **20 languages** + RTL (Arabic/Urdu) |
|
||||||
| **Default data egress** | ☁️ audio + notes to cloud | 🔒 local (cloud optional) | 🔒 **none** — everything off by default, allowlist-enforced |
|
| **Default data egress** | ☁️ audio + notes to cloud | 🔒 local (cloud optional) | 🔒 **none** — everything off by default, allowlist-enforced |
|
||||||
| **Calendar / Outlook `.pst` context** | ✅ cloud calendar | ❌ | ✅ local `.pst` import + **auto-record on events** |
|
| **Calendar / Outlook `.pst` context** | ✅ cloud calendar | ❌ | ✅ local `.pst` import + **auto-record on events** |
|
||||||
| **Import an existing recording (file/URL)** | ❌ live capture only | ❌ | ✅ any file or URL (ffmpeg + yt-dlp) |
|
| **Import an existing recording (file/URL)** | ❌ live capture only | ❌ | ✅ any file or URL (ffmpeg + yt-dlp) |
|
||||||
@@ -51,7 +56,7 @@ accelerated, zero-egress-by-default** option: it exploits the NPU/GPU in modern
|
|||||||
everything on the device unless you opt in, and adds Windows-specific context (Outlook) and a
|
everything on the device unless you opt in, and adds Windows-specific context (Outlook) and a
|
||||||
coding-agent handoff.
|
coding-agent handoff.
|
||||||
|
|
||||||
## What's built (v0.4.0)
|
## What's built (v0.5.2)
|
||||||
|
|
||||||
- **Bot-free capture — now both sides, with a live dual meter** — WASAPI loopback records the
|
- **Bot-free capture — now both sides, with a live dual meter** — WASAPI loopback records the
|
||||||
system mix (all participants), and an optional **microphone** path captures your own voice,
|
system mix (all participants), and an optional **microphone** path captures your own voice,
|
||||||
@@ -103,6 +108,14 @@ coding-agent handoff.
|
|||||||
(Claude, Codex, Copilot, OpenCode) over a **loopback-only, token-gated** MCP server that is off
|
(Claude, Codex, Copilot, OpenCode) over a **loopback-only, token-gated** MCP server that is off
|
||||||
by default, scope-limited, audited, and **adds no egress** — data leaves only via the agent's
|
by default, scope-limited, audited, and **adds no egress** — data leaves only via the agent's
|
||||||
own provider, which WA discloses.
|
own provider, which WA discloses.
|
||||||
|
- **20 interface languages, with RTL** — the whole UI (shell, meetings list, transcript/notes,
|
||||||
|
summary, and Settings) is available in **20 languages**, chosen under **Settings ▸ Language**:
|
||||||
|
Arabic (العربية), Bengali (বাংলা), Simplified Chinese (中文简体), English, Finnish (Suomi),
|
||||||
|
French — France & Canada (Français), German (Deutsch), Hindi (हिन्दी), Korean (한국어),
|
||||||
|
Norwegian Bokmål (Norsk bokmål), Portuguese — Brazil & Portugal (Português), Russian (Русский),
|
||||||
|
Sinhala (සිංහල), Spanish — Spain & Mexico (Español), Swedish (Svenska), Tamil (தமிழ்), and
|
||||||
|
Urdu (اردو). Selecting Arabic or Urdu flips the interface to **right-to-left**; any untranslated
|
||||||
|
string falls back to English rather than showing a raw key. Adding a language is a one-file job.
|
||||||
- **One universal installer** — a single signed MSI and NSIS `-setup.exe` that covers every
|
- **One universal installer** — a single signed MSI and NSIS `-setup.exe` that covers every
|
||||||
machine: Vulkan for all GPUs, the Intel NPU path (+ DirectML fallback), and CPU. The Vulkan
|
machine: Vulkan for all GPUs, the Intel NPU path (+ DirectML fallback), and CPU. The Vulkan
|
||||||
loader is bundled so it launches even on machines without a GPU driver.
|
loader is bundled so it launches even on machines without a GPU driver.
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# WhispAssist v0.5.2
|
||||||
|
|
||||||
|
**Privacy-first, Windows-native meeting assistant — everything on-device, nothing leaves unless you say so.**
|
||||||
|
|
||||||
|
A small but important bug-fix release. v0.5.2 fixes a startup crash that could stop WhispAssist
|
||||||
|
from opening after an upgrade, and makes any future database problem show a clear message instead
|
||||||
|
of failing silently. No feature or privacy changes — everything optional stays off-by-default and
|
||||||
|
local-first.
|
||||||
|
|
||||||
|
One universal installer (**MSI** and **NSIS**) covers every machine: **Vulkan** for all GPUs
|
||||||
|
(NVIDIA/AMD/Intel), the Intel **NPU** (OpenVINO), a **DirectML** fallback, and **CPU**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Fixes
|
||||||
|
|
||||||
|
### Fixed: app failing to launch after an upgrade
|
||||||
|
On some machines, upgrading could leave the app unable to open at all — no window, no message,
|
||||||
|
just nothing. The cause was a database-migration mismatch during startup: WhispAssist would hit
|
||||||
|
the error while opening its local database (`wa.db`) and, because the failure happened before the
|
||||||
|
window existed, the process exited silently and Windows reported only a generic crash.
|
||||||
|
|
||||||
|
### Startup database errors now explain themselves
|
||||||
|
Instead of that silent exit, a failure to open `wa.db` now shows a **native error dialog** naming
|
||||||
|
the problem and pointing at the database location, then exits cleanly. Your recordings and notes
|
||||||
|
are never touched — the message tells you exactly what happened and how to recover, rather than
|
||||||
|
leaving you with an app that won't start.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Install
|
||||||
|
|
||||||
|
**Requirements:** Windows 10 or 11 (x64). WhispAssist needs **WebView2** (preinstalled on Windows 11;
|
||||||
|
the installer fetches it on Windows 10). Importing from a file/URL additionally needs **`ffmpeg`**
|
||||||
|
(and **`yt-dlp`** for URLs) on your PATH — install those separately.
|
||||||
|
|
||||||
|
1. Download **`WhispAssist_0.5.2_x64_en-US.msi`** (or the NSIS **`WhispAssist_0.5.2_x64-setup.exe`**).
|
||||||
|
2. Run it and accept the UAC prompt. If SmartScreen appears, choose **More info → Run anyway**.
|
||||||
|
3. Launch **WhispAssist** from the Start menu.
|
||||||
|
|
||||||
|
On first run WA picks the best transcription backend (**NPU → NVIDIA → AMD → Intel → CPU**). It runs
|
||||||
|
without admin rights, never adds itself to startup, and keeps all data under
|
||||||
|
`%LOCALAPPDATA%\WhispAssist`.
|
||||||
|
|
||||||
|
## 🔐 Checksums (SHA-256)
|
||||||
|
|
||||||
|
```
|
||||||
|
b173b6b15590a65e96d3b24d0ad97666b8d1da905169d807ecc1c51df0584d3e WhispAssist_0.5.2_x64_en-US.msi
|
||||||
|
441b2e7ec7c68be39f9d2381af59ab9eadf916d6d23d0c5541d78bdd88c588b2 WhispAssist_0.5.2_x64-setup.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify after download:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Get-FileHash .\WhispAssist_0.5.2_x64_en-US.msi -Algorithm SHA256
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Privacy, unchanged
|
||||||
|
Everything optional is **off by default**. With nothing configured, WhispAssist makes **no content
|
||||||
|
egress at all**. Recording is opt-in; sync/AI credentials live only in the OS credential store; the
|
||||||
|
MCP server is loopback-only and adds no egress. The reachable-host allowlist is derived from your
|
||||||
|
settings and enforced in the core.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 728 KiB |
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "whispassist",
|
"name": "whispassist",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Privacy-first, fully local Windows meeting assistant.",
|
"description": "Privacy-first, fully local Windows meeting assistant.",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
|
|||||||
Generated
+1
-1
@@ -6043,7 +6043,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whispassist"
|
name = "whispassist"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2",
|
"argon2",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "whispassist"
|
name = "whispassist"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
description = "Privacy-first, fully local Windows meeting assistant"
|
description = "Privacy-first, fully local Windows meeting assistant"
|
||||||
authors = ["WhispAssist contributors"]
|
authors = ["WhispAssist contributors"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
@@ -99,6 +99,7 @@ windows = { version = "0.58", features = [
|
|||||||
"Win32_Devices_DeviceAndDriverInstallation", # SetupAPI: NPU detection (Phase 3, T3.4)
|
"Win32_Devices_DeviceAndDriverInstallation", # SetupAPI: NPU detection (Phase 3, T3.4)
|
||||||
"Win32_System_Com",
|
"Win32_System_Com",
|
||||||
"Win32_UI_Shell", # SetCurrentProcessExplicitAppUserModelID (Phase 8, T8.6)
|
"Win32_UI_Shell", # SetCurrentProcessExplicitAppUserModelID (Phase 8, T8.6)
|
||||||
|
"Win32_UI_WindowsAndMessaging", # MessageBoxW: fatal-startup error dialog (see run())
|
||||||
"UI_Notifications", # scheduled toast reminders (Phase 8, T8.6, FR-CAL-5) — the
|
"UI_Notifications", # scheduled toast reminders (Phase 8, T8.6, FR-CAL-5) — the
|
||||||
"Data_Xml_Dom", # OS delivers these itself at the due time, no polling timer
|
"Data_Xml_Dom", # OS delivers these itself at the due time, no polling timer
|
||||||
"Foundation",
|
"Foundation",
|
||||||
|
|||||||
+45
-4
@@ -98,14 +98,55 @@ pub struct RecordingSession {
|
|||||||
/// tooltip on recording state changes (FR-CAP-4).
|
/// tooltip on recording state changes (FR-CAP-4).
|
||||||
pub struct TrayHandle(pub TrayIcon);
|
pub struct TrayHandle(pub TrayIcon);
|
||||||
|
|
||||||
|
/// Show a blocking native error dialog and exit non-zero. Used for failures
|
||||||
|
/// that happen before the Tauri app (and its window) exist, where a silent
|
||||||
|
/// `panic=abort` fast-fail would otherwise close with no explanation. Exits
|
||||||
|
/// cleanly (code 1) rather than aborting so the OS reports no crash.
|
||||||
|
fn fatal_startup_error(body: &str) -> ! {
|
||||||
|
tracing::error!("fatal startup error: {body}");
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use windows::core::PCWSTR;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::{
|
||||||
|
MessageBoxW, MB_ICONERROR, MB_OK, MB_SYSTEMMODAL,
|
||||||
|
};
|
||||||
|
// Null-terminated UTF-16 for the Win32 wide API.
|
||||||
|
let to_wide = |s: &str| s.encode_utf16().chain(std::iter::once(0)).collect::<Vec<u16>>();
|
||||||
|
let text = to_wide(body);
|
||||||
|
let caption = to_wide("WhispAssist can't start");
|
||||||
|
// SAFETY: both buffers are null-terminated and outlive the call.
|
||||||
|
unsafe {
|
||||||
|
MessageBoxW(
|
||||||
|
None,
|
||||||
|
PCWSTR(text.as_ptr()),
|
||||||
|
PCWSTR(caption.as_ptr()),
|
||||||
|
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
eprintln!("WhispAssist can't start: {body}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/// Build state, register commands/events, and run the app.
|
/// Build state, register commands/events, and run the app.
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tracing_subscriber::fmt().with_env_filter("info").init();
|
tracing_subscriber::fmt().with_env_filter("info").init();
|
||||||
|
|
||||||
let store: Arc<dyn storage::Store> = Arc::new(
|
let store: Arc<dyn storage::Store> =
|
||||||
tauri::async_runtime::block_on(storage::SqliteStore::connect())
|
match tauri::async_runtime::block_on(storage::SqliteStore::connect()) {
|
||||||
.expect("failed to initialize storage (wa.db)"),
|
Ok(s) => Arc::new(s),
|
||||||
);
|
// A migration checksum mismatch (an edited-after-shipping migration)
|
||||||
|
// or a locked/corrupt file lands here. Tell the user instead of
|
||||||
|
// fast-failing into a silent no-launch.
|
||||||
|
Err(e) => fatal_startup_error(&format!(
|
||||||
|
"WhispAssist couldn't open its database (wa.db):\n\n{e}\n\n\
|
||||||
|
Your recordings and notes are not deleted. This usually means the \
|
||||||
|
database is from a newer version of WhispAssist, or a data migration \
|
||||||
|
is incompatible. Reinstalling the matching version, or moving wa.db \
|
||||||
|
aside from %LOCALAPPDATA%\\WhispAssist, will let the app start."
|
||||||
|
)),
|
||||||
|
};
|
||||||
let store_for_setup = store.clone();
|
let store_for_setup = store.clone();
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "WhispAssist",
|
"productName": "WhispAssist",
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"identifier": "bet.dou.whispassist",
|
"identifier": "bet.dou.whispassist",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
|
|||||||
Reference in New Issue
Block a user