Разработка Telegram-бота для распознавания текста на изображениях, синтеза и распознавания аудио
В этом руководстве вы создадите бота для Telegram, который умеет:
- синтезировать речь из текста сообщения и распознавать речь в голосовых сообщениях с помощью Python SDK сервиса Yandex SpeechKit;
- распознавать текст на изображениях с помощью сервиса Yandex Vision OCR.
Аутентификация в сервисах Yandex Cloud выполняется от имени сервисного аккаунта с помощью IAM-токена. IAM-токен содержится в контексте обработчика функции, которая программирует диалог пользователя с ботом.
Запросы от бота будет принимать API-шлюз Yandex API Gateway и перенаправлять их функции Yandex Cloud Functions для обработки.
Чтобы создать бота:
- Подготовьте облако к работе.
- Подготовьте ресурсы.
- Зарегистрируйте Telegram-бота.
- Создайте функцию.
- Создайте API-шлюз.
- Свяжите функцию и бота.
- Протестируйте бота.
Если созданные ресурсы вам больше не нужны, удалите их.
Перед началом работы
Зарегистрируйтесь в Yandex Cloud и создайте платежный аккаунт:
- Перейдите в консоль управления
, затем войдите в Yandex Cloud или зарегистрируйтесь. - На странице Yandex Cloud Billing
убедитесь, что у вас подключен платежный аккаунт, и он находится в статусеACTIVE
илиTRIAL_ACTIVE
. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Необходимые платные ресурсы
В стоимость поддержки Telegram-бота входят:
- плата за использование SpeechKit (см. тарифы для SpeechKit);
- плата за использование Vision OCR (см. тарифы для Vision OCR);
- плата за количество вызовов функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик (см. тарифы для Cloud Functions);
- плата за количество запросов к созданному API-шлюзу и исходящий трафик (см. тарифы API Gateway).
Подготовьте ресурсы
-
Создайте сервисный аккаунт с именем
recognizer-bot-sa
и назначьте ему ролиai.editor
,functions.editor
на ваш каталог. -
Скачайте
архив с пакетом FFmpeg для корректной работы Python SDK SpeechKit в среде выполнения функции. -
Подготовьте ZIP-архив с кодом функции:
-
Создайте файл
index.py
и добавьте в него указанный ниже код.index.py
import logging import requests import telebot import json import os import base64 from speechkit import model_repository, configure_credentials, creds from speechkit.stt import AudioProcessingType # Эндпоинты сервисов и данные для аутентификации API_TOKEN = os.environ['TELEGRAM_TOKEN'] vision_url = 'https://ocr.api.cloud.yandex.net/ocr/v1/recognizeText' folder_id = "" iam_token = '' path = os.environ.get("PATH") os.environ["PATH"] = path + ':/function/code' logger = telebot.logger telebot.logger.setLevel(logging.INFO) bot = telebot.TeleBot(API_TOKEN, threaded=False) # Получение идентификатора каталога def get_folder_id(iam_token, version_id): headers = {'Authorization': f'Bearer {iam_token}'} function_id_req = requests.get(f'https://serverless-functions.api.cloud.yandex.net/functions/v1/versions/{version_id}', headers=headers) function_id_data = function_id_req.json() function_id = function_id_data['functionId'] folder_id_req = requests.get(f'https://serverless-functions.api.cloud.yandex.net/functions/v1/functions/{function_id}', headers=headers) folder_id_data = folder_id_req.json() folder_id = folder_id_data['folderId'] return folder_id def process_event(event): request_body_dict = json.loads(event['body']) update = telebot.types.Update.de_json(request_body_dict) bot.process_new_updates([update]) def handler(event, context): global iam_token, folder_id iam_token = context.token["access_token"] version_id = context.function_version folder_id = get_folder_id(iam_token, version_id) # Аутентификация в SpeechKit через IAM-токен configure_credentials( yandex_credentials=creds.YandexCredentials( iam_token=iam_token ) ) process_event(event) return { 'statusCode': 200 } # Обработчики команд и сообщений @bot.message_handler(commands=['help', 'start']) def send_welcome(message): bot.reply_to(message, "Бот умеет:\n*распознавать текст с картинок;\n* генерировать голосовые сообщения из текста;\n* переводить голосовые сообщения в текст.") @bot.message_handler(func=lambda message: True, content_types=['text']) def echo_message(message): export_path = '/tmp/audio.ogg' synthesize(message.text, export_path) voice = open(export_path, 'rb') bot.send_voice(message.chat.id, voice) @bot.message_handler(func=lambda message: True, content_types=['voice']) def echo_audio(message): file_id = message.voice.file_id file_info = bot.get_file(file_id) downloaded_file = bot.download_file(file_info.file_path) response_text = audio_analyze(downloaded_file) bot.reply_to(message, response_text) @bot.message_handler(func=lambda message: True, content_types=['photo']) def echo_photo(message): file_id = message.photo[-1].file_id file_info = bot.get_file(file_id) downloaded_file = bot.download_file(file_info.file_path) image_data = base64.b64encode(downloaded_file).decode('utf-8') response_text = image_analyze(vision_url, iam_token, folder_id, image_data) bot.reply_to(message, response_text) # Распознавание изображения def image_analyze(vision_url, iam_token, folder_id, image_data): response = requests.post(vision_url, headers={'Authorization': 'Bearer '+iam_token, 'x-folder-id': folder_id}, json={ "mimeType": "image", "languageCodes": ["en", "ru"], "model": "page", "content": image_data }) blocks = response.json()['result']['textAnnotation']['blocks'] text = '' for block in blocks: for line in block['lines']: for word in line['words']: text += word['text'] + ' ' text += '\n' return text # Распознавание речи def audio_analyze(audio_data): model = model_repository.recognition_model() # Настройки распознавания model.model = 'general' model.language = 'ru-RU' model.audio_processing_type = AudioProcessingType.Full try: result = model.transcribe(audio_data) speech_text = [res.normalized_text for res in result] return ' '.join(speech_text) except: return 'Cannot recognize message' # Синтез речи def synthesize(folder_id, iam_token, text): model = model_repository.synthesis_model() # Настройки синтеза model.voice = 'kirill' result = model.synthesize(text, raw_format=False) result.export(export_path, 'ogg')
-
Создайте файл
requirements.txt
и укажите в нем библиотеку для работы с ботом и библиотеку Python SDK.telebot yandex-speechkit
-
Добавьте файлы
index.py
,requirements.txt
и бинарные файлыffmpeg
,ffprobe
из состава утилиты FFMpeg в ZIP-архивindex.zip
. -
Создайте бакет Object Storage и загрузите в него созданный ZIP-архив.
-
Зарегистрируйте Telegram-бота
Зарегистрируйте бота в Telegram и получите токен.
-
Запустите бота BotFather
и отправьте ему команду:/newbot
-
В поле
name
укажите имя создаваемого бота. Это имя увидят пользователи при общении с ботом. -
В поле
username
укажите имя пользователя создаваемого бота. По имени пользователя можно будет найти бота в Telegram. Имя пользователя должно оканчиваться на...Bot
или..._bot
.В результате вы получите токен. Сохраните его — он потребуется в дальнейшем.
Создайте функцию
Создайте функцию, которая будет обрабатывать действия пользователей в чате.
-
В консоли управления
перейдите в каталог, в котором хотите создать функцию. -
В списке сервисов выберите Cloud Functions
-
Создайте функцию:
- Нажмите кнопку Создать функцию.
- Введите имя функции —
for-recognizer-bot
. - Нажмите кнопку Создать.
-
Создайте версию функции:
-
Выберите среду выполнения
Python
, отключите опцию Добавить файлы с примерами кода и нажмите кнопку Продолжить. -
Укажите способ загрузки
Object Storage
и выберите созданный ранее бакет. В поле Объект укажите имя файлаindex.zip
. -
Укажите точку входа
index.handler
. -
В блоке Параметры укажите:
-
Таймаут —
30
. -
Память —
128 МБ
. -
Сервисный аккаунт —
recognizer-bot-sa
. -
Переменные окружения:
TELEGRAM_TOKEN
— токен вашего бота в Telegram.
-
-
Нажмите кнопку Сохранить изменения.
-
-
Создайте функцию
for-recognizer-bot
:yc serverless function create --name=for-recognizer-bot
Результат:
id: b09bhaokchn9******** folder_id: aoek49ghmknn******** created_at: "2023-03-21T10:03:37.475Z" name: for-recognizer-bot log_group_id: eolm8aoq9vcp******** http_invoke_url: https://functions.yandexcloud.net/b09bhaokchn9******** status: ACTIVE
-
Создайте версию функции
for-recognizer-bot
:yc serverless function version create \ --function-name for-recognizer-bot \ --memory=128m \ --execution-timeout=30s \ --runtime=python312 \ --entrypoint=index.handler \ --service-account-id=<идентификатор_сервисного_аккаунта> \ --environment TELEGRAM_TOKEN=<токен_бота> \ --package-bucket-name=<имя_бакета> \ --package-object-name=index.zip
Где:
--function-name
— имя функции, версия которой создается.--memory
— объем RAM.--execution-timeout
— максимальное время выполнения функции до таймаута.--runtime
— среда выполнения.--entrypoint
— точка входа.--service-account-id
— идентификатор сервисного аккаунтаrecognizer-bot-sa
.--environment
— переменные окружения.--package-bucket-name
— имя бакета.--package-object-name
— ключ файла в бакетеindex.zip
.
Результат:
done (1s) id: d4e6qqlh53nu******** function_id: d4emc80mnp5n******** created_at: "2025-03-22T16:49:41.800Z" runtime: python312 entrypoint: index.handler resources: memory: "134217728" execution_timeout: 30s service_account_id: aje20nhregkc******** image_size: "4096" status: ACTIVE tags: - $latest log_group_id: ckgmc3l93cl0******** environment: TELEGRAM_TOKEN: <токен_бота> log_options: folder_id: b1g86q4m5vej********
-
Опишите в конфигурационном файле параметры функции:
resource "yandex_function" "for-recognizer-bot-function" { name = "for-recognizer-bot" user_hash = "first function" runtime = "python312" entrypoint = "index.handler" memory = "128" execution_timeout = "30" service_account_id = "aje20nhregkcvu******" environment = { TELEGRAM_TOKEN = <токен_бота> } package { bucket_name = <имя_бакета> object_name = "index.zip" } }
Где:
name
— имя функции.user_hash
— произвольная строка, определяющая версию функции.runtime
— среда выполнения функции.entrypoint
— точка входа.memory
— объем памяти в мегабайтах, отведенный для выполнения функции.execution_timeout
— таймаут выполнения функции.service_account_id
— идентификатор сервисного аккаунтаrecognizer-bot-sa
.environment
— переменные окружения.package
— имя бакета, в который загружен ZIP-архивindex.zip
с исходным кодом функции.
Более подробную информацию о параметрах ресурса
yandex_function
см. в документации провайдера . -
Проверьте корректность конфигурационных файлов.
-
В командной строке перейдите в папку, где вы создали конфигурационный файл.
-
Выполните проверку с помощью команды:
terraform plan
Если конфигурация описана верно, в терминале отобразится список создаваемых ресурсов и их параметров. Если в конфигурации есть ошибки, Terraform на них укажет.
-
-
Разверните облачные ресурсы.
-
Если в конфигурации нет ошибок, выполните команду:
terraform apply
-
Подтвердите создание функции: введите в терминал слово
yes
и нажмите Enter.
-
Чтобы создать функцию, воспользуйтесь методом create для ресурса Function или вызовом gRPC API FunctionService/Create.
Чтобы создать версию функцию, воспользуйтесь методом createVersion для ресурса Function или вызовом gRPC API FunctionService/CreateVersion.
Создайте API-шлюз
Сервер Telegram будет оповещать ваш бот о поступлении новых сообщений с помощью веб-хукаfor-recognizer-bot
для обработки.
-
В консоли управления
выберите каталог, в котором хотите создать API-шлюз. -
В списке сервисов выберите API Gateway.
-
Нажмите кнопку Создать API-шлюз.
-
В поле Имя введите
recognizer-bot-api-gw
. -
В блок Спецификация добавьте спецификацию:
openapi: 3.0.0 info: title: Sample API version: 1.0.0 paths: /for-recognizer-bot-function: post: x-yc-apigateway-integration: type: cloud_functions function_id: <идентификатор_функции> service_account_id: <идентификатор_сервисного_аккаунта> operationId: for-recognizer-bot-function
Где:
function_id
— идентификатор функцииfor-recognizer-bot
;service_account_id
— идентификатор сервисного аккаунтаrecognizer-bot-sa
.
-
Нажмите кнопку Создать.
-
Выберите созданный API-шлюз. Сохраните значение поля Служебный домен — оно потребуется в дальнейшем.
-
Сохраните следующую спецификацию в файл
spec.yaml
:openapi: 3.0.0 info: title: Sample API version: 1.0.0 paths: /for-recognizer-bot-function: post: x-yc-apigateway-integration: type: cloud_functions function_id: <идентификатор_функции> service_account_id: <идентификатор_сервисного_аккаунта> operationId: for-recognizer-bot-function
Где:
function_id
— идентификатор функцииfor-recognizer-bot
.service_account_id
— идентификатор сервисного аккаунтаrecognizer-bot-sa
.
-
Выполните команду:
yc serverless api-gateway create --name recognizer-bot-api-gw --spec=spec.yaml
Где:
--name
— имя API-шлюза.--spec
— файл со спецификацией.
Результат:
done (5s) id: d5d1ud9bli1e******** folder_id: b1gc1t4cb638******** created_at: "2023-09-25T16:01:48.926Z" name: recognizer-bot-api-gw status: ACTIVE domain: d5dm1lba80md********.i9******.apigw.yandexcloud.net log_group_id: ckgefpleo5eg******** connectivity: {} log_options: folder_id: b1gc1t4cb638********
Чтобы создать API-шлюз:
-
Опишите в конфигурационном файле параметры ресурса
yandex_api_gateway
:resource "yandex_api_gateway" "recognizer-bot-api-gw" { name = "recognizer-bot-api-gw" spec = <<-EOT openapi: 3.0.0 info: title: Sample API version: 1.0.0 paths: /for-recognizer-bot-function: post: x-yc-apigateway-integration: type: cloud_functions function_id: <идентификатор_функции> service_account_id: <идентификатор_сервисного_аккаунта> operationId: for-recognizer-bot-function EOT }
Где:
name
— имя API-шлюза.spec
— спецификация API-шлюза.
Более подробную информацию о параметрах ресурсов в Terraform см. в документации провайдера
. -
Проверьте корректность конфигурационных файлов.
-
В командной строке перейдите в папку, где вы создали конфигурационный файл.
-
Выполните проверку с помощью команды:
terraform plan
Если конфигурация описана верно, в терминале отобразится список создаваемых ресурсов и их параметров. Если в конфигурации есть ошибки, Terraform на них укажет.
-
-
Разверните облачные ресурсы.
-
Если в конфигурации нет ошибок, выполните команду:
terraform apply
-
Подтвердите создание ресурсов: введите в терминал слово
yes
и нажмите Enter.
-
Чтобы создать API-шлюз, воспользуйтесь методом REST API create для ресурса ApiGateway или вызовом gRPC API ApiGatewayService/Create.
Настройте связь между функцией и Telegram-ботом
Установите веб-хук для вашего Telegram-бота:
curl --request POST \
--url https://api.telegram.org/bot<токен_бота>/setWebhook \
--header 'content-type: application/json' \
--data '{"url": "<домен_API-шлюза>/for-recognizer-bot-function"}'
Где:
<токен_бота>
— токен Telegram-бота.<домен_API-шлюза>
— служебный домен API-шлюзаrecognizer-bot-api-gw
.
Результат:
{"ok":true,"result":true,"description":"Webhook was set"}
Протестируйте бота
Поговорите с ботом:
-
Откройте Telegram и найдите бота по указанному имени пользователя
username
. -
Отправьте в чат сообщение
/start
.Бот должен ответить:
Бот умеет: * распознавать текст с картинок; * генерировать голосовые сообщения из текста; * переводить голосовые сообщения в текст.
-
Отправьте в чат текстовое сообщение. Бот ответит голосовым сообщением, синтезированным из вашего текста.
-
Отправьте в чат голосовое сообщение. Бот ответит сообщением с текстом, распознанным из вашей речи.
-
Отправьте в чат изображение с текстом. Бот ответит сообщением с распознанным текстом.
Примечание
Изображение должно соответствовать требованиям.
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы: