۰۳ اتوماسیون

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

رباتی که به سؤال مشتری‌ها جواب می‌دهد — قیمت، موجودی، سایز و رنگ — حتی وقتی اسم محصول را اشتباه می‌نویسند. بدون هوش مصنوعی پولی و بدون هزینه‌ی ماهانه.

PythonSQLiteFlaskdifflib

مشکل چه بود؟

صاحب یک فروشگاه کوچک، روزی ده‌ها بار به یک سؤال جواب می‌دهد: «سبد رخت چند؟»، «آبکش موجوده؟»، «چه رنگایی دارین؟»، «چطور سفارش بدم؟»

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

چی ساختم؟

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

محصولات هم با چت کردن اضافه می‌شوند — بدون پنل مدیریت، بدون فرم، بدون اپلیکیشن دوم.

چطور کار می‌کند؟

پ ربات فروشگاه
آنلاین · معمولاً فوری جواب می‌دهد
ابکش چند؟
آبکش بزرگ ۹۵٬۰۰۰ تومان موجودی: ۱۲ عدد سایز: ۲۸ سانتی‌متر
سبت رخت هم دارین؟
منظورتون کدوم بود؟ سبد رخت سبد خرید
سبد رخت ۱۸۵٬۰۰۰ تومان تنها ۴ عدد مانده
قابلمه دارید؟
متأسفم، این محصول را پیدا نکردم. 🤔

این خروجی واقعی ربات است، نه یک نمایش ساختگی.

چطور «باهوش» است، بدون هوش مصنوعی؟

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

۱. یکسان‌سازی متن فارسی

بیشترین کار را همین لایه انجام می‌دهد. یک کلمه به ده شکل تایپ می‌شود:

مشتری می‌نویسدچرا فرق دارد
آبکشدرست
آبكشکاف عربی
ابکشبدون مد
آب‌کشبا نیم‌فاصله
آبکـشبا کشیدگی
آبَکِشبا اعراب

هر شش‌تا به یک رشته‌ی واحد تبدیل می‌شوند.

۲. تشخیص موضوع سؤال

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

۳. حذف کلمات سؤالی

«قیمت سبد رخت چنده» → فقط «سبد رخت» می‌ماند. ولی ارقام و واحدها حذف نمی‌شوند: «۱۲ لیتری» تنها چیزی است که «سطل زباله پدالی ۱۲ لیتری» را از «سطل زباله آشپزخانه ۲۰ لیتری» جدا می‌کند. این یکی را از روی داده‌ی واقعی فهمیدم — اول ارقام را حذف می‌کردم و ربات مجبور بود هر بار بپرسد کدام سطل.

۴. پیدا کردن محصول

دقیق → مترادف → داخل جمله → و در آخر difflib برای غلط املایی. difflib داخل خود پایتون است؛ نه نصبی می‌خواهد، نه هزینه‌ای.

مهم‌ترین قانون

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

پنل فروشنده

هر پیامی که به ربات می‌رسد در دیتابیس ثبت می‌شود — چه ربات فهمیده باشد، چه نه. پنل از روی همین‌ها نشان می‌دهد:

  • پیام امروز، کل پیام‌ها، محصولات، کم‌موجودی و ناموجود
  • بیشترین سؤال‌ها — مردم دنبال چه چیزی هستند
  • سؤال‌هایی که ربات نفهمید — مفیدترین جدول پنل
  • آخرین پیام‌ها، با چیزی که ربات از هرکدام فهمیده

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

یک تابع، دو خروجی

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

آن تابع عمداً هیچ وابستگی‌ای ندارد — نه Flask، نه Jinja — تا نسخه‌ی ثابت روی کامپیوتری که هیچ‌چیز نصب ندارد هم ساخته شود. پنل را اینجا ببینید ←

تست، بدون توکن ربات

همه‌ی منطق در دو فایل است که هیچ‌کدام چیزی درباره‌ی تلگرام نمی‌دانند. پوشه‌ی handlers/ فقط سیم‌کشی است. نتیجه‌اش این است که ۳۶ تست بدون هیچ توکنی اجرا می‌شوند.

همین تست‌ها چهار باگ واقعی را پیدا کردند:

  1. مترادف‌های چندکلمه‌ای («سطل آشغال») هیچ‌وقت پیدا نمی‌شدند
  2. «سلام» به تنهایی با «سطل» جور می‌شد و جواب محصول می‌گرفت
  3. ارقام و واحدها حذف می‌شدند و دو سطل مختلف یکی می‌شدند
  4. «چطور سفارش بدم؟» با لیست سبدها جواب داده می‌شد — «بدم» به «سبد» شبیه بود

با چه ابزارهایی

پایتون، SQLite (داخل خود پایتون)، difflib (داخل خود پایتون)، python-telegram-bot و Flask برای پنل زنده. همه‌ی SQL در یک فایل است و هیچ فایل دیگری کوئری نمی‌زند.

نتیجه

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

پروژه‌ای دارید؟

اگر کاری شبیه این لازم دارید، خوشحال می‌شم دربارش حرف بزنیم.