Разработка Telegram-бота для распознавания текста на изображениях, синтеза и распознавания аудио
Важно
Часть ресурсов, необходимых для прохождения практического руководства, доступны только в регионе Россия.
Примечание
В регионе Казахстан доступна только версия API v3.
В этом руководстве вы создадите бота для 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 BillingACTIVEилиTRIAL_ACTIVE. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Необходимые платные ресурсы
В стоимость поддержки Telegram-бота входят:
- плата за использование SpeechKit (см. тарифы для SpeechKit);
- плата за использование Vision OCR (см. тарифы для Vision OCR);
- плата за количество вызовов функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик (см. тарифы для Cloud Functions);
- плата за количество запросов к созданному API-шлюзу и исходящий трафик (см. тарифы API Gateway).
Подготовьте ресурсы
- 
Создайте сервисный аккаунт с именем recognizer-bot-saи назначьте ему ролиai.editor,functions.editorна ваш каталог.
- 
Скачайте - 
Извлеките из архива бинарные файлы ffmpeg,ffprobeи сделайте их исполняемыми, выполнив команды:chmod +x ffmpeg chmod +x ffprobe
- 
Подготовьте ZIP-архив с кодом функции: - 
Создайте файл index.pyи добавьте в него указанный ниже код.index.pyimport logging import requests import telebot import json import os import base64 from speechkit import model_repository, configure_credentials, creds from speechkit.stt import AudioProcessingType folder_id = "" iam_token = '' # Эндпоинт сервиса распознавания изображений и данные для аутентификации API_TOKEN = os.environ['TELEGRAM_TOKEN'] vision_url = 'https://ocr.api.yandexcloud.kz/ocr/v1/recognizeText' # Добавление папки с ffmpeg в системный PATH 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.yandexcloud.kz/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.yandexcloud.kz/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) with open(export_path, 'rb') as voice: 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 result = model.transcribe(audio_data) speech_text = [res.normalized_text for res in result] return ' '.join(speech_text) # Синтез речи def synthesize(text, export_path): model = model_repository.synthesis_model() # Настройки синтеза model.voice = 'kirill' result = model.synthesize(text, raw_format=False) result.export(export_path, 'ogg')
- 
Создайте файл requirements.txtи укажите в нем библиотеку для работы с ботом и библиотеку Python SDK.pyTelegramBotAPI==4.27 yandex-speechkit==1.5.0
- 
Добавьте в ZIP-архив index.zipфайлыindex.py,requirements.txt,ffmpegиffprobe.
 
- 
- 
Создайте бакет 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.
- 
Память — 256 МБ.
- 
Сервисный аккаунт — recognizer-bot-sa.
- 
Переменные окружения: - TELEGRAM_TOKEN— токен вашего бота в Telegram.
 
 
- 
- 
Нажмите кнопку Сохранить изменения. 
 
- 
Если у вас еще нет интерфейса командной строки Yandex Cloud (CLI), установите и инициализируйте его.
По умолчанию используется каталог, указанный при создании профиля CLI. Чтобы изменить каталог по умолчанию, используйте команду yc config set folder-id <идентификатор_каталога>. Также для любой команды вы можете указать другой каталог с помощью параметров --folder-name или --folder-id.
- 
Создайте функцию 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=256m \ --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: "268435456" 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********
Terraform
Terraform распространяется под лицензией Business Source License
Подробную информацию о ресурсах провайдера смотрите в документации на сайте Terraform
Если у вас еще нет Terraform, установите его и настройте провайдер Yandex Cloud.
- 
Опишите в конфигурационном файле параметры функции: resource "yandex_function" "for-recognizer-bot-function" { name = "for-recognizer-bot" user_hash = "first function" runtime = "python312" entrypoint = "index.handler" memory = "256" 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 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.Бот должен ответить: Бот умеет: * распознавать текст с картинок; * генерировать голосовые сообщения из текста; * переводить голосовые сообщения в текст.
- 
Отправьте в чат текстовое сообщение. Бот ответит голосовым сообщением, синтезированным из вашего текста. 
- 
Отправьте в чат голосовое сообщение. Бот ответит сообщением с текстом, распознанным из вашей речи. 
- 
Отправьте в чат изображение с текстом. Бот ответит сообщением с распознанным текстом. Примечание Изображение должно соответствовать требованиям. 
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы: