关于 speech-recognition
面向 Apple 应用开发者的 Speech 框架语音转文本指南,涵盖实时录音和文件转写、较新的 SpeechAnalyzer 流程,以及 SFSpeechRecognizer 回退方案。
主要功能
- 01麦克风实时转写
- 02音频文件转写
- 03iOS 26+ 的 SpeechAnalyzer 流程
- 04SFSpeechRecognizer 回退指引
- 05处理部分、最终及备选结果
- 06检查设备端识别支持情况
适用场景
- 01录音时实时显示转写内容
- 02转写已保存的音频录音
- 03在 iOS 26+ 构建长音频转写
- 04选择设备端或网络识别
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill speech-recognition安装后在 Claude Code 中输入/speech-recognition确认已加载。
附带文件evals/evals.jsonreferences/speechanalyzer-patterns.md
详细介绍
语音识别
使用 Apple 的 Speech 框架将实时音频和预录音频转录为文本。
涵盖 SpeechAnalyzer / SpeechTranscriber(iOS 26+),以及
SFSpeechRecognizer(iOS 10+)回退方案指南。
范围界定: 将此技能用于语音转文本识别、语音授权、麦克风采集流程和结果处理。文本分析、转录后的语言识别、情感分析、嵌入和翻译请交由 natural-language;音频播放 UI 请交由 avkit;转录内容的摘要或生成请交由 apple-on-device-ai。
目录
SpeechAnalyzer 策略(iOS 26+)
对于现代 iOS 26+ 语音分析,尤其是长录音、实时转录、带时间索引的转录内容和完全在设备端运行的流程,请使用 SpeechAnalyzer。对于 iOS 10+ 部署目标、依赖服务器的语言区域覆盖,或现有的回调/代理实现,请继续使用 SFSpeechRecognizer。
实现 iOS 26+ 转录流程、模型资源处理、易变结果或文件/缓冲区示例时,请阅读 SpeechAnalyzer 模式。
SpeechAnalyzer 设置检查清单
- 选择模块:
- 新版通用设备端模型使用
SpeechTranscriber。 - 如果当前设备或语言区域不支持
SpeechTranscriber,且可接受兼容听写的支持,则使用DictationTranscriber。 - 仅当语音活动检测的准确度/功耗权衡值得时,才将
SpeechDetector与转录器配合使用。
- 新版通用设备端模型使用
- 创建会话前检查支持情况:
SpeechTranscriber.isAvailableSpeechTranscriber.supportedLocale(equivalentTo:)- 显示语言选项时使用
SpeechTranscriber.installedLocales/supportedLocales。
- 选择有文档说明的预设:
- 基本准确转录使用
.transcription。 - 实时 UI 更新使用
.progressiveTranscription。 - 播放高亮需要
audioTimeRange时使用.timeIndexedProgressiveTranscription。
- 基本准确转录使用
- 使用
AssetInventory.assetInstallationRequest安装所需资源。 - 在提供
AnalyzerInput前,将实时音频缓冲区转换为SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith:)。 - 在单独的任务中,从模块结果的
AsyncSequence中读取结果。 - 使用
finalizeAndFinish(through:)、finalizeAndFinishThroughEndOfInput()或cancelAndFinishNow()显式结束。
请勿使用 offlineTranscription 预设;Apple 并未为其提供文档说明。
结束 AsyncStream 输入序列并不会结束分析器会话。
SFSpeechRecognizer 设置
使用语言区域创建识别器
import Speech
// Default locale (user's current language)
let recognizer = SFSpeechRecognizer()
// Specific locale
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
// Check if recognition is available for this locale
guard let recognizer, recognizer.isAvailable else {
print("Speech recognition not available")
return
}
监控可用性变化
final class SpeechManager: NSObject, SFSpeechRecognizerDelegate {
private let recognizer = SFSpeechRecognizer()!
override init() {
super.init()
recognizer.delegate = self
}
func speechRecognizer(
_ speechRecognizer: SFSpeechRecognizer,
availabilityDidChange available: Bool
) {
// Update UI — disable record button when unavailable
}
}
授权
开始实时转录前,请同时请求语音识别和麦克风权限。在 Info.plist 中添加以下键:
NSSpeechRecognitionUsageDescriptionNSMicrophoneUsageDescription
import Speech
import AVFoundation
func requestPermissions() async -> Bool {
let speechStatus = await withCheckedContinuation { continuation in
SFSpeechRecognizer.requestAuthorization { status in
continuation.resume(returning: status)
}
}
guard speechStatus == .authorized else { return false }
let micStatus: Bool
if #available(iOS 17, *) {
micStatus = await AVAudioApplication.requestRecordPermission()
} else {
micStatus = await withCheckedContinuation { continuation in
AVAudioSession.sharedInstance().requestRecordPermission { granted in
continuation.resume(returning: granted)
}
}
}
return micStatus
}
实时麦克风转录
标准模式:AVAudioEngine 采集麦克风音频 → 将缓冲区追加到 SFSpeechAudioBufferRecognitionRequest → 持续接收结果。
import Speech
import AVFoundation
final class LiveTranscriber {
private let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))!
private let audioEngine = AVAudioEngine()
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
func startTranscribing() throws {
// Cancel any in-progress task
recognitionTask?.cancel()
recognitionTask = nil
// Configure audio session
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
// Create request
let request = SFSpeechAudioBufferRecognitionRequest()
request.shouldReportPartialResults = true
self.recognitionRequest = request
// Start recognition task
recognitionTask = recognizer.recognitionTask(with: request) { result, error in
if let result {
let text = result.bestTranscription.formattedString
print("Transcription: \(text)")
if result.isFinal {
self.stopTranscribing()
}
}
if let error {
print("Recognition error: \(error)")
self.stopTranscribing()
}
}
// Install audio tap
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) {
buffer, _ in
request.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
}
func stopTranscribing() {
audioEngine.stop()
audioEngine.inputNode.removeTap(onBus: 0)
recognitionRequest?.endAudio()
recognitionRequest = nil
recognitionTask?.cancel()
recognitionTask = nil
}
}
预录音频文件识别
对磁盘上的音频文件使用 SFSpeechURLRecognitionRequest:
func transcribeFile(at url: URL) async throws -> String {
guard let recognizer = SFSpeechRecognizer(), recognizer.isAvailable else {
throw SpeechError.unavailable
}
let request = SFSpeechURLRecognitionRequest(url: url)
request.shouldReportPartialResults = false
return try await withCheckedThrowingContinuation { continuation in
var didResume = false
recognizer.recognitionTask(with: request) { result, error in
guard !didResume else { return }
if let error {
didResume = true
continuation.resume(throwing: error)
} else if let result, result.isFinal {
didResume = true
continuation.resume(
returning: result.bestTranscription.formattedString
)
}
}
}
}
设备端识别与服务端识别
SFSpeechRecognizer 可在 iOS 13+ 上为受支持的地区使用设备端识别。如果 supportsOnDeviceRecognition 为 false,则识别器需要网络连接。requiresOnDeviceRecognition 仅在识别器支持设备端识别时才会生效。
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))!
// Check if on-device is supported for this locale
if recognizer.supportsOnDeviceRecognition {
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true // Force on-device
}
对于长时间录音,SFSpeechRecognizer 请求可能仍不太合适。Apple 文档指出,语音识别任务时长大约限制为一分钟,并且还有其他服务限制。对于 iOS 26+ 上的长时间录音,优先使用 SpeechAnalyzer;否则,应在达到限制前分段或重启识别,并在各任务间保留转录状态。
处理结果
部分结果与最终结果
启用 shouldReportPartialResults 后,在 SFSpeechRecognitionResult.isFinal 确认结果前,替换显示的部分转录文本。这与 SpeechTranscriber.Result.isFinal 不同:后者的易变属性范围必须由该范围的最终结果替换。实时示例和 references/speechanalyzer-patterns.md 包含规范的处理循环。
访问候选转录和置信度
recognizer.recognitionTask(with: request) { result, error in
guard let result else { return }
// Best transcription
let best = result.bestTranscription
// All alternatives (sorted by confidence, descending)
for transcription in result.transcriptions {
for segment in transcription.segments {
print("\(segment.substring): \(segment.confidence)")
}
}
}
添加标点符号(iOS 16+)
let request = SFSpeechAudioBufferRecognitionRequest()
request.addsPunctuation = true
上下文字符串
提升对领域专用术语的识别效果:
let request = SFSpeechAudioBufferRecognitionRequest()
request.contextualStrings = ["SwiftUI", "Xcode", "CloudKit"]
常见错误
| 错误 | 修正方法 |
|---|---|
| 实时音频请求只申请语音识别授权 | 同时要求语音识别权限和麦克风权限。 |
| 只检查一次识别器是否可用 | 监听代理的可用性变化,并处理服务不可用的情况。 |
| 最终结果、错误和轮换路径执行不同的清理操作 | 使用一个 stopTranscribing() 负责停止引擎、移除 tap、调用 endAudio 并取消任务。 |
| 对所有地区都强制使用设备端模式 | 检查 supportsOnDeviceRecognition,并提供回退方案。 |
使用单个 SFSpeechRecognizer 任务进行长时间录音 | 在 iOS 26+ 上优先使用 SpeechAnalyzer,或在保留已确认转录内容的同时滚动处理有时长限制的片段。 |
| 将结束 analyzer 输入视为会话完成 | 明确处理完最后一个采样后再完成,或取消并完成。 |
| 追加易变的 SpeechAnalyzer 结果 | 在最终结果确认前,替换易变范围。 |
| 第一个识别任务结束前就启动第二个任务 | 取消并完成当前活动任务,清理完成后再替换。 |
加载 references/speechanalyzer-patterns.md,查看完整的 analyzer 完成处理和易变结果代码。
检查清单
- Info.plist 中包含
NSSpeechRecognitionUsageDescription - Info.plist 中包含
NSMicrophoneUsageDescription(如使用实时音频) - 开始识别前请求授权
- 设置
SFSpeechRecognizerDelegate以处理availabilityDidChange - 识别结束时停止音频引擎并移除 tap
- 录音完成后调用
recognitionRequest.endAudio() - 开始新任务前取消之前的
recognitionTask - 要求使用设备端模式前检查
supportsOnDeviceRecognition - 将部分结果与最终(
isFinal)结果分开处理 - 考虑
SFSpeechRecognizer的一分钟时长限制和服务限制 - 对于 iOS 26+:使用
SpeechAnalyzer前安装AssetInventory资源 - 对于 iOS 26+:检查
SpeechTranscriber.isAvailable和地区支持情况 - 对于 iOS 26+:将实时缓冲区转换为 analyzer 兼容的格式
- 对于 iOS 26+:明确完成或取消 analyzer 会话
- 对于 iOS 26+:用最终结果替换易变结果,而非重复添加
参考资料
- 语音框架
- SpeechAnalyzer
- SpeechTranscriber
- SpeechTranscriber.Preset
- DictationTranscriber
- SpeechDetector
- SFSpeechRecognizer
- SFSpeechAudioBufferRecognitionRequest
- SFSpeechURLRecognitionRequest
- SFSpeechRecognitionResult
- SFSpeechRecognitionRequest
- AssetInventory
- 请求使用语音识别的权限
- 识别实时音频中的语音
- 使用 SpeechAnalyzer 为你的应用带来高级语音转文本功能