iOS MachineLearning 系列(13)—— 语音与音频相关的AI能力

简介: 在语音分析方面,iOS中提供了原生的Speech框架,这个框架可以实时的将语音解析成文本。这个能力非常强大,使用它我们可以实现类似实时翻译的功能。对于非语音的音频,也有一些原生的AI能力可以使用,例如分析语音的类型。SoundAnalysis框架能够识别300多种声音,我们也可以使用自己训练的模型来处理定制化的音频识别需求。

iOS MachineLearning 系列(13)—— 语音与音频相关的AI能力

在语音分析方面,iOS中提供了原生的Speech框架,这个框架可以实时的将语音解析成文本。这个能力非常强大,使用它我们可以实现类似实时翻译的功能。对于非语音的音频,也有一些原生的AI能力可以使用,例如分析语音的类型。SoundAnalysis框架能够识别300多种声音,我们也可以使用自己训练的模型来处理定制化的音频识别需求。

1 - 进行语音识别

使用Speech框架来进行语音识别非常简单,并且其支持多种语言。使用此功能前,我们需要先请求用户授予权限。在Info.plist文件中新增如下key:

NSSpeechRecognitionUsageDescription

此key设置的值为字符串文案,会在使用Speech框架时弹窗展示。

需要注意,Speech框架提供的并非是完全依赖本地的AI能力,其需要连接Apple的服务器来实现功能,因此在使用时要确保网络的正常。

首先需要定义个识别器对象,如下:

let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-Hants"))

其中locale参数设置所识别为的语言。

之后需要创建一个语音识别请求,并发起识别任务,如下:

// 这里使用本地的语音文件
let path = Bundle.main.path(forResource: "12168", ofType: ".wav")
let url = URL(fileURLWithPath: path!)
// 创建请求对象
let request = SFSpeechURLRecognitionRequest(url: url)

let label = UILabel(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 400))
label.numberOfLines = 0
view.addSubview(label)
// 发起请求任务
recognizer?.recognitionTask(with: request, resultHandler: { result, error in
    print(result?.bestTranscription.formattedString, error)
    label.text = result?.bestTranscription.formattedString
})

运行上面的代码,如果提供的音频文件是正常的语音文件,即可看到识别效果。上面的结果回调会根据音频的长度来多次回调,每次都会根据上下文进行之前识别结果的矫正。

Speech框架不仅支持语音文件的识别,也支持实时进行语音数据流的识别。只需要创建不同的Request类即可。我们可以先来看下语音分析请求的父类SFSpeechRecognitionRequest:

open class SFSpeechRecognitionRequest : NSObject {
    // 设置语音识别的类型
    open var taskHint: SFSpeechRecognitionTaskHint
    // 设置是否在解析过程中返回中间值,默认true,如果设置false则只有当整个语音文件解析完成再返回结果
    open var shouldReportPartialResults: Bool
    // 设置一组自定义的短语,这些短语可能不在词汇表中,针对场景的加强识别的准确性
    open var contextualStrings: [String]
    // 是否进行纯本地的解析,这种场景下不会发送语音到apple服务器,但是会降低准确性,某些语言不可用
    open var requiresOnDeviceRecognition: Bool
    // 设置识别结果中是否增加标点,iOS16之后可用
    open var addsPunctuation: Bool
}

其中taskHint属性用来设置识别类型,此枚举定义如下:

public enum SFSpeechRecognitionTaskHint : Int, @unchecked Sendable {
    case unspecified = 0 // 未指定明确类型
    case dictation = 1 // 一般的听写风格
    case search = 2 // 搜索请求风格
    case confirmation = 3 // 短语
}

要对语音文件进行分析,使用SFSpeechURLRecognitionRequest子类,如果要实时识别语音流,则使用SFSpeechAudioBufferRecognitionRequest子类即可,SFSpeechAudioBufferRecognitionRequest定义如下:

open class SFSpeechAudioBufferRecognitionRequest : SFSpeechRecognitionRequest {
    // 利于识别的音频格式
    open var nativeAudioFormat: AVAudioFormat { get }
    // 添加AVAudioPCMBuffer数据
    open func append(_ audioPCMBuffer: AVAudioPCMBuffer)
    // 添加CMSampleBuffer数据
    open func appendAudioSampleBuffer(_ sampleBuffer: CMSampleBuffer)
    // 调用此方法标识语音流数据添加完成
    open func endAudio()
}

SFSpeechRecognizer类用来发起语音识别请求,定义如下:

open class SFSpeechRecognizer : NSObject {
    // 所支持的语言
    open class func supportedLocales() -> Set<Locale>
    // 用户授权状态
    open class func authorizationStatus() -> SFSpeechRecognizerAuthorizationStatus
    // 请求用户授权
    open class func requestAuthorization(_ handler: @escaping (SFSpeechRecognizerAuthorizationStatus) -> Void)
    // 构造方法,使用当前系统语言
    public convenience init?()
    // 构造方法,设置语言
    public init?(locale: Locale)
    // 功能是否可用
    open var isAvailable: Bool { get }
    // 使用的语言
    open var locale: Locale { get }
    // 获取是否支持纯本地的请求
    open var supportsOnDeviceRecognition: Bool
    // 代理
    weak open var delegate: SFSpeechRecognizerDelegate?
    // 设置发起请求默认的类型
    open var defaultTaskHint: SFSpeechRecognitionTaskHint
    // 发起请求任务
    open func recognitionTask(with request: SFSpeechRecognitionRequest, resultHandler: @escaping (SFSpeechRecognitionResult?, Error?) -> Void) -> SFSpeechRecognitionTask
    open func recognitionTask(with request: SFSpeechRecognitionRequest, delegate: SFSpeechRecognitionTaskDelegate) -> SFSpeechRecognitionTask
    // 回调所使用的队列
    open var queue: OperationQueue
}

// SFSpeechRecognizerDelegate协议
public protocol SFSpeechRecognizerDelegate : NSObjectProtocol {
    // 可用性变化时回调
    optional func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool)
}

如果使用闭包的方式来发起请求,则结果会在闭包回调中给到,如果采用代理的方式,则会通过代理回调返回。SFSpeechRecognitionTaskDelegate协议如下:

public protocol SFSpeechRecognitionTaskDelegate : NSObjectProtocol {
    // 首次检测到语音时调用
    optional func speechRecognitionDidDetectSpeech(_ task: SFSpeechRecognitionTask)
    // 每次有中间结果时调用
    optional func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didHypothesizeTranscription transcription: SFTranscription)
    // 最终识别完成时调用
    optional func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishRecognition recognitionResult: SFSpeechRecognitionResult)
    // 识别任务结束后调用
    optional func speechRecognitionTaskFinishedReadingAudio(_ task: SFSpeechRecognitionTask)
    // 识别任务取消时调用
    optional func speechRecognitionTaskWasCancelled(_ task: SFSpeechRecognitionTask)
    // 识别任务完整成功后调用
    optional func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishSuccessfully successfully: Bool)
}

其中SFTranscription类用来描述识别中间结果,如下:

open class SFTranscription : NSObject, NSCopying, NSSecureCoding {
    // 格式化后的字符串
    open var formattedString: String { get }
    // 片段数组
    open var segments: [SFTranscriptionSegment] { get }
    // 语音速度,每秒单词数
    open var speakingRate: Double { get }
    // 单词间的平均停顿
    open var averagePauseDuration: TimeInterval { get }
}

其中SFTranscriptionSegment是具体的词组,里面封装了更多详细的信息:

open class SFTranscriptionSegment : NSObject, NSCopying, NSSecureCoding {
    // 词组
    open var substring: String { get }
    // 在原字符串中的位置
    open var substringRange: NSRange { get }
    // 在原音频中的时间点
    open var timestamp: TimeInterval { get }
    // 在音频中的时长
    open var duration: TimeInterval { get }
    // 测量的可信度,0到1,越大表示越可信
    open var confidence: Float { get }
    // 对此音频片段的更多可能结果
    open var alternativeSubstrings: [String] { get }
    // 发声特性对象
    open var voiceAnalytics: SFVoiceAnalytics? { get }
}

SFSpeechRecognitionResult类描述了分析的结果,实际上是一组SFTranscription的聚合。定义如下:

open class SFSpeechRecognitionResult : NSObject, NSCopying, NSSecureCoding {
    // 最完美的结果片段(如果分析结果,此为完整的)
    @NSCopying open var bestTranscription: SFTranscription { get }
    // 所有分析结果(根据可信度来排序)
    open var transcriptions: [SFTranscription] { get }
    // 是否分析结束
    open var isFinal: Bool { get }
    // 音频元数据信息
    open var speechRecognitionMetadata: SFSpeechRecognitionMetadata? { get }
}

SFSpeechRecognitionMetadata中封装了语音的基础数据:

open class SFSpeechRecognitionMetadata : NSObject, NSCopying, NSSecureCoding {
    // 语音速度,每分钟单词数
    open var speakingRate: Double { get }
    // 平均语速,每个单词平均秒数
    open var averagePauseDuration: TimeInterval { get }
    // 语音在音频中的开始时间
    open var speechStartTimestamp: TimeInterval { get }
    // 语音的持续时间
    open var speechDuration: TimeInterval { get }
    // 音频分析数据
    open var voiceAnalytics: SFVoiceAnalytics? { get }
}

open class SFVoiceAnalytics : NSObject, NSCopying, NSSecureCoding {
    // 人声稳定性
    @NSCopying open var jitter: SFAcousticFeature { get }
    @NSCopying open var shimmer: SFAcousticFeature { get }
    // 人声高低
    @NSCopying open var pitch: SFAcousticFeature { get }
    // 语音概率
    @NSCopying open var voicing: SFAcousticFeature { get }
}

发起语音请求后,会返回一个SFSpeechRecognitionTask对象,此任务对象可以对当次分析过程进行控制,如下:

open class SFSpeechRecognitionTask : NSObject {
    // 当前任务状态
    open var state: SFSpeechRecognitionTaskState { get }
    // 是否完成
    open var isFinishing: Bool { get }
    // 手动完成任务
    open func finish()
    // 是否取消
    open var isCancelled: Bool { get }
    // 手动取消任务
    open func cancel()
    // 异常数据
    open var error: Error? { get }
}

// 任务状态枚举定义如下
public enum SFSpeechRecognitionTaskState : Int, @unchecked Sendable {
    case starting = 0 // 开始
    case running = 1  // 运行中
    case finishing = 2 // 结束
    case canceling = 3 // 取消
    case completed = 4 //完成
}

2 - 音频类别识别

iOS内置API的音频分析能力可以方便的对音频进行分类,例如人声,乐器声等等。内置的SoundAnalysis框架能够分析识别300余种音效,当然其也支持使用自定义的模型来进行分析,本篇文章将只涉及到API的使用。

SNAudioFileAnalyzer类是音频分析的处理类,例如:

let analyzer = try! SNAudioFileAnalyzer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "12168", ofType: ".wav")!))

SNAudioFileAnalyzer在实例化时会包装一个音频文件地址,后续将对此音频进行分析。首先需要创建一个分析请求,如下:

let request = try! SNClassifySoundRequest(classifierIdentifier: .version1)

其参数设置使用的算法版本。

通过如下方法来向SNAudioFileAnalyzer实例中添加一个请求,并设置请求过程的监听:

try! analyzer.add(request, withObserver: self)

之后调用analyze方法来触发请求的执行:

analyzer.analyze()

对请求过程的监听对象需要实现SNResultsObserving协议,如下:

public protocol SNResultsObserving : NSObjectProtocol {
    // 分析到请求结果时调用的回调,一段音频分析中会持续调用
    func request(_ request: SNRequest, didProduce result: SNResult)
    // 请求失败
    optional func request(_ request: SNRequest, didFailWithError error: Error)
    // 请求完成
    optional func requestDidComplete(_ request: SNRequest)
}

请求的结果数据为SNResult,这个是基础协议,真正将返回的对象是SNClassificationResult类型的,定义如下:

open class SNClassificationResult : NSObject, SNResult {
    // 分析出的类别
    open var classifications: [SNClassification] { get }
    // 在音频中的时间范围
    open var timeRange: CMTimeRange { get }
    // 返回指定标识符的类别
    open func classification(forIdentifier identifier: String) -> SNClassification?
}

open class SNClassification : NSObject {
    // 当前类别的标识符
    open var identifier: String { get }
    // 可信度
    open var confidence: Double { get }
}

SoundAnalysis框架本身比较简单,我们再来看下分析请求类,SNRequest是请求类的基类,为了便于后续framework的升级,我们使用SNClassifySoundRequest类创建请求:

open class SNClassifySoundRequest : NSObject, SNRequest {
    // 模型对固定大小的音频块进行分析时的重叠量,影响分析准确性
    open var overlapFactor: Double
    // 缓冲窗口的持续时间
    open var windowDuration: CMTime
    // 设置一组类别,分析结果将从此组中选择
    open var knownClassifications: [String] { get }
    // 使用自定义的模型进行分析
    public init(mlModel: MLModel)
    // 使用内置模型进行分析
    public init(classifierIdentifier: SNClassifierIdentifier)
}

最后Analyzer相关的类主要用来对请求进行控制,并决定要分析的音频。SoundAnalysis框架支持直接对音频文件进行分析,也支持对音频数据流进行分析,使用的类如下:

// 分析音频文件
open class SNAudioFileAnalyzer : NSObject {
    // 构造方法
    public init(url: URL) throws
    // 添加一个请求和对应的监听实例
    open func add(_ request: SNRequest, withObserver observer: SNResultsObserving) throws
    // 移除一个请求
    open func remove(_ request: SNRequest)
    // 移除所有请求
    open func removeAllRequests()
    // 开启同步分析(会阻塞线程)
    open func analyze()
    // 异步进行分析
    open func analyze(completionHandler: @escaping (Bool) -> Void)
    // 异步分析
    open func analyze() async -> Bool
    // 取消分析任务
    open func cancelAnalysis()
}

// 分析音频流
open class SNAudioStreamAnalyzer : NSObject {
    // 构造方法
    public init(format: AVAudioFormat)
    open func add(_ request: SNRequest, withObserver observer: SNResultsObserving) throws
    // 请求控制方法
    open func remove(_ request: SNRequest)
    open func removeAllRequests()
    // 对数据流做分析
    open func analyze(_ audioBuffer: AVAudioBuffer, atAudioFramePosition audioFramePosition: AVAudioFramePosition)
    // 完成数据流分析
    open func completeAnalysis()
}

完整的示例代码可以在如下地址找到:

https://github.com/ZYHshao/MachineLearnDemo

目录
相关文章
|
8月前
|
人工智能 缓存 自然语言处理
Java与多模态AI:构建支持文本、图像和音频的智能应用
随着大模型从单一文本处理向多模态能力演进,现代AI应用需要同时处理文本、图像、音频等多种信息形式。本文深入探讨如何在Java生态中构建支持多模态AI能力的智能应用。我们将完整展示集成视觉模型、语音模型和语言模型的实践方案,涵盖从文件预处理、多模态推理到结果融合的全流程,为Java开发者打开通往下一代多模态AI应用的大门。
612 41
|
机器学习/深度学习 人工智能 算法
通义OmniAudio大模型,让 AI 看懂 360° 视频,并“听”出对应的空间音频
OmniAudio 是一项突破性的空间音频生成技术,能够直接从 360° 视频生成 FOA(First-order Ambisonics)空间音频,为虚拟现实和沉浸式娱乐带来全新可能。通过自监督 coarse-to-fine 预训练和双分支视频表示微调,OmniAudio 在非空间音频质量和空间定位准确性上显著优于现有方法。项目包含超过 103,000 个视频片段的 Sphere360 数据集,支持高质量的模型训练与评估。代码、数据及论文均已开源,助力沉浸式体验技术发展。
1819 63
|
人工智能 文字识别 安全
趣丸千音MCP首发上线魔搭社区,多重技术引擎,解锁AI语音无限可能
近日,趣丸千音(All Voice Lab)MCP正式首发上线魔搭社区。用户只需简单文本输入,即可调用视频翻译、TTS语音合成、智能变声、人声分离、多语种配音、语音转文本、字幕擦除等多项能力。
1309 32
|
11月前
|
人工智能 Android开发 iOS开发
安卓版快捷指令,加了AI语音可以一句话操作v0.2.7
Shortcuts for Android(SFA)是一款安卓自动化工具,支持语音创建快捷指令,实现听歌、导航、发消息等操作。操作简单,提升效率,快来体验语音控制的便捷!
1352 0
安卓版快捷指令,加了AI语音可以一句话操作v0.2.7
|
11月前
|
人工智能 自然语言处理 语音技术
深度解析:AI语音客服系统如何重塑客户服务体验与主流解决方案探析
在数字化浪潮下,AI语音客服凭借高效、便捷、24小时在线的优势,成为企业提升服务效率、优化体验的重要工具。本文详解其核心技术、应用价值、选型要点及市场主流方案,如阿里云通义晓蜜、合力亿捷等,助力企业智能化升级。
678 1
|
12月前
|
人工智能 移动开发 开发工具
H5录音、图文视频IndexDB储存最佳实践:用AI生成语音备忘录
随心记是一个由 AI 生成的网页备忘录,它支持语音录入(可下载)、图文视频记录。最重要的是,它支持离线使用,所有数据都储存在浏览器中,不依赖后端,刷新页面数据也不会丢失!
457 0
H5录音、图文视频IndexDB储存最佳实践:用AI生成语音备忘录
|
人工智能 搜索推荐 程序员
程序员圈爆火,狂揽2.4K星!1秒内AI语音双向对话,支持个性化发音和多端适配,颠覆你的交互想象!
RealtimeVoiceChat是一款基于现代Web技术的开源实时语音对话工具,无需下载任何软件,打开浏览器即可与AI实时语音互动。其核心亮点包括零安装体验、超低延迟、高度可定制化以及跨平台兼容等特性。通过Web Speech API实现毫秒级语音合成,支持多参数精细控制(如音色、语速、音调等),并提供隐私安全保障。项目适用于无障碍辅助、语言学习、智能客服及内容创作等多个场景。开发者可快速集成GPT/Claude等大模型,扩展为企业级应用。此外,随着Web Speech API普及率提升,该项目有望推动语音交互在教育、智能家居等领域的发展
1797 4
|
11月前
|
存储 人工智能 Java
Springboot集成AI Springboot3 集成阿里云百炼大模型CosyVoice2 实现Ai克隆语音(未持久化存储)
本项目基于Spring Boot 3.5.3与Java 17,集成阿里云百炼大模型CosyVoice2实现音色克隆与语音合成。内容涵盖项目搭建、音色创建、音频合成、音色管理等功能,适用于希望快速掌握Spring Boot集成语音AI技术的开发者。需提前注册阿里云并获取API Key。
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
iOS开发 开发者
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
984 67
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决