Всем чмоки, с вами Резник и сегодня мы распознаем голосовые сообщения …
Давайте отвлечёмся ненадолго от партнёрских сетей и сотворим бота, который будет помогать нам в технической поддержке. Его задача — распознавать содержимое голосовых и видео-сообщений в общих чатах Telegram. В качестве языка разработки возьмём Python. Мы будем распознавать речь с помощью бесплатной открытой библиотеки vosk и расставлять знаки препинания с помощью модели от Silero. Тот же механизм реализован в нашем AlterCPA Talk Bot.
Такой бот имеет важнейшее преимущество: распознавание речи происходит локально и не требует работы с API Яндекса или Google. Он целиком безопасен и подходит для параноиков и секретной информации. Этого бота сможет запустить начинающий разработчик или DevOps без глубоких профильных знаний.
Шаг 1. Подготовка бота в Telegram
Первым делом нам необходимо завести бота и получить его токен для работы.
- Заходим в Telegram и находим там @BotFather
- Отправляем боту команду
/newbot
для создания нового бота - Указываем название и будущий адрес нашего бота
- Бот создан, копируем полученный токен и записываем на листочек
- Отправляем боту команду
/mybots
для показа списка ботов - Выбираем только что созданного бота в списке
- Нажимаем Bot Settings
- Нажимаем Allow groups и убеждаемся, что Groups are currently enabled for bot
Бот готов и допущен к работе с групповыми чатами. Так он сможет автоматически распознавать сообщения в группах.
Шаг 2. Подготовка сервера
Как вы уже догадались, нам потребуется виртуальный сервер. Мои боты крутятся на тарифе Scarlett и Danny от Timeweb. В качестве операционной системы используется чистый Debian 10. По сути, подойдёт любая ОС, но шаг 5 на других ОС может отличаться от указанного тут. Для установки софта потребуется около 1.5 ГБ места, языковые модели потребуют ещё около 2-2.5 ГБ.
Перед началом работы обязательно обновляем систему:
apt update && apt upgrade -y
Устанавливаем Python и другой необходимый софт:
apt install -y python3 python3-dev python3-pip unzip ffmpeg
Устанавливаем необходимые для работы модули: torch, vosk, PyTelegramBotAPI и их зависимости:
pip3 install PyTelegramBotAPI pip3 install --no-cache-dir vosk pip3 install --no-cache-dir wave pip3 install --no-cache-dir numpy pip3 install --no-cache-dir torch pip3 cache purge
Обратите внимание, что некоторые модули — довольно увесистые, установка может затянуться.
Шаг 3. Скачивание моделей для распознавания речи
Модели для распознавания будут храниться локально. Сложим их в папку /home/ml
. Им потребуется около 3 ГБ свободного пространства. Доступные языки и модели распознавания лежат на сайте vosk в разделе Models. На момент написания самая свежая модель: vosk-model-ru-0.22, её мы и будем использовать.
Модель расстановки знаков препинания добывается из Github-репозитория компании Silero, в котором нам пригодится файл models.yml. В нём находим te_models и его package в latest. Это и есть искомая ссылка, моя вела вот сюда.
Лучше всего выполнять команды по одной — загрузка моделей может занять кучу времени.
mkdir /home/ml cd /home/ml wget https://alphacephei.com/vosk/models/vosk-model-ru-0.22.zip unzip vosk-model-ru-0.22.zip rm -f vosk-model-ru-0.22.zip wget https://models.silero.ai/te_models/v2_4lang_q.pt
Модели скачаны и готовы к работе. Обратите внимание, что на момент чтения статьи ссылки могут быть новыми. Используйте самые свежие версии файлов.
Шаг 4. Написание бота
Готовый файл бота voxy.py вы можете скачать в нашем репозитории на Gitlab. Просто закиньте его на сервер и наслаждайтесь процессом. Процесс описан в следующем шаге. А в этом разберём его код по пунктам.
В начале файла указываем версию Питона, с которой будем работать. Возможно, ваша будет гораздо свежее, проверьте её через which python3
.
#!/usr/bin/python3 # coding: utf-8
Подключаем все модули, скачанные на втором шаге.
import telebot import pathlib import requests import subprocess import os import json import wave import torch from vosk import Model, KaldiRecognizer
Указываем токен нашего бота из первого шага.
TOKEN = '12345:AAAA-BBBBBB_CCC'
Указываем пути к моделям и используемый язык. Если вы действовали строго по инструкции, пути не поменяются.
MODEL = r"/home/ml/vosk-model-ru-0.22" TEMODEL = "/home/ml/v2_4lang_q.pt" LANG = 'ru'
Подготавливаем бота и модели.
WORKDIR = str(pathlib.Path(__file__).parent.absolute()) bot = telebot.TeleBot( TOKEN ) model = Model( MODEL ) voska = KaldiRecognizer( model, 16000 ) tmodel = torch.package.PackageImporter( TEMODEL ).load_pickle( "te_model", "model" )
Мы будем перехватывать все сообщения с типом «голос» и «видео-сообщение».
@bot.message_handler(content_types=["voice","video_note"]) def voice_decoder(message):
Далее пойдёт код вложенной функции, не забывайте об отступах. Первым делом проверим тип сообщения.
if ( message.voice != None ): file = message.voice elif ( message.video_note != None ): file = message.video_note else: return False
Скачаем файл, прикреплённый к сообщению.
finfo = bot.get_file(file.file_id) try: contents = requests.get( 'https://api.telegram.org/file/bot{0}/{1}'.format(TOKEN, finfo.file_path) ) except Exception: return False
Сохраним файл прямо рядом с ботом. Путь WORKDIR
мы отыскали при инициализации.
downpath = WORKDIR + "/" + file.file_unique_id with open( downpath, 'wb' ) as dest: dest.write(contents.content)
Конвертируем файл волшебной командой, которую покажем ниже.
path = audioconvert( downpath ) if ( path == False ): return False
Преобразуем файл в текст простым вызовом модели распознавания. Если всё получилось — прогоняем текст по модели улучшения.
text = speech2text( path ) os.remove( path ) if ( text == False or text == "" or text == " " ): return False else: text = tmodel.enhance_text( text, LANG )
Отсылаем сообщение в качестве ответа, на этом вся работа распознавания заканчивается.
bot.reply_to(message, text)
Для конвертирования аудио будем использовать FFmpeg, потому что других вариантов я и не знаю. Нам потребуется файл с битрейтом в 16к, формат PCM, моно.
def audioconvert(path): out_path = path + ".wav" command = [ r'/usr/bin/ffmpeg', '-i', path, '-acodec', 'pcm_s16le', '-ac', '1', '-ar', '16000', out_path ] result = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) os.remove( path ) if ( result.returncode ): os.remove( out_path ) return False else: return out_path
Для извлечения текста через vosk, воспользуемся готовой магией от разработчиков. Я не имею ни малейшего представления о том, как это работает и почему это именно так. Но оно работает.
def speech2text(path): wf = wave.open(path, "rb") result = '' last_n = False while True: data = wf.readframes(16000) if len(data) == 0: break if voska.AcceptWaveform(data): res = json.loads(voska.Result()) if res['text'] != '': result += f" {res['text']}" last_n = False elif not last_n: result += 'n' last_n = True res = json.loads(voska.FinalResult()) result += f" {res['text']}" return result
Последний шаг — запускаем бота в режиме активной работы.
if __name__ == '__main__': bot.infinity_polling()
Шаг 5. Запуск бота как сервиса
Разместим бота в папке /home/bot
и будем там его запускать.
mkdir /home/bot cd /home/bot wget https://gitlab.com/altervision/altercpa-voxy/-/raw/main/voxy.py chmod a+x voxy.py nano voxy.py
Указываем токен бота из шага 1, сохраняем (Ctrl + O, Enter, Ctrl + X). Пробуем включить бота и проверить, запустится ли.
./voxy.py
Покажется несколько сообщений о загрузке и через несколько секунд бот будет готов. Отправьте ему голосовое сообщение и ждите ответа. Предполагается, что на этом шаге не появится никаких ошибок. Если они появились, рвите на себе волосы, устраивайте истерики и пишите жалобы в Спортлото.
Создадим файл, который будет отвечать за работу нашего сервиса. Сервис назовём voxybot.
nano /lib/systemd/system/voxybot.service
Содержимое файла будет примерно таким.
[Unit] Description=VoxyBot [Service] Type=simple Restart=on-failure RestartSec=5s ExecStart=/home/bot/voxy.py [Install] WantedBy=multi-user.target
Обновляем службы, включаем бота и запускаем сервис.
systemctl daemon-reload systemctl enable voxybot.service service voxybot start
Шаг 6. Проверка работы
Ваш бот запущен. Откройте диалог с ним и отправьте ему голосовое сообщение. А потом видео-сообщение. Если ответа не будет, вы знаете, что делать. Паника, отрицание, гнев, торг, депрессия, принятие неизбежности обращения в техподдержку или изучения Питона. Если ответ будет — пользуйтесь.
TL;DR: простая установка
После получения токена бота зайдите на сервер и выполните следующие команды:
wget https://gitlab.com/altervision/altercpa-voxy/-/raw/main/setup-ru.sh bash setup-ru.sh YOURBOTTOKEN
Где вместо YOURBOTTOKEN
укажите токен, полученный от BotFather. Установка может затянуться на пару часов — скрипту необходимо скачать около 3.5 ГБ файлов. После установки бот заработает сам.
А с вами был Резник, чмоки!