iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 10
1
Modern Web

從LINE BOT到資料視覺化:賴田捕手系列 第 10

第 10 天:LINE BOT SDK:初始化聊天機器人

第 10 天:LINE BOT SDK:初始化聊天機器人

  昨天我們把該註冊的帳號都註冊完了,今天就可以好好的來利用暴力破解法創造我們第一個 LINE 聊天機器人囉。為什麼說是暴力破解法呢?因為創造 LINE 聊天機器人的過程中,其實涉及了不少 HTTP Request、HTTP Response,以及GET、POST,等等現在依然很困擾著我的概念,以及許多 Python 模組的應用,要在一時三刻之內說明清楚,我的話是辦不到的。有興趣的話,卡米狗的作者在這方面討論的非常詳細➀,我也是拜讀他的大作走過來的。不過想想我們最初的目的吧,我們最終目標是要成為草泥馬訓練大師,而不是網路大師。只要能做出幫我們好好照顧草泥馬的 LINE 聊天機器人,對這些異次元的概念一知半解又有何妨(X)。

基本 LINE 聊天機器人的程式碼

  網路上不少地方都可以找到 LINE 聊天機器人相關的程式碼。各位強者寫出來的 LINE 聊天機器人其功能五花八門,有些可以幫你查天氣,有些可以幫你查美女圖片,有些甚至可以幫你查美女的 LINE(?)。不過這之中,都有一個最核心的部分,就是接收 LINE 的資訊,向 LINE 宣告這名機器人存在的程式碼。不囉嗦,直接來看看它的核心架構。

# 載入需要的模組
from __future__ import unicode_literals
import os
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError

app = Flask(__name__)

# LINE 聊天機器人的基本資料
line_bot_api = LineBotApi('聊天機器人的 Chennel access token')
handler = WebhookHandler('聊天機器人的 Channel secret')

# 接收 LINE 的資訊
@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']

    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

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

  上面那段程式碼真是看得令人眼花撩亂,是吧?我們先挑其中 3 個部份來講:

  • 載入需要的模組
    這是第一部分。其中最重要的兩個模組是flasklinebotflask是為了架設網站用的,而linebot應該就不用我再多說了吧,當然是 LINE 提供給 Python 讓我們控制 LINE 聊天機器的的模組。

  • LINE 聊天機器人的基本資料
      你登入你的 LINE 需要輸入帳號密碼,聊天機器人登入它的 LINE 當然也要。要去哪裡找到這些資料呢?請到我們昨天在 LINE Developers 裡創立的 Provider 的 Channel 裡,在 "Messaging Settings" 裡,有一欄 "Channel access token",如圖一。如果是空白的,右邊有個 "Issue" 按下去,LINE 會幫你產生一個。"Channel secret" 則是在 "Channel ID" 下面一欄,如圖二。這兩個都是很重要的聊天機器人個資,請小心保存。如果懷疑資料外洩了,也不要太緊張,按 "Issue",請 LINE 重新發給你一個。

https://ithelp.ithome.com.tw/upload/images/20190918/201201785aaHcCdHS8.png
圖一、Channel access token

https://ithelp.ithome.com.tw/upload/images/20190918/20120178l7MYvAXezX.png
圖二、Channel secret

  • 接收 LINE 的資訊
      首先,第一行程式碼@app.route("/callback", methods=['POST'])就有得講了。簡而言之,這是flask模組特有的方法。因為 LINE 確認聊天機器人存在的方法,以及所有 LINE 的資訊,就是要送到一個叫 "/callback" 的地方。因此我們利用這行程式碼,告訴我們的聊天機器人,當 LINE 來 "/callback" 敲門的時候,要做什麼動作。基本上,這段程式碼是一個標準流程➁,我們之後也鮮少機會去更動它。因此你注意到了嗎,這段程式碼是非常重要,但我們可以不知道它在寫什麼的一段程式碼。當然,如果有時間我們再回過頭來討論,不過今天先講別的。

Heroku 建立一個專案

  昨天已經註冊好 Heroku 也安裝了 Heroku CLI,那麼今天開啟命令提示字元(cmd)之後,輸入heroku login,應該就會看到如下畫面:

C:\Users\MyName>heroku login
heroku: Enter your login credentials
Email:

  請輸入你的 Heroku 帳號跟密碼。成功的話,應該會像這樣:

C:\Users\MyName>heroku login
heroku: Enter your login credentials
Email: 你的 Heroku 帳號
Password: *************
Logged in as 你的 Heroku 帳號

  利用heroku create的指令創造一個 Heroku 應用:

C:\Users\MyName>heroku create 你-APP-的名字
Creating ⬢ 你-APP-的名字... done
https://你-APP-的名字.herokuapp.com/ | https://git.heroku.com/你-APP-的名字.git

  首先 Heroku 會確認"你-APP-的名字"是否有人使用,若沒有,那麼就會幫你建立一個伺服器,而伺服器的首頁在這裡:https://你-APP-的名字.herokuapp.com/。

  Heroku 的應用程式需要幾個特殊的檔案,讓它知道你所啟用的應用程式類型,需要在什麼環境下,有哪些條件,有哪些附加的套件等等的。這些特殊的檔案分別是Procfilerequirements.txt,以及runtime.txt。我一項一項介紹:

  • Procfile
      告訴 Heroku 我們的應用程式是哪種類型的應用程式,以及需要執行哪個檔案。以我們目前的 LINE 聊天機器人而言,是 web 類型的應用程式,假設我們所執行的檔案是app_core,那麼我們的Procfile裡面會寫成這樣:
web: gunicorn app_core:app –preload

  需要注意的是,Procfile是一個沒有副檔名的檔案,你可以先用記事本將上面那段文字存成Procfile.txt之後,再把檔案重新命名成Procfile

  • requirements.txt
      告訴 Heroku 需要安裝那些套件。這裡比較有趣的是,我們的電腦本身沒有安裝這些套件也沒關係,Heroku 提供的伺服器才是我們的應用程式真正運行的地方,因此 Heroku 那邊有裝就可以。而我目前的requirements.txt裡面是長這樣的:
Flask==1.1.1
gunicorn==19.9.0
line-bot-sdk==1.14.0

  哈哈注意到了嗎,基本上都是我沒有安裝的套件。

  • runtime.txt
      這個檔案則是告訴 Heroku 我們要用哪種版本的 Python 來執行我們的應用程式。通常來說,沒有也沒關係,Heroku 聰明的很,會選擇預設的版本,通常是較穩定的版本。而我目前是這樣:
python-3.6.9

  所有的這些設定檔,包括Procfilerequirements.txt、以及runtime.txt,必須要同時放在 "Heroku 可以讀到的最外層資料夾" 裡面,而Procfile要讀的 Python 檔案也要放在一起。以我而言,我都把這四個檔案放在 "alpaca_fighting" 這個資料夾裡面。而 "alpaca_fighting" 就是我希望 "Heroku 可以讀到的最外層資料夾"。如果我在 "alpaca_fighting" 這個位置開啟命令提示字元,並輸入tree /F,應該會看起來像這樣:

D:\alpaca_fighting>tree /F
Folder PATH listing
Volume serial number is 9C33-6XDD
D:.
    Procfile
    requirements.txt
    runtime.txt
    app_core.py

No subfolders exist

Git push

  現在,我們要透過 Git 將我們的資料夾推向 Heroku 了。講白話一點,就是我們要把我們存放有聊天機器人程式碼的資料夾傳到 Heroku 幫我們設立好的伺服器上面了。不懂也沒關係,推久了就會有感覺?
  第一件事,確認我們是把資料夾推到這邊 https://git.heroku.com/你-APP-的名字.git。先從命令提示字元裡,進到你想要推向 Heroku 的資料夾裡,然後初始化 Git,如下:

D:\alpaca_fighting>git init
Initialized empty Git repository in D:/alpaca_fighting/.git/
D:\alpaca_fighting>git init
Reinitialized existing Git repository in D:/alpaca_fighting/.git/

  第一次初始化 Git 應該會是上面那種情況。以我而言,我想要將D:\alpaca_fighting這個資料夾推向 Heroku,那麼我就進到 "alpaca_fighting" 裡,然後輸入git init

  接著告訴 Git 我要推向 Heroku,而且是推向 "你-APP-的名字" 那邊:

D:\alpaca_fighting>heroku git:remote -a 你-APP-的名字
set git remote heroku to https://git.heroku.com/你-APP-的名字.git

  輸入git add .,先準備好清單,請 Git 推,所有檔案都推。

D:\alpaca_fighting>git add .
warning: LF will be replaced by CRLF in app_core.py.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in app_echo.py.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in requirements.txt.
The file will have its original line endings in your working directory

  回應不重要,只是 Git 的一些說明。接著輸入git commit -m "一些註解","一些註解" 你愛打什麼都可以。因為這是我們初始化的第一推,所以我說 "init"。

D:\alpaca_fighting>git commit -m "init"
[master (root-commit) 63788c6] init
 4 files changed, 90 insertions(+)
 create mode 100644 Procfile
 create mode 100644 app_core.py
 create mode 100644 requirements.txt
 create mode 100644 runtime.txt

  最後就是push了!

D:\alpaca_fighting>git push heroku master
… 以下略
remote: Verifying deploy... done.
To https://git.heroku.com/phoebe-takescareof-alpaca.git

  中間會跳出一些訊息蠻有趣的,大家可以試著閱讀一下。今天因為時間有點趕,我就先不解釋了。最後看到Verifying deploy… done,就是成功透過 Git 將我們的資料夾推向 Heroku 了!

LINE Developers

  最後的最後,回到 LINE Developers 上。登入,進到我們昨天創造的 Provider 的 Messaging API 裡。有一個 "Messaging Settings" 的設定區,如圖三,記得要將紅框處的 "Use webhooks" 用右邊的 "Edit" 改成 "Enabled"。在綠框處 "Webhook URL" 透過右邊的 "Edit" 改成 "https://你-APP-的名字.herokuapp.com/callback"。按下 "Verify",如果出現"Success" 那就是成功了。

https://ithelp.ithome.com.tw/upload/images/20190918/20120178i4i6ILDGKr.png
圖三、Messaging Settings

PS

最後放上學你說話的 LINE 聊天機器人程式碼,有興趣的人可以試看看,明天我們再仔細翻譯翻譯。

from __future__ import unicode_literals
import os
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError

from linebot.models import MessageEvent, TextMessage, TextSendMessage

app = Flask(__name__)

# LINE 聊天機器人的基本資料
line_bot_api = LineBotApi('聊天機器人的 Chennel access token')
handler = WebhookHandler('聊天機器人的 Channel secret')

# 接收 LINE 的資訊
@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']

    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

# 學你說話
@handler.add(MessageEvent, message=TextMessage)
def echo(event):
    
    if event.source.user_id != "Udeadbeefdeadbeefdeadbeefdeadbeef":
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=event.message.text)
        )

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

參考資料

卡米狗
➁ 官方 LINE-Bot-SDK
➂ 官方 Heroku Create APP
➃ Heroku 網站部署


上一篇
第 09 天:LINE BOT SDK:註冊!註冊!註冊!
下一篇
第 11 天:LINE BOT SDK:應用程式編程介面
系列文
從LINE BOT到資料視覺化:賴田捕手30

2 則留言

3
hiro08081
iT邦新手 5 級 ‧ 2020-02-01 16:25:56

請問我在執行git push heroku master 時遇到了
! [remote rejected] master -> master (pre-receive hook declined)
這個問題,請問是遇到了什麼狀況呢?
python版本是3.7.4
我requirement.txt文件是跟您設定的一樣

你好 ~

設定檔的檔名是 requirements.txt 而不是 requirement.txt
要多一個 s 在後面喔

你參考看看 如果還是無法解決我們再討論看看~

asd95022 iT邦新手 5 級 ‧ 2020-03-06 15:35:36 檢舉

你好 我也同樣出現

To https://git.heroku.com/diudiubot.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://git.heroku.com/diudiubot.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

這是確認後的分支
D:\LineBot\alpaca_fighting>git branch -vv

  • master dd3f966 LINEBOT

文件中的資料為
D:\LineBot\alpaca_fighting>tree /F
列出磁碟區 DATA 的資料夾 PATH
磁碟區序號為 5A12-0DFC
D:.
│ app_core.py
│ Procfile
│ requirements.txt
│ runtime.txt

└─.vs
ProjectSettings.json
slnx.sqlite

你好 ~
抱歉回覆來的慢了點。

再一個抱歉,看你的敘述我也想不出問題可能在哪裡呢 QQ

查了下網路上碰到跟你相同狀況的人,可能會這麼做:
https://gitbook.tw/chapters/github/fail-to-push.html
https://noootown.wordpress.com/2015/06/19/git-first-use/

或許可以試試看?

若有什麼更新也可以再留言討論看看

0
joe94113
iT邦新手 5 級 ‧ 2020-08-03 16:17:19

不會刪抱歉

我要留言

立即登入留言