SFSpeechURLRecognitionRequest 在线程调用完成之前不会输出语音识别的结果



我正在尝试使用SFSpeechURLRecognitionRequest在终端应用程序中转录音频文件。当我把它作为一个初步的形式工作时,我遇到了一个奇怪的问题。在我的测试应用程序中,它似乎只在主线程终止后输出语音识别结果(部分和完整(。注意,我是一个Swift noob,所以我可能错过了一些显而易见的东西。

下面我有一个完整的Xcode Playground应用程序来演示这个问题。操场的输出写入Playground Execution Complete,然后我开始接收部分输出,然后是最终输出。请注意,如果我在print之前添加sleep(5),它将等待5秒,然后输出print,并且只有在主线程结束后才开始处理文本。我在GUI测试应用程序中看到过类似的行为,它只在启动请求的方法调用完成后才开始处理文本。

我试着反复检查返回的任务的状态,每次检查之间都睡不着觉,但运气不好。

我还尝试过在DispatchQueue中调用识别任务,根据CPU使用情况,DispatchQueue似乎在后台成功运行,但Partial和Final打印在应用程序完成之前永远不会出现,此时控制台会填充Partials和Final。

有人知道在没有应用程序线程完成的情况下开始处理语音识别的方法吗?理想情况下,我希望能够开始并重复短暂的睡眠,检查识别任务是否在两者之间完成。

在找到解决方案之前立即在下面进行了编辑以匹配版本。

import Speech
var complete = false
SFSpeechRecognizer.requestAuthorization {
authStatus in
DispatchQueue.main.async {
if authStatus == .authorized {
print("Good to go!")
} else {
print("Transcription permission was declined.")
exit(1)
}
}
}
guard let myRecognizer = SFSpeechRecognizer() else {
print("Recognizer not supported for current locale!")
exit(1)
}
if !myRecognizer.isAvailable {
// The recognizer is not available right now
print("Recognizer not available right now")
exit(1)
}
if !myRecognizer.supportsOnDeviceRecognition {
print("On device recognition not possible!")
exit(1)
}
let path_to_wav = NSURL.fileURL(withPath: "/tmp/harvard.wav", isDirectory: false)
let request = SFSpeechURLRecognitionRequest(url: path_to_wav)
request.requiresOnDeviceRecognition = true
print("About to create recognition task...")
myRecognizer.recognitionTask(with: request) {
(result, error) in
guard let result = result else {
// Recognition failed, so check error for details and handle it
print("Recognition failed!!!")
print(error!)
exit(1)
}
if result.isFinal {
print("Final: (result.bestTranscription.formattedString)")
complete = true
} else {
print("Partial: (result.bestTranscription.formattedString)")
}
}
print("Playground execution complete.")

我想通了!sleep实际上并不让后台任务执行。相反,添加以下内容:

let runLoop = RunLoop.current
let distantFuture = NSDate.distantFuture as NSDate
while complete == false && runLoop.run(mode: RunLoop.Mode.default, before: distantFuture as Date) {}

直到最后一次打印工作之前结束(结果立即开始显示,最终打印正好在最终结果之后(。

最新更新