You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为recognitionTask适配async-await并获取任务实例

解决SFSpeechRecognitionTask适配async-await后无法主动取消的问题

你的核心问题是原适配方法将SFSpeechRecognitionTask封装在内部,外部无法访问,只能依赖系统任务取消机制,没法主动触发语音识别的取消操作。要解决这个问题,需要把底层任务实例的控制权暴露给外部,同时保留async-await的异步结果获取能力。

方案1:自定义封装结构体,支持中间结果与主动取消

这种方式既可以拿到取消任务的能力,还能处理语音识别的中间实时结果(SFSpeechRecognitionTask的回调会多次触发,返回逐字识别的实时结果):

import Speech

struct SpeechRecognitionSession {
    private let underlyingTask: SFSpeechRecognitionTask
    let recognitionResults: AsyncThrowingStream<SFSpeechRecognitionResult?, Error>
    
    init(request: SFSpeechRecognitionRequest, using recognizer: SFSpeechRecognizer) {
        // 创建异步流传递识别结果
        let (stream, continuation) = AsyncThrowingStream.makeStream(of: SFSpeechRecognitionResult?.self)
        self.recognitionResults = stream
        
        // 初始化底层识别任务
        self.underlyingTask = recognizer.recognitionTask(with: request) { result, error in
            if let error = error {
                continuation.finish(throwing: error)
                return
            }
            
            if let result = result {
                continuation.yield(result)
                // 拿到最终结果后结束流
                if result.isFinal {
                    continuation.finish()
                }
            } else {
                continuation.finish()
            }
        }
    }
    
    /// 主动取消语音识别任务
    func cancelRecognition() {
        underlyingTask.cancel()
    }
}

// 给SFSpeechRecognizer添加便捷扩展
extension SFSpeechRecognizer {
    func recognitionSession(with request: SFSpeechRecognitionRequest) -> SpeechRecognitionSession {
        SpeechRecognitionSession(request: request, using: self)
    }
}

使用示例

// 初始化识别器与请求
guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN")) else {
    fatalError("当前设备不支持语音识别")
}
let audioRequest = SFSpeechAudioBufferRecognitionRequest()
// 配置音频请求(如添加麦克风输入数据)...

// 创建会话对象
let session = recognizer.recognitionSession(with: audioRequest)

// 启动异步任务监听识别结果
Task {
    do {
        for try await result in session.recognitionResults {
            guard let result = result else { continue }
            print("实时识别:\(result.bestTranscription.formattedString)")
            
            if result.isFinal {
                print("最终识别结果:\(result.bestTranscription.formattedString)")
                break
            }
        }
    } catch {
        print("识别出错:\(error.localizedDescription)")
    }
}

// 按需主动取消识别(比如用户点击取消按钮)
// session.cancelRecognition()

方案2:仅获取最终结果的简化封装

如果你的场景只需要最终识别结果,不需要处理中间实时结果,可以用更简洁的封装:

import Speech

struct FinalRecognitionTask {
    private let underlyingTask: SFSpeechRecognitionTask
    private let finalResult: () async throws -> SFSpeechRecognitionResult?
    
    init(request: SFSpeechRecognitionRequest, using recognizer: SFSpeechRecognizer) {
        var continuation: CheckedContinuation<SFSpeechRecognitionResult?, Error>?
        
        self.underlyingTask = recognizer.recognitionTask(with: request) { result, error in
            guard let cont = continuation else { return }
            
            if let error = error {
                cont.resume(throwing: error)
            } else if let result = result, result.isFinal {
                // 仅在拿到最终结果时返回
                cont.resume(returning: result)
            }
            continuation = nil
        }
        
        self.finalResult = {
            try await withCheckedThrowingContinuation { cont in
                continuation = cont
            }
        }
    }
    
    func cancel() {
        underlyingTask.cancel()
    }
    
    func getFinalResult() async throws -> SFSpeechRecognitionResult? {
        try await finalResult()
    }
}

使用示例

let task = FinalRecognitionTask(request: audioRequest, using: recognizer)

// 主动取消识别
// task.cancel()

do {
    let finalResult = try await task.getFinalResult()
    if let result = finalResult {
        print("最终识别内容:\(result.bestTranscription.formattedString)")
    }
} catch {
    print("识别失败:\(error)")
}

原代码的问题说明

你之前的适配方法用withCheckedThrowingContinuation只返回一次结果,同时把SFSpeechRecognitionTask变量限制在方法内部,导致外部无法主动调用cancel()。另外,原代码没有处理SFSpeechRecognitionTask多次回调的特性,会丢失中间识别结果。

内容的提问来源于stack exchange,提问作者Eray Diler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:07:52