Статьи

Учебное пособие по iOS Speech API

С выпуском iOS 10 разработчики могут использовать новый захватывающий API: распознавание речи . Концепция перевода аудио в текст известна как пользователям, так и разработчикам. iOS предложила эту функцию через Siri и ее кнопку диктовки на клавиатуре в предыдущих версиях. Тем не менее, новая структура имеет больше преимуществ и проста в реализации, как вы скоро обнаружите.

Код для этой статьи можно скачать на GitHub .

Что нового?

С диктовкой было трудно работать из-за ее ограничений. Доступ к нему можно было получить только через клавиатуру по умолчанию или элементы, поддерживающие TextKit . Если язык клавиатуры не поддерживается, слишком плохо для вас! Распознавание может быть выполнено только на живом аудио, а взамен у вас был простой текст. Это может быть более чем достаточно для определенных приложений, но вы можете сделать немного больше.

API предлагает больше функциональности для разработчиков. Это позволяет им использовать фреймворк в любом месте своего приложения без необходимости присутствия клавиатуры. Аудио может подаваться как ввод из предварительно записанного файла или из живого источника. В обоих случаях вы можете контролировать, когда начинать и останавливать операцию, что раньше было невозможно. Кроме того, язык может быть установлен независимо от языка системы. Вы можете выбрать более 50 доступных языков.

Настройка интерфейса

Давайте попробуем API и создадим простое приложение. Для пользовательского интерфейса я использовал только несколько представлений: UIImageViewUILabel Весь вид сенсорный через UIButton

Все три представления объявлены как выходы в ViewController.swift .

 @IBOutlet weak var noteLabel: UILabel!
@IBOutlet weak var microphoneImageView: UIImageView!
@IBOutlet weak var button: UIButton!

Кнопка Touched in action for добавляется следующим образом.

 button

Чтобы соединить @IBAction func tappedButton() {

}
IBOutletsнажмите на кружок слева и перетащите на соответствующий вид. Это продемонстрировано ниже.

Outlets

Обратный путь также можно использовать для связи торговых точек. Удерживая Ctrl, перетащите вид на строку кода, где вы хотите добавить параметр.

Запрос разрешений

Тяжелая работа процесса распознавания выполняется на серверах Apple, за исключением некоторых более новых устройств, которые все время поддерживают распознавание речи. Поскольку аудиоданные покидают устройство, пользователь должен показать свое согласие, прежде чем услуга сможет быть использована.

Давайте добавим новую функцию в «ViewController.swift», которая использует IBAction Для этого требуется импортировать SFSpeechRecognizer

 Speech

Функция запросит у пользователя авторизацию для использования Speech Recognizer и вернет кортеж . Кортеж содержит import Speech
boolean

 string

Функция private func askMicPermission(completion: @escaping (Bool, String) -> ()) {
SFSpeechRecognizer.requestAuthorization { status in

}
}
requestAuthorization Переключите возможные значения и установите сообщение для каждого из них. Добавьте следующий код внутри тела SFSpeechRecognizerAuthorizationStatus

 requestAuthorization

Наконец, давайте назовем let message: String
var granted = false

switch status {
case .authorized:
message = "Listening..."
granted = true
break
case .denied:
message = "Access to speech recognition is denied by the user."
break
case .restricted:
message = "Speech recognition is restricted."
break
case .notDetermined:
message = "Speech recognition has not been authorized, yet."
break
}
кортежем .

 completion

Написанная нами функция будет вызываться при попытке запустить или остановить прослушивание аудиоданных. Слушатель уже на месте.

 completion(granted, message)

Если вы запустите проект в этом состоянии, он потерпит неудачу при касании представления. iOS 10 требует добавления строки описания в файл .plist для каждого запроса доступа. Эти строки должны помочь пользователю понять, зачем вам нужно разрешение или как вы собираетесь его использовать.

Откройте «Info.plist» и внутри основных тегов словаря добавьте следующий @IBAction func tappedButton() {
askMicPermission(completion: { (granted, message) in

})
}

 key

Сделайте то же самое, чтобы запросить доступ к микрофону, который нам понадобится позже.

     <key>NSSpeechRecognitionUsageDescription</key>
    <string>I need your permission to use speech recognition.</string>

На следующих скриншотах показано, как это выглядит. Обратите внимание, как Apple информирует пользователя о том, что речевые данные будут отправляться на его серверы.

Speech Recognition accessMicrophone access

Реализация API

Класс <key>NSMicrophoneUsageDescription</key>
<string>I need to hear you before I can convert your speech to text. Please allow access to the microphone.</string>
</dict>
соответствовать протоколу ViewController

 SFSpeechRecognizerDelegate

Это переменные, которые нам понадобятся. Объявите их глобально в классе class ViewController: UIViewController, SFSpeechRecognizerDelegate {

 ViewController

Инициализация private var listening = false
private var speechRecognizer: SFSpeechRecognizer?
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?

private let audioEngine = AVAudioEngine()
идентификатора локали , который я установил на албанский…

 speechRecognizer

… но это, конечно, не сработало.

Невозможно сделать распознаватель для sq-AL. Поддерживаемые идентификаторы локали:

Это должно было подчеркнуть важность уделения внимания языку и убедиться, что API поддерживает его. Измените идентификатор на «en-US».

Теперь давайте напишем функцию для выполнения реальной работы. Мы будем заполнять тело этой функции шаг за шагом.

 speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "sq-AL"))
speechRecognizer?.delegate = self

Проверьте, выполняется ли задача распознавания, и отмените ее, чтобы начать новую.

 private func startListening() {

}

Попробуйте активировать аудио сеанс .

 if recognitionTask != nil {
    recognitionTask?.cancel()
    recognitionTask = nil
}

Создайте запрос распознавания, который будет принимать в качестве входного аудиобуфера . Затем проверьте узел ввода аудио движка . Если нет входного узла , это означает, что устройство не имеет микрофона, откуда можно получить звук.

 let audioSession = AVAudioSession.sharedInstance()
do {
    try audioSession.setCategory(AVAudioSessionCategoryRecord)
    try audioSession.setMode(AVAudioSessionModeMeasurement)
    try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
} catch let error {
    noteLabel.text = "An error occurred when starting audio session. \(error.localizedDescription)"
    return
}

Затем запустите задачу распознавания . По результатам мы можем получить список возможных транскрипций. В противном случае, придерживайтесь recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

guard let inputNode = audioEngine.inputNode else {
fatalError("No input node detected")
}

guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
}
bestTranscription Обработчик завершения может вызываться много раз. Мы проверяем, закончил ли пользователь запись по значению noteLabel Если это так или произошла ошибка в процессе распознавания, звуковой движок останавливается. Задача затем устанавливается на result.isFinal

 nil

При получении звука с микрофона он добавляется в буфер в памяти. Это передается в recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

var isFinal = false

if result != nil {
self.noteLabel.text = result?.bestTranscription.formattedString
isFinal = result!.isFinal
}

if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)

self.recognitionRequest = nil
self.recognitionTask = nil

self.noteLabel.text = "Tap to listen"
}
})
recognitionRequest

 let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
    self.recognitionRequest?.append(buffer)
}

Наконец, подготовьте и запустите AVAudioEngine

 audioEngine.prepare()

do {
    try audioEngine.start()
} catch let error {
    noteLabel.text = "An error occurred starting audio engine. \(error.localizedDescription)"
}

Следующая функция — «кнопка паники», чтобы остановить все. Это полезно, когда пользователь снова нажимает на вид, приложение переходит в фоновый режим или в подобные сценарии.

 private func stopListening() {
    self.audioEngine.stop()
    self.recognitionRequest?.endAudio()
}

Давайте обновим функцию tappedButton Код выполняется в основном потоке. В зависимости от значения listening Затем, если пользователь предоставил разрешение, приложение запускает или останавливает прослушивание аудиовхода .

 DispatchQueue.main.async {
    if self.listening {
        self.listening = false
        self.microphoneImageView.image = UIImage(named: "Microphone")

        if granted {
            self.stopListening()
        }
    } else {
        self.listening = true
        self.microphoneImageView.image = UIImage(named: "Microphone Filled")
        self.noteLabel.text = message

        if granted {
            self.startListening()
        }
    }
}

Существуют разные причины, по которым распознаватель становится недоступным. Потеря подключения к Интернету или изменение разрешений в настройках — это два из них. Добавьте слушателя для обработки этого случая. Когда распознаватель становится недоступным, button Когда он снова становится доступным, button

 func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
    button.isEnabled = available
    if available {
        listening = true
        noteLabel.text = "Tap to listen"
        tappedButton()
    } else {
        noteLabel.text = "Recognition is not available."
    }
}

Время для речи

Мы наконец готовы увидеть наше приложение в действии. Симулятор не помогает в этом случае, нам нужно реальное устройство под управлением iOS 10. После запуска проекта коснитесь экрана телефона, и появится сообщение «Listening…». Немного креативности в выборе того, что сказать — это весело. Я застрял с простым приветствием.

Tap-to-listenListeningSpeech recognized

Я не использую речевые текстовые или голосовые команды ежедневно. Добавив тот факт, что я не являюсь носителем английского языка, приложение сначала немного затруднилось, чтобы дать правильный вывод. Тем не менее, чем больше вы используете его, тем лучше, и точность является приемлемой.

ограничения

Помимо преимуществ Speech API , есть и некоторые ограничения. Эти ограничения относятся к продолжительности аудио и доступности API. Для iOS 10 ограничение продолжительности звука составляет одну минуту.

Доступность устройств ограничена тем, сколько распознаваний они могут выполнять ежедневно. Это также действительно для признаний в приложении. Apple посоветовала обратиться за поддержкой, если этот предел часто достигается.

Еще одна вещь, которую стоит отметить, — это сильное влияние на разрядку аккумулятора и сетевой трафик. Так что лучше следить за длительными сессиями и использованием мобильных данных .

Лучшие практики

Чтобы обеспечить наилучшее взаимодействие с пользователем, необходимо принять во внимание некоторые моменты.

  • Первое, что я хотел бы упомянуть, это убедиться, что пользователь знает, что происходит. Взаимодействуйте с пользователем, сообщите ему, что происходит распознавание или что он записывается.
  • Использование распознавания речи для ввода пароля, номера кредитной карты или других конфиденциальных данных — плохой выбор.
  • Готовьтесь к любому сценарию. Процесс может потерпеть неудачу по многим причинам. Начиная с превышения лимита, до потери интернет-соединения, до пользователя, прерывающего операцию. Обработайте эти случаи с надлежащим сообщением.

Вывод

Речевой фреймворк — отличное дополнение к iOS 10, использующее ту же технологию, что и Siri и Dictation . Он обеспечивает результаты без необходимости сбора пользовательских данных, и его легко реализовать. Он предлагает больше контекста по результатам: информация о времени, уровень достоверности и альтернативные интерпретации.

Получайте удовольствие, используя этот API в своих приложениях!

Пусть кодекс будет с вами!

Ссылки