ឯកសារអ្នកអភិវឌ្ឍន៍
ភាសាខ្មែរ

ការអភិវឌ្ឍបូត

ការបង្កើតបូត

បង្កើតបូតជាមួយ @BotFather ទទួល និងឆ្លើយតបសារ រហូតដល់ប៊ូតុង ពាក្យបញ្ជា រូបថត និងក្រុម — មេរៀនដែលអ្នកអាចធ្វើតាមពីដើមដល់ចប់។

នៅចុងបញ្ចប់នៃមេរៀននេះ អ្នកនឹងមានបូតមួយដែលឆ្លើយតបសារ មានប៊ូតុង ដោះស្រាយម៉ឺនុយពាក្យបញ្ជា និងរូបថត ហើយធ្វើការនៅក្នុងក្រុមបានផងដែរ។ អ្វីដែលអ្នកត្រូវការ គឺកម្មវិធី Pabal កុំព្យូទ័រមួយសម្រាប់ដំណើរការកម្មវិធីបូត និង Python 3.10 ឡើងទៅ ឬ Node.js 18 ឡើងទៅ មួយណាក៏បាន។

បូតដំណើរការយ៉ាងដូចម្តេច

បូតរបស់ Pabal គឺជាគណនីដែលគ្រប់គ្រងដោយកម្មវិធី។ សារដែលផ្ញើទៅបូត ត្រូវបានប្រមូលទុកក្នុងប្រអប់សាររបស់បូត ហើយកម្មវិធីបូតសួរម៉ាស៊ីនមេថា "មានអ្វីថ្មីទេ?" (getUpdates) ដើម្បីយកវាទៅ រួចផ្ញើចម្លើយ (sendMessage)។ កម្មវិធីបូតដំណើរការនៅក្រៅម៉ាស៊ីនមេ គឺនៅលើកុំព្យូទ័ររបស់អ្នក។

មនុស្ស (កម្មវិធី) ម៉ាស៊ីនមេ Pabal កម្មវិធីបូត ① getUpdates?offset=0&timeout=30 រង់ចាំ update ថ្មី យូរបំផុត 30 វិនាទី ② ផ្ញើ "សួស្តី" ③ [{update_id: 1, message: "សួស្តី"}] ④ sendMessage(chat_id, "ជម្រាបសួរ!") ⑤ ចម្លើយដល់កម្មវិធី (ភ្លាមៗ) ⑥ getUpdates?offset=2 — បានទទួលលេខ 1 យកបន្ទាប់
លំដាប់មូលដ្ឋាន៖ ទទួលដោយ getUpdates ហើយឆ្លើយដោយ sendMessage

ការពន្យល់ដ្យាក្រាម

  • ខ្សែបី៖ ខាងឆ្វេងជាមនុស្សដែលប្រើកម្មវិធី កណ្តាលជាម៉ាស៊ីនមេ Pabal ហើយខាងស្តាំជាកម្មវិធីបូតរបស់អ្នក។ បន្ទាត់ដាច់ៗបញ្ឈរ បង្ហាញទិសដៅដែលពេលវេលាកំពុងដំណើរទៅ។
  • ព្រួញពណ៌ប្រផេះ គឺជាសំណើដែលបូតធ្វើមុន ហើយព្រួញពណ៌ខៀវ គឺជាសារដែលឆ្លងកាត់ជាលទ្ធផល។ កម្មវិធីបូតគ្រាន់តែផ្ញើសំណើ ហើយម៉ាស៊ីនមេមិនទាក់ទងបូតមុនទេ (លុះត្រាតែប្រើ webhook)។
  • ការរង់ចាំនៅ ① (long polling) គឺជាចំណុចសំខាន់៖ បើអ្នកផ្តល់ timeout=30 ពេលគ្មាន update ថ្មី ម៉ាស៊ីនមេមិនឆ្លើយភ្លាមៗជាចម្លើយទទេទេ ប៉ុន្តែកាន់សំណើទុករហូតដល់ 30 វិនាទី ហើយឆ្លើយត្រឡប់ (③) នៅពេលដែលសារមកដល់ (②)។ ដូច្នេះប្រតិកម្មលឿន ហើយចំនួនសំណើតិច។
  • offset នៅ ⑥ គឺជាសញ្ញា "បានទទួលហើយ"៖ បើផ្ញើ update_id ចុងក្រោយដែលបានដំណើរការ បូក 1 នោះ update ទាំងឡាយដែលតូចជាង ឬស្មើនឹងវា នឹងត្រូវលុបចេញពីម៉ាស៊ីនមេ។ បើមិនបង្កើន offset ទេ អ្នកនឹងទទួល update ដដែលៗជានិច្ច។
  • ⑤ ឆ្លងកាត់ផ្លូវដូចគ្នានឹងសារដែលមនុស្សផ្ញើ៖ ចម្លើយរបស់បូតត្រូវបាន push ទៅគ្រប់ឧបករណ៍របស់កម្មវិធី ហើយក៏ឡើងក្នុងបញ្ជីការសន្ទនាដែរ។

1. បង្កើតបូតជាមួយ @BotFather

អ្នកបង្កើតបូតដោយជជែកជាមួយ @BotFather នៅក្នុងកម្មវិធី Pabal។ BotFather គឺជាបូតដែលមានស្រាប់នៅក្នុងម៉ាស៊ីនមេ Pabal។

  1. បញ្ចូល BotFather ក្នុងប្រអប់ស្វែងរករបស់កម្មវិធី ហើយបើក BotFather។ ពេលចុច ចាប់ផ្តើម អ្នកនឹងទទួលបានបញ្ជីពាក្យបញ្ជា។
  2. ផ្ញើ /newbot
  3. ផ្ញើឈ្មោះរបស់បូត។ វាជាឈ្មោះដែលបង្ហាញក្នុងបញ្ជីការសន្ទនា ដូច្នេះអាចសរសេរជាអក្សរខ្មែរក៏បាន។
  4. ផ្ញើឈ្មោះអ្នកប្រើរបស់បូត។ វាមាន 5 ដល់ 32 តួ ជាអក្សរឡាតាំង លេខ និងសញ្ញាគូសក្រោម ចាប់ផ្តើមដោយអក្សរឡាតាំង ហើយត្រូវតែបញ្ចប់ដោយ bot
  5. ពេលអ្នកទទួលបានចម្លើយដែលមានតូខឹន ជាការស្រេច។ សូមចម្លងតូខឹនទុក។
/newbot
BotFather새 봇을 만듭니다. 봇의 이름을 알려 주세요. (대화 목록에 보이는 이름이에요)
បូតសួស្តី
BotFather좋아요. 이제 봇의 사용자명을 정해 주세요. …
hello_test_bot
BotFather완료! 새 봇 @hello_test_bot 를 만들었어요. 검색해서 대화를 시작할 수 있어요. 봇 토큰: 100003:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789 토큰은 비밀번호처럼 안전하게 보관하세요. …

បច្ចុប្បន្ន BotFather ឆ្លើយជាភាសាកូរ៉េ។ ចម្លើយខាងលើមានន័យថា៖ ដំបូង វាសួររកឈ្មោះរបស់បូត (ឈ្មោះដែលបង្ហាញក្នុងបញ្ជីការសន្ទនា) បន្ទាប់មក វាសួររកឈ្មោះអ្នកប្រើរបស់បូត ហើយចុងក្រោយ វាប្រាប់ថាបូត @hello_test_bot ត្រូវបានបង្កើតរួច ព្រមទាំងផ្តល់តូខឹនបូតឲ្យអ្នក និងរំលឹកឲ្យរក្សាតូខឹនឲ្យមានសុវត្ថិភាពដូចពាក្យសម្ងាត់។

ពាក្យបញ្ជា BotFatherអ្វីដែលវាធ្វើ
/newbotបង្កើតបូតថ្មី (ឈ្មោះ → ឈ្មោះអ្នកប្រើ → តូខឹន)
/mybotsបញ្ជីបូតដែលខ្ញុំបានបង្កើត
/tokenមើលតូខឹនបូតម្តងទៀត
/revokeចេញតូខឹនថ្មី — តូខឹនចាស់លែងមានសុពលភាពភ្លាមៗ ហើយការតភ្ជាប់ដែលភ្ជាប់ដោយតូខឹនចាស់ក៏ត្រូវផ្តាច់ដែរ
/setcommandsកំណត់ម៉ឺនុយពាក្យបញ្ជា (ពាក្យបញ្ជា - ការពិពណ៌នា មួយបន្ទាត់មួយ)
/deletebotលុបបូត — បញ្ជាក់ដោយផ្ញើ 네, 삭제합니다 (មានន័យថា "បាទ/ចាស លុបវាចុះ")។ ឈ្មោះអ្នកប្រើត្រូវបានដោះលែង ដើម្បីអាចប្រើម្តងទៀតបាន
/cancelបោះបង់ការងារដែលកំពុងដំណើរការ

បើអ្នកផ្ញើដោយភ្ជាប់ឈ្មោះអ្នកប្រើ ដូចជា /token @hello_test_bot នោះនឹងរំលងជំហានដែល BotFather សួរថា "បូតមួយណា?"។

2. ការគ្រប់គ្រងតូខឹន

តូខឹនមានទម្រង់ <ID បូត>:<អាថ៌កំបាំង>។ លេខខាងមុខជា ID អ្នកប្រើរបស់បូត ហើយផ្នែកខាងក្រោយជាអាថ៌កំបាំង។ ដោយសារតូខឹនតែមួយអាចគ្រប់គ្រងបូតបានទាំងស្រុង សូមរក្សាវាដូចពាក្យសម្ងាត់

  • កុំសរសេរវាក្នុងកូដ សូមដាក់វាក្នុងអថេរបរិស្ថាន (BOT_TOKEN) ឬកន្លែងរក្សាទុកអាថ៌កំបាំង។ កុំបង្ហោះវាទៅឃ្លាំងកូដសាធារណៈ។
  • បើវាលេចធ្លាយ សូមផ្ញើ /revoke ទៅ BotFather។ តូខឹនចាស់នឹងត្រូវបដិសេធភ្លាមៗ (401 Unauthorized) ហើយវគ្គ (session) បូតដែលភ្ជាប់ MTProto ដោយតូខឹនចាស់ ក៏ត្រូវផ្តាច់ដែរ។
  • ដោយសារតូខឹនស្ថិតនៅក្នុងអាសយដ្ឋាន (URL) សូមកុំឲ្យកម្មវិធីបូតកត់ត្រាអាសយដ្ឋានសំណើទៅក្នុង log។ ម៉ាស៊ីនមេ Pabal ក៏មិនកត់ត្រាអាសយដ្ឋាន Bot API ទៅក្នុង log ដែរ។

3. សំណើដំបូង — getMe

អាសយដ្ឋាននៃសំណើទាំងអស់គឺ https://pabal.me/bot<តូខឹន>/<method>។ តោះពិនិត្យមើលថាតូខឹនត្រឹមត្រូវឬអត់ ដោយប្រើ getMe

export BOT_TOKEN='100003:AbCdEf…'
curl -s "https://pabal.me/bot$BOT_TOKEN/getMe"
# pip install requests
import os
import requests

r = requests.get(f"https://pabal.me/bot{os.environ['BOT_TOKEN']}/getMe", timeout=10)
print(r.json())
// Node.js 18 ឡើងទៅ — មាន fetch ស្រាប់
const res = await fetch(`https://pabal.me/bot${process.env.BOT_TOKEN}/getMe`);
console.log(await res.json());

បើជោគជ័យ អ្នកនឹងទទួលបានដូចនេះ។ រាល់ការឆ្លើយតបទាំងអស់ជា JSON ដែលមាន ok និង result (ពេលជោគជ័យ) ឬ error_code និង description (ពេលបរាជ័យ)។

{
  "ok": true,
  "result": {
    "id": 100003,
    "is_bot": true,
    "first_name": "បូតសួស្តី",
    "username": "hello_test_bot",
    "can_join_groups": true,
    "can_read_all_group_messages": true,
    "supports_inline_queries": false,
    "can_connect_to_business": false,
    "has_main_web_app": false
  }
}

បើតូខឹនខុស អ្នកនឹងទទួលបាន {"ok": false, "error_code": 401, "description": "Unauthorized"} ជាមួយ HTTP 401។

4. ទទួលសារ — getUpdates

បើកបូតក្នុងកម្មវិធី ហើយចុច ចាប់ផ្តើម ឬផ្ញើអ្វីមួយ រួចទាញយក update ថ្មីៗ។

curl -s "https://pabal.me/bot$BOT_TOKEN/getUpdates?timeout=30"
{
  "ok": true,
  "result": [
    {
      "update_id": 1,
      "message": {
        "message_id": 1,
        "from": { "id": 100001, "is_bot": false, "first_name": "សុខា" },
        "chat": { "id": 100001, "first_name": "សុខា", "type": "private" },
        "date": 1789805661,
        "text": "/start",
        "entities": [ { "type": "bot_command", "offset": 0, "length": 6 } ]
      }
    }
  ]
}
  • update_id៖ លេខដែលកើនឡើង 1 សម្រាប់ update នីមួយៗ។ បន្ទាប់ពីដំណើរការរួច បើផ្តល់ offset=update_id+1 ក្នុងសំណើបន្ទាប់ នោះ update ដែលតូចជាង ឬស្មើ នឹងត្រូវលុបចោល ដោយចាត់ទុកថា "បានទទួលហើយ"។
  • timeout៖ ចំនួនវិនាទីដែលត្រូវរង់ចាំ ពេលគ្មាន update ថ្មី (0 ដល់ 50)។ បើ 0 វានឹងឆ្លើយបញ្ជីទទេភ្លាមៗ។ យើងណែនាំ 25 ដល់ 30។
  • chat.id៖ កន្លែងដែលត្រូវផ្ញើចម្លើយ។ ការសន្ទនា 1:1 គឺជា ID របស់មនុស្ស (លេខវិជ្ជមាន) ហើយក្រុមគឺជាលេខអវិជ្ជមាន។
  • update ដែលអាចទទួលបាន មានបីប្រភេទ៖ message (សារថ្មី) edited_message (សារដែលបានកែ) និង callback_query (ការចុចប៊ូតុង)។
ជួររង់ចាំស្ថិតនៅក្នុងអង្គចងចាំរបស់ម៉ាស៊ីនមេ

update ដែលមិនទាន់ទាញយក ត្រូវបានរក្សាទុកក្នុងអង្គចងចាំម៉ាស៊ីនមេ រហូតដល់ 1,000 ចុងក្រោយសម្រាប់បូតនីមួយៗ។ ពេលម៉ាស៊ីនមេចាប់ផ្តើមឡើងវិញ update ដែលមិនទាន់ទាញយកនឹងបាត់ (តែសារខ្លួនឯងនៅតែមានក្នុងការសន្ទនា)។ សូមកុំបិទបូតយូរពេក។

5. ផ្ញើចម្លើយ — sendMessage

curl -s "https://pabal.me/bot$BOT_TOKEN/sendMessage" \
  -H 'Content-Type: application/json' \
  -d '{"chat_id": 100001, "text": "ជម្រាបសួរ!"}'
requests.post(f"https://pabal.me/bot{os.environ['BOT_TOKEN']}/sendMessage",
              json={"chat_id": 100001, "text": "ជម្រាបសួរ!"}, timeout=10)
await fetch(`https://pabal.me/bot${process.env.BOT_TOKEN}/sendMessage`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ chat_id: 100001, text: 'ជម្រាបសួរ!' }),
});

អ្នកអាចផ្ញើប៉ារ៉ាម៉ែត្រតាមទម្រង់ណាដែលស្រួល៖ តួ JSON, ទម្រង់ form (application/x-www-form-urlencoded), multipart/form-data ពេលបង្ហោះឯកសារ ឬ query string នៅខាងក្រោយអាសយដ្ឋាន។ លទ្ធផលគឺជាសារដែលបានផ្ញើ (Message)។

បូតមិនអាចចាប់ផ្តើមការសន្ទនាមុនបានទេ

បូតអាចផ្ញើសារទៅមនុស្សម្នាក់បាន លុះត្រាតែមនុស្សនោះធ្លាប់ផ្ញើសារទៅបូតយ៉ាងហោចណាស់ម្តង។ បើមិនដូច្នោះទេ អ្នកនឹងទទួលបាន 403 Forbidden: bot can't initiate conversation with a user។ នេះជាច្បាប់ដូចគ្នានឹង Telegram។

6. បង្កើតបូតនិយាយតាមឲ្យចប់

គ្រាន់តែធ្វើការទទួល និងផ្ញើម្តងហើយម្តងទៀត អ្នកនឹងបានបូតមួយ។ នេះជាកូដពេញលេញ ដែលសរសេរដោយមិនប្រើបណ្ណាល័យ។

# echo.py — pip install requests
# ដំណើរការ៖ BOT_TOKEN='100003:…' python3 echo.py
import os
import requests

API = f"https://pabal.me/bot{os.environ['BOT_TOKEN']}"


def call(method, **params):
    r = requests.post(f"{API}/{method}", json=params, timeout=60)
    data = r.json()
    if not data["ok"]:
        raise RuntimeError(f"{method}: {data['description']}")
    return data["result"]


offset = 0
print("បូតបានបើកហើយ។ ចុច Ctrl+C ដើម្បីបញ្ឈប់")
while True:
    for update in call("getUpdates", offset=offset, timeout=30):
        offset = update["update_id"] + 1          # សម្គាល់ថាបានទទួល
        message = update.get("message")
        if message and "text" in message:
            call("sendMessage", chat_id=message["chat"]["id"], text=message["text"])
// echo.mjs — Node.js 18 ឡើងទៅ ដោយមិនប្រើបណ្ណាល័យ
// ដំណើរការ៖ BOT_TOKEN='100003:…' node echo.mjs
const API = `https://pabal.me/bot${process.env.BOT_TOKEN}`;

async function call(method, params = {}) {
  const res = await fetch(`${API}/${method}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params),
  });
  const data = await res.json();
  if (!data.ok) throw new Error(`${method}: ${data.description}`);
  return data.result;
}

let offset = 0;
console.log('បូតបានបើកហើយ។ ចុច Ctrl+C ដើម្បីបញ្ឈប់');
for (;;) {
  const updates = await call('getUpdates', { offset, timeout: 30 });
  for (const update of updates) {
    offset = update.update_id + 1;              // សម្គាល់ថាបានទទួល
    const message = update.message;
    if (message?.text) {
      await call('sendMessage', { chat_id: message.chat.id, text: message.text });
    }
  }
}

7. បង្កើតដោយប្រើបណ្ណាល័យ

បណ្ណាល័យបូតសម្រាប់ Telegram មានការកំណត់សម្រាប់ប្តូរអាសយដ្ឋានម៉ាស៊ីនមេ។ ដោយការកំណត់តែមួយនោះ វាដំណើរការលើ Pabal ដូចដើម។ ពេលផ្ទេរបូតដែលបង្កើតសម្រាប់ Telegram ក៏គ្រាន់តែប្តូរការកំណត់នេះ ហើយទទួលតូខឹនថ្មីពី BotFather របស់ Pabal ប៉ុណ្ណោះ។

បណ្ណាល័យការកំណត់ដែលត្រូវប្តូរកំណែដែលបានផ្ទៀងផ្ទាត់
python-telegram-bot.base_url("https://pabal.me/bot"), .base_file_url("https://pabal.me/file/bot")22.8
aiogramAiohttpSession(api=TelegramAPIServer.from_base("https://pabal.me"))3.31
គ្មានបណ្ណាល័យ (HTTP)ផ្នែកខាងមុខនៃអាសយដ្ឋាន https://api.telegram.orghttps://pabal.me
# hello_bot.py — pip install python-telegram-bot
# ដំណើរការ៖ BOT_TOKEN='100003:…' python3 hello_bot.py
import os

from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (Application, CallbackQueryHandler, CommandHandler, ContextTypes,
                          MessageHandler, filters)

SERVER = "https://pabal.me"


def buttons():
    return InlineKeyboardMarkup([[InlineKeyboardButton("👍 ចូលចិត្ត", callback_data="like"),
                                  InlineKeyboardButton("🔢 បង្កើនលេខ", callback_data="count")]])


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("ជម្រាបសួរ! សាកចុចប៊ូតុងមើល។", reply_markup=buttons())


async def button(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.data == "like":
        await query.answer("អរគុណ!")                  # អត្ថបទដែលលេចឡើងមួយភ្លែតលើអេក្រង់អ្នកចុច
    else:
        n = context.chat_data.get("n", 0) + 1
        context.chat_data["n"] = n
        await query.answer()                             # ឆ្លើយជាមុនសិន
        await query.edit_message_text(f"លេខ៖ {n}", reply_markup=buttons())   # រួចកែសារ


async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(f"អ្នកបាននិយាយថា '{update.message.text}'។")


def main():
    app = (Application.builder().token(os.environ["BOT_TOKEN"])
           .base_url(f"{SERVER}/bot")                   # Pabal ជំនួស api.telegram.org
           .base_file_url(f"{SERVER}/file/bot")
           .build())
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CallbackQueryHandler(button))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
    print("បូតបានបើកហើយ។ ចុច Ctrl+C ដើម្បីបញ្ឈប់")
    app.run_polling()


if __name__ == "__main__":
    main()
# echo_aiogram.py — pip install aiogram
# ដំណើរការ៖ BOT_TOKEN='100003:…' python3 echo_aiogram.py
import asyncio
import os

from aiogram import Bot, Dispatcher
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer
from aiogram.filters import CommandStart

dp = Dispatcher()


@dp.message(CommandStart())
async def start(message):
    await message.answer("ជម្រាបសួរ! សាកផ្ញើអ្វីមួយមកមើល។")


@dp.message()
async def echo(message):
    if message.text:
        await message.answer(message.text)


async def main():
    session = AiohttpSession(api=TelegramAPIServer.from_base("https://pabal.me"))   # Pabal
    bot = Bot(os.environ["BOT_TOKEN"], session=session)
    print("បូតបានបើកហើយ។ ចុច Ctrl+C ដើម្បីបញ្ឈប់")
    await dp.start_polling(bot)


asyncio.run(main())

8. ប៊ូតុង និង callback

ដើម្បីភ្ជាប់ប៊ូតុង inline ទៅនឹងសារ សូមផ្តល់ inline_keyboard (array នៃជួរ ហើយជួរនីមួយៗជា array នៃប៊ូតុង) ក្នុង reply_markup។ ប៊ូតុងមានពីរប្រភេទ៖ ប៊ូតុង callback_data ដែលជូនដំណឹងទៅបូតពេលចុច និងប៊ូតុង url ដែលបើកតំណ។

curl -s "https://pabal.me/bot$BOT_TOKEN/sendMessage" -H 'Content-Type: application/json' -d '{
  "chat_id": 100001,
  "text": "សូមជ្រើសរើស",
  "reply_markup": {
    "inline_keyboard": [
      [ {"text": "👍 ចូលចិត្ត", "callback_data": "like"}, {"text": "👎 មិនសូវ", "callback_data": "dislike"} ],
      [ {"text": "បើកឯកសារ Pabal", "url": "https://pabal.me/docs/"} ]
    ]
  }
}'

ពេលមនុស្សចុចប៊ូតុង callback_data បូតនឹងទទួលបាន update callback_query

{
  "update_id": 7,
  "callback_query": {
    "id": "5812039457730125441",
    "from": { "id": 100001, "is_bot": false, "first_name": "សុខា" },
    "message": { "message_id": 4, "chat": { "id": 100001, "type": "private", "first_name": "សុខា" }, "text": "សូមជ្រើសរើស", … },
    "chat_instance": "8413962145072395171",
    "data": "like"
  }
}

បូតត្រូវឆ្លើយដោយ answerCallbackQuery ក្នុងរយៈពេល 10 វិនាទី។ ក្នុងអំឡុងពេលនោះ កម្មវិធីបង្ហាញរូបនាឡិកាលើប៊ូតុង ហើយរង់ចាំ។

# អត្ថបទដែលលេចឡើងមួយភ្លែតនៅលើអេក្រង់ (បើ show_alert: true វាជាប្រអប់បញ្ជាក់)
curl -s "https://pabal.me/bot$BOT_TOKEN/answerCallbackQuery" -H 'Content-Type: application/json' \
  -d '{"callback_query_id": "5812039457730125441", "text": "អរគុណ!"}'

# ប្តូរអត្ថបទ និងប៊ូតុងនៃសារដែលត្រូវបានចុច
curl -s "https://pabal.me/bot$BOT_TOKEN/editMessageText" -H 'Content-Type: application/json' \
  -d '{"chat_id": 100001, "message_id": 4, "text": "អ្នកបានចុចចូលចិត្ត 👍"}'
  • callback_data មានទំហំពី 1 ដល់ 64 បៃ។ សារមួយអាចមានប៊ូតុងរហូតដល់ 100។
  • បើមិនឆ្លើយ callback ទេ កម្មវិធីនឹងឈប់រង់ចាំក្រោយ 10 វិនាទី។ បើបូតត្រូវបានបិទ ម៉ាស៊ីនមេនឹងបញ្ចប់ការរង់ចាំភ្លាមៗ។
  • មានតែចម្លើយលើកដំបូងប៉ុណ្ណោះដែលមានសុពលភាព។ បណ្ណាល័យខ្លះផ្ញើចម្លើយទទេជាមុន ពេលកែសារ ដូច្នេះសូមផ្ញើចម្លើយដែលមានអត្ថបទជាមុនសិន
  • បើកែដោយអត្ថបទដដែល និងប៊ូតុងដដែល អ្នកនឹងទទួលបាន 400 Bad Request: message is not modified (ដូច Telegram)។

ក្តារចុចនៅក្រោមប្រអប់បញ្ចូល

បើផ្តល់ keyboard ផ្ទាំងប៊ូតុងនឹងបង្ហាញជំនួសក្តារចុចធម្មតា ហើយពេលចុច អត្ថបទនៃប៊ូតុងនោះត្រូវបានផ្ញើជាសារ។ លាក់វាដោយ remove_keyboard ហើយបើករបៀបឆ្លើយតបដោយ force_reply

{
  "chat_id": 100001,
  "text": "តើមួយណា?",
  "reply_markup": {
    "keyboard": [ [ {"text": "បាទ/ចាស"}, {"text": "ទេ"} ], [ {"text": "ផ្ញើទីតាំងរបស់ខ្ញុំ", "request_location": true} ] ],
    "resize_keyboard": true,
    "one_time_keyboard": true
  }
}

9. ម៉ឺនុយពាក្យបញ្ជា

វាជាបញ្ជីដែលលេចឡើង ពេលអ្នកចុច / ក្នុងប្រអប់ជជែក ឬចុចប៊ូតុង ម៉ឺនុយ។ អ្នកអាចកំណត់វាដោយកូដ ឬដោយ /setcommands របស់ BotFather។

curl -s "https://pabal.me/bot$BOT_TOKEN/setMyCommands" -H 'Content-Type: application/json' -d '{
  "commands": [
    {"command": "start", "description": "ចាប់ផ្តើម"},
    {"command": "help",  "description": "ជំនួយ"}
  ]
}'

ពាក្យបញ្ជាមាន 1 ដល់ 32 តួ ជាអក្សរឡាតាំងតូច លេខ និងសញ្ញាគូសក្រោម ការពិពណ៌នាមាន 1 ដល់ 256 តួ ហើយមានបានរហូតដល់ 100។ បើផ្តល់ language_code ម៉ាស៊ីនមេនឹងរក្សាទុកបញ្ជីដាច់ដោយឡែកតាមភាសា ប៉ុន្តែបច្ចុប្បន្ន កម្មវិធីបង្ហាញតែបញ្ជីលំនាំដើម ដែលកំណត់ដោយគ្មានលេខកូដភាសាប៉ុណ្ណោះ។ ពាក្យបញ្ជាដែលមនុស្សផ្ញើ ដូចជា /start មកដល់ដោយត្រូវបានសម្គាល់ជា bot_command ក្នុង entities នៃសារ។

10. ការផ្ញើ និងទទួលរូបថត

ការផ្ញើ

បង្ហោះឯកសារដោយ multipart/form-data ឬប្រើ file_id នៃរូបថតដែលបានទទួលពីមុនម្តងទៀត។ រូបថតមានទំហំរហូតដល់ 10MB ហើយការពិពណ៌នា (caption) រហូតដល់ 1,024 តួ។ ការផ្ញើតាម URL មិនទាន់គាំទ្រនៅឡើយទេ។

curl -s "https://pabal.me/bot$BOT_TOKEN/sendPhoto" \
  -F chat_id=100001 -F caption='រូបថតថ្ងៃនេះ' -F photo=@sunset.jpg
with open("sunset.jpg", "rb") as f:
    requests.post(f"{API}/sendPhoto", data={"chat_id": 100001, "caption": "រូបថតថ្ងៃនេះ"},
                  files={"photo": f}, timeout=60)

ការទទួល

រូបថតដែលមនុស្សផ្ញើ មកដល់ក្នុង photo នៃសារ (បញ្ជីតាមទំហំ ហើយនៅ Pabal មានតែរូបដើមមួយ)។ ទទួលផ្លូវ (path) ដោយ getFile រួចទាញយក។

# 1) file_id → file_path
curl -s "https://pabal.me/bot$BOT_TOKEN/getFile?file_id=AQAAAAAAAAB7…"
# {"ok":true,"result":{"file_id":"AQAA…","file_unique_id":"AQAA…","file_size":48213,"file_path":"photos/AQAA….jpg"}}

# 2) ទាញយក — អាសយដ្ឋានមាន /file/
curl -s -o photo.jpg "https://pabal.me/file/bot$BOT_TOKEN/photos/AQAA….jpg"

11. នៅក្នុងក្រុម

  • ពេលបង្កើតក្រុមក្នុងកម្មវិធី ឬនៅ ព័ត៌មានក្រុម → បន្ថែមសមាជិក សូមស្វែងរកឈ្មោះអ្នកប្រើរបស់បូត ហើយបន្ថែមវា។
  • បូតដែលនៅក្នុងក្រុម ទទួលសារទាំងអស់របស់ក្រុម (ដូច "privacy mode បិទ" របស់ Telegram)។ chat.type គឺ "group" ហើយ chat.id ជាលេខអវិជ្ជមាន។
  • បើ sendMessage ទៅ chat.id នោះ សារនឹងត្រូវផ្ញើទៅក្រុម។ ប៊ូតុង រូបថត និងការកែ ក៏ដូចគ្នានឹងការសន្ទនា 1:1 ដែរ។
  • បើបូតចេញពីក្រុម ការផ្ញើទៅក្រុមនោះនឹងទទួលបាន 403 Forbidden: bot is not a member of the group chat

12. ប្តូរទៅប្រើ webhook

បើបូតដំណើរការលើម៉ាស៊ីនមេដែលមានអាសយដ្ឋាន HTTPS សាធារណៈ អ្នកអាចឲ្យម៉ាស៊ីនមេ Pabal ផ្ញើ update ថ្មីៗមកអាសយដ្ឋាននោះ ជំនួសឲ្យការសួរដោយ getUpdates

curl -s "https://pabal.me/bot$BOT_TOKEN/setWebhook" -H 'Content-Type: application/json' \
  -d '{"url": "https://bot.example.com/pabal-webhook", "secret_token": "ខ្សែអក្សរចៃដន្យវែង"}'

ការកំណត់ ការផ្ទៀងផ្ទាត់ ការព្យាយាមម្តងទៀត រហូតដល់ការឆ្លើយតាមការឆ្លើយតប មាននៅក្នុងឯកសារ Webhook

បូតដែលភ្ជាប់តាម MTProto (Telethon)

បូតក៏អាចភ្ជាប់តាម MTProto ដូចកម្មវិធីបានដែរ។ វាងាយស្រួល បើអ្នកកំពុងប្រើឧបករណ៍សម្រាប់គណនីមនុស្ស (ដូចជា Telethon) រួចហើយ។ ដោយសារវាជាគណនីបូតតែមួយ អ្នកអាចប្រើវាលាយជាមួយ HTTP បាន។

# pip install telethon==1.42.0   ← សូមប្រើ 1.42 (មើលការពន្យល់ខាងក្រោម)
# សោសាធារណៈរបស់ម៉ាស៊ីនមេ៖ ទាញយក https://pabal.me/docs/server-key.pem ទុកក្នុងថតដដែល
import asyncio
import os

from telethon import TelegramClient, events
from telethon.crypto import rsa
from telethon.sessions import StringSession

rsa.add_key(open("server-key.pem").read(), old=False)        # សោសាធារណៈរបស់ម៉ាស៊ីនមេ Pabal
client = TelegramClient(StringSession(), api_id=1, api_hash="0" * 32)
client.session.set_dc(2, "122.34.175.215", 8443)


@client.on(events.NewMessage(incoming=True))
async def echo(event):
    await event.reply(event.raw_text)


async def main():
    await client.start(bot_token=os.environ["BOT_TOKEN"])      # auth.importBotAuthorization
    print("បូតបានបើកហើយ។ ចុច Ctrl+C ដើម្បីបញ្ឈប់")
    await client.run_until_disconnected()


asyncio.run(main())
  • សូមប្រើ Telethon 1.42។ Pabal និយាយ layer 216 ប៉ុន្តែ Telethon កំណែថ្មីជាងនេះ ព្យាយាមអានការឆ្លើយតបដោយ layer ខ្ពស់ជាង ដូច្នេះបរាជ័យតាំងពីការចូលគណនី (TypeNotFoundError)។
  • Pabal មិនពិនិត្យ api_id និង api_hash ទេ ដូច្នេះតម្លៃណាក៏បាន។
  • សម្រាប់បូត MTProto ម៉ាស៊ីនមេ push សារថ្មីៗមកភ្លាមៗ (មិនត្រូវការ getUpdates ឬ webhook ទេ)។ សម្រាប់ចម្លើយ callback សូមហៅ event.answer("…") មុន event.edit(…)

ច្បាប់ និងដែនកំណត់

ធាតុតម្លៃ
ចំនួនតួអក្សរក្នុងសារ / ការពិពណ៌នារូបថត4,096 តួ / 1,024 តួ
ទំហំរូបថត (ការបង្ហោះ sendPhoto)10MB
ទំហំតួសំណើ12MB
getUpdates timeout · limit0 ដល់ 50 វិនាទី · 1 ដល់ 100
ការរក្សាទុក update ដែលមិនទាន់ទាញយក1,000 ចុងក្រោយសម្រាប់បូតនីមួយៗ ក្នុងអង្គចងចាំម៉ាស៊ីនមេ (បាត់ពេលចាប់ផ្តើមឡើងវិញ)
ការរង់ចាំចម្លើយ callback10 វិនាទី
callback_data · ចំនួនប៊ូតុង1 ដល់ 64 បៃ · 100 ក្នុងមួយសារ
ពាក្យបញ្ជាអក្សរឡាតាំងតូច លេខ និងសញ្ញាគូសក្រោម 1 ដល់ 32 តួ ការពិពណ៌នា 1 ដល់ 256 តួ រហូតដល់ 100
ការចាប់ផ្តើមសន្ទនាមុនមិនបាន — មនុស្សត្រូវផ្ញើទៅបូតមុន

ការដោះស្រាយបញ្ហា

រោគសញ្ញាមូលហេតុ និងដំណោះស្រាយ
401 Unauthorizedតូខឹនខុស ឬត្រូវបានប្តូរដោយ /revoke។ សូមផ្ញើ /token ទៅ BotFather ដើម្បីពិនិត្យ។
404 Not Found: method not foundនេះជា method ដែល Pabal មិនទាន់គាំទ្រ។ សូមពិនិត្យ បញ្ជី method
403 Forbidden: bot can't initiate conversation with a userមនុស្សនោះមិនទាន់ធ្លាប់ផ្ញើសារទៅបូតនៅឡើយ។ សូមឲ្យគាត់បើកបូតក្នុងកម្មវិធី ហើយចុច ចាប់ផ្តើម
409 Conflict: can't use getUpdates method while webhook is activewebhook កំពុងត្រូវបានកំណត់។ សូមហៅ deleteWebhook ឬទទួលតាម webhook។
ចុចប៊ូតុងហើយ គ្មានប្រតិកម្មបូតត្រូវបានបិទ ឬមិនបានហៅ answerCallbackQuery
ទទួលសារដដែលៗរហូតអ្នកមិនបានបង្កើន offset។ សូមផ្តល់ update_id + 1 ដែលបានដំណើរការ ក្នុងសំណើបន្ទាប់។
ទម្រង់ដិត ឬតំណ មិនដំណើរការparse_mode មិនទាន់គាំទ្រ ដូច្នេះអត្ថបទត្រូវបានផ្ញើដូចដើម។ ពាក្យបញ្ជា @mention URL និង #tag ត្រូវបានបង្ហាញជាតំណដែលអាចចុចបានដោយស្វ័យប្រវត្តិ។
បូតស្ងាត់នៅក្នុងក្រុមបូតមិនមែនជាសមាជិកក្រុមទេ។ សូមបន្ថែមវាតាម ព័ត៌មានក្រុម → បន្ថែមសមាជិក។