مدیریت دستورات (Commands) در Telebot: ساخت ربات‌های تعاملی

فهرست مطالب

مدیریت دستورات (Commands) در Telebot: ساخت ربات‌های تعاملی

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

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

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

مقدمه‌ای بر Telebot و اهمیت دستورات

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

در قلب هر ربات تلگرام تعاملی، مفهوم “دستورات” (Commands) نهفته است. دستورات، پیام‌هایی هستند که با کاراکتر / آغاز می‌شوند (مانند /start، /help یا /settings) و به کاربران امکان می‌دهند تا با ربات به روشی ساختاریافته ارتباط برقرار کنند. این دستورات به مثابه دکمه‌ها یا گزینه‌های منو در یک رابط کاربری گرافیکی عمل می‌کنند و به کاربران اجازه می‌دهند تا به سرعت عملکرد مورد نظر خود را فراخوانی کنند. اهمیت دستورات در چندین جنبه کلیدی قابل بررسی است:

  1. راهنمایی کاربر: دستورات، راهنمایی واضحی برای کاربران فراهم می‌کنند که چه کاری می‌توانند با ربات انجام دهند. دستوراتی مانند /help می‌توانند لیست تمام قابلیت‌ها را به کاربر نشان دهند.
  2. ساختاردهی تعامل: به جای پردازش پیام‌های متنی آزاد که ممکن است مبهم باشند، دستورات یک روش ساختاریافته برای ارسال درخواست‌ها به ربات ارائه می‌دهند.
  3. اتوماسیون وظایف: دستورات امکان اتوماسیون وظایف تکراری یا پیچیده را فراهم می‌کنند. برای مثال، یک دستور /remind me to call John in 30 minutes می‌تواند یک یادآوری تنظیم کند.
  4. مدیریت دسترسی: با استفاده از دستورات می‌توان سطوح دسترسی مختلفی را برای کاربران تعریف کرد. مثلاً دستورات مدیریتی تنها برای مدیران ربات قابل دسترسی باشند.
  5. پایه و اساس مکالمات پیچیده: در حالی که یک دستور ساده ممکن است تنها یک پاسخ واحد داشته باشد، اما دستورات می‌توانند نقطه شروعی برای یک جریان مکالمه‌ای چندمرحله‌ای باشند که در آن ربات اطلاعات بیشتری از کاربر می‌پرسد.

در Telebot، مدیریت دستورات به لطف دکوراتور @bot.message_handler(commands=['command_name']) بسیار آسان می‌شود. این دکوراتور به شما اجازه می‌دهد تا یک تابع پایتون را مستقیماً به یک یا چند دستور تلگرام نگاشت کنید. این رویکرد، کد را خواناتر و نگهداری آن را ساده‌تر می‌کند.

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

نصب و راه‌اندازی Telebot: اولین گام

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

۱. نصب کتابخانه pyTelegramBotAPI

Telebot یک کتابخانه پایتون است و همانند سایر پکیج‌های پایتون، می‌توان آن را با استفاده از pip، مدیر بسته پایتون، نصب کرد. ترمینال یا Command Prompt خود را باز کرده و دستور زیر را اجرا کنید:

pip install pyTelegramBotAPI

این دستور آخرین نسخه پایدار کتابخانه را نصب خواهد کرد. توصیه می‌شود که این کار را در یک محیط مجازی (virtual environment) انجام دهید تا از تداخل پکیج‌ها جلوگیری شود:

python -m venv venv
source venv/bin/activate  # در لینوکس/مک
# venv\Scripts\activate.bat # در ویندوز
pip install pyTelegramBotAPI

۲. دریافت توکن API از BotFather

برای اینکه ربات شما بتواند با API تلگرام ارتباط برقرار کند، به یک توکن API نیاز دارید. این توکن یک رشته منحصر به فرد است که هویت ربات شما را تأیید می‌کند. برای دریافت توکن:

  1. وارد اپلیکیشن تلگرام شوید.
  2. در بخش جستجو، @BotFather را جستجو کرده و با او چت کنید (اطمینان حاصل کنید که ربات رسمی با تیک آبی باشد).
  3. دستور /newbot را به @BotFather ارسال کنید.
  4. @BotFather از شما می‌خواهد که یک نام برای ربات خود انتخاب کنید (مثلاً “MyAwesomeBot”).
  5. سپس از شما می‌خواهد که یک نام کاربری (username) برای ربات خود انتخاب کنید که باید به _bot ختم شود (مثلاً “MyAwesomeBot_bot”).
  6. پس از انجام این مراحل، @BotFather توکن API ربات شما را به صورت یک رشته طولانی (مانند 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11) برای شما ارسال خواهد کرد. این توکن را در جایی امن نگهداری کنید و هرگز آن را به صورت عمومی به اشتراک نگذارید.

۳. مقداردهی اولیه ربات در کد پایتون

حالا که Telebot نصب شده و توکن API را در اختیار دارید، می‌توانید ربات خود را در کد پایتون مقداردهی اولیه کنید:

import telebot

# توکن API ربات خود را اینجا قرار دهید
API_TOKEN = 'YOUR_BOT_API_TOKEN'

bot = telebot.TeleBot(API_TOKEN)

# حالا می‌توانید handlers و منطق ربات خود را تعریف کنید

# شروع به گوش دادن برای پیام‌ها
bot.polling()

در این کد:

  • import telebot کتابخانه Telebot را وارد می‌کند.
  • متغیر API_TOKEN توکن API شما را ذخیره می‌کند. حتماً 'YOUR_BOT_API_TOKEN' را با توکن واقعی خود جایگزین کنید.
  • bot = telebot.TeleBot(API_TOKEN) یک نمونه از کلاس TeleBot ایجاد می‌کند که نقطه ورود اصلی برای تعامل با API تلگرام خواهد بود.
  • bot.polling() متدی است که ربات را به صورت بی‌نهایت اجرا می‌کند و به صورت مداوم برای دریافت پیام‌های جدید از سرور تلگرام گوش می‌دهد. این خط باید در انتهای اسکریپت اصلی ربات شما باشد.

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

آشنایی با decorator @bot.message_handler(): پایه و اساس مدیریت دستورات

در Telebot، مفهوم “handler” یا “مسئول پردازش” کلیدی‌ترین جزء برای مدیریت انواع مختلف پیام‌های دریافتی از کاربران است. این handlerها توابعی هستند که با استفاده از دکوراتورهای خاص، به انواع خاصی از پیام‌ها (مانند دستورات، متن ساده، تصاویر، Callback Queryها و غیره) متصل می‌شوند. برای مدیریت دستورات، دکوراتور @bot.message_handler() نقش اساسی ایفا می‌کند.

مفهوم Decorator در پایتون

پیش از غواصی در @bot.message_handler()، درک کوتاهی از Decoratorها در پایتون مفید است. Decoratorها در پایتون، توابعی هستند که به شما امکان می‌دهند رفتار یک تابع یا کلاس دیگر را بدون تغییر مستقیم کد آن، “تزیین” (decorate) کنید. آن‌ها توابع را به عنوان ورودی می‌گیرند و یک تابع جدید (معمولاً با افزودن قابلیت‌های اضافی) را برمی‌گردانند. در Telebot، دکوراتورها به ربات می‌گویند که کدام تابع باید در پاسخ به کدام نوع پیام فراخوانی شود.

دکوراتور @bot.message_handler(commands=[‘command_name’])

این دکوراتور، روش اصلی برای تعریف توابع مدیریت دستورات در Telebot است. وقتی یک کاربر یک دستور (پیامی که با / شروع می‌شود) را به ربات شما ارسال می‌کند، Telebot تمام message_handlerهایی را که با آن دستور مطابقت دارند، بررسی می‌کند و تابع مربوطه را فراخوانی می‌کند.

پارامتر commands یک لیست از رشته‌ها را می‌پذیرد که هر رشته نام یک دستور است. به عنوان مثال، اگر می‌خواهید تابعی به دستور /start پاسخ دهد، آن را به شکل زیر تعریف می‌کنید:

import telebot

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

@bot.message_handler(commands=['start'])
def send_welcome(message):
    bot.reply_to(message, "سلام! به ربات من خوش آمدید.")

bot.polling()

در این مثال:

  • @bot.message_handler(commands=['start']) به Telebot می‌گوید که تابع send_welcome باید هر زمان که یک پیام حاوی دستور /start دریافت شد، اجرا شود.
  • پارامتر message که به تابع send_welcome ارسال می‌شود، یک شیء از نوع telebot.types.Message است که حاوی تمام اطلاعات مربوط به پیام دریافتی (مانند فرستنده، متن پیام، زمان ارسال و غیره) است.
  • bot.reply_to(message, "...") یک روش راحت برای ارسال پاسخ به همان چتی است که پیام اصلی از آن ارسال شده است.

پارامترهای دیگر @bot.message_handler()

@bot.message_handler() بسیار منعطف است و می‌تواند پارامترهای دیگری نیز بپذیرد که به شما امکان می‌دهند فیلترهای پیچیده‌تری را اعمال کنید:

  • content_types: این پارامتر یک لیست از انواع محتوا (مانند ['text']، ['photo']، ['audio']، ['document'] و غیره) را می‌پذیرد. اگر این پارامتر را مشخص نکنید، پیش‌فرض آن ['text'] است. برای مثال، برای پردازش تصاویر:
    @bot.message_handler(content_types=['photo'])
    def handle_photo(message):
        bot.reply_to(message, "چه عکس زیبایی!")
            
  • regexp: این پارامتر یک عبارت منظم (regular expression) را می‌پذیرد. هر پیامی که متن آن با این الگو مطابقت داشته باشد، توسط این handler پردازش می‌شود. این برای دستورات پویا یا پیام‌های متنی با الگوی خاص بسیار مفید است:
    @bot.message_handler(regexp="^[Hh]ello")
    def handle_hello(message):
        bot.reply_to(message, "سلام به شما!")
            
  • func: این پارامتر یک تابع (predicate function) را می‌پذیرد که شیء message را به عنوان ورودی می‌گیرد و یک مقدار بولی (True یا False) برمی‌گرداند. اگر تابع True برگرداند، handler فعال می‌شود. این برای فیلترهای سفارشی و بسیار پیچیده عالی است:
    def is_admin(message):
        return message.from_user.id == ADMIN_ID
    
    @bot.message_handler(func=is_admin, commands=['admin_panel'])
    def admin_command(message):
        bot.reply_to(message, "به پنل مدیریت خوش آمدید.")
            

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

ساخت دستورات ساده: Hello World رباتیکی شما

پس از راه‌اندازی اولیه Telebot و آشنایی با دکوراتور @bot.message_handler()، زمان آن رسیده که اولین دستورات کاربردی را برای ربات خود ایجاد کنیم. این دستورات ساده، اغلب به عنوان “Hello World” در دنیای برنامه‌نویسی ربات‌ها شناخته می‌شوند و پایه و اساس تعاملات پیچیده‌تر را شکل می‌دهند.

دستور /start: دروازه ورود به ربات شما

دستور /start تقریباً در تمام ربات‌های تلگرام وجود دارد و معمولاً اولین دستوری است که کاربران پس از شروع مکالمه با ربات، ارسال می‌کنند. این دستور برای خوش‌آمدگویی به کاربر، ارائه اطلاعات اولیه در مورد قابلیت‌های ربات یا شروع یک جریان مکالمه‌ای طراحی شده است.

import telebot

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

@bot.message_handler(commands=['start'])
def send_welcome(message):
    user_name = message.from_user.first_name if message.from_user.first_name else "کاربر عزیز"
    welcome_text = (
        f"سلام {user_name}! به ربات تعاملی من خوش آمدید.\n"
        "من یک ربات هستم که می‌توانم کارهای مختلفی انجام دهم.\n"
        "برای مشاهده لیست دستورات، /help را ارسال کنید."
    )
    bot.send_message(message.chat.id, welcome_text)

bot.polling()

در این مثال:

  • ما از message.from_user.first_name برای شخصی‌سازی پیام خوش‌آمدگویی استفاده کرده‌ایم، اگر نام کاربر در دسترس باشد.
  • به جای bot.reply_to()، از bot.send_message(message.chat.id, ...) استفاده کردیم. هر دو متد برای ارسال پیام به کاربر استفاده می‌شوند، اما send_message کمی عمومی‌تر است و به شما امکان می‌دهد به هر chat.id پیام بفرستید. reply_to در پاسخ به یک پیام خاص در همان چت است.
  • پیام خوش‌آمدگویی شامل راهنمایی برای استفاده از دستور /help نیز هست، که یک الگوی رایج و خوب برای تجربه کاربری است.

دستور /help: راهنمای استفاده از ربات

دستور /help برای ارائه لیستی از تمام دستورات موجود و توضیح مختصر در مورد هر یک، ضروری است. این دستور به کاربران کمک می‌کند تا به راحتی قابلیت‌های ربات شما را کشف و استفاده کنند.

import telebot

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

@bot.message_handler(commands=['start'])
def send_welcome(message):
    user_name = message.from_user.first_name if message.from_user.first_name else "کاربر عزیز"
    welcome_text = (
        f"سلام {user_name}! به ربات تعاملی من خوش آمدید.\n"
        "من یک ربات هستم که می‌توانم کارهای مختلفی انجام دهم.\n"
        "برای مشاهده لیست دستورات، /help را ارسال کنید."
    )
    bot.send_message(message.chat.id, welcome_text)

@bot.message_handler(commands=['help'])
def send_help(message):
    help_text = (
        "لیست دستورات موجود:\n"
        "/start - شروع مکالمه و خوش‌آمدگویی\n"
        "/help - نمایش این راهنما\n"
        "/info - دریافت اطلاعات کلی در مورد ربات\n"
        "/echo [متن] - تکرار متن ارسالی شما (مثال: /echo سلام)\n"
        "/sum [عدد۱] [عدد۲] - جمع دو عدد (مثال: /sum 5 10)"
    )
    bot.send_message(message.chat.id, help_text)

@bot.message_handler(commands=['info'])
def send_info(message):
    info_text = (
        "این ربات یک نمونه برای آموزش مدیریت دستورات در Telebot است.\n"
        "توسعه‌دهنده: مثال کاربر\n"
        "نسخه: 1.0.0"
    )
    bot.send_message(message.chat.id, info_text)

bot.polling()

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

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

دستورات با آرگومان‌ها: افزودن پویایی به ربات

در بسیاری از سناریوها، یک دستور ساده که تنها یک پاسخ ثابت را برمی‌گرداند، کافی نیست. ربات‌ها نیاز دارند تا بتوانند ورودی‌های اضافی را از کاربران دریافت کرده و بر اساس آن عمل کنند. این ورودی‌های اضافی که پس از نام دستور می‌آیند، “آرگومان” نامیده می‌شوند. به عنوان مثال، دستور /echo سلام دنیا باید “سلام دنیا” را برگرداند، یا /sum 5 10 باید نتیجه جمع 5 و 10 را برگرداند.

مدیریت آرگومان‌ها در Telebot مستلزم تجزیه متن پیام دریافتی است. شیء message که به تابع handler ارسال می‌شود، حاوی ویژگی text است که کل پیام ارسالی توسط کاربر را در بر می‌گیرد.

تجزیه متن پیام برای استخراج آرگومان‌ها

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

import telebot

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

@bot.message_handler(commands=['echo'])
def echo_command(message):
    # پیام را به کلمات تقسیم می‌کنیم
    # ["/echo", "سلام", "دنیا"]
    parts = message.text.split() 
    
    # اگر فقط "/echo" ارسال شده باشد، آرگومانی وجود ندارد
    if len(parts) < 2:
        bot.reply_to(message, "لطفاً متنی برای تکرار وارد کنید. مثال: /echo سلام")
        return
    
    # آرگومان‌ها از اندیس ۱ به بعد هستند
    echo_text = " ".join(parts[1:])
    bot.reply_to(message, f"شما گفتید: {echo_text}")

@bot.message_handler(commands=['sum'])
def sum_command(message):
    parts = message.text.split()
    
    if len(parts) != 3: # انتظار داریم /sum num1 num2
        bot.reply_to(message, "لطفاً دو عدد برای جمع وارد کنید. مثال: /sum 5 10")
        return
    
    try:
        num1 = int(parts[1])
        num2 = int(parts[2])
        result = num1 + num2
        bot.reply_to(message, f"حاصل جمع {num1} و {num2} برابر است با: {result}")
    except ValueError:
        bot.reply_to(message, "ورودی نامعتبر است. لطفاً فقط عدد وارد کنید. مثال: /sum 5 10")

# ... سایر دستورات (start, help, info) ...
@bot.message_handler(commands=['start'])
def send_welcome(message):
    user_name = message.from_user.first_name if message.from_user.first_name else "کاربر عزیز"
    welcome_text = (
        f"سلام {user_name}! به ربات تعاملی من خوش آمدید.\n"
        "من یک ربات هستم که می‌توانم کارهای مختلفی انجام دهم.\n"
        "برای مشاهده لیست دستورات، /help را ارسال کنید."
    )
    bot.send_message(message.chat.id, welcome_text)

@bot.message_handler(commands=['help'])
def send_help(message):
    help_text = (
        "لیست دستورات موجود:\n"
        "/start - شروع مکالمه و خوش‌آمدگویی\n"
        "/help - نمایش این راهنما\n"
        "/info - دریافت اطلاعات کلی در مورد ربات\n"
        "/echo [متن] - تکرار متن ارسالی شما (مثال: /echo سلام)\n"
        "/sum [عدد۱] [عدد۲] - جمع دو عدد (مثال: /sum 5 10)"
    )
    bot.send_message(message.chat.id, help_text)

@bot.message_handler(commands=['info'])
def send_info(message):
    info_text = (
        "این ربات یک نمونه برای آموزش مدیریت دستورات در Telebot است.\n"
        "توسعه‌دهنده: مثال کاربر\n"
        "نسخه: 1.0.0"
    )
    bot.send_message(message.chat.id, info_text)

bot.polling()

توضیحات کد بالا:

  • دستور /echo:
    • message.text.split() رشته پیام را به لیستی از کلمات تبدیل می‌کند. برای /echo سلام دنیا، این لیست می‌شود ['/echo', 'سلام', 'دنیا'].
    • len(parts) < 2 بررسی می‌کند که آیا به جز خود دستور، آرگومان دیگری ارسال شده است یا خیر. اگر نه، پیام راهنما ارسال می‌شود.
    • " ".join(parts[1:]) تمام کلمات از اندیس ۱ به بعد (یعنی تمام آرگومان‌ها) را با فاصله به هم متصل کرده و متن نکرار شونده را می‌سازد.
  • دستور /sum:
    • len(parts) != 3 بررسی می‌کند که آیا دقیقاً دو آرگومان (علاوه بر خود دستور) ارسال شده است یا خیر.
    • یک بلاک try-except ValueError برای تبدیل رشته‌ها به عدد صحیح (int()) استفاده شده است. این بسیار مهم است، زیرا اگر کاربر چیزی غیر از عدد وارد کند، int() خطا می‌دهد. مدیریت خطا به ربات شما کمک می‌کند تا در برابر ورودی‌های نامعتبر مقاوم باشد.

نکات مهم:

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

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

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

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

در Telebot، مدیریت خطاها عمدتاً به دو صورت انجام می‌شود: اعتبارسنجی ورودی کاربر در سطح منطق برنامه و استفاده از ساختارهای try-except پایتون برای مقابله با خطاهای زمان اجرا.

۱. اعتبارسنجی ورودی کاربر

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

import telebot

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

@bot.message_handler(commands=['sum'])
def sum_command_with_error_handling(message):
    parts = message.text.split()
    
    # 1. اعتبارسنجی تعداد آرگومان‌ها
    if len(parts) != 3:
        bot.reply_to(message, 
                     "خطا: لطفاً دو عدد برای جمع وارد کنید. مثال صحیح: /sum 5 10")
        return
    
    try:
        # 2. اعتبارسنجی نوع داده (تبدیل به int)
        num1 = int(parts[1])
        num2 = int(parts[2])

        # 3. (اختیاری) اعتبارسنجی محدوده یا سایر منطق‌های کسب‌وکار
        # مثلاً اگر بخواهیم اعداد مثبت باشند:
        if num1 < 0 or num2 < 0:
            bot.reply_to(message, 
                         "خطا: لطفاً فقط اعداد مثبت را وارد کنید.")
            return

        result = num1 + num2
        bot.reply_to(message, f"حاصل جمع {num1} و {num2} برابر است با: {result}")
    
    except ValueError:
        # مدیریت خطای تبدیل نوع (اگر کاربر عدد وارد نکرده باشد)
        bot.reply_to(message, 
                     "خطا: ورودی نامعتبر است. لطفاً فقط عدد وارد کنید. مثال صحیح: /sum 5 10")
    except Exception as e:
        # یک مدیریت خطای کلی برای هر مشکل غیرمنتظره دیگر
        bot.reply_to(message, 
                     f"خطای غیرمنتظره رخ داد: {e}. لطفاً دوباره امتحان کنید یا با پشتیبانی تماس بگیرید.")
        # در اینجا می‌توانید خطا را log کنید
        print(f"An unexpected error occurred: {e}")

# ... سایر دستورات ...

bot.polling()

در این مثال، اعتبارسنجی‌ها به صورت زیر اعمال شده‌اند:

  • تعداد آرگومان‌ها: با len(parts) != 3 اطمینان حاصل می‌کنیم که کاربر دقیقاً دو عدد را وارد کرده است.
  • نوع داده: بلاک try-except ValueError برای مدیریت حالتی است که int() نتواند رشته را به عدد تبدیل کند (مثلاً اگر کاربر “پنج” به جای 5 وارد کند).
  • محدوده/منطق کسب‌وکار: یک شرط if num1 < 0 or num2 < 0 اضافه شده تا اگر نیاز باشد، فقط اعداد مثبت پذیرفته شوند. این مورد بسته به منطق ربات شما متغیر است.
  • خطای عمومی: یک except Exception as e کلی برای گرفتن هر خطای پیش‌بینی نشده‌ای که ممکن است رخ دهد، اضافه شده است. این برای پایداری ربات حیاتی است.

۲. استفاده از `bot.set_update_listener` و `bot.polling(none_stop=True)`

برای اطمینان از اینکه ربات شما در صورت بروز خطا در یک handler خاص، متوقف نشود و همچنان به دریافت پیام‌های دیگر ادامه دهد، می‌توانید از bot.polling(none_stop=True) استفاده کنید. همچنین می‌توانید یک listener برای خطاهای API اضافه کنید:

# ...
# در ابتدای کد، بعد از تعریف bot
@bot.message_handler(commands=['start', 'help', 'info', 'echo', 'sum'])
def handle_all_commands(message):
    try:
        if message.text.startswith('/start'):
            send_welcome(message)
        elif message.text.startswith('/help'):
            send_help(message)
        elif message.text.startswith('/info'):
            send_info(message)
        elif message.text.startswith('/echo'):
            echo_command(message)
        elif message.text.startswith('/sum'):
            sum_command_with_error_handling(message)
        else: # اگر دستور ناشناخته باشد
            bot.reply_to(message, "دستور نامعتبر. برای راهنما /help را ارسال کنید.")
    except Exception as e:
        bot.reply_to(message, "خطای داخلی ربات رخ داد. لطفاً دوباره امتحان کنید.")
        print(f"Error in command handler: {e}")

# برای پیام‌های غیردستوری
@bot.message_handler(func=lambda message: True)
def handle_other_messages(message):
    bot.reply_to(message, "من فقط دستورات را متوجه می‌شوم. برای راهنما /help را ارسال کنید.")

# این خط باید در انتها باشد
bot.polling(none_stop=True) # اطمینان از اینکه ربات در صورت خطا متوقف نشود

در این رویکرد، ما یک handle_all_commands ایجاد کردیم که تمام دستورات را در یک بلوک try-except بزرگتر قرار می‌دهد تا خطاهای عمومی را نیز مدیریت کند. همچنین یک handler برای تمام پیام‌هایی که دستور نیستند (func=lambda message: True) اضافه کردیم تا یک پاسخ پیش‌فرض به آن‌ها بدهد. استفاده از none_stop=True به bot.polling() تضمین می‌کند که حتی اگر یک خطا در پردازش یک پیام رخ دهد، ربات همچنان به گوش دادن برای پیام‌های بعدی ادامه می‌دهد.

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

استفاده از State در دستورات: ایجاد جریان‌های مکالمه‌ای پیچیده

برای ساخت ربات‌های تعاملی واقعی، اغلب نیاز است که ربات بتواند مکالمات چندمرحله‌ای را مدیریت کند. به عنوان مثال، یک فرآیند ثبت‌نام که در آن ربات ابتدا نام، سپس سن و در نهایت ایمیل کاربر را می‌پرسد. در این سناریوها، هر پاسخ کاربر به یک سوال، بستگی به سوال قبلی ربات دارد. این مفهوم در Telebot با استفاده از “حالت‌ها” (States) مدیریت می‌شود.

در نسخه‌های قدیمی‌تر pyTelegramBotAPI، مدیریت حالت‌ها نیاز به پیاده‌سازی دستی داشت. اما در نسخه‌های 4 و جدیدتر، Telebot یک سیستم مدیریت حالت داخلی قدرتمند را معرفی کرده است که بر اساس telebot.handler_backends.StateFilter و telebot.custom_filters.StateFilter کار می‌کند.

مفهوم State (حالت)

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

پیاده‌سازی States در Telebot

برای استفاده از States، نیاز به انجام چند مرحله است:

  1. تعریف کلاس States
  2. تنظیم State برای یک کاربر
  3. تعریف handlerها برای هر State
  4. حذف State پس از اتمام مکالمه

بیایید یک مثال برای فرآیند ثبت‌نام ایجاد کنیم که در آن ربات نام و سن کاربر را می‌پرسد.

import telebot
from telebot import custom_filters
from telebot.handler_backends import State, StatesGroup

API_TOKEN = 'YOUR_BOT_API_TOKEN'
bot = telebot.TeleBot(API_TOKEN)

# 1. تعریف کلاس States
# هر متغیر در این کلاس یک State منحصر به فرد را نشان می دهد
class MyStates(StatesGroup):
    name = State() # وضعیت انتظار برای دریافت نام
    age = State()  # وضعیت انتظار برای دریافت سن
    # در صورت نیاز می توانید States بیشتری اضافه کنید

# --------------------------------------------------------------
# Handlers برای شروع مکالمه
# --------------------------------------------------------------
@bot.message_handler(commands=['register'])
def register_start(message):
    bot.send_message(message.chat.id, "خب، بیایید ثبت‌نام کنیم. نام شما چیست؟")
    bot.set_state(message.from_user.id, MyStates.name, message.chat.id)
    # bot.set_state(user_id, state_name, chat_id)
    # user_id: شناسه کاربر
    # state_name: وضعیت فعلی که کاربر باید در آن قرار گیرد (از کلاس MyStates)
    # chat_id: شناسه چتی که وضعیت در آن تنظیم می شود (معمولاً همان chat.id پیام دریافتی)

@bot.message_handler(commands=['cancel'])
def cancel_registration(message):
    # اگر کاربر در هر مرحله ای خواست مکالمه را کنسل کند
    bot.delete_state(message.from_user.id, message.chat.id)
    bot.send_message(message.chat.id, "ثبت‌نام لغو شد.")

# --------------------------------------------------------------
# Handlers برای هر State
# --------------------------------------------------------------

# Handler برای State نام
@bot.message_handler(state=MyStates.name, content_types=['text'])
def get_name(message):
    if not message.text or len(message.text) < 2:
        bot.send_message(message.chat.id, "نام وارد شده معتبر نیست. لطفاً یک نام واقعی وارد کنید.")
        return

    # ذخیره نام کاربر
    with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
        data['name'] = message.text
    
    bot.send_message(message.chat.id, f"از آشنایی با شما، {message.text}، خوشبختم! چند سال دارید؟")
    bot.set_state(message.from_user.id, MyStates.age, message.chat.id)

# Handler برای State سن
@bot.message_handler(state=MyStates.age, content_types=['text'])
def get_age(message):
    if not message.text or not message.text.isdigit():
        bot.send_message(message.chat.id, "سن وارد شده معتبر نیست. لطفاً یک عدد صحیح وارد کنید.")
        return
    
    age = int(message.text)
    if age < 5 or age > 120:
        bot.send_message(message.chat.id, "لطفاً یک سن معتبر بین ۵ تا ۱۲۰ وارد کنید.")
        return

    # ذخیره سن کاربر
    with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
        data['age'] = age
        final_message = (
            f"متشکرم! اطلاعات شما ثبت شد:\n"
            f"نام: {data['name']}\n"
            f"سن: {data['age']}"
        )
    
    bot.send_message(message.chat.id, final_message)
    # پس از اتمام مکالمه، وضعیت کاربر را حذف می‌کنیم
    bot.delete_state(message.from_user.id, message.chat.id)

# --------------------------------------------------------------
# Handlers عمومی و سایر دستورات
# --------------------------------------------------------------

@bot.message_handler(commands=['start', 'help', 'info'])
def handle_general_commands(message):
    if message.text == '/start':
        bot.send_message(message.chat.id, "به ربات من خوش آمدید! برای ثبت‌نام /register را ارسال کنید.")
    elif message.text == '/help':
        bot.send_message(message.chat.id, "دستورات:\n/register - شروع ثبت‌نام\n/cancel - لغو ثبت‌نام در هر مرحله\n/help - نمایش این راهنما")
    elif message.text == '/info':
        bot.send_message(message.chat.id, "این ربات یک نمونه برای مدیریت States است.")

# Handler برای هر پیامی که با هیچ دستوری یا Stateای مطابقت ندارد
# و کاربر در حالت خاصی نیست
@bot.message_handler(func=lambda message: True, state=None)
def echo_all(message):
    bot.send_message(message.chat.id, "متوجه نشدم. لطفاً یکی از دستورات را ارسال کنید.")


# ثبت فیلترهای سفارشی برای States
bot.add_custom_filter(custom_filters.StateFilter(bot))

# شروع پولینگ ربات
bot.polling(none_stop=True)

توضیح کد:

  • from telebot.handler_backends import State, StatesGroup: کلاس‌های لازم برای تعریف Stateها را وارد می‌کند.
  • class MyStates(StatesGroup):: یک کلاس برای تعریف Stateهای ربات ایجاد می‌کند. هر متغیر در این کلاس (مانند name و age) یک State منحصر به فرد است.
  • @bot.message_handler(commands=['register']): این handler شروع فرآیند ثبت‌نام است. پس از ارسال پیام خوش‌آمدگویی، bot.set_state(user_id, MyStates.name, chat_id) وضعیت کاربر را به MyStates.name تغییر می‌دهد.
  • @bot.message_handler(state=MyStates.name, content_types=['text']): این handler تنها زمانی فعال می‌شود که کاربر در وضعیت MyStates.name باشد و یک پیام متنی ارسال کند.
  • with bot.retrieve_data(message.from_user.id, message.chat.id) as data:: این متد به شما امکان می‌دهد تا داده‌های مربوط به وضعیت فعلی کاربر (مثلاً نامی که قبلاً وارد کرده است) را ذخیره و بازیابی کنید. این data یک دیکشنری است که می‌توانید هر اطلاعاتی را در آن ذخیره کنید.
  • bot.set_state(...): برای تغییر وضعیت کاربر به مرحله بعدی مکالمه استفاده می‌شود.
  • bot.delete_state(...): پس از اتمام مکالمه (یا در صورت لغو)، برای بازنشانی وضعیت کاربر به None (حالت پیش‌فرض، یعنی بدون وضعیت خاص) استفاده می‌شود.
  • bot.add_custom_filter(custom_filters.StateFilter(bot)): این خط حیاتی است. این فیلتر سفارشی را به Telebot اضافه می‌کند تا بتواند با پارامتر state در دکوراتور @bot.message_handler() کار کند. باید پس از ایجاد شیء bot و قبل از bot.polling() فراخوانی شود.

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

دستورات سفارشی و فیلترها: انعطاف‌پذیری بیشتر

درحالی‌که پارامتر commands در @bot.message_handler() برای مدیریت دستورات استاندارد بسیار مفید است، Telebot ابزارهای قدرتمند دیگری نیز برای ایجاد فیلترهای سفارشی و منطق پیچیده‌تر برای انتخاب پیام‌ها ارائه می‌دهد. این ابزارها شامل پارامترهای func، regexp و content_types و همچنین امکان تعریف فیلترهای سفارشی پیشرفته‌تر هستند.

۱. استفاده از content_types

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

@bot.message_handler(content_types=['photo'])
def handle_photo_message(message):
    bot.reply_to(message, "ممنون برای ارسال عکس! چه عکس زیبایی!")
    # می‌توانید اطلاعات عکس را از message.photo دریافت کنید
    # message.photo حاوی لیستی از شیءهای PhotoSize است (نسخه‌های مختلف عکس با کیفیت‌های متفاوت)
    # برای دسترسی به بزرگترین عکس: message.photo[-1].file_id
    file_id = message.photo[-1].file_id
    print(f"File ID of the photo: {file_id}")

@bot.message_handler(content_types=['document'])
def handle_document_message(message):
    bot.reply_to(message, f"ممنون برای ارسال سند. نام فایل: {message.document.file_name}")

@bot.message_handler(content_types=['audio', 'voice'])
def handle_audio_message(message):
    bot.reply_to(message, "ممنون برای ارسال پیام صوتی یا فایل صوتی.")

لیست کامل content_types شامل: 'text', 'audio', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'location', 'contact', 'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', 'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', 'web_app_data', 'proximity_alert_triggered', 'forum_topic_created', 'forum_topic_closed', 'forum_topic_reopened', 'video_chat_started', 'video_chat_ended', 'video_chat_participants_invited', 'message_auto_delete_timer_changed', 'successfull_payment', 'game_skill_dice', 'animation', 'poll', 'all' (برای پردازش هر نوع محتوا).

۲. استفاده از regexp برای الگوهای پیچیده‌تر

پارامتر regexp به شما امکان می‌دهد تا پیام‌ها را بر اساس تطابق با یک عبارت منظم (Regular Expression) فیلتر کنید. این برای دستوراتی که الگوی خاصی دارند یا برای شناسایی کلمات کلیدی در متن پیام‌ها بسیار قدرتمند است.

@bot.message_handler(regexp=".*[Hh]ello.*") # هر پیامی که شامل "hello" یا "Hello" باشد
def handle_hello_regexp(message):
    bot.reply_to(message, "سلام! من کلمه 'hello' را در پیام شما تشخیص دادم.")

@bot.message_handler(regexp="^/weather ([a-zA-Z\s]+)$") # دستور /weather با نام شهر
def get_weather(message):
    # message.text = "/weather Tehran"
    # re.match().groups() خروجی (Tehran,)
    city_name = message.text.split(' ', 1)[1] # "Tehran"
    # در اینجا می‌توانید به API آب و هوا متصل شوید و اطلاعات را برگردانید
    bot.reply_to(message, f"در حال دریافت آب و هوای {city_name}...")
    # فرض کنید API آب و هوا را فراخوانی کرده‌اید
    # bot.reply_to(message, f"آب و هوای {city_name}: آفتابی، 25 درجه سانتی‌گراد")

نکته: وقتی از regexp برای استخراج اطلاعات استفاده می‌کنید، شیء message دارای ویژگی text_html_args یا text_markdown_args است که به شما امکان می‌دهد گروه‌های مطابق با عبارت منظم را استخراج کنید. با این حال، استفاده از message.text.split() اغلب برای دستورات ساده‌تر و خواناتر است.

۳. استفاده از func برای فیلترهای سفارشی

پارامتر func به شما اجازه می‌دهد تا هر تابع پایتونی را به عنوان فیلتر خود تعریف کنید. این تابع یک شیء message را به عنوان ورودی می‌گیرد و باید True یا False برگرداند. اگر True برگرداند، handler فعال می‌شود. این برای فیلترهای پیچیده مانند کنترل دسترسی، فیلتر کردن بر اساس زمان، یا منطق‌های بسیار خاص عالی است.

ADMIN_ID = 123456789 # شناسه عددی ادمین (مثلا شناسه خودتان)

def is_admin(message):
    return message.from_user.id == ADMIN_ID

@bot.message_handler(func=is_admin, commands=['broadcast'])
def admin_broadcast(message):
    # این دستور فقط توسط ادمین قابل استفاده است
    parts = message.text.split(' ', 1)
    if len(parts) < 2:
        bot.reply_to(message, "لطفاً پیامی برای پخش وارد کنید. مثال: /broadcast سلام به همه!")
        return
    
    broadcast_message = parts[1]
    # در اینجا باید منطق پخش پیام به تمام کاربران ربات را پیاده سازی کنید
    bot.reply_to(message, f"پیام '{broadcast_message}' برای همه کاربران ارسال شد. (این یک پیام شبیه‌سازی شده است)")

def contains_profanity(message):
    profane_words = ["کلمه بد", "واژه زشت"] # لیست کلمات توهین آمیز
    return any(word in message.text.lower() for word in profane_words)

@bot.message_handler(func=contains_profanity)
def handle_profanity(message):
    bot.delete_message(message.chat.id, message.message_id) # پاک کردن پیام
    bot.send_message(message.chat.id, "لطفاً از کلمات مناسب استفاده کنید.")

در مثال is_admin، تنها کاربر با ADMIN_ID می‌تواند دستور /broadcast را اجرا کند. در مثال contains_profanity، هر پیامی که حاوی کلمات توهین‌آمیز باشد، توسط ربات پاک می‌شود و به کاربر اخطار داده می‌شود.

۴. ترکیب فیلترها

شما می‌توانید چندین فیلتر را با هم ترکیب کنید تا به نتایج دقیق‌تری برسید. Telebot ابتدا فیلتر commands را بررسی می‌کند، سپس regexp، سپس content_types و در نهایت func را اجرا می‌کند. یک handler تنها در صورتی فعال می‌شود که تمام فیلترهای مشخص شده در آن True برگردانند.

# یک دستور که فقط ادمین می تواند یک فایل PDF را ارسال کند
@bot.message_handler(func=is_admin, content_types=['document'])
def handle_admin_document(message):
    if message.document.mime_type == 'application/pdf':
        bot.reply_to(message, "ادمین یک فایل PDF ارسال کرد.")
    else:
        bot.reply_to(message, "این سند یک PDF نیست.")

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

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

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

۱. ماژولار کردن کد (Modularization)

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

  • main.py: فایل اصلی که ربات را مقداردهی اولیه می‌کند و bot.polling() را اجرا می‌کند.
  • handlers/ (یک پوشه): حاوی فایل‌هایی برای دسته‌بندی handlerها. مثلاً handlers/general.py برای دستورات عمومی (start, help)، handlers/admin.py برای دستورات ادمین، handlers/state_handlers.py برای منطق مربوط به States.
  • config.py: برای ذخیره متغیرهای پیکربندی مانند API_TOKEN، شناسه‌های ادمین، تنظیمات پایگاه داده و غیره.

مثال ساختار پروژه:

├── main.py
├── config.py
├── handlers/
│   ├── __init__.py
│   ├── general.py
│   ├── admin.py
│   └── state_handlers.py
└── utils/
    ├── __init__.py
    └── helpers.py # توابع کمکی مشترک

در main.py، می‌توانید handlerها را از فایل‌های دیگر وارد کنید:

# main.py
import telebot
from telebot import custom_filters
from config import API_TOKEN

bot = telebot.TeleBot(API_TOKEN)

# وارد کردن handlerها از ماژول های مختلف
from handlers import general
from handlers import admin
from handlers import state_handlers

# رجیستر کردن handlerها (این ممکن است نیاز به کمی تغییر در طراحی handlerها داشته باشد)
# یک راه ساده تر این است که در هر فایل handler، bot را وارد کنید و handlerها را مستقیماً تعریف کنید
# و سپس آن فایل را در main.py import کنید تا دکوراتورها اجرا شوند.

# مثال رجیستر کردن Handlers اگر به صورت تابع تعریف شده باشند
# general.register_handlers(bot)
# admin.register_handlers(bot)
# state_handlers.register_handlers(bot)

# اگر از دکوراتورها در هر فایل استفاده می کنید، فقط کافیست import کنید:
# import handlers.general
# import handlers.admin
# import handlers.state_handlers

# افزودن فیلترهای سفارشی
bot.add_custom_filter(custom_filters.StateFilter(bot))

print("ربات در حال اجرا است...")
bot.polling(none_stop=True)

و در handlers/general.py:

# handlers/general.py
from main import bot # برای دسترسی به شیء bot

@bot.message_handler(commands=['start'])
def send_welcome(message):
    bot.send_message(message.chat.id, "خوش آمدید!")

@bot.message_handler(commands=['help'])
def send_help(message):
    bot.send_message(message.chat.id, "اینجا راهنما است.")

# اگر نمی خواهید از main.py وارد کنید، می توانید یک تابع register_handlers بسازید
# def register_handlers(bot_instance):
#     @bot_instance.message_handler(commands=['start'])
#     def send_welcome(message):
#         bot_instance.send_message(message.chat.id, "خوش آمدید!")
#     # ... سایر handlerها

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

۲. استفاده از فایل config.py برای تنظیمات

هرگز توکن API یا اطلاعات حساس دیگر را مستقیماً در کد اصلی قرار ندهید. استفاده از یک فایل config.py یا متغیرهای محیطی برای این منظور، امنیت و انعطاف‌پذیری را افزایش می‌دهد.

# config.py
import os

API_TOKEN = os.getenv('TELEBOT_API_TOKEN', 'YOUR_DEFAULT_API_TOKEN_IF_NOT_SET_IN_ENV')
ADMIN_IDS = [123456789, 987654321] # شناسه های عددی ادمین ها
DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///data.db')

سپس در main.py آن را وارد کنید: from config import API_TOKEN, ADMIN_IDS.

۳. مدیریت خطا و Logging

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

import logging
import telebot

# پیکربندی اولیه logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# ...
# در هر handler:
@bot.message_handler(commands=['some_command'])
def some_command(message):
    try:
        # منطق دستور
        logger.info(f"Command '/some_command' received from user {message.from_user.id}")
    except Exception as e:
        logger.error(f"Error in '/some_command' for user {message.from_user.id}: {e}", exc_info=True)
        bot.reply_to(message, "خطایی رخ داد. لطفاً دوباره امتحان کنید.")

۴. پیام‌های کاربرپسند و جامع /help

اطمینان حاصل کنید که پیام /help شما همیشه به‌روز و جامع است و تمام دستورات و قابلیت‌های ربات را با توضیحات کوتاه و واضح فهرست می‌کند. برای دستورات پیچیده‌تر، می‌توانید یک دستور /help_command_name (مثلاً /help_sum) برای راهنمایی دقیق‌تر ارائه دهید.

۵. استفاده از Inline Keyboards و Reply Keyboards

برای تعاملات بیشتر از صرفاً دستورات متنی، استفاده از دکمه‌های Inline (که زیر پیام ظاهر می‌شوند و با Callback Query کار می‌کنند) و Reply Keyboards (که در پایین صفحه کلید ظاهر می‌شوند) را در نظر بگیرید. اینها تجربه کاربری را به شدت بهبود می‌بخشند.

۶. استفاده بهینه از API تلگرام

از ارسال پیام‌های تکراری یا انجام درخواست‌های غیرضروری به API تلگرام خودداری کنید. تلگرام دارای محدودیت‌های نرخ (rate limits) است و ربات شما ممکن است در صورت سوء استفاده، به طور موقت مسدود شود.

۷. تست و دیباگینگ

ربات خود را به طور کامل تست کنید. از ابزارهای دیباگینگ پایتون استفاده کنید. در محیط توسعه، ربات را با bot.polling(none_stop=True) اجرا کنید تا در صورت بروز خطا، متوقف نشود.

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

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

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

۱. اعتبارسنجی ورودی (Input Validation)

همانطور که قبلاً بحث شد، اعتبارسنجی تمام ورودی‌های کاربر حیاتی است. هرگز به ورودی کاربر اعتماد نکنید. این شامل موارد زیر است:

  • اعتبارسنجی نوع داده: اطمینان حاصل کنید که ورودی‌ها از نوع مورد انتظار (عدد، رشته، تاریخ) هستند.
  • اعتبارسنجی فرمت: بررسی کنید که ورودی‌ها (مانند ایمیل، URL، شماره تلفن) فرمت صحیح دارند.
  • اعتبارسنجی محدوده: اطمینان حاصل کنید که مقادیر در محدوده مجاز قرار دارند (مثلاً سن بین 1 تا 120).
  • ضد SQL Injection: اگر ربات شما با پایگاه داده کار می‌کند، هرگز ورودی کاربر را مستقیماً به کوئری‌های SQL اضافه نکنید. همیشه از Prepared Statements یا ORMها (مانند SQLAlchemy) استفاده کنید که به طور خودکار از Injection جلوگیری می‌کنند.
  • ضد Path Traversal: اگر ربات شما با فایل‌سیستم تعامل دارد و نام فایل‌ها را از کاربر می‌گیرد، مطمئن شوید که کاربر نمی‌تواند با وارد کردن مسیرهای غیرمجاز (مانند ../../etc/passwd) به فایل‌های خارج از محدوده دسترسی پیدا کند.

۲. کنترل دسترسی (Authorization)

بسیاری از دستورات باید فقط برای کاربران خاص (مانند مدیران) قابل دسترس باشند. هرگز اجازه ندهید هر کاربری به دستورات مدیریتی یا حساس دسترسی داشته باشد.

from config import ADMIN_IDS # فرض کنید ADMIN_IDS در config.py تعریف شده است

def is_admin(message):
    return message.from_user.id in ADMIN_IDS

@bot.message_handler(commands=['admin_restart'], func=is_admin)
def admin_restart_command(message):
    bot.reply_to(message, "ربات در حال راه‌اندازی مجدد است...")
    # منطق ری‌استارت کردن یا استاپ کردن سرویس ربات
    # این قسمت باید با دقت فراوان و در محیط‌های کنترل شده انجام شود.

@bot.message_handler(commands=['delete_user'], func=is_admin)
def delete_user_command(message):
    parts = message.text.split()
    if len(parts) != 2 or not parts[1].isdigit():
        bot.reply_to(message, "لطفاً شناسه کاربر را وارد کنید. مثال: /delete_user 12345")
        return
    
    user_to_delete_id = int(parts[1])
    # منطق حذف کاربر از پایگاه داده یا سیستم شما
    bot.reply_to(message, f"کاربر با شناسه {user_to_delete_id} حذف شد. (شبیه‌سازی)")

# یک handler پیش‌فرض برای دستورات ادمین که توسط غیر ادمین‌ها ارسال می‌شود
@bot.message_handler(commands=['admin_restart', 'delete_user'])
def unauthorized_access(message):
    bot.reply_to(message, "شما اجازه دسترسی به این دستور را ندارید.")

در این مثال، اگر is_admin به False برگردد، Telebot به handler بعدی که با commands=['admin_restart', 'delete_user'] مطابقت دارد، می‌رود و پیام “شما اجازه دسترسی به این دستور را ندارید.” را نمایش می‌دهد. این یک راه عالی برای مدیریت دسترسی و جلوگیری از خطای پیش‌فرض Telebot است که اگر هیچ handler‌ای پیدا نشود، هیچ پاسخی ندهد.

۳. مدیریت توکن API

توکن API ربات شما معادل نام کاربری و رمز عبور ربات است. هرگز آن را به صورت عمومی به اشتراک نگذارید. از متغیرهای محیطی یا فایل .env برای ذخیره آن استفاده کنید و هرگز آن را به صورت Hardcode در مخزن کد خود (به خصوص اگر عمومی است) قرار ندهید.

# در config.py
import os
API_TOKEN = os.getenv('TELEBOT_API_TOKEN') # از متغیر محیطی بخوانید
if not API_TOKEN:
    raise ValueError("TELEBOT_API_TOKEN environment variable not set.")

۴. Rate Limiting (محدودیت نرخ)

برای جلوگیری از سوء استفاده از ربات (مثلاً ارسال سیلاب از پیام‌ها یا درخواست‌های زیاد به APIهای خارجی)، می‌توانید یک سیستم Rate Limiting پیاده‌سازی کنید. این کار می‌تواند در سطح تلگرام (API تلگرام خودش Rate Limit دارد) یا در سطح منطق ربات شما باشد. برای مثال، می‌توانید درخواست‌های یک کاربر را در یک بازه زمانی خاص محدود کنید.

from collections import defaultdict
import time

user_last_command_time = defaultdict(float)
COMMAND_COOLDOWN = 2 # ثانیه

@bot.message_handler(commands=['heavy_task'])
def heavy_task_command(message):
    user_id = message.from_user.id
    current_time = time.time()

    if current_time - user_last_command_time[user_id] < COMMAND_COOLDOWN:
        bot.reply_to(message, f"لطفاً {COMMAND_COOLDOWN - (current_time - user_last_command_time[user_id]):.1f} ثانیه صبر کنید.")
        return
    
    user_last_command_time[user_id] = current_time
    # منطق کار سنگین...
    bot.reply_to(message, "کار سنگین در حال انجام است...")

۵. Log کردن رویدادهای امنیتی

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

۶. به‌روزرسانی منظم کتابخانه‌ها

همیشه کتابخانه pyTelegramBotAPI و سایر وابستگی‌های پروژه خود را به آخرین نسخه پایدار به‌روز نگه دارید. به‌روزرسانی‌ها اغلب شامل اصلاحات امنیتی هستند که از آسیب‌پذیری‌های شناخته شده جلوگیری می‌کنند.

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

نمونه‌های پیشرفته و سناریوهای واقعی

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

۱. ادغام با پایگاه‌های داده (Databases)

اکثر ربات‌های کاربردی نیاز به ذخیره‌سازی و بازیابی اطلاعات دارند. این اطلاعات می‌تواند شامل تنظیمات کاربر، داده‌های جمع‌آوری شده، یا هر نوع داده‌ای باشد که ربات شما با آن کار می‌کند. Telebot به خودی خود ابزاری برای کار با پایگاه داده ندارد، اما به راحتی می‌تواند با کتابخانه‌های پایتون برای پایگاه داده‌ها ادغام شود.

  • SQLite (برای پروژه‌های کوچک): سبک، فایل-محور و بسیار مناسب برای ربات‌های کوچک تا متوسط. می‌توانید از ماژول sqlite3 داخلی پایتون یا ORMهایی مانند SQLAlchemy استفاده کنید.
  • PostgreSQL/MySQL (برای پروژه‌های بزرگ): قدرتمندتر، مقیاس‌پذیرتر و مناسب برای ربات‌های با ترافیک بالا یا داده‌های پیچیده‌تر. SQLAlchemy گزینه خوبی برای این موارد است.
import sqlite3

# تابع برای اتصال به دیتابیس
def get_db_connection():
    conn = sqlite3.connect('bot_data.db')
    conn.row_factory = sqlite3.Row # برای دسترسی به ستون ها با نام
    return conn

# تابع برای ایجاد جدول (اگر وجود ندارد)
def create_users_table():
    conn = get_db_connection()
    conn.execute('''
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY,
            telegram_id INTEGER UNIQUE NOT NULL,
            username TEXT,
            registered_at TEXT
        )
    ''')
    conn.commit()
    conn.close()

# فراخوانی یک بار در شروع ربات
create_users_table()

@bot.message_handler(commands=['register_db'])
def register_user_to_db(message):
    user_id = message.from_user.id
    username = message.from_user.username
    
    conn = get_db_connection()
    try:
        conn.execute("INSERT INTO users (telegram_id, username, registered_at) VALUES (?, ?, DATETIME('now'))",
                     (user_id, username))
        conn.commit()
        bot.reply_to(message, "شما با موفقیت در پایگاه داده ثبت نام شدید!")
    except sqlite3.IntegrityError:
        bot.reply_to(message, "شما قبلاً در پایگاه داده ثبت نام کرده‌اید.")
    finally:
        conn.close()

۲. ادغام با APIهای خارجی (External APIs)

ربات‌ها اغلب به APIهای خارجی متصل می‌شوند تا اطلاعاتی مانند آب و هوا، نرخ ارز، اخبار یا داده‌های سفارشی را دریافت و به کاربر نمایش دهند. کتابخانه‌های requests و aiohttp (برای عملیات ناهمزمان) در پایتون برای این منظور استفاده می‌شوند.

import requests

WEATHER_API_KEY = "YOUR_WEATHER_API_KEY" # از یک سرویس آب و هوا مانند OpenWeatherMap

@bot.message_handler(commands=['weather'])
def get_weather(message):
    parts = message.text.split(' ', 1)
    if len(parts) < 2:
        bot.reply_to(message, "لطفاً نام شهر را وارد کنید. مثال: /weather Tehran")
        return
    
    city = parts[1].strip()
    try:
        url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={WEATHER_API_KEY}&units=metric&lang=fa"
        response = requests.get(url)
        response.raise_for_status() # اگر خطا HTTP رخ دهد، exception پرتاب می کند
        data = response.json()

        if data['cod'] == 200:
            temp = data['main']['temp']
            description = data['weather'][0]['description']
            bot.reply_to(message, f"آب و هوای {city}: {description}، دما {temp}°C.")
        else:
            bot.reply_to(message, f"خطا در دریافت اطلاعات آب و هوا: {data['message']}")

    except requests.exceptions.RequestException as e:
        bot.reply_to(message, "خطا در برقراری ارتباط با سرویس آب و هوا.")
        print(f"Weather API error: {e}")
    except Exception as e:
        bot.reply_to(message, f"خطای غیرمنتظره: {e}")

۳. زمان‌بندی وظایف (Scheduled Tasks)

ربات‌ها ممکن است نیاز داشته باشند که پیام‌های دوره‌ای ارسال کنند (مثلاً اخبار روزانه) یا وظایف خاصی را در زمان‌های مشخص اجرا کنند. برای این کار می‌توانید از کتابخانه‌هایی مانند APScheduler یا schedule استفاده کنید.

from apscheduler.schedulers.background import BackgroundScheduler
import datetime

# یک تابع برای ارسال پیام به یک گروه خاص
def send_daily_report(chat_id):
    bot.send_message(chat_id, f"گزارش روزانه: ساعت {datetime.datetime.now().strftime('%H:%M:%S')}")

# راه اندازی زمان‌بندی
scheduler = BackgroundScheduler()
# هر روز ساعت 9 صبح به چت 123456789 گزارش ارسال کن
# scheduler.add_job(send_daily_report, 'cron', hour=9, minute=0, args=[123456789])
scheduler.start()

# مطمئن شوید که scheduler در یک thread جداگانه اجرا می شود و با bot.polling تداخل ندارد.
# APScheduler به طور خودکار این کار را انجام می دهد.

۴. استفاده از Inline Keyboards و Callback Queries

دکمه‌های Inline در زیر پیام‌ها ظاهر می‌شوند و به کاربر امکان می‌دهند بدون ارسال یک دستور متنی جدید، با ربات تعامل کنند. این دکمه‌ها “Callback Query” را به ربات ارسال می‌کنند.

from telebot import types

@bot.message_handler(commands=['menu'])
def show_menu(message):
    markup = types.InlineKeyboardMarkup(row_width=2)
    itembtn1 = types.InlineKeyboardButton("گزینه ۱", callback_data='option1')
    itembtn2 = types.InlineKeyboardButton("گزینه ۲", callback_data='option2')
    itembtn3 = types.InlineKeyboardButton("گزینه ۳", callback_data='option3')
    markup.add(itembtn1, itembtn2, itembtn3)
    bot.send_message(message.chat.id, "لطفاً یکی از گزینه‌ها را انتخاب کنید:", reply_markup=markup)

@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
    if call.data == 'option1':
        bot.answer_callback_query(call.id, "شما گزینه ۱ را انتخاب کردید.")
        bot.send_message(call.message.chat.id, "شما گزینه یک را انتخاب کردید.")
    elif call.data == 'option2':
        bot.answer_callback_query(call.id, "شما گزینه ۲ را انتخاب کردید.")
        bot.send_message(call.message.chat.id, "شما گزینه دو را انتخاب کردید.")
    # همیشه باید به callback query پاسخ دهید

۵. مدیریت فایل‌ها و رسانه‌ها

ربات می‌تواند فایل‌ها (اسناد، عکس‌ها، ویدئوها) را دریافت و ارسال کند. این برای ربات‌های پشتیبانی، ربات‌های ذخیره‌سازی ابری یا ربات‌های پردازش تصویر بسیار مفید است. Telebot امکان دسترسی به file_id فایل‌های آپلود شده را فراهم می‌کند که می‌توانید از آن‌ها برای دانلود فایل‌ها یا ارسال مجدد آن‌ها استفاده کنید.

@bot.message_handler(content_types=['photo'])
def handle_photos_for_download(message):
    file_id = message.photo[-1].file_id # گرفتن بزرگترین نسخه عکس
    file_info = bot.get_file(file_id)
    downloaded_file = bot.download_file(file_info.file_path)

    with open(f"downloaded_photo_{file_id}.jpg", 'wb') as new_file:
        new_file.write(downloaded_file)
    
    bot.reply_to(message, "عکس شما با موفقیت دانلود و ذخیره شد.")
    # بعد از پردازش، می‌توانید فایل را به کاربر برگردانید یا با آن کاری انجام دهید
    # bot.send_photo(message.chat.id, photo=open(f"downloaded_photo_{file_id}.jpg", 'rb'))

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

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

“تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”

قیمت اصلی 2.290.000 ریال بود.قیمت فعلی 1.590.000 ریال است.

"تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"

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

ویژگی‌های کلیدی:

بدون نیاز به تجربه قبلی برنامه‌نویسی

زیرنویس فارسی با ترجمه حرفه‌ای

۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان