Membuat Bot Telegram

Messenger telegram masih kurang populer di Indonesia, padahal Telegram memiliki banyak kelebihan dibanding messenger lain, misalnya: lebih cepat, bisa diakses via web, sinkronisasi pesan, dsb. Salah satu fitur yang baru diperkenalkan oleh Telegram adalah bot. Bot adalah software yang secara otomatis merespon pesan yang kita berikan.

Setelah saya membuat bot Bot Alkitab, beberapa orang bertanya bagaimana caranya membuat bot. Dengan harapan Telegram jad lebih populer, saya tuliskan di sini dasar pembuatan bot.

Sebelum membaca Artikel ini, silakan baca dulu artikel dari telegram yang memperkenalkan soal bot, lalu bereksperimen lah dengan bot-bot yang sudah ada, supaya bisa mengerti fitur bot dan interaksi dengan bot:

https://telegram.org/blog/bot-revolution

Mendaftarkan Bot

Sekarang setelah siap membuat bot, langkah pertama adalah mendaftarkan nama bot kita. Ini dilakukan dengan menggunakan BotFather.

Perintah yang perlu digunakan adalah /newbot. Perlu diperhatikan bahwa semua bot harus memiliki akhiran “Bot”. Setelah selesai, kita akan mendapatkan token, semacam ini: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11. Token ini tidak boleh disebar (karena orang lain bisa mengambil alih bot Anda).

botfather

Setelah didaftarkan, kita bisa langsung menambahkan bot di daftar teman kita.

daftar-teman

Ketika mulai chat, ada tombol “Start”

tombol-start

Jika kita tekan itu, yang terjadi adalah kita mengirimkan perintah “/start” ke bot (semua perintah bot dimulai dengan “/”).

pesan-pertama

Tapi kita belum menulis kode untuk bot kita, jadi bot kita belum bisa membalas apapun.

Menerima Pesan

Bot bisa menerima pesan dengan dua cara: polling dan webhook.

Polling artinya kita yang akan meminta pesan ke server telegram. Kira-kira begini: eh ada nggak pesan buat bot saya, kalo nggak ada, bilang aja nggak ada setelah N detik ya. Kalau dalam N detik ada pesan masuk, langsung berikan ke saya pesannya.

Cara kedua adalah dengan webhook. Kira-kira begini: ini saya punya URL, kalau ada pesan masuk, segera posting ke URL ini ya, nanti saya proses. URL ini harus HTTPS.

Telegram hanya mau mengantarkan pesan dengan salah satu cara di atas, tidak bisa keduanya, defaultnya adalah cara pertama.

Cara pertama cocok jika server dijalankan secara internal. Misalnya jika dijalankan di raspberry pi di rumah. Kita tidak perlu IP publik, tidak perlu punya domain, tidak perlu setup HTTPS, dsb. Cara ini agak sedikit lebih lambat dari cara kedua jika penggunanya banyak.

Cara kedua cocok jika Anda sudah punya web server eksternal dan sudah punya HTTPS, atau memakai layanan yang sudah memakai HTTPS (contohnya Google App Engine).

Pertama saya bahas cara polling karena ini sangat praktis ketika development. Pertama kita coba akses pesan yang diterima bot. Kita bisa meminta menggunakan browser seperti ini:


https://api.telegram.org/botTOKEN/getUpdates

Contohnya seperti ini:

getupdates

Sebenarnya ada beberapa parameter ekstra yang bisa kita tambahkan. Pertama adalah timeout: menyatakan berapa lama kita akan menunggu sampai ada pesan. Kedua adalah limit yang menyatakan berapa pesan yang ingin kita terima (max 100). Dan ketiga yang penting adalah offset.

Jika Anda coba refresh URL sebelumnya (tanpa memberikan offset), maka telegram tidak tahu apakah Anda sudah memproses pesan itu atau tidak (batasnya 24 jam). Untuk memberi tahu telegram bahwa pesan tadi sudah kita baca, kita perlu memberikan offset berupa update_id terakhir plus 1, jadi untuk mendapatkan pesan-pesan setelah pesan di atas, saya bisa menambahkan offset seperti ini (sekalian saya berikan contoh memberikan timeout dan limit):


https://api.telegram.org/botTOKEN/getUpdates?offset=142757037&timeout=2&limit=1

Hasil kembalian getUpdates seperti ini:

{"ok":true,"result":[{"update_id":142757036,
"message":{"message_id":3,"from":{"id":24912310,"first_name":"Yohanes","last_name":"Nugroho","username":"yohanesn"},"chat":{"id":24912310,"first_name":"Yohanes","last_name":"Nugroho","username":"yohanesn"},"date":1436950746,"text":"\/start"}}]}

Isi “result” adalah array of message (ada berbagai jenis message, bisa teks, video, dokumen, dsb, tapi dalam tutorial ini yang akan saya tangani hanya yang berisi “text”. Anda bisa membaca API Telegram untuk menangani jenis pesan yang lain.

Untuk membalas pesan, kita bisa menggunakan sendMessage. Anda bisa mencoba di browser (menggunakan token Anda) seperti ini (lihat chat_id di JSON di atas):


https://api.telegram.org/botTOKEN/sendMessage?chat_id=24912310&text=hello

Jika kita ingin menampilkan pesan sebagai balasan dari message tertentu, kita bisa menambahkan reply_to_message_id. Misalnya di atas tercantum message_id adalah 3:


https://api.telegram.org/botTOKEN/sendMessage?chat_id=24912310&text=hello&message_id=3

Jika kita menggunakan Python, kita bisa mendapatkan pesan updatenya dengan library requests (urllib juga bisa, tapi requests lebih enak). Karena URL requestnya sama semua prefixnya, saya membuat fungsi request_url untuk mempersingkat. Berikutnya agar singkat, saya hanya akan membahas PHP saja (dan Anda tetap bisa dengan mudah menerjemahkan ke Python).

def request_url(method):
    return  "https://api.telegram.org/bot"+TOKEN+"/" + method

def getUpdates(offset, limit=100, timeout=100):
    r = requests.get(request_url("getUpdates"),
                     params={"offset":offset,
                      "limit": limit,
                      "timeout": timeout
                      } )
    #asumsi semuanya OK
    result = json.loads(r.content)
    if result["ok"]:
        return result["result"]
    return []

Kode yang sama di PHP:

<?php

include("token.php");

function request_url($method)
{
	global $TOKEN;
	return "https://api.telegram.org/bot" . $TOKEN . "/". $method;
}

function get_updates() 
{
        $resp = file_get_contents(request_url("getUpdates"));
        $update = json_decode($resp, true);
         
?>

Kerangka sebuah program PHP command line (metode polling) yang menangani pesan adalah seperti ini:

<?php
include("token.php");

function request_url($method)
{
	global $TOKEN;
	return "https://api.telegram.org/bot" . $TOKEN . "/". $method;
}

function get_updates($offset) 
{
	$url = request_url("getUpdates")."?offset=".$offset;
        $resp = file_get_contents($url);
        $result = json_decode($resp, true);
        if ($result["ok"]==1)
            return $result["result"];
        return array();
}

function send_reply($chatid, $msgid, $text)
{
    $data = array(
        'chat_id' => $chatid,
        'text'  => $text,
        'reply_to_message_id' => $msgid

    );
    // use key 'http' even if you send the request to https://...
    $options = array(
    	'http' => array(
        	'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        	'method'  => 'POST',
        	'content' => http_build_query($data),
    	),
    );
    $context  = stream_context_create($options);

    $result = file_get_contents(request_url('sendMessage'), false, $context);
    print_r($result);
}

function create_response($text)
{
   return "definisi " . $text;
}


function process_message($message)
{
    $updateid = $message["update_id"];
    $message_data = $message["message"];
    if (isset($message_data["text"])) {
	$chatid = $message_data["chat"]["id"];
        $message_id = $message_data["message_id"];
        $text = $message_data["text"];
        $response = create_response($text);
        send_reply($chatid, $message_id, $response);
    }
    return $updateid;
}


function process_one()
{
	$update_id  = 0;

	if (file_exists("last_update_id")) {
		$update_id = (int)file_get_contents("last_update_id");
	}

	$updates = get_updates($update_id);

	foreach ($updates as $message)
	{
     		$update_id = process_message($message);
	}
	file_put_contents("last_update_id", $update_id + 1);

}

while (true) {
	process_one();
}
          
?>

Anda bisa mengakses sourcenya di sini:

https://gist.github.com/yohanes/987e1d48cbca9fde9377

Perhatikan bahwa ini perlu dijalankan di command line seperit ini:

$ php telegram-poll.php

Dan selama program masih berjalan, maka pesan yang masuk akan dibalas. Jika dijalankan di web server, maka akan timeout setelah beberapa detik/menit.

Isi file token.php hanyalah seperti ini:

<?php
$TOKEN="TOKENANDA";
?>

Untuk metode webHook, perbedaannya hanya pada fungsi get_updates, dan process_one tidak diperlukan, loop while juga tidak diperlukan, karena pesan akan dikirim satu per satu dengan POST. Kita cukup membaca POST yang masuk (dengan membaca php//:input), dan mendecode JSON-nya.

<?php
//bagian awal sama dengan sebelumnya

$entityBody = file_get_contents('php://input');
$message = json_decode($entityBody, true);
process_message($message);

?>

Source lengkap di:

https://gist.github.com/yohanes/3181a5424d10ea5e2429

Untuk menggunakan methode webHook, Anda harus melakukan beberapa hal:

  1. Mempersiapkan URL HTTPS
  2. Menset urlWebhook

Untuk bagian pertama: Anda perlu memiliki hosting yang mendukung HTTPS, Anda juga bisa memakai layanan cloudflare.com yang otomatis membungkus web Anda dengan https. Berikutya kita perlu mensetup web hook. Contohnya jika URL file php tersebut adalah:

http://cintaprogramming.com/xx.php

maka kita set dengan cara mengunjungi (menggunakan browser atau curl):

https://api.telegram.org/botTOKEN/setWebhook?url=https://cintaprogramming.com/xxx.php

Anda akan mendapatkan balasan:

{"ok":true,"result":true,"description":"Webhook was set"}

Jika ingin kembali menggunakan metode polling, maka set URL menjadi kosong:

https://api.telegram.org/botTOKEN/setWebhook?url=

Anda akan mendapatkan balasan:

{"ok":true,"result":true,"description":"Webhook was deleted"}

Atau jika memang belum diset:

{"ok":true,"result":true,"description":"There is no webhook to delete"}

Berikutnya terserah Anda bagaimana ingin memproses data masukan dari pengguna, misalnya bisa query ke database, bisa melakukan komputasi, dsb.

Jika kode Anda jalan di versi lokal/polling, tapi tidak ketika menggunakan webhook, maka Anda perlu mendebug. Pertama test apakah: webhook dipanggil oleh telegram (bisa dicoba dengan menuliskan isi $entityBody ke file). Kedua cek apakah Anda bisa memanggil send_reply. Beberapa hosting mematikan file_get_contents untuk mengakses HTTP/HTTPS, atau mendisable modul SSL (untuk kasus ini, mungkin harus diganti memakai modul curl) . Coba skrip paling sederhana di atas sebelum menambahkan kode custom Anda untuk reply (misalnya Anda mengakses MySQL, siapa tahu kode Anda yang error karena salah database atau salah query).

Saran saya: gunakan polling dulu sampai yakin sudah benar, setelah itu baru gunakan webhook.

Contoh ini sebenarnya adalah penyederhanaan sebuah kamus. Seharusnya bot ini membalas dengan definisi dari database, tapi di contoh ini bot selalu membalas dengan “definisi ” + KATA.

Sebuah bot bisa memiliki banyak perintah yang diawali dengan “/” (slash), terserah pembuat bot yang mendefinisikan. Misalnya jika kita membuat bot cuaca, kita bisa membuat perintah: “/cuaca NAMAKOTA” (untuk mendapatkan cuaca saat ini) atau “/ramalan NAMAKOTA” (untuk mendapatkan ramalan seminggu). Untuk menangani perintah-perintah ini kita bisa menggunakan parsing teks sederhana. Contoh parsing yang bisa dilakukan split teks menjadi kata-kata: jadikan kata pertama menjadi lower case, dan trim (hapus spasinya), lalu cek apakah sama dengan “/cuaca” atau “/ramalan”. Dan berikutnya lakukan aksi sesuai dengan perintahnya.

Setelah kita memiliki perintah-perintah tersebut. Kita bisa mendaftarkan perintahnya ke BotFather supaya Telegram bisa melakukan autocomplete perintah ketika user mengetikkan karakter /.

Demikian tutorial singkat bot Telegram. Jika ada pertanyaan, silakan tinggalkan di bagiann komentar, dan akan berusaha saya jawab (atau mungkin akan saya buatkan tutorial bagian kedua untuk menjelaskan lebih detail).