Pengembangan bot Python TamTam


Halo, Habr! Izinkan saya memperkenalkan diri: nama saya Sergey Agaltsov, dan saya seorang "programmer in life." Ini berarti bahwa saya telah lama menjadi manajer TI, dan sama sekali bukan programmer karena profesi, tetapi saya menggunakan pemrograman terus-menerus, baik dalam kegiatan utama saya maupun sebagai hobi. Seperti yang sering dikatakan salah satu mantan bos saya - "Seryoga! Anda kembali masuk ke pemrograman!" Benar, saya tidak bisa mengatakan bahwa dia atau siapa pun pernah merasa sangat tidak puas dengan ini.


Setelah kemunculan Bot API pada messenger TamTam, saya, sebagai programmer yang benar, dan karena itu malas, membuat 2 pustaka Python untuk bekerja dengannya:


  • API klien terbuka (selanjutnya - OAC) - awalnya membuatnya menggunakan Generator OpenAPI berdasarkan skema API, kemudian mengadaptasinya dengan mempertimbangkan fitur-fitur generator;
  • shell untuk klien ini adalah TamTamBot (selanjutnya - TTB), yang menyederhanakan pekerjaan dengan OAC.

Jadi ada SDK TamTam Python tertentu.


Saya melakukan ini pertama-tama "untuk diri saya sendiri, untuk jiwa", tetapi juga menyarankan agar komunitas TamTam, jika diinginkan, menggunakannya. Tapi, seperti yang Anda tahu, tidak ada satu pun perbuatan baik yang tidak dihukum - orang diminta untuk menulis artikel pelatihan. Dan di sinilah saya dengan artikel ini. Di dalamnya, saya akan memberi tahu Anda cara mengembangkan bot sederhana menggunakan perpustakaan ini.


Tantangan


Kembangkan bot yang dirancang untuk menyederhanakan tindakan pengembang bot. Bot harus bekerja dalam mode polling permanen negara-api (polling panjang). Dalam artikel ini, bot akan dilatih untuk menunjukkan bagian dalam dari pesan yang dikirim kepadanya, dan juga dikonfigurasi agar sesuai dengan fungsionalitas yang dikembangkan.


Dapat dipahami bahwa pembaca telah menginstal Python 3 , git , terhubung ke lingkungan pengembangan PyCharm (lingkungan pengembangan mungkin berbeda, tetapi ceritanya akan didasarkan pada PyCharm). Memahami dasar-dasar OOP diinginkan.


Mendapatkan token bot


Token diperoleh melalui panggilan ke bot khusus @PrimeBot


Kami menemukan bot ini di TamTam, masukkan perintah / buat dan jawab pertanyaan:


  • Masukkan nama pendek unik bot dalam huruf Latin - ini adalah nama pengguna bot yang dengannya bot akan tersedia melalui @ atau dengan tautan dari formulir https://tt.me/username . Tidak ada batasan khusus pada nama pengguna. Secara khusus, kata bot adalah opsional.
  • Masukkan nama - ini adalah nama tampilan bot. Di sini Anda sudah bisa menggunakan alfabet Cyrillic.

Jika semuanya dimasukkan dengan benar, maka bot yang dibuat akan ditambahkan ke kontak dan sebagai imbalannya kami akan menerima token - urutan karakter bentuk: HDyDvomx6TfsXkgwfFCUY410fv-vbf4XVjr8JVSUu4c.


Pengaturan awal


Tampilkan

Buat direktori:


 mkdir ttBotDevHelper 

Pergi ke sana:


 cd ttBotDevHelper/ 

Kami menginisialisasi repositori git:


 git init 

Unduh pustaka yang diperlukan, dengan menambahkannya sebagai submodul git:


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

Kami membuka direktori yang dibuat di PyCharm (misalnya, dari penjelajah di bawah menu konteks "Buka Folder sebagai proyek PyCharm") dan membuat file yang bot kami akan berisi - File / New / Python file. Pada dialog yang muncul, masukkan nama - ttBotDevHelper, dan jawablah secara positif pertanyaan penambahan ke git.


Sekarang kita perlu membuat lingkungan virtual untuk proyek kita.


Untuk membuat lingkungan virtual, pilih File / Pengaturan dan pilih subkunci Project Interpreter pada tab proyek. Selanjutnya, di sebelah kanan, klik ikon roda gigi dan pilih Tambahkan:


gambar


PyCharm akan menawarkan opsi akomodasi sendiri.


gambar


Masuk akal untuk setuju dengannya.


Setelah membuat lingkungan virtual, layar sebelumnya akan terbuka, tetapi itu sudah akan berisi informasi tentang lingkungan yang dibuat. Pada layar ini, Anda perlu menginstal paket yang diperlukan dengan mengklik ikon "+" di sebelah kanan dan memasukkan nama paket:


  • permintaan
  • enam

Kemudian kami menambahkan file .gitignore ke proyek, tidak termasuk file yang tidak diperlukan di git, dengan konten berikut:


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

Tambahkan variabel lingkungan bernama TT_BOT_API_TOKEN , di mana kami menunjukkan nilai token bot kami yang diterima dari https://tt.me/primebot dan mulai ulang PyCharm.


(!) Alih-alih menambahkan variabel lingkungan langsung ke lingkungan OS, PyCharm secara optimal menggunakan file .env khusus. Konfigurasi akan dibahas di bawah.


Selamat, sekarang Anda dapat melanjutkan ke bagian yang paling menarik - menulis bot Anda.


Peluncuran bot sederhana


Buka file ttBotDevHelper.py dan tulis baris pertama:


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

Di sini kita membuat kelas bot kita berdasarkan kelas TamTamBot.


PyCharm menyarankan bahwa kelas BotDevHelper berisi metode abstrak yang perlu diimplementasikan. Tekan Alt-Enter pada nama kelas, pilih "Terapkan metode abstrak", pilih semua metode (2 dari mereka) yang diusulkan oleh PyCharm dan klik OK. Akibatnya, dua metode properti kosong akan ditambahkan: token dan deskripsi. Kami memodifikasi kode yang dihasilkan sebagai berikut:


 # -*- 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() 

Properti token mengembalikan token bot kami, yang nilainya diambil dari variabel lingkungan TT_BOT_API_TOKEN . Properti description mengembalikan deskripsi panjang bot kami, yang akan ditampilkan kepada pengguna.


Kode di akhir file diperlukan untuk menjalankan bot kami dalam mode polling status.


Saya perhatikan bahwa kelas dasar TamTamBot melibatkan penggunaan server web Django untuk bekerja dalam mode web hook. Tapi sekarang tugasnya lebih sederhana, dan kami tidak perlu Django, yang kami laporkan di baris set_use_django(False) . Di sini, metode polling() dipanggil untuk objek kelas kami, yang memastikan operasi dalam mode yang diperlukan.


Minimal yang perlu dilakukan. Kode ini sudah cukup berfungsi. Jalankan untuk menjalankan. Untuk melakukan ini, tekan kombinasi tombol Ctrl-Shift-F10.


Jika Anda tidak menambahkan variabel lingkungan lebih awal, langsung ke OS, maka kesalahan dengan pesan "No access_token" akan terjadi saat startup. Untuk memperbaikinya, konfigurasikan PyCharm untuk menggunakan file .env.


Tunjukkan caranya

Buat file teks .env. Isinya dalam kasus kami adalah sebagai berikut:


 TT_BOT_API_TOKEN=__ 

Sekarang Anda harus menghubungkannya ke konfigurasi peluncuran di PyCharm:


Kami memilih Jalankan / Edit konfigurasi dan pada tab EnvFile kami menghubungkan file .env kami:


gambar


Kemudian klik Terapkan.


Setelah memulai bot, Anda dapat pergi ke TamTam, membuka dialog dengan bot kami dan klik tombol "Mulai". Bot akan melaporkan informasi tentang negara adidaya yang tersembunyi. Ini berarti bot berfungsi. Sementara bot bekerja dalam mode demo, di mana 4 perintah tersedia. Lihat saja.


Terlepas dari pendapat yang jelas dari bot tentang kesejukannya, dia dengan malu-malu mengisyaratkan fakta bahwa sejauh ini dia tidak bisa melakukan apa-apa. Untuk mengajarinya segala yang diperlukan untuk penaklukan dunia adalah tugas kita.


Menerima pesan sumber dan mengirim pesan tanggapan dengan representasi internal dari pesan sumber


Kami akan memblokir metode receive_text() , kontrol yang ditransfer saat mengirim teks ke obrolan dengan bot:


  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) 

Objek update kelas UpdateCmn , yang diteruskan ke metode ini, berisi berbagai informasi yang berguna dan, khususnya, semua yang kita butuhkan sekarang:


  • update.message - objek yang berisi pesan itu sendiri;
  • update.link - tautan respons siap ke pesan ini;
  • update.user_id - pengidentifikasi pengguna yang mengirim pesan.

Untuk mengirim pesan dari bot, kami menggunakan variabel self.msg , yang berisi objek MessagesApi yang mengimplementasikan fungsionalitas yang dijelaskan di bagian pesan pada deskripsi API . Objek ini berisi metode send_message() yang kami send_message() , yang menyediakan pengiriman pesan. Minimal, metode ini harus melewati objek kelas NewMessageBody dan tujuan - ID pengguna, dalam kasus kami.


Pada gilirannya, objek kelas NewMessageBody dalam hal ini dibuat dengan mengirimkan representasi tekstual dari objek pesan sumber dan tautan respons ke pesan sumber.


Kami memulai ulang bot kami dan memeriksa dalam dialog dengan bot bahwa bot menghasilkan respons terhadap pesan kami yang berisi representasi internal dari objek pesan sumber.


Kode sumber untuk status ini ada di sini .


Menambahkan perintah bot baru dengan parameter - menampilkan representasi internal pesan oleh pengidentifikasi


Ketika mengembangkan bot, seringkali diperlukan untuk melihat representasi internal dari pesan menggunakan satu atau lebih pengidentifikasi pesan yang dikenal (id pesan pertengahan). Tambahkan fungsi ini ke bot kami. Untuk melakukan ini, pertama-tama, kami menggunakan secara terpisah fungsi untuk menghasilkan informasi tentang representasi internal pesan:


  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 

Dalam metode ini, kami melewati daftar mid.


Untuk mendapatkan objek pesan, kami menggunakan metode self.msg.get_messages , yang mengembalikan daftar objek di properti pesan.


Selanjutnya, representasi tekstual dari masing-masing pesan yang diterima dikirim ke dialog kami dalam pesan terpisah. Untuk menghindari kesalahan, teks dari pesan yang dihasilkan dipotong oleh konstanta dari panjang pesan maksimum - NewMessageBody.MAX_BODY_LENGTH .


Kemudian tambahkan metode yang memproses perintah. Sebut saja vmp . Anda bisa melewati daftar tengah ke perintah dengan spasi.


TTB dirancang sehingga penangan perintah harus dibuat sebagai metode dengan nama cmd_handler_%s , di mana% s adalah nama perintah. Yaitu untuk perintah vmp, metode ini akan dipanggil cmd_handler_vmp . Objek dari kelas UpdateCmn diteruskan ke penangan perintah. Selain itu, untuk sebuah perintah, ini mungkin berisi properti cmd_args , yang berisi kamus baris dan kata-kata di dalamnya yang dimasukkan dengan perintah


Kode akan terlihat seperti ini:


  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) 

Kami me-restart bot. Sekarang, jika Anda mengetik perintah dalam dialog bot seperti: /vmp mid1 mid2 (Anda dapat mengambil cek pertengahan mereka sebelumnya), maka sebagai gantinya kami mendapatkan dua pesan dengan representasi internal dari objek pesan sumber, untuk masing-masing mid yang ditransmisikan.


Kode sumber untuk status ini ada di sini .


Modifikasi perintah bot untuk bekerja dengan respons teks


Anda juga dapat mencoba meneruskan pesan dari saluran / obrolan lain. Tetapi dalam kasus ini, hanya apa yang terkandung dalam pesan sumber dalam dialog dengan bot yang akan ditampilkan. Khususnya, ketika mengirim pesan, informasi tombol tidak disimpan.


Tetapi bagaimana jika kita ingin melihat informasi tentang pesan asli? Dalam hal ini, Anda perlu mengambil pertengahan dari pesan yang diteruskan.


Untuk mengimplementasikan mode ini, kami memodifikasi perintah vmp sehingga ketika dipanggil tanpa parameter, ia mengharapkan pesan untuk diteruskan, dan setelah itu mengambil bagian tengah dari pesan yang dikirim dan menampilkan informasi tentangnya.


(!) Untuk operasi yang benar dari fungsi ini, bot harus diberikan izin untuk membaca dari saluran / sumber obrolan.


Kami memodifikasi kode perintah sebagai berikut:


  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) 

Dan sejak itu dengan pendekatan ini, risiko meningkat karena kurangnya akses ke pesan, maka dalam metode view_messages() kami menambahkan cek untuk kepatuhan dengan jumlah pesan yang diminta / diterima:


  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 

Kami me-restart bot, memberikan perintah / vmp, dan setelah prompt tentang perlunya penerusan ditampilkan, kami meneruskan pesan dari saluran / obrolan. Jika bot memiliki hak untuk membaca pesan di saluran / obrolan ini, representasi tekstual dari objek pesan yang diteruskan akan ditampilkan. Jika tidak ada akses, bot akan melaporkan kemungkinan masalah dan akan menunggu penerusan dari sumber yang benar.


Pengaturan properti bot


Sekarang tinggal membawa gloss. Mari kita tutup properti about , yang mengembalikan teks yang ditampilkan oleh bot ketika ia mulai bekerja, serta perintah / mulai.


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

Kami akan memblokir metode get_commands() , yang mengembalikan daftar perintah bot kami, yang muncul dalam dialog dengan bot.


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

Mari matikan properti main_menu_buttons, yang mengembalikan daftar tombol pada menu utama, dipanggil oleh perintah / menu.


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

Kami me-restart bot, pastikan semuanya beres. Selamat, bot pertama Anda telah dibuat dan, terlepas dari beberapa mainan, ia cukup menuntut fungsionalitas.


Kode sumber untuk status ini ada di sini .


Bot @devhelpbot yang berfungsi dapat dilihat di sini .


Itu saja untuk saat ini. Jika topiknya menarik, maka dalam artikel berikut ini saya dapat mempertimbangkan pengembangan bot lebih lanjut. Misalnya, menambahkan tombol khusus (khususnya, Ya / Tidak) dan memprosesnya, mengirim berbagai jenis konten (file, foto, dll.), Bekerja dalam mode webhook, dll.


Ngomong-ngomong, Anda dapat dengan cepat mengajukan pertanyaan dalam obrolan khusus . Saran / ide langsung di sana.

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


All Articles