【祿】邁向財務「自由」之路 II — 育成收發 Telegram 的智能秘書(下篇)

本篇繼續我們開發收發 Telegram 短訊彙報牛記匯率的智能秘書之旅!由於這兩篇的技術含量較高,如果讀者是初次接觸編程,建議由上篇或者系列第一篇 Google Sheet 智能秘書開始閱讀。



上回講到我們已從牛記匯率網頁擱取到所有外幣的匯率,並儲存在一個名叫 FXDatabase 的 Python 字典物件內。本篇我們會討論:

  • 資訊的展現,即如何將 FXDatabase 內的資訊,換成秘書在 Telegram 發送的訊息;
  • 利用另一個 Python 程序,將已開發的程序跟 Telegram 聯繫,建立聊天機械人(Chatbot);
  • 將程序放上雲端運算,讓程序 24/7 執行,讓智能秘書隨時隨地為你效勞。

我們會討論兩種訊息: (1) 發送主要貨幣的匯率一覽,以及 (2) 根據我們輸入的貨幣代碼,回覆相應貨幣的匯率。


4. 以喜歡的形式  將字典裏的資訊換成短訊息

這個步驟是整個開發過程中最開心、最自由度大、最考創意的,因為我們可以通過資訊的展現,決定私人智能秘書的性格、做人物角色設定。當然,性格這回事,並沒有對錯的,喜歡就好 :)

這一步我們先來編寫秘書所回覆的訊息,下一步我們再想如何讓秘書連線上 Telegram,以及秘書如何看懂我們在 Telegram 發出的訊息。

現在假設筆者希望得到的訊息有兩款:

  1. 主要貨幣的匯率買賣價一覽,其中「主要貨幣」自定義為美元、英鎊、歐羅、日圓和人幣。效果如下圖:

  1. 當自己在 Telegram 輸入貨幣的代碼,顯示該貨幣的買賣價。效果如下圖:


為了方便 Telegram 程序的存取,我們將所需要的訊息寫成是函數的回傳。待會我們就能看到這個方法的好處——利用函數直接得到所需要的訊息,而不用將製作訊息和顯示訊息的程式碼混在一起。

在此之前,讓我們也先把上回得到 FXDatabase 的程序,以函數形式表示:

   def DownloadFXDB():
       r = requests.get(url).content
       Soup = BeautifulSoup(r, "html.parser")
       TargetRows = Soup.find("table").find_all("tr")[2:]

       FXDatabase = {}

       for Row in TargetRows:
           Currency = Row.find_all("td")[1].text.encode('utf-8')
           TDBuy = Row.find_all("td")[2]
           TDSell = Row.find_all("td")[3]
           Buy = GetFX(TDBuy)
           Sell = GetFX(TDSell)   
           FXDatabase[Currency] = { 'Buy' : Buy, 'Sell' : Sell }
    
       return FXDatabase

這樣每次呼叫 DownloadFXDB,Python 就會從網際網路下載最新的牛記匯率,並製作匯率字典了。


4a. 回傳訊息內容函數:主要貨幣的匯率買賣價一覽

第一行當然是定義一個函數:

   def MajorCurrFXMsg():

在函數中,首先讓我們從網際網路下載最新的匯率資訊:

   FXDatabase = DownloadFXDB()

然後,告訴 Python 我們需要的主要貨幣列表:

   MajorCurr = ['USD','GBP','EUR','JPY','RMB']

接下來,由於我們也是用 for 迴圈去累積訊息的內容,所以也得先建立一個空字串:

   Message = ""

當然,如果想為私人秘書加添一些個人性格,可以在這一步加上⋯⋯

  • 通告風: Message = "💹 主要貨幣匯率一覽" + "\n"
  • 客服風: Message = "👩🏻‍💻 以下是為尊貴閣下從網路實時取得的匯率報價" + "\n"
  • 女僕風: Message = "💁🏻‍♀️ 主人,這是您需要的匯率資訊 ☺️" + "\n"
  • 外星生物風: Message = "👽 本星球列強貨幣等價 🌍" + "\n"

其中 "\n" 是換行符號。

來到靈魂一步,寫一個 For 迴圈,將所有主要貨幣跑一遍,並將匯率資訊以自己喜歡的形式展現出來。這裏筆者只展現基本形式:

   for Currency in MajorCurr:
       Message = Message + Currency + " 買 " + 
                 str(FXDatabase[Currency]['Buy']) + " 沽 " + 
                 str(FXDatabase[Currency]['Sell']) + "\n"

其中 str() 函數是將匯率數字變成字串便於與訊息其餘部份連繫在一起。最後將 Message 作為函數的回傳:

return Message




4b. 回傳訊息內容函數:按照輸入顯示該貨幣匯價

假設使用者在 Telegram 輸入的貨幣代號名稱為 InputCurr (我們將在下節討論智能秘書如何接收我們的指令)。我們輸出訊息內容的函數可以直接以此為參數:

   def PromptedCurrFXMsg(InputCurr):

同樣的,我們先下載最新的匯率資訊:

   FXDatabase = DownloadFXDB()

然後在顯示匯率資訊之前,讓我們先檢查輸入的代號是否存在在從牛記取得的字典內。要取得 FXDatabase 內所有貨幣,亦即該字典的「索引」列表,方法是 .keys():

   if InputCurr not in FXDatabase.keys():
       Message = "對不起,沒有提供" + 
                 InputCurr.encode('utf-8') + "的匯率"

如果存在,則顯示相應的匯率:

   else:
       Message = InputCurr.encode('utf-8') + " 買 " + 
                 str(FXDatabase[InputCurr]['Buy']) + " 沽 " + 
                 str(FXDatabase[InputCurr]['Sell'])

   return Message

留意筆者在 InputCurr 用上了 .encode('utf-8'),這是因為使用者從 Telegram 輸入的訊息,也會被視之為 UTF-8 編碼的。




4c. 小結

至此,整個輸入輸出匯率的程序碼檔 NgauKeeFX.py 已開發完成。整個檔案應該有四個程序函數(內容從略):

   ## NgauKeeFX.py

   import requests
   from bs4 import BeautifulSoup

   def GetFX(TD):
       ...

   def DownloadFXDB():
       ...

   def MajorCurrFXMsg():
       ...

   def PromptedCurrFXMsg(InputCurr):
       ...


5.  建立 Telegram 聊天機械人  並將已開發的程序聯繫

說到底,我們的 Telegram 智能秘書就是一個聊天機械人(Chatbot)。我們現在就要建立一個新的 Chatbot,並以 Python 程序賦予這個 Chatbot 靈魂。

5a. 建立一個新 Chatbot

要建立一個新的 Telegram Chatbot,我們得去拜訪眾 Bot 之父 —— BotFather。(你猜對了!BotFather 本身就是一個 Bot。)要把他加進你的 Telegram 通訊表,網址是:


BotFather 能給你清晰的指示如何建立和管理你的聊天機械人(們)。例如,要建立一個新的聊天機械人,可以輸入「/newbot」指令(或直接按 BotFather 訊息上的相關連結),並按指示先後輸入顯示名稱(日後可更改)以及系統名稱(日後不可更改,並需以 bot 字結尾):



BotFather 會給予這個新 Bot 一個 Token,請務必妥善儲存及處理,因為不幸落入別人手中,別人就能騎劫你的秘書。

現在我們也可以利用「/setuserpic」指令,為秘書助理上載一幅個人玉照:


效果如下圖:


是否已經很有血肉的真實感覺了?且慢,現在我們的 Telegram Chatbot 還需要你為他/她賦予智慧,就是那顆有能力跟你對答的靈魂,而這就是本篇的重點所在。

5b. 為 Chatbot 賦予靈魂

Telegram 本身提供以 HTTP 為基礎的 API,所以要賦予 Telegram Bot 靈魂可以有很多方法,Python、JavaScript,甚至 Excel VBA 也可以,只要讀者能找到這些程式語言如何與 Telegram 提供的 API 溝通便可。

本篇筆者將會利用一個蠻好用的 Telegram API 的 Python Wrapper「Python Telegram Bot」。而為避免本文成為一篇真正的「宅文」,太技術性的部分筆者在解釋上或會有所從略。各位編程員如有興趣,可以拜讀其 GitHub 介紹:https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API

要使用這個 Wrapper,第一件事當然是安裝進系統(Google Colab 的朋友這回對不起了,Google 還沒有支援,所以請還是回到 Terminal 去⋯⋯):

$ pip install python-telegram-bot --upgrade

接著,讓我們新增一個靈魂程式碼檔 TelegramBot.py,並將之放在與 NgauKeeFX.py 同一個資料夾內。第一句我們從 Python Telegram Bot 匯入需要的部件:

   from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

還有要匯入的當然是擱取匯率資訊的自家建設的函數群:

   import NgauKeeFX

接下來幾句,筆者先不作解釋,請照著打就好;除了 Token 的位置,請換上 BotFather 親授閣下的智能秘書 Chatbot 的私人 Token(字串格式)。

   Token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
   updater = Updater(token=Token)
   dispatcher = updater.dispatcher

至此準備功夫已做好了。接下來就可以即席揮毫,就著使用者所有可能的輸入,逐一書寫智能秘書的回應!

首先,有否留意在上面截圖中,當跟新的智能秘書打招呼時,系統會強制執行一個叫做 /start 的指令?這個是讓智能秘書跟你 Say 個 Hi 的機會。上圖中的秘書尚未有反應,就是因為他/她的靈魂還沒有裝上。要編寫智能秘書在你給予 /start 指令的反應,可以新增以下幾句:

   def start(bot, update):
       Message = "福祿壽全兄您好!很高興能為您效勞!"
       bot.send_message(chat_id=update.message.chat_id, text=Message)
   start_handler = CommandHandler('start', start)
   dispatcher.add_handler(start_handler)
   updater.start_polling()


現在,我們可以呼喚一下這個小小靈魂,讓它叫動我們的智能秘書了!儲存好 TelegramBot.py 之後,在 Terminal 移動到放有兩個 .py 檔案的資料夾,然後執行:

   $ python TelegramBot.py

接著在 Telegram 試著再次開展跟秘書的對話。神奇的事… 就… 此… 發… 生…



不過這個時候如果我們向秘書發送其他的訊息,他/她還是會木頭木腦毫無反應的;這就要靠我們後續的努力了!另外,留意 Python 程序仍然在執行以不斷接收並處理使用者的輸入,一但我們中止了程序(Mac Terminal 可按 control + z)或是把電腦關掉,秘書的靈魂就會熄滅掉。這就是我們最後一步需要考慮將靈魂放上雲端運算的原因。


下一步就是牛記匯率的問答。我們希望秘書能回應「/fx」的指令。如果指令後有其他參數,將參數視為所需貨幣,並嘗試按照輸入顯示該貨幣匯價;否則就視指令為顯示主要貨幣的匯率買賣價一覽。輸入如下並再執行靈魂程式:

   def FX(bot, update, args):
       Currency = " ".join(args)
       if Currency == "":
           Message = NgauKeeFX.MajorCurrFXMsg()
       else:
           Message = NgauKeeFX.PromptedCurrFXMsg(Currency)
       bot.send_message(chat_id=update.message.chat_id, text=Message)

   fx_handler = CommandHandler('FX', FX, pass_args=True)
   dispatcher.add_handler(fx_handler)


建構一個 Chatbot 是否要比想像中簡單?

再來下一段,就是如果用家不是用「/fx」指令的方式提出要求,我們還是盡量希望能配合的。如果用家能輸入「FX」、「匯率」、「牛記」等字眼,我們也會視之為對牛記匯率的請求,顯示主要貨幣的匯率買賣價一覽。否則,我們的秘書還是會禮貌地(或不禮貌地,視乎讀者對其角色設定)告訴使用者自己看不明白:

   def echo(bot, update):
       if update.message.text.encode('utf-8') in ["FX","匯率","牛記"]:
           Message = NgauKeeFX.MajorCurrFXMsg()
       else:
           Message = "福祿壽全兄,恕我未能明白何謂「" + 
                     update.message.text.encode('utf-8') + "」。"
       bot.send_message(chat_id=update.message.chat_id, text=Message)
   echo_handler = MessageHandler(Filters.text, echo)
   dispatcher.add_handler(echo_handler)

告訴使用者自己看不明白,除了訊息外,同樣適用於看不明白的指令:

   def unknown(bot, update):
       Message = "福祿壽全兄,恕我未能明白何謂「" + 
                  update.message.text.encode('utf-8') + "」。"
       bot.send_message(chat_id=update.message.chat_id, text=Message)
   unknown_handler = MessageHandler(Filters.command, unknown)
   dispatcher.add_handler(unknown_handler)




5c. 小結

至此,整個控制智能秘書的靈魂程序碼檔 TelegramBot.py 也開發完成。整個檔案應該有四個程序函數及其相應新增至 Handler 及 Dispatcher 之指令(內容從略):

   ## TelegramBot.py

   from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
   import NgauKeeFX

   Token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
   updater = Updater(token=Token)
   dispatcher = updater.dispatcher

   def start(bot, update):
       ...

   def FX(bot, update, args):
       ...

   def echo(bot, update):
       ...

   def unknown(bot, update):
       ...


如果讀者打算長開個人電腦,為秘書提供永恆的靈魂,以下的最後一步可以省略。否則,請繼續完成最後一節……


6.  將智能秘書的靈魂程式放上雲端運算

網上支援 Python 雲端運算的服務可謂包羅萬有,從山寨免費服務到企業級的 Google Cloud Platform / Amazon AWS 都有,豐儉由人,讀者不妨多做比較再決定讓秘書的靈魂在何處落地生根。

筆者選用的是 Python Anywhere (https://www.pythonanywhere.com),貪其方便易用,系統 Up Time 和穩定性也不錯。網站雖然容許免費戶口,但免費戶口能「瀏覽」的只限此表(https://www.pythonanywhere.com/whitelist/)註明的網站;要擱取牛記匯率等特定網站,筆者用的是最低級的收費戶口,每個月美帝幣 5 枚。

開戶後,在 Files 新增一個資料夾(假設叫「TelegramBot」),並把 NgauKeeFX.py 及 TelegramBot.py 上載至資料夾內。

在 Consoles 新增一個 Bash(就是 Terminal / Command Prompt)。在執行靈魂程序 TelegramBot.py 之前,別忘了安裝我們會用到的 程序包。注意 Python Anywhere 支援不同版本的 Python,我們用到的是 2.7,所以應利用 「pip2.7」;另外我們只有替自己而沒有替其他用家安裝的權限,所以亦需註明「--user」:

   $ pip2.7 install --user requests
   $ pip2.7 install --user beautifulsoup4
   $ pip2.7 install --user python-telegram-bot --upgrade

之後便可以執行靈魂程序,其中 username 是閣下 Python Anywhere 的用戶名稱:

   $ python TelegramBot/TelegramBot.py

這就完成將秘書靈魂放到網路雲端處運算的工序了。

留意理論上靈魂程序的執行是不會自己終止的,但雲端伺服器偶爾也會有維護而強行殺掉靈魂的時候。Python Anywhere 提供了一個繞路方案,讓程序保持接近 24/7 執行,詳情可以參考:https://help.pythonanywhere.com/pages/LongRunningTasks

設定好後,靈魂程序便能(接近) 24/7 執行,讓智能秘書隨時隨地為我們效勞了!



總結

前後花了兩個月時間才將這幾個月來學到的技巧整理成文,雖然愈寫愈覺得是在「趕客」,希望仍然對某部份理科底子比較強的讀者群、有興趣研究自動化、以及以最皮毛的方式初窺一下下一波「中年危機」即人工智能如何取代我們飯碗的朋友,有所裨益和幫助吧!

書於山竹襲港全城戒備的十號風球前夕,明天既然大家都只能待在家裏,何不一起動手來,在 Telegram 砌個虛擬男女朋友 / 閨蜜 / 颱風預報科學主任,甚至懂報股價和分析股票的大師? 



30 則留言:

  1. 沙發!!! 好長丫,岩晒聽日玩~

    回覆刪除
    回覆
    1. 多謝星尼!! 希望聽日唔好斷電 / 寬頻...

      刪除
    2. 我未睇晒, 不過睇左最後的Python Anywhere...
      福兄應該可以開Aws用lambda喎, 一個月免費幾百萬條, 應該唔駛理whitelist or not~
      不過aws一個Free tier只可以玩12個月~

      刪除
    3. 哈哈,兩篇長到一個風假都睇唔晒 😅
      我就係唔想再輕易搬家啦⋯ 就算 12個月後 reg 另一個 Account 也是要搬來搬去。有些方便錢是要駛的~

      刪除
    4. haha, 大概睇晒~ 我諗我會試下用lambda整~
      我部macbook唔知點解認唔到telegram.ext, 最後都係用番windows
      不過快手試用python anywhere唔錯~

      刪除
    5. 我試過 config Google Cloud Platform 舞咗我大半日都搞唔掂,之後一試 Python Anywhere 五分鐘 ready,突然覺得 5蚊一個月好抵畀⋯

      刪除
  2. 小弟科技盲,純粹留言支持一下全兄大作。。。

    回覆刪除
    回覆
    1. 一謝! :D 希望三人行兄與家人在風災都安全!

      刪除
    2. 小弟所住區域不屬受風區。謝謝關心!

      刪除
    3. 如此甚好 :) 現在又得做好下一波防風措施(繼續貿易戰⋯),坐定定聽三人行兄講故事 😆

      刪除
    4. 呵呵!貿易戰寫了N集,小弟我手寫我口,繼續做大閘蟹了,大家可以開心下。呵呵!現時綜合各項民調(見下LINK:https://realclearpolitics.com/elections/2018/),估算共和黨很大機會輸掉眾議院。以目前特帝JOB APPROVAL之低,仇口之多,加上鐘擺效應,再爆多些醜聞,分分鐘拖累埋共和黨的參議院的表現,令特帝提早兩年成為跛腳鴨總統。很有趣,香港基本上沒有多少人關注美國中期選戰,很多人甚至以為特帝在美國民望好高!特帝的命運實際上,不見得比中港股市樂觀。

      刪除
    5. 哈哈,特帝只消講一句全部係抹黑、假新聞,又可以同支持者自 High。

      刪除
  3. 多謝福祿壽全兄的教學, 今天山竹襲港, 故打算跟著上述教學學習, 但在 "5b.為Chatbot賦予靈魂" 時安裝Python Wrapper部份卡住了, 不明白應如何進行. 我是用WIN10, 同時下載並安裝了Python2.7, 可成功登入terminal. 不過正打算按內容輸入"$ pip install python-telegram-bot --upgrade"的指令, 郤出現錯誤的訊息, 未知是否有什麼地方忽略了, 望指教. 感謝.

    回覆刪除
    回覆
    1. 史提芬兄你好!多謝支持!
      Error 可以有很多原因,未知道有否相關錯誤訊息參考?我也不敢誰能解決問題,不過可以跟其他讀者一起嘗試推敲一下。

      刪除
    2. 你好. 因為我完全係Python的新手, 故我估計碰到的問題是不知道應如何安裝 Telegram 的Package, 而有關的錯誤訊息如下, 望指教. 謝謝.

      Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32
      Type "copyright", "credits" or "license()" for more information.
      >>> pip install python-telegram-bot --upgrade
      SyntaxError: invalid syntax
      >>>

      刪除
    3. 明白了,pip install 是要先離開 python 介面回到 command prompt 安裝的。可以嘗試
      >>> Exit()
      讓提示碼回到 $ 的狀態。Windows 應該是 > 的狀態。

      刪除
    4. 謝謝你, 福祿壽全兄. 感覺Python很有趣, 真的值得花點時間好好學習.

      刪除
    5. 對,Python 的確很有趣,也很人性化,是容易上手而且廣泛使用的語言,花了的時間不會浪費。

      刪除
  4. 真是很棒的分享!我也很想試試一寫,如果我孩子不黏著我就可以動手了。可惜我又捨不得孩子⋯⋯唉呀

    回覆刪除
    回覆
    1. 哈哈,Summer 兄可以嘗試在街上用手機登上 Google Colab 開發主要部分 :D

      孩子多大了? 滿 4-5 歲應該可以玩方塊編程的玩具了吧?或者開發一個秘書給孩子,一邊開發一邊問他想要秘書姐姐(或哥哥)如何回應,應該會是不錯的親子活動。

      刪除
    2. 他還小呢,當他大點玩方塊編程的玩具也好呀,真是個好提議!

      刪除
    3. 希望孩子能有所得著 :)

      刪除
  5. 回覆
    1. 謝 AC 兄,「財務」「自由」路上一同加油!

      刪除
  6. 謝謝福兄, 太耐沒學電腦語言, 完全脫節了, 尤其是 CHATBOT 那一部份。福兄的分享令我重拾對電腦程式的興趣, 謝謝。

    回覆刪除
    回覆
    1. 我在兩三年前初次接觸大數據模型,興奮得差不多想轉行,我想那時心情應該跟二當家兄現在有過之而無不及。幸好最後沒有因為發覺自己只是三分鐘熱度,哈哈!

      刪除
  7. 自動化真的很有趣,但要自己搞一個就真係吾容易~~

    回覆刪除
    回覆
    1. 世上無難事,只怕有心人。搞自動化就像投資,今日投入心機本錢,明日就能輕鬆享受成果;今日搞得好,他朝減煩惱,哈哈!

      刪除
  8. print (MajorCurrFXMsg())的result說KeyError: 'USD'
    Why?

    回覆刪除
    回覆
    1. 單憑一個 Error Message 難以找出原因,Eric 兄可以試著逐行程式碼執行以收窄範圍。

      刪除

熱門文章