{"id":19704252,"url":"https://github.com/dbklim/voice_chatbot","last_synced_at":"2025-04-29T14:31:16.219Z","repository":{"id":115096296,"uuid":"153155594","full_name":"dbklim/Voice_ChatBot","owner":"dbklim","description":"Chatbot in russian with speech recognition using PocketSphinx and speech synthesis using RHVoice. The AttentionSeq2Seq model is used. Imlemented using Python3+TensorFlow+Keras.","archived":false,"fork":false,"pushed_at":"2019-11-05T13:30:58.000Z","size":379514,"stargazers_count":60,"open_issues_count":2,"forks_count":17,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-14T20:41:10.465Z","etag":null,"topics":["attention-model","bot","chatbot","flask","gensim","keras","lstm","natural-language-processing","nlp","pocketsphinx","restful-api","rhvoice","russian","seq2seq","speech-recognition","speech-synthesis","tensorflow","text-processing","word2vec"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dbklim.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-15T17:38:27.000Z","updated_at":"2024-06-11T21:24:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"86451eac-c80c-4391-bffd-530a1b25d3c4","html_url":"https://github.com/dbklim/Voice_ChatBot","commit_stats":null,"previous_names":["dbklim/voice_chatbot","desklop/voice_chatbot"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FVoice_ChatBot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FVoice_ChatBot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FVoice_ChatBot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FVoice_ChatBot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dbklim","download_url":"https://codeload.github.com/dbklim/Voice_ChatBot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251518984,"owners_count":21602245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attention-model","bot","chatbot","flask","gensim","keras","lstm","natural-language-processing","nlp","pocketsphinx","restful-api","rhvoice","russian","seq2seq","speech-recognition","speech-synthesis","tensorflow","text-processing","word2vec"],"created_at":"2024-11-11T21:21:34.966Z","updated_at":"2025-04-29T14:31:11.181Z","avatar_url":"https://github.com/dbklim.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Voice ChatBot\n\nПроект состоит из двух частей - голосовой бот и RESTful сервер для взаимодействия с ним.\n\nДля запуска бота локально нужно выполнить `python3 bot.py` (или `run_bot.sh`) и в предложенном меню выбрать желаемый вариант работы ([подробнее тут](https://github.com/Desklop/Voice_ChatBot#бот)).\n\nДля запуска RESTful сервера, предоставляющего интерфейс для взаимодействия с модулями голосового бота, нужно выполнить `python3 rest_server.py` (или `run_rest_server.sh`) ([подробнее тут](https://github.com/Desklop/Voice_ChatBot#restful-сервер)).\n\nДля сборки docker-образа на основе RESTful сервера выполните `sudo docker build -t voice_chatbot:0.1 .` ([подробнее тут](https://github.com/Desklop/Voice_ChatBot#docker-образ-с-restful-сервером)).\n\n**ВНИМАНИЕ!** Это был мой дипломный проект, по этому архитектура и код тут не очень хорошие, я это понимаю и как появится время - всё обновлю.\n\n## Зависимости\n\nПолный список всех необходимых для работы зависимостей:\n1. Для Python3.5-3.6: decorator, Flask (\u003e=1.0.2), Flask-HTTPAuth (\u003e=3.2.4), gensim, gevent (\u003e=1.3.7), h5py, Keras (\u003e=2.2.4), matplotlib, numpy, pocketsphinx, pydub, simpleaudio, [recurrentshop](https://github.com/datalogai/recurrentshop), requests, [seq2seq](https://github.com/Desklop/seq2seq), tensorflow[-gpu].\n2. Для 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.\n3. Данные для обучения и готовые модели: необходимо вручную загрузить из Google Drive архив [`Voice_ChatBot_data.zip`(3Gb)](https://drive.google.com/uc?export=download\u0026id=1_hUmsu1d2bigS2Lpkm0VRNiL7GFF_AvE) и распаковать в корень проекта (папки `data` и `install_files`).\n\nЕсли вы используете Ubuntu 16.04 или выше, для установки всех пакетов можно воспользоваться `install_packages.sh` (проверено в Ubuntu 16.04 и 18.04). По умолчанию будет установлен [TensorFlow](https://www.tensorflow.org/install/) для CPU. Если у вас есть видеокарта nvidia с утановленным официальным драйвером версии 410, вы можете установить [TensorFlowGPU](https://www.tensorflow.org/install/gpu). Для этого необходимо при запуске `install_packages.sh` передать параметр `gpu`. Например:\n```\n./install_packages.sh gpu\n```\nВ этом случае из моего Google Drive будет загружено 2 архива:\n1. [`Install_CUDA10.0_cuDNN_for410.zip`(2.0Gb)](https://drive.google.com/uc?export=download\u0026id=19kFTwkF7BOXmu1mYBTfOMoxhWDXfOytS) с CUDA 10.0 и cuDNN 7.5.0 (если был передан параметр `gpu`). Установка будет выполнена автоматически, но если что-то пошло не так, есть инструкция `Install.txt` в загруженном архиве.\n2. [`Voice_ChatBot_data.zip`(3Gb)](https://drive.google.com/uc?export=download\u0026id=1_hUmsu1d2bigS2Lpkm0VRNiL7GFF_AvE) с данными для обучения и готовыми моделями. Он будет автоматически распакован в папки `data` и `install_files` в корне проекта.\n\nЕсли вы не можете или не хотите воспользоваться скриптом для установки всех необходимых пакетов, нужно вручную установить [RHVoice](https://github.com/Olga-Yakovleva/RHVoice) и [CMUclmtk_v0.7](https://cmusphinx.github.io/wiki/cmuclmtkdevelopment/), используя инструкции в `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`, если у вас есть своя языковая модель и словарь).\n\n# Бот\n\nОснова бота - рекуррентная нейронная сеть, модель 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 вопросов правильно).\n\nНа данный момент предусмотрено 3 набора данных для обучения бота: 1601 пара вопрос-ответ из различных пьес (`data/plays_ru`), 136.000 пар из различных произведений (`data/conversations_ru`, спасибо [NLP Datasets](https://github.com/Koziev/NLP_Datasets)) и 2.500.000 пар из субтитров к 347 сериалам (`data/subtitles_ru`, подробнее в [Russian subtitles dataset](https://github.com/Desklop/Russian_subtitles_dataset)). Модели word2vec обучены для всех наборов данных, но нейронная сеть обучена только на наборе данных из пьес.\n\nОбучение модели word2vec и нейронной сети на наборе данных из пьес без изменения параметров длится примерно 7.5 часов на nvidia gtx1070 и intel core i7. Обучение на наборах данных из произведений и субтитров на данном железе будет длиться минимум нескольких суток.\n\nБот умеет работать в нескольких режимах:\n1. Обучение модели seq2seq.\n2. Работа с обученной моделью seq2seq в текстовом режиме.\n3. Работа с обученной моделью seq2seq с озвучиванием ответов с помощью [RHVoice](https://github.com/Olga-Yakovleva/RHVoice).\n4. Работа с обученной моделью seq2seq с распознаванием речи с помощью [PocketSphinx](https://github.com/cmusphinx/pocketsphinx).\n5. Работа с обученной моделью seq2seq с озвучиванием ответов и распознаванием речи.\n\n---\n\n## 1. Обучение модели seq2seq\n\nОбучающая выборка состоит из 1600 пар вопрос %% ответ, взятых из различных русских пьес. Она хранится в файле `data/plays_ru/plays_ru.txt`. Каждая пара вопрос %% ответ пишется с новой строки, т.е. на одной строке только одна пара.\n\nВсе необходимые для обучения этапы выполняются методами `prepare()` или `load_prepared()` и `train()` класса `TextToText` из модуля `text_to_text.py` и метод `build_language_model()` класса `LanguageModel` из модуля `preparing_speech_to_text.py`. Или можно использовать функцию `train()` модуля `bot.py`.\n\nДля запуска бота в режиме обучения нужно запустить `bot.py` с параметром `train`. Например, так:\n```\npython3 bot.py train\n```\n\nИли можно просто запустить `bot.py` (или выполнить `run_bot.sh`) и в предложенном меню выбрать режим 1 и 1.\n\nПроцесс обучения состоит из нескольких этапов:\n\n**1. Подготовка обучающей выборки.**\n\nДля подготовки обучающей выборки предназначен модуль `source_to_prepared.py`, состоящий из класса `SourceToPrepared`. Данный класс считывает обучающую выборку из файла, разделяет вопросы и ответы, удаляет неподдерживаемые символы и знаки препинания, преобразует полученные вопросы и ответы в последовательности фиксированного размера (с помощью слов-наполнителей `\u003cPAD\u003e`). Так же этот класс осуществляет подготовку вопросов к сети и обработку её ответов. Например:\n\nВход: `\"Зачем нужен этот класс? %% Для подготовки данных\"`\n\nВыход: `[['\u003cPAD\u003e', ..., '\u003cPAD\u003e', '?', 'класс', 'этот', 'нужен', 'Зачем', '\u003cGO\u003e'], ['Для', 'подготовки', 'данных', '\u003cEOS\u003e', '\u003cPAD\u003e', ..., '\u003cPAD\u003e']]`\n\nОбучающая выборка считывается из файла `data/plays_ru/plays_ru.txt`, преобразованные пары [вопрос,ответ] сохраняются в файл `data/plays_ru/prepared_plays_ru.pkl`. Так же при этом строится гистограмма размеров вопросов и ответов, которая сохраняется в `data/plays_ru/histogram_of_sizes_sentences_plays_ru.png`.\n\nДля подготовки обучающей выборки из набора данных на основе пьес достаточно передать методу `prepare_all()` имя соответствующего файла. Что бы подготовить обучающую выборку из набора данных на основе произведений или субтитров, нужно вначале вызвать `combine_conversations()` или `combine_subtitles()`, а после вызывать `preapre_all()`.\n\n**2. Перевод слов в вещественные вектора.**\n\nЗа этот этап отвечает модуль `word_to_vec.py`, состоящий из класса `WordToVec`. Данный класс кодирует последовательности фиксированного размера (т.е. наши вопросы и ответы) в вещественные вектора. Использутся кодировщик word2vec из библиотеки gensim. В классе реализованы методы для кодирования сразу всех пар [вопрос,ответ] из обучающей выборки в вектора, а так же для кодирования вопроса к сети и декодирования её ответа. Например:\n\nВход: `[['\u003cPAD\u003e', ..., '\u003cPAD\u003e', '?', 'класс', 'этот', 'нужен', 'Зачем', '\u003cGO\u003e'], ['Для', 'кодирования', 'предложений', '\u003cEOS\u003e', '\u003cPAD\u003e', ..., '\u003cPAD\u003e']]`\n\nВыход: `[[[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()`))\n\nПары [вопрос,ответ] считываются из файла `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`.\n\nДля перевода слов из обучающей выборки в вектора достаточно передать методу `build_word2vec()` имя соответствующего файла и задать желаемые параметры.\n\n**3. Обучение сети.**\n\nНа этом этапе выполняется обучение модели seq2seq на уже подготовленных ранее данных. За это отвечает модуль `text_to_text.py`, состоящий из класса `TextToText`. Данный класс осуществляет обучение сети, сохранение модели сети и весовых коэффициентов, и позволяет удобно взаимодействовать с обученной моделью.\n\nДля обучение необходим файл `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`.\n\nПосле обучения сети выполняется оценка качества обучения путём подачи на вход обученной сети всех вопросов и сравнения ответов сети с эталонными ответами из обучающей выборки. Если точность оцениваемой модели получается выше 75%, то неправильные ответы сети сохраняются в файл `data/plays_ru/wrong_answers_plays_ru.txt` (что бы их можно было потом проанализировать).\n\nДля обучения сети достаточно передать методу `train()` имя соответствующего файла и задать желаемые параметры.\n\n**4. Построение языковой модели и словаря для PocketSphinx.**\n\nЭтот этап нужен в случае, если будет использоваться распознавание речи. На этом этапе осуществляется создание статической языковой модели и фонетического словаря для 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-пользователя).\n\n---\n\n## 2. Работа с обученной моделью seq2seq в текстовом режиме\n\nДля взаимодействия с обученной моделью 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` с весами обученной сети.\n\nДля запуска бота в данном режиме нужно запустить `bot.py` с параметром `predict`. Например, так:\n```\npython3 bot.py predict\n```\n\nТак же можно просто запустить `bot.py` (или выполнить `run_bot.sh`) и в предложенном меню выбрать режим 2 и 1.\n\n---\n\n## 3. Работа с обученной моделью seq2seq с озвучиванием ответов с помощью [RHVoice](https://github.com/Olga-Yakovleva/RHVoice)\n\nДанный режим отличается от предыдущего тем, что функции `predict()` модуля `bot.py` передаётся параметр `speech_synthesis = True`. Это означает, что взаимодействие с сетью будет проходить так же, как и в режиме 2, но ответ сети дополнительно будет озвучиваться.\n\nОзвучивание ответов, т.е. синтез речи, реализован в методе `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](https://github.com/Olga-Yakovleva/RHVoice/wiki/Latest-version-%28Russian%29)).\n\nДля запуска бота в данном режиме нужно запустить `bot.py` с параметрами `predict -ss`. Например, так:\n```\npython3 bot.py predict -ss\n```\n\nТак же можно просто запустить `bot.py` (или выполнить `run_bot.sh`) и в предложенном меню выбрать режим 3 и 1.\n\n---\n\n## 4. Работа с обученной моделью seq2seq с распознаванием речи с помощью [PocketSphinx](https://github.com/cmusphinx/pocketsphinx)\n\nДля работы в этом режиме необходимо функции `predict()` модуля `bot.py` передать параметр `speech_recognition = True`. Это означает, что взаимодействие с сетью, а точнее ввод вопросов, будет осуществляться с помощью голоса.\n\nРаспознавание речи реализовано в методе `get()` класса `SpeechToText` модуля `speech_to_text.py`. Данный класс использует PocketSphinx и языковую модель со словарём (`ru_bot_plays_ru.lm` и `ru_bot_plays_ru.dic`), которые были построены в режиме обучения сети. Метод `get()` может работать в двух режимах: `from_file` - распознавание речи из .wav или .opus файла с частотой дискретизации \u003e=16кГц, 16bit, моно (имя файла передаётся в качестве аргумента функции) и `from_microphone` - распознавание речи с микрофона. Режим работы задаётся при создании экземпляра класса `SpeechRecognition`, т.к. загрузка языковой модели занимает некоторое время (чем больше модель, тем дольше она загружается).\n\nДля запуска бота в данном режиме нужно запустить `bot.py` с параметрами `predict -sr`. Например, так:\n```\npython3 bot.py predict -sr\n```\n\nТак же можно просто запустить `bot.py` (или выполнить `run_bot.sh`) и в предложенном меню выбрать режим 4 и 1.\n\n---\n\n## 5. Работа с обученной моделью seq2seq с озвучиванием ответов и распознаванием речи\n\nЭто комбинация режимов 3 и 4.\n\nДля работы в этом режиме необходимо функции `predict()` модуля `bot.py` передать параметры `speech_recognition = True` и `speech_synthesis = True`. Это означает, что ввод вопросов будет осуществляться с помощью голоса, а ответы сети будут озвучиваться. Описание используемых модулей можно найти в описании режимов 3 и 4.\n\nДля запуска бота в данном режиме нужно запустить `bot.py` с параметрами `predict -ss -sr`. Например, так:\n```\npython3 bot.py predict -sr -ss\n```\nили\n```\npython3 bot.py predict -ss -sr\n```\n\nТак же можно просто запустить `bot.py` (или выполнить `run_bot.sh`) и в предложенном меню выбрать режим 5 и 1.\n\n\n\n# RESTful сервер\n\nДанный сервер предоставляет REST-api для взаимодействия с ботом. При старте сервера загружается нейронная сеть, обученная на наборе данных из пьес. Наборы данных из произведений и субтитров пока не поддерживаются.\n\nСервер реализован с помощью [Flask](http://flask.pocoo.org/), а многопоточный режим (production-версия) с помощью [gevent.pywsgi.WSGIServer](http://flask.pocoo.org/docs/1.0/deploying/wsgi-standalone/). Также сервер имеет ограничение на размер принимаемых данных в теле запроса равное 16 Мб. Реализация находится в модуле `rest_server.py`.\n\nЗапустить WSGI сервер можно выполнив `run_rest_server.sh` (запуск WSGI сервера на `0.0.0.0:5000`).\n\nСервер поддерживает аргументы командной строки, которые немного упрощают его запуск. Аргументы имеют следующую структуру: `[ключ(-и)] [адрес:порт]`.\n\nВозможные ключи:\n1. `-d` - запуск тестового Flask сервера (если ключ не указывать - будет запущен WSGI сервер)\n2. `-s` - запуск сервера с поддержкой https (используется самоподписанный сертификат, получен с помощью openssl)\n\nДопустимые варианты `адрес:порт`:\n1. `host:port` - запуск на указанном `host` и `port`\n2. `localaddr:port` - запуск с автоопределением адреса машины в локальной сети и указанным `port`\n3. `host:0` или `localaddr:0` - если `port = 0`, то будет выбран любой доступный порт автоматически\n\nСписок возможных комбинаций аргументов командной строки и их описание: \n1. без аргументов - запуск WSGI сервера с автоопределением адреса машины в локальной сети и портом `5000`. Например: ```python3 rest_server.py```\n2. `host:port` - запуск WSGI сервера на указанном `host` и `port`. Например: ```python3 rest_server.py 192.168.2.102:5000```\n3. `-d` - запуск тестового Flask сервера на `127.0.0.1:5000`. Например: ```python3 rest_server.py -d```\n4. `-d host:port` - запуск тестового Flask сервера на указанном `host` и `port`. Например: ```python3 rest_server.py -d 192.168.2.102:5000```\n5. `-d localaddr:port` - запуск тестового Flask сервера с автоопределением адреса машины в локальной сети и портом `port`. Например: ```python3 rest_server.py -d localaddr:5000```\n6. `-s` - запуск WSGI сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом `5000`. Например: ```python3 rest_server.py -s```\n7. `-s host:port` - запуск WSGI сервера с поддержкой https на указанном `host` и `port`. Например: ```python3 rest_server.py -s 192.168.2.102:5000```\n8. `-s -d` - запуск тестового Flask сервера с поддержкой https на `127.0.0.1:5000`. Например: ```python3 rest_server.py -s -d```\n9. `-s -d host:port` - запуск тестового Flask сервера с поддержкой https на указанном `host` и `port`. Например: ```python3 rest_server.py -s -d 192.168.2.102:5000```\n10. `-s -d localaddr:port` - запуск тестового Flask сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом `port`. Например: ```python3 rest_server.py -s -d localaddr:5000```\n\nСервер может сам выбрать доступный порт, для этого нужно указать в `host:port` или `localaddr:port` порт `0` (например: ```python3 rest_server.py -d localaddr:0```).\n\nВсего поддерживается 5 запросов:\n1. GET-запрос на `/chatbot/about`, вернёт информацию о проекте\n2. GET-запрос на `/chatbot/questions`, вернёт список всех поддерживаемых вопросов\n3. POST-запрос на `/chatbot/speech-to-text`, принимает .wav/.opus-файл и возвращает распознанную строку\n4. POST-запрос на `/chatbot/text-to-speech`, принимает строку и возвращает .wav-файл с синтезированной речью\n5. POST-запрос на `/chatbot/text-to-text`, принимает строку и возвращает ответ бота в виде строки\n\n---\n\n## Описание сервера\n\n**1.** Сервер имеет базовую http-авторизацию. Т.е. для получения доступа к серверу надо в каждом запросе добавить заголовок, содержащий логин:пароль, закодированный с помощью `base64` (логин: `bot`, пароль: `test_bot`). Пример на python:\n```\nimport requests\nimport base64\n\nauth = base64.b64encode('testbot:test'.encode())\nheaders = {'Authorization' : \"Basic \" + auth.decode()}\n```\n\nВыглядеть это будет так:\n```\nAuthorization: Basic dGVzdGJvdDp0ZXN0\n```\n\n**2.** В запросе на распознавание речи (который под номером 3) сервер ожидает .wav или .opus файл (\u003e=16кГц 16бит моно) с записанной речью, который так же передаётся в json с помощью кодировки `base64` (т.е. открывается .wav/.opus-файл, читается в массив байт, потом кодирутеся `base64`, полученный массив декодируется из байтовой формы в строку `utf-8` и помещается в json), в python это выглядит так:\n```\n# Формирование запроса\nauth = base64.b64encode('testbot:test'.encode())\nheaders = {'Authorization' : \"Basic \" + auth.decode()}\n\nwith open('test.wav', 'rb') as audio:\n    data = audio.read()\ndata = base64.b64encode(data)\ndata = {'wav' : data.decode()}\n\n# Отправка запроса серверу\nr = requests.post('http://' + addr + '/chatbot/speech-to-text', headers=headers, json=data)\n\n# Разбор ответа\ndata = r.json()\ndata = data.get('text')\nprint(data)\n```\n\n**3.** В запросе на синтез речи (который под номером 4) сервер пришлёт в ответе json с .wav-файлом (16бит 32кГц моно) с синтезированной речью, который был закодирован так, как описано выше (что бы обратно его декодировать нужно из json получить нужную строку в массив байт, потом декодировать его с помощью `base64` и записать в файл или поток, что бы потом воспроизвести), пример на python:\n```\n# Формирование запроса\nauth = base64.b64encode('testbot:test'.encode())\nheaders = {'Authorization' : \"Basic \" + auth.decode()}\ndata = {'text':'который час'}\n\n# Отправка запроса серверу\nr = requests.post('http://' + addr + '/chatbot/text-to-speech', headers=headers, json=data)\n\n# Разбор ответа\ndata = r.json()\ndata = base64.b64decode(data.get('wav'))\nwith open('/home/vladislav/Проекты/Voice chat bot/temp/answer.wav', 'wb') as audio:\n    audio.write(data)\n```\n\n---\n\n## Передаваемые данные в каждом запросе\n\nВсе передаваемые данные обёрнуты в json (в том числе и ответы с ошибками).\n1. Сервер передаёт клиенту:\n```\n{\n\"text\" : \"Информация о проекте.\"\n}\n```\n2. Сервер передаёт клиенту:\n```\n{\n\"text\" : [\"Вопрос 1\",\n          \"Вопрос 2\",\n          \"Вопрос 3\"]\n}\n```\n3. Клиент в теле запроса должен отправить:\n```\n{\n\"wav\" : \"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH...\"\n}\n```\nили\n```\n{\n\"opus\" : \"ZFZm10IBUklQVZFZm10IBARLASBAAEOpH...\"\n}\n```\nСервер ему передаст:\n```\n{\n\"text\" : \"который час\"\n}\n```\n4. Клиент в теле запроса должен отправить:\n```\n{\n\"text\" : \"который час\"\n}\n```\nСервер ему передаст:\n```\n{\n\"wav\" : \"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH...\"\n}\n```\n5. Клиент в теле запроса должен отправить:\n```\n{\n\"text\" : \"прощай\"\n}\n```\nСервер ему передаст:\n```\n{\n\"text\" : \"это снова я\"\n}\n```\n\n---\n\n## Примеры запросов\n\n**1. GET-запрос на `/chatbot/about`**\n\nПример запроса, который формирует `python-requests`:\n```\nGET /chatbot/about HTTP/1.1\nHost: 192.168.2.83:5000\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: python-requests/2.9.1\n```\n\nПример запроса, который формирует curl (`curl -v -u testbot:test -i http://192.168.2.83:5000/chatbot/about`):\n```\nGET /chatbot/about HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 305\nDate: Fri, 02 Nov 2018 15:13:21 GMT\n\n{\n\"text\" : \"Информация о проекте.\"\n}\n```\n\n---\n\n**2. GET-запрос на `/chatbot/questions`**\n\nПример запроса, который формирует `python-requests`:\n```\nGET /chatbot/questions HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: python-requests/2.9.1\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\n```\n\nПример запроса, который формирует curl (`curl -v -u testbot:test -i http://192.168.2.83:5000/chatbot/questions`):\n```\nGET /chatbot/questions HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 1086\nDate: Fri, 02 Nov 2018 15:43:06 GMT\n\n{\n\"text\" : [\"Что случилось?\",\n          \"Срочно нужна твоя помощь.\",\n          \"Ты уезжаешь?\",\n          ...]\n}\n```\n\n---\n\n**3. POST-запрос на `/chatbot/speech-to-text`**\n\nПример запроса, который формирует `python-requests`:\n```\nPOST /chatbot/speech-to-text HTTP/1.1\nHost: 192.168.2.83:5000\nUser-Agent: python-requests/2.9.1\nAccept: */*\nContent-Length: 10739\nConnection: keep-alive\nContent-Type: application/json\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nAccept-Encoding: gzip, deflate\n\n{\n\"wav\" : \"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH...\"\n}\n```\n\nПример запроса, который формирует 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`):\n```\nPOST /chatbot/speech-to-text HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\nAccept: */*\nContent-Type: application/json\nContent-Length: 10739\n\n{\n\"wav\" : \"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH...\"\n}\n```\n\nСервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Length: 81\nDate: Fri, 02 Nov 2018 15:57:13 GMT\nContent-Type: application/json\n\n{\n\"text\" : \"Распознные слова из аудиозаписи\"\n}\n```\n\n---\n\n**4. POST-запрос на `/chatbot/text-to-speech`**\n\nПример запроса, который формирует `python-requests`:\n```\nPOST /chatbot/text-to-speech HTTP/1.1\nHost: 192.168.2.83:5000\nConnection: keep-alive\nAccept: */*\nUser-Agent: python-requests/2.9.1\nAccept-Encoding: gzip, deflate\nContent-Type: application/json\nContent-Length: 73\nAuthorization: Basic dGVzdGJvdDp0ZXN0\n\n{\n\"text\" : \"который час\"\n}\n```\n\nПример запроса, который формирует 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`):\n```\nPOST /chatbot/text-to-speech HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\nAccept: */*\nContent-Type: application/json\nContent-Length: 32\n\n{\n\"text\" : \"который час\"\n}\n```\n\nСервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 78151\nDate: Fri, 02 Nov 2018 16:36:02 GMT\n\n{\n\"wav\" : \"UklGRuTkAABXQVZFZm10IBAAAAABAAEAAH...\"\n}\n```\n\n---\n\n**5. POST-запрос на `/chatbot/text-to-text`**\n\nПример запроса, который формирует `python-requests`:\n```\nPOST /chatbot/text-to-text HTTP/1.1\nHost: 192.168.2.83:5000\nAccept-Encoding: gzip, deflate\nContent-Type: application/json\nUser-Agent: python-requests/2.9.1\nConnection: keep-alive\nContent-Length: 48\nAccept: */*\nAuthorization: Basic dGVzdGJvdDp0ZXN0\n\n{\n\"text\" : \"прощай\"\n}\n```\n\nПример запроса, который формирует 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`):\n```\nPOST /chatbot/text-to-text HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\nAccept: */*\nContent-Type: application/json\nContent-Length: 23\n\n{\n\"text\" : \"прощай\"\n}\n```\n\nСервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 68\nDate: Fri, 02 Nov 2018 16:41:22 GMT\n\n{\n\"text\" : \"это снова я\"\n}\n```\n\n---\n\n## Предполагаемый алгоритм работы с сервером\n\n1. Запросить список вопросов у сервера (запрос 2) и отобразить его\n2. В зависимости от выбранного режима:\n* Записать речь с микрофона клиента\n* Отправить на сервер (запрос 3) и получить ответ с распознанным текстом\n* Отобразить текст в поле ввода\n* Отправить текст на сервер (запрос 5) и получить ответ бота\n* Отправить ответ бота на сервер (запрос 4) и получить аудиофайл с синтезированной речью\n* Воспроизвести аудиофайл\n3. Если клиент хочет узнать информацию о данном проекте, послать запрос 1 на сервер и отобразить полученные данные\n\n---\n\n## Docker-образ с RESTful сервером\n\nВ проекте содержится Dockerfile, который позволяет собрать docker образ на основе данного проекта. Если для установки всех зависимостей вы использовали `install_packages.sh` и ранее Docker вы не устанавливали, вам необходимо установить его вручную. Например, так (проверено в Ubuntu 16.04-18.04):\n```\nsudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D\nsudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main' -y\nsudo apt-get -y update\nsudo apt-get install -y docker-engine\n```\nПосле установки выполните `sudo systemctl status docker` что бы убедиться, что всё установилось и работает (в выводе данной команды вы найдёте строку с зелёным текстом `active (running)`).\n\nДля сборки образа необходимо перейти в терминале в папку с проектом и выполнить (`-t` — запуск терминала, `.` — директория, из которой вызывается docker build (точка — значит в текущей директории находятся все файлы для образа), `voice_chatbot:0.1` — метка образа и его версия):\n```\nsudo docker build -t voice_chatbot:0.1 .\n```\n\nПосле успешного выполнения данной операции вы можете вывести список имеющихся образов, выполнив:\n```\nsudo docker images\n```\nВ полученном списке вы увидите наш образ — `voice_chatbot:0.1`.\n\nТеперь вы можете запустить этот образ (`-t` — запуск терминала, `-i` — интерактивный режим, `--rm` — удалить контейнер после завершения его работы, `-p 5000:5000` — пробросить все подключения на порт 5000 к машине-хосту в контейнер на порт 5000 (вы так же можете явно указать другой адрес, к которому нужно будет подключиться извне, например: `-p 127.0.0.1:5000:5000`)):\n```\nsudo docker run -ti --rm -p 5000:5000 voice_chatbot:0.1\n```\n\nВ результате запустится RESTful сервер на `0.0.0.0:5000` и можно к нему обращаться по указанному в терминале адресу (если вы не указали другой при запуске образа).\n\n**Примечание**: собранный docker-образ весит 5.2Гб. Исходные файлы проекта так же включают файл `.dockerignore`, в котором находятся имена файлов, которые не нужно добавлять в образ. Для минимизации размера итогового образа, из него были исключены все файлы, относящиеся к наборку данных из рассказов и из субтитров, файлы с промежуточными результатами обработки данных и обучения нейронной сети. Это значит, что образ содержит только файлы обученной сети и сырые исходные наборы данных.\n\nНа всякий случай, в исходных файлах проекта есть файл `command_for_docker.txt`, содержащий минимально необходимый набор команд для работы с docker.\n\n---\n\nЕсли у вас возникнут вопросы или вы хотите сотрудничать, можете написать мне на почту: vladsklim@gmail.com или в [LinkedIn](https://www.linkedin.com/in/vladklim/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbklim%2Fvoice_chatbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdbklim%2Fvoice_chatbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbklim%2Fvoice_chatbot/lists"}