I do chat bots for telegrams. At the moment there is a multi-dimensional menu that works on callback inline buttons. Everything would be fine, but there is a problem: for example, a person clicks to order , then selects a product. Then he needs to enter the address and time of delivery, as well as the phone and so on.

Please tell me how this can be done? Those. if a person simply enters the delivery address, he will be given a " not selected product " or " error ", and if he chooses a product, he will follow this scenario and so on.

The question is how to make a script?


My code ( for example, php , library telegram-bot-sdk ):

 <?php DEFINE('ROOT', 'root const here'); require_once(ROOT.'components/Db.php'); require_once(ROOT.'models/Product.php'); include('vendor/autoload.php'); //include telegram-bot-sdk use Telegram\Bot\Api; use Telegram\Bot\Keyboard\Keyboard; use Telegram\Bot\Actions; use Telegram\Bot\Commands\Command; use Telegram\Bot\Objects\CallbackQuery; $telegram = new Api('api token here'); //Устанавливаем токен, полученный у BotFather $result = $telegram -> getWebhookUpdates(); //Передаем в переменную $result полную информацию о сообщении пользователя $keyboard = Keyboard::make() ->inline() ->row( Keyboard::inlineButton(['text' => 'Показать меню', 'callback_data' => '/show_menu']), Keyboard::inlineButton(['text' => 'Купить цветы', 'callback_data' => '/buyflowers']) ); $keyboard_flowers = Keyboard::make() ->inline() ->row( Keyboard::inlineButton(['text' => 'Розы', 'callback_data' => '/buyflowers_roses']) ) ->row( Keyboard::inlineButton(['text' => 'Пионы', 'callback_data' => '/buyflowers_piony']) ) ->row( Keyboard::inlineButton(['text' => 'Шляпные коробки', 'callback_data' => '/buyflowers_hatbox']) ) ->row( Keyboard::inlineButton(['text' => 'Коробочки со сладостями', 'callback_data' => '/buyflowers_sweetbox']) ) ->row( Keyboard::inlineButton(['text' => 'Акции и спецпредложения', 'callback_data' => '/buyflowers_sales']) ); $keyboard_menu = Keyboard::make() ->inline() ->row( Keyboard::inlineButton(['text' => 'Связаться с нами', 'callback_data' => '/contact_us']) ) ->row( Keyboard::inlineButton(['text' => 'Купить цветы', 'callback_data' => '/buyflowers']) ) ->row( Keyboard::inlineButton(['text' => 'Стать партнером', 'callback_data' => '/partner']) ) ->row( Keyboard::inlineButton(['text' => 'Перейти на сайт', 'url' => 'https://kands.spb.ru/']) ) ->row( Keyboard::inlineButton(['text' => 'Акции и спецпредложения', 'callback_data' => '/buyflowers_sales']) ); $contact = $result['message']['contact']; $text = $result["message"]["text"]; //Текст сообщения $chat_id = $result["message"]["chat"]["id"]; $name = $result["message"]["from"]["username"]; //Юзернейм пользователя if ($result->isType('callback_query')) { $data = $result['callback_query']['data']; $chat = $result['callback_query']['message']['chat']['id']; switch ($data) { case '/buyflowers': $telegram->sendMessage([ 'chat_id' => $chat, 'text' => 'Выберите категорию:', 'reply_markup' => $keyboard_flowers ]); break; case '/show_menu': $telegram->sendMessage([ 'chat_id' => $chat, 'text' => 'Меню: ', 'reply_markup' => $keyboard_menu ]); break; default: # code... break; } } $telegram->sendMessage([ 'chat_id' => $chat_id, 'text' => 'Стартовая страница. Выберите дальнейшие действия.', 'reply_markup' => $keyboard ]); ?> ` 
  • since similarly stable questions are asked once a week / two (and alarms are often rejected), I suggest making the question general and adapting it accordingly - Anatol
  • one
    @Anatol if you see a question, the answer to which is already in another question - mark with a duplicate (as if you already do that). Make a common someone's question is possible only at the request of the author. - Nick Volynkin
  • Possible duplicate of the question: Text processing from the Telegram command in Python - Pavel Durmanov
  • @PavelDurmanov how can this be a duplicate if this question is several months older? Mark a duplicate on your link - Anatol
  • @Anatol does not negate the fact that it is a duplicate. And there you can find the answer - Pavel Durmanov February

1 answer 1

There are at least three options ( options can be combined ):

  1. Use a key-value type collection , where chat_id is used as a key, and an arbitrary identifier of the previous / next step of the script as the value ( conceptually, it can be absolutely any necessary data ). After receiving the next message from the user, check the status of the script with the value of the collection element for this chat.
  2. Use ForseReply when sending messages with address requests, etc., and then check incoming messages for the presence of a non-empty reply_to_message field and look at the text of this field. Depending on its content, it will be possible to understand exactly which step of the script is being executed.
  3. Use the built-in buttons ( inline buttons ) . Inline button differs from the usual button in that it does not send text to the chat. Instead, a callback , programmatically set and invisible to the user, is sent. Accordingly, you can use any text ( such as step1 or this_is_unexpected_step ) as callback_data , then waiting for the required callback when receiving updates

Example for the variant with ForseReply ( pseudocode ):

 // Производится запрос адреса пользователя Bot.SendChatAction(update.Message.Chat.Id, ChatAction.Typing); Bot.SendTextMessage(update.Message.Chat.Id, "Укажите адрес доставки", replyMarkup: force_reply); ... // Проверка полученных сообщений от пользователя if (update.Message.ReplyToMessage.Text.Contains("адрес доставки")) { if (!IsValidAddress(update.Message.ReplyToMessage.Text)) return; SaveAddressToDb(update.Message.Chat.Id, update.Message.ReplyToMessage.Text); Bot.SendChatAction(update.Message.Chat.Id, ChatAction.Typing); Bot.SendTextMessage(update.Message.Chat.Id, "Адрес успешно сохранён, ожидайте поступления заказа"); } else { ... } 

Related question on en SO