فصل ۶: کار با دستورات (Commands) در ربات تلگرام با پایتون

""

مقدمه‌ای جامع درباره دستورات در ربات‌های تلگرام

دستورات یا Commands یکی از مهم‌ترین اجزای هر ربات تلگرامی هستند. این دستورات به کاربر اجازه می‌دهند با ارسال عباراتی مشخص، رفتار ربات را کنترل کند و عملیات‌ خاصی را فعال کند. تقریباً تمام ربات‌های حرفه‌ای – از ربات‌های فروشگاهی تا دستیارهای هوشمند – مجموعه‌ای از دستورات منظم، قابل فهم و ساخت‌یافته دارند که ستون اصلی تجربه کاربری را تشکیل می‌دهند.

نقش Commands در هوشمند شدن ربات

Commands نقش «درگاه ورودیِ قابل پیش‌بینی» را برای ربات‌ها بازی می‌کنند. زمانی که کاربر یک دستور مشخص مثل /start یا /help ارسال می‌کند، ربات دقیقاً می‌داند چه کار باید انجام دهد. این پیش‌بینی‌پذیری باعث می‌شود:

  • ارتباط کاربر و ربات بسیار روان‌تر شود
  • ربات بتواند عملیات‌های پیچیده‌تر را مدیریت کند
  • کاربر سریع‌تر یاد بگیرد چطور با ربات کار کند
  • مسیرهای مشخص برای انجام وظایف ایجاد شود

در واقع، Commands مانند دکمه‌هایی هستند که در یک اپلیکیشن فشار می‌دهید؛ با این تفاوت که در تلگرام، این دکمه‌ها به شکل متن ارسال می‌شوند و ربات می‌تواند به آن‌ها پاسخ مشخص، پایدار و هوشمند بدهد.

تفاوت Command با پیام عادی

در ظاهر یک Command هم مثل یک پیام عادی ارسال می‌شود، اما تفاوت‌های مهمی وجود دارد:

  • یک Command همیشه با / شروع می‌شود، مانند /start
  • تلگرام آن را به‌صورت ساختاریافته به ربات ارسال می‌کند
  • Handlerهای مخصوص Commands آن را دریافت می‌کنند
  • ربات دقیقاً می‌داند که این پیام یک دستور است، نه یک متن معمولی
  • پردازش Commands سریع‌تر و قابل مدیریت‌تر است
  • Commands برای تعریف منو، دکمه‌ها و راهنمای ربات ضروری هستند

در پیام‌های عادی، ربات باید حدس بزند کاربر چه می‌خواهد یا متن را تحلیل کند. اما در Commands، ربات بدون شک می‌داند چه عملی باید انجام شود. همین تفاوت باعث می‌شود ساخت قابلیت‌های مهم مثل ثبت‌نام، نمایش وضعیت کاربر، ارسال اطلاعات و تغییر تنظیمات بسیار ساده‌تر و قابل اطمینان‌تر شود.

چرا یادگیری Command برای پروژه‌های آینده ضروری است

یادگیری Commands فقط برای شروع نیست؛ بلکه پایه‌ای برای تمام پروژه‌های آینده محسوب می‌شود. بدون تسلط بر Commands، توسعه ربات‌های حرفه‌ای تقریباً غیرممکن است.

دلایل اصلی اهمیت Commands:

  • هر ربات حرفه‌ای مجموعه‌ای از دستورات اصلی دارد (مثل /start، /help، /about).
  • برای مدیریت کاربران جدید و ذخیره اطلاعات، Commandها نقطه شروع هستند.
  • برای افزودن قابلیت‌های پیچیده مثل تنظیمات شخصی، گزارش‌گیری و کنترل ادمین، Commands ابزار اصلی هستند.
  • در ربات‌های سازمانی، کل فرآیندها بر اساس دستورات ساخت‌یافته طراحی می‌شوند.
  • حتی در پروژه‌هایی که از منوهای شیشه‌ای استفاده می‌کنند، Commands همچنان ستون اصلی منطق ربات باقی می‌مانند.

به زبان ساده:
اگر Commands را به‌خوبی یاد بگیرید، می‌توانید هر نوع رباتی بسازید؛ از یک ربات ساده پیام‌گو گرفته تا سیستم‌های پیچیده مدیریت کاربران، فروشگاه‌ها، سیستم رزرو، گزارش‌گیری و حتی ربات‌های هوش‌مصنوعی.

معرفی کامل Command در Bot API

Command یا «دستور» در Bot API یکی از مهم‌ترین ابزارهایی است که تلگرام برای تعامل کاربر و ربات ارائه می‌دهد. هر Command در واقع یک پیام ویژه است که با علامت / شروع می‌شود و تلگرام آن را به شکل یک درخواست ساختاریافته برای ربات ارسال می‌کند. این ساختار مشخص باعث می‌شود ربات بتواند رفتارهای منظم، قابل پیش‌بینی و قابل گسترش داشته باشد. تقریباً تمام ربات‌های حرفه‌ای – از ابزارهای ساده گرفته تا سیستم‌های بزرگ سازمانی – بر پایه همین دستورات ساخته می‌شوند.

Commandها اجازه می‌دهند:

  • شروع ارتباط با ربات مدیریت شود
  • عملیات‌های اصلی به‌صورت مستقیم فعال شوند
  • کاربر نیازی به حفظ چت‌های طولانی یا منوهای پیچیده نداشته باشد
  • قابلیت‌ها دقیق و بدون تفسیر اضافه اجرا شوند

به همین دلیل یادگیری Command نه فقط پایه‌ای، بلکه ضروری برای ساخت ربات‌های حرفه‌ای است.

ساختار کلی یک دستور در تلگرام

هر دستور در تلگرام الگوی مشخصی دارد که باید دقیق رعایت شود. ساختار عمومی به شکل زیر است:

/command
یا
/command arguments

اجزا:

  1. علامت / در ابتدای دستور
  2. نام دستور (بدون فاصله)
  3. آرگومان‌ها در صورت نیاز، با یک فاصله بعد از دستور

مثال‌های معتبر:
/start
/help
/weather tehran
/setname ali

در گروه‌ها ممکن است دستور همراه نام ربات باشد:
/help@my_robot

این حالت زمانی استفاده می‌شود که چند ربات در یک گروه حضور دارند و تلگرام باید تشخیص دهد فرمان برای کدام ربات ارسال شده است.

نکات ساختاری مهم:

  • نام دستور فقط شامل حروف انگلیسی کوچک، اعداد و _ است
  • نام دستور نمی‌تواند فاصله داشته باشد
  • آرگومان‌ها بعد از فاصله ارسال می‌شوند، نه داخل نام دستور
  • تلگرام Command را مانند پیام عادی منتقل می‌کند اما Bot API علامت‌گذاری ویژه‌ای روی آن انجام می‌دهد تا قابل تشخیص باشد

تفاوت دستورهای public و private

دستورات در Bot API به دو نوع عملی تقسیم می‌شوند: public و private. تفاوت این دو نوع از نظر نحوه ثبت، نمایش و دسترسی کاربران است.

دستورات public:

  • در BotFather ثبت می‌شوند
  • در منوی ربات برای کاربران نمایش داده می‌شوند
  • قابل مشاهده، قابل کلیک و عمومی هستند
  • معمولاً شامل دستورات پایه ربات هستند مثل:
    /start
    /help
    /about

کاربرد:
برای آشنا کردن کاربر با ربات و ارائه تجربه کاربری ساده و سریع.

دستورات private:

  • در BotFather ثبت نمی‌شوند
  • فقط کاربرانی که نام دستور را می‌دانند می‌توانند آن را استفاده کنند
  • معمولاً برای مدیریت، پیکربندی یا عملیات حسّاس استفاده می‌شود
  • مثال:
    /admin
    /broadcast
    /reset_settings

چرا private؟

  • جلوگیری از نمایش دستورات حساس در منو
  • محدود کردن دسترسی تنها به افراد مورد نظر
  • جلوگیری از کنجکاوی کاربران عادی

تلگرام به‌صورت تکنیکی بین این دو نوع تفاوتی نمی‌گذارد؛ تفاوت فقط به این بستگی دارد که شما آن‌ها را در BotFather ثبت می‌کنید یا خیر.

محدودیت‌ها و نکات مهم در تعریف Command

هنگام طراحی و اضافه‌کردن دستورات جدید باید چند محدودیت و نکته اساسی را در نظر بگیرید تا از خطاها و تجربه کاربری ضعیف جلوگیری شود.

محدودیت‌های رسمی:

  • نام دستور نباید بیشتر از 32 کاراکتر باشد
  • فقط حروف کوچک انگلیسی، اعداد و _ مجاز هستند
  • استفاده از فاصله و کاراکترهای خاص غیرمجاز است
  • دستورها باید یکتا باشند؛ نمی‌توان دو دستور با نام یکسان داشت
  • برای گروه‌ها، دستور باید همراه با @botname هم قابل استفاده باشد

نکات عملی مهم:

  • نام دستور باید کوتاه، واضح و قابل حدس باشد
  • دستورهایی مثل /start و /help همیشه باید بدون خطا اجرا شوند
  • برای دستورهای نیازمند آرگومان، بهتر است مثال در پیام راهنما ارائه شود
  • دستورات مدیریتی را در BotFather ثبت نکنید تا در منوی ربات نمایش داده نشوند
  • اگر ربات چند قابلیت دارد، دستورها باید منطقی و دسته‌بندی‌شده باشند
  • از نام‌های گیج‌کننده یا پیچیده پرهیز کنید (مثلاً /adminpanelv2 مناسب نیست)

چرا این‌ها مهم‌اند؟
زیرا Commands اولین چیزی هستند که کاربران تجربه می‌کنند و کیفیت طراحی آن‌ها به‌طور مستقیم روی اعتبار ربات و میزان استفاده کاربران تأثیر می‌گذارد.

تعریف دستورات در BotFather

برای اینکه کاربران بتوانند از دستورات ربات شما به‌صورت استاندارد و یک‌کلیک استفاده کنند، باید آن‌ها را در BotFather تعریف کنید. BotFather تنها ابزار رسمی تلگرام برای مدیریت ویژگی‌های ربات است و هر دستوری که اینجا ثبت شود در منوی ربات برای کاربران نمایش داده می‌شود. برای ثبت دستورات، کافی است در BotFather پیام setcommands/ را ارسال کنید، ربات خود را انتخاب کنید و سپس لیست دستورها را با فرمت مشخص وارد کنید. هر خط باید شامل نام دستور و توضیح کوتاه آن باشد، مانند:
start – شروع استفاده از ربات
help – نمایش راهنما
weather – وضعیت آب‌وهوا

این لیست پس از ذخیره، فوراً در اپلیکیشن تلگرام برای همه کاربران قابل مشاهده می‌شود.

نحوه تعریف لیست دستورات برای کاربران

لیست دستورات نقش منوی اصلی ربات را دارد و باید ساده، منظم و قابل فهم باشد. هنگام ثبت در BotFather چند نکته مهم را رعایت کنید:

  • توضیح هر دستور باید بسیار کوتاه و روشن باشد.
  • دستورهای پرکاربرد در ابتدا قرار بگیرند.
  • از نام‌های قابل حدس استفاده کنید تا کاربران نیازی به توضیحات اضافی نداشته باشند.
  • دستورهایی که مخصوص کاربران عادی نیستند را اصلاً در این لیست قرار ندهید.

نمونه یک لیست استاندارد:
start – شروع ربات
help – راهنمای استفاده
daily – فعال‌سازی پیام روزانه
stopdaily – غیرفعال‌سازی پیام روزانه

حفظ سادگی مهم است؛ هرچقدر لیست مختصرتر باشد، تجربه کاربر بهتر خواهد شد.

نکات امنیتی و اصول نام‌گذاری استاندارد

نام‌گذاری درست دستورات نه‌تنها باعث می‌شود کاربر راحت‌تر با ربات تعامل کند، بلکه امنیت ربات نیز بالاتر می‌رود. دستورات مدیریتی مانند broadcast/ یا admin/ هرگز نباید در BotFather ثبت شوند، زیرا عمومی خواهند شد و هر کاربری آن‌ها را خواهد دید. این دستورات را فقط در کد ربات تعریف کنید و قبل از اجرا، هویت ارسال‌کننده را بررسی کنید.

در نام‌گذاری استاندارد رعایت این نکات ضروری است:

  • فقط از حروف کوچک انگلیسی استفاده کنید.
  • از فاصله و کاراکترهای غیرمجاز پرهیز کنید.
  • دستورها باید کوتاه و معنی‌دار باشند.
  • در صورت نیاز از جداکننده _ استفاده کنید.
  • از نام‌های پیچیده، طولانی یا مشابه دوری کنید.

نمونه نام‌گذاری صحیح:
userinfo
setname
getweather

نمونه نام‌گذاری اشتباه:
getweathercityinfo
username_get_command
adminpanelv2

ساخت دسته‌بندی برای دستورات طولانی

اگر ربات شما تعداد زیادی دستور دارد، اضافه‌کردن همه آن‌ها به منوی BotFather باعث شلوغی و سردرگمی می‌شود. برای مدیریت حرفه‌ای، باید دستورات را دسته‌بندی کنید تا کاربران فقط موارد مهم را در منوی اصلی ببینند و بقیه از طریق زیردسته‌ها یا پیام‌های راهنما ارائه شوند.

سه روش کاربردی برای دسته‌بندی:

روش اول: دستورهای مادر
مثلاً دستور settings/ را در BotFather ثبت می‌کنید و وقتی کاربر آن را می‌زند، فهرست زیردستورات مانند set_name/ ،set_city/ یا set_age/ را به کاربر نمایش می‌دهید.

روش دوم: پیشوند مشترک
برای گروهی از دستورات از پیشوند یکسان استفاده کنید، مثل:
admin_users
admin_stats
admin_notify

این روش برای ربات‌های بزرگ بسیار مناسب است.

روش سوم: ترکیبی (پیشنهادی)
چند دستور عمومی در BotFather ثبت کنید و باقی دستورها را فقط در پاسخ‌ها یا پیام‌های راهنمای داخل ربات نمایش دهید. این روش باعث می‌شود منوی ربات همیشه کوچک، خوانا و قابل‌استفاده باقی بماند.

جمع‌بندی کوتاه
ثبت صحیح دستورات در BotFather، نام‌گذاری استاندارد و دسته‌بندی حرفه‌ای باعث می‌شود ربات شما ظاهر منسجم، امن و کاربرپسند داشته باشد. هرچه ساختار دستورات بهتر طراحی شود، تجربه کاربر روان‌تر خواهد بود و نگهداری پروژه برای شما نیز بسیار ساده‌تر می‌شود.

کار با Command Handler در پایتون

در ربات‌های تلگرامی، Command Handler وظیفه دارد پیام‌هایی را که با یک دستور شروع می‌شوند تشخیص دهد و تابع مشخصی را اجرا کند. این مکانیزم باعث می‌شود بتوانید برای هر دستور یک رفتار منظم، مستقل و قابل نگهداری تعریف کنید. در پایتون بسته به کتابخانه‌ای که استفاده می‌کنید (python-telegram-bot یا telebot)، نحوه تعریف Command Handler کمی متفاوت است اما مفهوم یکسان است:
«تشخیص دستور و اجرای تابع مربوط به آن با پارامترهای ورودی.»

در عمل، Command Handler مهم‌ترین نقطه تعامل کاربران با ربات است، بنابراین یادگیری آن برای ساخت ربات حرفه‌ای ضروری است.

تعریف CommandHandler در python-telegram-bot

در کتابخانه python-telegram-bot، شما CommandHandler را در ماژول handlers پیدا می‌کنید و با اضافه‌کردن آن به اپلیکیشن، دستور را ثبت می‌کنید.

مثال ساده:

from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("سلام! ربات فعال شد.")

app = Application.builder().token("TOKEN").build()

app.add_handler(CommandHandler("start", start))

app.run_polling()

نکات مهم:

  • دستور بدون / نوشته می‌شود (start).
  • توابع باید async باشند.
  • اگر کاربر همراه دستور متن اضافی ارسال کند، این ورودی در context.args قرار می‌گیرد.

مثال با ورودی:
ورودی کاربر:
/setname Ali

context.args → [“Ali”]

تعریف @bot.message_handler(commands=[]) در telebot

در کتابخانه telebot روش کار ساده‌تر و نزدیک‌تر به سبک دکوراتور است. دستورها با یک دکوراتور تعریف می‌شوند و پیام‌های شامل آن دستور به تابع موردنظر ارسال می‌شود.

مثال مشابه:

import telebot

bot = telebot.TeleBot("TOKEN")

@bot.message_handler(commands=["start"])
def start(message):
    bot.send_message(message.chat.id, "سلام! ربات فعال شد.")

bot.infinity_polling()

ویژگی‌ها:

  • لیست commands می‌تواند چند دستور را یکجا مدیریت کند.
  • ورودی‌های اضافی پس از دستور در message.text قابل پردازش هستند.
  • توابع async نیستند و اجرای ساده‌تری دارند.

مثال با ورودی:
ورودی کاربر:
/setname Ali

message.text → “/setname Ali”
شما باید خودتان پارس کنید:

@bot.message_handler(commands=["setname"])
def setname(message):
    parts = message.text.split(maxsplit=1)
    if len(parts) == 2:
        name = parts[1]
        bot.send_message(message.chat.id, f"اسم ذخیره شد: {name}")
    else:
        bot.send_message(message.chat.id, "یک نام وارد کنید.")

تفاوت بین دو کتابخانه با مثال

برای درک بهتر تفاوت‌ها، یک مثال مشترک را در هر دو کتابخانه بررسی کنیم: دستور /weather tehran.

python-telegram-bot:

async def weather(update, context):
    city = context.args[0] if context.args else None
    if not city:
        await update.message.reply_text("لطفاً نام شهر را وارد کنید.")
        return
    await update.message.reply_text(f"آب‌وهوا برای شهر {city} دریافت شد!")

app.add_handler(CommandHandler("weather", weather))

telebot:

@bot.message_handler(commands=["weather"])
def weather(message):
    parts = message.text.split(maxsplit=1)
    if len(parts) == 1:
        bot.send_message(message.chat.id, "لطفاً نام شهر را وارد کنید.")
        return
    city = parts[1]
    bot.send_message(message.chat.id, f"آب‌وهوا برای شهر {city} دریافت شد!")

تفاوت اصلی:

  • python-telegram-bot ورودی‌ها را خودش پارس می‌کند و در context.args می‌گذارد.
  • telebot ورودی‌ها را به صورت message.text خام می‌دهد و شما باید خودتان آن را پردازش کنید.
  • python-telegram-bot ساختار منظم‌تر، async و مناسب پروژه‌های بزرگ است.
  • telebot برای شروع سریع، ساده‌تر و مناسب پروژه‌های کوچک است.

مدیریت ورودی اضافی همراه با دستور

کاربران معمولاً فقط دستور نمی‌نویسند؛ ممکن است اطلاعاتی مانند نام، شهر، شماره یا متن طولانی همراه آن ارسال کنند. مدیریت این ورودی‌ها بخش مهمی از Command Handling است.

روش‌های استاندارد برای مدیریت ورودی همراه دستور:

  1. دریافت یک مقدار ساده
    مثال:
    /setname Ali
    پارامتر اول پس از دستور → نام

python-telegram-bot: context.args[0]
telebot: split روی message.text

  1. دریافت چند پارامتر
    مثال:
    /setreminder 10 meeting

python-telegram-bot: context.args → [“10”, “meeting”]
telebot: split → بخش‌بندی دستی

  1. دریافت متن طولانی
    مثال:
    /feedback متن دلخواه کاربر…

بهترین روش:
split(maxsplit=1)
بخش ۱ → نام دستور
بخش ۲ → متن کامل

  1. جلوگیری از خطا
    همیشه ورودی ناقص را مدیریت کنید:
  • اگر ورودی نبود، راهنمای استفاده بدهید.
  • اگر تعداد پارامترها اشتباه بود، پیام راهنما ارسال کنید.
  • داده‌ها را قبل از استفاده اعتبارسنجی کنید.

مثال استاندارد برای telebot:

@bot.message_handler(commands=["feedback"])
def feedback(message):
    parts = message.text.split(maxsplit=1)
    if len(parts) < 2:
        bot.send_message(message.chat.id, "لطفاً متن بازخورد را بنویسید.")
        return

    feedback_text = parts[1]
    bot.send_message(message.chat.id, "بازخورد شما ثبت شد. ممنون!")

مثال استاندارد برای python-telegram-bot:

async def feedback(update, context):
    if not context.args:
        await update.message.reply_text("لطفاً متن بازخورد را بنویسید.")
        return

    text = " ".join(context.args)
    await update.message.reply_text("بازخورد شما ثبت شد. ممنون!")

جمع‌بندی کوتاه
درک Command Handler برای ساخت ربات حرفه‌ای ضروری است. کتابخانه python-telegram-bot ساختار دقیق‌تر و مدیریت بهتری روی ورودی‌ها دارد، در حالی که telebot ساده‌تر و سریع‌تر برای شروع است. مدیریت ورودی‌ها—چه کوتاه و چه طولانی—بخش مهمی از طراحی دستورهای کاربردی است و رعایت نکات گفته‌شده باعث می‌شود ربات شما تمیزتر، واضح‌تر و قابل‌اعتمادتر عمل کند.

ساخت دستورات پایه و ضروری برای ربات تلگرامی

در هر ربات تلگرامی، اولین بخش‌هایی که باید ساخته شوند مجموعه‌ای از دستورات پایه هستند؛ دستورهایی که تعامل اولیه با ربات را شکل می‌دهند، مسیر استفاده را روشن می‌کنند و به کاربران کمک می‌کنند ربات را به‌درستی درک و تجربه کنند. در این بخش، ساخت سه دستور مهم یعنی start/ ،help/ و about/ را بررسی می‌کنیم و در ادامه نکات UX برای طراحی پیام‌های دستوری را مرور می‌کنیم تا خروجی شما حرفه‌ای و کاربرپسند باشد.

ساخت دستورات پایه برای ربات

دستورات پایه در هر ربات شامل موارد زیر هستند:

  • start/ برای شروع تعامل
  • help/ برای نمایش راهنما
  • about/ برای اطلاعات کوتاه درباره ربات
    این دستورها معمولاً اولین چیزهایی هستند که کاربر با آن‌ها مواجه می‌شود و بنابراین باید بسیار واضح، کوتاه و خوش‌ساخت باشند. این بخش‌ها بنیان تجربه کاربری ربات شما را تشکیل می‌دهند.

پیاده‌سازی /start با پیام خوش‌آمد

دستور start/ زمانی اجرا می‌شود که کاربر برای اولین بار وارد ربات شود یا چند بار بخواهد تعامل را از نو شروع کند. پیام این دستور باید دوستانه، کوتاه و راهنمای شروع سریع باشد.

نمونه در python-telegram-bot:

async def start(update, context):
    text = (
        "سلام! خوش اومدی 😊\n"
        "من ربات نمونه هستم و می‌تونم کارهای مختلفی انجام بدم.\n"
        "برای دیدن امکانات، دستور /help رو بزن."
    )
    await update.message.reply_text(text)

نمونه در telebot:

@bot.message_handler(commands=["start"])
def start(message):
    text = (
        "سلام! خوش اومدی 😊\n"
        "برای دیدن امکانات ربات دستور /help رو ارسال کن."
    )
    bot.send_message(message.chat.id, text)

نکات مهم برای پیام خوش‌آمد:

  • کاربر را با لحن دوستانه و کوتاه دعوت کنید.
  • حتماً کاربر را به مرحله بعد هدایت کنید (معمولاً دستور help/).
  • از متن طولانی خودداری کنید.

پیاده‌سازی /help برای معرفی امکانات

هدف دستور help/ نمایش امکانات ربات و نحوه استفاده از هر بخش است. بهتر است این پیام کاملاً شفاف، طبقه‌بندی‌شده و قابل مطالعه باشد.

نمونه در python-telegram-bot:

async def help_command(update, context):
    text = (
        "لیست دستورات ربات:\n\n"
        "/start - شروع استفاده از ربات\n"
        "/help - نمایش این راهنما\n"
        "/about - اطلاعات درباره ربات\n"
        "/weather شهر - دریافت آب‌وهوا\n"
        "برای مثال: /weather tehran"
    )
    await update.message.reply_text(text)

نمونه در telebot:

@bot.message_handler(commands=["help"])
def help_command(message):
    text = (
        "راهنمای ربات:\n\n"
        "/start - شروع دوباره\n"
        "/help - نمایش راهنما\n"
        "/about - اطلاعات ربات\n"
        "برای دیدن آب‌وهوا:  /weather tehran"
    )
    bot.send_message(message.chat.id, text)

نکته مهم:
پیام help/ باید همیشه به‌روزرسانی شود و با امکانات واقعی ربات همخوان باشد.

ساخت یک دستور اطلاعاتی مثل /about

دستور about/ برای معرفی سازنده، هدف ربات یا اطلاعات تکمیلی استفاده می‌شود. این دستور نباید طولانی باشد؛ معمولاً جانمایی آن میان start/ و help/ قرار دارد.

نمونه python-telegram-bot:

async def about(update, context):
    text = (
        "این ربات با پایتون ساخته شده و هدفش آموزش مراحل ساخت ربات‌های تلگرامی است.\n"
        "توسعه‌دهنده: شما ✨"
    )
    await update.message.reply_text(text)

نمونه telebot:

@bot.message_handler(commands=["about"])
def about(message):
    text = (
        "ربات نمونه آموزشی تلگرام با پایتون.\n"
        "هدف: یادگیری قدم به قدم ساخت ربات."
    )
    bot.send_message(message.chat.id, text)

کاربرد دستور about/:

  • معرفی کوتاه و رسمی
  • نمایش نسخه ربات
  • توضیح هدف و امکانات اصلی

نکات UX برای طراحی پیام‌های دستوری

برای اینکه ربات شما حرفه‌ای، شفاف و کاربرپسند باشد، رعایت چند نکته کلیدی در طراحی پیام‌ها ضروری است:

  • پیام‌ها باید کوتاه، هدفمند و قابل اسکن توسط چشم باشند.
  • از متن‌های طولانی که موبایل را پر می‌کنند خودداری کنید.
  • برای بخش‌بندی پیام چند خط خالی اضافه کنید.
  • از ایموجی‌ها به‌صورت محدود استفاده کنید تا پیام گرم‌تر شود ولی کودکانه نشود.
  • در انتهای هر پیام، اقدام بعدی را مشخص کنید (Call To Action).
  • دستوراتی که نیاز به ورودی دارند، مثال کاربردی بدهید.
  • در پیام‌ها از اصطلاحات فنی پیچیده پرهیز کنید.
  • پیام‌های تکراری یا نامشخص تجربه کاربر را کاهش می‌دهد.

نکته طلایی:
هر پیام باید یک هدف مشخص داشته باشد: خوش‌آمد، راهنمای استفاده، درخواست ورودی یا معرفی امکانات.

جمع‌بندی کوتاه
سه دستور start/ ،help/ و about/ شالوده هر ربات تلگرامی هستند و پایه تجربه کاربر را تشکیل می‌دهند. با طراحی پیام‌های واضح، کوتاه و خوش‌ساخت و رعایت نکات UX، می‌توانید رباتی حرفه‌ای و قابل‌استفاده بسازید. اگر بخواهید، می‌توانم بخش بعدی را درباره ساخت دستورهای پیشرفته مثل /weather همراه با گرفتن ورودی یا ارسال دکمه‌های تعاملی ارائه کنم.

ارسال پاسخ‌های قالب‌بندی‌شده در دستورات ربات تلگرام

در بسیاری از ربات‌ها لازم است پاسخ‌ها فقط متن ساده نباشند؛ گاهی باید عبارت‌ها پررنگ شوند، لینک قرار بگیرد، متن بخش‌بندی شود یا حتی عکس و دکمه ارسال کنید. تلگرام دو روش قالب‌بندی Markdown و HTML را پشتیبانی می‌کند اما اگر درست استفاده نشوند باعث خطای رایج markdown_invalid می‌شوند. این بخش تمام اصول لازم برای ارسال پیام‌های قالب‌بندی‌شده و حرفه‌ای را به‌صورت ساده توضیح می‌دهد.

ارسال پاسخ‌های قالب‌بندی‌شده در دستورات

برای اینکه پیام‌های شما خواناتر و حرفه‌ای‌تر باشند می‌توانید از ویژگی‌های زیر استفاده کنید:

  • بولد کردن
  • ایتالیک
  • لینک
  • فهرست‌ها
  • بلوک کد
  • نقل‌قول
  • عکس و دکمه‌ها

در هر دو کتابخانه python-telegram-bot و telebot، کافی است نوع پارس پیام را مشخص کنید.

نمونه در python-telegram-bot:

await update.message.reply_text(
    "*به ربات خوش اومدی!* \n\n_این یک متن نمونه است._",
    parse_mode="Markdown"
)

نمونه در telebot:

bot.send_message(
    message.chat.id,
    "<b>به ربات خوش اومدی!</b>\n<i>این یک متن نمونه است.</i>",
    parse_mode="HTML"
)

استفاده از Markdown و HTML

تلگرام دو روش رسمی برای قالب‌بندی پشتیبانی می‌کند:

  1. Markdown (نسخه ساده تلگرام)
  1. HTML

نکته مهم:
Markdown در تلگرام نسخه کامل Markdown نیست و بسیاری از کاراکترها اگر درست escape نشوند خطا می‌دهند. HTML پایدارتر و کمتر خطادار است.

نمونه Markdown:

text = "*عنوان اصلی*\n_متن توضیحی_"
await update.message.reply_text(text, parse_mode="Markdown")

نمونه HTML:

text = "<b>عنوان اصلی</b>\n<i>متن توضیحی</i>"
bot.send_message(message.chat.id, text, parse_mode="HTML")

اگر برای کاربرانی که پیام شما را منتقل می‌کنند سازگاری بیشتر می‌خواهید، HTML انتخاب بهتری است.

ارسال عکس، دکمه، لینک و… در پاسخ یک دستور

بسیاری از ربات‌ها هنگام اجرای دستور باید عناصر اضافی مثل تصویر، دکمه، یا لینک ارسال کنند.

ارسال عکس در python-telegram-bot:

await update.message.reply_photo(
    photo="https://example.com/image.jpg",
    caption="این یک عکس نمونه است"
)

ارسال عکس در telebot:

bot.send_photo(
    message.chat.id,
    "https://example.com/image.jpg",
    caption="این یک عکس نمونه است"
)

ارسال دکمه (InlineKeyboard):

python-telegram-bot:

from telegram import InlineKeyboardButton, InlineKeyboardMarkup

button = InlineKeyboardButton("باز کردن لینک", url="https://example.com")
markup = InlineKeyboardMarkup([[button]])

await update.message.reply_text("روی دکمه کلیک کن:", reply_markup=markup)

telebot:

from telebot.types import InlineKeyboardButton, InlineKeyboardMarkup

markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton("باز کردن لینک", url="https://example.com"))

bot.send_message(message.chat.id, "روی دکمه کلیک کن:", reply_markup=markup)

کاربردهای رایج دکمه‌ها:

  • ارسال لینک
  • اجرای Callback
  • جابه‌جایی بین صفحات
  • تأیید یا لغو عملیات

جلوگیری از خطای markdown_invalid

این خطا یکی از رایج‌ترین مشکلات هنگام استفاده از Markdown است. علت دقیق آن معمولاً وجود کاراکترهای خاص، ناهماهنگی بین * یا _ یا استفاده همزمان از قالب‌بندی‌های اشتباه است.

روش‌های جلوگیری:

  • همیشه از HTML استفاده کنید؛ هوشمندتر و پایدارتر است.
  • اگر Markdown استفاده می‌کنید، حتماً کاراکترهای *، _, [, ], (, )، ` را escape کنید.
  • متن‌هایی که از کاربر دریافت می‌کنید را بدون قالب‌بندی ارسال نکنید، چون ممکن است داخل آن‌ها کاراکترهای مشکل‌زا وجود داشته باشد.
  • در Markdown همیشه یک کاراکتر فضای خالی قبل یا بعد از قالب‌بندی قرار دهید.
  • در صورت ارسال لینک Markdown، آدرس باید بدون فاصله باشد.

نمونه اشتباه در Markdown:
این یک متن لینک نامعتبر است

نمونه درست:
این یک متن لینک معتبر است

اگر پیام کاربر را داخل Markdown قرار می‌دهید:

اشتباه:
بازخورد شما: ” + user_message

درست:

user_text = user_text.replace("*", "\\*").replace("_", "\\_")

یا راحت‌ترین و امن‌ترین گزینه:

  • اصلاً از Markdown استفاده نکنید و فقط HTML استفاده کنید.

جمع‌بندی کوتاه
با استفاده از Markdown و HTML می‌توانید پیام‌های زیبایی برای ربات تولید کنید، اما HTML معمولاً کم‌خطاتر و پایدارتر است. ارسال عکس، لینک، دکمه‌ و عناصر تعاملی باعث حرفه‌ای‌تر شدن ربات می‌شود. اگر از Markdown استفاده می‌کنید، حتماً کاراکترهای خاص را escape کنید تا خطای markdown_invalid نگیرید. در بخش‌های بعدی می‌توانم ساخت پاسخ‌های چندرسانه‌ای پیچیده‌تر، ارسال آلبوم، منوی تعاملی و طراحی کارت اطلاعات حرفه‌ای را آموزش دهم.

ساخت دستورات پیشرفته در ربات تلگرام

بعد از ساخت دستورهای پایه، نوبت به ساخت دستورهای پیشرفته‌تر می‌رسد؛ دستورهایی که ورودی دریافت می‌کنند، خطا را مدیریت می‌کنند، چند پیام ارسال می‌کنند و حتی دکمه‌های تعاملی دارند. این بخش تمام اصول لازم برای طراحی دستورهای کاربردی‌تر را پوشش می‌دهد.


دستور با ورودی: مثال /weather Tehran

یک دستور پیشرفته معمولاً ورودی دریافت می‌کند. مثال کلاسیک:
weather Tehran/

کاربر نام شهر را بعد از دستور وارد می‌کند و ربات باید آن را پردازش کند.

نمونه در python-telegram-bot:

async def weather(update, context):
    if not context.args:
        await update.message.reply_text("لطفاً نام شهر را وارد کنید. مثال:\n/weather tehran")
        return

    city = " ".join(context.args)
    await update.message.reply_text(f"در حال دریافت آب‌وهوا برای: {city}")

نمونه در telebot:

@bot.message_handler(commands=["weather"])
def weather(message):
    parts = message.text.split(maxsplit=1)
    if len(parts) < 2:
        bot.send_message(message.chat.id, "لطفاً نام شهر را وارد کنید. مثال:\n/weather tehran")
        return

    city = parts[1]
    bot.send_message(message.chat.id, f"در حال دریافت آب‌وهوا برای: {city}")

نکته مهم: split(maxsplit=1) بهترین روش برای دریافت ورودی است، چون ورودی چندکلمه‌ای را هم مدیریت می‌کند.


وریفای ورودی و مدیریت خطا

ورودی کاربر همیشه معتبر نیست؛ ممکن است خالی، اشتباه یا مخدوش باشد. ربات باید ورودی را قبل از استفاده بررسی کند.

نکات مهم در وریفای ورودی:

  • اگر ورودی خالی بود، پیام راهنمای درست بدهید.
  • اگر ورودی باید عدد باشد، بررسی کنید.
  • اگر ورودی نباید شامل کاراکتر خاص باشد، آن را فیلتر کنید.
  • در صورت خطا پیام دوستانه و واضح بفرستید.

مثال بررسی ورودی عددی:

async def reminder(update, context):
    if not context.args:
        await update.message.reply_text("مثال درست:\n/remind 10")
        return

    if not context.args[0].isdigit():
        await update.message.reply_text("عدد وارد کنید. مثال:\n/remind 10")
        return

    minutes = int(context.args[0])
    await update.message.reply_text(f"یادآور برای {minutes} دقیقه دیگر تنظیم شد.")

یا در telebot:

if not parts[1].isdigit():
    bot.send_message(chat_id, "عدد معتبر وارد کنید.")

ورودی کاربر همیشه نامطمئن است؛ شما باید آن را امن و قابل استفاده کنید.


ارسال چند پیام با یک فرمان

گاهی لازم است ربات با یک دستور چند پیام پشت سر هم ارسال کند؛ مثلاً نمایش مراحل، نتایج چندگانه، یا ارسال عکس و سپس توضیح.

python-telegram-bot:

async def info(update, context):
    await update.message.reply_text("مرحله ۱: دریافت اطلاعات...")
    await update.message.reply_text("مرحله ۲: پردازش داده‌ها...")
    await update.message.reply_text("مرحله ۳: نتیجه آماده است!")

telebot:

@bot.message_handler(commands=["info"])
def info(message):
    bot.send_message(message.chat.id, "مرحله ۱ انجام شد.")
    bot.send_message(message.chat.id, "مرحله ۲ انجام شد.")
    bot.send_message(message.chat.id, "مرحله ۳ انجام شد.")

نکته طراحی:
هنگام ارسال چند پیام، ترتیب آن باید منطقی، کوتاه و مرحله‌به‌مرحله باشد تا کاربر حس کنترل داشته باشد.


ساخت دکمه‌های Reply و Inline برای دستورات

برای ساخت ربات حرفه‌ای، باید بتوانید دکمه‌های تعاملی اضافه کنید. این دکمه‌ها دو نوع هستند:

  1. Reply Keyboard (دکمه‌های بزرگ پایین صفحه)
  2. Inline Keyboard (دکمه‌هایی که زیر پیام ظاهر می‌شوند)

دکمه Reply Keyboard:

python-telegram-bot:

from telegram import ReplyKeyboardMarkup

keyboard = [["Weather", "Help"], ["About"]]
markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True)

await update.message.reply_text("یکی را انتخاب کنید:", reply_markup=markup)

telebot:

from telebot.types import ReplyKeyboardMarkup

markup = ReplyKeyboardMarkup(resize_keyboard=True)
markup.row("Weather", "Help")
markup.row("About")

bot.send_message(chat_id, "یکی را انتخاب کن:", reply_markup=markup)

دکمه Inline Keyboard:

python-telegram-bot:

from telegram import InlineKeyboardButton, InlineKeyboardMarkup

btn = InlineKeyboardButton("باز کردن سایت", url="https://example.com")
markup = InlineKeyboardMarkup([[btn]])

await update.message.reply_text("روی دکمه کلیک کن:", reply_markup=markup)

telebot:

from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton

markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton("باز کردن سایت", url="https://example.com"))

bot.send_message(chat_id, "روی دکمه کلیک کن:", reply_markup=markup)

کاربردهای واقعی دکمه‌ها:

  • نمایش منوی اصلی
  • انتخاب گزینه از بین چند مورد
  • ارسال لینک
  • دریافت تأیید (مثبت یا منفی)
  • صفحه‌بندی نتایج
  • هدایت کاربر بین مراحل یک فرآیند

جمع‌بندی کوتاه
در دستورات پیشرفته شما ورودی کاربر را دریافت می‌کنید، آن را وریفای می‌کنید، چند پیام ارسال می‌کنید و حتی دکمه‌های تعاملی نمایش می‌دهید. این موارد ربات را از یک ابزار ساده به یک سیستم واقعی تبدیل می‌کنند. با ترکیب ورودی، مدیریت خطا، دکمه‌ها و پیام‌های چندمرحله‌ای، می‌توانید دستورات بسیار حرفه‌ای و قابل توسعه بسازید.

ساخت دستورات تعاملی و چندمرحله‌ای در ربات تلگرام

بعضی دستورها فقط یک پیام برنمی‌گردانند؛ بلکه یک «فرآیند» را آغاز می‌کنند.
مثلاً ثبت‌نام کاربر، گرفتن چند ورودی، تغییر تنظیمات، یا ساخت یک فرم چندمرحله‌ای.
برای ساخت چنین سیستم‌هایی باید از state (وضعیت فعلی کاربر) استفاده کنید تا بدانید کاربر در کدام مرحله قرار دارد و پاسخ بعدی او به کدام بخش مربوط می‌شود. این بخش به زبان ساده و همراه مثال کامل، ساخت دستورات تعاملی حرفه‌ای را آموزش می‌دهد.


دستورات تعاملی (Interactive Commands)

دستورات تعاملی دستورهایی هستند که پس از اجرا به یک مکالمه چندمرحله‌ای منجر می‌شوند.
ویژگی‌های آن‌ها:

  • کاربر یک دستور وارد می‌کند، مثلاً register/
  • ربات یک سؤال می‌پرسد
  • منتظر پاسخ کاربر می‌ماند
  • پاسخ را ذخیره می‌کند
  • سؤال بعدی را می‌پرسد
  • در مراحل بعد داده‌ها را کامل کرده و در پایان نتیجه را اعلام می‌کند

این ساختار مشابه فرم‌های چند صفحه‌ای در وب است.

کاربردهای واقعی:

  • فرم ثبت‌نام
  • گرفتن اطلاعات پرداخت
  • تنظیمات پروفایل
  • ثبت سفارش
  • ایجاد تیکت پشتیبانی
  • نظرسنجی چندمرحله‌ای

برای پیاده‌سازی چنین فرآیندی باید state کاربران را مدیریت کنید.


ساخت منوی چندمرحله‌ای با دستور

در یک منوی چندمرحله‌ای، ربات در هر مرحله چند گزینه نشان می‌دهد و کاربر باید یکی را انتخاب کند. این ساختار معمولاً با InlineKeyboard انجام می‌شود.

مثال ساخت منوی چندمرحله‌ای (python-telegram-bot):

from telegram import InlineKeyboardButton, InlineKeyboardMarkup

async def menu(update, context):
    buttons = [
        [InlineKeyboardButton("نمایش اطلاعات", callback_data="info")],
        [InlineKeyboardButton("تنظیمات", callback_data="settings")]
    ]
    markup = InlineKeyboardMarkup(buttons)
    await update.message.reply_text("منو:", reply_markup=markup)

async def handle_callback(update, context):
    query = update.callback_query
    data = query.data

    if data == "info":
        await query.message.reply_text("اینجا اطلاعات قرار می‌گیرد.")
    elif data == "settings":
        await query.message.reply_text("این بخش تنظیمات است.")

    await query.answer()

کارکرد این منو:

  • دکمه‌ها مرحله اول هستند
  • کاربر روی یکی کلیک می‌کند
  • callback_data مشخص می‌کند بعدی چه اتفاقی بیفتد

این الگو پایه‌ای برای ساخت منوهای پیچیده‌تر است.


مدیریت state کاربران

State یعنی «کاربر الان در کجای فرآیند قرار دارد؟»

ساده‌ترین روش: یک دیکشنری در حافظه

user_state = {}   # key = chat_id, value = state

مثال:

  • state = “ask_name”
  • state = “ask_age”
  • state = “done”

هنگامی که کاربر پیام جدیدی می‌فرستد:

  1. چک می‌کنید state فعلی چیست
  2. همان مرحله را ادامه می‌دهید

نمونه ساده با telebot:

user_state = {}

@bot.message_handler(commands=["register"])
def start_register(message):
    chat_id = message.chat.id
    user_state[chat_id] = "ask_name"
    bot.send_message(chat_id, "اسم شما چیست؟")

@bot.message_handler(func=lambda msg: True)
def handle_states(message):
    chat_id = message.chat.id

    if chat_id not in user_state:
        return  # کاربر در فرآیند نیست

    state = user_state[chat_id]

    if state == "ask_name":
        user_state[chat_id] = "ask_age"
        bot.send_message(chat_id, f"سلام {message.text}! سن شما چند است؟")

    elif state == "ask_age":
        user_state[chat_id] = "done"
        bot.send_message(chat_id, "ثبت‌نام کامل شد!")

    elif state == "done":
        bot.send_message(chat_id, "شما قبلاً ثبت‌نام کرده‌اید.")

مزیت این روش: ساده
عیب: با ریست شدن ربات از بین می‌رود (برای پروژه واقعی باید در دیتابیس ذخیره شود).


مثال: ثبت‌نام کاربر با چند مرحله سوال و جواب

در این مثال یک فرآیند کامل سه‌مرحله‌ای می‌سازیم:

  1. کاربر دستور register/ را می‌زند
  2. ربات نام می‌پرسد
  3. ربات سن را می‌پرسد
  4. ربات شهر را می‌پرسد
  5. همه اطلاعات را نمایش می‌دهد

نسخه python-telegram-bot:

user_state = {}
user_data = {}

async def register(update, context):
    chat_id = update.message.chat_id
    user_state[chat_id] = "ask_name"
    user_data[chat_id] = {}

    await update.message.reply_text("نام شما چیست؟")

async def handle_messages(update, context):
    chat_id = update.message.chat_id
    text = update.message.text

    if chat_id not in user_state:
        return

    state = user_state[chat_id]

    if state == "ask_name":
        user_data[chat_id]["name"] = text
        user_state[chat_id] = "ask_age"
        await update.message.reply_text("سن شما چند است؟")

    elif state == "ask_age":
        if not text.isdigit():
            await update.message.reply_text("سن باید یک عدد باشد.")
            return

        user_data[chat_id]["age"] = int(text)
        user_state[chat_id] = "ask_city"
        await update.message.reply_text("شهر محل زندگی شما چیست؟")

    elif state == "ask_city":
        user_data[chat_id]["city"] = text
        user_state[chat_id] = "done"

        info = user_data[chat_id]
        summary = f"ثبت‌نام کامل شد!\n\nنام: {info['name']}\nسن: {info['age']}\nشهر: {info['city']}"

        await update.message.reply_text(summary)

و نسخه telebot:

user_state = {}
user_data = {}

@bot.message_handler(commands=["register"])
def start_register(message):
    chat_id = message.chat.id
    user_state[chat_id] = "ask_name"
    user_data[chat_id] = {}
    bot.send_message(chat_id, "نام شما چیست؟")

@bot.message_handler(func=lambda msg: True)
def step_handler(message):
    chat_id = message.chat.id
    text = message.text

    if chat_id not in user_state:
        return

    state = user_state[chat_id]

    if state == "ask_name":
        user_data[chat_id]["name"] = text
        user_state[chat_id] = "ask_age"
        bot.send_message(chat_id, "سن شما چند است؟")

    elif state == "ask_age":
        if not text.isdigit():
            bot.send_message(chat_id, "سن باید عدد باشد.")
            return

        user_data[chat_id]["age"] = int(text)
        user_state[chat_id] = "ask_city"
        bot.send_message(chat_id, "شهر محل سکونت؟")

    elif state == "ask_city":
        user_data[chat_id]["city"] = text
        user_state[chat_id] = "done"

        info = user_data[chat_id]
        bot.send_message(chat_id,
            f"ثبت‌نام تکمیل شد.\nنام: {info['name']}\nسن: {info['age']}\nشهر: {info['city']}"
        )

ویژگی‌های مهم این ساختار:

  • هر مرحله یک سؤال، یک پاسخ
  • مدیریت state برای تعیین مرحله فعلی
  • اعتبارسنجی ورودی
  • نمایش جمع‌بندی نهایی

جمع‌بندی کوتاه
دستورات تعاملی، منوی چندمرحله‌ای و مدیریت state ابزارهای اصلی برای ساخت ربات‌های حرفه‌ای هستند. با همین الگو می‌توانید فرم‌های پیچیده، تنظیمات چندمرحله‌ای، فرآیند خرید، ثبت سفارش و ده‌ها قابلیت دیگر بسازید.

اتصال دستورات ربات تلگرام به APIهای خارجی

برای اینکه ربات شما بتواند اطلاعات واقعی مثل وضعیت هوا، نرخ ارز یا اخبار را نمایش دهد، باید به APIهای خارجی متصل شود. در این مدل، ربات ورودی کاربر را دریافت می‌کند، درخواست HTTP به سرویس ارسال می‌کند و داده‌ها را پس از پردازش به‌صورت قالب‌بندی‌شده به کاربر برمی‌گرداند. این بخش یک نمونه کامل با API هواشناسی ارائه می‌دهد و نکات مهم مثل Timeout و مدیریت خطا را توضیح می‌دهد.

اتصال دستورات به APIهای خارجی

برای اتصال ربات به API مراحل کلی زیر را انجام می‌دهیم:

  • دریافت ورودی از کاربر (مثل نام شهر)
  • ساخت URL بر اساس ورودی
  • ارسال درخواست با requests
  • بررسی وضعیت پاسخ (Status Code)
  • مدیریت خطاهای احتمالی
  • استخراج داده‌ها و ساخت پیام مناسب

ساده‌ترین کتابخانه برای ارتباط با API در پایتون requests است.

نمونه ساده درخواست:

import requests
response = requests.get("https://api.example.com/data", timeout=8)
data = response.json()

استفاده از timeout ضروری است تا ربات هنگ نکند.

نمونه عملی با API هواشناسی

در این مثال از سرویس رایگان OpenWeatherMap استفاده می‌کنیم. شما یک API Key از سایت دریافت می‌کنید و با آن درخواست را ارسال می‌کنید.

نمونه کامل برای python-telegram-bot:

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.openweathermap.org/data/2.5/weather"

async def weather(update, context):
    if not context.args:
        await update.message.reply_text("لطفاً نام شهر را وارد کنید. مثال:\n/weather tehran")
        return

    city = context.args[0]

    try:
        url = f"{BASE_URL}?q={city}&appid={API_KEY}&units=metric&lang=fa"
        response = requests.get(url, timeout=8)

        if response.status_code == 404:
            await update.message.reply_text("شهر پیدا نشد. لطفاً دوباره امتحان کنید.")
            return

        data = response.json()

        temp = data["main"]["temp"]
        hum = data["main"]["humidity"]
        desc = data["weather"][0]["description"]

        text = (
            f"<b>وضعیت هوا برای {city}</b>\n"
            f"🌡 دما: <b>{temp}°C</b>\n"
            f"💨 رطوبت: <b>{hum}%</b>\n"
            f"☁ وضعیت: <i>{desc}</i>"
        )

        await update.message.reply_text(text, parse_mode="HTML")

    except requests.Timeout:
        await update.message.reply_text("⏳ سرور هواشناسی دیر پاسخ داد. لطفاً دوباره تلاش کنید.")
    except Exception:
        await update.message.reply_text("مشکلی در دریافت اطلاعات رخ داد.")

نمونه telebot:

@bot.message_handler(commands=["weather"])
def weather(message):
    parts = message.text.split(maxsplit=1)
    if len(parts) < 2:
        bot.send_message(message.chat.id, "مثال:\n/weather tehran")
        return

    city = parts[1]

    try:
        url = f"{BASE_URL}?q={city}&appid={API_KEY}&units=metric&lang=fa"
        response = requests.get(url, timeout=8)

        if response.status_code == 404:
            bot.send_message(message.chat.id, "شهر پیدا نشد.")
            return

        data = response.json()

        temp = data["main"]["temp"]
        hum = data["main"]["humidity"]
        desc = data["weather"][0]["description"]

        text = (
            f"<b>هواشناسی {city}</b>\n"
            f"🌡 دما: <b>{temp}°C</b>\n"
            f"💨 رطوبت: <b>{hum}%</b>\n"
            f"☁ وضعیت: <i>{desc}</i>"
        )

        bot.send_message(message.chat.id, text, parse_mode="HTML")

    except requests.Timeout:
        bot.send_message(message.chat.id, "درخواست شما زمان زیادی گرفت.")
    except Exception:
        bot.send_message(message.chat.id, "مشکل نامشخص رخ داد.")

مدیریت تاخیر و Timeout

ارتباط با سرویس‌های خارجی همیشه سریع نیست. اگر Timeout تنظیم نکنید، ربات ممکن است چند ثانیه قفل شود و کاربر تصور کند ربات از کار افتاده است. بنابراین موارد زیر مهم هستند:

  • همیشه timeout برای درخواست قرار دهید.
  • در صورت طولانی شدن پاسخ، پیام مناسب به کاربر بدهید.
  • خطاهای شبکه (Timeout، ConnectionError) را مدیریت کنید.
  • درخواست‌های زیاد را محدود کنید تا به Rate Limit برخورد نکنید.

مثال اصولی:

requests.get(url, timeout=6)

اگر API کند است می‌توانید:

  • یک پیام “در حال دریافت اطلاعات…” بفرستید
  • نتایج API را Cache کنید
  • درخواست را در یک Job Queue اجرا کنید

ارسال پاسخ قالب‌بندی‌شده با داده‌های واقعی

هنگامی که داده را از API گرفتید، ارائه آن در قالب زیبا و قابل‌خواندن باعث افزایش کیفیت ربات می‌شود. بهترین انتخاب parse_mode=”HTML” است چون خطاهای Markdown را ندارد.

نمونه پیام زیبا:

text = (
    f"<b>وضعیت هوا برای {city}</b>\n\n"
    f"🌡 دما: <b>{temp}°C</b>\n"
    f"💨 رطوبت: <b>{hum}%</b>\n"
    f"☁ وضعیت: <i>{desc}</i>"
)

می‌توانید علاوه بر متن:

  • ایموجی اضافه کنید
  • عکس شرایط آب‌وهوا (آیکون) بفرستید
  • دکمه «بروز‌رسانی» قرار دهید

این موارد تجربه کاربر را حرفه‌ای‌تر می‌کند.

جمع‌بندی کوتاه
برای اتصال ربات به API خارجی کافی است ورودی کاربر را بگیرید، درخواست HTTP ارسال کنید، خطاها را مدیریت کنید و نتیجه را در قالب مناسب نمایش دهید. با رعایت Timeout و قالب‌بندی خوب، می‌توانید دستورهای واقعی و حرفه‌ای بسازید.

بهبود ساختار و معماری فرمان‌ها در ربات تلگرام

وقتی تعداد فرمان‌ها کم است، می‌توان همه آن‌ها را در یک فایل قرار داد. اما در یک پروژه واقعی، این کار باعث شلوغی، سخت‌شدن نگهداری و کاهش انعطاف‌پذیری می‌شود. برای مدیریت بهتر، باید فرمان‌ها را در فایل‌های جداگانه قرار دهیم، یک CommandManager برای ثبت و اجرای فرمان‌ها داشته باشیم و از بارگذاری خودکار استفاده کنیم تا بدون تغییر کد اصلی، فرمان‌های جدید اضافه شوند. این بخش برای مبتدی‌ها نوشته شده و تمام مراحل را با مثال واقعی توضیح می‌دهد.

بهبود ساختار و معماری فرمان‌ها

در معماری ساده، تمام Commandها داخل فایل اصلی (bot.py) قرار می‌گیرند. این مدل برای شروع خوب است اما مشکلات زیر را ایجاد می‌کند:

  • سخت شدن نگهداری وقتی تعداد فرمان‌ها زیاد می‌شود
  • تکرار کد و نبود نظم
  • دشواری توسعه تیمی
  • وابستگی زیاد بین فایل اصلی و فرمان‌ها

راه‌حل این است که فرمان‌ها را به شکل ماژول‌های مستقل پیاده‌سازی کنیم. هر فرمان مسئول کار خودش است و فایل اصلی فقط نقش هماهنگ‌کننده را دارد.

یک ساختار پیشنهادی:

bot/
  main.py
  commands/
    start.py
    help.py
    weather.py
    ...
  core/
    manager.py

در این ساختار، هر فایل داخل commands فقط یک مسئولیت دارد: تعریف یک دستور.

جدا کردن Command ها در فایل‌های مستقل

هر دستور می‌تواند یک فایل جداگانه باشد که یک تابع (Handler) و نام فرمان را برمی‌گرداند.
یک مثال ساده برای فایل start.py:

from telegram import Update
from telegram.ext import ContextTypes

COMMAND = "start"

async def handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("سلام! من ربات شما هستم.")

و مثال برای help.py:

COMMAND = "help"

async def handler(update, context):
    await update.message.reply_text("لیست دستورات در حال حاضر محدود است.")

مزیت این روش:

  • اضافه‌کردن فرمان جدید فقط با ساخت یک فایل جدید انجام می‌شود
  • هیچ تغییری در فایل اصلی لازم نیست
  • تست کردن فرمان‌ها ساده‌تر می‌شود

نوشتن کلاس CommandManager

این کلاس مسئول مدیریت و ثبت تمام دستورهاست.
کارهای اصلی CommandManager:

  • پیدا کردن تمام فایل‌های دستور
  • بارگیری تابع handler هر دستور
  • ثبت آن‌ها در Application (در PTB) یا bot (در telebot)

یک نمونه ساده برای python-telegram-bot:

import importlib
import os
from telegram.ext import CommandHandler

class CommandManager:
    def __init__(self, app, commands_folder="commands"):
        self.app = app
        self.commands_folder = commands_folder

    def load_commands(self):
        for filename in os.listdir(self.commands_folder):
            if filename.endswith(".py"):
                module_name = filename[:-3]
                module_path = f"{self.commands_folder}.{module_name}"

                module = importlib.import_module(module_path)

                command = getattr(module, "COMMAND", None)
                handler_func = getattr(module, "handler", None)

                if command and handler_func:
                    self.app.add_handler(CommandHandler(command, handler_func))
                    print(f"Loaded command: {command}")

مزیت این کلاس:

  • جدا کردن کامل منطق بارگذاری از فایل اصلی
  • امکان توسعه آسان و افزودن قابلیت‌های جدید
  • نگهداری شفاف‌تر فرمان‌ها

بارگذاری خودکار دستورات (Dynamic Loading)

Dynamic Loading به شما اجازه می‌دهد بدون دست زدن به main.py هر تعداد دستور جدید اضافه کنید. کافی است یک فایل جدید داخل پوشه commands بسازید و COMMAND و handler را تعریف کنید.

فرایند به شکل زیر است:

  • CommandManager تمام فایل‌های پوشه commands را پیدا می‌کند
  • ماژول‌ها را با importlib لود می‌کند
  • بررسی می‌کند که آیا COMMAND و handler وجود دارند
  • فرمان را در ربات ثبت می‌کند

فایل main.py بسیار ساده می‌شود:

from telegram.ext import ApplicationBuilder
from core.manager import CommandManager

async def main():
    app = ApplicationBuilder().token("TOKEN").build()

    manager = CommandManager(app)
    manager.load_commands()

    print("Bot is running...")
    await app.run_polling()

در این معماری:

  • اضافه‌کردن start2 فقط با ساخت start2.py انجام می‌شود
  • حذف فرمان نیز با حذف فایل انجام می‌شود
  • کد اصلی بدون تغییر باقی می‌ماند
  • پروژه ساختار تمیز و قابل‌گسترش پیدا می‌کند

جمع‌بندی کوتاه
جدا کردن فرمان‌ها در فایل‌های مستقل و استفاده از CommandManager باعث نظم، مقیاس‌پذیری و توسعه‌پذیری بیشتر ربات می‌شود. با Dynamic Loading می‌توان بدون تغییر فایل اصلی فرمان‌های جدید اضافه کرد و پروژه را حرفه‌ای‌تر و استانداردتر ساخت.

خطاهای رایج در Commands و نحوه رفع آن

در پروژه‌های واقعی ربات تلگرام معمولاً خطاهایی رخ می‌دهند که باعث اجرا نشدن دستورات می‌شوند. بسیاری از این خطاها به سادگی قابل رفع هستند اما اگر دلیل آن‌ها را ندانید، زمان زیادی صرف Debug می‌شود. در این بخش خطاهای رایج در فرمان‌ها را همراه با مثال واقعی و روش رفع توضیح می‌دهیم تا هنگام توسعه ربات سریع‌تر مشکل را پیدا کنید.

اجرا نشدن دستور به دلیل پاک شدن لیست BotFather

گاهی کاربر دستور را در فهرست داخلی تلگرام می‌بیند اما ربات آن را نمی‌شناسد، یا برعکس دستور در کد فعال است اما تلگرام آن را در لیست Commandها نمایش نمی‌دهد. دلیل این مشکل معمولاً پاک شدن یا بروزرسانی نشدن لیست دستورات در BotFather است.

علائم رایج:

  • کاربر دستور /weather را می‌بیند اما ربات می‌گوید unknown command
  • یا شما دستور جدید اضافه کرده‌اید اما تلگرام آن را نشان نمی‌دهد
  • یا پس از تغییر اسم یک دستور، نسخه قبلی اجرا می‌شود

راه‌حل‌ها:

  • در BotFather دستور /setcommands را اجرا کنید و لیست جدید را ثبت کنید
  • اگر نمی‌خواهید نمایش داده شود، کاملاً پاک کنید و وارد کنید
  • پس از تغییر فرمان‌های مهم، یک بار کش تلگرام (Clear Cache) را بزنید
  • اگر dynamic loading دارید، مطمئن شوید فایل جدید درست نام‌گذاری شده است
  • اگر کاربر complaint دارد، از او بخواهید داخل ربات تایپ کند نه از منوی تلگرام

نکته مهم: BotFather فقط برای Display دستورات است؛ اگر دستور در کد تعریف نشده باشد، ربات پاسخ نمی‌دهد حتی اگر در منو باشد.

خطای bad request در input

یکی از رایج‌ترین خطاها در ربات‌ها خطای Bad Request است. این خطا معمولاً زمانی رخ می‌دهد که پیام ارسالی شما از قوانین Telegram Bot API پیروی نکند.

دلایل متداول:

  • وجود کاراکترهای غیرمجاز در Markdown
  • مقدار None در پاسخ
  • ارسال پیام خیلی طولانی
  • ارسال HTML اشتباه (تگ باز بدون بسته شدن)
  • فرستادن محتوای خالی (مثلاً text=”)
  • مقدار ورودی کاربر آنالیز نشده (مثلاً /setname علی رضایی بدون split صحیح)

نمونه خطای رایج:

await update.message.reply_text("<b>Hello", parse_mode="HTML")

تگ b بسته نشده و Telegram خطا می‌دهد.

راه‌حل:

  • از HTML استفاده کنید (کم‌خطاتر از Markdown)
  • قبل از ارسال همیشه متن را validate کنید
  • اگر از Markdown استفاده می‌کنید، escape کردن کاراکترهای خاص ضروری است
  • ورودی کاربر را strip کنید و بررسی کنید خالی نباشد
  • برای خطاهای پیچیده، چاپ کنید چه متنی ارسال می‌شود

مثال رفع مشکل:

safe_text = text.replace("<", "&lt;").replace(">", "&gt;")
await update.message.reply_text(safe_text)

اشتباه در decorator یا handler

اگر از کتابخانه telebot استفاده می‌کنید، اشتباه در decorator یکی از دلایل اصلی اجرا نشدن دستور است.
نمونه اشتباه:

@bot.message_handler(command=["start"])  # اشتباه: باید commands باشد

یا:

@bot.message_handler(commands=["start"])
def start():
    pass  # پارامتر message فراموش شده

در python-telegram-bot نیز استفاده اشتباه از CommandHandler باعث بروز مشکل می‌شود:

app.add_handler(CommandHandler("start"))  # اشتباه: callback تعریف نشده

روش درست:

app.add_handler(CommandHandler("start", start_handler))

خطاهای رایج Handler:

  • دو بار تعریف کردن یک دستور
  • اشتباه بودن نام COMMAND در فایل دستور
  • بارگذاری نشدن فایل هنگام Dynamic Loading
  • فراموش کردن async در نسخه‌های جدید PTB
  • تایپ اشتباه نام دستور (“/starts” به جای “start”)

راه‌حل‌های دقیق:

  • هر فایل دستور باید شامل COMMAND و handler باشد
  • قبل از اجرای app.run_polling، لیست تمام Commandهای لودشده را چاپ کنید
  • اگر telebot دارید، همیشه message را به handler پاس بدهید
  • اگر decorator دارید، spelling دقیق commands مهم است

روش‌های لاگ گرفتن برای debug دستورات

داشتن لاگ خوب مهم‌ترین ابزار برای فهمیدن دلیل اجرا نشدن یک دستور است. بدون لاگ، پیدا کردن مشکل تقریباً کورکورانه خواهد بود.

روش عمومی: چاپ ساده
ساده‌ترین روش:

print("Loaded command:", command)

در telebot:

print("User input:", message.text)

در PTB:

print("Args:", context.args)

روش بهتر: استفاده از logging پایتون

import logging
logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)
logger.info("Command loaded: %s", command)

لاگ برای خطاها:

try:
    ...
except Exception as e:
    logger.exception("Error in weather command")

در PTB کل ربات را می‌توانید با لاگ اجرا کنید:

application = Application.builder().token(TOKEN).build()
application.run_polling(allowed_updates=Update.ALL_TYPES)

این کار باعث می‌شود همه خطاهای Telegram API، نوع message و خطاهای داخلی چاپ شود.

بهترین روش حرفه‌ای: ذخیره لاگ در فایل
برای پروژه‌های جدی:

logging.basicConfig(
    filename="bot.log",
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s"
)

مزایا:

  • دنبال کردن رفتار ربات در روزهای مختلف
  • پیدا کردن علت توقف یا خطا
  • مناسب برای سرور و دیپلوی دائمی

جمع‌بندی کوتاه
خطاهای رایج دستورات معمولاً به دلیل اشتباه در decorator، قالب‌بندی HTML/Markdown، به‌روزرسانی نشدن لیست BotFather یا مدیریت نکردن ورودی کاربر رخ می‌دهند. با ساختار درست، چک کردن COMMAND، استفاده صحیح از Handler و داشتن لاگ مناسب، رفع این خطاها بسیار ساده می‌شود.

پروژه نهایی: ساخت یک ربات با مجموعه دستورات کامل

در این بخش یک پروژه کامل و واقعی طراحی می‌کنیم که شامل دستورات پایه، دستورات تعاملی، اتصال به دیتابیس، ساخت منوی اصلی و در نهایت آماده‌سازی نسخه قابل انتشار است. هدف این است که بتوانید یک ربات حرفه‌ای بسازید که ساختار درست داشته باشد و به‌راحتی قابل گسترش باشد. این پروژه بر پایه مفاهیم قبلی مثل معماری فرمان‌ها، مدیریت خطا و طراحی ماژولار بنا شده است.

تعریف دستورات پایه و تعاملی

در اولین مرحله باید مجموعه‌ای از دستورات مشخص کنیم که پایه ربات را تشکیل دهند. این دستورات باید ساده، قابل فهم و کاربردی باشند. برای این پروژه دستورات زیر را انتخاب می‌کنیم:

  • start
  • help
  • profile (نمایش اطلاعات کاربر)
  • register (فرآیند ثبت‌نام چندمرحله‌ای)
  • menu (نمایش منوی اصلی)
  • info (دریافت توضیحات یا قوانین)

هر دستور باید در فایل مستقل خود پیاده‌سازی شود. مثال فایل start.py:

COMMAND = "start"

async def handler(update, context):
    await update.message.reply_text(
        "سلام، خوش آمدی! از /menu برای دیدن امکانات استفاده کن."
    )

و دستور profile که تعاملی است و اطلاعات را از دیتابیس می‌گیرد:

COMMAND = "profile"

async def handler(update, context):
    user_id = update.effective_user.id
    db = context.bot_data["db"]

    user = db.get_user(user_id)
    if not user:
        await update.message.reply_text("شما ثبت‌نام نکرده‌اید. دستور /register را وارد کنید.")
        return

    text = (
        f"نام: {user['name']}\n"
        f"سن: {user['age']}\n"
        f"تاریخ عضویت: {user['created_at']}"
    )
    await update.message.reply_text(text)

فرآیند دستورهای چندمرحله‌ای مثل register معمولاً با نگهداری state کاربر پیاده‌سازی می‌شود:

COMMAND = "register"

async def handler(update, context):
    context.user_data["state"] = "ask_name"
    await update.message.reply_text("اسمت چیه؟")

و یک MessageHandler برای پاسخ به state کاربران لازم است.

اتصال دستورها به یک دیتابیس

برای حرفه‌ای شدن ربات، نیاز به ذخیره اطلاعات در دیتابیس داریم. ساده‌ترین انتخاب SQLite است که بدون نصب اضافی کار می‌کند.

ابتدا یک کلاس ساده برای دیتابیس می‌سازیم:

import sqlite3

class Database:
    def __init__(self, path="bot.db"):
        self.conn = sqlite3.connect(path)
        self.create_tables()

    def create_tables(self):
        self.conn.execute("""
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY,
            name TEXT,
            age INTEGER,
            created_at TEXT
        )
        """)

    def add_user(self, user_id, name, age):
        self.conn.execute(
            "INSERT INTO users (id, name, age, created_at) VALUES (?, ?, ?, datetime('now'))",
            (user_id, name, age)
        )
        self.conn.commit()

    def get_user(self, user_id):
        cur = self.conn.execute("SELECT * FROM users WHERE id=?", (user_id,))
        row = cur.fetchone()
        if row:
            return {"id": row[0], "name": row[1], "age": row[2], "created_at": row[3]}
        return None

در main.py دیتابیس را مقداردهی کرده و در bot_data قرار می‌دهیم:

db = Database()
app.bot_data["db"] = db

حالا تمام دستورات به راحتی می‌توانند دیتابیس را بخوانند یا بنویسند.

ایجاد یک منوی اصلی مبتنی بر دستورها

برای اینکه ربات UX خوبی داشته باشد، باید یک منوی اصلی داشته باشد که کاربر بتواند به راحتی به امکانات دسترسی پیدا کند. این منو می‌تواند متنی یا دکمه‌دار باشد.

نسخه ساده منوی متنی:

منوی اصلی:
1. نمایه من /profile
2. ثبت نام /register
3. اطلاعات /info
4. راهنما /help

فایل menu.py:

COMMAND = "menu"

async def handler(update, context):
    text = (
        "منوی اصلی:\n"
        "1. پروفایل /profile\n"
        "2. ثبت‌نام /register\n"
        "3. اطلاعات /info\n"
        "4. راهنما /help"
    )
    await update.message.reply_text(text)

نسخه حرفه‌ای‌تر با دکمه Inline:

from telegram import InlineKeyboardButton, InlineKeyboardMarkup

COMMAND = "menu"

async def handler(update, context):
    keyboard = [
        [InlineKeyboardButton("پروفایل", callback_data="profile")],
        [InlineKeyboardButton("ثبت‌نام", callback_data="register")],
        [InlineKeyboardButton("اطلاعات", callback_data="info")]
    ]
    await update.message.reply_text(
        "منوی اصلی:",
        reply_markup=InlineKeyboardMarkup(keyboard)
    )

و سپس در handler مربوط به callback_data بررسی می‌کنید که کاربر روی کدام دکمه کلیک کرده است.

پیاده‌سازی نسخه قابل انتشار

برای اینکه ربات شما آماده انتشار روی سرور باشد، باید چند مرحله مهم انجام دهید:

  1. ساختاردهی پروژه
  • دستورات در پوشه commands
  • دیتابیس در پوشه core
  • CommandManager برای بارگذاری خودکار
  • main.py ساده و شفاف
  1. افزودن logging برای ثبت خطاها
  2. استفاده از Token از طریق فایل env
  3. جلوگیری از Crash با try/except در دستورات حساس
  4. تست تک‌تک دستورات با چند ورودی متفاوت
  5. اجرای ربات با systemd یا pm2 روی سرور

نمونه main.py نهایی:

from telegram.ext import ApplicationBuilder, MessageHandler, filters
from core.manager import CommandManager
from core.db import Database

async def main():
    app = ApplicationBuilder().token(TOKEN).build()

    db = Database()
    app.bot_data["db"] = db

    manager = CommandManager(app)
    manager.load_commands()

    app.add_handler(MessageHandler(filters.TEXT, global_state_handler))

    await app.run_polling()

پس از اجرای همه مراحل، شما یک ربات کامل، ساختاریافته، قابل توسعه و قابل انتشار دارید که می‌تواند در پروژه‌های واقعی هم استفاده شود.

جمع‌بندی کوتاه
در پروژه نهایی یاد گرفتیم چگونه مجموعه‌ای از دستورات پایه و تعاملی بسازیم، آن‌ها را به دیتابیس متصل کنیم، منوی اصلی طراحی کنیم و در نهایت نسخه قابل انتشار تولید کنیم. این معماری برای ساخت هر نوع ربات در آینده قابل استفاده است و می‌توانید به‌راحتی قابلیت‌های جدید اضافه کنید.

جمع‌بندی نهایی

در این بخش همه مراحل ساخت یک ربات تلگرام حرفه‌ای را به‌صورت خلاصه، منسجم و قابل استفاده برای مرور سریع جمع‌بندی می‌کنیم. این جمع‌بندی طوری نوشته شده که بتوانید مسیر کامل ساخت ربات را از ایده تا انتشار در یک نگاه ببینید و هنگام توسعه پروژه، آن را به‌عنوان چک‌لیست استفاده کنید.

مقدمه کوتاه
در طول این مسیر یاد گرفتیم که ساخت یک ربات تلگرام تنها نوشتن چند خط کد نیست؛ بلکه شامل طراحی معماری، مدیریت فرمان‌ها، تعامل با دیتابیس، ایجاد تجربه کاربری مناسب و در نهایت انتشار پایدار روی سرور است. این جمع‌بندی تصویری روشن از تمام مراحل ایجاد یک ربات واقعی ارائه می‌دهد.

بدنه کامل
برای ساخت یک ربات حرفه‌ای، مسیر از چند مرحله اساسی تشکیل می‌شود:

  1. آماده‌سازی و درک اصول اولیه
  • ساخت Token از طریق BotFather
  • راه‌اندازی محیط پایتون و ساخت venv
  • شناخت Bot API و اینکه چگونه درخواست‌ها و پاسخ‌ها ارسال می‌شوند
  • انتخاب کتابخانه مناسب مثل python-telegram-bot
  1. طراحی معماری پروژه
  • ساختار پوشه‌ها شامل commands، services، handlers، core
  • تفکیک مسئولیت‌ها طبق اصول Clean Code
  • استفاده از CommandManager برای بارگذاری خودکار فرمان‌ها
  • نوشتن handlerهای شفاف و ساده برای نگهداری بهتر پروژه
  1. تعریف فرمان‌های پایه و تعاملی
  • پیاده‌سازی دستورات start، help، menu، profile
  • ساخت فرمان‌های چندمرحله‌ای با مدیریت state
  • طراحی پیام‌های کوتاه، شفاف و دوستانه
  • جلوگیری از خطاهای مربوط به HTML یا Markdown
  1. اتصال ربات به دیتابیس
  • ساخت دیتابیس SQLite برای ذخیره کاربران
  • طراحی جدول‌ها، توابع ثبت و بازیابی اطلاعات
  • استفاده از context.bot_data برای اشتراک‌گذاری db
  • اطمینان از پایدار بودن داده‌ها در فرآیندهای چندمرحله‌ای
  1. طراحی منوی اصلی
  • ساخت منوی متنی ساده یا نسخه پیشرفته با Inline Keyboard
  • مدیریت callbackها برای پاسخ به انتخاب کاربر
  • ایجاد ساختاری که کاربر بدون تایپ دستی، قابلیت‌ها را پیدا کند
  1. مدیریت خطا و ثبت لاگ
  • فعال‌سازی logging برای مشاهده خطاها
  • جلوگیری از crash با استفاده از try و except
  • لاگ‌گذاری در فایل برای سرور و پایش طولانی‌مدت
  1. آماده‌سازی نسخه قابل انتشار
  • قرار دادن Token در فایل env به‌جای ذخیره در کد
  • تست تمام دستورات با سناریوهای واقعی
  • استقرار روی سرور لینوکسی با systemd
  • استفاده از polling برای شروع و webhook برای نسخه حرفه‌ای

جمع‌بندی کوتاه
مسیر ساخت ربات تلگرام از اصول ساده آغاز می‌شود، اما با رعایت معماری مناسب، مدیریت فرمان‌ها، اتصال به دیتابیس، طراحی تجربه کاربری درست و استقرار حرفه‌ای، می‌توانید یک ربات واقعی و قابل اتکا بسازید. با این ساختار، توسعه قابلیت‌های جدید در آینده بسیار آسان‌تر خواهد بود.

سوالات متداول (FAQ)

در این بخش رایج‌ترین پرسش‌هایی را که هنگام ساخت ربات تلگرام مطرح می‌شود پاسخ می‌دهیم. پاسخ‌ها برای مبتدی‌ها نوشته شده‌اند و همراه با مثال‌های واقعی هستند تا بهتر بتوانید رفتار Bot API را درک کنید.

حداکثر تعداد دستورهای قابل تعریف چقدر است؟

به‌صورت رسمی محدودیت سختی برای تعداد دستورها وجود ندارد، اما چند نکته مهم باید رعایت شود:

  • BotFather در بخش /setcommands فقط حدود چند ده دستور را به‌صورت خوانا نمایش می‌دهد. اگر تعداد خیلی زیاد شود، لیست غیرقابل استفاده می‌شود.
  • از نظر کدنویسی می‌توانید صدها فرمان تعریف کنید، اما تجربه کاربری ضعیف می‌شود و کاربر سردرگم خواهد شد.
  • بهترین حالت این است که مجموعه‌ای کوچک از فرمان‌های پایه (مثلاً ۵ تا ۱۰ فرمان) داشته باشید و سایر قابلیت‌ها را از طریق منو یا دکمه‌ها ارائه کنید.

مثال واقعی:
اگر بیش از ۳۰ فرمان در BotFather ثبت کنید، کاربران روی موبایل برای پیدا کردن دستور مدنظر مجبور به اسکرول زیاد می‌شوند که UX را خراب می‌کند.

نتیجه:
حد نصاب توصیه‌شده ۱۰ تا ۲۰ فرمان است، اما از نظر تکنیکی محدودیت سختی وجود ندارد.

آیا می‌شود دستورات مخفی تعریف کرد؟

بله. دو حالت وجود دارد:

  1. فرمان‌هایی که در BotFather ثبت نمی‌کنید.
  • این دستورها فقط زمانی کار می‌کنند که کاربر آن‌ها را دستی تایپ کند.
  • برای فرمان‌های داخلی، تست، مدیریت یا قابلیت‌های ویژه مناسب است.
  1. فرمان با شرط دسترسی.
  • دستور وجود دارد، اما فقط برای کاربران خاص اجرا می‌شود.
  • برای مثال مدیر ربات یک دستور /broadcast دارد، اما برای کاربران عادی پیام “اجازه ندارید” نمایش داده می‌شود.

مثال:
در کد می‌نویسید:

if user_id not in ADMINS:
    return await update.message.reply_text("شما اجازه استفاده از این دستور را ندارید.")

نتیجه:
بله، می‌شود دستورهای مخفی داشت؛ فقط آنها را در BotFather ثبت نکنید یا با شرط دسترسی محدودشان کنید.

بهترین روش دسته‌بندی دستورات چیست؟

برای اینکه پروژه در آینده قابل نگهداری باشد، باید دستورات را در پوشه‌های جداگانه و بر اساس نوع عملکرد سازمان‌دهی کنید.

روش عملی پیشنهادی:

  • پوشه commands برای دستورات اصلی
  • start.py
  • help.py
  • menu.py
  • پوشه commands/user برای قابلیت‌های کاربر
  • profile.py
  • register.py
  • پوشه commands/admin برای مدیرها
  • broadcast.py
  • stats.py
  • همه فایل‌ها شامل دو بخش باشند:
  • یک ثابت COMMAND
  • یک تابع handler

این ساختار باعث می‌شود CommandManager بتواند همه فایل‌ها را به‌صورت خودکار لود کند و توسعه ربات در آینده ساده بماند.

مثال:
وقتی می‌خواهید دستور جدید اضافه کنید، فقط یک فایل جدید ایجاد می‌کنید و COMMAND را مشخص می‌کنید؛ دیگر نیازی به ویرایش main نیست.

چرا بعضی دستورات در گروه کار نمی‌کنند؟

دلایل زیادی وجود دارد که یک دستور در گروه کار نکند، حتی اگر در چت خصوصی درست اجرا شود. رایج‌ترین علل:

  • Bot در گروه دسترسی ندارد (مثلاً اجازه خواندن پیام‌ها غیرفعال است).
  • تلگرام در گروه پیام‌ها را به‌صورت کامل برای Bot ارسال نمی‌کند مگر اینکه Bot را Admin کرده باشید یا Privacy Mode را خاموش کنید.
  • Privacy Mode فعال است و Bot فقط پیام‌هایی را می‌بیند که با / شروع شوند.
  • بعضی کتابخانه‌ها نیاز دارند explicitly AllowedUpdates تنظیم شود.
  • دستور شما فقط روی message کار می‌کند ولی در گروه رویداد callback یا reply اجرا می‌شود.

مثال واقعی:
اگر Privacy Mode روشن باشد، پیام “سلام” را نمی‌بیند اما پیام “/start” را می‌بیند.

راه‌حل‌ها:

  • در BotFather گزینه /setprivacy را روی Disabled بگذارید اگر می‌خواهید همه پیام‌ها را ببینید.
  • Bot را در گروه Admin کنید اگر نیاز است پیام‌ها یا فایل‌ها را پردازش کند.
  • همیشه برای Group قابلیت‌ها را تست کنید، چون رفتار پیام‌ها در گروه و خصوصی متفاوت است.

جمع‌بندی کوتاه
در این بخش آموختیم تعداد فرمان‌ها محدودیت سخت ندارد اما باید مدیریت‌شده باشند، امکان ایجاد فرمان‌های مخفی وجود دارد، بهترین دسته‌بندی بر اساس ماژول‌ها و نوع کاربرد است و در گروه‌ها محدودیت‌هایی مثل Privacy Mode رفتار فرمان‌ها را تغییر می‌دهد.

محمد وب‌سایت

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *