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

 

درباره‌ی SDK #

از آن‌جایی که فرایند تعامل با سرور لیمو نیاز به I/O زیادی دارد، SDk پایتون به صورت event driven و با استفاده از ماژول استاندارد asyncio نوشته‌شده‌است. استفاده از پارادایم event driven باعث حفظ سرعت و عملکرد بات و در عین حال کاهش منابع مورد استفاده در مقایسه با پارادایم thread based concurrency به خصوص در زبان پایتون می‌شود. همچنین ماژول asyncio ساختار ساده و منعطفی دارد و اکثر چارچوب‌های توسعه‌ی سرور نیز به نوعی از ماژول asyncio و پکیج‌های مبتنی بر آن پشتیبانی می‌کنند که این امر استفاده از SDK پایتون همراه با آن چارچوب‌ها را آسان‌تر می‌کند.

برای استفاده از SDK‌ نیاز به پایتون ۳.۷ است. مخزن کد SDK در GitHub قرار دارد و برای نصب آن می‌توانید از دستور زیر استفاده کنید:

pip install limoo-sdk

 

بات اکو #

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

import asyncio

from limoo import LimooDriver

async def respond(event):
   if (event['event'] == 'message_created'
       and not (event['data']['message']['type']
                or event['data']['message']['user_id'] == self['id'])):
       message_id = event['data']['message']['id']
       thread_root_id = event['data']['message']['thread_root_id']
       direct_reply_message_id = event['data']['message']['thread_root_id'] and event['data']['message']['id']
       response = await ld.messages.create(
          event['data']['workspace_id'],
          event['data']['message']['conversation_id'],
          event['data']['message']['text'],
          thread_root_id=thread_root_id or message_id,
          direct_reply_message_id=thread_root_id and message_id)

async def main():
   global ld, self
   ld = LimooDriver('web.limoo.im', 'botusername', 'botpassword')
   try:
       self = await ld.users.get()
       forever = asyncio.get_running_loop().create_future()
       ld.set_event_handler(lambda event: asyncio.create_task(respond(event)))
       await forever
   finally:
       await ld.close()

asyncio.run(main())

 

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

درایور لیمو #

کلاس LimooDriver رابط بین کد برنامه و سرور لیمو است. برای نمونه‌گیری (instantiation) از کلاس LimooDriver باید آدرس سرور لیمو (مثلا web.limoo.im برای نسخه‌ی عمومی لیمو) و نام کاربری و رمز عبور بات (در ادامه درباره‌ی به دست آوردن این اطلاعات توضیح خواهم داد) را به عنوان آرگومان بفرستید. پس از نمونه‌گیری، برنامه متود LimooDriver.users.get را بدون دادن هیچ آرگومانی فراخوانی می‌کند. این کار باعث می‌شود تا این متود، اطلاعات کاربر بات را به عنوان خروجی برگرداند. این اطلاعات بعدا برای پاسخ‌گویی به پیام‌ها کاربرد خواهد داشت. در خط ۲۴ برنامه درخواست می‌کند تا در زمان دریافت رویدادها از سرور، یک asyncio.Task ساخته شود که در آن تابع respond فراخوانی می‌شود و رویداد دریافتی در ورودی می‌گیرد. علت ساختن asyncio.Task برای فراخوانی تابع respond این است که تابع respond یک coroutine است در حالی که ورودی متود LimooDriver.set_event_handler باید یک تابع معمولی باشد.

جواب دادن به پیام‌ها #

تابع respond با هر بار دریافت رویداد جدید فراخوانی می‌شود و اطلاعات رویداد را به عنوان پارامتر ورودی دریافت می‌کند. LimooDriver برای سادگی همان اطلاعات رویدادی را که از سرور به صورت JSON دریافت کرده به یک dict پایتون تبدیل می‌کند و در اختیار برنامه قرار می‌دهد. تابع respond با بررسی محتوای این dict سعی می‌کند بفهمد که آیا رویداد مربوط به ایجاد پیام است. اگر چنین باشد، برنامه باید مطمئن شود که پیام از نوع پیام‌های سیستمی (پیام‌هایی شبیه به «کاربری به گروه اضافه شد» که توسط خود سرور لیمو ایجاد می‌شوند) نیست: فیلد type پیام‌های غیر سیستمی مقدار null دارد. همچنین پیام‌هایی که شناسه‌ی فرستنده‌ی آن‌ها با شناسه‌ی کاربر بات یکسان است، از طرف خود بات فرستاده شده‌اند و نباید به آن‌ها پاسخی بدهیم.

برای این که پاسخ بات در همان رشته‌ی پیام دریافتی، ارسال شود باید فیلد thread_root_id و یا در صورت null بودن آن فیلد message.id به عنوان thread_root_id پیام ارسالی استفاده شود. همچنین برای این که پیام بات به عنوان پاسخ پیام دریافتی در نظر گرفته‌شود، باید در صورت null نبودن فیلد thread_root_id، مقدار فیلد message.id به عنوان direct_reply_message_id پیام ارسالی در نظر گرفته شود.

ایجاد کاربر بات #

همانطور که قبلا اشاره شد، این بات برای اتصال به سرور نیاز به نام کاربری و کلمه‌ی عبور و در واقع یک حساب کاربری است. برای ساختن کاربر بات از دستور «ساخت-بات»‌ استفاده می‌کنیم. این دستور توسط مدیر (ادمین) فضای کاری در پیام شخصی‌اش با «لیموبات» استفاده می‌شود. پارامترهای این دستور نام کاربری بات و نام نمایشی آن هستند. قالب استفاده از این دستور به این صورت است:

‍‍‍‍‍‍/ساخت-بات نام-کاربری-بات نام-نمایشی-بات

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

ایجاد کاربر بات

 

بات در حال اجرا #

در تصویر زیر نمونه‌ای از نحوه‌ی تعامل یک کاربر معمولی با بات را در فضای لیمو مشاهده می‌شود:

بات در حال اجرا

 

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

ورود به لیمو