From 3803f0987d7fd38cbd754f3dc37caa29247c852c Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Wed, 01 Jul 2026 23:21:27 +0800
Subject: [PATCH] Merge Windows preview build
---
privatevoice.src/internal/engine/engine_darwin.go | 69 +++++++++++++++++++++++++---------
1 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/privatevoice.src/internal/engine/engine_darwin.go b/privatevoice.src/internal/engine/engine_darwin.go
index 3fc59e1..ddf1ad8 100755
--- a/privatevoice.src/internal/engine/engine_darwin.go
+++ b/privatevoice.src/internal/engine/engine_darwin.go
@@ -6,6 +6,7 @@
"fmt"
"strings"
"sync"
+ "time"
"voicesnap/internal/logger"
"voicesnap/internal/model"
@@ -15,14 +16,20 @@
const (
asrSampleRate = 16000
+ xasrHeadPaddingSamples = asrSampleRate / 4
xasrTailPaddingSamples = asrSampleRate + asrSampleRate/2
+ xasrReleaseTailDelay = 300 * time.Millisecond
)
-var xasrTailPadding = make([]float32, xasrTailPaddingSamples)
+var (
+ xasrHeadPadding = make([]float32, xasrHeadPaddingSamples)
+ xasrTailPadding = make([]float32, xasrTailPaddingSamples)
+)
type sherpaEngine struct {
- recognizer *sherpa.OfflineRecognizer
- hwInfo string
+ recognizer *sherpa.OfflineRecognizer
+ backendKind string
+ hwInfo string
}
type xasrStreamingEngine struct {
@@ -32,10 +39,11 @@
}
type xasrStreamingSession struct {
- engine *xasrStreamingEngine
- stream *sherpa.OnlineStream
- lastText string
- finished bool
+ engine *xasrStreamingEngine
+ stream *sherpa.OnlineStream
+ lastText string
+ hasAcceptedSamples bool
+ finished bool
}
func newPlatformEngine(resolved model.ResolvedModel) (Engine, error) {
@@ -59,8 +67,9 @@
info := fmt.Sprintf("%s ยท %s", resolved.Profile.DisplayName, p.name)
logger.Info("Engine initialized: %s", info)
return &sherpaEngine{
- recognizer: recognizer,
- hwInfo: info,
+ recognizer: recognizer,
+ backendKind: resolved.BackendKind,
+ hwInfo: info,
}, nil
}
logger.Info("Failed to init with %s, trying next provider", p.name)
@@ -111,21 +120,19 @@
config.ModelConfig.Moonshine.Encoder = resolved.Files["encoder"]
config.ModelConfig.Moonshine.UncachedDecoder = resolved.Files["uncached_decoder"]
config.ModelConfig.Moonshine.CachedDecoder = resolved.Files["cached_decoder"]
+ case model.BackendTransducer:
+ config.ModelConfig.Transducer.Encoder = resolved.Files["encoder"]
+ config.ModelConfig.Transducer.Decoder = resolved.Files["decoder"]
+ config.ModelConfig.Transducer.Joiner = resolved.Files["joiner"]
case model.BackendNemoTransducer:
config.ModelConfig.Transducer.Encoder = resolved.Files["encoder"]
config.ModelConfig.Transducer.Decoder = resolved.Files["decoder"]
config.ModelConfig.Transducer.Joiner = resolved.Files["joiner"]
config.ModelConfig.ModelType = model.BackendNemoTransducer
case model.BackendQwen3ASR:
- config.ModelConfig.Qwen3ASR.ConvFrontend = resolved.Files["conv_frontend"]
- config.ModelConfig.Qwen3ASR.Encoder = resolved.Files["encoder"]
- config.ModelConfig.Qwen3ASR.Decoder = resolved.Files["decoder"]
- config.ModelConfig.Qwen3ASR.Tokenizer = resolved.Files["tokenizer"]
- config.ModelConfig.Qwen3ASR.MaxTotalLen = 1024
- config.ModelConfig.Qwen3ASR.MaxNewTokens = 256
- config.ModelConfig.Qwen3ASR.Temperature = 0.0
- config.ModelConfig.Qwen3ASR.TopP = 0.9
- config.ModelConfig.Qwen3ASR.Seed = 0
+ if err := applyQwen3ASRConfig(&config, resolved); err != nil {
+ return sherpa.OfflineRecognizerConfig{}, err
+ }
default:
return sherpa.OfflineRecognizerConfig{}, fmt.Errorf("unsupported backend kind: %s", resolved.BackendKind)
}
@@ -233,6 +240,10 @@
if s.stream == nil || s.finished {
return s.lastText, nil
}
+ if !s.hasAcceptedSamples {
+ samples = xasrSamplesWithHeadPadding(samples)
+ s.hasAcceptedSamples = true
+ }
s.engine.mu.Lock()
defer s.engine.mu.Unlock()
@@ -293,14 +304,36 @@
return nextText
}
+func xasrSamplesWithHeadPadding(samples []float32) []float32 {
+ padded := make([]float32, 0, len(xasrHeadPadding)+len(samples))
+ padded = append(padded, xasrHeadPadding...)
+ padded = append(padded, samples...)
+ return padded
+}
+
func (e *sherpaEngine) HardwareInfo() string {
return e.hwInfo
}
+func (e *sherpaEngine) ReleaseTailCaptureDelay() time.Duration {
+ if e.backendKind == model.BackendSenseVoice {
+ return senseVoiceReleaseTailDelay
+ }
+ return 0
+}
+
func (e *xasrStreamingEngine) HardwareInfo() string {
return e.hwInfo
}
+func (e *xasrStreamingEngine) ReleaseTailCaptureDelay() time.Duration {
+ return xasrReleaseTailDelay
+}
+
+func (e *xasrStreamingEngine) HoldPreCaptureEnabled() bool {
+ return true
+}
+
func (e *sherpaEngine) Close() {
if e.recognizer != nil {
sherpa.DeleteOfflineRecognizer(e.recognizer)
--
Gitblit v1.9.3