Stella Platform Documentation

Stella Platform Documentation

  • Docs
  • Procedures
  • Reference
  • FAQ
  • Bot API
  • API
  • Languages iconEnglish
    • 中文

›FAQ Chatbot Setup

Get Started

  • Build your First Chatbot

Basic Facebook Chatbot Setup

  • Overview
  • 1.1: Connect to Channels
  • 1.2: Create New Tree
  • 1.3: Build the First Node
  • 1.4: Create a Global Node
  • 1.5: Build Child Nodes
  • 2.1: Production Channel
  • 3.1: Draft a Post
  • 3.2: Create Comment Reply

Basic Instagram Chatbot Setup

  • Overview
  • 1.1: Connect to Channels
  • 1.2: Create New Tree
  • 1.3: Build the First Node
  • 1.4: Create Global Node
  • 1.5: Build Child Nodes
  • 2.1: Create Story Mention
  • 2.2: Create Comment Reply
  • 2.3: Send Push Message

Basic Web Chat Chatbot Setup

  • Overview
  • 1.1: Connect to Channels
  • 1.2: Create New Tree
  • 1.3: Build the First Node
  • 1.4: Create a Global Node
  • 1.5: Build Child Nodes

Basic WhatsApp Chatbot Setup

  • Overview
  • 1.1: WABA Subscription
  • 1.2: Connect WABA
  • 1.3: Check Approval Status of WABA
  • 1.4: Setup WABA with Used WhatsApp Number
  • 1.5: Reset / Terminate WABA
  • 2.1: Create New Tree
  • 2.2: Build the First Node
  • 2.3: Create a Global Node
  • 2.4: Build Child Nodes
  • 2.5: Connect to Datasource
  • 3.1: Create Priority Group
  • 4.1: Create Product Message

Common Use Case Application

  • Overview
  • 1.1: Apply Fail-Safe to Chatbot
  • 1.2: Apply Member Unsubscription Flow to Chatbot

Advanced Chatbot Application

  • Overview
  • Apply Datasource to Chatbot
  • Apply Payload Value to Chatbot
  • Apply API to Chatbot
  • Apply Custom Locale to Chatbot
  • Apply Opt-in Flow to Chatbot
  • Apply Agenda to Chatbot
  • Apply Stella API to Chatbot
  • Apply Web Event to Webchat Chatbot

Error Handling

  • Handle Errors for Chatbot

Stella Partner Portal Setup

  • Overview
  • 1.1: Partner Portal Setup
  • 1.2: New Customer Onboarding
  • 1.3: WABA Setup
  • 1.4: Check Approval Status of WABA
  • 1.5: Setup WABA with Used WhatsApp Number
  • 1.6: Reset / Terminate WABA

Template Tree

  • Overview
  • Create Template Tree
  • Manage Proxy Tree

Chatbot Testing & Deployment

  • Overview
  • Stage One - Tree Building
  • Stage Two - Testing Stage
  • Stage Three - Production Deployment

Slack Live Chat Tree Setup

  • Overview
  • 1.1: Create Tree for Live Chat Assignment
  • 2.1: Set Up Pick Ticket Status
  • 2.2: Create Done Command
  • 2.3: Create Transfer Command
  • 2.4: Create Archive Function
  • 2.5: Create Member Tagging/Remarks Command
  • 3.1: Automatic End Live Chat Function

Zendesk Live Chat Tree Setup

  • Overview
  • 1.1: Create Tree for Assignment
  • 2.1: Create Done Command
  • 2.2: Auto End Live Chat Function

FAQ Chatbot Setup

  • Overview
  • 1.1: Exact Keyword Match
  • 1.2: Keyword Groups Match & Diversion
  • 2.1: Redirect to Existing Chatbot Tree
  • 2.2: Data Analytics for FAQ Chatbot
  • 2.3: NLP for FAQ Chatbot
  • 3.1: Filtering Questions for FAQ Chatbot

NLP Chatbot Setup

  • Overview
  • 1.1: Apply NLP to your Chatbot
  • 2.1: Set Up an NLP Fallback Tree
  • 3.1: NLP Fallback to Other Languages

Connect Shopify Store to Stella

  • Overview
  • 1.1: Integrate Stella to Shopify
  • 2.1: Setup Facebook Messenger Chatbot for Shopify
  • 2.2: Setup WhatsApp Chatbot for Shopify
  • 2.3: WhatsApp Customer Care Notification for Shopify

Stella Inbox Setup

  • Overview
  • 1.1: Connect Channel to Slack
  • 1.2: Access Control & Admin Panel
  • 1.3: Set up Customizable Message
  • 1.4: Inbox Channel
  • 2.1: Turn on Live Chat Directly
  • 2.2: End Live Chat Mode
  • 2.3: Ticketing
  • 2.4: Manage Ticket Helper
  • 2.5: Add Member Tag
  • 3.1: Send Chatbot Message

Filtering Questions for FAQ Chatbot

Apart from typing the text directly to the FAQ chatbot, filtering questions allows users to find their answer in a pre-set flow (similar to IVRS in phones). You can categorize your FAQ entries into 3 (or more) layers, so that users can just select the categories layer by layer until they reach the final answer.

Please make sure you have inputted "Category 1-3" & "Category 1-3 Priority". For details on FAQ data source format, please see here.


What is your Result?

  1. User goes through 3 layers of filtering questions and ends up with a filtering result.
Category 1-3 and Filtering Result
  1. In the backend, Stella sorts these questions based on the FAQ data source. Category 1-3 represents the options of chatbot filtering questions 1-3. The order of the options is based on Category 1-3 Priority.
Categories in FAQ Data Source

FAQ Data Source Format

Please refer to level one procedure for the the FAQ Data Source Format.


Getting Hands-on

Sample Tree Structure

Tree Structure of FAQ Chatbot with Filtering Questions

Create the 1st Tree Node - Category 1

  1. Before proceeding, you should have completed up to level 4.1 and 4.2 (or 4.3 optionally) FAQ procedure. You may edit the level four tree directly or duplicate a new tree.

  2. Create a tree node in the level four tree and rename it as "Category 1".

Save Category 1 Answers
  1. Create a Pre-action with the following code and rename it as "Save Category 1 Answers".
return new Promise(async (resolve, reject) => {
  try {
    console.log("in Save Category 1 answers")
    let result = await this.fetchDataFromDataSource({
      collectionName: "Insert your Data Source ID here",
      filter: {}
    })
    console.log("result", result)
    result = this.lodash.uniqBy(result, "Category 1")
    console.log("result", result)
    result = this.lodash.reject(result, { "Category 1": "" })
    console.log("result", result)

    result = this.lodash.sortBy(result, "Category 1 Priority")

    this.member.botMeta.tempData.currentAnswers = result.map(obj => obj["Category 1"])
    this.member.botMeta.tempData.listLength = result.length

    resolve({
      member: this.member,
    })
  } catch (e) {
    reject(e)
  }
})
  1. Input the Data Source ID of the FAQ data source you have been using since level one into the above code.
  1. Create a Response under "Advanced" with the following code and rename it as "Category 1 Question".
Advanced Response
return new Promise((resolve) => {
  let currentAnswers = this.member.botMeta.tempData.currentAnswers || []
  let text = `Please input number to select🔢:\n`
  currentAnswers.forEach((str, i) => {
    let t = ""
    switch (i + 1) {
      case 1:
        t = "1️⃣"
        break
      case 2:
        t = "2️⃣"
        break
      case 3:
        t = "3️⃣"
        break
      case 4:
        t = "4️⃣"
      break
        case 5:
        t = "5️⃣"
        break
      case 6:
        t = "6️⃣"
        break
      case 7:
        t = "7️⃣"
        break
      case 8:
        t = "8️⃣"
        break
      case 9:
        t = "9️⃣"
        break
      case 10:
        t = "🔟️"
        break
      case 11:
        t = "1️⃣1️⃣"
        break
      case 12:
        t = "1️⃣2️⃣"
        break
      case 13:
        t = "1️⃣3️⃣"
        break
      case 14:
        t = "1️⃣4️⃣"
        break
      case 15:
        t = "1️⃣5️⃣"
        break
      case 16:
        t = "1️⃣6️⃣"
        break
      case 17:
        t = "1️⃣7️⃣"
        break
      case 18:
        t = "1️⃣8️⃣"
        break
      case 19:
        t = "1️⃣9️⃣"
        break
      case 20:
        t = "2️⃣0️⃣"
        break
      default:

    }
    text = `${text}\n${t} ${str}`
  })
  text = `${text}\n\nCan't find what you are looking for? Type keywords to ask Stella. You can also type *#* anytime to return to this menu.` 
  resolve({
    type: "TEXT",
    text,
  })
})
  1. You can edit the filtering question content (the header & footer of the text message) marked inside the back quotation marks of text = in the above code. ${text} refers to the Category 1 options displayed from FAQ data source.

  2. Save this tree node.

  3. You can also create a Global Node that redirects user to the Category 1 tree node. As a result, users can easily return to Category 1 by keyword when there are multiple categories.


Create the 2nd Tree Node - Category 2

  1. Select the Category 1 tree node. Create the next tree node and rename it as "Category 2".
  1. Create a trigger with the following conditions & relationships:
Category Option Trigger

First condition - Type Text:

this.messageEvent.type === "TEXT"

Second condition - Number within list length:

this.member.botMeta.tempData.listLength ? new RegExp("\\b" + [...Array(this.member.botMeta.tempData.listLength + 1).keys()].slice(1).join("\\b|\\b") + "\\b").test(this.messageEvent.data.text) : false
  1. Create a Pre-action with the following code and rename it as "Save Category 1".
Save Category 1
return new Promise((resolve) => {
  console.log("in Save FAQ Category 1")
  if (/(\+)/i.test(this.messageEvent.data.text)) {
    resolve()
  } else {
    let match = this.messageEvent.data.text.match(new RegExp("\\b" + [...Array(this.member.botMeta.tempData.listLength + 1).keys()].slice(1).join("\\b|\\b") + "\\b"))
    let indexStr = match[0]
    let index = parseInt(indexStr) - 1
    let currentAnswers = this.member.botMeta.tempData.currentAnswers
    let currentAnswer = currentAnswers[index]
    this.member.botMeta.tempData.category1 = currentAnswer
    resolve({ member: this.member })
  }
})
  1. Create a 2nd Pre-action with the following code and rename it as "Save Category 2 Answers".
return new Promise(async (resolve, reject) => {
  try {
    console.log("in Save Category 2 Answers")
    let result = await this.fetchDataFromDataSource({
      collectionName: "Insert your Data Source ID here",
      filter: {
        "Category 1": this.member.botMeta.tempData.category1
      }
    })
    console.log("result", result)
    
    if (result.length === 1) {
      this.member.displayAnswer = true
      this.member.botMeta.tempData.faq = result[0]
      resolve({ member: this.member })
    } else {
      result = this.lodash.uniqBy(result, "Category 2")
      console.log("result", result)
      result = this.lodash.reject(result, { "Category 2": "" })
      console.log("result", result)

      result = this.lodash.sortBy(result, "Category 2 Priority")

      this.member.botMeta.tempData.currentAnswers = result.map(obj => obj["Category 2"])
      this.member.botMeta.tempData.listLength = result.length

      resolve({
        member: this.member,
      })
    }
  } catch (e) {
    reject(e)
  }
})
  1. Input the Data Source ID of the FAQ data source you have been using since level one into the above code.
  1. Create a Response under "Advanced" with the following code and rename it as "Category 2 Question".
Advanced Response
return new Promise((resolve) => {
  if (this.member.displayAnswer) {
    resolve()
  } else {
    let currentAnswers = this.member.botMeta.tempData.currentAnswers || []
    let text = `Do you want to know about ${this.member.botMeta.tempData.category1} ?\n`
    currentAnswers.forEach((str, i) => {
      let t = ""
      switch (i + 1) {
        case 1:
          t = "1️⃣"
          break
        case 2:
          t = "2️⃣"
          break
        case 3:
          t = "3️⃣"
          break
        case 4:
          t = "4️⃣"
          break
        case 5:
          t = "5️⃣"
          break
        case 6:
          t = "6️⃣"
          break
        case 7:
          t = "7️⃣"
          break
        case 8:
          t = "8️⃣"
          break
        case 9:
          t = "9️⃣"
          break
        case 10:
          t = "1️⃣0️⃣️"
          break
        case 11:
          t = "1️⃣1️⃣"
          break
        case 12:
          t = "1️⃣2️⃣"
          break
        case 13:
          t = "1️⃣3️⃣"
          break
        case 14:
          t = "1️⃣4️⃣"
          break
        case 15:
          t = "1️⃣5️⃣"
          break
        case 16:
          t = "1️⃣6️⃣"
          break
        case 17:
          t = "1️⃣7️⃣"
          break
        case 18:
          t = "1️⃣8️⃣"
          break
        case 19:
          t = "1️⃣9️⃣"
          break
        case 20:
          t = "2️⃣0️⃣"
          break
        default:

      }
      text = `${text}\n${t} ${str}`
    })
    text = `${text}\n\nCan't find what you are looking for? Type keywords to ask Stella. You can also type *#* anytime to return to this menu.`
    resolve({
      type: "TEXT",
      text,
    })
  }
})
  1. You can edit the filtering question content (the header & footer of the text message) marked inside the back quotation marks of text = in the above code. ${text} refers to the Category 2 options displayed from FAQ data source. ${this.member.botMeta.tempData.category1} displays the Category 1 that user has chosen.

  2. Toggle on the Advanced tab in "Redirect" and paste the following code:

Advanced Redirect
return new Promise((resolve) => {
  if (this.member.displayAnswer) {
    resolve({
      tree: this.node.tree,
      nodeCompositeId: "Input the node composite ID of the filtering result tree node here",
      runPreAction: false
    })
  } else {
    resolve()
  }
})
  1. Input the node composite ID of the filtering result tree node into the above code. You will be able to retrieve the node composite ID in the coming steps. Remember to come back and edit later.

  2. Save this tree node.


Create the 3rd Tree Node - Category 3

  1. Select the Category 2 tree node. Create the next tree node and rename it as "Category 3".
  1. Use the same trigger you made in Step 9 tree node.
Category Option Trigger
  1. Create a Pre-action with the following code and rename it as "Save Category 2".
Save Category 2
return new Promise((resolve) => {
  console.log("in Save FAQ Category 2")
  let match = this.messageEvent.data.text.match(new RegExp("\\b" + [...Array(this.member.botMeta.tempData.listLength + 1).keys()].slice(1).join("\\b|\\b") + "\\b"))
  let indexStr = match[0]
  let index = parseInt(indexStr) - 1
  let currentAnswers = this.member.botMeta.tempData.currentAnswers
  let currentAnswer = currentAnswers[index]
  console.log("category2 ans", currentAnswer)
  this.member.botMeta.tempData.category2 = currentAnswer
  resolve({ member: this.member })
})
  1. Create a 3rd Pre-action with the following code and rename it as "Save Category 3 Answers".
return new Promise(async (resolve, reject) => {
  try {
    console.log("in Save Category 3 Answers")
    let result = await this.fetchDataFromDataSource({
      collectionName: "Insert your Data Source ID here",
      filter: {
        "Category 1": this.member.botMeta.tempData.category1,
        "Category 2": this.member.botMeta.tempData.category2,
      }
    })
    console.log("result", result)
    
    if (result.length === 1) {
      this.member.displayAnswer = true
      this.member.botMeta.tempData.faq = result[0]
      resolve({ member: this.member })
    } else {
      result = this.lodash.uniqBy(result, "Category 3")
      console.log("result", result)
      result = this.lodash.reject(result, { "Category 3": "" })
      console.log("result", result)

      result = this.lodash.sortBy(result, "Category 3 Priority")
      
      this.member.botMeta.tempData.currentAnswers = result.map(obj => obj["Category 3"])
      this.member.botMeta.tempData.listLength = result.length
    
      resolve({
        member: this.member,
      })
    }
  } catch (e) {
    reject(e)
  }
})
  1. Input the Data Source ID of the FAQ data source you have been using since level one into the above code.
  1. Create a Response under "Advanced" with the following code and rename it as "Category 3 Question".
Advanced Response
return new Promise((resolve) => {
  if (this.member.displayAnswer) {
    resolve()
  } else {
    let currentAnswers = this.member.botMeta.tempData.currentAnswers || []
    let text = `Do you want to know about ${this.member.botMeta.tempData.category2}?\n`
    currentAnswers.forEach((str, i) => {
      let t = ""
      switch (i + 1) {
        case 1:
          t = "1️⃣"
          break
        case 2:
          t = "2️⃣"
          break
        case 3:
          t = "3️⃣"
          break
        case 4:
          t = "4️⃣"
          break
        case 5:
          t = "5️⃣"
          break
        case 6:
          t = "6️⃣"
          break
        case 7:
          t = "7️⃣"
          break
        case 8:
          t = "8️⃣"
          break
        case 9:
          t = "9️⃣"
          break
        case 10:
          t = "1️⃣0️⃣️"
          break
        case 11:
          t = "1️⃣1️⃣"
          break
        case 12:
          t = "1️⃣2️⃣"
          break
        case 13:
          t = "1️⃣3️⃣"
          break
        case 14:
          t = "1️⃣4️⃣"
          break
        case 15:
          t = "1️⃣5️⃣"
          break
        case 16:
          t = "1️⃣6️⃣"
          break
        case 17:
          t = "1️⃣7️⃣"
          break
        case 18:
          t = "1️⃣8️⃣"
          break
        case 19:
          t = "1️⃣9️⃣"
          break
        case 20:
          t = "2️⃣0️⃣"
          break
        default:

      }
      text = `${text}\n${t} ${str}`
    })
    text = `${text}\n\nCan't find what you are looking for? Type keywords to ask Stella. You can also type *#* anytime to return to this menu.`
    resolve({
      type: "TEXT",
      text,
    })
  }
})
  1. You can edit the filtering question content (the header & footer of the text message) marked inside the back quotation marks of text = in the above code. ${text} refers to the Category 3 options displayed from FAQ data source. ${this.member.botMeta.tempData.category2} displays the Category 1 that user has chosen.

  2. Toggle on the Advanced tab in "Redirect" and use the same code as you've made in Step 15.

Advanced Redirect
  1. Input the node composite ID of the filtering result tree node into the above code. You will be able to retrieve the node composite ID in coming steps. Remember to come back and edit later.

  2. Save this tree node.


Create the 4th Tree Node - Filtering Result

  1. Select the Category 3 tree node. Create the next tree node and rename it as "Filtering Result".
  1. Use the same trigger you made in Step 9 tree node.
Category Option Trigger
  1. Create a Pre-action with the following code and rename it as "Save Category 3".
Save Category 3
return new Promise((resolve) => {
  console.log("in Save FAQ Category 3")
  let match = this.messageEvent.data.text.match(new RegExp("\\b" + [...Array(this.member.botMeta.tempData.listLength + 1).keys()].slice(1).join("\\b|\\b") + "\\b"))
  let indexStr = match[0]
  let index = parseInt(indexStr) - 1
  let currentAnswers = this.member.botMeta.tempData.currentAnswers
  let currentAnswer = currentAnswers[index]
  this.member.botMeta.tempData.category4 = currentAnswer
  console.log("Category 3", currentAnswer)
  resolve({ member: this.member })
})
  1. Create a 2nd Pre-action with the following code and rename it as "Save Filtering Result".
return new Promise(async (resolve, reject) => {
  try {
    console.log("in Save Filtering Result")
    let result = await this.fetchDataFromDataSource({
      collectionName: "Insert your Data Source ID here",
      filter: {
        "Category 1": this.member.botMeta.tempData.category1,
        "Category 2": this.member.botMeta.tempData.category2,
        "Category 3": this.member.botMeta.tempData.category3,
      }
    })
    console.log("result", result)

    this.member.botMeta.tempData.faq = result[0]

    resolve({
      member: this.member,
    })
  } catch (e) {
    reject(e)
  }
})
  1. Input the Data Source ID of the FAQ data source you have been using since level one into the above code.
  1. Create a Response under "Advanced" with the following code and rename it as "Show Selected Question Content".
Advanced Response
return new Promise((resolve, reject) => {
  console.log("in Show Selected Question Content")
  let result = this.member.botMeta.tempData.faq
  console.log("result", result)
  let response = {}
  let type = result["Type"]
  console.log("type", type)
  switch (type) {
    case "Text":
      response.type = "TEXT"
      response.text = result.Text
      if (result.Preview === true || result.Preview === "TRUE") {
        response.preview_url = true
      }
      break
    case "Image":
    case "Image_Text":
    case "Image with caption":
      response.type = "IMAGE"
      response.url = result.URL
      response.text = result.Text
      break
    case "Video":
    case "GIF":
    case "File":
      response.type = "FILE"
      response.url = result.URL
      response.text = result.Text
      response.filename = result["File Name"]
      break
    case "Audio":
      response.type = "AUDIO"
      response.url = result.URL
      break
    case "Carousel":
      response.type = "CAROUSEL"
      response.carousel = [{
        title: result.Text,
        image_url: result.URL,
        buttons: [{
          type: "web_url",
          title: result["Button title"],
          url: result["Button url"],
        }]
      }]
      break
    case "Button":
      response.type = "BUTTON"
      response.text = result.Text,
        response.buttons = [{
          type: "web_url",
          title: result["Button title"],
          url: result["Button url"],
        }]
      break
    default:
      response = null
      break;
  }
  console.log("response", response)
  resolve(response)
})
  1. Save and see if you can produce the expected outcome.
← 2.3: NLP for FAQ ChatbotOverview →
  • What is your Result?
  • FAQ Data Source Format
  • Getting Hands-on
    • Sample Tree Structure
    • Create the 1st Tree Node - Category 1
    • Create the 2nd Tree Node - Category 2
    • Create the 3rd Tree Node - Category 3
    • Create the 4th Tree Node - Filtering Result
Stella Platform Documentation
Docs
Get StartedBot API ReferenceAPI ReferenceStandard Procedures
Community
FAQUser ShowcaseChat with Us
Copyright © 2023 Sanuker Inc. Limited