الفبای پایتون برای رباتنویسی
متغیرها، انواع دادهها و ساختار توابع
پیش از ورود به دنیای رباتها، باید بدانیم در پایتون اطلاعات چگونه نگهداری و پردازش میشوند. در رباتنویسی، به وفور با رشتهها (String) برای دریافت متن پیامها، عددها (Integers) برای شناسههای چت و کاربر، و دیکشنریها (Dict) برای ذخیره موقت اطلاعات سر و کار داریم:
# تعریف متغیرها و انواع داده
user_id = 987654321 # شناسه چت (عددی)
user_name = "سوشیانس" # نام کاربر (متنی)
is_active = True # وضعیت فعال بودن (بولین)
# تعریف یک تابع ساده برای خوشآمدگویی
def generate_welcome_message(name: str) -> str:
return f"درود {name} عزیز! به سیستم هوشمند خوش آمدید 🚀"
print(generate_welcome_message(user_name))
راز برنامهنویسی ناهمگام (Async / Await)
چرا برای تلگرام به async نیاز داریم؟
تصور کنید در یک کافیشاپ، گارسون سفارش قهوه نفر اول را بگیرد و تا زمانی که قهوه دم بکشد جلوی میز او بایستد و به بقیه مشتریها سرویس ندهد! در کدنویسی همگام (Sync) ربات شما معطل دریافت پاسخ تلگرام میشود. اما با async و await گارسون ربات شما سفارش را ثبت کرده و بلافاصلهبه پیام کاربران دیگر پاسخ میدهد:
import asyncio
# تعریف یک تابع ناهمگام با async
async def prepare_coffee(customer_name: str):
print(f"☕ شروع آمادهسازی سفارش برای {customer_name}...")
await asyncio.sleep(2) # شبیهسازی انتظار برای تلگرام بدون مسدودسازی برنامه
print(f"✅ قهوه {customer_name} تحویل داده شد!")
async def main():
# اجرای همزمان سفارشهای چند کاربر
await asyncio.gather(
prepare_coffee("سوشیانس"),
prepare_coffee("علی"),
prepare_coffee("مریم")
)
asyncio.run(main())
ربات تلگرام از پشتصحنه چطور کار میکند؟
معماری مبتنی بر آبجکتهای Update و سرور تلگرام
وقتی کاربری در تلگرام به ربات شما پیامی میفرستد، تلگرام آن رویداد را به یک بسته داده به نام Update تبدیل میکند. ربات شما این بسته را دریافت، تحلیل کرده و سپس پاسخی از طریق متدهای استاندارد Bot API (مثل sendMessage) برای تلگرام ارسال مینماید.
مقایسه Long Polling و Webhook
دو روش دریافت پیامها از سرورهای تلگرام
Long Polling (پیشفرض LazyNoto)
ربات شما مدام از سرور تلگرام میپرسد «پیام جدیدی هست؟». نیازی به دامنه، آیپی اختصاصی یا SSL ندارد و به صورت مستقیم روی سیستم لوکال یا سرور اجرا میشود.
Webhook
تلگرام به محض دریافت پیام، یک درخواست POST به سرور شما میفرستد. این روش نیازمند دامنه عمومی با گواهی SSL معتبر است.
چرا فریمورک LazyNoto؟
کاهش چشمگیر کدهای تکراری و بالا بردن خوانایی سورس
کتابخانههای خام تلگرام نیازمند پاسدادن مکرر chat_id، ساختارهای پیچیده و چندین خط کد برای یک ارسال ساده هستند. در LazyNoto تمام این جزئیات در شیء قدرتمند ctx کپسوله شده است.
راهنمای دریافت توکن از BotFather
ساخت ربات تلگرامی و دریافت کلید دسترسی به API
برای شروع، وارد ربات رسمی @BotFather در تلگرام شوید، دستور /newbot را ارسال کنید و پس از انتخاب نام و نام کاربری، توکن دسترسی (HTTP API Token) را دریافت نمایید.
نصب و پیکربندی پکیجها
راهاندازی در کمتر از ۱۰ ثانیه با ابزار استاندارد pip
# نصب فریمورک اختصاصی
pip install python-telegram-bot
# و قرار دادن پکیج یا فایل کمکی lazynoto در مسیر پروژه
اولین پروژه عملی (Quickstart)
سادهترین ربات پاسخگو به دستور start
from lazynoto import LazyNoto, NotoContext
# نمونهسازی از ربات با توکن
bot = LazyNoto(token="YOUR_TELEGRAM_BOT_TOKEN")
@bot.command("start")
async def start_handler(ctx: NotoContext):
await ctx.reply(f"سلام {ctx.user.first_name} عزیز! به فریمورک LazyNoto خوش آمدید 🚀")
if __name__ == "__main__":
print("ربات با موفقیت فعال شد...")
bot.run()
کالبدشکافی کامل شیء NotoContext
مغز متفکر رویدادها، پراپرتیها و متدهای عملیاتی
ویژگیها و دادهها (Properties)
ctx.user: آبجکت کاربر فرستندهctx.chat_id: شناسه یکتای چتctx.text: متن خام پیام ارسال شدهctx.message: آبجکت کامل پیام تلگرامctx.data: داده بازگشتی دکمه شیشهای (Callback)
متدها و عملیاتها (Actions)
await ctx.reply("متن"): ارسال پیام جدیدawait ctx.edit("متن جدید"): ویرایش متن پیام فعلیawait ctx.delete(): حذف پیام جاریawait ctx.answer_callback("متن"): پاپآپ روی دکمهawait ctx.set_state("مرحله"): تغییر وضعیت FSMawait ctx.clear_state(): ریست کردن وضعیت FSM
زیباسازی و استایل متنها (HTML Formatting)
استفاده از تگهای استاندارد برای فرمتدهی متون
برای بولد، ایتالیک، هایلایت کردن کد و افزودن لینک به متن پیامها، از تگهای HTML پشتیبانیشده تلگرام استفاده کنید:
@bot.command("format")
async def send_formatted_text(ctx: NotoContext):
styled_message = (
"<b>✨ متن بولد و پررنگ</b>\n"
"<i>🍃 متن کج (ایتالیک)</i>\n"
"<code>print('کد تکخطی')</code>\n"
"<pre>def my_func():\n return 'بلوک کد چندخطی'</pre>\n"
"<a href='https://telegram.org'>🔗 مشاهده وبسایت تلگرام</a>"
)
await ctx.reply(styled_message, parse_mode="HTML")
انواع دکوراتورها و فیلترهای پیام
مدیریت دستورات، فیلترهای متنی و کلیک دکمهها
# ۱. دستورات اسلشدار
@bot.command("rules")
async def show_rules(ctx: NotoContext):
await ctx.reply("📜 قوانین ربات:\n۱. عدم ارسال محتوای اسپم\n۲. احترام به اعضا")
# ۲. فیلتر کردن کلمات با رجکس (Regex)
@bot.message(pattern=r"^قیمت")
async def price_query(ctx: NotoContext):
await ctx.reply("💵 آخرین تعرفه سرویسها:\nاشتراک یکماهه: ۵۰ هزار تومان")
# ۳. مدیریت رویداد کلیک دکمههای شیشهای
@bot.callback("confirm_order")
async def on_confirm(ctx: NotoContext):
await ctx.answer_callback("سفارش شما تایید شد! ✅")
await ctx.edit("✅ فاکتور شما تسویه و ثبت نهایی گردید.")
ماشین وضعیت و فرمهای مرحلهای (FSM)
دریافت گامبهگام اطلاعات با ذخیرهسازی حافظهای
وقتی میخواهید از کاربر در چند مرحله اطلاعات بگیرید (مثل ثبتنام یا سفارش)، ربات باید بداند کاربر هماکنون در چه مرحلهای قرار دارد:
# مرحله ۱: شروع ثبتنام و تغییر وضعیت به WAITING_FOR_NAME
@bot.command("register")
async def step_one(ctx: NotoContext):
await ctx.set_state("WAITING_FOR_NAME")
await ctx.reply("👤 لطفاً نام و نام خانوادگی خود را ارسال کنید:")
# مرحله ۲: دریافت نام و بردن به مرحله دریافت سن
@bot.message(state="WAITING_FOR_NAME")
async def step_two(ctx: NotoContext):
name = ctx.text
await ctx.set_data("full_name", name) # ذخیره موقت در حافظه ربات
await ctx.set_state("WAITING_FOR_AGE")
await ctx.reply(f"ممنون {name}! حالا سن خود را به عدد بفرستید:")
# مرحله ۳: دریافت سن و ثبت نهایی
@bot.message(state="WAITING_FOR_AGE")
async def step_three(ctx: NotoContext):
age = ctx.text
name = await ctx.get_data("full_name") # بازیابی اطلاعات از مرحله قبل
await ctx.clear_state() # ریست و پاکسازی وضعیت کاربر
await ctx.reply(f"🎉 ثبتنام تکمیل شد!\n👤 نام: {name}\n🎂 سن: {age}")
ارسال عکس، اسناد و فایلهای مالتیمدیا
ارسال تصویر با لینک مستقیم یا فایل سیستمی
@bot.command("send_photo")
async def send_image_example(ctx: NotoContext):
# ارسال عکس با استفاده از لینک مستقیم یا فایل لوکال
photo_url = "https://picsum.photos/600/400"
await ctx.app.bot.send_photo(
chat_id=ctx.chat_id,
photo=photo_url,
caption="📸 این یک تصویر تستی ارسالشده با LazyNoto است!"
)
سیستم تابآوری و ضد کرش هوشمند (Rate Limit)
مدیریت خودکار خطاهای شبکه و ریتلیمیت تلگرام
اگر تعداد زیادی پیام در یک ثانیه بفرستید، تلگرام خطای RetryAfter صادر میکند. LazyNoto به طور هوشمند این ارورها را شناسایی کرده و برنامه را دقیقاً به اندازه ثانیههای اعلامشده به حالت خواب (Sleep) میبرد تا ربات بدون کرش یا افت سرعت به کار خود ادامه دهد.
پروژه کامل عملی: سامانه تیکتینگ و پیام به ادمین
ترکیب منوی شیشهای، FSM و فوروارد هوشمند پیام
این سورسکد کامل، نحوه ترکیب منوی شیشهای، تغییر مرحله (FSM) و فوروارد پیام به ادمین را نشان میدهد:
from lazynoto import LazyNoto, NotoContext, InlineMenu
# تنظیم آیدی ادمین و توکن
ADMIN_ID = 123456789
bot = LazyNoto(token="YOUR_BOT_TOKEN", admin_ids=[ADMIN_ID])
@bot.command("start")
async def start_cmd(ctx: NotoContext):
menu = (
InlineMenu()
.button("📩 ارسال تیکت به پشتیبانی", callback_data="ticket_start")
.button("ℹ️ درباره ربات", callback_data="about_us")
.build()
)
await ctx.reply(f"سلام {ctx.user.first_name}! خوش آمدید. گزینهای را انتخاب کنید:", reply_markup=menu)
@bot.callback("about_us")
async def about_us_cmd(ctx: NotoContext):
await ctx.answer_callback()
await ctx.reply("🤖 توسعه داده شده با فریمورک قدرتمند LazyNoto.")
@bot.callback("ticket_start")
async def ticket_ask(ctx: NotoContext):
await ctx.set_state("SENDING_TICKET")
await ctx.edit("✍️ لطفاً پیام، انتقاد یا مشکل خود را به صورت متن بفرستید:")
@bot.message(state="SENDING_TICKET")
async def ticket_forward(ctx: NotoContext):
sender = ctx.user
message_text = ctx.text
# فوروارد پیام برای ادمین ربات
await ctx.app.bot.send_message(
chat_id=ADMIN_ID,
text=f"🚨 تیکت جدید از طرف @{sender.username} (آیدی: {sender.id}):\n\n{message_text}",
parse_mode="HTML"
)
# ریست کردن وضعیت کاربر
await ctx.clear_state()
await ctx.reply("✅ پیام شما با موفقیت برای مدیریت ارسال شد. به زودی بررسی خواهد شد.")
if __name__ == "__main__":
bot.run()