Python TamTam机器人开发


哈Ha! 让我自我介绍:我叫Sergey Agaltsov,我是“生活中的程序员”。 这意味着我长期以来一直是IT经理,完全不是专业的程序员,但是我经常在自己的主要活动和业余爱好中使用编程。 正如我以前的一位老板经常说的那样:“ Seryoga!您再次陷入编程之中!” 没错,我不能说他或其他任何人对此都不满意。


在TamTam Messenger上出现Bot API之后,作为一个真正的程序员,因此我是懒惰的程序员,我创建了2个Python库来使用它:



因此,有一个特定的TamTam Python SDK。


我首先“为了自己,为了灵魂”做到了这一点,但也建议TamTam社区(如果需要)使用它。 但是,正如您所知,没有一件好事会受到惩罚-人们要求写一篇培训文章。 这是我的这篇文章。 在其中,我将告诉您如何使用这些库开发一个简单的机器人。


挑战赛


开发旨在简化机器人开发人员操作的机器人。 该机器人应以状态bot-api的永久轮询(长时间轮询)模式工作。 在本文中,该机器人将经过训练以显示发送给他的消息的内部,并且还将其配置为与开发的功能匹配。


据了解,读者已经安装了连接到PyCharm开发环境的Python 3 git (开发环境可能有所不同,但故事将基于PyCharm)。 了解OOP的基础是可取的。


获取机器人令牌


通过调用专用机器人@PrimeBot获得令牌。


我们在TamTam中找到该机器人,输入/ create命令并回答以下问题:


  • 输入机器人的唯一简称(用拉丁字母)-这是机器人的用户名,可以通过@或形式为https://tt.me/username的链接来使用它。 用户名没有特别限制。 特别是,bot这个词是可选的。
  • 输入名称-这是机器人的显示名称。 在这里您已经可以使用西里尔字母。

如果正确输入所有内容,则创建的漫游器将添加到联系人中,作为回报,我们将收到令牌-一系列字符,格式为:HDyDvomx6TfsXkgwfFCUY410fv-vbf4XVjr8JVSUu4c。


初始设定


显示

创建目录:


 mkdir ttBotDevHelper 

转到它:


 cd ttBotDevHelper/ 

我们初始化git仓库:


 git init 

下载必要的库,将它们添加为git的子模块:


 git submodule add https://github.com/asvbkr/openapi_client.git openapi_client git submodule add https://github.com/asvbkr/TamTamBot.git TamTamBot 

我们在PyCharm中打开创建的目录(例如,从资源管理器中的上下文菜单“以PyCharm项目打开文件夹”下),并创建一个我们的机器人将包含的文件-File / New / Python文件。 在出现的对话框中,输入名称-ttBotDevHelper,并回答添加到git的问题。


现在,我们需要为项目创建一个虚拟环境。


要创建虚拟环境,请选择“文件/设置”,然后在“项目”选项卡上选择“项目解释器”子项。 接下来,在右侧,点击齿轮图标,然后选择添加:


图片


PyCharm将提供自己的住宿选择。


图片


同意他是有意义的。


创建虚拟环境后,将打开上一个屏幕,但该屏幕已经包含有关创建的环境的信息。 在此屏幕上,您需要通过单击右侧的“ +”图标并输入软件包名称来安装必要的软件包:


  • 要求

然后,我们将.gitignore文件添加到项目中,不包括git中不需要的文件,其内容如下:


 venv/ .idea/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class *.log *.log.* .env ttb.sqlite3 

添加一个名为TT_BOT_API_TOKEN 的环境变量 ,在其中我们指示从https://tt.me/primebot接收到的机器人标记的值,然后重新启动PyCharm。


(!) PyCharm最好使用特殊的.env文件,而不是直接将环境变量添加到OS环境。 其配置将在下面讨论。


恭喜,现在您可以继续进行最有趣的部分-编写机器人。


简单的机器人启动


打开ttBotDevHelper.py文件并编写第一行:


 # -*- coding: UTF-8 -*- from TamTamBot.TamTamBot import TamTamBot class BotDevHelper(TamTamBot): pass 

在这里,我们基于TamTamBot类创建bot类。


PyCharm建议BotDevHelper类包含需要实现的抽象方法。 在类名称上按Alt-Enter,选择“实施抽象方法”,选择PyCharm提出的所有方法(其中2种),然后单击“确定”。 结果,将添加两个空属性方法:令牌和描述。 我们修改结果代码如下:


 # -*- coding: UTF-8 -*- import os from TamTamBot.TamTamBot import TamTamBot from TamTamBot.utils.lng import set_use_django class BotDevHelper(TamTamBot): @property def token(self): return os.environ.get('TT_BOT_API_TOKEN') @property def description(self): return '       .\n\n' \ 'This bot is an helper in the development and management of bots.' if __name__ == '__main__': set_use_django(False) BotDevHelper().polling() 

token属性返回我们机器人的令牌,其值来自环境变量TT_BOT_API_TOKENdescription属性返回我们机器人的扩展描述,它将显示给用户。


要在状态轮询模式下运行我们的漫游器,需要文件末尾的代码。


我注意到基类TamTamBot涉及使用django Web服务器在Web挂钩模式下工作。 但是现在任务变得更简单了,我们不需要django,这就是我们在set_use_django(False)中报告的set_use_django(False) 。 在这里,为我们类的对象调用polling()方法,以确保在所需模式下进行操作。


完成了最低限度的工作。 该代码已经相当有效。 运行它来运行。 为此,请按组合键Ctrl-Shift-F10。


如果您之前没有将环境变量直接添加到操作系统,则在启动时会出现错误消息“ No access_token”。 要解决此问题,请将PyCharm配置为使用.env文件。


展示如何

创建一个.env文本文件。 在我们的情况下,其内容应如下:


 TT_BOT_API_TOKEN=__ 

现在,您需要将其连接到PyCharm中的启动配置:


我们选择运行/编辑配置,然后在EnvFile选项卡上连接我们的.env文件:


图片


然后单击“应用”。


启动机器人后,您可以转到TamTam,与我们的机器人打开对话框,然后单击“开始”按钮。 该机器人将报告有关其隐藏的超能力的信息。 这意味着该机器人正在运行。 当机器人在演示模式下工作时,有4个命令可用。 只需检查一下。


尽管机器人对该机器人的冷静发表了明确的意见,但他还是胆怯地暗示了一个事实,即到目前为止,他什么也做不了。 教导他征服世界所需的一切是我们的任务。


接收源消息并发送带有源消息内部表示的响应消息


我们将阻止receive_text()方法,当向机器人发送文本到聊天室时,该方法的控制权将被转移:


  def receive_text(self, update): res = self.msg.send_message(NewMessageBody(f' : {update.message}', link=update.link), user_id=update.user_id) return bool(res) 

传递给此方法的UpdateCmn类的update对象包含各种有用的信息,尤其是我们现在需要的所有信息:


  • update.message包含消息本身的对象;
  • update.link此消息的就绪响应链接;
  • update.user_id发送消息的用户的标识符。

要从漫游器发送消息,我们使用self.msg变量,该变量包含MessagesApi对象,该对象实现API说明messages部分中描述的功能 。 该对象包含我们send_message()send_message()方法,该方法提供消息的发送。 至少,必须将此方法传递给NewMessageBody类的对象和目标(在本例中为用户ID)。


反过来,在这种情况下, NewMessageBody类的对象是通过发送源消息对象的文本表示形式以及到源消息的响应链接来创建的。


我们重新启动僵尸程序,并与僵尸程序进行对话,检查该僵尸程序对包含源消息对象内部表示的任何消息产生响应。


此状态的源代码在此处


添加带有参数的新bot命令-通过其标识符显示消息的内部表示


开发机器人时,通常需要使用一个或多个已知消息标识符(消息ID-中)查看消息的内部表示。 将此功能添加到我们的机器人中。 为此,首先,我们采用一种单独的方法来输出有关消息内部表示的信息的功能:


  def view_messages(self, update, list_mid, link=None): res = False msgs = self.msg.get_messages(message_ids=list_mid) if msgs: for msg in msgs.messages: r = self.msg.send_message(NewMessageBody(f' {msg.body.mid}:\n`{msg}`'[:NewMessageBody.MAX_BODY_LENGTH], link=link), user_id=update.user_id) res = res or r return res 

在这种方法中,我们将列表传递给中间。


要获取消息对象,我们使用self.msg.get_messages方法,该方法返回messages属性中的对象列表。


此外,每个接收到的消息的文本表示形式都以单独的消息发送到我们的对话中。 为避免错误,生成的消息的文本将被最大消息长度的常量NewMessageBody.MAX_BODY_LENGTH截断。


然后添加一种处理命令的方法。 我们称之为vmp 。 您可以将中间列表传递给带有空格的命令。


TTB的设计使命令处理程序应作为名为cmd_handler_%s的方法创建,其中%s是命令的名称。 即 对于vmp命令,该方法将称为cmd_handler_vmpUpdateCmn类的对象传递给命令处理程序。 此外,对于命令,它可能包含cmd_args属性,该属性包含使用命令输入的行和单词的字典


该代码将如下所示:


  def cmd_handler_vmp(self, update): res = None if not update.this_cmd_response: #    ,       if update.cmd_args: #        list_id = [] parts = update.cmd_args.get('c_parts') or [] if parts: for line in parts: for part in line: list_id.append(str(part)) if list_id: res = self.view_messages(update, list_id, update.link) return bool(res) 

我们重启机器人。 现在,如果您在漫游器对话框中键入以下命令: /vmp mid1 mid2 (您可以将其先前的检查作为mid),那么作为回报,对于每个传输的mid,我们都会得到两条带有内部消息源消息对象的消息。


此状态的源代码在此处


修改用于处理文本响应的bot命令


您也可以尝试从其他频道/聊天转发消息。 但是在这种情况下,只会显示与机器人对话时源消息中包含的内容。 特别是在发送消息时,不会保存按钮信息。


但是,如果我们想查看有关原始消息的信息怎么办? 在这种情况下,您需要从转发的消息中抽中。


为了实现此模式,我们修改了vmp命令,以便在不带参数的情况下调用该命令时,它希望消息被转发,然后,它使用已发送消息的中间并显示有关该消息的信息。


(!)为使此功能正确运行,必须授予漫游器从频道/聊天源读取的权限。


我们将命令代码修改如下:


  def cmd_handler_vmp(self, update): res = None if not update.this_cmd_response: #    ,       if update.cmd_args: #        list_id = [] parts = update.cmd_args.get('c_parts') or [] if parts: for line in parts: for part in line: list_id.append(str(part)) if list_id: res = self.view_messages(update, list_id, update.link) else: #      self.msg.send_message(NewMessageBody(f' **  /    :'), user_id=update.user_id) update.required_cmd_response = True #       else: #    message = update.message link = message.link #       link #  -   . if link and link.type == MessageLinkType.FORWARD: res = self.view_messages(update, [link.message.mid], update.link) else: #         ,    . self.msg.send_message(NewMessageBody(f'.  **   /. , .'), user_id=update.user_id) return False return bool(res) 

由于 使用这种方法,由于缺少消息访问权限,风险会增加,然后在view_messages()方法中添加检查是否符合请求/接收的消息数量的方法:


  def view_messages(self, update, list_mid, link=None): res = False msgs = self.msg.get_messages(message_ids=list_mid) if msgs: #    mid     if len(msgs.messages) < len(list_mid): self.msg.send_message(NewMessageBody( f'     .    @{self.username}  /  .', link=update.link ), user_id=update.user_id) return False else: for msg in msgs.messages: r = self.msg.send_message(NewMessageBody(f' {msg.body.mid}:\n`{msg}`'[:NewMessageBody.MAX_BODY_LENGTH], link=link), user_id=update.user_id) res = res or r return res 

我们重新启动漫游器,给出/ vmp命令,并且在显示有关转发必要性的提示后,我们从频道/ chat转发消息。 如果漫游器有权在此频道/聊天中阅读消息,则将显示转发的消息对象的文本表示形式。 如果没有访问权限,该漫游器将报告可能的问题,并将等待从正确的源进行转发。


设置机器人属性


现在仍然可以带来光泽。 让我们关闭about属性,该属性返回机器人开始工作时显示的文本以及/ start命令。


  @property def about(self): return '       .' 

我们将阻止get_commands()方法,该方法返回机器人的命令列表,该列表显示在机器人的对话框中。


  def get_commands(self): # type: () -> [BotCommand] commands = [ BotCommand('start', ' '), BotCommand('menu', ' '), BotCommand('vmp', '  '), ] return commands 

让我们关闭main_menu_buttons属性,该属性返回由/ menu命令调用的主菜单上的按钮列表。


  def main_menu_buttons(self): # type: () -> [] buttons = [ #       -  [CallbackButtonCmd(' ', 'start')], #        - .    -  [CallbackButtonCmd('  ', 'vmp', intent=Intent.POSITIVE)], ] return buttons 

我们重启机器人,确保一切正常。 恭喜,您创建了第一个机器人,尽管有一些玩具,但它具有非常强大的功能。


此状态的源代码在此处


可以在这里看到正在运行的@devhelpbot机器人。


现在就这些了。 如果您对该主题感兴趣,那么在以下文章中,我将考虑该机器人的进一步开发。 例如,添加自定义按钮(尤其是“是/否”)并进行处理,发送各种类型的内容(文件,照片等),在网络摘机模式下工作等。


顺便说一句,您可以在特殊聊天中快速提问。 直接的建议/想法在那里。

Source: https://habr.com/ru/post/zh-CN466373/


All Articles