Foundation — Speech

Speech 是 Apple 提供的用于 语音识别(Speech-to-Text,STT)的框架。它使开发者能够将音频内容转换为文本,其核心是 Speech 框架(Speech Framework)。这个框架可以用来识别本地设备的语音输入或者现有音频文件中的语音内容,便于创建语音助手、语音识别应用(如字幕生成)等功能。

总结功能一览 #

各个核心类主要功能简述如下:

类名功能
SFSpeechRecognizer核心语音识别类,支持初始化、管理任务、判断是否离线识别等。
SFSpeechRecognitionRequest所有请求的基类,提供基础功能。
SFSpeechURLRecognitionRequest对音频文件的识别,适合离线语音转换和分析。
SFSpeechAudioBufferRecognitionRequest处理流式音频数据,支持实时语音识别应用。
SFSpeechRecognitionResult包含识别结果,并提供多个匹配结果的置信度信息。
SFSpeechRecognitionTask管理语音识别任务的生命周期,例如取消、完成或实时结果更新。
SFSpeechRecognizerDelegate监听语音识别器状态(如网络断开导致不可用)。

使用这些组件可以实现从文件或麦克风读取音频并进行实时或离线的语音识别。以下是对 Speech 框架中各个类的功能介绍使用方法的详细说明,确保每个类都单独描述每个具体功能,并结合实例代码展示其用法。

1.1 SFSpeechRecognizer #

功能介绍#

SFSpeechRecognizerSpeech 框架中的核心类,负责语音识别的逻辑。它主要的功能如下:

  • 初始化语音识别器(支持多语言)。
  • 判断语音识别功能是否可用。
  • 启动语音识别任务,接收并解析语音输入。
  • 支持在线和部分离线语音识别功能(iOS 13+ 设备)。

常用属性#

属性描述
isAvailable指示语音识别器当前是否可用(依赖网络、设备语言支持)。
supportsOnDeviceRecognition指示是否支持离线语音识别(需要设备和语言支持,iOS 13+)。

常用方法#

方法描述
init(locale: Locale?)初始化语音识别器,设置对应的语言环境(如中文:“zh-CN”)。
recognitionTask(with: SFSpeechRecognitionRequest)执行语音识别任务,并异步获取识别回调结果或错误。

使用方法#

初始化语音识别器并检查状态: #

import Speech

let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN")) // 使用中文
if speechRecognizer?.isAvailable == true {
    print("语音识别器可用!")
} else {
    print("语音识别器当前不可用。")
}

检查是否支持离线识别: #

if speechRecognizer?.supportsOnDeviceRecognition == true {
    print("支持离线语音识别")
} else {
    print("仅支持在线识别需网络连接")
}

启动语音识别任务: #

let request = SFSpeechURLRecognitionRequest(url: /*音频文件URL*/)
speechRecognizer?.recognitionTask(with: request) { result, error in
    if let result = result {
        print("识别结果: \(result.bestTranscription.formattedString)")
    } else if let error = error {
        print("识别任务失败: \(error)")
    }
}

1.2 SFSpeechRecognitionRequest #

功能介绍#

SFSpeechRecognitionRequest 是所有语音识别请求的基类,定义了一些通用属性并由子类扩展实现。 子类包括:

  • SFSpeechURLRecognitionRequest:用于处理音频文件的识别请求。
  • SFSpeechAudioBufferRecognitionRequest:用于处理实时音频流的识别请求。

常用属性#

属性描述
shouldReportPartialResults是否需要中间识别结果,默认为 true(识别过程中会返回实时的中间结果)。
requiresOnDeviceRecognition是否强制要求离线识别,默认为 false(仅对 iOS 13+ 有效)。

1.3 SFSpeechURLRecognitionRequest #

功能介绍#

SFSpeechURLRecognitionRequestSFSpeechRecognitionRequest 的子类,用于将音频文件作为输入并进行离线语音识别。适用于例如语音备忘录转录、文件录音分析等业务。

使用方法#

处理音频文件请求: #

import Speech

let speechRecognizer = SFSpeechRecognizer()
let audioURL = URL(fileURLWithPath: "/path/to/audio-file.m4a")
let request = SFSpeechURLRecognitionRequest(url: audioURL)

// 启动音频文件识别任务
speechRecognizer?.recognitionTask(with: request) { result, error in
    if let result = result {
        print("识别结果: \(result.bestTranscription.formattedString)") // 最佳匹配结果
    } else if let error = error {
        print("识别失败: \(error)")
    }
}

设置是否返回部分结果: #

request.shouldReportPartialResults = false // 不返回中间结果,等待最终输出

1.4 SFSpeechAudioBufferRecognitionRequest #

功能介绍#

此类用于实时语音流的识别操作,通常与 AVAudioEngine 配合使用,将麦克风数据实时传输到识别器。

常用属性#

属性描述
append(buffer: AVAudioPCMBuffer)将实时音频数据传递给当前的识别请求。
endAudio()通知请求输入的音频已结束(停止实时音频识别)。

使用方法#

处理实时音频流: #

import AVFoundation
import Speech

let audioEngine = AVAudioEngine()
let speechRecognizer = SFSpeechRecognizer()
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

let inputNode = audioEngine.inputNode

// 配置实时音频捕获
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
    recognitionRequest.append(buffer) // 将实时音频流数据附加到请求中
}

do {
    audioEngine.prepare()
    try audioEngine.start()

    speechRecognizer?.recognitionTask(with: recognitionRequest) { result, error in
        if let result = result {
            print("实时识别文本: \(result.bestTranscription.formattedString)") // 打印实时识别结果
        } else if let error = error {
            print("实时识别失败: \(error)")
        }
    }
} catch {
    print("音频引擎启动失败: \(error)")
}

1.5 SFSpeechRecognitionResult #

功能介绍#

语音识别任务的结果,通过识别器回调提供。可以包含多个转录结果,以及对每个结果的置信度信息。

常用属性#

属性描述
bestTranscription最佳转录结果对象,包含完整文本。
isFinal是否为最终结果。此属性为 false 时表示可能有更好的结果还未返回。
transcriptions包含多个可能的转录结果,每个结果按其置信度排序(最可信排名第 1 位)。

使用方法#

获取最佳转录结果: #

speechRecognizer?.recognitionTask(with: request) { result, error in
    if let result = result {
        print("最佳结果: \(result.bestTranscription.formattedString)")
    }
}

获取多个可能匹配结果: #

let candidates = result.transcriptions
for transcription in candidates {
    print("候选结果: \(transcription.formattedString)")
}

1.6 SFSpeechRecognitionTask #

功能介绍#

表示语音识别的任务,可用于控制任务状态,如取消、完成以及接收识别的更新结果。

常用方法#

方法描述
cancel()取消正在进行的识别任务。
finish()手动完成识别任务。

停止任务并释放资源: #

recognitionTask.cancel() // 取消任务
audioEngine.stop()
recognitionTask = nil

1.7 SFSpeechRecognizerDelegate #

功能介绍#

用于监视语音识别器的状态变化,例如监听是否可用。

方法#

方法描述
speechRecognizer(_:availabilityDidChange:)当语音识别器状态(如网络断开)发生变化时触发。

实现代理方法: #

class SpeechRecognizerDelegate: NSObject, SFSpeechRecognizerDelegate {
    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
        if available {
            print("语音识别可用了!")
        } else {
            print("语音识别器暂时不可用")
        }
    }
}

let delegate = SpeechRecognizerDelegate()
speechRecognizer?.delegate = delegate

2. 核心流程 #

在使用 Foundation Speech 框架时,语音识别可以分为几个关键步骤:

1. 请求权限 #

  • 必须请求用户授权才能使用语音识别功能和麦克风访问。

2. 初始化语音识别器 #

  • 通过 SFSpeechRecognizer 根据指定语言初始化一个语音识别器。

3. 创建识别请求 #

  • 根据需求选择文件请求(SFSpeechURLRecognitionRequest)或实时音频流请求(SFSpeechAudioBufferRecognitionRequest)。

4. 启动识别任务 #

  • 调用语音识别器的 recognitionTask 方法进行识别任务,并获取实时更新或最终识别结果。

5. 处理识别结果 #

  • 通过 result.bestTranscription 提取识别的文本。

好的,以下是重新梳理过的完整介绍,补充了缺失的内容,同时使用 列表表格形式 清晰地描述了 Speech 框架的关键组件及功能。希望对您有所帮助!


在 Swift 中,Speech 框架 (Speech Framework) 提供了全面的语音识别功能,包括识别实时音频和对离线音频文件进行转录。这一功能广泛应用于语音命令、语音交互、实时语音输入等领域。


3. 详细步骤 #

在使用 Speech 框架时,一般分为以下几个主要步骤:

(1) 请求权限 #

在使用语音识别之前,必须获得用户的授权(语音识别权限和麦克风权限):

import Speech

SFSpeechRecognizer.requestAuthorization { status in
    switch status {
    case .authorized:
        print("用户已授权语音识别权限")
    case .denied:
        print("用户拒绝语音识别权限")
    case .restricted:
        print("设备对语音识别有限制")
    case .notDetermined:
        print("语音识别权限未决定")
    @unknown default:
        fatalError("未知的语音识别状态")
    }
}

Info.plist 文件中还需要申请以下权限:

  1. NSSpeechRecognitionUsageDescription(语音识别)
  2. NSMicrophoneUsageDescription(麦克风)

(2) 初始化 SFSpeechRecognizer #

SFSpeechRecognizer 是核心类,用于启动和管理语音识别功能。你可以指定语言,也可以使用设备支持的默认语言。

// 使用默认设备语言
let speechRecognizer = SFSpeechRecognizer()

// 指定使用中文(zh-CN)为语言的识别器
let locale = Locale(identifier: "zh-CN") // 英文为 "en-US"
let speechRecognizerLocale = SFSpeechRecognizer(locale: locale)

// 检查语音识别器是否可用
if speechRecognizer?.isAvailable == true {
    print("语音识别器可以使用")
} else {
    print("语音识别器当前不可用")
}

(3) 构建识别任务 #

a. 基于音频文件的语音识别 #

使用 SFSpeechURLRecognitionRequest 处理离线音频文件:

import Speech

let speechRecognizer = SFSpeechRecognizer() // 初始化识别器
let audioURL = URL(fileURLWithPath: "/path/to/audio-file.m4a") // 音频文件路径

// 创建识别请求
let request = SFSpeechURLRecognitionRequest(url: audioURL)

// 创建识别任务
speechRecognizer?.recognitionTask(with: request) { result, error in
    if let error = error {
        print("语音识别错误: \(error)")
    } else if let result = result {
        // 打印最佳匹配的转录结果
        print("识别结果最佳匹配: \(result.bestTranscription.formattedString)")
    }
}

b. 基于实时音频流的语音识别 #

实时语音需要和 AVAudioEngine 配合,以下是完整代码流程:

import AVFoundation
import Speech

// 初始化必要组件
let audioEngine = AVAudioEngine()
let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
var recognitionTask: SFSpeechRecognitionTask?
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

// 检查语音识别器是否可用
guard speechRecognizer?.isAvailable == true else {
    print("语音识别器当前不可用")
    return
}

// 配置音频引擎,捕获麦克风数据
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)

inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
    recognitionRequest.append(buffer) // 将音频输入数据传递到实时语音请求
}

// 启动音频引擎
do {
    audioEngine.prepare()
    try audioEngine.start()

    // 启动语音识别任务
    recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest) { result, error in
        if let result = result {
            print("实时识别文本: \(result.bestTranscription.formattedString)")
        } else if let error = error {
            print("实时语音识别任务错误: \(error)")
        }
    }
} catch {
    print("音频引擎启动失败: \(error)")
}

(4) 停止语音识别 #

当识别任务完成时,需要正确释放资源。

audioEngine.stop()
recognitionRequest.endAudio()
audioEngine.inputNode.removeTap(onBus: 0) // 移除音频捕获 Tap
recognitionTask?.finish()
recognitionTask = nil

4. 处理语音识别结果 #

语音识别返回的 SFSpeechRecognitionResult 包含以下信息:

  • bestTranscription:最佳转录结果。
  • isFinal:表示本次识别任务是否结束。
  • transcriptions:包含多个可能的转录结果,按可信度排序。

获取最佳识别文本 #

if let result = result {
    print("最佳识别结果: \(result.bestTranscription.formattedString)")
}

获取多个可能结果 #

for transcription in result.transcriptions {
    print("可能的识别结果: \(transcription.formattedString)")
}

逐段获取转录结果 #

if let result = result {
    for segment in result.bestTranscription.segments {
        print("识别段文本: \(segment.substring)")
        print("置信度: \(segment.confidence)")
    }
}

5. 常见错误与解决 #

错误类型描述解决方案
权限未授权用户拒绝语音识别或麦克风权限请求权限并提示用户开启权限。
网络不可用在线语音识别需要依赖网络连接提示用户检查网络,或尝试支持离线模式。
语言模型不支持当前语言可能未被支持或不被苹果提供离线识别支持使用 Locale 检查支持的语言列表,选择兼容的语言。
输入音频格式错误传递给 recognitionRequest 的音频数据格式不兼容确保音频格式匹配(如麦克风输入和识别请求的数据格式)。

6. Code:如何使用 Speech #

以下是实现语音识别的具体代码示例:

6.1 添加权限到 Info.plist #

在使用麦克风和语音识别之前,首先需要在 Info.plist 中添加权限:

<key>NSSpeechRecognitionUsageDescription</key>
<string>App requires speech recognition for processing your voice input.</string>

<key>NSMicrophoneUsageDescription</key>
<string>App requires microphone access to capture your voice.</string>

6.2 请求权限 #

使用 SFSpeechRecognizer.requestAuthorization 请求用户许可:

import Speech

SFSpeechRecognizer.requestAuthorization { authStatus in
    switch authStatus {
    case .authorized:
        print("Speech recognition authorized.")
    case .denied:
        print("Speech recognition authorization denied.")
    case .restricted:
        print("Speech recognition restricted on this device.")
    case .notDetermined:
        print("Speech recognition authorization not yet determined.")
    @unknown default:
        fatalError("Unknown authorization status.")
    }
}

6.3 从音频文件识别语音 #

如果需要从现有的音频文件创建语音识别任务,可以使用 SFSpeechURLRecognitionRequest

示例代码: #

func recognizeSpeechFromFile(url: URL) {
    // 初始化语音识别器
    let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
    
    guard let recognizer = speechRecognizer, recognizer.isAvailable else {
        print("Speech recognizer is unavailable.")
        return
    }
    
    // 创建音频文件识别请求
    let request = SFSpeechURLRecognitionRequest(url: url)
    
    // 启动识别任务
    recognizer.recognitionTask(with: request) { result, error in
        if let error = error {
            print("Error during recognition: \(error.localizedDescription)")
        } else if let result = result {
            print("Recognized text: \(result.bestTranscription.formattedString)")
        }
    }
}

关键点: #

  • 使用指定音频文件的 URL 进行语音识别。
  • 注意音频文件的格式需要被 Apple 支持,如 .m4a.wav.aac

6.4 实时语音识别(通过麦克风) #

对于需要实时捕获语音的场景(如语音助手或文字转录应用),使用 SFSpeechAudioBufferRecognitionRequest

示例代码: #

import AVFoundation
import Speech

class SpeechRecognizer {
    private let audioEngine = AVAudioEngine()
    private var speechRecognizer: SFSpeechRecognizer? = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
    private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
    private var recognitionTask: SFSpeechRecognitionTask?
    
    func startRecognition() {
        guard let recognizer = speechRecognizer, recognizer.isAvailable else {
            print("Speech recognizer is unavailable.")
            return
        }
        
        // 设置音频会话
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
            return
        }
        
        // 配置实时语音请求
        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
        guard let request = recognitionRequest else { return }
        request.shouldReportPartialResults = true // 实时返回部分结果
        
        // 使用音频引擎捕获输入
        let inputNode = audioEngine.inputNode
        let recordingFormat = inputNode.outputFormat(forBus: 0)
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
            self.recognitionRequest?.append(buffer)
        }
        
        // 开始音频引擎
        audioEngine.prepare()
        do {
            try audioEngine.start()
            print("AudioEngine started. Say something!")
        } catch {
            print("AudioEngine failed to start: \(error.localizedDescription)")
        }
        
        // 启动语音识别任务
        recognitionTask = recognizer.recognitionTask(with: request) { result, error in
            if let result = result {
                print("Recognized text: \(result.bestTranscription.formattedString)")
            }
            
            if error != nil || result?.isFinal == true {
                self.audioEngine.stop()
                inputNode.removeTap(onBus: 0)
                self.recognitionRequest = nil
                self.recognitionTask = nil
                print("Recognition task ended.")
            }
        }
    }
    
    func stopRecognition() {
        audioEngine.stop()
        recognitionRequest?.endAudio()
        print("AudioEngine stopped.")
    }
}

关键点: #

  1. 音频会话 (AVAudioSession)

    • 设置会话类别以允许录音。
  2. 添加 AudioEngine Tap

    • 使用 installTap(onBus:bufferSize:format:) 捕获实时音频。
  3. 实时语音识别

    • shouldReportPartialResults 用于开启实时显示部分识别结果。
    • 处理完成或中断时,记得停止音频引擎。
本文共 4632 字,上次修改于 Jan 1, 2025