ZaminDocs

Inline tugmali menyu bot

Bitta xabar ichida ishlaydigan menyu: tugma bosilganda bot yangi xabar yubormaydi, balki o'sha xabarni editMessageText bilan yangilaydi. Har bir callback'ga answerCallbackQuery bilan javob beriladi.

Kod

menu_bot.py
import os
import time

import requests

TOKEN = os.environ["ZAMIN_BOT_TOKEN"]
API = f"https://api.zamin.app/bot{TOKEN}"

PRODUCTS = {
    "olma": ("🍎 Olma", "12 000 so'm/kg"),
    "anor": ("πŸ… Anor", "25 000 so'm/kg"),
    "uzum": ("πŸ‡ Uzum", "18 000 so'm/kg"),
}


def call(method, params=None, http_timeout=15):
    r = requests.post(f"{API}/{method}", json=params or {}, timeout=http_timeout)
    body = r.json()
    if not body.get("ok"):
        raise RuntimeError(f"{method}: {body.get('error_code')} {body.get('description')}")
    return body["result"]


def main_menu():
    return {
        "inline_keyboard": [
            [{"text": "πŸ› Mahsulotlar", "callback_data": "products"}],
            [
                {"text": "ℹ️ Biz haqimizda", "callback_data": "about"},
                {"text": "🌐 Sayt", "url": "https://example.com"},
            ],
        ]
    }


def products_menu():
    rows = [[{"text": name, "callback_data": f"p:{key}"}] for key, (name, _) in PRODUCTS.items()]
    rows.append([{"text": "Β« Orqaga", "callback_data": "home"}])
    return {"inline_keyboard": rows}


def back_menu(target="home"):
    return {"inline_keyboard": [[{"text": "Β« Orqaga", "callback_data": target}]]}


def show(chat_id, message_id, text, markup):
    """Xabarni joyida yangilaydi (yangi xabar yubormasdan)."""
    try:
        call("editMessageText", {"chat_id": chat_id, "message_id": message_id, "text": text, "reply_markup": markup})
    except RuntimeError as e:
        if "message is not modified" not in str(e):
            raise


def on_message(message):
    text = message.get("text", "")
    if text.startswith("/start") or text.startswith("/menu"):
        call("sendMessage", {"chat_id": message["chat"]["id"], "text": "Meva do'koniga xush kelibsiz! πŸ‰", "reply_markup": main_menu()})


def on_callback(query):
    data = query.get("data", "")
    chat_id = query["message"]["chat"]["id"]
    message_id = query["message"]["message_id"]
    notice = None

    if data == "home":
        show(chat_id, message_id, "Meva do'koniga xush kelibsiz! πŸ‰", main_menu())
    elif data == "products":
        show(chat_id, message_id, "Mahsulotni tanlang:", products_menu())
    elif data == "about":
        show(chat_id, message_id, "Biz 2026-yildan beri yangi meva yetkazamiz.", back_menu())
    elif data.startswith("p:") and data[2:] in PRODUCTS:
        name, price = PRODUCTS[data[2:]]
        show(chat_id, message_id, f"{name}\nNarxi: {price}", back_menu("products"))
        notice = f"{name} tanlandi"
    else:
        notice = "Bu tugma eskirgan"

    # Har bir callback'ga bir marta, 60 soniya ichida javob beriladi
    params = {"callback_query_id": query["id"]}
    if notice:
        params["text"] = notice
    call("answerCallbackQuery", params)


def main():
    call("deleteWebhook")
    call("setMyCommands", {"commands": [{"command": "start", "description": "Boshlash"}, {"command": "menu", "description": "Menyu"}]})
    offset = None
    while True:
        params = {"timeout": 30, "allowed_updates": ["message", "callback_query"]}
        if offset is not None:
            params["offset"] = offset
        try:
            updates = call("getUpdates", params, http_timeout=40)
        except (requests.RequestException, RuntimeError, ValueError) as e:
            print("getUpdates xatosi:", e)
            time.sleep(3)
            continue
        for update in updates:
            offset = update["update_id"] + 1
            try:
                if "message" in update:
                    on_message(update["message"])
                elif "callback_query" in update:
                    on_callback(update["callback_query"])
            except (requests.RequestException, RuntimeError, ValueError) as e:
                print("Xato:", e)


if __name__ == "__main__":
    main()

Ishga tushirish

Terminal
pip3 install requests
export ZAMIN_BOT_TOKEN="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
python3 menu_bot.py

Muhim nuqtalar

  • callback_data β€” 64 baytgacha. Qisqa kodlar ishlating (p:olma), katta ma'lumotni serveringizda saqlang.
  • Foydalanuvchi eski xabardagi tugmani ham bosishi mumkin β€” noma'lum data uchun ham javob bering.
  • editMessageText'da reply_markup berilmasa, tugmalar o'chadi. Shu sabab har safar menyu qayta yuboriladi.
  • Bot xabarlarini faqat 48 soat ichida tahrirlash mumkin; undan keyin /menu yangi xabar yuboradi.
  • URL tugma (🌐 Sayt) callback yubormaydi β€” ilova havolani tasdiq bilan ochadi.