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

Bird

05‏/02‏/2020

واتساب

1 min read

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

أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. إنها تتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتها باستخدام واجهة برمجة تطبيقات واحدة.

أطلقت Bird مؤخرًا محادثات قابلة للبرمجة. يتيح للشركات دمج منصات الاتصالات مثل WhatsApp وMessenger وSMS في أنظمتها - باستخدام API واحد.

أردت تجربة ذلك، لذلك قمت بإنشاء قائمة مهام بوت على WhatsApp، لأنه من الذي لا يحتاج إلى قائمة مهام مؤتمتة للمساعدة في تنظيم يومه؟ قد يبدو ذلك معقدًا، لكنه كان في الواقع سهلًا، وأود إخباركم بكل شيء عنه.

الآن، أعمل في MessageBird، لذلك كان بإمكاني البدء في البناء فورًا. إذا جربت هذا، ستحتاج إلى طلب الوصول المبكر. ولكن بمجرد إعداد قناة WhatsApp، يمكنك تسجيل الدخول إلى لوحة التحكم على موقع MessageBird وبدء العمل.

أول شيء فعلته هو قراءة المستندات. علمت أنه لكي أحصل على رسائل من البوت، سأحتاج إلى استخدام webhook. هذا يعني أن البوت الخاص بي يجب أن يكون متاحًا من الإنترنت. عند بناء واجهات برمجة التطبيقات مثل هذه، من المهم اتباع أفضل ممارسات إصدار API للصيانة. بما أنني بدأت للتو في برمجتها، قررت استخدام ngrok. يقوم بإنشاء نفق من الإنترنت العام إلى منفذ localhost المحبوب 5007. انطلق!

ngrok http 5007 -region eu -subdomain todobot

بعد ذلك، كنت بحاجة لإجراء مكالمة إلى واجهة برمجة محادثات قابلة للبرمجة لإنشاء الـ webhook. إنه طلب 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))
  }
}

رائع. الآن ستقوم محادثات API بإجراء طلب POST إلى:

https://todobot.eu.ngrok.io/create-hook كلما تم إنشاء رسالة جديدة على قناة WhatsApp التي قمت بإعدادها سابقًا.

هذا هو شكل حمولة الـ webhook:


{
  "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
}

هناك. هذا كل ما تحتاجه لإنشاء بوت يتصرف مثل إنسان عمره 5 سنوات.

الآن، دعونا نتوجه نحو بناء قائمة المهام بأكملها. أولاً، قم بتعديل وظيفة createHookHandler قليلاً بحيث تستدعي الوظيفة الجديدة handleMessage بدلاً من الرد.

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). بشكل أساسي، "manager" هو خريطة آمنة للتزامن تقوم بتعيين معرفات المحادثة إلى قوائم المهام.

قائمة المهام هي مجموعة نصوص آمنة للتزامن. كل ذلك في الذاكرة!

شيء آخر مهم! يمكنك أرشفة المحادثات. في بعض التطبيقات، مثل CRMs، من المهم تتبع تفاعلات معينة - لتتبع فعالية موظفي دعم العملاء، على سبيل المثال. تتيح لك محادثات API أرشفة محادثة "لإغلاق" الموضوع. إذا أرسل المستخدم/العميل رسالة أخرى، فستفتح محادثات 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) سيزيل محادثة قائمة المهام.

ولكن مهلاً، محادثات قابلة للبرمجة هي حل متعدد القنوات. ماذا لو أردت إعادة استخدام رمز البوت لمنصة مختلفة، مثل WeChat؟ هذا النهج متعدد القنوات هو جزء من إعادة توجيه الاستفسارات إلى قنوات ذات تكلفة أقل استراتيجية. كيف ستقوم بذلك؟

فقط قم بإنشاء webhook جديد لاستهداف تلك القناة! webhook الذي يرسل طلبات إلى نفس عنوان url https://todobot.eu.ngrok.io/create-hook الذي استخدمناه لـ WhatsApp!

سيعمل هذا لأن شفرة المعالجة دائمًا تستخدم معرّف المحادثة من حمولة الـ webhook للإجابة على الرسائل بدلاً من معرّف القناة الثابت. ستقوم MessageBird’s Conversations API بتحديد القناة تلقائيًا لإرسال رسالتك عليها.

هل تريد إنشاء بوت خاص بك؟ ألقِ نظرة على الشفرة الكاملة على Github: Wabot على Github، واطلب الوصول المبكر إلى WhatsApp بزيارة صفحة WhatsApp والنقر فوق زر تواصل مع المبيعات لملء النموذج. صيد سعيد للبوتات!

أخبار أخرى

اقرأ المزيد من هذه الفئة

A person is standing at a desk while typing on a laptop.

منصة AI-native الكاملة التي تتماشى مع نمو عملك.

A person is standing at a desk while typing on a laptop.

منصة AI-native الكاملة التي تتماشى مع نمو عملك.

A person is standing at a desk while typing on a laptop.

منصة AI-native الكاملة التي تتماشى مع نمو عملك.