聊天機器人應用實務
Line Bot Again
Web Server
Line Bot
網站空間/網址?
開發語言?
架網站
- 網站開發語言: 以Flask為例
- 網址取得/轉址: ngrok
Flask+ngrok架設網站運作方式
NGROK服務
網站空間: localhost(本機)
網站開發:
Flask
網址: ngrok提供
'''
將程式碼存為一個 .py 檔案,如app.py並在命令列中執行該檔案以啟動伺服器。例如:
python app.py
則應該看到"Hello, World!"
'''
# 引入 Flask 模組
from flask import Flask
# 建立 Flask 物件
app = Flask(__name__)
# 設定路由和對應的處理函式
@app.route('/')
def home():
return 'Hello, World!'
# 啟動 Flask 伺服器
if __name__ == '__main__':
app.run()
pip install flask
安裝Flask套件
Flask+ngrok架設網站網站
app.py
Flask+ngrok架設網站使用ngrok
下載並安裝 ngrok
Flask+ngrok架設網站使用ngrok
前往 https://ngrok.com/ 註冊免費帳號
登入後即可看到authtoken
Flask+ngrok架設網站使用ngrok
在命令列中,切換到你的 ngrok 安裝目錄
ngrok http 5000
告知 ngrok 監聽本機 5000 埠號(Flask 的預設埠號)
你的公開網址
程式必須維持執行
ngrok config add-authtoken 你的authtoken
設定一次即可
Flask+ngrok架設網站Colab
from google.colab import drive
drive.mount('/content/drive', force_remount=True) # 名稱
!mkdir -p /drive # 在colab環境建立drive資料夾
#umount /drive
!mount --bind /content/drive/MyDrive/drive # 綁定雲端硬碟
!mkdir -p /drive/ngrok-ssh # 建立資料夾
!mkdir -p ~/.ssh
1. 新建Colab筆記本,如ngrok_hello,將此筆記本接上雲端硬碟
ngrok_hello.ipynb
!mkdir -p /drive/ngrok-ssh
%cd /drive/ngrok-ssh
!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -O ngrok-stable-linux-amd64.zip
!unzip -u ngrok-stable-linux-amd64.zip
!cp /drive/ngrok-ssh/ngrok /ngrok
!chmod +x /ngrok
ngrok_hello.ipynb
2.下載ngrok,安裝至雲端硬碟
Flask+ngrok架設網站Colab
!/ngrok authtoken 貼上你的authtoken
3.設定authtoken
ngrok_hello.ipynb
from flask import Flask
from flask_ngrok import run_with_ngrok
app = Flask(__name__)
run_with_ngrok(app)
@app.route("/")
def home():
return f"<h1>hello World!</h1>"
app.run()
ngrok_hello.ipynb
5. 呼叫run_with_ngrok()執行web app
!pip install flask_ngrok
4.安裝flask_ngrok
架網站web hook
- Line Messaging API複習
1. 前往LINE Developers Console建立Channel
(使用Messaging API)
2. 完成Flask Web程式端的設定
3. 從ngrok執行端取得Line所需之 web hook URL
4. 完成Line web hook設定(Line 平台端)
整合Line平台Messaging API
步驟1: 建立Line Channel使用Line Messaging API
1. 前往LINE Developers Console建立Channel
你的系統(如Dialogflow)
Channel是LINE平台與你的系統之間的「溝通路徑」
(HTTP協定、採用「訂閱」機制)
建立Line Channel使用Line Messaging API
1-1. 登入LINE Developers Console
建立Line Channel使用Line Messaging API
1-2. 以開發者身份註冊(僅需設定一次)
輸入姓名、Email
建立Line Channel使用Line Messaging API
1-3. 建立新的Provider
輸入Provider名稱
建立Line Channel使用Line Messaging API
1-4. 建立Messaging API channel (2/3)
建立Line Channel使用Line Messaging API
1-4. 建立Messaging API channel (3/3)
建立Line Channel使用Line Messaging API
1-5. 確認Channel已成功建立
步驟2: 設定Channel secret, Channel access token環境變數
建議名稱
用於Flask程式中
從Line Developers Console複製過來
確定後,再開啟CMD
from flask_ngrok import run_with_ngrok
from flask import Flask, request
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
# 載入 json 標準函式庫,處理回傳的資料格式
import json
import os
app = Flask(__name__)
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = os.environ.get('CHANNEL_ACCESS_TOKEN')
secret = os.environ.get('CHANNEL_SECRET')
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
msg = json_data['events'][0]['message']['text'] # 取得 LINE 收到的文字訊息
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
line_bot_api.reply_message(tk,TextSendMessage(msg)) # 回傳訊息
print(msg, tk) # 印出內容
except:
print(body) # 如果發生錯誤,印出收到的內容
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
run_with_ngrok(app) # 串連 ngrok 服務
app.run()
app.py
步驟3: 執行Flask App, 啟動ngrok服務
若出現[WinError 10061] 無法連線,因為目標電腦拒絕連線
代表先前Flask App未關閉,必須手動關閉服務
1.查詢所有執行中程序(process), 依字串':5000'過濾
netstat -ano | findstr :5000
2. 終止程序,最右邊數字為process id
taskkill /PID 最右邊數字 /F
步驟3: 執行Flask App, 啟動ngrok服務
ngrok http 5000
ngrok config add-authtoken 你的authtoken
找到你的ngrok程式所在資料夾,設定authtoken(只須做一次)
Flask App正常執行後,綁定ngrok服務
複製ngrok提供的網址
步驟4: Line後台設定web hook網址
# OpenAI 函式庫
from openai import OpenAI
# Flask函式庫
from flask import Flask, request
# 載入 LINE Message API 相關函式庫
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import (
InvalidSignatureError
)
from linebot.v3.messaging import (
Configuration,
ApiClient,
MessagingApi,
ReplyMessageRequest,
TextMessage
)
from linebot.v3.webhooks import (
MessageEvent,
TextMessageContent
)
# 讀取環境變數用
import os
#... web hook 程式
app.py (part 1: importing)
Webhook程式 import
# ...import 略(見上頁)...
app = Flask(__name__)
# 建立OpenAI Client, 需有環境變數OPENAI_API_KEY
client = OpenAI()
# 從Line Developers Console取得Line Messaging API Keys
# 一樣設定為環境變數
access_token = os.environ.get('CHANNEL_ACCESS_TOKEN')
secret = os.environ.get('CHANNEL_SECRET')
# 設定呼叫Line ApiClient所需環境: client server溝通必須有合法的access_token
configuration = Configuration(access_token=access_token)
# 建立Web hook handler,必須有合法的channel secret
handler = WebhookHandler(secret)
# ...web hook程式 略...
# ...
# ...
if __name__ == "__main__":
app.run()
Webhook程式 OpenAI, Line Web hook準備工作
app.py (part 2: 準備工作)
# ...import 略(見上頁)...
# ...準備工作openai client, line messaging api參數等 略...
@app.route("/callback", methods=['POST'])
def callback():
# 取得 X-Line-Signature header數值
signature = request.headers['X-Line-Signature']
# 取得 request body 的文字內容
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
try:
# 處理 webhook body內容,交由@handler.add, handler.default處理
handler.handle(body, signature)
except InvalidSignatureError:
app.logger.info("Invalid signature. 檢查Channel access token與channel secret設定")
abort(400)
return 'OK'
# ...web hook handler 略
# ....
Webhook程式 回呼函式-主程式
app.py (part 3: callback)
# ...import 略(見上頁)...
# ...準備工作openai client, line messaging api參數等 略...
# ...web hook handler主程式 略
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
msg = event.message.text
ai_msg = msg[:6].lower() # 取出文字的前五個字元,轉換成小寫
reply_msg = ''
if ai_msg == 'hi ai:': # 取出文字的前五個字元是 hi ai:
# 將第六個字元之後的訊息發送給 OpenAI
response = client.chat.completions.create(
model='gpt-3.5-turbo',
messages=[ {'role': 'user', 'content': msg[6:]}],
max_tokens=256,
temperature=0.5,
)
# 接收到回覆訊息後,移除換行符號
reply_msg = response.choices[0].message.content.replace('\n','')
else:
reply_msg = msg
text_message = TextMessage(text=reply_msg)
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(reply_token=event.reply_token,messages=[text_message])
)
# ....
Webhook程式 回呼函式-handler
app.py (part 4: handler)
from openai import OpenAI
import os
from flask import Flask, request
# 載入 LINE Message API 相關函式庫
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import (
InvalidSignatureError
)
from linebot.v3.messaging import (
Configuration,
ApiClient,
MessagingApi,
ReplyMessageRequest,
TextMessage
)
from linebot.v3.webhooks import (
MessageEvent,
TextMessageContent
)
import json
app = Flask(__name__)
client = OpenAI() # for OpenAI API calls
access_token = os.environ.get('CHANNEL_ACCESS_TOKEN')
secret = os.environ.get('CHANNEL_SECRET')
configuration = Configuration(access_token=access_token)
handler = WebhookHandler(secret)
@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)
#json_data = json.loads(body)
#print(json_data)
try:
# handle webhook body
handler.handle(body, signature)
except InvalidSignatureError:
app.logger.info("Invalid signature. 檢查Channel access token與channel secret設定")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
msg = event.message.text
# 取出文字的前五個字元,轉換成小寫
ai_msg = msg[:6].lower()
reply_msg = ''
# 取出文字的前五個字元是 hi ai:
if ai_msg == 'hi ai:':
# 將第六個字元之後的訊息發送給 OpenAI
response = client.chat.completions.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'user', 'content': msg[6:]}],
max_tokens=256,
temperature=0.5,
)
# 接收到回覆訊息後,移除換行符號
reply_msg = response.choices[0].message.content.replace('\n','')
else:
reply_msg = msg
text_message = TextMessage(text=reply_msg)
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[text_message]
)
)
if __name__ == "__main__":
app.run()
app.py (完整)
其他範例
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
msg = event.message.text
if not str(msg).startswith('/'): # 如果開頭不是/線字元,代表非指令
reply_msg = msg # 非指令直接回覆
else:
tokens = str(msg).split() # 空白字元分割
command = tokens[0]
reply_msg = ''
if command == '/說笑話':
response = client.chat.completions.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'system', 'content': '你是說笑話專家'}, # 角色
{'role': 'user', 'content': '說一則笑話'}], # 指令
max_tokens=256,
temperature=0.5,
)
# 接收到回覆訊息後,移除換行符號
reply_msg = response.choices[0].message.content.replace('\n','')
else:
reply_msg = msg
text_message = TextMessage(text=reply_msg)
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,messages=[text_message]
)
)
# ....
說笑話 (部份)
from openai import OpenAI
client = OpenAI(
api_key= "你的API_KEY"
)
response = client.chat.completions.create(
model = "gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "建立一個包含 8 個問題的清單,用於訪問一位科幻作家。"
}
],
temperature=0.5, # 回應變化的多樣性,0:變化最少, 1:變化最多
max_tokens=1024 # 最多1024個token
)
print(response.choices[0].message.content) # 訊息
範例:面試提問generation生成
聊天機器人應用實務
By Leuo-Hong Wang
聊天機器人應用實務
- 279