他老是話說個不停,而且最糟的是,往往都是在說一些不中聽的話。但他卻能把一件事做得很好:FlexMessage。那個傢伙能寫出最漂亮的 FlexMessage,比我認識的每一個人都還厲害。
~節錄自《賴田捕手》第十七章
昨天我們提到了利用 FlexMessage 來讓 LINE 聊天機器人創造出一個有點像是問答的環境,藉此從 Heroku Postgres 資料庫中選擇我們有興趣的其中幾筆資料。因為 FlexMessage 實在太有趣了,而昨天我又講得太匆忙,因此今天我們就來仔細的了解下 FlexMessage。我會從 FlexMessage 的基本架構開始,如何方便的寫出一個 FlexMessage 框架,如何將我們的參數送進 FlexMessage,到最後,如何讓 LINE 聊天機器人發送 FlexMessage,把我所知的 FlexMessage 講清楚說明白。
首先來看一看今天的目標:我希望能作出一個根據使用者訊息而產生變化的 FlexMessage。圖一是實作的結果:
圖一、陽光、沙灘、比基尼
我利用關鍵字 flex 告訴 LINE 聊天機器人我們想要看 FlexMessage,請給我 FlexMessage。LINE 聊天機器人於是給了我一個 FlexMessage,上頭有我輸入的訊息(陽光)、該訊息的英文翻譯(sunlight)、與該訊息相關的圖片,以及圖片的出處:沒錯,我們把 FlexMessage 變成了一個單字小卡!難道是空中 FlexMessage 教室?
LINE 所建立的 FlexMessage 是一個超級巨大的字典物件,對寫網頁有點概念的人應該會發現,其實這個設計就跟網頁的架構有點像。FlexMessage 的基本架構分為"header"
、"hero"
、"body"
、跟"footer"
,如圖二➀。
圖二、FlexMessage 的基本架構
要建立 FlexMessage,的一件事就是寫出包含這些基本架構的字典:
{
"type": "bubble",
"header":,
"hero":,
"body":,
"footer":
}
第一個參數 "type": "bubble"
可以想像成我們在創造一個 FlexMessage 的框架,接下來所有的基本架構都會放在這個框架裡。當然,也不是說這四樣基本架構通通都要放進去。如果你的 FlexMessage 需要一個"header"
,那就放進去"header"
。如果你的 FlexMessage 不需要"footer"
,那就不用放進去。
有了這四個基本架構之後,就可以根據你的設計,繼續在"header"
、"hero"
、"body"
、"footer"
中放入相對應的元素。這些元素也通通都是由字典物件所組成,常用的如'box'
、'image'
、'text'
、'separator'
、'button'
等等➀。
box = {'type':'box',
'layout':,
'contents':}
image = {'type':'image',
'url':,
'size':,
'aspect_ratio':,
'aspect_mode':,
'action':}
text = {'type':'text',
'text':,
'size':,
'align':,
'color':}
separator = {'type':'separator',
'type':}
button = {'type':'button',
'type':,
'style':,
'color':,
'action':}
其中'box'
裡面的'contents'
是一個由字典物件組成的清單,所以清單當中可以按照你的需求,再放入相對應的各種字典物件➁,如圖三。
圖三、'box'
裡面的'contents'
看仔細一點:
"body": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"contents": [
{"type": "separator"},
{"type": "text", "text": "我是\"box\"中的第一個物件", "size": "lg", "weight": "bold"},
{"type": "text", "text": "我是\"box\"中的第二個物件", "size": "lg", "weight": "bold", "color": "#888888"},
{"type": "separator"}
]
}
FlexMessage 當中的"box"
字典物件,裡面有一個項目"contents"
。"contents"
是一個清單,而我們可以在其中放入需要的元素。由此層層疊疊,就可以組建出我們想要的 FlexMessage。
當我們對 FlexMessage 提供的各種元素越來越熟悉之後,也許就會開始想要設計一個比較複雜的 FlexMessage。但漸漸地,隨著 FlexMessage 變得越來越複雜,我們也越來越難從一行行的程式碼想像出最後得到的結果。因此 LINE 官方很親切地提供了一個 FlexMessage 模擬器。就像寫 HTML 5 的檔案,我們可以從 codepen ➂即時看到結果,寫 FlexMessage,我們也可以藉由 FlexMessage 模擬器,馬上得知我們的程式碼還有哪裡需要修改。
首先登入 LINE Developers,來到 Provider List 的頁面,看向左手邊,看到有一排 Providers、Tools、Support,點選 Tools,在點擊畫面中央的 Flex Message Simulator,如圖四,就會跳出一個分頁供我們編輯 FlexMessage 了。
圖四、使用 FlexMessage 模擬器
從零開始設計一個 FlexMessage 這種龐大的架構並不是辦不到,但真的挺累人的。還好還又另一種方法:進入 FlexMessage 模擬器之後,點選畫面右上角的加號( + ),就可以看到 LINE 提供的幾種 FlexMessage 模板,如圖五。我們可以選擇與我們設計需求相近的模板,再從模板的程式碼開始,慢慢的修修改改去得到我們的目標。修改的過程中,也可以隨時點擊 Preview 去觀看結果,如圖六。
圖五、LINE 所提供的 FlexMessage 模板
圖六、Flex Message Simulator Preview
藉由 FlexMessage 模擬器的幫忙,我們成功的做出了想要的 FlexMessage 外觀。接下來,我們希望這個 FlexMessage 當中的元素,能夠跟著我們發送的訊息而有所改變。以圖一為例,我們希望 FlexMessage 當中"header"
的文字、"hero"
的圖片、"footer"
的連結,會因為我們發送的訊息而給出相應的回答。
怎麼做呢?那還不簡單:
text = event.message.text
translate = get_translate(event.message.text)
"header": {
"type": "box",
"layout": "horizontal",
"contents": [{"type": "text", "text": text, "size": "xl", "weight": "bold"},
{"type": "text", "text": translate, "size": "lg", "color": "#888888", "align": "end", "gravity": "bottom"}]
}
以我的「空中 FlexMessage 教室」為例,可以看到我的"header"
中有兩個變數text
跟translate
,直接把它們放在相對應的位置上就行了。當然,get_translate()
這個函數是等等我們要來定義的。再看一例:
random_img_url = get_img_url(event.message.text)
"hero": {
"type": "image",
"url": random_img_url,
"size": "full",
"aspect_ratio": "20:13",
"aspect_mode": "cover"
}
一樣的,我在"hero"
當中放入了圖片,而圖片的網址就是我們的變數,藉由我們之前寫過的get_img_url()
這個函數來獲得。這邊要稍微注意一下:如果你用的是 Python,最後要利用 line-bot-sdk-python 這個套件來執行這些程式碼的話(像我一樣),那麼"aspectRatio"
、"aspectMode"
這種用駝峰式命名➃的項目在你的 Pyhont 檔案裡都要記得改成"aspect_ratio"
、"aspect_mode"
,小寫加底線的命名方式,這樣 line-bot-sdk-python 才看得懂。
知道怎麼在 FlexMessage 當中放入變數之後,接下來就回過頭來看看怎麼寫get_translate()
這個函數。
就像之前寫過的找圖函數一樣,我們請 google 大神幫我們翻譯。最直接快速的方式,就是在 google 搜尋列上輸入:「我有興趣的東西 英文」,google 就會很貼心地幫忙翻譯了,如圖七,而我們要找的,就是 google 翻譯出來的文字:
圖七、google 的貼心翻譯
def get_translate(text):
translate = f'{text} 英文'
url = f"https://www.google.com/search?{urllib.parse.urlencode(dict([['oq', translate], ['q', translate]]))}/"
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'}
req = urllib.request.Request(url, headers = headers)
conn = urllib.request.urlopen(req)
data = conn.read()
pattern = '<span tabindex="0">\S*</span>'
match = re.search(pattern, str(data))
return match.group()[19:-7]
這樣子就算是翻譯好了!
我們從了解 FlexMessage 的基本架構開始、用 FlexMessage 模擬器創立符合我們需求的 FlexMessage、並把變數送進 FlexMessage 當中,距離把 FlexMessage 裝備到 LINE 聊天機器人只剩一步之遙了,那就是:教 LINE 聊天機器人發送 FlexMessage。
就像之前我們用TextSendMessage()
跟ImageSendMessage()
一樣,LINE 也有提供一個FlexSendMessage()
函數來發送 FlexMessage。基本的方送方法如下:
line_bot_api.reply_message(
event.reply_token,
FlexSendMessage(alt_text, contents)
)
FlexSendMessage()
當中需要兩個參數,alt_text
跟contents
。alt_text
是 LINE 跳出通知時,上面會顯示的文字,而contents
就是我們上面寫出來的 FlexMessage 那個複雜的字典物件。以我的 LINE 聊天機器人為例:
from linebot.models import FlexSendMessage
def img_search_flex(event):
if re.match("flex", event.message.text.lower()):
try:
translate = get_translate(event.message.text[5:])
random_img_url = get_img_url(img_source='pixabay', target=translate)
contents = prepare_img_search_flex(event.message.text[5:], translate, random_img_url)
line_bot_api.reply_message(
event.reply_token,
FlexSendMessage(
alt_text = f'flex {translate}',
contents = contents
)
)
from linebot.models import FlexSendMessage
FlexSendMessage
if re.match("flex", event.message.text.lower()):
"flex"
作為啟動 FlexMessage 的條件。如果使用者輸入flex 想查的關鍵字
,LINE 聊天機器人才會傳送 FlexMessage。 contents = prepare_img_search_flex(event.message.text[5:], translate, random_img_url)
prepare_img_search_flex()
的函數,用來創造 FlexMessage 當中的contents
,並放入三個參數包括關鍵字、翻譯、圖片的網址,使得創造出來的contents
會隨著關鍵字不同而改變。最後就是透過FlexSendMessage()
將我們的 FlexMessage 發送到使用者手中啦! 我們今天從 FlexMessage 的基本架構開始講起,講到了 FlexMessage 可用的許多元素,學到了利用 FlexMessage 模擬器快速做出符合需求的 FlexMessage,接著更進一步在我們的 FlexMessage 當中放入變數,使得 FlexMessage 可以隨著使用者輸入的訊息而改變,最後用 LINE 提供的 FlexSendMessage()
這個函數將 FlexMessage 發送給使用者。經過這一番說明,大家是否有對 FlexMessage 更加了解了呢?試著寫寫看自己期望中的 FlexMessage 吧!今天相關的程式碼,我已經放到 Github 上了,有興趣的人歡迎過去我的 Github 參考看看。另外,如果覺得這篇文章中有哪部分說明不夠清楚,或是希望能夠再深入討論的,也歡迎大家在下面留言,謝謝大家!有關於 LINT 聊天機器人,以及 Heroku Postgres 資料庫的說明就到這裡。明天將要開始介紹用 Flask 架設網站,讓我們儲存在 Heroku Postgres 的資料能夠在網站上清楚呈現,邁向這個主題的最終目標:資料視覺化囉!
➀ FlexMessage 基本架構
➁ FlexMessage 版面配置
➂ codepen
➃ 駝峰式命名 wiki
註:對於此系列文有興趣的讀者,歡迎參考由此系列文擴編成書的 LINE Bot by Python,以及最新的系列文《賴田捕手:追加篇》
第 31 天 初始化 LINE BOT on Heroku
第 32 天 快速回覆 QuickReply 介紹
第 33 天 妥善運用 Heroku APP 暫存空間
第 34 天 妥善運用 LINE Notify 免費推播
第 35 天 製造 Deploy to Heroku 按鈕