Présentation
La période est révolue lorsque chaque deuxième article sur Habrahabr était consacré à la rédaction de son bot de télégramme. En outre, une période de temps s'est écoulée lorsque le bot sans difficulté pouvait être placé sur votre ordinateur ou hébergement en Russie. Il y a six mois, mon bot vient de démarrer sur un ordinateur portable et n'a rencontré aucun problème de connexion à l'API. Mais maintenant, quand j'ai pensé à le remettre au travail, j'ai réalisé que ce ne serait pas si facile. Je ne voulais pas rechercher et configurer un serveur proxy, et encore plus à l'étranger. De plus, avant cela, j'ai écrit le bot dans Wolfram Language et je ne savais pas comment le langage fonctionne avec les serveurs proxy, car je ne les ai pas encore utilisés. Et puis une excellente idée est venue! Utilisez Wolfram Cloud. Dans cet article, je veux montrer à quel point l'enregistrement est très simple, mais sans SMS, vous pouvez démarrer votre bot de télégramme simple écrit en Wolfram Language. Parmi les outils, vous n'avez besoin que d'un navigateur.
Un peu sur le nuage Wolfram
Pour accéder au cloud, vous devez créer un compte Wolfram. Pour ce faire, accédez à https://account.wolfram.com et suivez les instructions après avoir cliqué sur le bouton Créer un.

Après toutes les manipulations effectuées, sur la page principale du cloud à https://www.wolframcloud.com tous les produits et leurs plans d'utilisation seront affichés. Vous devez sélectionner la plateforme de développement et créer un nouveau bloc-notes.

Tout le code donné plus tard sera exécuté dans ce bloc-notes cloud particulier.
Un peu sur les robots télégrammes
De nombreux articles leur sont dédiés. Ici, il suffit de dire qu'avant d'effectuer toutes les autres actions, le bot doit être créé de manière standard. C'est-à -dire, commencez simplement une conversation avec le bot @BotFather et envoyez-lui la commande:
/newbot
Ensuite, il vous suffit de suivre les instructions et d'entrer le nom et la connexion. Que son nom soit Wolfram Cloud Bot et connectez-vous Ă WolframCloud5973827Bot.

Implémentation d'API
Nous profitons des recommandations de @BotFather et examinons brièvement l'API HTTP des bots de télégramme. La tâche d'implémenter la totalité de l'API n'en vaut pas encore la peine. Pour écrire un bot, seule une petite partie suffit. Vérifiez que l'API est accessible et que le bot avec le jeton spécifié ci-dessus existe. Pour ce faire, il suffit de faire une ligne:
URLExecute["https://api.telegram.org/bot753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY/getMe"]
Sortie [..]: = ... {"ok" -> True, "result" -> {"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"}}
La commande ci-dessus est le moyen le plus simple de faire une demande HTTP à partir de Wolfram Language. Mais compliquons-le un peu pour qu'il soit facile d'implémenter toutes les autres méthodes API. Créons une méthode générale pour exécuter une requête API:
TelegramBot::usage = "TelegramBot[token]"; $telegramAPI = "https://api.telegram.org"; telegramExecute[ TelegramBot[token_String], method_String, parameters: {(_String -> _)...}: {} ] := Module[{ request, requestURL, requestRules, requestBody, response, responseBody }, requestURL = URLBuild[{$telegramAPI, "bot" <> token, method}]; requestRules = DeleteCases[parameters, _[_String, Automatic | Null | None]]; requestBody = ImportString[ExportString[requestRules, "JSON"], "Text"]; request = HTTPRequest[requestURL, <| Method -> "POST", "ContentType" -> "application/json; charset=utf-8", "Body" -> requestBody |>]; response = URLRead[request]; responseBody = response["Body"]; Return[ImportString[responseBody, "RawJSON"]] ]
Vérifiez si cela fonctionne avec la méthode déjà testée ci-dessus:
token = "753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY"; bot = TelegramBot[token]; telegramExecute[bot, "getMe"]
Sortie [..]: = ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
Super. Créons une fonction distincte pour effectuer une vérification de bot:
- getMe - informations sur le bot
getMe::usage="getMe[bot]"; TelegramBot /: getMe[bot_TelegramBot] := telegramExecute[bot, "getMe"] getMe[bot]
Sortie [..]: = ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
Maintenant, de manière similaire, il reste à ajouter les méthodes de base nécessaires pour créer un bot dans le cloud:
- getUpdates - récupère tous les derniers messages écrits dans le bot
getUpdates::usage = "getUpdates[bot, opts]"; Options[getUpdates] = { "offset" -> Automatic, "limit" -> Automatic, "timeout" -> Automatic, "allowed_updates" -> Automatic }; TelegramBot /: getUpdates[bot_TelegramBot, opts: OptionsPattern[getUpdates]] := telegramExecute[bot, "getUpdates", Flatten[{opts}]]
- setWebhook - définit l'adresse du serveur pour le traitement des mises à jour
setWebhook::usage = "setWebhook[bot, url, opts]"; Options[setWebhook] = { "certificate" -> Automatic, "max_connections" -> Automatic, "allowed_updates" -> Automatic }; TelegramBot /: setWebhook[bot_TelegramBot, url_String, opts: OptionsPattern[setWebhook]] := telegramExecute[bot, "setWebhook", Join[{"url" -> url}, Flatten[{opts}]]]
deleteWebhook::usage = "deleteWebhook[bot]"; TelegramBot /: deleteWebhook[bot_TelegramBot] := telegramExecute[bot, "deleteWebhook"]
getWebhookInfo::usage = "getWebhookInfo[bot]"; TelegramBot /: getWebhookInfo[bot_TelegramBot] := telegramExecute[bot, "getWebhookInfo"]
sendMessage::usage = "sendMessage[bot, chat, text]"; Options[sendMessage] = { "parse_mode" -> Automatic, "disable_web_page_preview" -> Automatic, "disable_notification" -> Automatic, "reply_to_message_id" -> Automatic, "reply_markup" -> Automatic }; TelegramBot /: sendMessage[bot_TelegramBot, chat_Integer, text_String, opts: OptionsPattern[sendMessage]] := telegramExecute[ bot, "sendMessage", Join[{"chat_id" -> chat, "text" -> text}, Flatten[{opts}]] ]
La version minimale de l'API est prête. Voyons comment fonctionne l'envoi d'un message et la réception des mises à jour. Pour ce faire, créez un chat avec notre bot. Lorsque le bot est créé, le premier message avec le texte / start sera envoyé. Voyons voir s'il est entré dans la liste des mises à jour:
updates = getUpdates[bot]
Sortie [..]: = ... <|"ok" -> True, "result" -> {<|"update_id" -> 570790461, "message" -> <|"message_id" -> 1, "from" -> <|"id" -> 490138492, "is_bot" -> False, "first_name" -> "Kirill", "last_name" -> "Belov", "username" -> "KirillBelovTest"|>, "chat" -> <|"id" -> 490138492, "first_name" -> "Kirill", "last_name" -> "Belov", "username" -> "KirillBelovTest", "type" -> "private"|>, "date" -> 1542182547, "text" -> "/start", "entities" -> {<|"offset" -> 0, "length" -> 6, "type" -> "bot_command"|>}|>|>}|>
Vous pouvez obtenir les dernières données de mise à jour à partir de la liste des mises à jour comme suit:
lastUpdate = updates["result"][[-1]]
Sortie [..]: = ... <|"update_id" -> 570790461, "message" -> <|"message_id" -> 1, "from" -> <|"id" -> 490138492, "is_bot" -> False, "first_name" -> "Kirill", "last_name" -> "Belov", "username" -> "KirillBelovTest"|>, "chat" -> <|"id" -> 490138492, "first_name" -> "Kirill", "last_name" -> "Belov", "username" -> "KirillBelovTest", "type" -> "private"|>, "date" -> 1542182547, "text" -> "/start", "entities" -> {<|"offset" -> 0, "length" -> 6, "type" -> "bot_command"|>}|>|>
Et voici comment vous pouvez obtenir le chat d'oĂą provient le message et le texte du message lui-mĂŞme:
chat = lastUpdate["message", "chat", "id"] text = lastUpdate["message", "text"]
Comme vous pouvez le voir sur le résultat, tout est en place. Nous allons maintenant envoyer un message au nom du bot en utilisant sendMessage.
sendMessage[bot, chat, "hello"]
Sortie [..]: = ... <|"ok" -> True, "result" -> <|"message_id" -> 2, "from" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>, "chat" -> <|"id" -> 490138492, "first_name" -> "Kirill", "last_name" -> "Belov", "username" -> "KirillBelovTest", "type" -> "private"|>, "date" -> 1542182601, "text" -> "hello"|>| >

En général, cet ensemble de fonctions est déjà suffisant. Cependant, l'utilisation de la méthode getUpdates n'est pas très pratique. Vous devez trouver un moyen de gérer les messages à l'aide de webhook.
Création d'un webhook
Wolram Langauge a un type spécial de fonction qui est créé en utilisant APIFunction. En voici un exemple:
apiFunc = APIFunction[{"n" -> "Integer"}, Plot[Sin[#n * x], {x, -2Pi, 2Pi}]&, "PNG"]; apiFunc[{"n"->3}]
Ces fonctionnalités sont spécifiquement conçues pour un déploiement dans le cloud. Cette fonction accepte un paramètre de demande en entrée. Pour le déployer dans le cloud, transférez simplement la fonction elle-même vers CloudDeploy.
apiObject = CloudDeploy[apiFunc, "Deploy/apiObject"]
Sortie [..]: = ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/apiObject]
Ensuite, vous pouvez suivre le lien dans le navigateur et ajouter un paramètre de requête:

La fonction ci-dessus a géré les paramètres de demande. Vous devez donc créer la même fonction pour traiter le corps de la requête HTTP provenant du bot de télégramme sous la forme d'un objet Update. Pour générer l'adresse, nous utilisons un jeton pour accéder à l'objet cloud était plus difficile. Vous devez également indiquer que l'objet a un accès public, sinon les télégrammes ne pourront pas accéder au webhook.
deployWebhook[bot_TelegramBot, handler_] := CloudDeploy[APIFunction[{}, handler[HTTPRequestData["Body"]] &], "Deploy/Webhooks/" <> Hash[bot, "SHA", "HexString"], Permissions -> "Public" ]
handler est un autre gestionnaire de fonctions. Laissez le gestionnaire transformer la chaîne du corps de la demande en association, obtenez l'identifiant de conversation à partir de là et renvoyez le mot "bonjour".
handlerHello[bot_TelegramBot][body_String] := Block[{json = ImportString[body, "RawJSON"], chat}, chat = json["message", "chat", "id"]; sendMessage[bot, chat, "hello"]; ]
Déployez maintenant le funky dans le cloud.
webhookObject = deployWebhook[bot, handlerHello[bot]]
Sortie [..]: = ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/Deploy/Webhooks/b9bd74f89348faecd6b683ba02637dd4d4028a28]
Et la dernière étape consiste à transférer l'adresse de cet objet vers le télégramme bot.
setWebhook[bot, webhookObject[[1]]]
Sortie [..]: = ... <|"ok" -> True, "result" -> True, "description" -> "Webhook was set"|>
Maintenant, nous allons écrire quelque chose pour le bot et voir ce qu'il dit:

Le dialogue peut être considéré comme valide. Afin de changer la logique d'un gestionnaire existant, redéployez simplement l'objet cloud. Dans le même temps, l'installation d'un webhook pour le bot n'est plus nécessaire.
Logique des réponses
Ce sera la dernière partie du processus de création d'un bot dans le cloud Wolfram. De plus, de la même manière, vous pouvez compliquer la logique et ajouter de nouvelles méthodes API. Passons maintenant au dialogue lui-même. Supposons qu'après l'envoi de la commande / start, le bot retourne une réponse «Bonjour» et change le clavier de l'utilisateur. Il ne reste que deux boutons sur le clavier: "Bonjour" et "Qui êtes-vous?" Nous réalisons le dialogue sous forme d'association. Les clés seront les commandes que l'utilisateur envoie au bot. Les valeurs clés sont la réponse du robot lui-même et le nouveau clavier. Dans ce cas, de nombreuses touches et boutons doivent correspondre exactement. Sinon, une situation peut survenir lorsque le bot ne sait pas quoi répondre. Dans de tels cas, bien sûr, vous pouvez ajouter une réponse par défaut.
keyboard[buttons : {__String}] := {"keyboard" -> {Table[{"text" -> button}, {button, buttons}]}, "resize_keyboard" -> True} $answers = <| (*user_text-><|"answer"->bot_text,"keyboard"->next_text|>*) "/start"-><|"answer"->"","keyboard"-> keyboard[{""," ?"}]|>, ""-><|"answer"->" ?", "keyboard" -> keyboard[{" ?"}]|> , " ?"-><|"answer"->"", "keyboard" -> keyboard[{""}]|> , " ?"-><|"answer"->" Wolfram Language ", "keyboard"->keyboard[{" ?"," ?"}]|> , " ?"-><|"answer"->" :\nhttps://habr.com/post/422517/", "keyboard"->keyboard[{""," ?"}]|> , " ?"-><|"answer"->" :\n@KirillBelovTest", "keyboard"->keyboard[{" ?",""}]|> , ""-><|"answer"->"", "keyboard"->keyboard[{""," ?"}]|> |>; answer[text_String] /; KeyExistsQ[$answers, text] := $answers[text]
Créez maintenant un gestionnaire:
handlerAbout[bot_TelegramBot][body_String] := Block[{json = ImportString[body, "RawJSON"], chat, text}, chat = json["message", "chat", "id"]; text = json["message", "text"]; sendMessage[bot, chat, answer[text]["answer"], "reply_markup" -> answer[text]["keyboard"]]; ]
Et redéployez l'objet cloud:
deployWebhook[bot, handlerAbout[bot]];
Vérifions ce qui s'est passé dans le chat avec le bot. Mais d'abord, effaçons l'historique des messages:

Extension de fonctionnalité
Jusqu'à présent, il n'y a pas de différences fondamentales avec le grand nombre de robots existants. Peut-être que ça ne sert à rien non plus? Le sens de tout le travail effectué ci-dessus sera, si vous comprenez quels sont les avantages d'un tel bot! Après tout, il peut utiliser toutes les fonctionnalités de Wolfram Language et Wolrfam Cloud. Est-il nécessaire que le robot résolve des équations? C'est très simple! Vous avez juste besoin de redéfinir la réponse!
answer[text_String]["keyboard"] /; StringContainsQ[text, " "] := Automatic answer[text_String]["answer"] /; StringContainsQ[text, " "] := ToString[Flatten[Block[{args = StringSplit[text, " "]}, Solve[ToExpression[args[[1]]], ToExpression[args[[2]]]] ]]] deployWebhook[bot, handlerAbout[bot]];

Si quelqu'un s'intéresse en outre aux capacités du cloud, alors une bonne description de ses fonctionnalités est ici .
Limitations
Wolfram Cloud est une plate-forme qui vous permet d'utiliser gratuitement le langage Wolfram, tandis que le produit principal de Wolfram Research, Mathematica, coûte de l'argent. En conséquence, il existe des restrictions d'utilisation et, à mon avis, elles sont très fortes. Lors de l'utilisation de la version gratuite de la plateforme de développement, un utilisateur reçoit 1 000 crédits cloud par mois. Chaque prêt cloud donne le temps de calculer un type différent. Étant donné que l'article parle de CloudDeploy + APIFunction, ces objets stockés dans le cloud dépensent 1 crédit en 0,1 seconde de temps de calcul. Il est facile de calculer que l'utilisateur ne dispose gratuitement que de 1 minute et 40 secondes de temps serveur pour le fonctionnement de son application (dans ce cas, le bot). Je n'ai rien à ajouter ici - c'est très, très petit. L'accent principal est mis sur les utilisateurs qui travaillent indépendamment dans la plateforme de développement à l'aide d'un navigateur. En effet, dans ce mode il n'y a pas de limite de temps, mais uniquement en fonction de la durée de la session et des ressources allouées. Avec cette utilisation, la plate-forme de développement est presque un Mathematica complet, mais ne nécessite ni installation ni licence.
→ Article et code dans Wolfram Cloud