Проект состоит из двух частей - голосовой бот и 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 .
(подробнее тут).
ВНИМАНИЕ! Это был мой дипломный проект, по этому архитектура и код тут не очень хорошие, я это понимаю и как появится время - всё обновлю.
Полный список всех необходимых для работы зависимостей:
- Для 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].
- Для 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.
- Данные для обучения и готовые модели: необходимо вручную загрузить из 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 архива:
Install_CUDA10.0_cuDNN_for410.zip
(2.0Gb) с CUDA 10.0 и cuDNN 7.5.0 (если был передан параметрgpu
). Установка будет выполнена автоматически, но если что-то пошло не так, есть инструкцияInstall.txt
в загруженном архиве.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. Обучение на наборах данных из произведений и субтитров на данном железе будет длиться минимум нескольких суток.
Бот умеет работать в нескольких режимах:
- Обучение модели seq2seq.
- Работа с обученной моделью seq2seq в текстовом режиме.
- Работа с обученной моделью seq2seq с озвучиванием ответов с помощью RHVoice.
- Работа с обученной моделью seq2seq с распознаванием речи с помощью PocketSphinx.
- Работа с обученной моделью 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-пользователя).
Для взаимодействия с обученной моделью 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.
Это комбинация режимов 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.
Данный сервер предоставляет REST-api для взаимодействия с ботом. При старте сервера загружается нейронная сеть, обученная на наборе данных из пьес. Наборы данных из произведений и субтитров пока не поддерживаются.
Сервер реализован с помощью Flask, а многопоточный режим (production-версия) с помощью gevent.pywsgi.WSGIServer. Также сервер имеет ограничение на размер принимаемых данных в теле запроса равное 16 Мб. Реализация находится в модуле rest_server.py
.
Запустить WSGI сервер можно выполнив run_rest_server.sh
(запуск WSGI сервера на 0.0.0.0:5000
).
Сервер поддерживает аргументы командной строки, которые немного упрощают его запуск. Аргументы имеют следующую структуру: [ключ(-и)] [адрес:порт]
.
Возможные ключи:
-d
- запуск тестового Flask сервера (если ключ не указывать - будет запущен WSGI сервер)-s
- запуск сервера с поддержкой https (используется самоподписанный сертификат, получен с помощью openssl)
Допустимые варианты адрес:порт
:
host:port
- запуск на указанномhost
иport
localaddr:port
- запуск с автоопределением адреса машины в локальной сети и указаннымport
host:0
илиlocaladdr:0
- еслиport = 0
, то будет выбран любой доступный порт автоматически
Список возможных комбинаций аргументов командной строки и их описание:
- без аргументов - запуск WSGI сервера с автоопределением адреса машины в локальной сети и портом
5000
. Например:python3 rest_server.py
host:port
- запуск WSGI сервера на указанномhost
иport
. Например:python3 rest_server.py 192.168.2.102:5000
-d
- запуск тестового Flask сервера на127.0.0.1:5000
. Например:python3 rest_server.py -d
-d host:port
- запуск тестового Flask сервера на указанномhost
иport
. Например:python3 rest_server.py -d 192.168.2.102:5000
-d localaddr:port
- запуск тестового Flask сервера с автоопределением адреса машины в локальной сети и портомport
. Например:python3 rest_server.py -d localaddr:5000
-s
- запуск WSGI сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом5000
. Например:python3 rest_server.py -s
-s host:port
- запуск WSGI сервера с поддержкой https на указанномhost
иport
. Например:python3 rest_server.py -s 192.168.2.102:5000
-s -d
- запуск тестового Flask сервера с поддержкой https на127.0.0.1:5000
. Например:python3 rest_server.py -s -d
-s -d host:port
- запуск тестового Flask сервера с поддержкой https на указанномhost
иport
. Например:python3 rest_server.py -s -d 192.168.2.102:5000
-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 запросов:
- GET-запрос на
/chatbot/about
, вернёт информацию о проекте - GET-запрос на
/chatbot/questions
, вернёт список всех поддерживаемых вопросов - POST-запрос на
/chatbot/speech-to-text
, принимает .wav/.opus-файл и возвращает распознанную строку - POST-запрос на
/chatbot/text-to-speech
, принимает строку и возвращает .wav-файл с синтезированной речью - 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 (в том числе и ответы с ошибками).
- Сервер передаёт клиенту:
{
"text" : "Информация о проекте."
}
- Сервер передаёт клиенту:
{
"text" : ["Вопрос 1",
"Вопрос 2",
"Вопрос 3"]
}
- Клиент в теле запроса должен отправить:
{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}
или
{
"opus" : "ZFZm10IBUklQVZFZm10IBARLASBAAEOpH..."
}
Сервер ему передаст:
{
"text" : "который час"
}
- Клиент в теле запроса должен отправить:
{
"text" : "который час"
}
Сервер ему передаст:
{
"wav" : "UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH..."
}
- Клиент в теле запроса должен отправить:
{
"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" : "это снова я"
}
- Запросить список вопросов у сервера (запрос 2) и отобразить его
- В зависимости от выбранного режима:
- Записать речь с микрофона клиента
- Отправить на сервер (запрос 3) и получить ответ с распознанным текстом
- Отобразить текст в поле ввода
- Отправить текст на сервер (запрос 5) и получить ответ бота
- Отправить ответ бота на сервер (запрос 4) и получить аудиофайл с синтезированной речью
- Воспроизвести аудиофайл
- Если клиент хочет узнать информацию о данном проекте, послать запрос 1 на сервер и отобразить полученные данные
В проекте содержится 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.