1、在plist 文件加入以下配置:
<dict>
<key>Speech Recognition Usage Description</key>
<string>语音识别</string>
<key>NSMicrophoneUsageDescription</key>
<string>麦克风权限</string>
</dict>
2、单例管理:
//
// SpeechManager.swift
// ChatgptClient
//
// Created by 柯木超 on 2023/5/16.
//
import UIKit
import Speech
class SpeechManager: NSObject {
static let shared = SpeechManager()
// 定义语言识别需要用到的几个对象的引用
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN"))! // 创建与指定区域设置关联的语音识别器
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? // 语音识别的请求
private var recognitionTask: SFSpeechRecognitionTask? // 语音识别的任务类
private let audioEngine = AVAudioEngine() // 音频引擎,用于音频输入
private var inputNode:AVAudioInputNode!
override init() {
super.init()
do {
try initConfig()
} catch {
print("录音不可用!")
}
}
func initConfig() throws {
// 配置应用程序的音频会话
let audioSession = AVAudioSession.sharedInstance() // 管理音频硬件资源的分配
try audioSession.setCategory(.playAndRecord, options: [ .mixWithOthers]) // 设置音频会话的类别、模式和选项。
try audioSession.setActive(true, options: .notifyOthersOnDeactivation) // 激活音频会话
inputNode = audioEngine.inputNode // inputNode|outputNode分别对应硬件的麦克风和扬声器
}
//开启麦克风权限
func openAudioSession() {
let permissionStatus = AVAudioSession.sharedInstance().recordPermission
if permissionStatus == AVAudioSession.RecordPermission.undetermined {
AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
//此处可以判断权限状态来做出相应的操作,如改变按钮状态
if !granted {
DispatchQueue.main.async {
ToastUtils.showMessage("不开启麦克风权限没法进行语音聊天哦!!!")
}
}
}
}
}
func IsOpenAudioSession() -> Bool{
let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
return authStatus != .restricted && authStatus != .denied
}
func stopRecording() {
self.audioEngine.stop()
self.recognitionRequest?.endAudio()
}
// 录制方法
func startRecording(comple:@escaping (_ resultStr: String?) -> ()) throws {
if !IsOpenAudioSession() {
openAudioSession()
return
}
// 取消上一次正在识别任务(如果有的话)
recognitionTask?.cancel()
self.recognitionTask = nil
// 创建并配置语音识别请求
recognitionRequest = SFSpeechAudioBufferRecognitionRequest() // 从捕获的音频内容(如来自设备麦克风的音频)识别语音的请求
guard let recognitionRequest = recognitionRequest else { fatalError("无法创建SFSpeechAudioBufferRecognitionRequest对象") }
if #available(iOS 16, *) {
// iOS 16 已经支持自动添加标点符号,不需要再喊标点符号了
recognitionRequest.addsPunctuation = true
}
if #available(iOS 13, *) {
if speechRecognizer.supportsOnDeviceRecognition {
recognitionRequest.requiresOnDeviceRecognition = true
}
}
// 设置在音频录制完成之前返回结果
// 每产生一种结果就马上返回
recognitionRequest.shouldReportPartialResults = true
// 将语音识别数据仅限于设备上
if #available(iOS 13, *) {
// 将此属性设置为true以防止SFSpeechRecognitionRequest通过网络发送音频
// 设备上的请求将不那么准确。
recognitionRequest.requiresOnDeviceRecognition = true
}
// 为语音识别会话创建识别任务
// 保留对任务的引用,以便可以取消该任务
recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in
var isFinal = false
if let result = result {
isFinal = result.isFinal
print("【识别内容】\(result.bestTranscription.formattedString)")
}
if error != nil || isFinal {
// 如果出现问题,停止识别语音
self.audioEngine.stop()
self.inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
comple(validString(result?.bestTranscription.formattedString))
}
}
// 配置麦克风输入
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
}
}
3、使用方法:
(1) 开始识别
do {
try SpeechManager.shared.startRecording { resultStr in
if validString(resultStr) != "" {
// 这里做识别后的操作
} else {
print("chat 返回数据为空")
}
}
}
} catch {
print("语音输入失败")
}
(2) 结束识别:
SpeechManager.shared.stopRecording()