如何使 SFSpeechRecognizer 在 macOS 上可用?
How to make SFSpeechRecognizer available on macOS?
我正在尝试使用 Apple 的语音框架在 macOS 10.15.1 上进行语音识别。在 macOS 10.15 之前,语音识别仅在 iOS 上可用,但根据 the documentation and this talk,现在应该也可在 macOS 上使用。
但是,我所有使用它的尝试都导致 SFSpeechRecognizer
的 isAvailable
属性 被设置为 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()
}
}
}
}
特别奇怪的是,如果我 运行 应用程序然后单击 "Try auth" 按钮,回调返回的 authStatus
始终是 .authorized
。但是,我从未看到要求我授权该应用程序的对话框,并且该应用程序未显示在“系统偏好设置”>“安全和隐私”>“隐私”>“语音识别”下的授权应用程序列表中。
尽管如此,之后单击 "Test" 按钮会导致打印 not available
。
看来我对macOS privacy/permissions系统的理解有一些漏洞,但我不确定如何进一步调试。我也认为应该可以让它工作,因为我在 Whosebug 上看到其他问题表明人们已经这样做了,例如 here, here.
编辑:根据评论的建议,我尝试简单地忽略 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
?
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
不会有任何效果。
我正在尝试使用 Apple 的语音框架在 macOS 10.15.1 上进行语音识别。在 macOS 10.15 之前,语音识别仅在 iOS 上可用,但根据 the documentation and this talk,现在应该也可在 macOS 上使用。
但是,我所有使用它的尝试都导致 SFSpeechRecognizer
的 isAvailable
属性 被设置为 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()
}
}
}
}
特别奇怪的是,如果我 运行 应用程序然后单击 "Try auth" 按钮,回调返回的 authStatus
始终是 .authorized
。但是,我从未看到要求我授权该应用程序的对话框,并且该应用程序未显示在“系统偏好设置”>“安全和隐私”>“隐私”>“语音识别”下的授权应用程序列表中。
尽管如此,之后单击 "Test" 按钮会导致打印 not available
。
看来我对macOS privacy/permissions系统的理解有一些漏洞,但我不确定如何进一步调试。我也认为应该可以让它工作,因为我在 Whosebug 上看到其他问题表明人们已经这样做了,例如 here, here.
编辑:根据评论的建议,我尝试简单地忽略 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
?
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
不会有任何效果。