
-
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 prática de codificação.
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...
Olá! Sou Donovan, engineer da equipe Speech framework. E eu sou Shantini, engineer da equipe do Notes. Este ano, apresentamos a próxima evolução da nossa API e tecnologia de conversão de fala em texto: SpeechAnalyzer. Nesta sessão, vamos falar sobre a API SpeechAnalyzer e seus conceitos mais importantes. Também vamos abordar alguns dos novos recursos do modelo por trás dela. Ao final, vamos fazer uma demonstração ao vivo de como usar a API. A SpeechAnalyzer já está presente em muitos apps, como o Notas, o Gravador, o Diário e outros.
Quando a combinamos com a Apple Intelligence, criamos recursos poderosos, como o resumo de ligações. Já, já, vou mostrar como usar a API para criar seu próprio recurso de transcrição ao vivo. Primeiro, Donovan vai dar uma visão geral da nova API SpeechAnalyzer. A conversão de fala em texto, conhecida como reconhecimento automático de fala, ou ASR, é uma tecnologia que permite criar experiências usando fala ao vivo ou gravada, convertendo-a em texto para ser exibido ou interpretado por um dispositivo. Os apps armazenam, pesquisam ou transmitem o texto em tempo real ou o transferem para um modelo de linguagem baseado em texto.
No iOS 10, apresentamos a SFSpeechRecognizer. Com essa classe, tivemos acesso ao modelo de conversão de fala em texto presente na Siri. Ela funcionava bem para ditados curtos e usava servidores da Apple em dispositivos com recursos limitados, mas não atendia a alguns casos de uso tão bem quanto gostaríamos, e cabia ao usuário adicionar idiomas. Agora, no iOS 26, estamos introduzindo uma nova API chamada SpeechAnalyzer, que oferece suporte a mais casos de uso. Ela aproveita o poder do Swift para processar a conversão de fala em texto e gerenciar ativos de modelo no dispositivo do usuário com muito pouco código. Também criamos um novo modelo de conversão de fala em texto que já está presente nos recursos dos apps das nossas plataformas. O novo modelo é mais rápido e flexível do que o disponibilizado pela SFSpeechRecognizer. Ele é bom para áudios longos e à distância, como palestras, reuniões e conversas. Devido a essas melhorias, a Apple está usando esse novo modelo (e a nova API) no Notas e nos outros apps que já mencionamos. Você pode usar essas novas funcionalidades para criar seu próprio app com os mesmos recursos que o Notas e os outros apps oferecem. Antes, vamos conferir o design da API. A API consiste na classe SpeechAnalyzer e várias outras. A classe SpeechAnalyzer gerencia uma sessão de análise. Você pode adicionar uma classe de módulo à sessão para executar um tipo específico de análise. Adicionar um módulo Transcriber à sessão a transforma em uma sessão de transcrição que converte fala em texto. Você envia buffers de áudio para a instância do analisador, que os direciona pelo modelo de conversão de fala em texto do transcritor. O modelo prevê o texto que corresponde ao áudio falado e retorna esse texto com alguns metadados para seu app.
Tudo isso funciona de forma assíncrona. Seu app adiciona áudio conforme a disponibilidade em uma tarefa e exibe ou processa os resultados de forma independente em outra tarefa. As sequências assíncronas do Swift armazenam em buffer e desvinculam a entrada dos resultados.
A sessão "Conhecer o AsyncSequence" da WWDC21 aborda como fornecer uma sequência de entrada e ler a sequência de resultados.
Para correlacionar a entrada aos resultados, a API usa a marcação de tempo do áudio. As operações da API são programadas usando as marcações na linha do tempo do áudio, tornando a ordem delas previsível e independente de quando são acionadas. As marcações de tempo são precisas até mesmo em uma amostra de áudio individual. Note como o transcritor fornece resultados em sequência, cada um deles abrangendo a própria faixa de áudio, sem sobreposição. Normalmente, é assim que funciona. Mas, como recurso opcional, você pode deixar a transcrição iterativa dentro de uma faixa de áudio. Faça isso se quiser oferecer feedback mais imediato na interface do app. Você pode mostrar um resultado aproximado e, em seguida, mostrar iterações melhores desse resultado nos próximos segundos. Chamamos os resultados imediatos de "resultados voláteis". Eles são fornecidos logo depois de falados, mas são "palpites" menos precisos. No entanto, o modelo melhora a transcrição conforme recebe mais áudio com mais contexto. No fim, o resultado será o melhor possível, e a transcrição fornece um último "resultado finalizado". Feito isso, o transcritor para de fornecer resultados para essa faixa de áudio e passa para a próxima. Note como as marcações de tempo mostram que os resultados posteriores substituem os anteriores. Isso só acontece quando você ativa os resultados voláteis. Normalmente, o transcritor só fornece resultados finalizados, e nenhum deles substitui os anteriores. Se você só precisa ler o arquivo e retornar a transcrição, pode criar um recurso de transcrição em apenas uma função. Essa tarefa não exige processamento de resultados voláteis ou muita simultaneidade. Aqui temos a função. Aqui criamos o módulo Transcriber. Nós informamos o idioma da transcrição. Ele ainda não tem resultados, mas vamos lê-los conforme forem entrando e usar a versão de "reduce" do AsyncSequence para concatená-los. Vamos fazer isso em segundo plano usando "async let". Aqui, criamos o analisador e adicionamos o módulo Transcriber. Depois, começamos a analisar o arquivo. O método analyzeSequence lê o arquivo e adiciona o áudio a uma sequência de entrada. Depois disso, pedimos ao analisador para terminar, porque não estamos planejando trabalhar em nenhum outro áudio. Por fim, retornamos a transcrição que fomos montando em segundo plano. Serão as palavras faladas no arquivo, na forma de uma única string atribuída. E pronto. Falei sobre os conceitos e o uso básico da API. Você adiciona módulos a uma sessão de análise para fazer uma transcrição, por exemplo. Ele funciona de forma simultânea e assíncrona, desvinculando a entrada de áudio dos resultados. Você correlaciona áudio, resultados e operações usando a marcação de tempo do áudio da sessão. Alguns desses resultados são voláteis, se você quiser que sejam, e o restante é definitivo. Também mostrei como isso funciona em uma função. Mais tarde, Shantini vai demonstrar como usar essa função em diferentes visualizações, modelos e modelos de visualização. Ela vai mostrar vários métodos e propriedades das classes SpeechAnalyzer e Transcriber que você pode usar em situações comuns. Você também pode ler sobre isso na documentação. Agora, queremos descrever algumas vantagens do novo modelo da classe SpeechTranscriber. A SpeechTranscriber funciona com um novo modelo projetado pela Apple para dar suporte a vários casos de uso. Queríamos criar um modelo que aceitasse falas longas e conversacionais em que os palestrantes estão longe do microfone, como gravar uma reunião. Também queríamos oferecer experiências de transcrição ao vivo que exigissem baixa latência sem sacrificar a precisão ou a legibilidade, além de manter a privacidade. Nosso novo modelo faz tudo isso, no dispositivo. Trabalhamos com parceiros internos para criar uma ótima experiência para você. Agora, você pode dar suporte aos mesmos casos de uso nos seus apps. Com a SpeechTranscriber, você tem um modelo de conversão de fala em texto sem precisar adquirir e gerenciar nada. Basta instalar os ativos de modelo relevantes pela nova API AssetInventory. Você pode baixá-los quando precisar. O modelo fica armazenado no sistema e não aumenta o tamanho do download ou do armazenamento do seu app. Ele também não aumenta o tamanho da memória do tempo de execução. Ele funciona fora do espaço de memória do seu app, para você não se preocupar em exceder o limite de tamanho. Estamos sempre melhorando o modelo, para que o sistema instale as atualizações conforme forem disponibilizadas. A SpeechTranscriber pode transcrever estes idiomas (outros em breve) e está disponível para todas as plataformas, exceto watchOS, com certos requisitos de hardware. Se precisar de um idioma ou dispositivo ainda não aceitos, temos uma segunda classe de transcritor: DictationTranscriber. Ela aceita os mesmos idiomas, modelo de conversão de fala em texto e dispositivos que a SFSpeechRecognizer do iOS 10. Porém, você NÃO vai precisar pedir aos usuários para entrar em Ajustes e ativar o ditado da Siri ou do teclado para um idioma específico. Essa foi nossa introdução à nova API e ao novo modelo. Ficou bem abstrata, mas vamos ser mais concretos agora. Vou passar para Shantini, que vai mostrar como integrar a SpeechAnalyzer ao seu app. Obrigada por essa excelente visão geral, Donovan! Você já deve ter visto os recursos que adicionamos ao Notas no iOS 18 para gravar e transcrever ligações, áudio em tempo real e áudio gravado. Além disso, integramos esses recursos à Apple Intelligence, resultando em resumos que economizam tempo. Trabalhamos em parceria com a equipe de Speech para garantir que a SpeechAnalyzer e a SpeechTranscriber oferecessem um recurso de qualidade. A SpeechTranscriber é ótima porque é rápida, precisa em longas distâncias e funciona no dispositivo. Um dos nossos objetivos era que você criasse recursos semelhantes aos que adicionamos ao Notas e os personalizasse para seus usuários. Vou mostrar como começar. Vamos ver um app que criei com um recurso de transcrição ao vivo. Meu app é voltado para crianças. Ele grava e transcreve histórias para dormir, permitindo reprodução. Estes são os resultados da transcrição em tempo real.
Ao reproduzir o áudio, o segmento de texto correspondente é destacado, para as crianças poderem acompanhar a história. Aqui está a configuração do projeto.
No exemplo de código, tenho uma classe Recorder e uma classe SpokenWordTranscriber. Transformei as duas em observáveis.
Também criei o modelo Story para registrar as informações de transcrição e detalhes relevantes para exibição. Temos a visualização da transcrição, com visualizações de transcrição ao vivo e reprodução, além de botões de gravação e reprodução. Ele também processa estados de gravação e reprodução. Vamos analisar a transcrição primeiro. Podemos configurar a transcrição ao vivo em 3 etapas: configurar a SpeechTranscriber, verificar se o modelo está presente e gerenciar os resultados. Na configuração, inicializamos o transcritor com um objeto de localidade e as opções necessárias. O código de idioma da localidade corresponde ao idioma em que a transcrição será feita. Como Donovan já falou, resultados voláteis são "palpites" em tempo real, e resultados finalizados são os melhores "palpites". Aqui ambos são usados, com os resultados voláteis em uma opacidade mais leve sendo substituídos pelos resultados finalizados que entram. Para configurar isso no transcritor, vamos definir os seguintes tipos de opção. Vou adicionar a opção audioTimeRange para termos informações sobre tempo.
Isso permite sincronizar a reprodução do texto com o áudio.
Há também ajustes pré-configurados com diferentes opções.
Agora vamos configurar o objeto SpeechAnalyzer com o módulo SpeechTranscriber.
Isso nos permite ter o formato de áudio que precisamos usar.
Assim também garantimos que o modelo de conversão de fala em texto está ativo.
Para concluir a configuração do transcritor, vamos salvar referências à entrada AsyncStream e iniciar a análise.
Agora que terminamos a configuração, vamos ver como obter os modelos. No nosso método "verificar se o modelo está presente", vamos verificar se o transcritor faz transcrições para o idioma desejado.
Também vamos checar se o idioma foi baixado e instalado.
Se o idioma é aceito, mas não foi baixado, podemos fazer uma solicitação à AssetInventory para baixá-lo.
Lembre-se: a transcrição é feita inteiramente no dispositivo, mas os modelos precisam ser obtidos. A solicitação de download inclui um objeto "progress" que você pode usar para informar ao usuário o que está acontecendo.
Seu app pode dar suporte a um número limitado de idiomas ao mesmo tempo. Se você exceder o limite, poderá pedir à AssetInventory para realocar um ou mais deles e liberar uma vaga.
Agora que já temos os modelos, vamos para a parte divertida: os resultados.
Ao lado do código de configuração do transcritor, vou criar uma tarefa e salvar uma referência a ela.
Também vou criar duas variáveis para acompanhar os resultados voláteis e finalizados.
A SpeechTranscriber retorna resultados via AsyncStream. Cada objeto de resultado tem campos diferentes.
O primeiro que queremos obter é "text", que é representado por uma string atribuída. Este é o resultado da transcrição de um segmento de áudio. Toda vez que tivermos um resultado no fluxo, vamos verificar se ele é volátil ou finalizado usando a propriedade "isFinal".
Se for volátil, vamos salvá-lo em volatileTranscript.
Sempre que tivermos um resultado finalizado, vamos apagar volatileTranscript e adicionar o resultado a finalizedTranscript.
Se não apagarmos os resultados voláteis, poderemos ter duplicações.
Sempre que tivermos um resultado finalizado, também vou adicioná-lo ao modelo Story para usar depois.
Também vou definir formatações condicionais usando APIs com strings atribuídas da SwiftUI.
Assim podemos visualizar os resultados da transcrição conforme passarem de voláteis para finalizados.
Caso você esteja se perguntando sobre os dados de tempo da transcrição, eles fazem parte da string atribuída.
Cada execução tem um atributo audioTimeRange representado como CMTimeRange. Vou usá-lo no meu código de visualização para destacar o segmento correto. Agora vamos configurar a entrada de áudio.
Na função de gravação, acionada quando o usuário pressiona o botão de gravar, vou solicitar permissão de áudio e iniciar a AVAudioSession. Também devemos garantir que o app esteja configurado para usar o microfone, nas configurações do projeto.
Em seguida, vou acionar a função setUpTranscriber que criamos antes.
Por fim, vou processar a entrada do fluxo de áudio. Vamos ver como configurei isso. Algumas coisas estão acontecendo aqui. Configuramos o AVAudioEngine para retornar um fluxo assíncrono e enviamos os buffers de entrada para o fluxo.
Também gravamos o áudio no disco.
Agora, estamos iniciando o audioEngine.
Voltando à função Record, vou enviar a entrada AsyncStream para o transcritor.
As fontes de áudio têm formatos de saída e taxas de amostragem diferentes. A SpeechTranscriber nos deu um bestAvailableAudioFormat que podemos usar.
Vou submeter os buffers de áudio a uma etapa de conversão para garantir que o formato corresponda a bestAvailableAudioFormat.
Depois, vou direcionar o fluxo assíncrono da SpeechTranscriber para o objeto inputBuilder. Ao parar a gravação, precisamos fazer algumas coisas. Parei o mecanismo de áudio e o transcritor. É importante cancelar as tarefas e acionar a finalização no fluxo de análise. Isso garante a finalização dos resultados voláteis. Vamos ver como conectar tudo isso à nossa visualização.
A TranscriptView tem uma vinculação com a história atual e uma com a SpokenWordTranscriber. Se estivermos gravando, mostramos uma concatenação da transcrição finalizada com a transcrição volátil observada na classe SpokenWordTranscriber. Na reprodução, mostramos a transcrição final do modelo de dados. Inseri um método para dividir as frases e deixar o visual mais limpo.
Um recurso importante que mencionei foi destacar as palavras conforme são reproduzidas. Usei alguns métodos auxiliares para calcular se cada execução deve ser destacada, com base no atributo audioTimeRange e no tempo de reprodução atual.
A precisão da SpeechTranscriber é ótima por muitas razões, entre elas o uso da Apple Intelligence para fazer transformações úteis nos resultados.
Aqui usei a nova API FoundationModels para gerar um título para minha história quando ela terminar. A API facilita a criação de títulos criativos, então nem preciso pensar em um! Para saber mais sobre as APIs FoundationModels, confira a sessão "Conhecer o framework Foundation Models".
Vamos ver nosso recurso em ação! Vou tocar no botão + para criar uma nova história.
Depois, vou começar a gravar. "Era uma vez, no reino místico de Magenta, uma menina chamada Delilah, que vivia em um castelo na colina. Delilah passava os dias explorando a floresta e cuidando dos animais de lá."
Ao terminar, o usuário poderá reproduzir o áudio, e cada palavra será destacada em sincronia com ele.
"Era uma vez, no reino místico de Magenta, uma menina chamada Delilah, que vivia em um castelo na colina.
Delilah passava os dias explorando a floresta e cuidando dos animais de lá." A SpeechAnalyzer e a SpeechTranscriber nos permitiram criar um app inteiro em pouco tempo. Para saber mais, confira a documentação do framework Speech, que inclui o exemplo de app que criamos. E essa é a SpeechAnalyzer! Temos certeza de que você vai criar recursos incríveis com ela. Agradecemos sua participação.
-
-
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 simultâneo 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.