كيفية إنشاء روبوت WhatsApp لقوائم المهام باستخدام Bird’s Programmable Conversations API
Bird
05/02/2020
واتساب
1 min read

النقاط الرئيسية
Bird’s Programmable Conversations API يوحّد WhatsApp وMessenger وSMS في طبقة اتصال واحدة، مما يبسط تطوير الروبوتات متعددة القنوات.
يمكنك بسرعة تصميم نموذج أولي لروبوت قائمة مهام WhatsApp باستخدام webhooks وطلبات POST بسيطة.
تتيح لك الأدوات مثل ngrok عرض الخادم المحلي الخاص بك لاختبار webhooks دون إعداد استضافة معقد.
تتعامل واجهة برمجة التطبيقات مع المحادثات عبر قنوات متعددة، مما يسمح بقاعدة منطق واحدة لـ WhatsApp وWeChat وتطبيقات أخرى.
استخدم نقطة النهاية archiveConversation لإغلاق المحادثات أو "المواضيع"، مما يعتبر مثالياً لدعم أو تتبع سير العمل.
يمكن للمنطق الروبوتي إدارة المحادثات المتزامنة بأمان في الذاكرة مع بنية بيانات بسيطة.
يعمل نفس معالج webhook عبر القنوات—Bird يقوم بتوجيه الردود بناءً على معرف المحادثة الأصلية تلقائياً.
أبرز الأسئلة والأجوبة
ما مدى صعوبة بناء روبوت WhatsApp باستخدام واجهة برمجة التطبيقات الخاصة بـ Bird؟
إنه سهل بشكل مفاجئ. باستخدام webhook وعدد قليل من مكالمات API، يمكنك بناء بوت وظيفي يقرأ الرسائل ويرد عليها في غضون دقائق.
هل أحتاج إلى إعداد خاص لتلقي الرسائل؟
نعم — يجب أن يكون الروبوت قادرًا على الوصول من الإنترنت. تساعد أدوات مثل ngrok في إنشاء نفق آمن من جهازك المحلي.
هل يمكنني استخدام نفس قاعدة الشيفرة لتطبيقات المراسلة المختلفة؟
بالتأكيد. تقوم واجهة برمجة تطبيقات المحادثات بتجريد القنوات، بحيث يمكن لروبوتك العمل على WhatsApp أو WeChat أو Messenger بنفس المنطق.
كيف يمكنني إغلاق أو إعادة تعيين سلسلة المحادثة؟
أرسل طلب PATCH إلى نقطة نهاية المحادثة بالحالة المناسبة لأرشفتها. أي رسالة جديدة تفتح محادثة جديدة تلقائيًا.
أين يمكنني العثور على مثال للكود؟
ج: العرض التوضيحي الكامل العامل — Wabot على GitHub — يظهر تنفيذ التعامل مع الرسائل، التزامن، والأرشفة.
أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. إنها تتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتها باستخدام واجهة برمجة تطبيقات واحدة.
أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. تتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتهم - باستخدام واجهة API واحدة.
أردت تجربة ذلك، لذلك قمت ببناء روبوت قائمة المهام على WhatsApp، لأنه من لا يحتاج إلى قائمة مهام آلية لمساعدته في تنظيم يومه؟ قد يبدو الأمر معقدًا، لكنه كان في الواقع سهلًا، وأود أن أخبركم بكل شيء عنه.
الآن، أعمل في MessageBird، لذلك كان بإمكاني الانخراط وبدء البناء مباشرة. إذا كنتم تجربون هذا، فستحتاجون إلى طلب الوصول المبكر. ولكن بمجرد إعدادك لقناة WhatsApp، يمكنك تسجيل الدخول إلى لوحة التحكم على موقع MessageBird والبدء.
أول شيء فعلته هو قراءة الوثائق. تعلمت أنه للحصول على الرسائل من الروبوت، سيتعين علي استخدام webhook. هذا يعني أن روبوتي سيحتاج إلى أن يكون متاحاً عبر الإنترنت. عندما تبني واجهات API مثل هذه، من المهم اتباع أفضل ممارسات إصدار API للصيانة. نظرًا لأني كنت قد بدأت في كتابة الكود، قررت استخدام ngrok. إنه ينشئ نفقاً من الإنترنت العام إلى منفذ localhost الخاص بك 5007. تابع الانخراط!
ngrok http 5007 -region eu -subdomain todobot
بعد ذلك، احتجت إلى إجراء اتصال بواجهة API الخاصة بالمحادثات القابلة للبرمجة لإنشاء الويب هوك. إنه طلب POST إلى https://conversations.messagebird.com/v1/webhooks ويبدو شيئاً كهذا:
func main() {// define the webhook json payload wh := struct { Events []string `json:"events"` ChannelID string `json:"channelId"` URL string `json:"url"` } { // we would like to be notified on the URL URL: "https://todobot.eu.ngrok.io/create-hook", // whenever a message gets created Events: []string{"message.created"}, // on the WhatsApp channel with ID ChannelID: "23a780701b8849f7b974d8620a89a279", } // encode the payload to json var b bytes.Buffer err := json.NewEncoder(&b).Encode(&wh) if err != nil { panic(err) } // create the http request and set authorization header req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json") // fire the http request client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close()// is everything ok? body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode >= http.StatusBadRequest { panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body))) } else { log.Println("All good. response body: ", string(body)) } }
رائع. الآن ستقوم Conversations API بإجراء طلب POST إلى:
https://todobot.eu.ngrok.io/create-hook كلما تم إنشاء رسالة جديدة على قناة WhatsApp التي قمت بإعدادها سابقًا.
هذا ما يبدو عليه payload الخاص بالويب هوك:
{ "conversation":{ "id":"55c66895c22a40e39a8e6bd321ec192e", "contactId":"db4dd5087fb343738e968a323f640576", "status":"active", "createdDatetime":"2018-08-17T10:14:14Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z", "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z" }, "message":{ "id":"ddb150149e2c4036a48f581544e22cfe", "conversationId":"55c66895c22a40e39a8e6bd321ec192e", "channelId":"23a780701b8849f7b974d8620a89a279", "status":"received", "type":"text", "direction":"received", "content":{ "text":"add buy milk" }, "createdDatetime":"2018-08-17T14:30:31.898389294Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z" }, "type":"message.created" }
نريد الرد على تلك الرسائل. دعنا نبدأ بتكرارها، ما رأيك؟
// define the structs where we'll parse the webhook payload into type whPayload struct { Conversation conversation `json:"conversation"` Message message `json:"message"` Type string `json:"type"` } type message struct { ID string `json:"id"` Direction string `json:"direction"` Type string `json:"type"` Content content `json:"content"` } type content struct { Text string `json:"text"` } type conversation struct { ID string `json:"id"` } func main() { http.HandleFunc("/create-hook", createHookHandler) log.Fatal(http.ListenAndServe(*httpListenAddress, nil)) } // createHookHandler is an http handler that will handle webhook requests func createHookHandler(w http.ResponseWriter, r *http.Request) { // parse the incoming json payload whp := &whPayload{} err := json.NewDecoder(r.Body).Decode(whp) if err != nil { log.Println("Err: got weird body on the webhook") w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error") return } if whp.Message.Direction != "received" { // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those. fmt.Fprintf(w, "ok") return } // echo: respond what we get err = respond(whp.Conversation.ID, whp.Message.Content.Text) if err != nil { log.Println("Err: ", err) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error")return } w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "ok") }
الآن، للجزء المثير للاهتمام. قم بإجراء طلب POST إلى:
https://conversations.messagebird.com/v1/conversations/<conversationID>/messages للرد على الطلب.
func respond(conversationID, responseBody string) error { u := fmt.Sprintf("https://conversations.messagebird.com/v1/conversations/%s/messages", conversationID)msg := message{ Content: content{ Text: responseBody, }, Type: "text", } var b bytes.Buffer err := json.NewEncoder(&b).Encode(&msg) if err != nil { return fmt.Errorf("Error encoding buffer: %v", err) } req, err := http.NewRequest("POST", u.String(), &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json")client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode != http.StatusCreated { return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body)) } log.Println("All good. Response body: ", string(body)) return nil }
هناك. هذا كل ما تحتاجه لإنشاء روبوت يتصرف مثل إنسان في الخامسة من العمر.
الآن، دعنا نخطو خطوة نحو بناء قائمة المهام الكاملة. أولاً، قم بتعديل وظيفة createHookHandler قليلاً بحيث تستدعى الوظيفة الجديدة handleMessage بدلاً من respond.
func createHookHandler(w http.ResponseWriter, r *http.Request) { ... err = handleMessage(whp) ... }
handle سيقوم بشكل بسيط بتحليل الرسائل، والقيام ببعض العمل، واختيار الرد. دعنا ننظر إلى أمر "add":
func handleMessage(whp *whPayload) error { // every conversation has a todo list list := manager.fetch(whp.Conversation.ID) // parse the command from the message body: it's the first word text := whp.Message.Content.Text text = regexp.MustCompile(" +").ReplaceAllString(text, " ") parts := strings.Split(text, " ") command := strings.ToLower(parts[0]) // default message responseBody := "I don't understand. Type 'help' to get help." switch command { ... case "add": if len(parts) < 2 { return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.") } // get the item from the message body item := strings.Join(parts[1:], " ")list.add(item) responseBody = "added." ... return respond(whp.Conversation.ID, responseBody) }
هنا، نقوم بإعداد: list := manager.fetch(whp.Conversation.ID). ببساطة، "المدير" هو خريطة آمنة للتزامن تربط معرفات المحادثات بقوائم المهام.
قائمة المهام عبارة عن شريحة سلسلة آمنة للتزامن. كل ذلك في الذاكرة!
شيء مهم آخر! يمكنك أرشفة المحادثات. في بعض التطبيقات، مثل أنظمة إدارة علاقات العملاء، من المهم تتبع بعض التفاعلات - لتتبع فعالية موظفي دعم العملاء، على سبيل المثال. تسمح لك Conversations API بأرشفة المحادثة لإغلاق الموضوع. إذا أرسل المستخدم / العميل رسالة أخرى، ستفتح Conversations API موضوعاً جديداً تلقائيًا.
أيضاً. بإجراء طلب PATCH إلى https://conversations.messagebird.com/v1/conversations/{id} بالحالة المناسبة في الجسم، يمكنك أرشفة المحادثة بهذا المعرف. نقوم بذلك باستخدام الأمر "bye":
case "bye": archiveConversation(whp.Conversation.ID) manager.close(whp.Conversation.ID) responseBody = "bye!"
archiveConversation سيقوم بإجراء طلب PATCH وmanager.close(whp.Conversation.ID) سيقوم بإزالة المحادثة من قائمة المهام.
ولكن مهلاً، Programmable Conversations هي حل متعدد القنوات. ماذا لو كنت تريد إعادة استخدام كود الروبوت لمنصة مختلفة، مثل WeChat؟ هذا النهج المتعدد القنوات هو جزء من استراتيجية تحويل الاستفسارات إلى قنوات أقل تكلفة. كيف ستفعل ذلك؟
فقط قم بإنشاء webhook جديد لاستهداف تلك القناة! webhook يقوم بإرسال الطلبات إلى نفس عنوان الإنترنت https://todobot.eu.ngrok.io/create-hook الذي استخدمناه لـ WhatsApp!
سيعمل هذا لأن كود المعالجة دائمًا يستخدم معرف المحادثة من tải هوك بدلاً من معرف قناة محدد. API MessageBird للمحادثات سوف يحدد القناة للمحادثة لإرسال رسالتك إليها تلقائيًا.
هل تريد إنشاء الروبوت الخاص بك؟ تحقق من الكود الكامل على Github: Wabot على Github، واطلب الوصول المبكر إلى WhatsApp من خلال زيارة صفحة WhatsApp والنقر على زر اتصل بالمبيعات لملء النموذج. بوت سعيد!
أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. تتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتهم - باستخدام واجهة API واحدة.
أردت تجربة ذلك، لذلك قمت ببناء روبوت قائمة المهام على WhatsApp، لأنه من لا يحتاج إلى قائمة مهام آلية لمساعدته في تنظيم يومه؟ قد يبدو الأمر معقدًا، لكنه كان في الواقع سهلًا، وأود أن أخبركم بكل شيء عنه.
الآن، أعمل في MessageBird، لذلك كان بإمكاني الانخراط وبدء البناء مباشرة. إذا كنتم تجربون هذا، فستحتاجون إلى طلب الوصول المبكر. ولكن بمجرد إعدادك لقناة WhatsApp، يمكنك تسجيل الدخول إلى لوحة التحكم على موقع MessageBird والبدء.
أول شيء فعلته هو قراءة الوثائق. تعلمت أنه للحصول على الرسائل من الروبوت، سيتعين علي استخدام webhook. هذا يعني أن روبوتي سيحتاج إلى أن يكون متاحاً عبر الإنترنت. عندما تبني واجهات API مثل هذه، من المهم اتباع أفضل ممارسات إصدار API للصيانة. نظرًا لأني كنت قد بدأت في كتابة الكود، قررت استخدام ngrok. إنه ينشئ نفقاً من الإنترنت العام إلى منفذ localhost الخاص بك 5007. تابع الانخراط!
ngrok http 5007 -region eu -subdomain todobot
بعد ذلك، احتجت إلى إجراء اتصال بواجهة API الخاصة بالمحادثات القابلة للبرمجة لإنشاء الويب هوك. إنه طلب POST إلى https://conversations.messagebird.com/v1/webhooks ويبدو شيئاً كهذا:
func main() {// define the webhook json payload wh := struct { Events []string `json:"events"` ChannelID string `json:"channelId"` URL string `json:"url"` } { // we would like to be notified on the URL URL: "https://todobot.eu.ngrok.io/create-hook", // whenever a message gets created Events: []string{"message.created"}, // on the WhatsApp channel with ID ChannelID: "23a780701b8849f7b974d8620a89a279", } // encode the payload to json var b bytes.Buffer err := json.NewEncoder(&b).Encode(&wh) if err != nil { panic(err) } // create the http request and set authorization header req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json") // fire the http request client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close()// is everything ok? body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode >= http.StatusBadRequest { panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body))) } else { log.Println("All good. response body: ", string(body)) } }
رائع. الآن ستقوم Conversations API بإجراء طلب POST إلى:
https://todobot.eu.ngrok.io/create-hook كلما تم إنشاء رسالة جديدة على قناة WhatsApp التي قمت بإعدادها سابقًا.
هذا ما يبدو عليه payload الخاص بالويب هوك:
{ "conversation":{ "id":"55c66895c22a40e39a8e6bd321ec192e", "contactId":"db4dd5087fb343738e968a323f640576", "status":"active", "createdDatetime":"2018-08-17T10:14:14Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z", "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z" }, "message":{ "id":"ddb150149e2c4036a48f581544e22cfe", "conversationId":"55c66895c22a40e39a8e6bd321ec192e", "channelId":"23a780701b8849f7b974d8620a89a279", "status":"received", "type":"text", "direction":"received", "content":{ "text":"add buy milk" }, "createdDatetime":"2018-08-17T14:30:31.898389294Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z" }, "type":"message.created" }
نريد الرد على تلك الرسائل. دعنا نبدأ بتكرارها، ما رأيك؟
// define the structs where we'll parse the webhook payload into type whPayload struct { Conversation conversation `json:"conversation"` Message message `json:"message"` Type string `json:"type"` } type message struct { ID string `json:"id"` Direction string `json:"direction"` Type string `json:"type"` Content content `json:"content"` } type content struct { Text string `json:"text"` } type conversation struct { ID string `json:"id"` } func main() { http.HandleFunc("/create-hook", createHookHandler) log.Fatal(http.ListenAndServe(*httpListenAddress, nil)) } // createHookHandler is an http handler that will handle webhook requests func createHookHandler(w http.ResponseWriter, r *http.Request) { // parse the incoming json payload whp := &whPayload{} err := json.NewDecoder(r.Body).Decode(whp) if err != nil { log.Println("Err: got weird body on the webhook") w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error") return } if whp.Message.Direction != "received" { // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those. fmt.Fprintf(w, "ok") return } // echo: respond what we get err = respond(whp.Conversation.ID, whp.Message.Content.Text) if err != nil { log.Println("Err: ", err) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error")return } w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "ok") }
الآن، للجزء المثير للاهتمام. قم بإجراء طلب POST إلى:
https://conversations.messagebird.com/v1/conversations/<conversationID>/messages للرد على الطلب.
func respond(conversationID, responseBody string) error { u := fmt.Sprintf("https://conversations.messagebird.com/v1/conversations/%s/messages", conversationID)msg := message{ Content: content{ Text: responseBody, }, Type: "text", } var b bytes.Buffer err := json.NewEncoder(&b).Encode(&msg) if err != nil { return fmt.Errorf("Error encoding buffer: %v", err) } req, err := http.NewRequest("POST", u.String(), &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json")client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode != http.StatusCreated { return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body)) } log.Println("All good. Response body: ", string(body)) return nil }
هناك. هذا كل ما تحتاجه لإنشاء روبوت يتصرف مثل إنسان في الخامسة من العمر.
الآن، دعنا نخطو خطوة نحو بناء قائمة المهام الكاملة. أولاً، قم بتعديل وظيفة createHookHandler قليلاً بحيث تستدعى الوظيفة الجديدة handleMessage بدلاً من respond.
func createHookHandler(w http.ResponseWriter, r *http.Request) { ... err = handleMessage(whp) ... }
handle سيقوم بشكل بسيط بتحليل الرسائل، والقيام ببعض العمل، واختيار الرد. دعنا ننظر إلى أمر "add":
func handleMessage(whp *whPayload) error { // every conversation has a todo list list := manager.fetch(whp.Conversation.ID) // parse the command from the message body: it's the first word text := whp.Message.Content.Text text = regexp.MustCompile(" +").ReplaceAllString(text, " ") parts := strings.Split(text, " ") command := strings.ToLower(parts[0]) // default message responseBody := "I don't understand. Type 'help' to get help." switch command { ... case "add": if len(parts) < 2 { return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.") } // get the item from the message body item := strings.Join(parts[1:], " ")list.add(item) responseBody = "added." ... return respond(whp.Conversation.ID, responseBody) }
هنا، نقوم بإعداد: list := manager.fetch(whp.Conversation.ID). ببساطة، "المدير" هو خريطة آمنة للتزامن تربط معرفات المحادثات بقوائم المهام.
قائمة المهام عبارة عن شريحة سلسلة آمنة للتزامن. كل ذلك في الذاكرة!
شيء مهم آخر! يمكنك أرشفة المحادثات. في بعض التطبيقات، مثل أنظمة إدارة علاقات العملاء، من المهم تتبع بعض التفاعلات - لتتبع فعالية موظفي دعم العملاء، على سبيل المثال. تسمح لك Conversations API بأرشفة المحادثة لإغلاق الموضوع. إذا أرسل المستخدم / العميل رسالة أخرى، ستفتح Conversations API موضوعاً جديداً تلقائيًا.
أيضاً. بإجراء طلب PATCH إلى https://conversations.messagebird.com/v1/conversations/{id} بالحالة المناسبة في الجسم، يمكنك أرشفة المحادثة بهذا المعرف. نقوم بذلك باستخدام الأمر "bye":
case "bye": archiveConversation(whp.Conversation.ID) manager.close(whp.Conversation.ID) responseBody = "bye!"
archiveConversation سيقوم بإجراء طلب PATCH وmanager.close(whp.Conversation.ID) سيقوم بإزالة المحادثة من قائمة المهام.
ولكن مهلاً، Programmable Conversations هي حل متعدد القنوات. ماذا لو كنت تريد إعادة استخدام كود الروبوت لمنصة مختلفة، مثل WeChat؟ هذا النهج المتعدد القنوات هو جزء من استراتيجية تحويل الاستفسارات إلى قنوات أقل تكلفة. كيف ستفعل ذلك؟
فقط قم بإنشاء webhook جديد لاستهداف تلك القناة! webhook يقوم بإرسال الطلبات إلى نفس عنوان الإنترنت https://todobot.eu.ngrok.io/create-hook الذي استخدمناه لـ WhatsApp!
سيعمل هذا لأن كود المعالجة دائمًا يستخدم معرف المحادثة من tải هوك بدلاً من معرف قناة محدد. API MessageBird للمحادثات سوف يحدد القناة للمحادثة لإرسال رسالتك إليها تلقائيًا.
هل تريد إنشاء الروبوت الخاص بك؟ تحقق من الكود الكامل على Github: Wabot على Github، واطلب الوصول المبكر إلى WhatsApp من خلال زيارة صفحة WhatsApp والنقر على زر اتصل بالمبيعات لملء النموذج. بوت سعيد!
أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. تتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتهم - باستخدام واجهة API واحدة.
أردت تجربة ذلك، لذلك قمت ببناء روبوت قائمة المهام على WhatsApp، لأنه من لا يحتاج إلى قائمة مهام آلية لمساعدته في تنظيم يومه؟ قد يبدو الأمر معقدًا، لكنه كان في الواقع سهلًا، وأود أن أخبركم بكل شيء عنه.
الآن، أعمل في MessageBird، لذلك كان بإمكاني الانخراط وبدء البناء مباشرة. إذا كنتم تجربون هذا، فستحتاجون إلى طلب الوصول المبكر. ولكن بمجرد إعدادك لقناة WhatsApp، يمكنك تسجيل الدخول إلى لوحة التحكم على موقع MessageBird والبدء.
أول شيء فعلته هو قراءة الوثائق. تعلمت أنه للحصول على الرسائل من الروبوت، سيتعين علي استخدام webhook. هذا يعني أن روبوتي سيحتاج إلى أن يكون متاحاً عبر الإنترنت. عندما تبني واجهات API مثل هذه، من المهم اتباع أفضل ممارسات إصدار API للصيانة. نظرًا لأني كنت قد بدأت في كتابة الكود، قررت استخدام ngrok. إنه ينشئ نفقاً من الإنترنت العام إلى منفذ localhost الخاص بك 5007. تابع الانخراط!
ngrok http 5007 -region eu -subdomain todobot
بعد ذلك، احتجت إلى إجراء اتصال بواجهة API الخاصة بالمحادثات القابلة للبرمجة لإنشاء الويب هوك. إنه طلب POST إلى https://conversations.messagebird.com/v1/webhooks ويبدو شيئاً كهذا:
func main() {// define the webhook json payload wh := struct { Events []string `json:"events"` ChannelID string `json:"channelId"` URL string `json:"url"` } { // we would like to be notified on the URL URL: "https://todobot.eu.ngrok.io/create-hook", // whenever a message gets created Events: []string{"message.created"}, // on the WhatsApp channel with ID ChannelID: "23a780701b8849f7b974d8620a89a279", } // encode the payload to json var b bytes.Buffer err := json.NewEncoder(&b).Encode(&wh) if err != nil { panic(err) } // create the http request and set authorization header req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json") // fire the http request client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close()// is everything ok? body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode >= http.StatusBadRequest { panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body))) } else { log.Println("All good. response body: ", string(body)) } }
رائع. الآن ستقوم Conversations API بإجراء طلب POST إلى:
https://todobot.eu.ngrok.io/create-hook كلما تم إنشاء رسالة جديدة على قناة WhatsApp التي قمت بإعدادها سابقًا.
هذا ما يبدو عليه payload الخاص بالويب هوك:
{ "conversation":{ "id":"55c66895c22a40e39a8e6bd321ec192e", "contactId":"db4dd5087fb343738e968a323f640576", "status":"active", "createdDatetime":"2018-08-17T10:14:14Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z", "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z" }, "message":{ "id":"ddb150149e2c4036a48f581544e22cfe", "conversationId":"55c66895c22a40e39a8e6bd321ec192e", "channelId":"23a780701b8849f7b974d8620a89a279", "status":"received", "type":"text", "direction":"received", "content":{ "text":"add buy milk" }, "createdDatetime":"2018-08-17T14:30:31.898389294Z", "updatedDatetime":"2018-08-17T14:30:31.915292912Z" }, "type":"message.created" }
نريد الرد على تلك الرسائل. دعنا نبدأ بتكرارها، ما رأيك؟
// define the structs where we'll parse the webhook payload into type whPayload struct { Conversation conversation `json:"conversation"` Message message `json:"message"` Type string `json:"type"` } type message struct { ID string `json:"id"` Direction string `json:"direction"` Type string `json:"type"` Content content `json:"content"` } type content struct { Text string `json:"text"` } type conversation struct { ID string `json:"id"` } func main() { http.HandleFunc("/create-hook", createHookHandler) log.Fatal(http.ListenAndServe(*httpListenAddress, nil)) } // createHookHandler is an http handler that will handle webhook requests func createHookHandler(w http.ResponseWriter, r *http.Request) { // parse the incoming json payload whp := &whPayload{} err := json.NewDecoder(r.Body).Decode(whp) if err != nil { log.Println("Err: got weird body on the webhook") w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error") return } if whp.Message.Direction != "received" { // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those. fmt.Fprintf(w, "ok") return } // echo: respond what we get err = respond(whp.Conversation.ID, whp.Message.Content.Text) if err != nil { log.Println("Err: ", err) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal Server Error")return } w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "ok") }
الآن، للجزء المثير للاهتمام. قم بإجراء طلب POST إلى:
https://conversations.messagebird.com/v1/conversations/<conversationID>/messages للرد على الطلب.
func respond(conversationID, responseBody string) error { u := fmt.Sprintf("https://conversations.messagebird.com/v1/conversations/%s/messages", conversationID)msg := message{ Content: content{ Text: responseBody, }, Type: "text", } var b bytes.Buffer err := json.NewEncoder(&b).Encode(&msg) if err != nil { return fmt.Errorf("Error encoding buffer: %v", err) } req, err := http.NewRequest("POST", u.String(), &b) req.Header.Set("Authorization", "AccessKey todo-your-access-key") req.Header.Set("Content-Type", "application/json")client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode != http.StatusCreated { return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body)) } log.Println("All good. Response body: ", string(body)) return nil }
هناك. هذا كل ما تحتاجه لإنشاء روبوت يتصرف مثل إنسان في الخامسة من العمر.
الآن، دعنا نخطو خطوة نحو بناء قائمة المهام الكاملة. أولاً، قم بتعديل وظيفة createHookHandler قليلاً بحيث تستدعى الوظيفة الجديدة handleMessage بدلاً من respond.
func createHookHandler(w http.ResponseWriter, r *http.Request) { ... err = handleMessage(whp) ... }
handle سيقوم بشكل بسيط بتحليل الرسائل، والقيام ببعض العمل، واختيار الرد. دعنا ننظر إلى أمر "add":
func handleMessage(whp *whPayload) error { // every conversation has a todo list list := manager.fetch(whp.Conversation.ID) // parse the command from the message body: it's the first word text := whp.Message.Content.Text text = regexp.MustCompile(" +").ReplaceAllString(text, " ") parts := strings.Split(text, " ") command := strings.ToLower(parts[0]) // default message responseBody := "I don't understand. Type 'help' to get help." switch command { ... case "add": if len(parts) < 2 { return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.") } // get the item from the message body item := strings.Join(parts[1:], " ")list.add(item) responseBody = "added." ... return respond(whp.Conversation.ID, responseBody) }
هنا، نقوم بإعداد: list := manager.fetch(whp.Conversation.ID). ببساطة، "المدير" هو خريطة آمنة للتزامن تربط معرفات المحادثات بقوائم المهام.
قائمة المهام عبارة عن شريحة سلسلة آمنة للتزامن. كل ذلك في الذاكرة!
شيء مهم آخر! يمكنك أرشفة المحادثات. في بعض التطبيقات، مثل أنظمة إدارة علاقات العملاء، من المهم تتبع بعض التفاعلات - لتتبع فعالية موظفي دعم العملاء، على سبيل المثال. تسمح لك Conversations API بأرشفة المحادثة لإغلاق الموضوع. إذا أرسل المستخدم / العميل رسالة أخرى، ستفتح Conversations API موضوعاً جديداً تلقائيًا.
أيضاً. بإجراء طلب PATCH إلى https://conversations.messagebird.com/v1/conversations/{id} بالحالة المناسبة في الجسم، يمكنك أرشفة المحادثة بهذا المعرف. نقوم بذلك باستخدام الأمر "bye":
case "bye": archiveConversation(whp.Conversation.ID) manager.close(whp.Conversation.ID) responseBody = "bye!"
archiveConversation سيقوم بإجراء طلب PATCH وmanager.close(whp.Conversation.ID) سيقوم بإزالة المحادثة من قائمة المهام.
ولكن مهلاً، Programmable Conversations هي حل متعدد القنوات. ماذا لو كنت تريد إعادة استخدام كود الروبوت لمنصة مختلفة، مثل WeChat؟ هذا النهج المتعدد القنوات هو جزء من استراتيجية تحويل الاستفسارات إلى قنوات أقل تكلفة. كيف ستفعل ذلك؟
فقط قم بإنشاء webhook جديد لاستهداف تلك القناة! webhook يقوم بإرسال الطلبات إلى نفس عنوان الإنترنت https://todobot.eu.ngrok.io/create-hook الذي استخدمناه لـ WhatsApp!
سيعمل هذا لأن كود المعالجة دائمًا يستخدم معرف المحادثة من tải هوك بدلاً من معرف قناة محدد. API MessageBird للمحادثات سوف يحدد القناة للمحادثة لإرسال رسالتك إليها تلقائيًا.
هل تريد إنشاء الروبوت الخاص بك؟ تحقق من الكود الكامل على Github: Wabot على Github، واطلب الوصول المبكر إلى WhatsApp من خلال زيارة صفحة WhatsApp والنقر على زر اتصل بالمبيعات لملء النموذج. بوت سعيد!



