引言
这段时期过去了,关于哈布拉哈伯的每第二篇文章都致力于编写其电报机器人。 此外,一段时间后,可以轻松地将漫游器放置在您的计算机上或托管在俄罗斯。 六个月前,我的机器人刚刚在笔记本电脑上启动,并且在连接到API时没有遇到任何问题。 但是现在,当我想到让他重返工作岗位时,我意识到这并非易事。 我不想搜索和配置代理服务器,在国外甚至更多。 另外,在此之前,我用Wolfram语言编写了该机器人,却不知道该语言如何与代理服务器一起工作,因为我还没有使用过它们。 然后一个好主意出现了! 使用Wolfram Cloud。 在本文中,我想展示如何简单地进行注册,但是如果没有SMS,您可以启动用Wolfram语言编写的简单电报机器人。 在这些工具中,您仅需要浏览器。
关于Wolfram云的一点点
要访问云,您需要创建一个Wolfram帐户。 为此,请访问https://account.wolfram.com,并单击“创建一个”按钮后按照说明进行操作。

完成所有操作后,将在云的主页https://www.wolframcloud.com上显示所有产品及其使用计划。 您必须选择开发平台并创建一个新的笔记本。

稍后给出的所有代码将在此特定的云笔记本中执行。
关于电报机器人的一些知识
有许多专门针对他们的文章。 在这里,仅需说在执行所有其他操作之前,必须以标准方式创建机器人。 也就是说,只需与@BotFather机器人开始聊天并向他发送命令:
/newbot
然后,您只需要按照说明输入名称并登录即可。 让他的名字叫Wolfram Cloud Bot并登录@ WolframCloud5973827Bot。

API实施
我们利用@BotFather的建议,并简要检查电报机器人的HTTP API。 实现整个API的任务还不值得。 要编写机器人,只需一小部分就足够了。 检查该API是否可访问,并且存在具有上述指定令牌的漫游器。 为此,只需执行一行:
URLExecute["https://api.telegram.org/bot753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY/getMe"]
出[..]:= ... {"ok" -> True, "result" -> {"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"}}
上面的命令是从Wolfram语言发出HTTP请求的最简单方法。 但是让我们复杂一点,以便于实现所有其他API方法。 让我们创建一个执行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"]] ]
检查这是否适用于上面已经测试过的方法:
token = "753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY"; bot = TelegramBot[token]; telegramExecute[bot, "getMe"]
出[..]:= ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
太好了 让我们创建一个单独的函数来执行机器人检查:
getMe::usage="getMe[bot]"; TelegramBot /: getMe[bot_TelegramBot] := telegramExecute[bot, "getMe"] getMe[bot]
出[..]:= ... <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|>
现在,以类似的方式可以添加在云中创建机器人所需的基本方法:
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::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}]] ]
该API的最低版本已准备就绪。 让我们检查发送消息和接收更新的工作方式。 为此,请与我们的机器人进行聊天。 创建漫游器后,将发送带有/起始文本的第一条消息。 让我们看看它是否进入了更新列表:
updates = getUpdates[bot]
出[..]:= ... <|"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"|>}|>|>}|>
您可以从更新列表中获取最新的更新数据,如下所示:
lastUpdate = updates["result"][[-1]]
出[..]:= ... <|"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"|>}|>|>
这就是您如何获得消息的聊天记录以及消息文本本身的方法:
chat = lastUpdate["message", "chat", "id"] text = lastUpdate["message", "text"]
从结果中可以看到,一切就绪。 现在,我们将使用sendMessage代表机器人发送一条消息。
sendMessage[bot, chat, "hello"]
出[..]:= ... <|"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"|>| >

通常,这组功能已经足够。 但是,使用getUpdates方法不是很方便。 您需要提出一种使用webhook处理消息的方法。
创建webhook
Wolram Langauge具有使用APIFunction创建的一种特殊功能。 这是其中之一的示例:
apiFunc = APIFunction[{"n" -> "Integer"}, Plot[Sin[#n * x], {x, -2Pi, 2Pi}]&, "PNG"]; apiFunc[{"n"->3}]
这些功能是专门为在云中部署而设计的。 此函数将接受一个请求参数作为输入。 要将其部署到云中,只需将功能本身转移到CloudDeploy。
apiObject = CloudDeploy[apiFunc, "Deploy/apiObject"]
出[..]:= ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/apiObject]
然后,您可以在浏览器中单击链接并添加查询参数:

上面的函数处理了请求参数。 因此,您需要创建相同的函数来处理来自电报机器人的HTTP请求的主体(以Update对象的形式)。 为了生成地址,我们使用令牌来访问云对象更加困难。 还必须指出该对象具有公共访问权限,否则电报将无法访问网络挂钩。
deployWebhook[bot_TelegramBot, handler_] := CloudDeploy[APIFunction[{}, handler[HTTPRequestData["Body"]] &], "Deploy/Webhooks/" <> Hash[bot, "SHA", "HexString"], Permissions -> "Public" ]
handler是另一个函数处理程序。 让处理程序将请求主体的字符串转换为关联,从那里获取聊天标识符,然后将单词“ hello”发送回去。
handlerHello[bot_TelegramBot][body_String] := Block[{json = ImportString[body, "RawJSON"], chat}, chat = json["message", "chat", "id"]; sendMessage[bot, chat, "hello"]; ]
现在将时髦部署在云中。
webhookObject = deployWebhook[bot, handlerHello[bot]]
出[..]:= ... CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/Deploy/Webhooks/b9bd74f89348faecd6b683ba02637dd4d4028a28]
最后一步是将该对象的地址传输到电报机器人。
setWebhook[bot, webhookObject[[1]]]
出[..]:= ... <|"ok" -> True, "result" -> True, "description" -> "Webhook was set"|>
现在,我们将为该机器人编写一些内容,并查看其内容:

对话可以被认为是有效的。 为了更改现有处理程序的逻辑,只需重新部署云对象。 同时,您将不再需要为该机器人安装webhook。
答案逻辑
这将是在Wolfram云中创建机器人的过程的最后一部分。 此外,您可以用相同的方式使逻辑复杂化并添加新的API方法。 现在介绍对话本身。 假设在发送/ start命令后,该机器人返回了“ Hello”响应并更改了用户的键盘。 键盘上只剩下两个按钮:“你好”和“你是谁?” 我们以协会的形式实现对话。 密钥将是用户发送给机器人的命令。 关键值是漫游器响应本身和新键盘。 在这种情况下,许多按键和按钮应该完全匹配。 否则,当机器人不知道该怎么回答时,可能会出现这种情况。 当然,在这种情况下,您可以添加默认答案。
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]
现在创建一个处理程序:
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"]]; ]
并重新部署云对象:
deployWebhook[bot, handlerAbout[bot]];
我们来验证一下与机器人聊天时发生的情况。 但是首先,让我们清除消息历史记录:

功能扩展
到目前为止,与大量现有的机器人没有根本的区别。 也许喝酒也没有意义吗? 如果您了解这种机器人的优势,那么上面完成的所有工作的意义将是! 毕竟,他可以使用Wolfram语言和Wolrfam Cloud的所有功能。 机器人有必要求解方程吗? 这很容易! 您只需要重新定义答案即可!
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]];

如果另外有人对云的功能感兴趣,那么可以在此处对其功能进行详细描述。
局限性
Wolfram Cloud是一个平台,可让您免费使用Wolfram语言,而Wolfram Research的主要产品Mathematica则要花钱。 因此,使用受到限制,我认为这些限制非常严格。 使用免费版本的开发平台时,每月为用户提供1000个云积分。 每笔云贷款都提供了时间来计算不同的类型。 由于本文讨论的是CloudDeploy + APIFunction,因此存储在云中的此类对象会在0.1秒的计算时间内花费1积分。 可以很容易地计算出,仅为用户免费提供了1分钟40秒的服务器时间来运行其应用程序(在本例中为bot)。 我在这里没有要补充的内容-它很小,非常小。 主要重点是使用浏览器在Development Platform中独立工作的用户。 实际上,在此模式下没有时间限制,而仅根据会话的持续时间和分配的资源。 通过这种使用,开发平台几乎可以构成完整的Mathematica,但不需要安装和许可。
→ Wolfram Cloud中的文章和代码