أهلاً بك مجدداً!
في الدرس السابق، استكشفنا الجانب النظري من عملية "الاستماع" وتعرفنا على مفهوم الـ Webhooks. تعلمنا أنها آلية "دفع" تُعلم تطبيقنا بوقوع حدث ما (مثل وصول رسالة واتساب) عن طريق إرسال طلب HTTP POST إلى عنوان URL نحدده. لقد فهمنا لماذا نحتاج إليها وكيف تعمل من حيث المبدأ.
اليوم، سنحول هذه النظرية إلى واقع. سنقوم ببناء عنوان URL هذا بأنفسنا. هدفنا في هذا الدرس هو بناء نقطة نهاية (Endpoint) بسيطة باستخدام لغة بايثون لاستقبال الرسائل الواردة من واتساب. سنكتب الكود الذي سيسمح لوكيلنا بـ "الاستماع" حقًا، مما يكمل الحلقة الأساسية للمحادثة.
1. كيف يستمع تطبيقنا للإنترنت؟ مقدمة إلى خوادم الويب
تطبيق البايثون الذي نكتبه يعمل على جهاز الكمبيوتر الخاص بك. كيف يمكن لخدمة خارجية مثل Twilio، الموجودة على الإنترنت، أن تتواصل معه؟ الحل هو تحويل جزء من تطبيقنا إلى خادم ويب (Web Server).
- خادم الويب: هو برنامج متخصص وظيفته الاستماع باستمرار للطلبات القادمة من الإنترنت عبر بروتوكول HTTP. عندما يستقبل طلبًا موجهًا إلى عنوان معين (URL)، فإنه يقوم بتنفيذ كود مرتبط بهذا العنوان ثم يرسل استجابة.
بناء خادم ويب من الصفر أمر معقد. لحسن الحظ، توجد أطر عمل ويب (Web Frameworks) تسهل هذه المهمة بشكل كبير. في عالم بايثون، أحد أشهر وأبسط هذه الأطر هو Flask.
إطار عمل Flask يوفر لنا الأدوات اللازمة لإنشاء خادم ويب ببضعة أسطر من الكود، مما يسمح لنا بالتركيز على منطق التطبيق بدلاً من تعقيدات بروتوكول HTTP.
2. بناء أول خادم ويب باستخدام Flask
لنبنِ الآن خادمنا الصغير الذي سيستقبل إشعارات الـ Webhook.
الخطوة الأولى: تثبيت Flask
افتح الطرفية (Terminal) أو موجه الأوامر (Command Prompt) وقم بتثبيت مكتبة Flask باستخدام pip، تمامًا كما فعلنا مع المكتبات السابقة:
pip install Flask
الخطوة الثانية: كتابة كود الخادم
الآن، أنشئ ملف بايثون جديد (مثلاً app.py) واكتب فيه الكود التالي. سأشرح كل سطر بالتفصيل.
# 1. استيراد الأدوات اللازمة من مكتبة Flask
from flask import Flask, request
# 2. إنشاء نسخة من تطبيق الويب
app = Flask(__name__)
# 3. تحديد المسار (Route) ونوع الطلب للـ Webhook
@app.route('/webhook', methods=['POST'])
def receive_webhook():
# 4. هذه الدالة ستعمل عند وصول طلب POST إلى عنوان /webhook
print("تم استقبال Webhook!")
# 5. قراءة البيانات الواردة من Twilio واستخراجها
# Twilio ترسل البيانات بتنسيق form-data، وFlask يقرأها عبر request.form
message_body = request.form.get('Body')
sender_id = request.form.get('From')
print(f"الرسالة من {sender_id}: {message_body}")
# 6. إرسال استجابة لتأكيد الاستلام
return 'OK', 200
# 7. تشغيل الخادم عند تنفيذ الملف مباشرة
if __name__ == '__main__':
# debug=True يجعل الخادم يعيد التشغيل تلقائيًا عند تعديل الكود
app.run(debug=True)
شرح الكود:
from flask import Flask, request: نستوردFlaskلإنشاء التطبيق، وrequestللوصول إلى بيانات الطلب الوارد.app = Flask(__name__): ننشئ كائن التطبيق الرئيسي.@app.route('/webhook', methods=['POST']): هذا هو الجزء الأهم. هذا السطر، المسمى "Decorator"، يخبر Flask بأن الدالة التالية (receive_webhook) يجب أن تُنفذ فقط عند وصول طلب من نوعPOSTإلى المسار/webhook. هذا المسار هو ما يُعرف بـ نقطة النهاية (Endpoint).def receive_webhook():: الدالة التي تحتوي على المنطق الذي نريد تنفيذه عند استقبال الـ Webhook.request.form.get('...'): في الدرس السابق، رأينا مثالاً لحمولة (Payload) الـ Webhook. كائنrequestيحتوي على كل معلومات الطلب. بما أن Twilio ترسل البيانات بتنسيقform-data، نستخدمrequest.formللوصول إليها.get('Body')تستخرج نص الرسالة، وget('From')تستخرج رقم المرسل.return 'OK', 200: من الضروري أن يرد خادمنا على Twilio لتأكيد أنه استلم الإشعار بنجاح.200هو رمز حالة HTTP ويعني "OK". إذا لم نرسل هذه الاستجابة، ستعتقد Twilio أن الإشعار فشل وستحاول إرساله مرة أخرى.app.run(debug=True): هذا السطر يقوم بتشغيل خادم الويب المحلي على جهازك.
3. مشكلة "localhost" والحل باستخدام ngrok
إذا قمت الآن بتشغيل الملف (python app.py)، سترى رسالة تفيد بأن الخادم يعمل على عنوان مثل http://127.0.0.1:5000. هذا العنوان يُعرف بـ localhost، وهو يعني "هذا الكمبيوتر". المشكلة هي أن هذا العنوان خاص بجهازك فقط. خوادم Twilio الموجودة على الإنترنت لا يمكنها الوصول إليه.
إذًا، كيف نجعل خادمنا المحلي متاحًا للإنترنت بشكل مؤقت وآمن لأغراض الاختبار؟
الحل هو أداة تسمى ngrok.
ngrok هو برنامج يقوم بإنشاء "نفق" آمن بين عنوان URL عام على الإنترنت وخادم الويب الذي يعمل على جهازك المحلي. عندما ترسل Twilio إشعارًا إلى عنوان ngrok العام، يقوم ngrok بتوجيهه عبر هذا النفق مباشرة إلى تطبيق Flask الخاص بك.
خطوات استخدام ngrok:
-
قم بتنزيل
ngrokمن موقعه الرسمي واتبع تعليمات التثبيت البسيطة. -
في نافذة طرفية (Terminal)، قم بتشغيل خادم Flask الخاص بك:
python app.py. -
في نافذة طرفية أخرى، اكتب الأمر التالي لتوجيه
ngrokإلى المنفذ الذي يعمل عليه خادم Flask (المنفذ الافتراضي هو 5000):ngrok http 5000 -
سيقوم
ngrokبعرض شاشة تحتوي على معلومات، وأهمها هو عنوان URL العام تحت قسم "Forwarding". سيبدو شيئًا كهذا:https://<سلسلة-عشوائية>.ngrok-free.app.

4. ربط كل شيء معًا
الآن لدينا كل القطع اللازمة. لنجمعها:
- خادم Flask يعمل: تأكد من أن ملف
app.pyيعمل في نافذة طرفية. - نفق
ngrokمفتوح: تأكد من أنngrokيعمل في نافذة طرفية أخرى. - احصل على عنوان الـ Webhook الكامل: انسخ عنوان
ngrokالعام وأضف إليه نقطة النهاية التي حددناها في الكود (/webhook). العنوان النهائي سيكون:https://<سلسلة-عشوائية>.ngrok-free.app/webhook. - تحديث إعدادات Twilio: اذهب إلى لوحة تحكم Twilio، ثم إلى إعدادات رقم واتساب الخاص بك. ابحث عن قسم "Messaging" أو "Webhook for incoming messages" والصق عنوان URL الكامل الذي أنشأته في الخطوة السابقة. تأكد من أن طريقة الطلب (Method) محددة إلى
HTTP POST. - أرسل رسالة اختبار: من هاتفك الشخصي، أرسل رسالة واتساب إلى رقمك في Twilio.
إذا سار كل شيء على ما يرام، يجب أن ترى في نافذة الطرفية التي يعمل بها خادم Flask مخرجات تبدو كالتالي:
تم استقبال Webhook!
الرسالة من whatsapp:+966501234567: مرحباً، هل المنتج متوفر؟
لقد نجحت! تطبيقك الآن "يستمع" إلى رسائل واتساب الواردة في الوقت الفعلي.
اختبر فهمك!
ماذا سيحدث لو قمت بتغيير السطر @app.route('/webhook', methods=['POST']) إلى @app.route('/whatsapp', methods=['POST']) في الكود، دون تغيير عنوان URL في إعدادات Twilio؟
Show answer
سيتوقف الـ Webhook عن العمل. سترسل Twilio طلبها إلى .../webhook، لكن خادم Flask الخاص بك لم يعد يستمع على هذا المسار. إنه الآن يستمع فقط على .../whatsapp. سيؤدي هذا إلى خطأ 404 Not Found، وستعتقد Twilio أن الإشعار فشل في الوصول. يجب أن يتطابق المسار في الكود تمامًا مع المسار المحدد في عنوان URL الذي تم إعداده في الخدمة الخارجية.
خلاصة الدرس
في هذا الدرس، قمنا بخطوة عملية هائلة. لنلخص ما أنجزناه:
- بنينا خادم ويب: تعلمنا كيفية استخدام إطار عمل Flask لإنشاء خادم ويب بسيط في بايثون.
- أنشأنا نقطة نهاية (Endpoint): حددنا مسارًا (
/webhook) مخصصًا لاستقبال طلباتPOSTمن Twilio. - حللنا مشكلة
localhost: فهمنا لماذا لا يمكن الوصول إلى الخوادم المحلية من الإنترنت واستخدمنا أداةngrokلإنشاء نفق عام آمن. - أكملنا دورة الاتصال: أصبح وكيلنا الآن قادرًا على "التحدث" (من خلال الأداة التي بنيناها سابقًا) و"الاستماع" (من خلال نقطة النهاية التي بنيناها اليوم).
لقد وضعت الأساس التقني لاستقبال البيانات من العالم الخارجي.
ماذا بعد؟
الآن بعد أن أصبح وكيلنا قادرًا على استقبال الرسائل، ما هي الخطوة التالية؟ ما الذي يجب أن يفعله بالرسالة التي استقبلها؟ هذا هو المكان الذي يبدأ فيه الذكاء الحقيقي للوكيل. في الدرس القادم، سننتقل من البنية التحتية إلى المنطق، حيث سنقوم بـ تصميم مخطط تدفق لمحادثة وكيل مبيعات بسيط عبر واتساب. سنبدأ في التخطيط لكيفية سير المحادثة والقرارات التي سيتخذها وكيلنا.