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

Так как задачу надо было решить максимально быстро в качестве языка программирования был выбран Python3 и несколько библиотек, которые упростили жизнь. Для работы с Telegram API был выбран pyTelegramBotAPI, а в качестве распознавания аудио в текст SpeechRecognition.

Создадим новую папку и откроем там терминал. Нам Нужно создать виртуальное окружение. Если у вас установлен virtualenv, то открываем терминал и вводим virualenv soundbot

Если нет вводим в терминал :

pip install virtualenv

Далее переходим в папку которая создалась то просто выбираем .cmd файл и кидаем его на окно терминала.

Далее по очереди выполняем установку двух модулей командами:

pip install SpeechRecognition
pip install pyTelegramBotAPI

Далее в любимом редакторе создаем главный файл бота с расширением .py В самом начале кода импортируем все библиотеки которые нам нужны.

import telebot
import uuid
import os 
import speech_recognition as sr

Модуль telebot нужен для создания Telegram ботов на Python3. Модуль  uuid является встроенным в Python3 и используется в данном случае  для генерации случайного имени файла. Модуль os используется для запуска конвертации файлов из .ogg в .wav и модуль speech_recognition распознает голос и выдает текст на выходе. Давайте сейчас создадим переменные и инициализируем распознавание  голоса в текст и создадим объект бота;

language='ru_RU' 
TOKEN='xxxxxxxxxxxxxxxxxxxxxxxx' 
bot = telebot.TeleBot(TOKEN)
 r = sr.Recognizer() 

Здесь объявлены самые главные переменные, language это переменная языка и отвечает за язык распознавания. Токен это токен бота который надо получить. Для этого открываем Telegram и ищем там @BotFather. Начинаем беседу с команды /new_bot и отвечаем на все вопросы бота. В самом последнем сообщении будет как раз токен который нам нужен.

def recognise(filename):
    with sr.AudioFile(filename) as source:
        audio_text = r.listen(source)
        try:
            text = r.recognize_google(audio_text,language=language)
            print('Converting audio transcripts into text ...')
            print(text)
            return text
        except:
            print('Sorry.. run again...')
            return "Sorry.. run again..."

В начале мы открываем наш аудиофайл, далее передаем это в r.recognize_google()  
которая преобразует это в текст. Однако так как запись может быть низкого качества или просто файл может быть поврежден, Это будет означать что код может выдать исключение и как раз для вылавливания исключения здесь применен блок try/catch. А также обязательно в случае исключения выводится какое-то сообщение, так как мы получим ошибку если попытаемся отправить пустое сообщение.

Вот мы и добрались до основной функции бота которая срабатывает если есть кто-то отметивший бота и при этом сообщение является голосовым.

@bot.message_handler(content_types=['voice'])
def voice_processing(message):
    filename = str(uuid.uuid4())
    file_name_full="./voice/"+filename+".ogg"
    file_name_full_converted="./ready/"+filename+".wav"
    file_info = bot.get_file(message.voice.file_id)
    downloaded_file = bot.download_file(file_info.file_path)
    with open(file_name_full, 'wb') as new_file:
        new_file.write(downloaded_file)
    os.system("ffmpeg -i "+file_name_full+"  "+file_name_full_converted)
    text=recognise(file_name_full_converted)
    bot.reply_to(message, text)
    os.remove(file_name_full)
    os.remove(file_name_full_converted)

Стоит обратить ваше внимание еще раз на то что данная функция срабатывает только если есть упоминание бота, и содержит голосовое сообщение. В самом начале мы создаем уникальное имя файла и сохраняем его в переменную. Далее мы создаем путь где будет храниться сам файл, то есть к имени файла добавляем папку где оно будет храниться. Далее создаем имя, но уже сконвертированного в нормальный формат который понятен распознавался текста. Далее вы скачиваем файл и сохраняем по недавно сгенерированному пути. Следующем шагом вы вызываем ffmpeg из консоли* и передаем ему два параметра file_name_full это где лежит исходный файл, а также file_name_full_converted это уже куда сохранить конвертированный файл. После этого вызываем функцию recognise() которая преобразует наше аудио в текст. И остается дело за малым ответить на сообщение при помощи функции .reply_to() и удалить оба аудио-файла.

Поздравляю мы почти уже у цели. Осталось запустить бота при запуске нашего файла. Для этого в конце нашего файла напишем: bot.polling()

Все можем сохранить файл и запустить его из консоли командой python3 вашеимяфайла.py

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

Перед запуском создаем директории ready и voice.

Финальный код: (Спасибо @victoriously)

import telebot
import uuid
import os
import speech_recognition as sr

language='ru_RU'
TOKEN='YOUR_TOKEN'
#CHAT_ID='-100xxxxxxxxxxxxxxxxxxxxx')
bot = telebot.TeleBot(TOKEN)
r = sr.Recognizer()

def recognise(filename):
    with sr.AudioFile(filename) as source:
        audio_text = r.listen(source)
        try:
            text = r.recognize_google(audio_text,language=language)
            print('Converting audio transcripts into text ...')
            print(text)
            return text
        except:
            print('Sorry.. run again...')
            return "Sorry.. run again..."

@bot.message_handler(content_types=['voice'])
def voice_processing(message):
    filename = str(uuid.uuid4())
    file_name_full="./voice/"+filename+".ogg"
    file_name_full_converted="./ready/"+filename+".wav"
    file_info = bot.get_file(message.voice.file_id)
    downloaded_file = bot.download_file(file_info.file_path)
    with open(file_name_full, 'wb') as new_file:
        new_file.write(downloaded_file)
    os.system("ffmpeg -i "+file_name_full+"  "+file_name_full_converted)
    text=recognise(file_name_full_converted)
    bot.reply_to(message, text)
    os.remove(file_name_full)
    os.remove(file_name_full_converted)

bot.polling()

UPD. Спасибо @victoriously за найденые ошибки в первой версии статьи. А так же за полный и рабочий код .

Комментарии (12)


  1. centralhardware
    29.08.2021 13:44
    +5

    Voicy существует уже миллион лет и делает то же самое, если уж нужна была более качественная альтернатива то и писать стоило, что то качественное.


    1. AlexZas20 Автор
      30.08.2021 19:21

      Спасибо , не знал .


    1. dobergroup
      30.08.2021 20:11

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


  1. aamonster
    29.08.2021 13:54
    +3

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


    1. AlexZas20 Автор
      30.08.2021 19:18

      На самом деле думал об этом, но иногда хочется просто пообщатся голосовыми.


  1. victoriously
    29.08.2021 18:56
    +4

    Есть несколько замечаний к вашей статье:
    * Не хватает сравнения с уже существующими аналогами.
    * Не хватает уже выложенного бота для собственной проверки
    * Не хватает выложенного исходного кода, чтобы запустить бота :)

    Ну и при попытке самостоятельно запустить его, возникло еще пару замечаний и проблем
    * os.system выглядит как костыль. Почему бы не использовать ffmpeg библиотеку для питона?
    * Зависимости проще было бы указать через pip freeze > requirements.txt
    * Зачем нам CHAT_ID, если дальше по коду мы его нигде не используем?
    * Различные ошибки, в основном из-за того, что код в статье не полный

    Сами ошибки и их исправление

    * Не хватает 1 строчки кода, взял её из примера в документации
    (venv) [root@vitka-k soundto]$ python soundto.py
    Traceback (most recent call last):
    File "soundto.py", line 38, in bot.polling()
    File "/root/bots/soundto/venv/lib/python3.7/site-packages/telebot/__init__.py", line 622, in polling
    self.__threaded_polling(non_stop, interval, timeout, long_polling_timeout, allowed_updates)
    File "/root/bots/soundto/venv/lib/python3.7/site-packages/telebot/__init__.py", line 681, in __threaded_polling
    raise e
    File "/root/bots/soundto/venv/lib/python3.7/site-packages/telebot/__init__.py", line 644, in __threaded_polling
    self.worker_pool.raise_exceptions()
    File "/root/bots/soundto/venv/lib/python3.7/site-packages/telebot/util.py", line 130, in raise_exceptions
    raise self.exception_info
    File "/root/bots/soundto/venv/lib/python3.7/site-packages/telebot/util.py", line 82, in run
    task(*args, **kwargs)
    File "soundto.py", line 29, in voice_processing
    downloaded_file = bot.download_file(file_info.file_path)
    NameError: name 'file_info' is not defined


    Исправляется добавление строчки перед использованием file_info
    file_info = bot.get_file(message.voice.file_id)


    * Питон жалуется на отсутствие директории voice и ready, создаем её вручную или через сам питон
    FileNotFoundError: [Errno 2] No such file or directory: './voice/aa9cc69a-26d6-4e43-a84e-99e367c47510.ogg'


    Кто хочет потестировать — некоторое время будет работать @soundto_bot, дальше могу передать его автору, если он планирует развивать его.
    Полный код
    import telebot
    import uuid
    import os
    import speech_recognition as sr
    
    language='ru_RU'
    TOKEN='YOUR_TOKEN'
    #CHAT_ID='-100xxxxxxxxxxxxxxxxxxxxx')
    bot = telebot.TeleBot(TOKEN)
    r = sr.Recognizer()
    
    def recognise(filename):
        with sr.AudioFile(filename) as source:
            audio_text = r.listen(source)
            try:
                text = r.recognize_google(audio_text,language=language)
                print('Converting audio transcripts into text ...')
                print(text)
                return text
            except:
                print('Sorry.. run again...')
                return "Sorry.. run again..."
    
    @bot.message_handler(content_types=['voice'])
    def voice_processing(message):
        filename = str(uuid.uuid4())
        file_name_full="./voice/"+filename+".ogg"
        file_name_full_converted="./ready/"+filename+".wav"
        file_info = bot.get_file(message.voice.file_id)
        downloaded_file = bot.download_file(file_info.file_path)
        with open(file_name_full, 'wb') as new_file:
            new_file.write(downloaded_file)
        os.system("ffmpeg -i "+file_name_full+"  "+file_name_full_converted)
        text=recognise(file_name_full_converted)
        bot.reply_to(message, text)
        os.remove(file_name_full)
        os.remove(file_name_full_converted)
    
    bot.polling()
    


    1. un1t
      29.08.2021 22:15
      +2

      Google Cloud Speech-to-Text API платное с бесплатными лимитом 60 минут в месяц, каждый запрос округляется до 15 секунд.

      Меня удивило, что этот кусок кода сработал без ключа

      text = r.recognize_google(audio_text,language=language)

      посмотрел исходники там написано что нужно передать key, если key is None то используется ключ по умолчанию зашитый в функции и нет гарантии что это будет работать


    1. AlexZas20 Автор
      30.08.2021 19:21

      Спасибо огромное. По ошибке удалил ее когда писал статью . Однако есть версия с подключеным configparser и немного другим кодом на github . Можно взять как отправную точку: https://github.com/alex5250/TelegramSoundBot


  1. sneg2015
    29.08.2021 23:00
    -2

    Может вопрос глупый, но объясните

    Будет ли бот работать на телефоне? И если да, то что необходимо установить, ведь код должен в чем то обрабатываться.


    1. dobergroup
      30.08.2021 20:07

      Боты работают на сервере, а не на телефоне


  1. Flexoplus
    19.09.2021 00:54

    У меня вопрос зачем нужен такой бот, если на Андроиде есть уже голосовая клавиатура?


    1. AlexZas20 Автор
      19.09.2021 00:57

      Отличный вопрос, однако не все умеют ей пользоваться. Мне намного легче научить компьютер обрабатывать голос, чем объяснить людям как правильно общаться. Особенно сложно если эти люди твои знакомые /друзья (не в обиду им) .