| CHANGELOG.md | ●●●●● patch | view | raw | blame | history | |
| privatevoice.src/app.go | ●●●●● patch | view | raw | blame | history | |
| privatevoice.src/app_live_caption_test.go | ●●●●● patch | view | raw | blame | history | |
| privatevoice.src/build/darwin/Info.plist | ●●●●● patch | view | raw | blame | history | |
| privatevoice.src/frontend/package-lock.json | ●●●●● patch | view | raw | blame | history | |
| privatevoice.src/frontend/package.json | ●●●●● patch | view | raw | blame | history |
CHANGELOG.md
@@ -1,5 +1,20 @@ # Changelog ## v2.1.36 (2026-06-28) ### 首尾字稳定性修复 - **Hold 模式首字保护扩展到所有模型**:按下热键后立即启动本地预采集,确认不是组合键后保留这段音频,降低 SenseVoice / Qwen3-ASR / Moonshine / Parakeet 等离线模型开头 1-2 个字丢失的概率。 - **松键尾部采集保护扩展到所有模型**:松开热键后默认继续采集约 300ms 再停止录音,降低最后 1-2 个字被截断的概率。 - **保留取消和组合键隔离**:组合键或过早释放仍会丢弃预采集音频,不进入识别流程。 ### 构建 - build: `20260628.2354` - 说明: 本版本为首尾字稳定性修复的本地验证候选包。 --- ## v2.1.35 (2026-06-23) ### 输入配置页排版优化 privatevoice.src/app.go
@@ -28,8 +28,8 @@ ) const ( appVersion = "2.1.35" appBuild = "20260623.1435" appVersion = "2.1.36" appBuild = "20260628.2354" appDisplayVersion = appVersion + " (build " + appBuild + ")" appName = "PrivateVoice Dictation" @@ -37,6 +37,7 @@ silenceTimeoutDuration = 3 * time.Second // auto-stop after this much silence in free-talk silenceGracePeriod = 2 * time.Second // don't auto-stop within first 2s of free-talk holdActivationDelay = 180 * time.Millisecond defaultReleaseTailDelay = 300 * time.Millisecond doneIndicatorHideDelayMs = 250 liveCaptionInterval = 120 * time.Millisecond liveCaptionMaxBytes = 108 @@ -985,9 +986,12 @@ } func releaseTailCaptureDelayForEngine(eng engine.Engine) time.Duration { if eng == nil { return 0 } tailCaptureEng, ok := eng.(engine.ReleaseTailCaptureEngine) if !ok { return 0 return defaultReleaseTailDelay } delay := tailCaptureEng.ReleaseTailCaptureDelay() if delay < 0 { @@ -997,9 +1001,12 @@ } func holdPreCaptureEnabledForEngine(eng engine.Engine) bool { if eng == nil { return false } preCaptureEng, ok := eng.(engine.HoldPreCaptureEngine) if !ok { return false return true } return preCaptureEng.HoldPreCaptureEnabled() } privatevoice.src/app_live_caption_test.go
@@ -29,12 +29,30 @@ } } func TestReleaseTailCaptureDelayDefaultsToZero(t *testing.T) { func TestReleaseTailCaptureDelayCanBeDisabledByEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(plainTestEngine{}) a.replaceEngine(tailCaptureTestEngine{delay: 0}) if got := a.releaseTailCaptureDelay(); got != 0 { t.Fatalf("releaseTailCaptureDelay() = %v, want 0", got) } } func TestReleaseTailCaptureDelayDefaultsToProtectionWindow(t *testing.T) { a := &App{} a.replaceEngine(plainTestEngine{}) if got := a.releaseTailCaptureDelay(); got != defaultReleaseTailDelay { t.Fatalf("releaseTailCaptureDelay() = %v, want %v", got, defaultReleaseTailDelay) } } func TestReleaseTailCaptureDelayDisabledWithoutEngine(t *testing.T) { a := &App{} a.replaceEngine(nil) if got := a.releaseTailCaptureDelay(); got != 0 { t.Fatalf("releaseTailCaptureDelay() = %v, want 0 without engine", got) } } @@ -47,12 +65,30 @@ } } func TestHoldPreCaptureDefaultsToFalse(t *testing.T) { func TestHoldPreCaptureCanBeDisabledByEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(holdPreCaptureTestEngine{enabled: false}) if a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should respect engine capability false") } } func TestHoldPreCaptureDefaultsToTrueForReadyEngine(t *testing.T) { a := &App{} a.replaceEngine(plainTestEngine{}) if !a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should default to true for ready engines") } } func TestHoldPreCaptureDisabledWithoutEngine(t *testing.T) { a := &App{} a.replaceEngine(nil) if a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should default to false") t.Fatal("hold pre-capture should be disabled without an engine") } } privatevoice.src/build/darwin/Info.plist
@@ -17,9 +17,9 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>2.1.35</string> <string>2.1.36</string> <key>CFBundleVersion</key> <string>20260623.1435</string> <string>20260628.2354</string> <key>ITSAppUsesNonExemptEncryption</key> <false/> <key>LSApplicationCategoryType</key> privatevoice.src/frontend/package-lock.json
@@ -1,12 +1,12 @@ { "name": "privatevoice-dictation-frontend", "version": "2.1.35", "version": "2.1.36", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "privatevoice-dictation-frontend", "version": "2.1.35", "version": "2.1.36", "dependencies": { "@wailsio/runtime": "latest" }, privatevoice.src/frontend/package.json
@@ -1,7 +1,7 @@ { "name": "privatevoice-dictation-frontend", "private": true, "version": "2.1.35", "version": "2.1.36", "type": "module", "scripts": { "dev": "vite dev",