mirror of
https://github.com/OpenWhispr/openwhispr.git
synced 2026-10-21 06:40:37 +08:00
codex/note-header-responsive
22
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c4ae6071e8 |
fix(scripts): let download scripts exit after following a redirect (#2410)
* fix(scripts): let download scripts exit after following a redirect downloadFile followed redirects without reading the redirect body. On Node 24 the global agent keeps sockets alive and only frees (and unrefs) a socket once its response ends, so the unread 302 from huggingface.co pinned the socket and kept `download-whisper-vad-model.js` alive for minutes, stalling the `predev:main` chain before Electron started. Drain redirect bodies in downloadFile and fetchJson, drain fetchJson's non-200 bodies, and destroy a timed-out fetchJson request instead of only rejecting. * fix(scripts): keep a followed redirect from cancelling the live download downloadFile's error and timeout handlers acted on whichever request was current, so a reset on a redirect whose body was still draining destroyed the request that replaced it and forced a retry. Each handler now only acts on its own request; a stale one that times out is just destroyed. Also adds a test for fetchJson's timeout closing the stalled request. |
||
|
|
94aeecb75a |
fix(notes): give note formatting a ten-minute deadline and stop retrying timeouts (#2204)
## Problem Generate AI Summary with a bring-your-own-key provider sends the whole transcript to a model that may reason for a minute or more before it writes. Every BYOK request shared the 30-second deadline meant for dictation cleanup, and an expired deadline was treated like a dropped connection and retried three more times. A 2,170-word transcript through GPT-5.6 Terra spun for about 1.5 minutes, was billed for four requests, and ended with "Request timed out after 30s" and no note. 1.10.1 exposed this: raising the reasoning-model output cap to 25k tokens let Terra think long enough to cross 30s. Enterprise reasoning (Bedrock, Azure, Vertex) had the same bug behind a different constant: the main-process handler applied its own 60-second default because the renderer never sent a deadline. ## Fix - `getLlmRequestTimeoutSeconds` takes the request's inference scope. `noteFormatting` gets 600s (the OpenAI SDK's own default); dictation cleanup keeps 30s; streaming keeps its 60s idle deadline. - `llmRequestTimeoutError` carries `LLM_REQUEST_TIMEOUT_CODE`, and `createApiRetryStrategy` refuses to retry it. The same request under the same deadline expires again, and every attempt is billed. - OpenAI, Gemini, Tinfoil and the generic chat-completions path (Groq, LAN, custom endpoints) pass their scope and raise the coded error. Tinfoil maps the SDK's `APIConnectionTimeoutError` onto it so it is not re-sent either. - The enterprise provider sends `timeoutMs` from the same helper. The handler already honoured that field. Note: this moves enterprise dictation cleanup from 60s to 30s, matching every other provider. - Note prompt wrappers and `NOTE_OUTPUT_MAX_TOKENS` move from the action store to `builtinActions.js` so the live canary sends exactly what the app sends. ## Tests - Every inference scope must be classified as interactive (≤ 60s) or background (≥ 300s); a new scope with no verdict fails. - OpenAI and Gemini note requests survive the 30s tick, fail once at 600s, and issue exactly one POST. Cleanup still times out at 30s. - A note request through the real `ReasoningService` dispatch outlives the dictation deadline and is sent once. - Tinfoil receives the long deadline, maps the SDK timeout to the coded error, and does not re-send. - Enterprise forwards 600s for notes and 30s for cleanup to the main process. - `withRetry` makes exactly one attempt for a coded timeout. - The note store's requests carry the `noteFormatting` scope. ## Canary `llm-canary` now runs one meeting-sized Detailed Notes request per keyed provider (gpt-5.6-terra, gemini-3.5-flash) through the app's real provider code under the note-formatting deadline, reporting elapsed time, tokens, and a slow warning past half the budget. This is the only layer that can catch a provider or model change crossing the deadline. |
||
|
|
4d6077ded8 |
fix(parakeet): ship ONNX Runtime under a private DLL name on Windows (#2074)
* build(win32): add a PE import-name reader and patcher Read and rewrite module names in a PE image's import and delay-load directories. Names are patched in place, so a replacement can never be longer than the original. Needed to point the bundled sherpa-onnx binaries at a privately named ONNX Runtime (#2054). * fix(parakeet): ship ONNX Runtime as ow-onnxrt.dll on Windows (#2054) Windows 11 ships an older onnxruntime.dll (1.17) in System32. The bundled sherpa-onnx 1.13.4 binaries are built against ORT 1.27 and bind the runtime by bare module name, and on some machines the loader resolves that name to the System32 copy even though ours sits beside the exe. The exe then fails with "requested API version [27] is not available" before it can listen, which the app reports as "parakeet-ws process died during startup". Rename the extracted runtime to ow-onnxrt.dll at download time and rewrite the import tables of every sherpa image to match, so no name-based loader rule (PreferSystem32Images, KnownDlls, an already loaded module) can substitute the system copy. Record the rename in the install marker so checkouts extracted before this change re-download. Upstream's archive lists each DLL twice (bin/ and lib/), so the library list is deduplicated. Remove once microsoft/onnxruntime#27893 (version-suffixed DLL names) lands and sherpa-onnx adopts it. * build(win32): fail packaging if onnxruntime.dll would ship The Windows package must contain ow-onnxrt.dll and no onnxruntime.dll. A stray upstream DLL or a missing private one means the rename step in download-sherpa-onnx.js was skipped (stale cache, older marker) and Parakeet would die at startup for users (#2054). * fix(parakeet): Invalidate install markers before automatic repairs Clear the completion marker before every reinstall so a failed DLL patch cannot leave a partially patched bundle marked complete. Add regression coverage for patch failure and successful automatic retry. |
||
|
|
fad475c6f4 |
fix(whisper): extract MSVC runtime DLLs beside win32 whisper-server (#1687)
* fix(whisper): extract MSVC runtime DLLs beside win32 whisper-server The win32 CPU whisper-server.exe links the dynamic MSVC runtime (msvcp140/vcruntime140/vcruntime140_1/vcomp140) but shipped as a bare exe: download-whisper-cpp.js copied only the binary out of the release zip, so on machines without the VC++ 2015-2022 redistributable the Windows loader killed every spawn with 0xC0000135 (STATUS_DLL_NOT_FOUND) before main(), with empty stderr — local transcription dead on arrival (CUS-113). - pin whisper.cpp 0.0.10, the first release whose win32 zips bundle the DLLs - give the win32 config the same libPattern DLL-companion extraction the llama/sherpa download scripts already use, consolidating their duplicated findLibrariesInDir/matchesPattern helpers into lib/download-utils.js - prep whisperVulkanManager with libPattern so the 0.0.10 vulkan zip's CRT DLLs are extracted too (its "statically linked" comment was wrong re CRT) electron-builder's extraResources filter already passes *.dll and cleanupFiles already spares libraries, so no packaging-config change needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(downloads): validate cached binaries and traversal errors * fix(whisper): Preserve migration and propagate download failures Keep legacy Windows Vulkan packs migratable until the DLL-bearing release and digest update lands. Make all-platform downloads exit nonzero after any platform failure and remove the unused numeric library-search options shim. * fix(gpu): Require Windows whisper runtime libraries Pin CUDA and Vulkan packs to verified 0.0.10 assets and reject incomplete caches or staged installs. Preserve the existing pack when validation fails. * fix(deps): Upgrade Tiptap past attribute injection advisory Align the full Tiptap package family at 3.30.4, the first patched release for GHSA-cp6q-959q-f8rh. Restore the npm audit gate without unrelated dependency upgrades. * fix(deps): Patch xmldom serialization advisory Upgrade the existing xmldom override to 0.8.15, the first patched 0.8.x release for GHSA-6gmq-8vp8-gcm6, so the npm audit gate remains clean. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Chadpiha <chadpiha23@gmail.com> |
||
|
|
5d69b75a2e |
feat(calendar): Apple Calendar (EventKit) integration for macOS (#1237)
* feat(calendar): Apple Calendar (EventKit) integration for macOS Add a second calendar provider that reads the local EventKit store — covering iCloud, Google, Exchange, and Outlook accounts already in Calendar.app — with one native permission prompt and push-based updates instead of OAuth + polling. - New macos-calendar-listener Swift helper (mic-listener pattern): emits permission + calendars/events snapshots as line-delimited JSON, re-emits on EKEventStoreChanged, stdin "sync", and a 5-min window roll; --request triggers the TCC prompt attributed to OpenWhispr - Build script patches dev Electron's Info.plist with calendar usage strings; packaged builds get them via electron-builder extendInfo, plus the calendars entitlement for hardened runtime - calendar_events gains a provider column; new apple_calendars table; Google deletes are provider-scoped; shared read queries suppress Apple copies of Google-mirrored meetings (datetime-normalized, Google rows never collapsed) so reminders fire once per meeting - Meeting reminder scheduling extracted from GoogleCalendarManager into a provider-agnostic CalendarReminderScheduler shared by both managers - AppleCalendarManager owns the helper lifecycle; meeting join links are extracted from url/location/notes into hangout_link at sync time so Join buttons and note linking work unchanged - Integrations UI gets an Apple Calendar row (macOS only) with connect, denied → System Settings flow, source list, and disconnect; i18n keys added to all 10 locales Downstream consumers (Upcoming Meetings, overlay reminders, agent calendar tool, note linking) read the shared table and work for both providers with no changes. * refactor(calendar): Harden EventKit integration and extract shared helpers * fix(calendar): Show the calendar permission prompt in dev builds * chore(calendar): Clean up after dev TCC fix * fix: tentative meeting responses and stale state fix * fix: dev script * fix(tests): broken test after rebase --------- Co-authored-by: Chadpiha <chadpiha23@gmail.com> |
||
|
|
e4e5d19ddb |
feat(parakeet): add NVIDIA Nemotron streaming ASR models (EN + multilingual 3.5) (#1131)
* feat: add Nemotron ASR model Add Nemotron Speech Streaming EN 0.6B through sherpa-onnx online websocket support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(parakeet): bump sherpa-onnx to 1.13.4 for Nemotron streaming support The Nemotron model artifact in the registry (sherpa-onnx-nemotron-speech-streaming-en-0.6b-560ms-int8-2026-04-25) was re-exported alongside runtime updates in sherpa-onnx v1.13.0; the previously pinned v1.12.23 runtime produces degraded transcripts on Nemotron streaming models (verified empirically: 1.12.x mis-decodes words that 1.13.4 gets right on the model's own test wavs). Also correct the Nemotron registry size to the extracted model size (632MB, matching the convention used by the other Parakeet entries — this value feeds the pre-download disk-space check), and document the new model and the offline/online runtime split in CLAUDE.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdfxroZFwgsVyKMhum1UAo * feat(parakeet): add multilingual Nemotron 3.5 ASR Streaming 0.6B model Adds nemotron-3.5-asr-streaming-0.6b to the local model registry alongside the English Nemotron model. Cache-aware streaming FastConformer with per-stream automatic language detection; 15 transcription-ready languages. Uses the same online websocket runtime added for the English model — no code changes needed, only registry + i18n + docs. Verified against sherpa-onnx 1.13.4: the published int8 export (sherpa-onnx-nemotron-3.5-asr-streaming-0.6b-560ms-int8-2026-06-11) loads with the exact encoder/decoder/joiner/tokens flags OpenWhispr passes and decodes English, German, and Japanese test wavs with language auto-detection. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdfxroZFwgsVyKMhum1UAo * feat(parakeet): stream Nemotron live preview over a persistent connection The Live Transcription Preview previously transcribed buffered 1.5s chunks independently, which discards a cache-aware streaming model's context at every chunk boundary. When the selected NVIDIA model has runtime "online" (Nemotron), the preview now opens one persistent websocket stream to the online sherpa-onnx server for the whole recording: worklet PCM is converted to float32 and forwarded as it is captured, partial results replace the preview text live, and stopping the preview flushes the stream ("Done" / "Done!" handshake) for the final text. Audio captured while the streaming server is warming up is buffered and fed into the stream once it opens. Offline models keep the existing chunked path, and the online path falls back to it if the stream cannot start. Covered by test/helpers/parakeetOnlineStream.test.js using a mock websocket server that speaks the sherpa-onnx online protocol (partials, endpointed segments, finish handshake, abort). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdfxroZFwgsVyKMhum1UAo * refactor(parakeet): code-quality pass on Nemotron integration Applies the findings from a four-angle review (reuse, simplification, efficiency, altitude) of the Nemotron PR diff: - Single registry access point: new parakeetModelInfo.js owns getModelRuntime and REQUIRED_MODEL_FILES; parakeetWsServer no longer reads the model registry, and the getModelRuntime pass-throughs on both manager layers are gone. ipcHandlers now asks a capability question (supportsOnlineStreaming) instead of comparing runtime strings. - Runtime-only binary API: getWsBinaryPath/isAvailable take a runtime (the model-name-or-runtime union sniffing is gone), callers resolve model to runtime once, hasAnyWsBinary replaces the hand-rolled offline-OR-online checks, and per-runtime path memoization is restored. - One online-protocol implementation: _transcribeOnline is now a thin wrapper over createOnlineStream instead of a ~55-line duplicate of it. - Incremental result accumulation: createOnlineAccumulator parses each websocket message once (the previous per-message re-parse of the whole history was quadratic over a recording) and live preview updates are emitted only when the text actually changes. parseOnlineMessages keeps its API as a wrapper over the accumulator. - Wire format stays in the ws layer: the stream handle exposes sendPcm16 (int16 capture format, converted internally) so ipcHandlers no longer performs float32 conversion; abort now settles a pending finish(). - Preview session staleness is tracked by one generation counter instead of three heuristic condition sets. - pcm16ToFloat32 is the canonical converter (returns Float32Array); meetingEchoLeakDetector and liveSpeakerIdentifier drop their local copies. - Sidecar reaper matches parakeet against its two exact ws binary prefixes instead of the whole "sherpa-onnx-" vendor prefix, which also overlapped the diarization entry. - Download script reuses the shared cleanupFiles (extended to accept multiple keep prefixes) and copyBinary drops its redundant label and basename handling. Verified on Node 24 with full dependencies: 278 tests, 270 pass, 0 fail (8 skipped), tsc --noEmit clean, eslint clean, prettier clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdfxroZFwgsVyKMhum1UAo * fix(parakeet): repair sherpa-onnx 1.13.4 binary downloads - Windows release assets are now suffixed (-MD-Release); old name 404s - ad-hoc re-sign macOS binaries/dylibs: upstream ships libonnxruntime with an invalid arm64 signature that dyld SIGKILLs - rm before copy so a stale symlink can't redirect writes into an old inode - re-point the unversioned lib symlink and prune stale versioned libs - run download:sherpa-onnx in predev/prestart (marker-gated, fast no-op) * refactor(parakeet): condense comments --------- Co-authored-by: Joel Tony <github@jaytau.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
43b4c16880 | fix(linux): fall back to --no-sandbox when user namespaces are restricted (#1042) | ||
|
|
3f4aad6549 | chore: bump bundled llama.cpp to b9763 (#995) | ||
|
|
70a0d677b4 |
feat(onboarding): use-case intent capture, meeting step, and finish step (#928)
* feat(onboarding): use-case intent capture, meeting step, and finish step Reworks the onboarding wizard around an id-keyed dynamic step machine: - New "Why are you here?" step: multi-select use-case cards (OptionCard) plus an optional note, persisted to settings and synced fire-and-forget to /api/onboarding-intent for signed-in users - Permission copy rewritten to explain outcomes; system audio badge flips to Recommended when the user came for meeting notes - New conditional meeting step introducing auto-detection and the existing meeting hotkey (shown when system audio is granted or meetings selected) - New finish step: OpenWhispr Cloud summary with Open Settings deep-link (Settings > Transcription) or Skip; local/BYOK variant for skip-auth users; registry-gated Corti partner screen for medical intent - All new strings translated across the 10 locale files * refactor(lint): fix react-refresh and hook-deps warnings, run formatter - Move pending-invitation token helpers out of AcceptInvitationModal into src/utils/pendingInvitationToken.ts so the component file only exports components (react-refresh/only-export-components) - Memoize the invitations fallback in ShareNoteDialog so its callback dependencies are stable (react-hooks/exhaustive-deps) - Prettier reflow in clipboard.js * fix(onboarding): add back-to-sign-in escape from email verification Without it, users who never receive the verification email are stuck on the polling screen with no way back to choose another email or sign-in method. * style(onboarding): match back-to-sign-in button to auth screen idiom Align the verification back button with AuthenticationStep's continue- without-account styling; prettier array reflow in zh locale files. * refactor(auth): use Button ghost variant for subtle text actions Replace bespoke raw buttons (back-to-sign-in, continue-without-account) with the design-system Button, gaining focus-visible rings and proper disabled styling. * feat(onboarding): broaden medical use case to healthcare, clarify multi-select - Rename use-case id medical -> healthcare; card now reads "Medical, clinical & therapy transcription / Dictate patient notes, session notes and reports" so therapy and psychology users self-identify - Add "Select all that apply" hint and switch OptionCard's selection indicator from radio circle to checkbox square so multi-select is obvious - Update Corti finish title to match; all 10 locales updated * fix(onboarding): allow proceeding with Corti credentials in setup step The Corti provider tab (#929) now appears in the onboarding transcription picker, but canProceed only recognized openai/groq/mistral/custom — a user selecting Corti was blocked on Next unless an OpenAI key happened to be set. Gate on client id + secret, matching shouldUseStreaming's readiness rule. * feat(onboarding): preselect Corti provider when opening settings from finish step The Corti finish screen's Set up in Settings CTA now sets cloudTranscriptionProvider to corti so the settings picker opens on the Corti tab with its credential fields. Safe for signed-in users — the provider only takes effect in BYOK mode. * feat(onboarding): inline Corti setup on the finish step Replace the settings detour with credentials entered in place: honest copy (clinical-grade, HIPAA compliant), a visible $50 free credit badge next to the create-account link, Client ID/Secret fields reusing ApiKeyInput, and a US/EU data-region select (defaults prefilled from the store). Use Corti activates the provider in BYOK mode and completes onboarding; Not now falls through to the default finish. * refactor(onboarding): remove quit button from title bar The power/quit button only ever rendered in onboarding (TitleBar's sole consumer) and duplicates OS-level quit (Cmd+Q, dock, window controls). Remove it end to end: TitleBar quit UI + confirm dialog, app-quit IPC handler, appQuit preload bridge and type, and the titleBar i18n block in all 10 locales. * feat(onboarding): link Corti homepage with UTM and add setup steps Point the create-account link at corti.ai with the partnership UTM params instead of the console, and add a three-step guide (sign up, create API credentials in the console, paste below) since the homepage no longer lands users on signup. * feat(onboarding): refine use-case step copy and move progress into macOS title bar - Subtext constrained to readable width and rewritten to say plainly that the user's picks set up the app and steer what we build next - Select-all hint restyled to the existing uppercase section-label idiom - Note placeholder reduced to "Optional" — no canned examples - TitleBar gains a centered no-drag slot; on macOS the step progress renders there (reclaiming the progress strip's height), Windows/Linux keep the strip alongside their window controls * feat(onboarding): add upload-audio use case and skip button for optional steps - New "Uploading audio files" use-case option (id: upload) with FileAudio icon - Skip button beside Next on optional steps (use case, voice agent, meeting) - Add common.skip and the upload option copy across all 10 locales * feat(transcription): add Corti provider icon Register the Corti logo in PROVIDER_ICONS so the Corti tab and provider chips show a real icon; monochrome (currentColor) like xai. * refactor(meetings): consolidate meeting detection into the notification toggle The meeting-detection notification was the only consumer of detection, so a detector running with notifications off did nothing but burn CPU. Drive the audio detector from the notification toggle (notificationsEnabled && notifyMeetingDetection) and remove the redundant standalone Audio Detection setting, its UI section, and the now-dead calendar.detection translations. * fix(settings): don't grab the mic when opening settings MicrophoneSettings called getUserMedia on mount to read device labels, which activates a mic input session and interrupts other audio (pauses music on macOS) every time Settings opens. Enumerate devices first and only fall back to getUserMedia when labels are missing (permission not yet granted). * feat: add UTM tracking to Corti 'get a key' link Point the Corti transcription provider's 'Get a key' link at the corti.ai home page with referral UTM params, matching the canonical CORTI_SIGNUP_URL used in onboarding instead of console.corti.app. * chore: apply prettier formatting to pre-existing files Format 21 docs, build scripts, and test files that were not prettier-compliant on main. Pure formatting, no logic changes. Kept separate from the onboarding feature work. * chore(release): 1.7.3 Bump version to 1.7.3 and document the onboarding upgrade, Corti provider polish, simplified meeting-detection setting, and the Settings microphone fix in the changelog. * docs(changelog): capture full 1.7.3 scope Expand the 1.7.3 entry to cover everything merged since v1.7.2, not just the onboarding branch: Corti BYOK and xAI transcription providers, Snippets, Voice Agent hotkey, dictionary redesign, notification controls, Linux PipeWire/paste fixes, new AI models, and the broader fix batch. * fix(onboarding): keep step progress labels on one line The stepper renders inside TitleBar's absolutely-positioned `left-1/2` center slot, whose shrink-to-fit width is capped at the space from center to edge. That squeezed the row and wrapped the longest label ("Voice Agent") onto two lines. Adding `whitespace-nowrap` lets the wrapper resolve to the content's full width and center it cleanly, fixing the layout across all platforms (shared StepProgress component). * fix(auth): recover stale-bearer cloud requests via session cookie The main process authenticates cloud requests with a single saved bearer token that only refreshes on sign-in. After an email/password login (which, unlike OAuth, never force-refreshes it) that token can go stale, so main-process requests 401 while the renderer stays signed in via its session cookie. onboarding-intent was the visible casualty: it fires right after the use-case step and failed silently, leaving intent unsaved. Retry cloud-api-request once with the window's session cookie when a bearer request returns 401. Cookie-only on retry, since a tagging-along bearer overwrites the cookie server-side. * fix(onboarding): hide voice agent step for continue-without-account users Continue-without-account users have no LLM configured, so the dictation agent can't run — skip the voice agent onboarding step for them and show it only to signed-in account users. * fix(i18n): add Hyprland hotkey locale strings * fix(clipboard): prevent stale clipboard restores during paste * fix(dictation-agent): reach cloud agent from voice hotkey without a selected model The voice agent hotkey resolved to "skip" for signed-in OpenWhispr cloud users because agentReachable required a non-empty dictationAgentModel, which cloud mode never sets — pasting the raw transcript instead of running the agent. Mirror the cleanup cloud fallback: the dictation agent is now reachable in cloud (openwhispr) and self-hosted (lan) modes without an explicit model, matching ReasoningService.processText's empty-model allowance, and the agent route forces provider "openwhispr" in cloud mode so it no longer depends on the cleanup scope. Also pass voiceAgentRequested on the streaming-STT path so the hotkey works there too. Reachability logic is extracted into a pure, tested helper (resolveDictationAgentReachability) alongside resolveDictationRouteKind. * feat(onboarding): preview the real meeting notification in the meeting step Replace the abstract "meeting detected" explainer with a faithful preview of the actual notification, rendered from a shared MeetingNotificationCard that MeetingNotificationOverlay now also consumes so the two never drift. Add the onboarding.meeting.notification.{title,body,cta} keys across all 10 locales. * fix(note-formatting): use cloud provider when no model is selected Note formatting passed no provider to processText, so cloud users fell back to getModelProvider(""), which resolves from the cleanup scope — throwing "No reasoning model selected" when cleanup uses a BYOK/local provider. Pin the provider to openwhispr in cloud mode for both enhancement and title generation. * feat(onboarding): temporarily hide the meeting step for all users * fix(dev): diagnose missing Electron binary * feat(transcription): dedicated Audio Upload speech-to-text settings Give audio upload its own transcription context, mirroring how Note Recording was split from Dictation. Adds an Audio Upload tab under Settings -> Speech-to-Text with independent upload* settings; the upload page is now settings-only (inline picker removed). A one-time migration copies existing users' dictation transcription preference into the new context; new users default to OpenWhispr Cloud. - store: 9 upload* keys, selectResolvedUploadTranscription (falls back to base dictation values), migrateUploadTranscription (runs after provider migration) - settings: new UploadTranscriptionPanel (openwhispr/providers/local) - upload page: read-only consumer of resolved upload settings; no-provider CTA routes to the Audio Upload tab - i18n: tabs.upload across all 10 locales; remove orphaned upload setup strings - fix cross-window boolean sync for meeting/upload useLocalWhisper (BOOLEAN_SETTINGS) - extract shared useStartOnboarding hook; drop dead uploadSetupComplete write * fix(history): inline discarded toggle and stop list flash on refresh Move the "Show Discarded" toggle inline to the left of "Clear All" in the first day header so the pair reveals together on hover; keep it reachable above the empty state. Gate the loading spinner on the initial load only (no data yet) so toggling discarded keeps the current list mounted and swaps in new data instead of unmounting to a spinner and flashing. * feat(upload): cancel button during audio-file transcription Add a Cancel transcription action beneath the progress bar on the upload page (shown for every transcription). Cancelling returns to the upload screen and discards the result so nothing is saved; a run-id token guards the async path so a cancelled or superseded run never persists a note. * docs(changelog): document late-breaking 1.7.3 changes * fix(onboarding): apply Corti to all transcription scopes on finish Choosing Corti during onboarding only set the dictation cloud provider, so note recording and audio upload kept their previous provider and every Settings tab still showed OpenWhispr Cloud — each tab displays the InferenceMode field, which was never updated. setCloudTranscriptionForAllScopes now applies the chosen provider to dictation, note recording, and audio upload, and sets each scope's InferenceMode via a shared deriveTranscriptionMode helper (also reused by the provider-settings migration). * refactor(corti): rework streaming close handshake with ack tracking Replace the single closeResolve callback with a pendingAck/waitForAck mechanism that resolves on the matching server ack (flushed/ended) or socket close, times out cleanly, and closes the socket with code 1000. * feat(onboarding): rename activation step to Dictation and add voice agent test area - Rename the activation onboarding step to "Dictation" in the progress nav and "Dictation Setup" in the step header - Rename the voice agent step header to "Voice Agent Setup" - Add a test area under the voice agent hotkey with example spoken commands and a textarea to try it - Add and translate the new strings across all 10 locales * fix(meeting): send true 24kHz sample rate to cloud streaming providers Meeting capture runs at 24kHz end-to-end, but Corti/Deepgram/AssemblyAI were told 16kHz, so they read the PCM ~1.5x too slow and degraded accuracy. Thread the real rate through the meeting connect path and teach cortiStreaming to honor options.sampleRate (matching Deepgram/AssemblyAI). OpenAI already declares 24kHz; dictation (16kHz) and the local downsample path are untouched. * fix(dictation-agent): default to OpenWhispr Cloud for signed-in users The dictation agent scope defaulted to "providers" (BYOK) with no model, unlike the cleanup and chat-agent scopes which default to OpenWhispr Cloud. As a result, a signed-in user who never explicitly configured the dictation agent had it unreachable, so the voice agent hotkey silently typed the raw transcript instead of running the command. Default dictationAgentMode and dictationAgentCloudMode to "openwhispr" so the voice agent works out of the box on Cloud. Users who explicitly chose BYOK, local, or self-hosted are unaffected (persisted values are read first). * perf(corti): pre-warm dictation socket to cut startup latency and first-word loss Corti dictation paid the full token-mint + socket-open + CONFIG_ACCEPTED cost at hotkey time (~1s), and audio captured before the socket existed was dropped. Give CortiStreaming a real warmup() that opens the socket and finishes the config handshake ahead of recording, keeps it alive with WS pings, and lets connect() promote the warm socket for an instant start — mirroring Deepgram/AssemblyAI. Falls back to a cold connect when no warm socket exists, so behavior is never worse than before. Meeting mode (fresh instance, no warmup) is unaffected. |
||
|
|
dac4a1ba82 |
fix(windows): pin llama.cpp to b8857 to keep whisper-server loadable
whisper-server.exe (built from OpenWhispr/whisper.cpp 0.0.6, frozen since
2026-01-23) dynamically links against the ggml-*.dll set that
download-llama-server.js ships into resources/bin. Both download scripts
fetch latest, which was fine until a llama.cpp release between b8861 and
b9020 bumped ggml's ABI — whisper-server.exe then crashes on
load_backend, leaving local Whisper users on 1.7.0 unable to transcribe.
Pin LLAMA_CPP_VERSION to b8857 (last build verified working in 1.6.10).
Add a `tag` option to fetchLatestRelease for exact-tag lookup via
/releases/tags/{tag} — the existing tagPrefix path only paginates the 50
most recent releases, which silently fails for old pins like b8857
(~165 releases back).
Bump version to 1.7.1.
|
||
|
|
94ac45bca3 |
fix(meeting-aec): link winmm on windows
timeGetTime (used by rtc_base/system_time.cc under WEBRTC_WIN) lives in winmm.lib. Without /DEFAULTLIB:winmm.lib lld-link errors with 'undefined symbol __declspec(dllimport) timeGetTime'. |
||
|
|
8de0662b7d |
fix(meeting-aec): cross-platform build for linux, windows, and macOS x64
- Extend Bazel select parser to recognize @platforms//cpu:x86_64 so SSE2 and AVX2 WebRTC targets get compiled into x86_64 builds. - Compile AVX2 sources with per-file copts (-mavx2 -mfma / /arch:AVX2) via set_source_files_properties and a dedicated direct-build bucket. - Link CoreFoundation on darwin so logging.cc's CFSTR references resolve on macOS x64 (implicit on arm64). - Add _GNU_SOURCE on Linux so pffft.c sees M_PI/M_SQRT2 from glibc. - Stub rtc_base/win32.h in compat/: webrtc-apm omits it but time_utils.cc includes it under WEBRTC_WIN; the referenced Windows types already come from <minwinbase.h>. |
||
|
|
0646df5c84 |
fix(meeting-aec): single-pass escape in CMake quoter
Escape both quotes and backslashes in one regex pass to silence CodeQL incomplete-escape warning. No behavior change for the paths we actually pass through. |
||
|
|
068280ba86 |
feat(meeting): add WebRTC AEC helper and text-level dedupe
- Adds native WebRTC APM sidecar (meeting-aec-helper) built from webrtc-apm + abseil-cpp, wired into the mic pipeline via MeetingAecManager with graceful fallback when unavailable. - Adds transcript-level duplicate suppression (transcriptsOverlap, transcriptsLooselyOverlap, buildMergedCandidates) and retract segment events to drop mic duplicates after system audio confirms. - Tunes MeetingEchoLeakDetector thresholds with a system-VAD gate and per-state bleed profiles. - Packaging: electron-builder extraResources, afterPack verify+chmod, cache keys on both CI workflows, prebuild:compile:meeting-aec. |
||
|
|
a893037d5b |
feat(agent): enable local model tool calling + RAG context injection
Route local models through AI SDK chat completions with tool support for models >= 4B params. Inject RAG note context via Qdrant semantic search into system prompt for all models. Bundle MiniLM embedding model in production builds. Add --jinja flag for llama.cpp tool templates. Fix redirect handling for 303/307/308 in download utils. |
||
|
|
8eb7556338 |
fix(ci): resolve Intel Mac binary architecture mismatch (#196)
The prebuild:mac npm hook runs download scripts and compile scripts without target architecture context. On arm64 CI runners building for x64, this caused: - Download scripts to resolve to arm64, then cleanup deleted the x64 binaries (sherpa-onnx, whisper-server, llama-server) and overwrote x64 dylibs with arm64 versions - macos-fast-paste to compile as arm64-only Fixes: - parseArgs() now checks TARGET_ARCH/TARGET_PLATFORM env vars (already set in CI) before falling back to process.arch/process.platform - build-macos-fast-paste.js now supports cross-compilation via TARGET_ARCH env var and --arch flag, matching the globe-listener pattern - CI cache keys updated to include fast-paste build files - .gitignore updated for arch-specific hash files |
||
|
|
c810d2b205 |
fix(ci): prevent prebuild hook from deleting x64 binaries on arm64 CI runners
The prebuild:mac npm hook runs download scripts with --current but without --platform/--arch flags. On arm64 CI runners, this resolved to arm64 and the cleanup logic deleted the x64 binaries that were explicitly downloaded moments earlier — causing Intel Mac builds to ship without sherpa-onnx, whisper-server, and llama-server binaries. parseArgs() now checks TARGET_ARCH/TARGET_PLATFORM env vars (already set in CI workflows) before falling back to process.arch/process.platform. |
||
|
|
92deca76ac |
fix: await async zip extraction in download scripts
extractZip is async (uses unzipper on Windows) but was called without await in 4 download scripts, causing the binary search to run before extraction finished — resulting in "not found in archive" errors. |
||
|
|
68c037b455 |
fix: use unzipper instead of tar for Windows key listener extraction (#273)
Windows' built-in tar command fails with path resolution errors when extracting the windows-key-listener binary: tar: Cannot connect to c: resolve failed This change switches to the unzipper npm package (already in dependencies) which properly handles Windows paths and provides more reliable extraction. Benefits: - Eliminates error messages during npm run dev - Enables push-to-talk for fresh Windows installations - More reliable cross-platform extraction Tested on Windows 11 with successful extraction. Co-authored-by: solwer-se <solwer-se@users.noreply.gitlab.com> |
||
|
|
6e9583f240 | fix: use tar instead of PowerShell Expand-Archive for zip extraction on Windows | ||
|
|
e3969d0538 |
feat(windows): add Push-to-Talk support with compound hotkeys (#153)
* feat(windows): add Push-to-Talk support with compound hotkeys Adds full Push-to-Talk functionality on Windows with support for compound hotkeys like Ctrl+F11, Alt+F8, etc. ## Windows Push-to-Talk - Add native Windows keyboard hook (windows-key-listener.c) using Low-Level Keyboard Hook (WH_KEYBOARD_LL) for reliable KEY_DOWN/KEY_UP detection - Support compound hotkeys with modifiers (Ctrl, Alt, Shift) by tracking modifier key states with GetAsyncKeyState() - Add WindowsKeyManager.js to manage the native binary lifecycle - Emit KEY_UP when modifier keys are released while main key is held ## Hotkey Capture Fix - Stop Windows key listener when entering hotkey capture mode so it doesn't interfere with recording new hotkeys - Temporarily unregister globalShortcut during capture to prevent key event consumption - Restart listener when exiting capture mode if in push mode ## ELECTRON_RUN_AS_NODE Fix - Add run-electron.js wrapper script to unset ELECTRON_RUN_AS_NODE environment variable (inherited from Claude Code and similar tools) - Update dev:main script to use the wrapper ## Additional Improvements - Add auto-start at login feature with UI in Settings - Add debug logging for audio recording and whisper-server - Fix whisper-server PATH to find companion DLLs on Windows - Fix hotkeyManager to check isRegistered before returning success - Change dev server port from 5174 to 5080 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add Custom Dictionary and fix Windows production build - Add Custom Dictionary feature for improving transcription accuracy - New "Custom Dictionary" section in Settings sidebar - Words are passed as context hints to Whisper via initialPrompt - Supports adding phrases like "The word is Synty" for difficult words - Fix windows-key-listener.exe not bundled in production builds - Add windows-key-listener* to electron-builder extraResources filter Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(windows): add prebuilt binary support and improve Push-to-Talk code quality * refactor: download-nircmd.js to use shared utils * fix: code quality fixes for download scripts and dev server port alignment * fix: add GITHUB_TOKEN auth to avoid API rate limits in CI * chore: updates docs * fix: hotkey capture mode re-registration and platform improvements * feat: add F13-F24 extended function key support for Windows, GNOME Wayland, and hotkey capture * feat: persist custom dictionary to SQLite with localStorage sync and inject into reasoning system prompts * fix: update llama.cpp download script for new release asset naming and tar.gz format Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add gh_token to downlaod scripts to avoid rate limits --------- Co-authored-by: Craig von Chamier <craig@cvcwebsolutions.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
286fab53a8 |
Unify prompt system into single intelligent prompt (#136)
* refactor: unify system prompts with world-class dictation prompt - Create centralized prompts.ts (renderer) and prompts.js (main process) with a single, comprehensive system prompt - The unified prompt handles both cleanup and instruction modes, letting the LLM intelligently detect which mode to use based on context - Remove code-based agent detection (text.includes(agentName)) in favor of LLM-based contextual understanding - Update all providers (OpenAI, Anthropic, Gemini, Groq, Local) to use the new unified prompt - Update PromptStudio UI to show single unified prompt with clear explanation of how cleanup vs instruction mode works - Support custom prompt customization via localStorage The new prompt clearly establishes: - Primary function is ALWAYS cleanup (filler words, grammar, punctuation) - Instruction mode is triggered when user directly addresses the agent - LLM distinguishes between "Hey Agent, do X" vs "I told Agent about X" - Strict output rules to prevent explanations/commentary * feat: add smart formatting to unified dictation prompt Add intelligent formatting capabilities that automatically apply appropriate structure based on content context: - Bullet points for lists (shopping, to-do, enumerated items) - Numbered lists when order/sequence matters - Paragraph breaks between distinct topics - Email formatting (greeting, body, closing) - Social media post structure (hook, body, CTA) Includes guidance to NOT over-format simple dictations. * refactor: rename AI Prompts to Prompt Studio in settings - Rename sidebar item from "AI Prompts" to "Prompt Studio" - Update section header and description to reflect unified prompt approach - Clarify that there's a single system prompt for both cleanup and instructions * refactor: remove cli fallbacks and add llama-server * fix: add llama-server to build config, extract shared download utils, consolidate prompts to single JSON source, improve health check reliability with failure threshold * refactor: reuse components between settings and onboarding * chore: cleanups * chore: ui cleanups * feat: AI models to AI text cleanup label change * chore: UI cleanups * refactor: improve persisting of api keys * chore: cleanup dead code --------- Co-authored-by: Claude <noreply@anthropic.com> |