Einführung
Die Zeit ist vergangen, in der jeder zweite Artikel über Habrahabr dem Schreiben seines Telegrammbot gewidmet war. Außerdem verging eine Zeitspanne, in der der Bot ohne Schwierigkeiten auf Ihrem Computer oder Hosting in Russland platziert werden konnte. Vor sechs Monaten startete mein Bot gerade auf einem Laptop und hatte keine Probleme mit der Verbindung zur API. Aber jetzt, als ich darüber nachdachte, ihn wieder zur Arbeit zu bringen, wurde mir klar, dass es nicht so einfach sein würde. Ich wollte keinen Proxyserver suchen und konfigurieren, und noch mehr im Ausland. Außerdem habe ich vorher den Bot in Wolfram Language geschrieben und hatte keine Ahnung, wie die Sprache mit Proxyservern funktioniert, da ich sie noch nicht verwendet habe. Und dann kam eine großartige Idee! Verwenden Sie Wolfram Cloud. In diesem Artikel möchte ich zeigen, wie einfach die Registrierung ist, aber ohne SMS können Sie Ihren einfachen Telegramm-Bot starten, der in Wolfram Language geschrieben ist. Von den Tools benötigen Sie nur einen Browser.
Ein bisschen über die Wolfram-Wolke
Um auf die Cloud zugreifen zu können, müssen Sie ein Wolfram-Konto erstellen. Gehen Sie dazu zu https://account.wolfram.com und befolgen Sie die Anweisungen, nachdem Sie auf die Schaltfläche Create One geklickt haben.

Nach allen vorgenommenen Manipulationen werden auf der Hauptseite der Cloud unter https://www.wolframcloud.com alle Produkte und ihre Verwendungspläne angezeigt. Sie müssen die Entwicklungsplattform auswählen und ein neues Notizbuch erstellen.

Der gesamte später angegebene Code wird in diesem speziellen Cloud-Notizbuch ausgeführt.
Ein bisschen über Telegramm-Bots
Es gibt viele Artikel, die ihnen gewidmet sind. Hier muss nur gesagt werden, dass der Bot vor dem Ausführen aller weiteren Aktionen auf die übliche Weise erstellt werden muss. Starten Sie einfach einen Chat mit dem @ BotFather-Bot und senden Sie ihm den folgenden Befehl:
/newbot
Dann müssen Sie nur noch den Anweisungen folgen und den Namen und das Login eingeben. Sein Name sei Wolfram Cloud Bot und login @ WolframCloud5973827Bot.

API-Implementierung
Wir nutzen die Empfehlungen von @BotFather und untersuchen kurz die HTTP-API von Telegramm-Bots. Die Implementierung der gesamten API lohnt sich noch nicht. Um einen Bot zu schreiben, reicht nur ein kleiner Teil. Überprüfen Sie, ob auf die API zugegriffen werden kann und der Bot mit dem oben angegebenen Token vorhanden ist. Machen Sie dazu nur eine Zeile:
URLExecute["https://api.telegram.org/bot753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY/getMe"]
Out [..]: = ... {"ok" -> True, "result" -> {"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"}}
Der obige Befehl ist der einfachste Weg, eine HTTP-Anfrage von Wolfram Language aus zu stellen. Aber lassen Sie es uns etwas komplizieren, damit es einfach ist, alle anderen API-Methoden zu implementieren. Erstellen wir eine allgemeine Methode zum Ausführen einer API-Anforderung:
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"]] ]
Überprüfen Sie, ob dies mit der oben bereits getesteten Methode funktioniert:
token = "753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY"; bot = TelegramBot[token]; telegramExecute[bot, "getMe"]
Out [..]: = ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
Großartig. Erstellen wir eine separate Funktion zum Durchführen einer Bot-Prüfung:
- getMe - bot Informationen
getMe::usage="getMe[bot]"; TelegramBot /: getMe[bot_TelegramBot] := telegramExecute[bot, "getMe"] getMe[bot]
Out [..]: = ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
In ähnlicher Weise müssen nun die grundlegenden Methoden hinzugefügt werden, die zum Erstellen eines Bots in der Cloud erforderlich sind:
- getUpdates - Ruft die neuesten Nachrichten ab, die an den Bot geschrieben wurden
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 - Legt die Serveradresse für die Verarbeitung von Updates fest
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}]] ]
Die Mindestversion der API ist bereit. Lassen Sie uns überprüfen, wie das Senden einer Nachricht und das Empfangen von Updates funktioniert. Erstellen Sie dazu einen Chat mit unserem Bot. Wenn der Bot erstellt wird, wird die erste Nachricht mit dem Text / start gesendet. Mal sehen, ob es in die Liste der Updates aufgenommen wurde:
updates = getUpdates[bot]
Out [..]: = ... <|"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"|>}|>|>}|>
Sie können die neuesten Aktualisierungsdaten wie folgt aus der Liste der Aktualisierungen abrufen:
lastUpdate = updates["result"][[-1]]
Out [..]: = ... <|"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"|>}|>|>
Und so erhalten Sie den Chat, aus dem die Nachricht stammt, und den Nachrichtentext selbst:
chat = lastUpdate["message", "chat", "id"] text = lastUpdate["message", "text"]
Wie Sie dem Ergebnis entnehmen können, ist alles vorhanden. Jetzt senden wir mit sendMessage eine Nachricht im Namen des Bots.
sendMessage[bot, chat, "hello"]
Out [..]: = ... <|"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"|>| >

Im Allgemeinen reicht dieser Funktionsumfang bereits aus. Die Verwendung der Methode getUpdates ist jedoch nicht sehr praktisch. Sie müssen einen Weg finden, um Nachrichten mit Webhook zu verarbeiten.
Webhook erstellen
Wolram Langauge hat eine spezielle Art von Funktion, die mit APIFunction erstellt wird. Hier ist ein Beispiel für eines davon:
apiFunc = APIFunction[{"n" -> "Integer"}, Plot[Sin[#n * x], {x, -2Pi, 2Pi}]&, "PNG"]; apiFunc[{"n"->3}]
Diese Funktionen wurden speziell für die Bereitstellung in der Cloud entwickelt. Diese Funktion akzeptiert einen Anforderungsparameter als Eingabe. Um es in der Cloud bereitzustellen, übertragen Sie einfach die Funktion selbst auf CloudDeploy.
apiObject = CloudDeploy[apiFunc, "Deploy/apiObject"]
Out [..]: = ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/apiObject]
Dann können Sie dem Link im Browser folgen und einen Abfrageparameter hinzufügen:

Die obige Funktion hat die Anforderungsparameter behandelt. Sie müssen also dieselbe Funktion erstellen, um den Text der HTTP-Anforderung zu verarbeiten, die vom Telegrammbot in Form eines Aktualisierungsobjekts kommt. Um die Adresse zu generieren, verwenden wir ein Token, um Zugriff auf das Cloud-Objekt zu erhalten, was schwieriger war. Es muss auch angegeben werden, dass das Objekt öffentlich zugänglich ist, da sonst Telegramme nicht zum Webhook gelangen können.
deployWebhook[bot_TelegramBot, handler_] := CloudDeploy[APIFunction[{}, handler[HTTPRequestData["Body"]] &], "Deploy/Webhooks/" <> Hash[bot, "SHA", "HexString"], Permissions -> "Public" ]
Handler ist ein weiterer Funktionshandler. Lassen Sie den Handler die Zeichenfolge des Anforderungshauptteils in eine Zuordnung verwandeln, von dort die Chat-ID abrufen und das Wort "Hallo" zurücksenden.
handlerHello[bot_TelegramBot][body_String] := Block[{json = ImportString[body, "RawJSON"], chat}, chat = json["message", "chat", "id"]; sendMessage[bot, chat, "hello"]; ]
Stellen Sie nun den Funky in der Cloud bereit.
webhookObject = deployWebhook[bot, handlerHello[bot]]
Out [..]: = ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/Deploy/Webhooks/b9bd74f89348faecd6b683ba02637dd4d4028a28]
Der letzte Schritt besteht darin, die Adresse dieses Objekts an den Telegrammbot zu übertragen.
setWebhook[bot, webhookObject[[1]]]
Out [..]: = ... <|"ok" -> True, "result" -> True, "description" -> "Webhook was set"|>
Jetzt schreiben wir etwas für den Bot und sehen, was darin steht:

Der Dialog kann als gültig angesehen werden. Um die Logik eines vorhandenen Handlers zu ändern, stellen Sie das Cloud-Objekt einfach erneut bereit. Gleichzeitig müssen Sie den Webhook für den Bot nicht mehr installieren.
Logik der Antworten
Dies ist der letzte Teil beim Erstellen eines Bots in der Wolfram-Cloud. Auf die gleiche Weise können Sie die Logik komplizieren und neue API-Methoden hinzufügen. Nun zum Dialog selbst. Angenommen, der Bot gibt nach dem Senden des Befehls / start eine Antwort "Hallo" zurück und ändert die Tastatur des Benutzers. Es bleiben nur zwei Tasten auf der Tastatur: "Hallo" und "Wer bist du?" Wir realisieren den Dialog in Form eines Vereins. Die Schlüssel sind die Befehle, die der Benutzer an den Bot sendet. Die Schlüsselwerte sind die Bot-Antwort selbst und die neue Tastatur. In diesem Fall sollten viele Tasten und Knöpfe genau übereinstimmen. Andernfalls kann es vorkommen, dass der Bot nicht weiß, was er antworten soll. In solchen Fällen können Sie natürlich eine Standardantwort hinzufügen.
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]
Erstellen Sie nun einen Handler:
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"]]; ]
Und stellen Sie das Cloud-Objekt erneut bereit:
deployWebhook[bot, handlerAbout[bot]];
Lassen Sie uns überprüfen, was im Chat mit dem Bot passiert ist. Aber zuerst löschen wir den Nachrichtenverlauf:

Funktionserweiterung
Bisher gibt es keine grundsätzlichen Unterschiede zu der Vielzahl der vorhandenen Bots. Vielleicht macht es auch keinen Sinn, es zu trinken? Die Bedeutung aller oben geleisteten Arbeit wird sein, wenn Sie verstehen, was die Vorteile eines solchen Bots sind! Immerhin kann er alle Funktionen von Wolfram Language und Wolrfam Cloud nutzen. Muss der Roboter Gleichungen lösen? Es ist sehr einfach! Sie müssen nur die Antwort neu definieren!
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]];

Wenn jemand zusätzlich Interesse an den Funktionen der Cloud hat, finden Sie hier eine gute Beschreibung ihrer Funktionalität.
Einschränkungen
Wolfram Cloud ist eine Plattform, auf der Sie die Wolfram-Sprache kostenlos verwenden können, während das Hauptprodukt von Wolfram Research, Mathematica, Geld kostet. Dementsprechend gibt es Einschränkungen bei der Verwendung und meiner Meinung nach sind sie sehr stark. Bei Verwendung der kostenlosen Version der Entwicklungsplattform erhält ein Benutzer 1000 Cloud-Credits pro Monat. Jeder Cloud-Kredit gibt Zeit, um einen anderen Typ zu berechnen. Da der Artikel über CloudDeploy + APIFunction spricht, verbrauchen solche in der Cloud gespeicherten Objekte 1 Guthaben in 0,1 Sekunden Rechenzeit. Es ist leicht zu berechnen, dass der Benutzer nur 1 Minute und 40 Sekunden Serverzeit für den Betrieb seiner Anwendung (in diesem Fall des Bots) kostenlos erhält. Ich habe hier nichts hinzuzufügen - es ist sehr, sehr klein. Das Hauptaugenmerk liegt auf Benutzern, die unabhängig in der Entwicklungsplattform mit einem Browser arbeiten. In diesem Modus gibt es keine zeitlichen Beschränkungen, sondern nur nach der Dauer der Sitzung und den zugewiesenen Ressourcen. Bei dieser Verwendung ist die Entwicklungsplattform fast eine vollständige Mathematica, erfordert jedoch keine Installation und Lizenz.
→ Artikel und Code in Wolfram Cloud