图像与设计
用 Apple Speech 框架实现语音转文字时:授权…
在 iOS/macOS 上做语音转文字(实时麦克风或音频文件)时,如何配置授权、选择 SFSpeechRecognizer 或 iOS 26+ 的 SpeechAnalyzer,并正确处理结果与清理。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
用 Apple Speech 框架实现语特定
解决思路
- 选择识别模块:iOS 26+ 优先用 SpeechAnalyzer;通用场景用 SpeechTranscriber,当 SpeechTranscriber 在当前设备或语言不可用且可接受听写兼容支持时用 DictationTranscriber,仅在需要语音活动检测且能接受精度/功耗权衡时配合 transcriber 使用 SpeechDetector;iOS 10+ 部署目标、需要服务端语言覆盖或已有回调/代理实现时保留 SFSpeechRecognizer。
- 创建会话前检查支持情况:SpeechTranscriber.isAvailable、SpeechTranscriber.supportedLocale(equivalentTo:)、SpeechTranscriber.installedLocales / supportedLocales(用于展示语言选项)。
- 选择文档化的 preset:基础准确转写用 .transcription,实时 UI 更新用 .progressiveTranscription,播放高亮需要 audioTimeRange 时用 .timeIndexedProgressiveTranscription;不要使用 offlineTranscription preset(Apple 未文档化)。
- 用 AssetInventory.assetInstallationRequest 安装所需模型资源。
- 将实时音频 buffer 转换为 SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith:) 后再 yield AnalyzerInput。
- 在独立 task 中从模块的 AsyncSequence 消费结果。
- 显式结束会话:调用 finalizeAndFinish(through:)、finalizeAndFinishThroughEndOfInput() 或 cancelAndFinishNow();结束 AsyncStream 输入序列并不会结束 analyzer 会话。
- 创建 SFSpeechRecognizer:用 SFSpeechRecognizer() 取默认语言,或 SFSpeechRecognizer(locale: Locale(identifier: "en-US")) 指定语言,并用 recognizer.isAvailable 检查可用性。
- 设置 SFSpeechRecognizerDelegate 并实现 speechRecognizer(_:availabilityDidChange:) 以在不可用时更新 UI(如禁用录音按钮)。
- 在 Info.plist 中添加 NSSpeechRecognitionUsageDescription 和 NSMicrophoneUsageDescription。
- 启动实时转写前同时请求语音识别和麦克风权限:用 SFSpeechRecognizer.requestAuthorization 获取语音权限,iOS 17+ 用 AVAudioApplication.requestRecordPermission(),更早版本用 AVAudioSession.sharedInstance().requestRecordPermission。
- 实时麦克风转写流程:先取消进行中的 recognitionTask,配置 AVAudioSession(如 setCategory(.record, mode: .measurement, options: .duckOthers) 并 setActive(true, options: .notifyOthersOnDeactivation)),创建 SFSpeechAudioBufferRecognitionRequest 并设 shouldReportPartialResults = true,启动 recognizer.recognitionTask(with:),在 audioEngine.inputNode 上 installTap(onBus:bufferSize:format:) 将 buffer append 到 request,然后 audioEngine.prepare() 并 start()。
- 停止转写时统一清理:audioEngine.stop()、inputNode.removeTap(onBus: 0)、recognitionRequest?.endAudio()、recognitionTask?.cancel(),并将 request 和 task 置 nil。
- 识别磁盘音频文件用 SFSpeechURLRecognitionRequest,设 shouldReportPartialResults = false,在 result.isFinal 时返回 result.bestTranscription.formattedString,并用 didResume 标志防止 continuation 重复恢复。
- 区分设备端与服务端识别:检查 recognizer.supportsOnDeviceRecognition,仅在支持时设 request.requiresOnDeviceRecognition = true;不支持时识别需要网络连接。
- 处理长音频:SFSpeechRecognizer 有约一分钟任务限制,iOS 26+ 长录音优先用 SpeechAnalyzer,否则在限制前分块或重启识别并保留已提交的转写状态。
- 处理部分结果与最终结果:shouldReportPartialResults 时先替换显示部分转写,直到 SFSpeechRecognitionResult.isFinal 提交;SpeechTranscriber.Result.isFinal 的 volatile 范围必须用该范围的最终结果替换,而不是追加。
- 访问候选转写与置信度:遍历 result.transcriptions 及 transcription.segments,读取 segment.substring 和 segment.confidence。
- iOS 16+ 可设 request.addsPunctuation = true 添加标点。
- 用 request.contextualStrings 传入领域专有词(如 ["SwiftUI", "Xcode", "CloudKit"])提升识别率。
- 避免常见错误:实时音频不能只申请语音权限;不能只检查一次可用性;final/error/rollover 路径应共用同一个 stopTranscribing() 清理;不要对所有语言强制设备端模式;不要用单个 SFSpeechRecognizer task 处理长音频;不要将结束 analyzer 输入当作会话完成;不要追加 volatile 结果;启动新任务前先取消/结束并清理旧任务。
适用边界 · 注意事项
- 需要文本分析、转写后语言识别、情感、嵌入或翻译时,应交给 natural-language 技能。
- 需要音频播放 UI 时,应交给 avkit 技能。
- 需要对转写文本做摘要或生成时,应交给 apple-on-device-ai 技能。