# Bot Development
Speaker: Lee Wei
###### tags: `Tutorial`
---
## 不知道大家想像的機器人是怎樣的
----
### Pepper
![Pepper](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/SoftBank_pepper.JPG/440px-SoftBank_pepper.JPG)
----
### ASIMO
![asimo](https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/ASIMO_4.28.11.jpg/350px-ASIMO_4.28.11.jpg)
----
### Transformer
![Transformer](https://upload.wikimedia.org/wikipedia/zh/thumb/0/01/變形金剛_殲滅世紀.jpg/440px-變形金剛_殲滅世紀.jpg =330x489)
----
### ~~Transformer~~
![Transformer](https://upload.wikimedia.org/wikipedia/zh/thumb/0/01/變形金剛_殲滅世紀.jpg/440px-變形金剛_殲滅世紀.jpg =330x489)
#### 阿,不是這個
---
## 不過今天要談的不是這種東西
----
## 而是
----
### Facebook Bot
![Facebook Bot](https://scontent-tpe1-1.xx.fbcdn.net/t39.2178-6/12995571_1588331784790779_717340601_n.png =265x500)
----
### Line Bot
![Line Bot](https://scdn.line-apps.com/n/_5/partner-center/img/lp/tw/msgapi-figure3.png)
----
## Chat Bot 聊天機器人
---
### 有人說聊天機器人(with AI)將要取代APP
- [Why chatbots are replacing apps](http://venturebeat.com/2016/08/02/why-chatbots-are-replacing-apps/)
- [This is how Chatbots will Kill 99% of Apps](https://chatbotslife.com/this-is-how-chatbots-will-kill-99-of-apps-2fd938a22c99#.tdfugot4m)
----
### 各大軟體公司爭相提供Bot的服務
- [Facebook Messenger Platform](https://messengerplatform.fb.com)
- [Line Messaging API](https://developers.line.me/messaging-api/overview)
- [Slack API](https://api.slack.com)
- [Telegram Bot Platform](https://core.telegram.org/bots/api)
---
## What can Bot Do?
{%youtube C7ZuzJe24y4 %}
----
### 影片中出現了什麼?
- 預約餐廳
- 訂車
- 偵測beacon提供coupon
- 遠端控制家中的IoT設備澆水
----
原本在App上處理的這些服務
未來都有可能被Chat Bot取代
----
### 背後發生了什麼事
e.g. 預約餐廳
1. User傳一個訊息給Bot的帳號 <!-- .element: class="fragment" data-fragment-index="1" -->
2. Bot把訊息傳給服務提供者的Server <!-- .element: class="fragment" data-fragment-index="2" -->
3. 服務提供者的Server把訊息,傳給指定的Server <!-- .element: class="fragment" data-fragment-index="3" -->
4. 指定的Server做了適當的運算和判斷 <!-- .element: class="fragment" data-fragment-index="4" -->
把結果回傳給服務提供者Server
5. 服務提供者Server收到後,再傳給User的帳號 <!-- .element: class="fragment" data-fragment-index="5" -->
---
## Why Chat Bot?
- 市面上App太多
- 每裝一個APP都要學一次,使用者沒你想的勤勞!
- 不如把服務嵌入現在使用者常用的App
(e.g. Facebook Messenger, Line)
- 文字是人類相對直覺的溝通方式
----
## Why not Chat Bot?
- 設計彈性不如App (e.g. 介面受限嵌入的App)
- 文字處理依然不夠好
---
## How to Design a Bot?
1. 選擇使用的Bot平台 (e.g. Facebook, Line and etc.)
2. 寫一些服務 (e.g. 訂票、新聞推播) <!-- .element: class="fragment" data-fragment-index="1" -->
3. 把服務架在一台https server <!-- .element: class="fragment" data-fragment-index="2" -->
4. 用Bot平台提供的sdk,把Server跟平台串起來 <!-- .element: class="fragment" data-fragment-index="3" -->
5. 用NLP精準的判斷使用者的意思,串到服務上 <!-- .element: class="fragment" data-fragment-index="4" -->
----
用NLP精準的判斷使用者的意思,串到服務上
`Just like the fifth step of...` <!-- .element: class="fragment" data-fragment-index="1
" -->
----
![Five Steps draw a horse](http://68.media.tumblr.com/tumblr_lxc8ghQU2T1qincqxo1_500.jpg)
by Van Oktop
---
## Implement an Echo Bot
(The Simplest ChatBot)
----
## How to Build an Echo Bot?
1. 選擇使用的Bot平台 (e.g. Facebook, Line and etc.)
2. ~~寫一些服務 (e.g. 訂票、新聞推播)~~
3. 把寫的服務,架在一台https server
4. 用Bot平台提供的sdk,把Server跟平台串起來
5. ~~用NLP精準的判斷使用者的意思,串到服務上~~
----
## How to Build an Echo Bot?
1. 選擇使用的Bot平台 (e.g. Facebook, Line and etc.)
2. 接受訊息並Echo,把這個功能架在一台https server
3. 用Bot平台的提供的sdk,把Server跟平台串起來
---
## Let's Build an Echo Bot
----
## Tools
![line](https://static.line.naver.jp/line_regulation/files/ver2/LINE_Icon.png =200x200)
![django](https://www.djangoproject.com/m/img/logos/django-logo-negative.png =300x136)
---
## Create a Line@ Account
[[Bot] Apply Line Messaging API](http://lee-w-blog.logdown.com/posts/1129876-apply-line-messaging-api)
---
## Create Project
```sh
# Create a line_echobot project
django-admin startproject line_echobot
# Create an echobot app
python3 manage.py startapp echobot
```
---
## Setup Line Secrets
- Channel Secret
- Channel Access Token
----
## Setup Line Secrets
不過這些值不該被git記錄
所以不該被寫死在`settings.py`中
建議寫入環境變數
```sh
export SECRET_KEY='Your django secret key'
export LINE_CHANNEL_ACCESS_TOKEN='Your line channel access token'
export LINE_CHANNEL_SECRET='Your line channel secret'
```
----
## Setup Line Secrets
```python
# line_echobot/settings.py
......
def get_env_variable(var_name):
try:
return os.environ[var_name]
except KeyError:
error_msg = 'Set the {} environment variable'.format(var_name)
raise ImproperlyConfigured(error_msg)
SECRET_KEY = get_env_variable('SECRET_KEY')
LINE_CHANNEL_ACCESS_TOKEN = get_env_variable('LINE_CHANNEL_ACCESS_TOKEN')
LINE_CHANNEL_SECRET = get_env_variable('LINE_CHANNEL_SECRET')
```
---
## Setup Line Webhook URL
設定一個Webhook URL
讓Line可以把Bot收到的訊息傳給我們
----
## Setup Line Webhook URL
讓project找到app
```python
# line_echobot/urls.py
......
import echobot
urlpatterns = [
......,
url(r'^echobot/', include('echobot.urls')),
]
......
```
----
## Setup Line Webhook URL
將app的url導到相對應的function
```python
# echobot/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url('^callback/', views.callback),
]
```
----
## Setup Line Webhook URL
**https://"your domain name"/echobot/callback/**
---
## Implement Callback Funtion
----
import相關的函式庫
```python
from django.conf import settings
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from linebot import LineBotApi, WebhookParser, WebhookHanlder
from linebot.exceptions import InvalidSignatureError, LineBotApiError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
```
----
透過line_bot_api傳訊息給Line,讓Line轉傳給使用者
```python
line_bot_api = LineBotApi(settings.LINE_CHANNEL_ACCESS_TOKEN)
```
----
### Callback Function
有兩種方法可以處理Line Server送過來的訊息
這裡先用Todo記著,待會再來補上
```python
# TODO: Define Receiver
@csrf_exempt
def callback(request):
if request.method == 'POST':
signature = request.META['HTTP_X_LINE_SIGNATURE']
body = request.body.decode('utf-8')
# TODO: Handler when receive Line Message
return HttpResponse()
else:
return HttpResponseBadRequest()
```
----
### Validate Signature
確認這個request是不是從Line Server傳來的
要確認這件事,需要
- request的body
- request header中的X-Line-Signature
```python
signature = request.META['HTTP_X_LINE_SIGNATURE']
body = request.body.decode('utf-8')
```
----
## Handle Recevied Message
取得body跟signature後
Line Bot API會在處理訊息的同時驗證訊息來源
----
## WebhookParser
Parse出訊息的所有欄位
e.g.
- UserID
- Event Type
- Message Content
- and etc.
```python
parser = WebhookParser(settings.LINE_CHANNEL_SECRET)
```
----
### Handle Line Related Exception
```python
try:
events = parser.parse(body, signature)
except InvalidSignatureError:
return HttpResponseForbidden()
except LineBotApiError:
return HttpResponseBadRequest()
```
----
### Echo
如果是文字訊息,就回傳給使用者
```python
for event in events:
if isinstance(event, MessageEvent):
if isinstance(event.message, TextMessage):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(
text=event.message.text
)
)
```
----
## WebhookHandler
針對每一種不同的訊息型態註冊一個處理器
只要收到這樣的訊息,就會丟給對應的處理器
```python
handler = WebhookHandler(settings.LINE_CHANNEL_SECRET)
```
----
### Text Message Handler
```python
@handler.add(MessageEvent, message=TextMessage)
def handle_text_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text)
)
```
----
### Default Handler
```python
@handler.default()
def default(event):
print(event)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(
text='Currently Not Support None Text Message'
)
)
```
----
### Handle
```python
try:
handler.handle(body, signature)
except InvalidSignatureError:
return HttpResponseForbidden()
except LineBotApiError:
return HttpResponseBadRequest()
```
----
## Full Code
兩種不同處理方式的完整Code
- [views.py (WebhookParser)](https://github.com/Lee-W/line_echobot/blob/master/echobot/views.py)
- [views.py (WebhookHandler)](https://github.com/Lee-W/line_echobot/blob/webhookhandler/echobot/views.py)
到了這裡,echo bot實作的部分就完成了
---
## Https Server
1. 自己架一個Https Server `(Skip)`<!-- .element: class="fragment" data-fragment-index="1" -->
2. 使用[ngrok](https://ngrok.com)
3. 架在[Heroku](https://www.heroku.com)
----
### ngrok
![ngrok](https://ngrok.com/static/img/demo.png)
----
### ngrok
先把django的server run起來
```sh
python3 manage.py runserver
```
----
### ngrok
用ngrok將request導到本地端的port 8000
```sh
ngrok http 8000
```
![1_ngrok_example](http://i.imgur.com/r525wEI.png =681x387)
----
### ngrok
再來到Line Bot的`Line Developer`頁面
設定Webhook URL
----
### ngrok
然後就可以跟Bot聊天了
![3_message_sample](http://i.imgur.com/boxeHoG.png)
---
## Heroku
----
### Why not always use ngrok
- 本地端必須一直開著
- 免費版的ngrok每次都會改url
----
### When to use ngrok or Heroku?
- ngrok -> 基本Bot除錯
- Heroku -> 開放給其他人測試Bot功能
- 自己架Https Server -> 上線
----
### Create App
先上[Heroku](https://www.heroku.com)辦個帳號
到個人的dashboard
`New` -> `Create New App`
選一個名字,就創好App了
----
## Deploy
### Add Remote
在部署之前要先安裝[Heroku CLI](https://devcenter.heroku.com/articles/heroku-command-line)
```sh
heroku login
heroku git:remote -a leewbot
```
----
### Environment Variables
```sh
heroku config:set "env key":"env value"
```
----
### Python Envrionments
- Heroku透過`requirements.txt`來判斷是否為Python專案
- 指定Python版本(`runtime.txt`)
- `python-2.7.12`
- `python-3.5.2`
----
### Deploy Settings - Procfile
使用gunicorn部署到Heroku上
- 在`requirements.txt`加入`gunicorn==19.0.0`
- 在`Procfile`寫入
```
web: gunicorn line_echobot.wsgi --log-file -
```
接著
```sh
git push heroku master
```
就部署到Heroku上了
---
## More than just an Echo Bot
----
## How to Design a Bot?
1. 選擇使用的Bot平台 (e.g. Facebook, Line and etc.)
2. 寫一些服務 (e.g. 訂票、新聞推播)
3. 把寫的服務,架在一台https server
4. 用Bot平台提供的sdk,把Server跟平台串起來
5. 用NLP精準的判斷使用者的意思,串到服務上
----
## How to Design a Bot?
1. ~~選擇使用的Bot平台 (e.g. Facebook, Line and etc.)~~
2. 寫一些服務 (e.g. 訂票、新聞推播)
3. ~~把寫的服務,架在一台https server~~
4. ~~用Bot平台提供的sdk,把Server跟平台串起來~~
5. 用NLP精準的判斷使用者的意思,串到服務上
----
## How to Design a Bot?
1. ~~選擇使用的Bot平台 (e.g. Facebook, Line and etc.)~~
2. ~~寫一些服務 (e.g. 訂票、新聞推播)~~
3. ~~把寫的服務,架在一台https server~~
4. ~~用Bot平台提供的sdk,把Server跟平台串起來~~
5. 用NLP精準的判斷使用者的意思,串到服務上
---
## 淺談如何判斷使用者的意圖
如果使用者問:
- 「今天天氣如何?」
- 「天氣今天好嗎?」
要如何知道,他都是要詢問今天的天氣狀況
也就是使用者的「意圖」
---
## Based on Keyword
同樣是天氣的問題
- 試著找出「天氣」是否有出現在使用者的問句中
- 再來判斷「今天」, 「明天」這樣敘述時間的詞
----
## Based on Keyword
e.g.
```python
if '天氣' in text:
if '今天' in text:
return today_s_weather
elif '明天' in text:
return tomorrow_s_weather
```
----
## Based on Keyword
- Pros
- 不需要其他的背景知識,容易實作
- 運算量小
- Cons
- 建立規則很麻煩
- 規則很容易就會出現例外,很難定義得完整
- 只要使用者無法觸發到關鍵字,就無法使用功能
- 一堆if else造成程式冗長,不易擴充和維護
---
## AIML
一款基於XML的markup language
這是最基本的AIML
```xml
<aiml version="1.0.1" encoding="UTF-8"?>
<category>
<pattern> HELLO ALICE </pattern>
<template>
Hello User!
</template>
</category>
</aiml>
```
----
## AIML
- Pros
- 比起只用if else更結構化,較易維護和擴充
- Cons
- 依然很難包含所有的狀況
---
## Other NLP Service
- [Wit.ai](https://wit.ai) (Facebook)
- COSCUP 2016的聊天機器人小啄
- [LUIS](https://www.luis.ai) (Microsoft)
- [API.ai](https://api.ai) (Google)
----
## Other NLP Service
這些服務能透過標記和訓練
解析出這句話的每一個片段,所具有的意義
- e.g. 「今天西雅圖天氣如何」
- 時間:今天
- 地點:西雅圖
- 意圖:天氣如何
----
### Wit.ai
Wit.ai跟Luis, API.ai比較不同的地方是
從Wit.ai得到的是,我們設定的回覆
而不是一句話解析後的結果
----
### LUIS
- Question
```
how is the weather in the Taipei
```
- Response
```json
{
"query": "how is the weather in the Taipei",
"topScoringIntent": {
"intent": "GetCurrentWeather",
"score": 0.50119406,
"actions": [
{
"triggered": false,
"name": "GetCurrentWeather",
"parameters": [
{
"name": "location",
"required": true,
"value": null
}
]
}
]
},
"entities": [],
"dialog": {"contextId": "80cd646a-d85d-4b40-873d-1b47fa49adc8",
"status": "Question",
"prompt": "Where would you like to get the current weather for?",
"parameterName": "location"
}
}
```
----
### API.ai
- Question
```
Hey Calendar, schedule lunch with
Mary Johnson at 12 pm tomorrow.
```
- Response
```json
{
"action":"meeting.create",
"name":"Lunch with Mary Johnson",
"invitees":["Mary Johnson"],
"time":"2014-08-06T12:00:00-07:00"
}
```
---
## Implement Through Powerful Libraries
- [NLTK](http://www.nltk.org)
- Python經典的NLP函式庫
- [word2vec](https://radimrehurek.com/gensim/)
- 透過詞向量,找出相似詞
- [jieba](https://github.com/fxsjy/jieba)
- 中文斷詞
- 判斷句子中的關鍵詞
***
[NLP Libs Sample](https://gist.github.com/Lee-W/72f3a59b015cd67b3a939bf8a12680ac)
---
## Beyond NLP
不過就算做了這些分詞、判斷意圖
也不能保證使用者就會買單
有人稱Chat Bot為下一代的UX Design
----
### Issue
- 如何讓使用者,在Chat Bot的Scope內不會碰壁
- 如何讓Chat Bot的判斷足夠robust
不會每次都不懂使用者的意思
- 如何讓使用者在最少的操作下,得到想得到的服務
----
### Issue
更進一步是
如何設計一個有個性、有溫度的機器人
---
# Reference
- [[Bot] Introduction to Chatbot](http://lee-w-blog.logdown.com/posts/1126591-introduction-to-chatbot)
- [[Bot] Apply Line Messaging API](http://lee-w-blog.logdown.com/posts/1129876-apply-line-messaging-api)
- [[Bot] Line Echo Bot on Django](http://lee-w-blog.logdown.com/posts/1134898-line-echo-bot-on-django)
- [[Bot] Deploy LineBot on Heroku](http://lee-w-blog.logdown.com/posts/1148021-deploy-linebot-on-heroku)
- [[Bot] More About Line Messaging API - Template Messages](http://lee-w-blog.logdown.com/posts/1148026-more-about-line-messaging-api-template-messages)
- [[Bot] More than Just Echo Bot](http://lee-w-blog.logdown.com/posts/1151669-more-than-just-echo-bot)
----
# Reference
- [Van Oktop](http://oktop.tumblr.com/post/15352780846)
- [icon infinder](https://www.iconfinder.com/icons/317727/facebook_social_social_media_icon#size=128)
- [django Logo](https://www.djangoproject.com/community/logos/)
- [Line Logo](https://line.me/en/logo)
---
## Thanks For Your Attention
{"metaMigratedAt":"2023-06-14T12:09:18.244Z","metaMigratedFrom":"Content","title":"Bot Development","breaks":true,"contributors":"[{\"id\":\"45254ecf-b61f-46f5-ae2e-0e226ba55757\",\"add\":26,\"del\":0}]"}