Голосовой бот + телефония на полном OpenSource. Часть 2 — учим бота слушать и говорить

от автора

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

Чтобы наш чат-бот заговорил и начал слушать, нужно пройти несколько подготовительных этапов:

  1. Озвучить все ответные фразы
  2. Установить систему телефонии
  3. Установить систему распознавания голоса
  4. Написать простые скрипты для связи телефонии и нашей нейронной сети с чат-ботом

Шаг 1: Озвучка ответных фраз

Так как наш бот довольно примитивный и может произносить только заранее подготовленные фразы, то первым делом озвучим все наши ответные фразы с использованием к примеру yandex speechkit. Положим их в корневую директорию с аудиозаписями freeswitch /usr/share/freeswitch/sounds/en/us/callie/ivr предварительно обрежем длину имени до 50 символов.

Шаг 2: Установка системы телефонии

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

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

Для сборки freeswitch с поддержкой mod_vosk рекомендуется использовать репозиторий, предлагаемый разработчиком vosk. Скомпилировать его можно по инструкциина сайте freeswitch. Важный момент, для корректной работы mod_vosk необходимо перекомпилировать libks из репозитория.

PS. для удобства конфигурирования Freeswitch можно установить вэб-интерфейс FusionPBX

Шаг 3: Установка системы распознавания голоса

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

docker run -d -p 2700:2700 alphacep/kaldi-ru:latest

Далее необходимо сконфигурировать mod_vosk для freeswitch, для этого в директории /etc/freeswitch/autoload_configs необходимо создать файл vosk.conf.xml, если его нет. В данном файле необходимо указать только адрес вашего vosk сервера:

<configuration name="vosk.conf" description="Vosk ASR Configuration">   <settings>     <param name="server-url" value="ws://localhost:2700"/>     <param name="return-json" value="0"/>   </settings> </configuration>

После настройки можно запустить сам freeswitch

systemctl start freeswitch

И запустить модуль

fs_cli -x "load mod_vosk

Шаг 4: Скрипты для запуска распознавания голоса

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

Шаг 4.1: REST API интерфейс для нейронной сети

Самым быстрым и удобным способом научить нейросеть отвечать на http запросы является библиотека Fastapi для python. Для начала объявим класс Prediction, который содержит формат входных данных для запроса.

class Prediction(BaseModel): 	text: str

Загрузим нашу модель

model = Sequential() model.add(LSTM(64,return_sequences=True,input_shape=(description_length, num_encoder_tokens))) model.add(LSTM(32)) model.add(Dropout(0.25)) model.add(Dense(1024, activation='relu')) model.add(Dropout(0.25)) model.add(Dense(158, activation='softmax')) opt=keras.optimizers.adam(lr=0.01,amsgrad=True) model.compile(loss='categorical_crossentropy', 				  optimizer=opt, 				  metrics=['accuracy']) #model.summary()  model.load_weights("h_10072020.h5")

напишем небольшую функцию по предсказанию ответа

def get_answer(text): 	t = preprocess_ru_text(text) # функция по препроцессингу текста, такая же как и при обучении модели 	input_data = np.zeros( 			(1,description_length,num_encoder_tokens), 			dtype='float32') 	j=0 	for word in t: 		wordidxs = np.zeros((num_encoder_tokens),dtype='float32') 		if word in input_token_index: 			wordidxs[input_token_index[word]]=1 			input_data[0,j]=wordidxs 			j+=1 			print(word) 	results = model.predict(input_data) 	print (results[0][np.argmax(results)],           list(y_dict)[np.argmax(results)]) 	if results[0][np.argmax(results)]>0.5: 		return random.choice(result_config['intents'][list(y_dict)[np.argmax(results)]]['responses']) 	else: #если уверенность нейронной сети меньше 50%, возвращаем фразу, что не расслышали вопрос. 		return random.choice(result_config['failure_phrases'])

и в конце сделаем интерфейс для получения ответа по запросу:

@app.post('/prediction/',response_model=Prediction) async def prediction_route(text: Prediction): 	question = text.text 	answer = get_answer(question) 	return HTMLResponse(content=clear_text(answer)[:50], status_code=200) # обрезаем длину ответа до 50, чтобы совпадало с именем озвученных файлов

Можно запускать наш сервис:

uvicorn main:app --reload --host 0.0.0.0

Теперь при запросе на localhost:8000/prediction:

{ 	"text":"привет" }

мы получаем ответ:

Хай

Шаг 4.2: LUA скрипт для запуска приложения на freeswitch

Задачами lua скрипта будут во первых получение распознанного текста из звонка, во вторых получение ответа от нейронной сети и воспроизведение подготовленного файла с озвученной фразой.

Для возможности осуществления http запросов из lua необходимо установить библиотеку luasocket.

Чтобы без проблем импортировать эту библиотеку, добавьте в свой скрипт строчку:

package.path = package.path .. ";" .. [[/usr/share/lua/5.2/?.lua]];

Далее напишем небольшую функцию получения ответа от нашей нейронной сети:

function sendRequest(speech_res)   local path = "http://localhost:8000/prediction/";   local payload = string.format("{\"text\":\"%s\"}",speech_res);   log.notice(payload);   local response_body = { };   log.notice(path);   local res, code, response_headers, status = http.request   {     url = path,     method = "POST",     headers =     {       ["Authorization"] = "",       ["Content-Type"] = "application/json",       ["Content-Length"] = payload:len()     },     source = ltn12.source.string(payload),     sink = ltn12.sink.table(response_body)   }   return trim1(table.concat(response_body)) end

И запускаем в бесконечном цикле распознавание и воспроизведение ответных фраз:

session:execute("play_and_detect_speech", "ivr/привет я могу посоветовать тебе фильм или сериал.wav detect:vosk default"); while session:ready() do     local res = session:getVariable('detect_speech_result'); 	if res ~= nil then 		local speech_res = session:getVariable("detect_speech_result"); 		local response_body = sendRequest(speech_res); 		log.notice(response_body); 		session:execute("play_and_detect_speech", "ivr/"..response_body..".wav detect:vosk default"); 	end end

Чтобы повесить этот скрипт на определенный номер, достаточно создать конфигурацию такого вида:

<extension name="7000" continue="false"> 	<condition field="destination_number" expression="7000"> 		<action application="lua" data="test_vosk.lua"/> 	</condition> </extension>

И перечитать конфиги:

fs_cli -x "reloadxml"

Заключение

После запуска нейронной сети и freeswitch можно позвонить на номер с привязанным lua скриптом и поговорить с роботом.

ссылка на оригинал статьи https://habr.com/ru/post/522842/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *