» » » Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст

 

Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст

Автор: admin от 9-01-2018, 21:25, посмотрело: 43

Привет, хабр. Обычно я пишу программы для неговорящих людей, но решил ударится в крайности и сделать продукт для говорящих людей. Я хочу рассказать о разработке бота для VK, который переводит пересланные ему голосовые сообщения в текст. Сначала я использовал Yandex SpeechKit, но потом уперся в дневной лимит распознаваемых единиц и перешел на wit.ai, об этом и хочу рассказать, а также о фреймворке для создания ботов vk с помощью node.js, болтовне гугловского dialogflow.



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



node-vk-bot-api, ссылку на которую нашел в официальной документации ВКонтакте, хотя у того же автора есть более крутая библиотека с поддержкой webhooks botact.



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



Для работы с Google Dialogflow был взят пакет apiai.



Поскольку изначально предполагалось использовать api Яндекса, готовую библиотеку, которого я не нашел, файл для работы с голосовым api написал сам, используя модуль request-promise.



2. Разделение проекта





Комментарии в коде русские только в статье, так то я // true programmer



2.0 asr.js





В этом файле мы опишим функцию получания текста из буфера с аудиофайлом:

const fs = require('fs')
const request = require('request-promise')

const uri = `https://api.wit.ai/speech`
const apikey = '<...>' // получаем ключ доступа на wit.ai

module.exports = async (body) => {
  // отправляем post запрос с буфером аудио
  const response = await request.post({
    uri,
    headers: {
      'Accept': 'audio/x-mpeg-3',
      'Authorization': `Bearer ` + apikey,
      'Content-Type': 'audio/mpeg3',
      'Transfer-Encoding': 'chunked'
    },
    body
  })
  // парсим ответ и отдаем результат расшифровки
  return JSON.parse(response)._text
}




Вообще wit.ai — это платформа facebook'а для обработки нативной речи для создания ботов с искусственным интеллектом, которая принимает на вход текстовую или голосовую фразу на естественном языке и пробует ответить с помощью нейросетки. Я использую лишь голосовое распознавание, так сказать штырюсь от побочки.



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



Платформа не имеет никаких лимитов, кроме ограничения в виде одного запроса в секунду, и то отслеживается самой платформой и запрос просто ставится в очередь.



1. assistent.js





В этом файле мы опишем работу с платформой dialogflow, которая будет отвечать на текстовые сообщения. Почему не wit.ai? У этого две причины. Во-первых, проект развлекательно-развивающий, соответственно целью было попробовать как можно больше технологий, во-вторых изначально использовался speechkit, только после блокировки из-за дневного лимита, было принято экстренное решение перейти на wit.



Код весьма банальный:



const apiai = require('apiai');
// для каждого пользователя будем использовать уникальный идентификатор сессии, но из-за того, что нам лень поднимать дб, мы будем его генерировать из 36 битного ключа, заменяя последние символы на id пользователя
// не делайте так
const uniqid = 'e4278f61-9437-4dff-a24b-aaaaaaaaaaaa';
const app = apiai(‘<...>’);
module.exports = (q, uid) => {
  // городим свой промис, так как библиотека стремная
  return new Promise((resolve, reject) => {
    uid = uid + ''
    // don’t touch, magic
    const cuniqid = uniqid.slice(0, uniqid.length - uid.length) + uid
    // запрос
    const request = app.textRequest(q, {
      sessionId: uniqid
    })
    // удача!
    request.on('response', (response) => {
      resolve(response)
    })
    // нееееееет!
    request.on('error', (error) => {
      reject(error);
    })
    // не знаю зачем, но надо
    request.end();
  })
}




Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



В консоле dialogflow включим и настроим готовый модуль Small Talk из агентов по умолчанию.



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



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



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



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



В итоге получается такая вот беседа:



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст



2. index.js





Собираем всё это в главном файле.



const vk = require('api.vk.com')
const request = require('request-promise')
const Bot = require('node-vk-bot-api')

const asr = require('./asr')
const assistent = require('./assistent')
const token = require('./token');

// оборачиваем в промис старенький модуль для работы с api
const api = (method, options) => {
  return new Promise((resolve, reject) => {
    vk(method, options, (err, result) => {
      if (err) return reject(err)
      resolve(result)
    })
  })
}

// создаем экземпляр бота
const bot = new Bot({ token })

// вешаем событие на входящие сообщение
bot.on(async (object) => {
  // для простоты создадим один catcher ошибок, и при появлении онных будем отвечать пользователю о неудаче
  try {
    //асинхронно помечаем прочитанность и устанавливаем статус печатанья
    api('messages.setActivity', { access_token: token, type: 'typing', user_id: object.user_id })
    api('messages.markAsRead', { access_token: token, message_ids: object.message_id })
    
//переменная, в которую попадет uri аудиосообщения
    let uri

    // проверяем наличие прикрепленных сущностей 
    if (object.attachments.length != 0) {
      // получаем подробную информацию о сообщении
      const [msg] = (await api('messages.getById', { access_token: token, message_ids: object.message_id, v: 5.67 })).items
      // проверяем, прикреплена ли вообще аудио запись
      if (msg.attachments[0].type != 'audio' || msg.attachments[0].type != 'doc' || msg.attachments[0].doc.type != 5) {
        uri = null
      }
      // выковырываем uri
      try {
        if (msg.attachments[0].type === 'doc') uri = msg.attachments[0].doc.preview.audio_msg.link_mp3
        else if (msg.attachments[0].type === 'audio') uri = msg.attachments[0].audio.url
      } catch (e) {
        uri = null
      }

      // обрабатываем пересланное голосовое сообщение
    } else if (object.forward != null) {
      try {
        uri = object.forward.attachments[0].doc.preview.audio_msg.link_mp3
      }
      catch (e) {
        uri = null
      }
    } else {
      uri = null
    }
    // ошибка авторских прав на аудиозапись
    if (uri === '') {
      throw ('Не могу послушать это аудио')
    }
    if (uri == null) {
      // если есть текстовое cообщение, отправляем в dialogflow
      if (object.body != '') {
        const { speech } = (await assistent(object.body, object.user_id)).result.fulfillment
        object.reply(speech)
        return
      }
      else {
        throw ('Мы не нашли голосовых сообщений. Отправь нам свой голос или перешли его')
      }
    }
    // получаем буфер с аудио
    const audio = await request.get({ uri, encoding: null })
    let phrase
    try {
      phrase = await asr(audio)
    }
    catch (e) {
      console.error('asr error', e)
      throw ('сбой в распознавании речи')
    }
    // отправляем результат
    if (phrase != null) {
      object.reply(phrase, (err, mesid) => { });
    } else {
      throw ('Не удалось распознать')
    }
  } catch (error) {
    // логируем ошибку и отвечаем пользователю
    console.error(error)
    object.reply('string' == typeof error ? error : 'Произошла непонятная ошибка. Я не знаю, что делать!')
  }
})

// не забываем про главное, включаем long pong.
bot.listen()




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



Результат:



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



Безлимитное распознавание речи. Или как я перевожу в боте голосовые сообщения в текст

Источник: Хабрахабр

Категория: Facebook, Google

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *