Skip to content

Chatbot in russian with speech recognition using PocketSphinx and speech synthesis using RHVoice. The AttentionSeq2Seq model is used. Imlemented using Python3+TensorFlow+Keras.

License

Notifications You must be signed in to change notification settings

dbklim/Voice_ChatBot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Voice ChatBot

Проект состоит из двух частей - голосовой бот и RESTful сервер для взаимодействия с ним.

Для запуска бота локально нужно выполнить python3 bot.py (или run_bot.sh) и в предложенном меню выбрать желаемый вариант работы (подробнее тут).

Для запуска RESTful сервера, предоставляющего интерфейс для взаимодействия с модулями голосового бота, нужно выполнить python3 rest_server.py (или run_rest_server.sh) (подробнее тут).

Для сборки docker-образа на основе RESTful сервера выполните sudo docker build -t voice_chatbot:0.1 . (подробнее тут).

ВНИМАНИЕ! Это был мой дипломный проект, по этому архитектура и код тут не очень хорошие, я это понимаю и как появится время - всё обновлю.

Зависимости

Полный список всех необходимых для работы зависимостей:

  1. Для Python3.5-3.6: decorator, Flask (>=1.0.2), Flask-HTTPAuth (>=3.2.4), gensim, gevent (>=1.3.7), h5py, Keras (>=2.2.4), matplotlib, numpy, pocketsphinx, pydub, simpleaudio, recurrentshop, requests, seq2seq, tensorflow[-gpu].
  2. Для Ubuntu: ffmpeg, x264, x265, make, git, scons, gcc, pkg-config, pulseaudio, libpulse-dev, portaudio19-dev, libglibmm-2.4-dev, libasound-dev, libao4, libao-dev, sonic, sox, swig, flite1-dev, net-tools, zip, unzip.
  3. Данные для обучения и готовые модели: необходимо вручную загрузить из Google Drive архив Voice_ChatBot_data.zip(3Gb) и распаковать в корень проекта (папки data и install_files).

Если вы используете Ubuntu 16.04 или выше, для установки всех пакетов можно воспользоваться install_packages.sh (проверено в Ubuntu 16.04 и 18.04). По умолчанию будет установлен TensorFlow для CPU. Если у вас есть видеокарта nvidia с утановленным официальным драйвером версии 410, вы можете установить TensorFlowGPU. Для этого необходимо при запуске install_packages.sh передать параметр gpu. Например:

./install_packages.sh gpu

В этом случае из моего Google Drive будет загружено 2 архива:

  1. Install_CUDA10.0_cuDNN_for410.zip(2.0Gb) с CUDA 10.0 и cuDNN 7.5.0 (если был передан параметр gpu). Установка будет выполнена автоматически, но если что-то пошло не так, есть инструкция Install.txt в загруженном архиве.
  2. Voice_ChatBot_data.zip(3Gb) с данными для обучения и готовыми моделями. Он будет автоматически распакован в папки data и install_files в корне проекта.

Если вы не можете или не хотите воспользоваться скриптом для установки всех необходимых пакетов, нужно вручную установить RHVoice и CMUclmtk_v0.7, используя инструкции в install_files/Install RHVoice.txt и install_files/Install CMUclmtk.txt. Так же необходимо скопировать файлы языковой, акустической модели и словаря для PocketSphinx из temp/ в /usr/local/lib/python3.6/dist-packages/pocketsphinx/model (у вас путь к python3.6 может отличаться). Файлы языковой модели prepared_questions_plays_ru.lm и словаря prepared_questions_plays_ru.dic необходимо переименовать в ru_bot_plays_ru.lm и ru_bot_plays_ru.dic (либо изменить их название в speech_to_text.py, если у вас есть своя языковая модель и словарь).

Бот

Основа бота - рекуррентная нейронная сеть, модель AttentionSeq2Seq. В текущей реализации она состоит из 2 двунаправленных LSTM ячеек в кодировщике, слоя внимания и 2 LSTM ячеек в декодировщике. Использование модели внимания позволяет установить "мягкое" соответствие между входными и выходными последовательностями, что повышает качество и производительность. Размерность входа в последней конфигурации равна 500 и длина последовательности 26 (т.е. максимальная длина предложений в обучающей выборке). Слова переводятся в вектора с помощью кодировщика word2vec (со словарём на 445.000 слов) из бибилотеки gensim. Модель seq2seq реализована с помощью Keras и RecurrentShop. Обученная модель seq2seq (веса которой находятся в data/plays_ru/model_weights_plays_ru.h5) с параметрами, которые указаны в исходных файлах, имеет точность 99.19% (т.е. бот ответит на 1577 из 1601 вопросов правильно).

На данный момент предусмотрено 3 набора данных для обучения бота: 1601 пара вопрос-ответ из различных пьес (data/plays_ru), 136.000 пар из различных произведений (data/conversations_ru, спасибо NLP Datasets) и 2.500.000 пар из субтитров к 347 сериалам (data/subtitles_ru, подробнее в Russian subtitles dataset). Модели word2vec обучены для всех наборов данных, но нейронная сеть обучена только на наборе данных из пьес.

Обучение модели word2vec и нейронной сети на наборе данных из пьес без изменения параметров длится примерно 7.5 часов на nvidia gtx1070 и intel core i7. Обучение на наборах данных из произведений и субтитров на данном железе будет длиться минимум нескольких суток.

Бот умеет работать в нескольких режимах:

  1. Обучение модели seq2seq.
  2. Работа с обученной моделью seq2seq в текстовом режиме.
  3. Работа с обученной моделью seq2seq с озвучиванием ответов с помощью RHVoice.
  4. Работа с обученной моделью seq2seq с распознаванием речи с помощью PocketSphinx.
  5. Работа с обученной моделью seq2seq с озвучиванием ответов и распознаванием речи.

1. Обучение модели seq2seq

Обучающая выборка состоит из 1600 пар вопрос %% ответ, взятых из различных русских пьес. Она хранится в файле data/plays_ru/plays_ru.txt. Каждая пара вопрос %% ответ пишется с новой строки, т.е. на одной строке только одна пара.

Все необходимые для обучения этапы выполняются методами prepare() или load_prepared() и train() класса TextToText из модуля text_to_text.py и метод build_language_model() класса LanguageModel из модуля preparing_speech_to_text.py. Или можно использовать функцию train() модуля bot.py.

Для запуска бота в режиме обучения нужно запустить bot.py с параметром train. Например, так:

python3 bot.py train

Или можно просто запустить bot.py (или выполнить run_bot.sh) и в предложенном меню выбрать режим 1 и 1.

Процесс обучения состоит из нескольких этапов:

1. Подготовка обучающей выборки.

Для подготовки обучающей выборки предназначен модуль source_to_prepared.py, состоящий из класса SourceToPrepared. Данный класс считывает обучающую выборку из файла, разделяет вопросы и ответы, удаляет неподдерживаемые символы и знаки препинания, преобразует полученные вопросы и ответы в последовательности фиксированного размера (с помощью слов-наполнителей <PAD>). Так же этот класс осуществляет подготовку вопросов к сети и обработку её ответов. Например:

Вход: "Зачем нужен этот класс? %% Для подготовки данных"

Выход: [['<PAD>', ..., '<PAD>', '?', 'класс', 'этот', 'нужен', 'Зачем', '<GO>'], ['Для', 'подготовки', 'данных', '<EOS>', '<PAD>', ..., '<PAD>']]

Обучающая выборка считывается из файла data/plays_ru/plays_ru.txt, преобразованные пары [вопрос,ответ] сохраняются в файл data/plays_ru/prepared_plays_ru.pkl. Так же при этом строится гистограмма размеров вопросов и ответов, которая сохраняется в data/plays_ru/histogram_of_sizes_sentences_plays_ru.png.

Для подготовки обучающей выборки из набора данных на основе пьес достаточно передать методу prepare_all() имя соответствующего файла. Что бы подготовить обучающую выборку из набора данных на основе произведений или субтитров, нужно вначале вызвать combine_conversations() или combine_subtitles(), а после вызывать preapre_all().

2. Перевод слов в вещественные вектора.

За этот этап отвечает модуль word_to_vec.py, состоящий из класса WordToVec. Данный класс кодирует последовательности фиксированного размера (т.е. наши вопросы и ответы) в вещественные вектора. Использутся кодировщик word2vec из библиотеки gensim. В классе реализованы методы для кодирования сразу всех пар [вопрос,ответ] из обучающей выборки в вектора, а так же для кодирования вопроса к сети и декодирования её ответа. Например:

Вход: [['<PAD>', ..., '<PAD>', '?', 'класс', 'этот', 'нужен', 'Зачем', '<GO>'], ['Для', 'кодирования', 'предложений', '<EOS>', '<PAD>', ..., '<PAD>']]

Выход: [[[0.43271607, 0.52814275, 0.6504923, ...], [0.43271607, 0.52814275, 0.6504923, ...], ...], [[0.5464854, 1.01612, 0.15063584, ...], [0.88263285, 0.62758327, 0.6659863, ...], ...]] (т.е. каждое слово кодируется вектором с длинной 500 (это значение можно изменить, аргумент size в методе build_word2vec()))

Пары [вопрос,ответ] считываются из файла data/plays_ru/prepared_plays_ru.pkl (который был получен на предыдущем этапе, для расширения и повышения качества модели рекомендуется дополнительно передать методу build_word2vec() предобработанный набор данных из субтитров data/subtitles_ru/prepared_subtitles_ru.pkl), закодированные пары сохраняются в файл data/plays_ru/encoded_plays_ru.npz. Так же в процессе работы строится список всех используемых слов, т.е. словарь, который сохраняется в файле data/plays_ru/w2v_vocabulary_plays_ru.txt. Также сохраняется обученная модель word2vec в data/plays_ru/w2v_model_plays_ru.bin.

Для перевода слов из обучающей выборки в вектора достаточно передать методу build_word2vec() имя соответствующего файла и задать желаемые параметры.

3. Обучение сети.

На этом этапе выполняется обучение модели seq2seq на уже подготовленных ранее данных. За это отвечает модуль text_to_text.py, состоящий из класса TextToText. Данный класс осуществляет обучение сети, сохранение модели сети и весовых коэффициентов, и позволяет удобно взаимодействовать с обученной моделью.

Для обучение необходим файл data/plays_ru/encoded_plays_ru.npz, содержащий пары [вопрос,ответ], закодированные в вектора, которые были получены на предыдущем этапе. В процессе обучения после каждой 5-ой эпохи (это значение можно изменить) сохраняется крайний промежуточный результат обучения сети в файл data/plays_ru/model_weights_plays_ru_[номер_итерации].h5, а на последней итерации в файл data/plays_ru/model_weights_plays_ru.h5 (итерация - один цикл обучения сети, некоторое число эпох, после которых происходит сохранение весов в файл и можно например оценить точность работы сети или вывести другие её параметры. По умолчанию число эпох равно 5, а общее число итераций 200). Модель сети сохраняется в файле data/plays_ru/model_plays_ru.json.

После обучения сети выполняется оценка качества обучения путём подачи на вход обученной сети всех вопросов и сравнения ответов сети с эталонными ответами из обучающей выборки. Если точность оцениваемой модели получается выше 75%, то неправильные ответы сети сохраняются в файл data/plays_ru/wrong_answers_plays_ru.txt (что бы их можно было потом проанализировать).

Для обучения сети достаточно передать методу train() имя соответствующего файла и задать желаемые параметры.

4. Построение языковой модели и словаря для PocketSphinx.

Этот этап нужен в случае, если будет использоваться распознавание речи. На этом этапе осуществляется создание статической языковой модели и фонетического словаря для PocketSphinx на основе вопросов из обучающей выборки (осторожно: чем больше вопросов в обучающей выборке, тем дольше PocketSphinx будет распознавать речь). Для этого используется метод build_language_model() (которая обращается к text2wfreq, wfreq2vocab, text2idngram и idngram2lm из CMUclmtk_v0.7) класса LanguageModel из модуля preparing_speech_to_text.py. Данный метод использует вопросы из файла с исходной обучающей выборкой (до их подготовки модулем source_to_prepared.py), сохраняет языковую модель в файл temp/prepared_questions_plays_ru.lm, а словарь в temp/prepared_questions_plays_ru.dic (plays_ru может меняться, в зависимости от того, какая обучающая выборка была использована). В конце работы языковая модель и словарь будут скопированы в /usr/local/lib/python3.х/dist-packages/pocketsphinx/model с именами ru_bot_plays_ru.lm и ru_bot_plays_ru.dic (plays_ru может меняться так же, как и на предыдущем этапе, потребуется ввод пароля root-пользователя).


2. Работа с обученной моделью seq2seq в текстовом режиме

Для взаимодействия с обученной моделью seq2seq предназначена функция predict() (которая является обёрткой над методом predict() класса TextToText из модуля text_to_text.py) модуля bot.py. Данная функция поддерживает несколько режимов работы. В текстовом режиме, т.е. когда пользователь вводит вопрос с клавиатуры и сеть отвечает текстом, используется только метод predict() класса TextToText из модуля text_to_text.py. Данный метод принимает строку с вопросом к сети и возвращает строку с ответом сети. Для работы необходимы: файл data/plays_ru/w2v_model_plays_ru.bin с обученной моделью word2vec, файл data/plays_ru/model_plays_ru.json с параметрами модели сети и файл data/plays_ru/model_weights_plays_ru.h5 с весами обученной сети.

Для запуска бота в данном режиме нужно запустить bot.py с параметром predict. Например, так:

python3 bot.py predict

Так же можно просто запустить bot.py (или выполнить run_bot.sh) и в предложенном меню выбрать режим 2 и 1.


3. Работа с обученной моделью seq2seq с озвучиванием ответов с помощью RHVoice

Данный режим отличается от предыдущего тем, что функции predict() модуля bot.py передаётся параметр speech_synthesis = True. Это означает, что взаимодействие с сетью будет проходить так же, как и в режиме 2, но ответ сети дополнительно будет озвучиваться.

Озвучивание ответов, т.е. синтез речи, реализован в методе get() класса TextToSpeech из модуля text_to_speech.py. Данный класс требует установленного RHVoice-client и с помощью аргументов командной строки передаёт ему необходимые параметры для синтеза речи (об установке RHVoice и примеры обращения к RHVoice-client можно посмотреть в install_files/Install RHVoice.txt). Метод get() принимает на вход строку, которую нужно преобразовать в речь, и, если требуется, имя .wav файла, в который будет сохранена синтезированная речь (с частотой дискретизации 32 кГц и глубиной 16 бит, моно; если его не указывать - речь будет воспроизводиться сразу после синтеза). При создании объекта класса TextToSpeech можно указать имя используемого голоса. Поддерживается 4 голоса: мужской Aleksandr и три женских - Anna, Elena и Irina (подробнее в RHVoice Wiki).

Для запуска бота в данном режиме нужно запустить bot.py с параметрами predict -ss. Например, так:

python3 bot.py predict -ss

Так же можно просто запустить bot.py (или выполнить run_bot.sh) и в предложенном меню выбрать режим 3 и 1.


4. Работа с обученной моделью seq2seq с распознаванием речи с помощью PocketSphinx

Для работы в этом режиме необходимо функции predict() модуля bot.py передать параметр speech_recognition = True. Это означает, что взаимодействие с сетью, а точнее ввод вопросов, будет осуществляться с помощью голоса.

Распознавание речи реализовано в методе get() класса SpeechToText модуля speech_to_text.py. Данный класс использует PocketSphinx и языковую модель со словарём (ru_bot_plays_ru.lm и ru_bot_plays_ru.dic), которые были построены в режиме обучения сети. Метод get() может работать в двух режимах: from_file - распознавание речи из .wav или .opus файла с частотой дискретизации >=16кГц, 16bit, моно (имя файла передаётся в качестве аргумента функции) и from_microphone - распознавание речи с микрофона. Режим работы задаётся при создании экземпляра класса SpeechRecognition, т.к. загрузка языковой модели занимает некоторое время (чем больше модель, тем дольше она загружается).

Для запуска бота в данном режиме нужно запустить bot.py с параметрами predict -sr. Например, так:

python3 bot.py predict -sr

Так же можно просто запустить bot.py (или выполнить run_bot.sh) и в предложенном меню выбрать режим 4 и 1.


5. Работа с обученной моделью seq2seq с озвучиванием ответов и распознаванием речи

Это комбинация режимов 3 и 4.

Для работы в этом режиме необходимо функции predict() модуля bot.py передать параметры speech_recognition = True и speech_synthesis = True. Это означает, что ввод вопросов будет осуществляться с помощью голоса, а ответы сети будут озвучиваться. Описание используемых модулей можно найти в описании режимов 3 и 4.

Для запуска бота в данном режиме нужно запустить bot.py с параметрами predict -ss -sr. Например, так:

python3 bot.py predict -sr -ss

или

python3 bot.py predict -ss -sr

Так же можно просто запустить bot.py (или выполнить run_bot.sh) и в предложенном меню выбрать режим 5 и 1.

RESTful сервер

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

Сервер реализован с помощью Flask, а многопоточный режим (production-версия) с помощью gevent.pywsgi.WSGIServer. Также сервер имеет ограничение на размер принимаемых данных в теле запроса равное 16 Мб. Реализация находится в модуле rest_server.py.

Запустить WSGI сервер можно выполнив run_rest_server.sh (запуск WSGI сервера на 0.0.0.0:5000).

Сервер поддерживает аргументы командной строки, которые немного упрощают его запуск. Аргументы имеют следующую структуру: [ключ(-и)] [адрес:порт].

Возможные ключи:

  1. -d - запуск тестового Flask сервера (если ключ не указывать - будет запущен WSGI сервер)
  2. -s - запуск сервера с поддержкой https (используется самоподписанный сертификат, получен с помощью openssl)

Допустимые варианты адрес:порт:

  1. host:port - запуск на указанном host и port
  2. localaddr:port - запуск с автоопределением адреса машины в локальной сети и указанным port
  3. host:0 или localaddr:0 - если port = 0, то будет выбран любой доступный порт автоматически

Список возможных комбинаций аргументов командной строки и их описание:

  1. без аргументов - запуск WSGI сервера с автоопределением адреса машины в локальной сети и портом 5000. Например: python3 rest_server.py
  2. host:port - запуск WSGI сервера на указанном host и port. Например: python3 rest_server.py 192.168.2.102:5000
  3. -d - запуск тестового Flask сервера на 127.0.0.1:5000. Например: python3 rest_server.py -d
  4. -d host:port - запуск тестового Flask сервера на указанном host и port. Например: python3 rest_server.py -d 192.168.2.102:5000
  5. -d localaddr:port - запуск тестового Flask сервера с автоопределением адреса машины в локальной сети и портом port. Например: python3 rest_server.py -d localaddr:5000
  6. -s - запуск WSGI сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом 5000. Например: python3 rest_server.py -s
  7. -s host:port - запуск WSGI сервера с поддержкой https на указанном host и port. Например: python3 rest_server.py -s 192.168.2.102:5000
  8. -s -d - запуск тестового Flask сервера с поддержкой https на 127.0.0.1:5000. Например: python3 rest_server.py -s -d
  9. -s -d host:port - запуск тестового Flask сервера с поддержкой https на указанном host и port. Например: python3 rest_server.py -s -d 192.168.2.102:5000
  10. -s -d localaddr:port - запуск тестового Flask сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом port. Например: python3 rest_server.py -s -d localaddr:5000

Сервер может сам выбрать доступный порт, для этого нужно указать в host:port или localaddr:port порт 0 (например: python3 rest_server.py -d localaddr:0).

Всего поддерживается 5 запросов:

  1. GET-запрос на /chatbot/about, вернёт информацию о проекте
  2. GET-запрос на /chatbot/questions, вернёт список всех поддерживаемых вопросов
  3. POST-запрос на /chatbot/speech-to-text, принимает .wav/.opus-файл и возвращает распознанную строку
  4. POST-запрос на /chatbot/text-to-speech, принимает строку и возвращает .wav-файл с синтезированной речью
  5. POST-запрос на /chatbot/text-to-text, принимает строку и возвращает ответ бота в виде строки

Описание сервера

1. Сервер имеет базовую http-авторизацию. Т.е. для получения доступа к серверу надо в каждом запросе добавить заголовок, содержащий логин:пароль, закодированный с помощью base64 (логин: bot, пароль: test_bot). Пример на python:

import requests
import base64

auth = base64.b64encode('testbot:test'.encode())
headers = {'Authorization' : "Basic " + auth.decode()}

Выглядеть это будет так:

Authorization: Basic dGVzdGJvdDp0ZXN0

2. В запросе на распознавание речи (который под номером 3) сервер ожидает .wav или .opus файл (>=16кГц 16бит моно) с записанной речью, который так же передаётся в json с помощью кодировки base64 (т.е. открывается .wav/.opus-файл, читается в массив байт, потом кодирутеся base64, полученный массив декодируется из байтовой формы в строку utf-8 и помещается в json), в python это выглядит так:

# Формирование запроса
auth = base64.b64encode('testbot:test'.encode())
headers = {'Authorization' : "Basic " + auth.decode()}

with open('test.wav', 'rb') as audio:
    data = audio.read()
data = base64.b64encode(data)
data = {'wav' : data.decode()}

# Отправка запроса серверу
r = requests.post('http://' + addr + '/chatbot/speech-to-text', headers=headers, json=data)

# Разбор ответа
data = r.json()
data = data.get('text')
print(data)

3. В запросе на синтез речи (который под номером 4) сервер пришлёт в ответе json с .wav-файлом (16бит 32кГц моно) с синтезированной речью, который был закодирован так, как описано выше (что бы обратно его декодировать нужно из json получить нужную строку в массив байт, потом декодировать его с помощью base64 и записать в файл или поток, что бы потом воспроизвести), пример на python:

# Формирование запроса
auth = base64.b64encode('testbot:test'.encode())
headers = {'Authorization' : "Basic " + auth.decode()}
data = {'text':'который час'}

# Отправка запроса серверу
r = requests.post('http://' + addr + '/chatbot/text-to-speech', headers=headers, json=data)

# Разбор ответа
data = r.json()
data = base64.b64decode(data.get('wav'))
with open('/home/vladislav/Проекты/Voice chat bot/temp/answer.wav', 'wb') as audio:
    audio.write(data)

Передаваемые данные в каждом запросе

Все передаваемые данные обёрнуты в json (в том числе и ответы с ошибками).

  1. Сервер передаёт клиенту:
{
"text" : "Информация о проекте."
}
  1. Сервер передаёт клиенту:
{
"text" : ["Вопрос 1",
          "Вопрос 2",
          "Вопрос 3"]
}
  1. Клиент в теле запроса должен отправить:
{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}

или

{
"opus" : "ZFZm10IBUklQVZFZm10IBARLASBAAEOpH..."
}

Сервер ему передаст:

{
"text" : "который час"
}
  1. Клиент в теле запроса должен отправить:
{
"text" : "который час"
}

Сервер ему передаст:

{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}
  1. Клиент в теле запроса должен отправить:
{
"text" : "прощай"
}

Сервер ему передаст:

{
"text" : "это снова я"
}

Примеры запросов

1. GET-запрос на /chatbot/about

Пример запроса, который формирует python-requests:

GET /chatbot/about HTTP/1.1
Host: 192.168.2.83:5000
Connection: keep-alive
Accept-Encoding: gzip, deflate
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: python-requests/2.9.1

Пример запроса, который формирует curl (curl -v -u testbot:test -i http://192.168.2.83:5000/chatbot/about):

GET /chatbot/about HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 305
Date: Fri, 02 Nov 2018 15:13:21 GMT

{
"text" : "Информация о проекте."
}

2. GET-запрос на /chatbot/questions

Пример запроса, который формирует python-requests:

GET /chatbot/questions HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: python-requests/2.9.1
Connection: keep-alive
Accept-Encoding: gzip, deflate

Пример запроса, который формирует curl (curl -v -u testbot:test -i http://192.168.2.83:5000/chatbot/questions):

GET /chatbot/questions HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1086
Date: Fri, 02 Nov 2018 15:43:06 GMT

{
"text" : ["Что случилось?",
          "Срочно нужна твоя помощь.",
          "Ты уезжаешь?",
          ...]
}

3. POST-запрос на /chatbot/speech-to-text

Пример запроса, который формирует python-requests:

POST /chatbot/speech-to-text HTTP/1.1
Host: 192.168.2.83:5000
User-Agent: python-requests/2.9.1
Accept: */*
Content-Length: 10739
Connection: keep-alive
Content-Type: application/json
Authorization: Basic dGVzdGJvdDp0ZXN0
Accept-Encoding: gzip, deflate

{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}

Пример запроса, который формирует curl (curl -v -u testbot:test -i -H "Content-Type: application/json" -X POST -d '{"wav":"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."}' http://192.168.2.83:5000/chatbot/speech-to-text):

POST /chatbot/speech-to-text HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0
Accept: */*
Content-Type: application/json
Content-Length: 10739

{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}

Сервер ответил:

HTTP/1.1 200 OK
Content-Length: 81
Date: Fri, 02 Nov 2018 15:57:13 GMT
Content-Type: application/json

{
"text" : "Распознные слова из аудиозаписи"
}

4. POST-запрос на /chatbot/text-to-speech

Пример запроса, который формирует python-requests:

POST /chatbot/text-to-speech HTTP/1.1
Host: 192.168.2.83:5000
Connection: keep-alive
Accept: */*
User-Agent: python-requests/2.9.1
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 73
Authorization: Basic dGVzdGJvdDp0ZXN0

{
"text" : "который час"
}

Пример запроса, который формирует curl (curl -v -u testbot:test -i -H "Content-Type: application/json" -X POST -d '{"text":"который час"}' http://192.168.2.83:5000/chatbot/text-to-speech):

POST /chatbot/text-to-speech HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0
Accept: */*
Content-Type: application/json
Content-Length: 32

{
"text" : "который час"
}

Сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 78151
Date: Fri, 02 Nov 2018 16:36:02 GMT

{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}

5. POST-запрос на /chatbot/text-to-text

Пример запроса, который формирует python-requests:

POST /chatbot/text-to-text HTTP/1.1
Host: 192.168.2.83:5000
Accept-Encoding: gzip, deflate
Content-Type: application/json
User-Agent: python-requests/2.9.1
Connection: keep-alive
Content-Length: 48
Accept: */*
Authorization: Basic dGVzdGJvdDp0ZXN0

{
"text" : "прощай"
}

Пример запроса, который формирует curl (curl -v -u testbot:test -i -H "Content-Type: application/json" -X POST -d '{"text":"прощай"}' http://192.168.2.83:5000/chatbot/text-to-text):

POST /chatbot/text-to-text HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0
Accept: */*
Content-Type: application/json
Content-Length: 23

{
"text" : "прощай"
}

Сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 68
Date: Fri, 02 Nov 2018 16:41:22 GMT

{
"text" : "это снова я"
}

Предполагаемый алгоритм работы с сервером

  1. Запросить список вопросов у сервера (запрос 2) и отобразить его
  2. В зависимости от выбранного режима:
  • Записать речь с микрофона клиента
  • Отправить на сервер (запрос 3) и получить ответ с распознанным текстом
  • Отобразить текст в поле ввода
  • Отправить текст на сервер (запрос 5) и получить ответ бота
  • Отправить ответ бота на сервер (запрос 4) и получить аудиофайл с синтезированной речью
  • Воспроизвести аудиофайл
  1. Если клиент хочет узнать информацию о данном проекте, послать запрос 1 на сервер и отобразить полученные данные

Docker-образ с RESTful сервером

В проекте содержится Dockerfile, который позволяет собрать docker образ на основе данного проекта. Если для установки всех зависимостей вы использовали install_packages.sh и ранее Docker вы не устанавливали, вам необходимо установить его вручную. Например, так (проверено в Ubuntu 16.04-18.04):

sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main' -y
sudo apt-get -y update
sudo apt-get install -y docker-engine

После установки выполните sudo systemctl status docker что бы убедиться, что всё установилось и работает (в выводе данной команды вы найдёте строку с зелёным текстом active (running)).

Для сборки образа необходимо перейти в терминале в папку с проектом и выполнить (-t — запуск терминала, . — директория, из которой вызывается docker build (точка — значит в текущей директории находятся все файлы для образа), voice_chatbot:0.1 — метка образа и его версия):

sudo docker build -t voice_chatbot:0.1 .

После успешного выполнения данной операции вы можете вывести список имеющихся образов, выполнив:

sudo docker images

В полученном списке вы увидите наш образ — voice_chatbot:0.1.

Теперь вы можете запустить этот образ (-t — запуск терминала, -i — интерактивный режим, --rm — удалить контейнер после завершения его работы, -p 5000:5000 — пробросить все подключения на порт 5000 к машине-хосту в контейнер на порт 5000 (вы так же можете явно указать другой адрес, к которому нужно будет подключиться извне, например: -p 127.0.0.1:5000:5000)):

sudo docker run -ti --rm -p 5000:5000 voice_chatbot:0.1

В результате запустится RESTful сервер на 0.0.0.0:5000 и можно к нему обращаться по указанному в терминале адресу (если вы не указали другой при запуске образа).

Примечание: собранный docker-образ весит 5.2Гб. Исходные файлы проекта так же включают файл .dockerignore, в котором находятся имена файлов, которые не нужно добавлять в образ. Для минимизации размера итогового образа, из него были исключены все файлы, относящиеся к наборку данных из рассказов и из субтитров, файлы с промежуточными результатами обработки данных и обучения нейронной сети. Это значит, что образ содержит только файлы обученной сети и сырые исходные наборы данных.

На всякий случай, в исходных файлах проекта есть файл command_for_docker.txt, содержащий минимально необходимый набор команд для работы с docker.


Если у вас возникнут вопросы или вы хотите сотрудничать, можете написать мне на почту: vladsklim@gmail.com или в LinkedIn.