LINE Bot basic build with Wit.ai
===
為了讓line bot 可以建入更多彈性的內容,而非僅有寫死在程式內的語言判斷
可以與機器學習串接起來
因為著名的 LUIS.ai 近期開始收費,所以選用最近被 facebook 買下來的 Wit.ai
---
首先創好帳號,並選擇 new App

`
若要吃中文,語言記得選Chinese (BETA)
`

---
### 基礎篇 - 建入entity
從  來訓練我們的ai

1. 先從一句話去訓練,將一句話的關鍵字選取,分別給予意圖。
:::info
"你好,我想要吃蛋餅當早餐" 這句話 有兩個關鍵字: 早餐 & 蛋餅
:::
* 若反白選取沒有內建的意圖,可以直接建立新的

* 並建入keyword
2. 點選Validate

3. 擴充 entity 新增keyword & Synonyms

:::warning
如何建入entity,是根據你要怎麼去使用為主。程式與wit.ai串起來後,判斷後是傳回keyword。
`再舉一個例子,匯率 如下`

:::
4. 到這邊就訓練完成。可以反覆使用 sentence 去讓wit 更準確的判斷entity
###### 備註
> 其餘還有 stories等進階功能,詳細可以參閱 [wit.ai docs](https://wit.ai/docs)
---
### 與 line bot 串接
1. nodejs 安裝 node-wit套件 [node-wit官方文件](https://github.com/wit-ai/node-wit)
```
npm install --save node-wit
```
2. 至  拿取accessToken

3. 設定好 wit
```javascript=
const {Wit, log} = require('node-wit');
// generate wit bot
const witBot = new Wit({
accessToken: 'your accessToken',
logger: new log.Logger(log.DEBUG), // optional
});
```
4. 看到官方文件,基礎版的 我們只需要用到 message api

:::info
需要注意的是,到時候程式是直接去跟wit拿,是屬於非同步動作。因此我們需要用到 ES6 的 Promise 去做處理。 也可以用到更新的 async/await (不過只有node 7.0版本以上才支援)
:::
> :star2: 關於 Promise - 就是進階版的 callback 可以[避免掉 callback hell](http://huli.logdown.com/posts/292655-javascript-promise-generator-async-es6) 有更好的可讀性, 推薦一個簡單易懂的 [網站](http://azu.github.io/promises-book/#introduction) & [文章](http://eddychang.me/blog/javascript/88-promise-basic-usage.html)
> > :eyes: 更進階一點的 可以了解看看 ES6 generator 的 [yield](http://huli.logdown.com/posts/292655-javascript-promise-generator-async-es6) 是什麼
> :star2: 關於 async/await 最新的callBack 可以看 [這裡](https://jigsawye.com/2016/04/18/understanding-javascript-async-await/) 若可以使用async/await 程式會更加簡單好讀 :relaxed:
5. 用message api
```javascript=
// messageText - line bot user 傳入的 text
witBot.message(messageText, {})
.then((data) => {
// data - wit.ai 分析過後的資料回傳回來的 object (請見下方)
console.log('Yay, got Wit.ai response: ' + JSON.stringify(data));
console.log('result in msg:' + data.msg_id);
const entities = {};
// 只需要entities 所以稍做處理
Object.keys(data.entities).forEach((entityKey) => {
entities[entityKey] = data.entities[entityKey][0].value;
});
})
.catch(console.error);
```
> 補充 [Object.keys](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) [使用方式](http://stackoverflow.com/questions/8763125/get-array-of-objects-keys)
wit message 處理好後丟回來的object
```jsx=
{
"msg_id": "79171cbb-afbe-4ff9-aaea-a97ed6aef3bc",
"_text": "請告訴我日幣匯率是多少",
"entities": { // 有兩個entities
"ask": [
{
"confidence": 1,
"type": "value",
"value": "告訴我" //這邊我毎建一個word 就當作是keyword
//所以直接回回來的就是從message裡抓到的
},
{
"confidence": 1,
"type": "value",
"value": "是多少"
}
],
"exchangeRate": [ //日幣匯率
{
"confidence": 1,
"type": "value",
"value": "JPY" // return 回來的是 keyword
}
]
}
}
```
6. 接下來就是,要怎麼把非同步處理好的 `entities` 這個object 回回去給主程式呢?
**use Promise** return new Promise回去給主程式
```javascript=
function getIntent(messageText) {
return new Promise(function(resolve, reject){
witBot.message(messageText, {})
.then((data) => {
console.log('Yay, got Wit.ai response: ' + JSON.stringify(data));
console.log('result in msg:' + data.msg_id);
const entities = {};
Object.keys(data.entities).forEach((entityKey) => {
entities[entityKey] = data.entities[entityKey][0].value;
});
resolve(entities); // callback, return result to main function
})
.catch(console.error);
})
}
```
主程式
```javascript=
getIntent(msg).then(function(entities){
// entities 就是我們需要的主要資料了
// 邏輯部分
}.catch((error) => console.log(error));
```
> 若需要再拿 entities 的 keyword 去做爬蟲,也可以使用Promise
---
:sparkles: 若想使用 async / await 程式碼如下
```javascript=
async function getIntent(messageText) {
const result = await witBot.message(messageText);
const entities = {};
Object.keys(result.entities).forEach((entityKey) => {
entities[entityKey] = result.entities[entityKey][0].value;
});
const newResult = { ...result, entities };
if (!newResult.entities.intent) {
newResult.entities.intent = 'None';
}
return newResult;
}
```
> [name=Hyman Chen]
主程式
```javascript=
const result = await getIntent(messageText);
```
###### 真的簡單很多...
---
wit 還有一個好用的功能 就是 Inbox 他會紀錄所有由外部傳入的句子 你可以藉此訓練你的wit
點選 

---
教學就到此,若與line bot串起來的話,真的會增加不少彈性
