-
Integre a conversão de fala em texto avançada ao seu app com o SpeechAnalyzer
Descubra a nova API SpeechAnalyzer para conversão de fala em texto. Vamos saber mais sobre a API do Swift e seus recursos, que podem ser usados nos apps Notas, Gravador, Diário e muito mais. Vamos conferir em detalhes como a conversão de fala para texto funciona e como o SpeechAnalyzer e o SpeechTranscriber permitem criar recursos interessantes e eficientes. Além disso, você aprenderá a incorporar o SpeechAnalyzer e a transcrição ao vivo em seu app em uma sessão de codificação guiada.
Capítulos
- 0:00 - Introdução
- 2:41 - API SpeechAnalyzer
- 7:03 - Modelo SpeechTranscriber
- 9:06 - Criar um recurso de conversão de fala em texto
Recursos
Vídeos relacionados
WWDC23
-
Buscar neste vídeo...
-
-
5:21 - Transcribe a file
// Set up transcriber. Read results asynchronously, and concatenate them together. let transcriber = SpeechTranscriber(locale: locale, preset: .offlineTranscription) async let transcriptionFuture = try transcriber.results .reduce("") { str, result in str + result.text } let analyzer = SpeechAnalyzer(modules: [transcriber]) if let lastSample = try await analyzer.analyzeSequence(from: file) { try await analyzer.finalizeAndFinish(through: lastSample) } else { await analyzer.cancelAndFinishNow() } return try await transcriptionFuture -
11:02 - Speech Transcriber setup (volatile results + timestamps)
func setUpTranscriber() async throws { transcriber = SpeechTranscriber(locale: Locale.current, transcriptionOptions: [], reportingOptions: [.volatileResults], attributeOptions: [.audioTimeRange]) } -
11:47 - Speech Transcriber setup (volatile results, no timestamps)
// transcriber = SpeechTranscriber(locale: Locale.current, preset: .progressiveLiveTranscription) -
11:54 - Set up SpeechAnalyzer
func setUpTranscriber() async throws { transcriber = SpeechTranscriber(locale: Locale.current, transcriptionOptions: [], reportingOptions: [.volatileResults], attributeOptions: [.audioTimeRange]) guard let transcriber else { throw TranscriptionError.failedToSetupRecognitionStream } analyzer = SpeechAnalyzer(modules: [transcriber]) } -
12:00 - Get audio format
func setUpTranscriber() async throws { transcriber = SpeechTranscriber(locale: Locale.current, transcriptionOptions: [], reportingOptions: [.volatileResults], attributeOptions: [.audioTimeRange]) guard let transcriber else { throw TranscriptionError.failedToSetupRecognitionStream } analyzer = SpeechAnalyzer(modules: [transcriber]) self.analyzerFormat = await SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith: [transcriber]) } -
12:06 - Ensure models
func setUpTranscriber() async throws { transcriber = SpeechTranscriber(locale: Locale.current, transcriptionOptions: [], reportingOptions: [.volatileResults], attributeOptions: [.audioTimeRange]) guard let transcriber else { throw TranscriptionError.failedToSetupRecognitionStream } analyzer = SpeechAnalyzer(modules: [transcriber]) self.analyzerFormat = await SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith: [transcriber]) do { try await ensureModel(transcriber: transcriber, locale: Locale.current) } catch let error as TranscriptionError { print(error) return } } -
12:15 - Finish SpeechAnalyzer setup
func setUpTranscriber() async throws { transcriber = SpeechTranscriber(locale: Locale.current, transcriptionOptions: [], reportingOptions: [.volatileResults], attributeOptions: [.audioTimeRange]) guard let transcriber else { throw TranscriptionError.failedToSetupRecognitionStream } analyzer = SpeechAnalyzer(modules: [transcriber]) self.analyzerFormat = await SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith: [transcriber]) do { try await ensureModel(transcriber: transcriber, locale: Locale.current) } catch let error as TranscriptionError { print(error) return } (inputSequence, inputBuilder) = AsyncStream<AnalyzerInput>.makeStream() guard let inputSequence else { return } try await analyzer?.start(inputSequence: inputSequence) } -
12:30 - Check for language support
public func ensureModel(transcriber: SpeechTranscriber, locale: Locale) async throws { guard await supported(locale: locale) else { throw TranscriptionError.localeNotSupported } } func supported(locale: Locale) async -> Bool { let supported = await SpeechTranscriber.supportedLocales return supported.map { $0.identifier(.bcp47) }.contains(locale.identifier(.bcp47)) } func installed(locale: Locale) async -> Bool { let installed = await Set(SpeechTranscriber.installedLocales) return installed.map { $0.identifier(.bcp47) }.contains(locale.identifier(.bcp47)) } -
12:39 - Check for model installation
public func ensureModel(transcriber: SpeechTranscriber, locale: Locale) async throws { guard await supported(locale: locale) else { throw TranscriptionError.localeNotSupported } if await installed(locale: locale) { return } else { try await downloadIfNeeded(for: transcriber) } } func supported(locale: Locale) async -> Bool { let supported = await SpeechTranscriber.supportedLocales return supported.map { $0.identifier(.bcp47) }.contains(locale.identifier(.bcp47)) } func installed(locale: Locale) async -> Bool { let installed = await Set(SpeechTranscriber.installedLocales) return installed.map { $0.identifier(.bcp47) }.contains(locale.identifier(.bcp47)) } -
12:52 - Download the model
func downloadIfNeeded(for module: SpeechTranscriber) async throws { if let downloader = try await AssetInventory.assetInstallationRequest(supporting: [module]) { self.downloadProgress = downloader.progress try await downloader.downloadAndInstall() } } -
13:19 - Deallocate an asset
func deallocate() async { let allocated = await AssetInventory.allocatedLocales for locale in allocated { await AssetInventory.deallocate(locale: locale) } } -
13:31 - Speech result handling
recognizerTask = Task { do { for try await case let result in transcriber.results { let text = result.text if result.isFinal { finalizedTranscript += text volatileTranscript = "" updateStoryWithNewText(withFinal: text) print(text.audioTimeRange) } else { volatileTranscript = text volatileTranscript.foregroundColor = .purple.opacity(0.4) } } } catch { print("speech recognition failed") } } -
15:13 - Set up audio recording
func record() async throws { self.story.url.wrappedValue = url guard await isAuthorized() else { print("user denied mic permission") return } #if os(iOS) try setUpAudioSession() #endif try await transcriber.setUpTranscriber() for await input in try await audioStream() { try await self.transcriber.streamAudioToTranscriber(input) } } -
15:37 - Set up audio recording via AVAudioEngine
#if os(iOS) func setUpAudioSession() throws { let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playAndRecord, mode: .spokenAudio) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) } #endif private func audioStream() async throws -> AsyncStream<AVAudioPCMBuffer> { try setupAudioEngine() audioEngine.inputNode.installTap(onBus: 0, bufferSize: 4096, format: audioEngine.inputNode.outputFormat(forBus: 0)) { [weak self] (buffer, time) in guard let self else { return } writeBufferToDisk(buffer: buffer) self.outputContinuation?.yield(buffer) } audioEngine.prepare() try audioEngine.start() return AsyncStream(AVAudioPCMBuffer.self, bufferingPolicy: .unbounded) { continuation in outputContinuation = continuation } } -
16:01 - Stream audio to SpeechAnalyzer and SpeechTranscriber
func streamAudioToTranscriber(_ buffer: AVAudioPCMBuffer) async throws { guard let inputBuilder, let analyzerFormat else { throw TranscriptionError.invalidAudioDataType } let converted = try self.converter.convertBuffer(buffer, to: analyzerFormat) let input = AnalyzerInput(buffer: converted) inputBuilder.yield(input) } -
16:29 - Finalize the transcript stream
try await analyzer?.finalizeAndFinishThroughEndOfInput()
-
-
- 0:00 - Introdução
A Apple está lançando o SpeechAnalyzer, uma nova API e tecnologia de conversão de fala em texto no iOS 26, substituindo o SFSpeechRecognizer introduzido no iOS 10. O SpeechAnalyzer, criado com Swift, é mais rápido, flexível e oferece suporte a áudios longos e à distância, tornando-o adequado para vários casos de uso, como palestras, reuniões e conversas. A nova API permite a criação de recursos de transcrição ao vivo e já está sendo usada em apps do sistema, como Notas, Gravações e Diário. Quando combinada com o Apple Intelligence, facilita recursos avançados, como o Resumo de Ligações.
- 2:41 - API SpeechAnalyzer
O design da API gira em torno da classe SpeechAnalyzer, que gerencia sessões de análise. Ao adicionar um módulo de transcritor, a sessão se torna uma sessão de transcrição capaz de realizar o processamento da conversão de fala em texto. Os buffers de áudio são passados para a instância do analisador, que os direciona pelo modelo de conversão de fala em texto do transcritor. O modelo prevê texto e metadados, que são retornados de modo assíncrono para o app usando as sequências assíncronas do Swift. Todas as operações da API são agendadas usando timecodes na linha de tempo do áudio, garantindo ordem previsível e independência. O transcritor entrega os resultados em sequência, cobrindo faixas específicas de áudio. Um recurso opcional permite a transcrição iterativa dentro de um intervalo, fornecendo "resultados voláteis" imediatos, embora menos precisos, para um retorno mais rápido da interface do usuário que, posteriormente, são refinados em resultados finalizados. Mais adiante nesta apresentação, é discutido um caso de uso que demonstra como criar um módulo transcritor, definir a localidade, ler o áudio de um arquivo, concatenar os resultados usando sequências assíncronas e retornar a transcrição final como uma string atribuída. A API permite o processamento concorrente e assíncrono, desacoplando a entrada de áudio dos resultados, e pode ser expandida para lidar com necessidades mais complexas em diferentes visualizações, modelos e modelos de visualização, como será demonstrado mais adiante.
- 7:03 - Modelo SpeechTranscriber
A Apple desenvolveu um novo modelo de conversão de fala em texto para a classe SpeechTranscriber, desenvolvido para lidar com vários cenários, como gravações longas, reuniões e transcrições ao vivo, com baixa latência e alta precisão. O modelo opera totalmente no dispositivo, garantindo privacidade e eficiência. Ele não aumenta o tamanho do app nem o uso de memória e é atualizado automaticamente. Você pode integrar facilmente o modelo aos seu apps usando a API AssetInventory. Atualmente, a classe SpeechTranscriber oferece suporte a vários idiomas e está disponível na maioria das plataformas Apple, com uma opção de fallback, DictationTranscriber, fornecida para idiomas ou dispositivos não compatíveis.
- 9:06 - Criar um recurso de conversão de fala em texto
No iOS 18, o app Notas foi aprimorado com novos recursos que permitem gravar e transcrever ligações, áudio ao vivo e áudio gravado. Esses recursos foram integrados ao Apple Intelligence para a geração de resumos. A equipe do Speech desenvolveu o SpeechAnalyzer e o SpeechTranscriber, permitindo uma transcrição de alta qualidade no dispositivo, com rapidez e precisão, mesmo à distância. Agora você pode usar essas ferramentas para criar seus próprios recursos de transcrição personalizados. Um app de exemplo foi pensado para crianças; ele grava e transcreve histórias para dormir. O app exibe os resultados da transcrição em tempo real e destaca o segmento de texto correspondente durante a reprodução do áudio. Para implementar a transcrição ao vivo em um app, siga estas três importantes etapas: Configure o SpeechTranscriber com a localidade e as opções apropriadas, certifique-se de que o modelo de conversão de fala em texto necessário seja baixado e instalado no dispositivo e, em seguida, manipule os resultados da transcrição à medida que eles são recebidos por meio de um AsyncStream. Os resultados incluem textos voláteis (suposições em tempo real) e finalizados, permitindo uma sincronização suave entre o texto e a reprodução de áudio. Quando um resultado finalizado é obtido, o "volatileTranscript" é limpo e o resultado é adicionado a "finalizedTranscript" para evitar duplicações. O resultado finalizado também é gravado no modelo Story para uso posterior e visualizado com formatação condicional usando APIs AttributedString no SwiftUI. Configure a entrada de áudio solicitando permissão, iniciando a "AVAudioSession" e configurando a AVAudioEngine para retornar um AsyncStream. O áudio é gravado em disco e passado para o transcritor depois de ser convertido no melhor formato de áudio disponível. Ao parar a gravação, o mecanismo de áudio e o transcritor são interrompidos, e quaisquer resultados voláteis são finalizados. A "TranscriptView" exibe a concatenação de transcrições finalizadas e voláteis durante a gravação, e a transcrição final do modelo de dados durante a reprodução, com as palavras destacadas em sincronia com o áudio. No app de exemplo, o Apple Intelligence é utilizado para gerar um título para a história usando a API Foundation Models, mostrando como você pode usar o Apple Intelligence para executar transformações úteis na saída da conversão de fala em texto. O framework Speech permite o desenvolvimento desse app com tempo de inicialização mínimo. Mais detalhes podem ser encontrados na documentação do produto.