TelegramBot na nuvem Wolfram

1. Introdução


O período passou quando cada segundo artigo sobre Habrahabr foi dedicado a escrever seu bot de telegrama. Além disso, passou um período em que o bot sem dificuldades poderia ser colocado no seu computador ou hospedagem na Rússia. Seis meses atrás, meu bot acabou de iniciar em um laptop e não teve problemas ao conectar-se à API. Mas agora, quando pensei em fazê-lo voltar ao trabalho, percebi que não seria tão fácil. Eu não queria pesquisar e configurar um servidor proxy, e mais ainda no exterior. Além disso, antes disso, escrevi o bot na Wolfram Language e não fazia ideia de como a linguagem funciona com servidores proxy, pois ainda não os usei. E então surgiu uma ótima idéia! Use Wolfram Cloud. Neste artigo, quero mostrar o quão simples é o registro, mas sem o SMS, você pode iniciar seu bot de telegrama simples, escrito em Wolfram Language. Das ferramentas, você só precisa de um navegador.


Um pouco sobre a nuvem Wolfram


Para acessar a nuvem, você precisa criar uma conta Wolfram. Para fazer isso, acesse https://account.wolfram.com e siga as instruções depois de clicar no botão Criar um.



Após todas as manipulações feitas, na página principal da nuvem em https://www.wolframcloud.com, todos os produtos e seus planos de uso serão exibidos. Você deve selecionar a Plataforma de Desenvolvimento e criar um novo notebook.



Todo o código fornecido posteriormente será executado neste notebook em nuvem específico.


Um pouco sobre bots de telegrama


Existem muitos artigos dedicados a eles. Aqui, basta dizer que antes de executar todas as ações adicionais, o bot deve ser criado da maneira padrão. Ou seja, basta iniciar uma conversa com o bot @BotFather e enviar a ele o comando:


/newbot 

Então você só precisa seguir as instruções e inserir o nome e o login. Deixe o nome dele ser Wolfram Cloud Bot e faça o login @ WolframCloud5973827Bot.



Implementação de API


Aproveitamos as recomendações do @BotFather e examinamos brevemente a API HTTP dos bots de telegrama. A tarefa de implementar toda a API ainda não vale a pena. Para escrever um bot, apenas uma pequena parte é suficiente. Verifique se a API está acessível e se existe o bot com o token especificado acima. Para fazer isso, basta fazer uma linha:


 URLExecute["https://api.telegram.org/bot753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY/getMe"] 

Fora [..]: = ...
 {"ok" -> True, "result" -> {"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"}} 

O comando acima é a maneira mais fácil de fazer uma solicitação HTTP da Wolfram Language. Mas vamos complicar um pouco, para que seja fácil implementar todos os outros métodos de API. Vamos criar um método geral para executar uma solicitação de 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"]] ] 

Verifique se isso funciona no método já testado acima:


 token = "753681357:AAFqdRFN_QoODJxsBy3VN2sVwWTPKJEqteY"; bot = TelegramBot[token]; telegramExecute[bot, "getMe"] 

Fora [..]: = ...
 <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|> 

Ótimo. Vamos criar uma função separada para executar uma verificação de bot:


  • getMe - informações sobre bot

 getMe::usage="getMe[bot]"; TelegramBot /: getMe[bot_TelegramBot] := telegramExecute[bot, "getMe"] getMe[bot] 

Fora [..]: = ...
 <|"ok" -> True, "result" -> <|"id" -> 753681357, "is_bot" -> True, "first_name" -> "Wolfram Cloud Bot", "username" -> "WolframCloud5973827Bot"|>|> 

Agora, de maneira semelhante, resta adicionar os métodos básicos necessários para criar um bot na nuvem:


  • getUpdates - recebe todas as últimas mensagens gravadas no 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 - define o endereço do servidor para processar atualizações

 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}]] ] 

A versão mínima da API está pronta. Vamos verificar como funciona o envio de uma mensagem e o recebimento de atualizações. Para fazer isso, crie um bate-papo com o nosso bot. Quando o bot é criado, a primeira mensagem com o texto / start será enviada. Vamos ver se ele entrou na lista de atualizações:


 updates = getUpdates[bot] 

Fora [..]: = ...
 <|"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"|>}|>|>}|> 

Você pode obter os dados de atualização mais recentes da lista de atualizações da seguinte maneira:


 lastUpdate = updates["result"][[-1]] 

Fora [..]: = ...
 <|"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"|>}|>|> 

E é assim que você pode obter o bate-papo de onde a mensagem veio e o próprio texto da mensagem:


 chat = lastUpdate["message", "chat", "id"] text = lastUpdate["message", "text"] 

Fora [..]: = ...
 490138492 /start 

Como você pode ver no resultado, tudo está no lugar. Agora enviaremos uma mensagem em nome do bot usando sendMessage.


 sendMessage[bot, chat, "hello"] 

Fora [..]: = ...
 <|"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"|>| > 


Em geral, esse conjunto de funções já é suficiente. No entanto, o uso do método getUpdates não é muito conveniente. Você precisa criar uma maneira de lidar com mensagens usando o webhook.


Criando webhook


O Wolram Langauge possui um tipo especial de função criada usando a função APIF. Aqui está um exemplo de um destes:


 apiFunc = APIFunction[{"n" -> "Integer"}, Plot[Sin[#n * x], {x, -2Pi, 2Pi}]&, "PNG"]; apiFunc[{"n"->3}] 

Fora [..]: = ...


Esses recursos foram projetados especificamente para implantação na nuvem. Esta função aceitará um parâmetro de solicitação como entrada. Para implantá-lo na nuvem, basta transferir a própria função para o CloudDeploy.


 apiObject = CloudDeploy[apiFunc, "Deploy/apiObject"] 

Fora [..]: = ...
 CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/apiObject] 

Em seguida, você pode seguir o link no navegador e adicionar um parâmetro de consulta:



A função acima tratou dos parâmetros de solicitação. Portanto, você precisa criar a mesma função para processar o corpo da solicitação HTTP proveniente do bot de telegrama na forma de um objeto Update. Para gerar o endereço, usamos um token para obter acesso ao objeto em nuvem era mais difícil. Também é necessário indicar que o objeto tem acesso público, caso contrário, os telegramas não poderão acessar o webhook.


 deployWebhook[bot_TelegramBot, handler_] := CloudDeploy[APIFunction[{}, handler[HTTPRequestData["Body"]] &], "Deploy/Webhooks/" <> Hash[bot, "SHA", "HexString"], Permissions -> "Public" ] 

handler é outro manipulador de função. Deixe o manipulador transformar a sequência do corpo da solicitação em uma associação, obtenha o identificador de bate-papo a partir daí e envie de volta a palavra "olá".


 handlerHello[bot_TelegramBot][body_String] := Block[{json = ImportString[body, "RawJSON"], chat}, chat = json["message", "chat", "id"]; sendMessage[bot, chat, "hello"]; ] 

Agora implante o funky na nuvem.


 webhookObject = deployWebhook[bot, handlerHello[bot]] 

Fora [..]: = ...
 CloudObject[https://www.wolframcloud.com/objects/kirillbelovtest/Deploy/Webhooks/b9bd74f89348faecd6b683ba02637dd4d4028a28] 

E o último passo é transferir o endereço desse objeto para o bot de telegrama.


 setWebhook[bot, webhookObject[[1]]] 

Fora [..]: = ...
 <|"ok" -> True, "result" -> True, "description" -> "Webhook was set"|> 

Agora vamos escrever algo para o bot e ver o que ele diz:



O diálogo pode ser considerado válido. Para alterar a lógica de um manipulador existente, basta reimplementar o objeto de nuvem. Ao mesmo tempo, não é mais necessário instalar um webhook para o bot.


Lógica de respostas


Esta será a última parte do processo de criação de um bot na nuvem Wolfram. Além disso, da mesma maneira, você pode complicar a lógica e adicionar novos métodos de API. Agora sobre o próprio diálogo. Suponha que depois de enviar o comando / start, o bot retorne uma resposta "Hello" e mude o teclado do usuário. Apenas dois botões permanecem no teclado: "Olá" e "Quem é você?" Percebemos o diálogo na forma de uma associação. As chaves serão os comandos que o usuário envia ao bot. Os valores das teclas são a resposta do bot em si e o novo teclado. Nesse caso, muitas teclas e botões devem corresponder exatamente. Caso contrário, pode surgir uma situação em que o bot não sabe o que responder. Nesses casos, é claro, você pode adicionar uma resposta padrão.


 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] 

Agora crie um manipulador:


 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"]]; ] 

E reimplemente o objeto de nuvem:


 deployWebhook[bot, handlerAbout[bot]]; 

Vamos verificar o que aconteceu no bate-papo com o bot. Mas primeiro, vamos limpar o histórico de mensagens:



Extensão de funcionalidade


Até o momento, não há diferenças fundamentais em relação ao grande número de bots existentes. Talvez não faça sentido beber também? O significado de todo o trabalho realizado acima será, se você entender quais são as vantagens desse bot! Afinal, ele pode usar todos os recursos do Wolfram Language e Wolrfam Cloud. É necessário que o robô resolva equações? É muito fácil! Você só precisa redefinir a resposta!


 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]]; 


Se alguém também tiver interesse nos recursos da nuvem, aqui está uma boa descrição de sua funcionalidade.


Limitações


O Wolfram Cloud é uma plataforma que permite o uso gratuito da linguagem Wolfram, enquanto o principal produto da Wolfram Research, Mathematica, custa dinheiro. Por conseguinte, existem restrições à utilização e, na minha opinião, são muito fortes. Ao usar a versão gratuita da Plataforma de Desenvolvimento, um usuário recebe 1000 créditos de nuvem por mês. Cada empréstimo na nuvem dá tempo para calcular um tipo diferente. Como o artigo fala sobre o CloudDeploy + APIFunction, esses objetos armazenados na nuvem gastam 1 crédito em 0,1 segundo de tempo de computação. É fácil calcular que o usuário recebe gratuitamente apenas 1 minuto e 40 segundos de tempo do servidor para a operação de seu aplicativo (neste caso, o bot). Não tenho nada a acrescentar aqui - é muito, muito pequeno. A ênfase principal está nos usuários que trabalham independentemente na Plataforma de Desenvolvimento usando um navegador. De fato, nesse modo, não há limites de tempo, mas apenas de acordo com a duração da sessão e os recursos alocados. Com esse uso, a Plataforma de Desenvolvimento é quase um Mathematica completo, mas não requer instalação e licença.


Artigo e código no Wolfram Cloud

Source: https://habr.com/ru/post/pt422517/


All Articles