【问题标题】:How to make SFSpeechRecognizer available on macOS?如何使 SFSpeechRecognizer 在 macOS 上可用?
【发布时间】:2019-11-29 22:33:01
【问题描述】:

我正在尝试使用 Apple 的语音框架在 macOS 10.15.1 上进行语音识别。在 macOS 10.15 之前,语音识别只能在 iOS 上使用,但根据 the documentationthis talk,现在应该也可以在 macOS 上使用。

但是,我使用它的所有尝试都导致SFSpeechRecognizerisAvailable 属性设置为false。根据那次谈话和文档,我启用了 Siri,并确保我的应用程序将 "Privacy - Speech Recognition Usage Description" 键设置为 Info.plist 中的字符串值。

我也尝试过启用代码签名(this question 建议可能需要),在系统首选项中的键盘 > 听写下启用听写。

这里有一些示例代码,虽然细节可能并不重要;我已经尝试使用 Storyboard 而不是 SwiftUI,将 SFSpeechRecognizer 的实例化放在 requestAuthorization 回调内部和外部,未指定语言环境等。似乎没有任何效果:

import SwiftUI
import Speech

struct ContentView: View {

    func tryAuth() {
        SFSpeechRecognizer.requestAuthorization { authStatus in
            switch authStatus {
                case .authorized:
                    print("authorized")
                case .denied:
                    print("denied")
                case .restricted:
                    print("restricted")
                case .notDetermined:
                    print("notDetermined")
                @unknown default:
                    print("unanticipated auth status encountered")
            }
        }
    }

    func speechTest() {
        guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US")) else {
            // Not supported for device's locale
            print("couldnt get recognizer")
            return
        }

        if !recognizer.isAvailable {
            print("not available")
            return
        }

        print("Success")
    }

    var body: some View {
        VStack {
            Button("Try auth") {
                self.tryAuth()
            }
            Button("Test") {
                self.speechTest()
            }
        }
    }
}

特别奇怪的是,如果我运行应用程序然后单击“尝试身份验证”按钮,则回调返回的 authStatus 始终是 .authorized。但是,我从未收到要求我授权应用程序的对话框,并且该应用程序未显示在系统偏好设置 > 安全和隐私 > 隐私 > 语音识别下的授权应用程序列表中。

尽管如此,之后单击“测试”按钮会导致打印not available

我对 macOS 隐私/权限系统的理解似乎有些漏洞,但我不确定如何进一步调试。我也认为应该可以让它工作,因为我在 StackOverflow 上看到其他问题表明人们已经这样做了,例如herehere

编辑:根据评论的建议,我尝试简单地忽略 isAvailable 是错误的事实,将我的检查替换为实际尝试转录文件的代码,例如:

let request = SFSpeechURLRecognitionRequest(url: URL(fileURLWithPath: "/Users/james/Downloads/test.wav"))

recognizer.recognitionTask(with: request) { (result, error) in
    guard let result = result else {
        print("There was an error transcribing that file")
        print("print \(error!.localizedDescription)")
        return
    }

    if result.isFinal {
        print(result.bestTranscription.formattedString)
    }
}

然后它失败了,打印:The operation couldn’t be completed. (kAFAssistantErrorDomain error 1700.)。所以看起来确实有必要检查isAvailable,我的问题仍然存在:如何让它成为true

【问题讨论】:

  • 音频的来源是什么?
  • @ElTomato 到目前为止,我什至还没有提供要转录的音频,因为如果没有SFSpeechRecognizerisAvailable 属性为true,它将无法工作。也就是说,如果我忽略这一点,不要先检查可用性,而只是提供要从 URL 转录的文件,它会失败并显示 "The operation couldn’t be completed. (kAFAssistantErrorDomain error 1700.)"。我已经编辑了原始问题以反映我已经尝试过了。
  • 我有同样的问题,但在我的情况下 kAFAssistantErrorDomain 错误代码是 601。

标签: swift macos sfspeechrecognizer


【解决方案1】:

SFSpeechRecognizer也有类似的问题……或许你可以在请求授权之前设置SFSpeechRecognizer的委托,如图here

例如:

class ViewController: NSViewController {
  var speechRecognizer: SFSpeechRecognizer!

  override func viewDidLoad() {
    super.viewDidLoad()
    speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
    speechRecognizer.delegate = self
  }

  override func viewWillAppear() {
    SFSpeechRecognizer.requestAuthorization { authStatus in
       ...
    }

    if !speechRecognizer.isAvailable {
      print("Not available!")
    }

    let url = Bundle.main.url(forResource: "sample", withExtension: "mp3")!
    let request = SFSpeechURLRecognitionRequest(url: url)

    // will now ask for authorisation
    speechRecognizer.recognitionTask(with: request) { (result, error) in
        ...
    }
  }
}

extension ViewController: SFSpeechRecognizerDelegate {

}

然后the authorisation dialog会正确显示。

此外,似乎只有在调用recognitionTask 时,才会要求用户授予权限。相反,单独调用requestAuthorization 不会有任何效果。

【讨论】:

  • 成功了,非常感谢!我可能应该尝试设置一个委托,但令人沮丧的是他们没有在文档中明确说明这是一项要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 2012-10-16
  • 2011-01-30
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多