//go:build darwin package engine import ( "fmt" "voicesnap/internal/logger" "voicesnap/internal/model" _ "github.com/k2-fsa/sherpa-onnx-go-macos" sherpa "github.com/k2-fsa/sherpa-onnx-go/sherpa_onnx" ) type sherpaEngine struct { recognizer *sherpa.OfflineRecognizer hwInfo string } func newPlatformEngine(resolved model.ResolvedModel) (Engine, error) { providers := darwinProviders(resolved.ProviderOrder) for _, p := range providers { config := sherpa.OfflineRecognizerConfig{} config.FeatConfig.SampleRate = 16000 config.FeatConfig.FeatureDim = 80 config.ModelConfig.SenseVoice.Model = resolved.Files["model"] config.ModelConfig.SenseVoice.UseInverseTextNormalization = 1 config.ModelConfig.Tokens = resolved.Files["tokens"] config.ModelConfig.NumThreads = resolved.Profile.NumThreads config.ModelConfig.Provider = p.provider config.DecodingMethod = "greedy_search" recognizer := sherpa.NewOfflineRecognizer(&config) if recognizer != nil { info := fmt.Sprintf("SenseVoice ยท %s", p.name) logger.Info("Engine initialized: %s", info) return &sherpaEngine{ recognizer: recognizer, hwInfo: info, }, nil } logger.Info("Failed to init with %s, trying next provider", p.name) } return nil, fmt.Errorf("failed to initialize sherpa-onnx with any provider") } func darwinProviders(providerOrder []string) []struct { name string provider string } { names := map[string]string{ "coreml": "CoreML (Apple Neural Engine)", "cpu": "CPU", } providers := make([]struct { name string provider string }, 0, len(providerOrder)) for _, provider := range providerOrder { name, ok := names[provider] if !ok { continue } providers = append(providers, struct { name string provider string }{name: name, provider: provider}) } if len(providers) == 0 { providers = append(providers, struct { name string provider string }{name: "CPU", provider: "cpu"}) } return providers } func (e *sherpaEngine) Recognize(samples []float32) (string, error) { stream := sherpa.NewOfflineStream(e.recognizer) defer sherpa.DeleteOfflineStream(stream) stream.AcceptWaveform(16000, samples) e.recognizer.Decode(stream) result := stream.GetResult() return result.Text, nil } func (e *sherpaEngine) HardwareInfo() string { return e.hwInfo } func (e *sherpaEngine) Close() { if e.recognizer != nil { sherpa.DeleteOfflineRecognizer(e.recognizer) e.recognizer = nil } }