Задать вопрос
grantur5707
@grantur5707
Full Stack Web Developer

Почему обработчик события отправки данных из WebApp в бота не срабатывает и бот не подхватывает это событие?

WebApp реализован в HTML и JavaScript. При выборе картинки js код должен отправлять выбранный вариант при помощи метода Telegram.WebApp.sendData(data) в JSON-формате и WebApp должен закрывать.

webapp.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Выбор варианта</title>
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
</head>
<body>
    <h3>Выберите один из предложенных вариантов:</h3>
    <div id="variants">
        <script type="text/javascript">
            Telegram.WebApp.ready();

            const path = `${window.location.origin}/userData/`;

            const parsedUrl = new URL(document.URL);
            const userId = Telegram.WebApp.initDataUnsafe.user.id;
            const previewImages = parsedUrl.searchParams.get("images");

            const imagesArray = previewImages ? JSON.parse(previewImages) : [];

            imagesArray.forEach((image, index) => {
                const imgElement = document.createElement("img");
                imgElement.src = path + userId + "/" + image;
                imgElement.alt = `Вариант ${index + 1}`;
                imgElement.style.width = "100px";
                imgElement.style.margin = "5px";
                imgElement.onclick = () => selectOption(index);
                document.getElementById("variants").appendChild(imgElement);
            });

            function selectOption(index) {
                const data = JSON.stringify({ selected_variant: index });
                Telegram.WebApp.sendData(data);
                Telegram.WebApp.close();
            }
        </script>
    </div>
</body>
</html>


Бот в Telegram должен принимать данные WebApp с помощью обработчика web_app_data, определённого в коде боат следующим образом:

run.py:

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton, WebAppInfo
from telegram.ext import CommandHandler, MessageHandler, filters, CallbackContext, CallbackQueryHandler, Application
import os
import logging
import time
import json
from urllib.parse import urlencode

from config import *
from utils.image_processing import *

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)

logging.getLogger("httpx").setLevel(logging.WARNING)

logger = logging.getLogger(__name__)

def message_format(lines):
    return "\n".join(lines)

async def start(update: Update, context: CallbackContext) -> None:
    welcome_message_lines = [
        "Добро пожаловать! ",
        "",
        "Чтобы начать обработку, нажмите кнопку ниже и отправьте фото.",
        "Рекомендации к фото:",
        "1. Фото должно быть четким.",
        "2. Предпочтительно использовать горизонтальную ориентацию.",
        "3. Избегайте слишком маленьких объектов на фото."
    ]
    
    keyboard = [[InlineKeyboardButton("/preview", callback_data='preview')]]
    reply_markup = InlineKeyboardMarkup(keyboard)

    await update.message.reply_text(message_format(welcome_message_lines), reply_markup=reply_markup)

async def preview(update: Update, context: CallbackContext) -> None:
    await update.callback_query.answer()
    await update.callback_query.message.reply_text("Пожалуйста, отправьте фото для обработки.")

async def handle_photo(update: Update, context: CallbackContext) -> None:
    user_id = update.effective_user.id
    timestamp = int(time.time())

    user_dir = f"/var/www/www-root/data/www/***/userData/{user_id}"
    if not os.path.exists(user_dir):
        os.makedirs(user_dir)

    photo_file = await update.message.photo[-1].get_file()
    photo_path = f"photo_{timestamp}.jpg"
    await photo_file.download_to_drive(user_dir + "/" + photo_path)

    notify_message_lines = [
        "Фото получено! ️",
        "Начинаю обработку...",
        "Пожалуйста, подождите несколько секунд."
    ]
    
    await update.message.reply_text(message_format(notify_message_lines))

    preview_images = process_image(user_dir, photo_path, PALETTE, PREVIEW_SIZE, MAX_PIXELS_PER_COLOR)

    context.user_data['preview_images'] = preview_images

    images_param = json.dumps(preview_images)
    query_params = urlencode({'images': images_param})

    web_app_url = f"https://***?{query_params}"

    keyboard = InlineKeyboardMarkup(
        [[InlineKeyboardButton(text="Выбрать вариант", web_app=WebAppInfo(url=web_app_url))]]
    )
    await update.message.reply_text("Обработка завершена! Нажмите кнопку ниже, чтобы выбрать вариант.", reply_markup=keyboard)

async def web_app_data(update: Update, context: CallbackContext) -> None:
    data = json.loads(update.effective_message.web_app_data.data)
    variant_index = int(data.get("selected_variant"))

    print(variant_index)

def main():
    application = Application.builder().token(BOT_TOKEN).build()

    application.add_handler(CommandHandler("start", start))
    application.add_handler(MessageHandler(filters.PHOTO, handle_photo))
    application.add_handler(CallbackQueryHandler(preview, pattern='^preview$'))
    application.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, web_app_data))

    application.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == '__main__':
    main()


В main() добавлен MessageHandler с фильтром filters.StatusUpdate.WEB_APP_DATA для обработки данных WebApp, но не понятно по какой причине данный обработчик не срабатывает. Проведены отладочные проверки с использованием фильтров ALL и логирования всех типов обновлений, но обновление с типом WEB_APP_DATA не приходит в бота, несмотря на то, что Telegram.WebApp.sendData() корректно отправляет данные и WebApp закрывается.
  • Вопрос задан
  • 158 просмотров
Подписаться 1 Простой 7 комментариев
Пригласить эксперта
Ответы на вопрос 1
@kaiser_ego
Удалось решить проблему? тоже сейчас с этим мучаюсь.
Форма работает в веб клиенте, но не работает в клиентах.
@dp.message(F.web_app_data) ловит данные sendData вызванные инлайн кнопкой, но при условии что это веб форма.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы