Я абсолютно уверен что скоро в telegram - перевод аудио-сообщений в текст будет функцией по-умолчанию, ну а пока хотел бы показать простенький пример как реализовать такой функционал в telegram-боте (которых уже сотни, но почему бы не посмотреть как это работает на примере).

Сразу оговорюсь что используемый в примере сервис Wit не совсем предназначен для перевода аудио-сообщений, у этого сервиса другое предназначение, более интересное о котором я возможно напишу позже, но раз у него такой функционал есть и он бесплатен, то почему бы и нет?
Для начала нужно зарегистрироваться и создать проект, в этом ничего сложного нет, останавливаться на этом подробнее я не буду, нам лишь понадобится токен для работы с API.
Регистрация бота
Бот в telegram создаётся папой-ботом @BotFather, маму-бота заменим мы.

А сам бот будет написан на самом «уважаемом» среди сообщества хабра - языке программирования PHP. Плюсом выбора этого языка является то что мы можем закинуть скрипт на абсолютно любой самый дешевый .
Сам же процесс создания бота не сложен, мы просто отвечаем на вопросы, а в конце получаем токен который понадобится для работы с API telegram.

Теперь нужно зарегистрировать обработчик нашего бота, для этого переходим по ссылке: https://api.telegram.org/bot<TOKEN>/setWebhook?url=<URL>
Где <TOKEN> это токен нашего бота, а <URL> путь к обработчику. Учтите что путь до обработчика должен начинаться с https.
В ответ должны увидеть что-то вроде этого:
{
"ok":true,
"result":true,
"description":"Webhook is already set"
}
Теперь каждый раз когда бот получит сообщение, на наш обработчик будет отправлен POST запрос с JSON в теле запроса, там много чего интересного но так как наш бот будет выполнять только одну задачу, нас интересует наличие в нём аудио-сообщения.
К слову любой бот в вашем групповом чате имеет доступ ко всем сообщениям, всем вложенным файлам, фотографиям (надеюсь это ни для кого не секрет). И именно по этой причине я не могу в рабочей переписке использовать сторонних ботов.
Написание скрипта.
И так определим схему работы бота:

Вроде всё просто. Конечно мы могли бы отправить скачанное аудио-сообщение сразу в Wit без предварительного сохранения на диск, но аудио-файл скачанный из telegram кодирован в OGG (Кодек: opus, 48000 Hz, mono, fltp, 26 kb/s) к сожалению Wit такой формат не принимает, поэтому нам нужно конвертировать этот файл в любой другой формат на выбор:
-
audio/wav
-
audio/mpeg3
-
audio/ogg
-
audio/ulaw
-
audio/raw
Но я буду конвертировать из OGG в OGG с помощью ffmpeg кодеком vorbis что для Wit в самый раз.
Теперь приступим к программированию. Писать как я уже сказал ранее буду на PHP версии 8.0.
<?php
class VoioverBot {
private string $url = "https://api.telegram.org/bot";
function __construct(private string $wit, private string $tg)
{
$this->msg = json_decode(file_get_contents("php://input"), true);
$this->url .= $tg;
}
// Ищем в сообщении аудио
public function getAudio() : bool | string
{
if (!isset($this->msg["message"]["voice"]["file_id"])) return false;
// Получаем информацию о файле аудио-сообщения
$info = json_decode(@file_get_contents("{$this->url}/getFile?file_id={$this->msg["message"]["voice"]["file_id"]}"), true);
if (!$info || !isset($info["result"]["file_path"])) return false;
// Скачиваем аудио-сообщение
$file = @file_get_contents("https://api.telegram.org/file/bot{$this->tg}/{$info["result"]["file_path"]}");
if (!$file) return false;
// Сохраняем аудио-сообщение во временный файл
if (!file_put_contents("./{$this->msg["message"]["voice"]["file_id"]}", $file)) return false;
// Конвертируем файл:
$this->convertAudio();
// Преобразуем ауди в текст
return $this->getTranscription();
}
// Конвертируем аудио в подходящий формат
private function convertAudio()
{
shell_exec("ffmpeg -i ./{$this->msg["message"]["voice"]["file_id"]} -f ogg ./{$this->msg["message"]["voice"]["file_id"]}.ogg");
}
// Переводим голос в текст используя API wit
private function getTranscription() : bool | string
{
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Authorization: Bearer {$this->wit}rn" .
"Content-Type: audio/ogg",
'content' => file_get_contents("./{$this->msg["message"]["voice"]["file_id"]}.ogg"),
'timeout' => 20
],
]);
$answer = json_decode(file_get_contents("https://api.wit.ai/speech?v=20200422", false, $context), true);
// Временные файлы можно удалить:
unlink("./{$this->msg["message"]["voice"]["file_id"]}");
unlink("./{$this->msg["message"]["voice"]["file_id"]}.ogg");
return (isset($answer['_text']) && !empty($answer['_text'])) ? $answer['_text'] : false;
}
// Отправляем текст в чат
public function sendMessage($text) : bool
{
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json' . PHP_EOL,
'content' => json_encode([
'chat_id' => $this->msg["message"]["chat"]["id"],
'text' => "✍ <b>{$this->msg['message']['from']['first_name']} " .
"{$this->msg['message']['from']['last_name']}</b>rn{$text}",
'parse_mode' => "HTML"
])
]
]);
$result = file_get_contents("{$this->url}/sendMessage", false, $context);
return $result ? true : false;
}
}
$vbot = new Voiover("ТОКЕН Wit", "ТОКЕН telegram");
$voice = $vbot->getAudio();
if ($voice) $vbot->sendMessage($voice);
Это базовый код, и в нём много недостатков:
-
Скрипт не проверяет от кого приходят запросы
-
Если сообщение по какой-то причине не отправилось то оно не будет отправлено повторно.
-
Максимальная длина аудио-сообщений для Wit всего 20 секунд.

P.S перед публикацией я обнаружил что буквально за день до этого на хабре появилась схожая статья Распознавание речи в Telegram «на лету», но на языке GO.
Автор: Дмитрий Корольков
