Ariver
2026-07-01 2547282e0942a09b67fccfd53cf62a403ccd4a52
privatevoice.src/internal/engine/engine_darwin.go
@@ -16,15 +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 {
@@ -34,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) {
@@ -61,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)
@@ -113,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)
   }
@@ -235,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()
@@ -295,8 +304,22 @@
   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 {
@@ -307,6 +330,10 @@
   return xasrReleaseTailDelay
}
func (e *xasrStreamingEngine) HoldPreCaptureEnabled() bool {
   return true
}
func (e *sherpaEngine) Close() {
   if e.recognizer != nil {
      sherpa.DeleteOfflineRecognizer(e.recognizer)