---
# System prepended metadata

title: AI LINE Bot練功坊-L16 Azure AI Language 交談語言理解機器人
tags: [Python, Line Bot]

---

AI LINE Bot練功坊-L16 Azure AI Language 交談語言理解機器人
===
Azure AI Language
---
Azure AI Language是一個雲端式服務，可提供自然語言處理 (NLP) 功能，用於了解和分析文字，包括的項目有：
* 具名實體辨識 (NER)
* 語言偵測
* 情感分析與意見挖掘
* 摘要
* 關鍵字擷取
* 交談語言理解
* 問題解答

>Reference：https://learn.microsoft.com/zh-tw/azure/ai-services/language-service/overview

Conversational Language Understanding (CLU) 交談語言理解
---
當我們輸入一句話給機器人並且想要它知道我們的用意是甚麼就可以透過CLU，CLU有兩個重要的名詞分別是 intent 和 entity
### intent意圖
就是判斷一句話的用意是甚麼，舉裡來說：
```
今天下午我想要跟張三去看鬼滅之刃
```
這句話的意圖就會是【看電影】

### entity實體
就是句子中重要的資訊是甚麼，以剛剛的句子來說可能會有幾個重要資訊
* 時間：今天下午
* 跟誰去：張三
* 電影名稱：鬼滅之刃

當然你想要的重要資訊不一定是這些，你有可能想要把時間再細分成"日期"和"時間"，也就是把 "今天下午" 拆成 "今天" 和 "下午"

### 訓練語句
定義好 intent 和 entity 後，需要提供不同類型的句子作為訓練資料，讓模型學習如何辨識和理解不同的意圖和實體。舉例來說，針對剛才提到的「看電影」的意圖，我們可以再準備以下訓練語句：


<h3><span style="background-color:#effa5a">明天晚上</span>我要和<span style="background-color:#5eff89">李四</span>去看<span style="background-color:#5eeaff">名偵探柯南</span></h3>

intent: 看電影
entity: 
時間：<span style="background-color:#effa5a">明天晚上</span>
跟誰去：<span style="background-color:#5eff89">李四</span>
電影名稱：<span style="background-color:#5eeaff">名偵探柯南</span>

---

<h3><span style="background-color:#effa5a">7/5</span>和<span style="background-color:#5eff89">小華</span>一起去看<span style="background-color:#5eeaff">腦筋急轉彎</span></h3>

intent: 看電影
entity: 
時間：<span style="background-color:#effa5a">7/5</span>
跟誰去：<span style="background-color:#5eff89">小華</span>
電影名稱：<span style="background-color:#5eeaff">腦筋急轉彎</span>

---

<h3>我跟<span style="background-color:#5eff89">小明</span><span style="background-color:#effa5a">七月十五</span>要一起看<span style="background-color:#5eeaff">排球少年</span></h3>

intent: 看電影
entity: 
時間：<span style="background-color:#effa5a">七月十五</span>
跟誰去：<span style="background-color:#5eff89">小明</span>
電影名稱：<span style="background-color:#5eeaff">排球少年</span>

---

### Azure的entity有四種類型
* Learned
![image](https://hackmd.io/_uploads/S1oUwDALC.png)

* List
![image](https://hackmd.io/_uploads/ryr_wwR8C.png)

* Prebuild
![image](https://hackmd.io/_uploads/By3tDwC8A.png)

* Regex
![image](https://hackmd.io/_uploads/B1VqPDC80.png)

>Reference：https://learn.microsoft.com/en-us/azure/ai-services/luis/concepts/entities
>Reference：https://learn.microsoft.com/zh-tw/azure/ai-services/language-service/conversational-language-understanding/overview

## 安裝開發環境
https://hackmd.io/@ntuebigdata/setup-linebot-development-environment#建立Python虛擬環境
## 註冊LINE官方帳號
https://hackmd.io/@ntuebigdata/create-a-line-official-account#1-建立Line-Developers帳號
## 註冊教育版的Azure帳號
https://hackmd.io/@ntuebigdata/azure-basic-introduction#註冊教育版的Azure帳號

---

## 建立語言服務

![image](https://hackmd.io/_uploads/Sye18zhiI0.png)
![image](https://hackmd.io/_uploads/S11Nmno8C.png)
![image](https://hackmd.io/_uploads/rkOE73iIC.png)
![image](https://hackmd.io/_uploads/SyiN72sLC.png)

要注意不是所有地區都有F0以及Conversation Language Understanding可以使用
:::warning
:bulb:下方連結的區域要Authoring有打勾的才有支援CLU
>Reference：https://learn.microsoft.com/en-us/azure/ai-services/language-service/concepts/regional-support#conversational-language-understanding-and-orchestration-workflow
:::

![image](https://hackmd.io/_uploads/H1xHQ2o8A.png)
![image](https://hackmd.io/_uploads/Bk8cQ2iI0.png)
![image](https://hackmd.io/_uploads/B1vt7nsL0.png)
![image](https://hackmd.io/_uploads/HJFsQ3oIA.png)
![image](https://hackmd.io/_uploads/S10omnsLR.png)
![image](https://hackmd.io/_uploads/BJZhX3sLA.png)
![image](https://hackmd.io/_uploads/HJ7n73oIR.png)
![image](https://hackmd.io/_uploads/S1H2mhoL0.png)
這裡的名稱在後面建立LineBot會用到
![image](https://hackmd.io/_uploads/S11IbO680.png)
![image](https://hackmd.io/_uploads/H1FwZda80.png)
![image](https://hackmd.io/_uploads/r1itWdTIA.png)
![image](https://hackmd.io/_uploads/Sk2jbOTUA.png)
![image](https://hackmd.io/_uploads/H1YVMuTLC.png)
![image](https://hackmd.io/_uploads/H1N1mO6UA.png)
![image](https://hackmd.io/_uploads/S1g47_aLA.png)
![image](https://hackmd.io/_uploads/HJ6_mdTL0.png)
![image](https://hackmd.io/_uploads/S1ZofdpIA.png)
![image](https://hackmd.io/_uploads/HJQifO6LC.png)
![image](https://hackmd.io/_uploads/H1AiQ_pLR.png)
![image](https://hackmd.io/_uploads/BkyamuTUA.png)
![image](https://hackmd.io/_uploads/SJjJNd6IC.png)
![image](https://hackmd.io/_uploads/HJWQdupUR.png)
這裡的名稱也要記住，後面建立LineBot會用到
![image](https://hackmd.io/_uploads/SJIIuO6U0.png)
![image](https://hackmd.io/_uploads/H1l3uOp80.png)
![image](https://hackmd.io/_uploads/HJC2O_p8A.png)
![image](https://hackmd.io/_uploads/Byl45dTL0.png)
![image](https://hackmd.io/_uploads/ry9r9uTLR.png)

## 撰寫程式

### 程式準備

新增一個專案資料夾，並在專案資料夾內新增`.env`、`requirements.txt`及`app.py`檔案，並貼上以下內容
![image](https://hackmd.io/_uploads/Hkskg4DBR.png)

<font style="background:yellow">requirements.txt</font>
```
line-bot-sdk
flask
azure-ai-translation-text
```

<font style="background:yellow">app.py</font>
```python
from flask import Flask, request, abort
from linebot.v3 import (
    WebhookHandler
)
from linebot.v3.exceptions import (
    InvalidSignatureError
)
from linebot.v3.webhooks import (
    MessageEvent,
    LocationMessageContent
)
from linebot.v3.messaging import (
    Configuration,
    ApiClient,
    MessagingApi,
    ReplyMessageRequest,
    TextMessage
)
import os
#Azure CLU
from azure.core.credentials import AzureKeyCredential
from azure.ai.language.conversations import ConversationAnalysisClient

app = Flask(__name__)

CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
clu_endpoint = os.getenv("ENDPOINT")
clu_key = os.getenv("API_KEY")
project_name = os.getenv("PROJECT_NAME")
deployment_name = os.getenv("DEPLOYMENT_NAME")    

line_handler = WebhookHandler(CHANNEL_SECRET)
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # parse webhook body
    try:
        line_handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'


@line_handler.add(event=MessageEvent, message=LocationMessageContent)
def handle_location_message(event):
    address = event.message.address
    result = analyze_address(address)
    entities = result['prediction']['entities']

    messages = []
    if len(entities) == 2 and entities[0]['category'] == 'city' and entities[1]['category'] == 'town':
        city = result['prediction']['entities'][0]['text']
        town = result['prediction']['entities'][1]['text']
        messages.append(TextMessage(text=f"你傳送的位址資訊的城市:{city}"))
        messages.append(TextMessage(text=f"你傳送的位址資訊的鄉鎮:{town}"))
    else:
        messages.append(TextMessage(text="無法辨識你傳送的位址資訊"))

    with ApiClient(configuration) as api_client:
        line_bot_api = MessagingApi(api_client)
        line_bot_api.reply_message_with_http_info(
            ReplyMessageRequest(
                reply_token=event.reply_token,
                messages=messages
            )
        )

def analyze_address(address):
    credential = AzureKeyCredential(clu_key)
    client = ConversationAnalysisClient(clu_endpoint, credential)
    with client:
        result = client.analyze_conversation(
            task={
                "kind": "Conversation",
                "analysisInput": {
                    "conversationItem": {
                        "participantId": "1",
                        "id": "1",
                        "modality": "text",
                        "language": "zh-hant",
                        "text": address
                    },
                    "isLoggingEnabled": False
                },
                "parameters": {
                    "projectName": project_name,
                    "deploymentName": deployment_name,
                    "verbose": True
                }
            }
        )
    return result['result']

if __name__ == "__main__":
    app.run()
```

<font style="background:yellow">.env</font>
```python=
CHANNEL_ACCESS_TOKEN = "XXX"
CHANNEL_SECRET = "XXX"
API_KEY = "XXX"
ENDPOINT = "XXX"
PROJECT_NAME = "XXX"
DEPLOYMENT_NAME = "XXX"
```
貼上之後記得修改幾個地方：
* Line Developers的Channel Access Token
* Line Developers的Channel Secret
* 剛剛建立Azure資源的金鑰
* 剛剛建立Azure資源的端點
* 剛剛建立Azure語言的project的名稱
* 剛剛建立Azure服務後部署的deplotment的名稱

---

## 測試效果
在聊天室點選定位功能，會回傳一個縣市的訊息以及一個鄉鎮的訊息

![image](https://hackmd.io/_uploads/S19wwZEPA.png)
![image](https://hackmd.io/_uploads/HJxQDWVDC.png)
![image](https://hackmd.io/_uploads/BkiBwZVP0.png)


>Reference：https://azure.microsoft.com/zh-tw/pricing/details/cognitive-services/language-service/

Youtube 課程影片
---
<iframe width="560" height="315" src="https://www.youtube.com/embed/VOiZ1de_7e4?si=uSdU2dDdC0z5Wpt6" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

{%hackmd @ntuebigdata/about %}

## 相關教材連結

<div style="display: flex; justify-content:space-between;">
  <div>
    <a class="btn btn-warning" href="https://hackmd.io/@ntuebigdata/azure-AI-translator" style="color:white;width:300px;text-overflow:ellipsis;overflow:hidden">◀◀◀ L15 Azure Translator 翻譯機器人 ◀◀◀</a>
  </div>
  <div>
    <a class="btn btn-warning" href="https://hackmd.io/@ntuebigdata/azure-AI-translator" style="color:white;width:300px;text-overflow:ellipsis;overflow:hidden">◀◀◀ L15 Azure Translator 翻譯機器人 ◀◀◀</a>
  </div>
</div>