2024年1月31日 星期三

參加 Google Cloud 線上研討會

今天參加 Google Cloud 以 Gemini 為主題的線上研討會共三場 :





主題包含如何將谷歌大預言模型 Gemini 應用在業界各領域, 檢索增強生成 (RAG) 的技術, 以及 如何運用 BigQuerry 來儲存與檢索向量等. Google 在 GAI 相關領域提供許多免費資源 :





昨天我 miss 掉已報名的 Azure OpenAI Lab 內訓課程 (搞錯日期以為是今天) 非常懊惱, 但抱著碰機會問老師, 哈哈, 結果可以補課, 爽. 我上回有參加 Google Vertex AI Lab 覺得很不錯, 2/5 還會有第二梯可千萬別忘了. 















2024年1月30日 星期二

參加茶米老師的 AIGC 生成式內容多媒體應用首部曲 Vrew 分享會

晚上參加茶米老師的 AI 影音剪輯工具分享會 (還好有滑臉書), 介紹一套很棒的工具 Vrew, 它最大的亮點是利用 AI 分析影片中的音訊, 產生字幕逐字稿, 我們可以直接編輯字幕, 刪除不要的字, 它會同步刪掉對應的視訊, 在字幕編輯器中按 Enter 跳行就自動切割視訊, 這實在太方便了, 比甚麼威力導演還要威! AI 的出現已為數位生活帶來翻山倒海的改變! 

Vrew 這套 AI 剪輯軟體需下載安裝, 可註冊免費帳戶, 使用上的雖然有些限制, 但對一般應用來說也算足夠了, 下載網址 : 


課程中用到的材料可從雲端硬碟下載 : 


註 : 今日起茶米老師連續三天晚上 19:00 開講, 課程連結:

【線上】1/30(19:00-21:00)-黃信溢-AIGC生成式內容多媒體應用首部曲Vrew - AI 影音剪輯酷兵器


【線上】1/31(19:00-21:00)-黃信愷-AIGC生成式內容多媒體應用二部曲 Leonardo:揭開 AI 繪圖大師的魔法面紗

【線上】2/1(19:00-21:00)-黃信愷-AIGC生成式內容多媒體應用三部曲 Clipchamp:AI 影音編輯新體驗


2024-01-31 補充 : 

今天上 Leonardo 要註冊帳戶才發現去年在益師傅分享會我就註冊使用過了, Leonardo 每天 150 點可用真的很佛心, 付費使用 API 最低才 9 美元. 

Python 學習筆記 : LINE Bot 開發 (三) 在本機佈署 Echo Bot 聊天機器人

在前一篇測試中已經建立 Line 聊天機器人的官方帳號, 並將自己加入為好友. 接下來要測試 Line Bot 最重要的部分 : 設定 Webhook URL, 這樣才能將 Line Bot 伺服器串接到我們的後台網頁伺服器, 讓裡面的 Python 程式來處理所接收到的訊息並決定如何回應.

本系列之前的文章參考 :


教學文章參考 :



Line 聊天機器人其實就是安裝在開發者的後台網頁伺服器中的網頁程式 (可用 Python 的 Flask 或 Django 等實作), 使用者傳送的訊息會透過 Line 的訊息伺服器 (Messaging Server) 作為介接, 利用 Webhook (採用 RESTful 的一個 URL) 以 HTTPS 向後台網頁伺服器提出 POST 請求, 我們的 Line Bot 程式須根據收到的訊息決定如何回應, 處理架構與流程如下圖所示 :




Line 聊天機器人的開發程序如下 :
  1. 到 Line 開發者網站將自己的 Line 帳號註冊為開發者帳號 (Business ID).
  2. 建立供應商 (Provider) 名稱, 相當於開發者的公司招牌.
  3. 建立頻道 (Channel) 名稱, 一個頻道代表一個聊天機器人 (會有一個 @ 開頭的 Line 官方帳號), 一個供應商可以建立多個頻道. 
  4. 到 Line 官方帳號管理頁面進行此頻道之回應設定並將此官方帳號加為好友.
  5. 安裝 line-bot-sdk 套件以便撰寫聊天機器人網頁程式, 並佈署到自己的網頁伺服器 (取得HTTPS 網址). 
  6. 將聊天機器人的網址設為此頻道的 Webhook URL 並進行測試. 
在前兩篇測試中已完成步驟 1~4, 本篇將以簡單的 Echo Bot (鸚鵡機器人, 會將收到的訊息值接回傳) 為例完成步驟 5~6. 參考官方教學文件 :


首先我們必須來完成後台網頁伺服器的架設, 首先用 Flask 寫一個運行於本機的網頁伺服器, 然後再用 Ngrok 程式讓其擁有 HTTPS 網域功能 (Line 訊息伺服器的 Webhook 必須是 HTTPS 域名網址, 不可以使用 IP). 


一. 取得頻道密鑰 (Channel secret) 與頻道存取權杖 (Channel access token) : 

先開啟 Line 開發者首頁 : 





按左邊的 "Console" 進入控制台, 或直接拜訪下列網址 :


控制台會顯示所有已建立之頻道 (即聊天機器人, 目前只有一個) : 




點選要設定的頻道進入基本設定頁面 : 




拉到頁面最底下可以看到 Channel secret, 如果沒有就按 "Issue" 鈕產生一個 : 




按複製鈕先將其貼到記事本保存, 例如 :

secret="abcdefbd24f2f1eabd274024catony1966"   (此為範例)

然後切換到 Messaging API 頁籤, 上面是官方帳號與其 QR code (可以讓測試者加入好友) : 




往下拉到底可以看到 Channel access token 欄位, 因尚未發行過權杖目前是空的 :




按 "Issue" 鈕新增一個 : 




按複製鈕將其貼到記事本保存, 例如 : 

token="tony1966/pOjFWcV+AJ2qQTcGSQXvvDdoRa98W6W44fC/vwCG5B+Pg03dPP/gHVuUpRcJGZ6glj5aA1PEoN9VlCIBDgFW5/wRGMP+/hvfscg3P2M1jMCNLv8pjIV53DIyT9WpY4MPQYMWgAKbdV3GySwdB04t89/1O/w1cDabcdef="  (此為範例)

此 Messaging API 設定頁面還有一個 Webhook 欄位要設定, 等網頁伺服器架設好再來填. 

參考 :



二. 用 Flask 在本機架設一個網頁伺服器 : 

Flask 是一個 Python 輕量級的 Web 框架套件, Flask 應用程式執行時會在本機建立一個網頁伺服器 (localhost 或 127.0.0.1, 預設埠口為 5000), 因語法簡單常被用來快速建立 Web 網站雛形以驗證 RESTful 服務, 關於 Flask 用法參考 : 



1. 安裝 flask 套件 : 

使用 pip install 來安裝 flask 套件 :

pip install flask  


2. 匯入 Flask 類別建立 app : 

從 flask 匯入 Flask() 類別, 然後呼叫其建構子並傳入 __name__ 即可建立一個網頁應用程式 (即傳回之 Flask 物件) :

>>> from flask import Flask    
>>> app=Flask(__name__)    
>>> type(app)   
<class 'flask.app.Flask'>   


3. 用裝飾器定義路由與處理函式 : 

接下來是定義路由 (routes), 即 URL 路徑與所對應之處理函式, Flask 使用 app.route() 函式的裝飾器來定義 URL 路徑, 放在所對應之處理函式前面, 作法簡單直觀, 語法如下 :

@app.route("路徑")
def handler([參數序列]):
    ,,,
    return 回應訊息      # HTML 格式字串

URL 路徑其實就是所謂的 Web API, 這是一種採用 RESTful 規範的 GET 請求方式, 它以斜線做區隔的層級路徑來區別要執行網站伺服器裡的哪一個資源 (程式), "/" 表示網站首頁, 亦即根目錄, 斜線底下是資源名稱, 例如 "/hello" 表示存取 hello 資源, 也可以傳遞多個參數, 語法如下 :

/資源名稱/參數1/<值1>/參數2/<值2> ....

此 RESTful 的 GET 請求路徑相當下列的一般 GET 路徑語法 :

資源名稱?參數1=值1&參數2=值2 ....  

如果有傳入參數的話, 要依序傳入處理函式 :

def handler(參數1, 參數2, ...): 

參考 :


例如可為上面建立的 app 建立三個路由 :

"/" : 請求首頁, 回應 "<h1>歡迎光臨我的網站</h1>"
"/ok" : 請求 ok 資源, 回應 "<p>OK</p>" 
"/hello/<name>" : 請求 hello 資源傳入 name 參數, 回應 "<h3>Hello, {name}!"

例如 :  

>>> @app.route('/')  
def main():  
    return '<h1>歡迎光臨我的網站</h1>'    
>>> @app.route('/ok')   
def ok():   
    return '<h1>OK</h1>'   
>>> @app.route('/hello/<name>')   
def hello(name):   
    return f'<h1>Hello, {name}!</h1>'   

這裡的路徑有分大小寫 (因為 Python 字串是區分大小寫的), 寫錯會回應 not found, 但最後面的參數則無關大小寫 (參數字串會被忠實傳送). 例如請求 /hello/TONY 會回應 "Hello, TONY"; 請求 /hello/tony 會回應 "Hello, tony"; 但請求 /HELLO/TONY 則是回應網頁不存在. 

注意, 在 Python 命令列執行上面指令時, 裝飾器必須與其所修飾的函式一起輸入後再按 Enter, 若只輸入 @app.route() 就按 Enter 會出現 SyntaxError. 


4. 呼叫 app.run() 建立網站 :  

定義好路由後只要呼叫 app.run() 就會將此網站架起來了 :

>>> app.run(debug=True)   
 * Serving Flask app '__main__'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000   
Press CTRL+C to quit
 * Restarting with watchdog (windowsapi)
OK

可見此 Flask 應用程式預設監聽本機 (127.0.0.1 或 localhost) 的 5000 埠請求, 注意, 此處 debug=True 表示會顯示呼叫 app.run() 時也傳入 host 與 port 等參數, 例如 (先按 Ctrl + C 停止上面已啟動之開發伺服器) : 

>>> app.run(host='0.0.0.0', port=8080, debug=True)   
 * Serving Flask app 'flask_app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080   
 * Running on http://192.168.2.128:8080   
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 260-650-195

此處 host='0.0.0.0' 表示 Flask 開發伺服器監聽對本機任何 IPv4 位址的請求, 可見除了 127.0.0.1 外, 還多了一個 192.168.2.128, 這是本機從區網 DHCP 獲得之網址. port 參數則是開發伺服器要監聽的埠號. debug=True 表示要顯示偵錯訊息. 關於 0.0.0.0 與 127.0.0.0 參考 :


網站架起來後即可開啟瀏覽器拜訪 http://127.0.0.1:8080 (或此處本機獲得之區網網址 192.168.2.128:8080), 基於安全會出現防火牆警告視窗 :




按 "允許" 後會出現首頁頁面 : 



在網址列輸入 127.0.0.1/ok 會回應 OK 網頁 : 




在網址列輸入 127.0.0.1/hello/tony 則會回應 Hello, tony 網頁 : 



可見這個 Flasp 網站已能正常運作, 我們的聊天機器人運作模式也是如此, Line Messaging Server 會依照 Webhook URL 網址對我們的後台網頁伺服器提出請求, 然後網頁伺服器依據請求做出是當的回應. 

完整程式碼如下 :

app.py
from flask import Flask

app=Flask(__name__)

@app.route('/')
def main():
    return '<h1>歡迎光臨我的網站</h1>'

@app.route('/ok')
def ok():
    return '<h1>OK</h1>'

@app.route('/hello/<name>')
def hello(name):
    return f'<h1>Hello, {name}!</h1>'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)
    
注意, 在本機執行 Flask 應用程式建立網站時, 建議使用 flask run 指令於命令列執行, 且應用程式檔案名稱要取名為 app.py, 指令語法如下 :

flask run -h localhost -p 埠號   

或 

flask run -h 127.0.0.1 -p 埠號

如果用 python 指令執行或在 Thonny 中按 Play 鍵執行, 在有些電腦可能會因 "網站無回應" 而無法顯示網頁, 參考 : 


不過這個網站只能在本機存取, 外網無法連線此網站. 若要用本機網站充當聊天機器人的後台伺服器, 必須讓此網站具有 HTTPS 域名網址 (這是 Line 訊息伺服器對 Webhook URL 的要求), 這可以透過 Ngrok 代理伺服器來達成, 它會將我們在本機指定埠號上執行的網頁伺服器綁定一個 HTTPS 域名網址. 參考 : 



5. 下載代理伺服器 Ngrok :   

上面用 Flask 在本機所架設的 localhost 網站只支援 HTTP 協定, 且只有本機區域 IP 網段能存, 外網無法連線此網站, 解決辦法是使用 Ngrok 代理伺服器, 它可以為 localhost 本機伺服器上的網站提供一個 HTTP 與 HTTPS 網域網址 (不是 IP), 讓外網能存取此本機網站, 其 HTTPS 網址就能符合 Line Bot 的 webhook URL 要求. 參考 :


Ngrok 可在官網下載 zip 檔 (v3 約 9MB 左右), 毋須安裝, 解開即可使用 : 





ngrok-v3-stable-windows-amd64.zip 解開後得到一個單一的 ngrok.exe, 不過執行時需要輸入認證用的權杖 (token), 故須先按上圖右上角的 "Sign up" 鈕申請帳號 (可以使用 Email 或 GitHub 帳號), 然後點左方導覽列 "Getting Started" 項下的 "Your Authtoken" 會在右方顯示權杖 :




按 "Copy" 鈕將權杖複製到記事本儲存. 取得權杖後開啟一個命令提示字元視窗, 用下列指令進行認證 (注意, token 不可用括號括起來) :

ngrok authtoken 權杖 

例如 :

D:\python\test>ngrok authtoken tonybyjkVWZ1RXPyZVSQ1nKz8Mn_3kbM1966At62W7RGhsx1L   (此為範例權杖) 
Authtoken saved to configuration file: C:\Users\tony1\AppData\Local/ngrok/ngrok.yml   

如看到 "Authtoken saved to configuration file ... " 表示認證 OK, 然後就可以用下列指令讓 Ngrok 為目前監聽本機 8080 埠的網站伺服器產生一個 HTTPS 網址 :

ngrok http 8080   

此處 8080 為目前本機網頁伺服器的埠號. 注意, 新版 ngrok 程式已取消用來指定伺服器所在區域的 -r 參數 (會自動選擇較近之主機). 執行後就會出現所綁定的 HTTPS 網址 : 




複製此 HTTPS 網址 https://b55d-220-133-183-132.ngrok-free.app/ 貼到瀏覽器即可顯示本機網站內容了 (不須指定埠號) :





可見任何對 https://b55d-220-133-183-132.ngrok-free.app 的連線請求都會被轉發到本機的區網位址 127.0.0.1:8080 來, 從而使外網也可以看得到位於內網的網站. 只要沒按 CTRL + C 終止這個轉發程序, 這個 HTTPS 網址就會一直存在. 注意, 結束程序再次執行時會綁定不同的 HTTPS 網址. 


三. 安裝 line-bot-sdk 套件與撰寫聊天機器人程式 :     

LINE 公司為 Python 聊天機器人開發者提供了一個開源套件 line-bot-sdk, 其原始碼與範例檔寄存於 GitHub :



1. 安裝 line-bot-sdk 套件 : 

撰寫 Line 聊天機器人程式需要安裝 Line 提供的開發套件 line-bot-sdk : 

pip install line-bot-sdk 

如果使用 Thonny 編輯器可在 "工具/管理套件" 搜尋 "line-bot-sdk" 後安裝 :




Line Bot 開發套件安裝完成後, 即可開始聊天機器人程式, 最簡單的便是將收到的訊息回傳的 Echo Bot 鸚鵡聊天機器人.

參考 :



2. 撰寫 LINE 聊天機器人程式 : 

在 line-bot-sdk 套件的 GitHub 寄存庫中有提供 Echo Bot 的範例程式, 參考 : 


複製此範例程式碼到 Thonny 或其他編輯器中, 稍微修改一下, 加入存取根目錄 "/" 的路由為顯示歡迎訊息, 方便檢查網站是否正常運行 : 

from flask import Flask, request, abort
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
    )

secret='abcdefbd24f2f1eabd274024catony1966'        # 此為範例密鑰
token='tony1966/pOjFWcV+AJ2qQTcGSQXvvDdoRa98W6W44fC/vwCG5B+Pg03dPP/gHVuUpRcJGZ6glj5aA1PEoN9VlCIBDgFW5/wRGMP+/hvfscg3P2M1jMCNLv8pjIV53DIyT9WpY4MPQYMWgAKbdV3GySwdB04t89/1O/w1cDabcdef='                # 此為範例權杖
configuration=Configuration(access_token=token)    # 設定權杖 
handler=WebhookHandler(secret)                               # 建立處理 Webhook 的物件

app=Flask(__name__)      # 建立 Web app

@app.route('/')                  # 測試網站是否正常運行的路由
def main():
    return '<h1>歡迎光臨我的網站</h1>'

@app.route("/callback", methods=['POST'])     # 聊天機器人頻道之 Webhook 網址
def callback():
    # 從 HTTP 標頭取得數位簽證 X-Line-Signature
    signature=request.headers['X-Line-Signature'] 
    # 取得 HTTP 請求之內容 (BODY)
    body=request.get_data(as_text=True)
    app.logger.info('HTTP 請求內容: ' + body) 
    # 比對數位簽證是否符合, 符合就觸發 MessageEvent 呼叫 handle_message() 
    try:
        handler.handle(body, signature)     # 比對數位簽證是否符合
    except InvalidSignatureError:            # 不符合就拋出例外
        app.logger.info("驗證失敗: 頻道密鑰存取權杖不符合")
        abort(400)  # 回應 400: 中斷連線
    return 'OK'

@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):       # 驗證通過時用來處理回應的函式
    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=[TextMessage(text=event.message.text)]
            )
        )

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

此程式的核心是 @app.route() 所修飾的 "/callback" 路由處理函式與 @handler.add() 所修飾的訊息事件處理函式, 這個 "/callback " 是自訂的, 也可以用 "/linebot" 或任意其他名稱 (甚至直接用根目錄 "/" 也行), 它將會是 Webhook URL 的一部分. 

將上面的程式儲存為 app.py (如果要用 flask run 執行 Flask 應用程式一定要用此檔名), 然後在相同目錄下執行 flask run 指令運行本機網頁伺服器 (此處指定伺服器監聽 3000 埠, 其實指定 80, 5000, 或 8080 等埠亦可) : 

D:\python\flask>flask run -h localhost -p 3000    
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://localhost:3000    
Press CTRL+C to quit

這樣 Flask 網頁伺服器就成功運行了, 用瀏覽器拜訪 http://localhost:3000 或 http://127.0.0.1:3000 就會顯示歡迎網頁, 證明網站運作正常 :

 


接下來執行 ngrok.exe 程式指定上面這個監聽 3000 埠的網站, 讓此區網內的網站擁有一個公網的 HTTPS 網址, 這樣才能讓 Line Messaging Server 可以透過 Webhook URL 將訊息 : 

>>> ngrok http 3000   




這樣此內網的網站便有了如下可讓 Internet 公網存取的 HTTPS 網址 :

https://c9d8-2001-b400-e7ac-be86-5522-c9e6-d934-88d.ngrok-free.app

而所謂的 Line 聊天機器人 Webhook URL 便是在後面加上 "/calback" :

https://c9d8-2001-b400-e7ac-be86-5522-c9e6-d934-88d.ngrok-free.app/callback    

如上所述, 如果直接把處理 Line Messaging Server 傳來的 HTTP 訊息的路由直接做在根目錄 "/" 而非 "/callback" 上, 則 Webhook URL 就直接用 Ngrok 產生的 HTTPS 網址即可. 


四. 設定 Webhook URL :   

透過 Ngrok 為區網網站取得 HTTPS 網址後便要回 Line 開發者控制台設定 Webhook URL :


切到第二個頁籤 "Messaging API", 往下拉到 "Webhook setting" 欄按 "Edit" 鈕, 在 Webhook URL 框中輸入上面的 HTTPS 網址 (後面串接 /callback) :




開啟底下的 "Use webhook" 後按 "Update" 鈕即可 : 



這樣便完成全部設定, 按 "Verify" 鈕驗證 Webhook URL 是否可順利連線後台 Flask 伺服器 : 




出現 Success 表示一切正常, 這時開啟手機 Line App, 點 "好友名單" 再切換到 "官方帳號", 找到上面已加入好友的 "小狐狸事務所聊天機器人", 點進去聊天 (傳送訊息) 就可看到訊息原封不動傳回來了 : 





Bingo! 奮戰了兩個禮拜終於 (才) 搞定這個最簡單的 Line 聊天機器人測試, 到底是難呢還是自己笨都有點搞不清楚了. 總之, 經過這段時間奮鬥算是搞懂整個流程了, 接下去還有更多實務的 Line Bot 要玩, 可參考官方範例 :


2024-02-01 補充 : 

如果用瀏覽器拜訪 Webhook URL 會得到 "Method Not Allowed" 回應 :



 
這是因為此網址必須用 POST 方法提出請求, 而網址列是使用 GET 方法之故. 


2024-03-08 補充 :

看到一篇 iT 邦幫忙好文章 :


2024年1月29日 星期一

在 Python v3.12 安裝 line-bot-sdk 套件出現 Failed building wheel for multidict 錯誤的問題

今天持續測試 Line Bot, 進展到安裝 Line Messaging API 的開發套件 line-bot-sdk 時出現 "Failed building wheel for multidict" 的錯誤訊息 : 

D:\python\flask>pip install line-bot-sdk    
Collecting line-bot-sdk
  Using cached line_bot_sdk-3.7.0-py2.py3-none-any.whl.metadata (13 kB)
Collecting requests==2.31.0 (from line-bot-sdk)
  Using cached requests-2.31.0-py3-none-any.whl.metadata (4.6 kB)
Collecting urllib3<3,>=2.0.5 (from line-bot-sdk)
  Using cached urllib3-2.1.0-py3-none-any.whl.metadata (6.4 kB)
Collecting aiohttp==3.9.1 (from line-bot-sdk)
  Using cached aiohttp-3.9.1-cp312-cp312-win_amd64.whl.metadata (7.6 kB)
Collecting future (from line-bot-sdk)
  Using cached future-0.18.3-py3-none-any.whl
Collecting pydantic<3,>=2.0.3 (from line-bot-sdk)
  Using cached pydantic-2.5.3-py3-none-any.whl.metadata (65 kB)
Collecting aenum>=3.1.11 (from line-bot-sdk)
  Using cached aenum-3.1.15-py3-none-any.whl.metadata (3.7 kB)
Collecting python-dateutil>=2.5.3 (from line-bot-sdk)
  Using cached python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Collecting Deprecated (from line-bot-sdk)
  Using cached Deprecated-1.2.14-py2.py3-none-any.whl.metadata (5.4 kB)
Collecting attrs>=17.3.0 (from aiohttp==3.9.1->line-bot-sdk)
  Using cached attrs-23.2.0-py3-none-any.whl.metadata (9.5 kB)
Collecting multidict<7.0,>=4.5 (from aiohttp==3.9.1->line-bot-sdk)
  Using cached multidict-6.0.4.tar.gz (51 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Installing backend dependencies ... done
  Preparing metadata (pyproject.toml) ... done
Collecting yarl<2.0,>=1.0 (from aiohttp==3.9.1->line-bot-sdk)
  Using cached yarl-1.9.4-cp312-cp312-win_amd64.whl.metadata (32 kB)
Collecting frozenlist>=1.1.1 (from aiohttp==3.9.1->line-bot-sdk)
  Using cached frozenlist-1.4.1-cp312-cp312-win_amd64.whl.metadata (12 kB)
Collecting aiosignal>=1.1.2 (from aiohttp==3.9.1->line-bot-sdk)
  Using cached aiosignal-1.3.1-py3-none-any.whl (7.6 kB)
Collecting charset-normalizer<4,>=2 (from requests==2.31.0->line-bot-sdk)
  Using cached charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl.metadata (34 kB)
Collecting idna<4,>=2.5 (from requests==2.31.0->line-bot-sdk)
  Using cached idna-3.6-py3-none-any.whl.metadata (9.9 kB)
Collecting certifi>=2017.4.17 (from requests==2.31.0->line-bot-sdk)
  Using cached certifi-2023.11.17-py3-none-any.whl.metadata (2.2 kB)
Collecting annotated-types>=0.4.0 (from pydantic<3,>=2.0.3->line-bot-sdk)
  Using cached annotated_types-0.6.0-py3-none-any.whl.metadata (12 kB)
Collecting pydantic-core==2.14.6 (from pydantic<3,>=2.0.3->line-bot-sdk)
  Using cached pydantic_core-2.14.6-cp312-none-win_amd64.whl.metadata (6.6 kB)
Collecting typing-extensions>=4.6.1 (from pydantic<3,>=2.0.3->line-bot-sdk)
  Using cached typing_extensions-4.9.0-py3-none-any.whl.metadata (3.0 kB)
Requirement already satisfied: six>=1.5 in c:\users\tony1\appdata\local\programs\python\python312\lib\site-packages (from python-dateutil>=2.5.3->line-bot-sdk) (1.16.0)
Collecting wrapt<2,>=1.10 (from Deprecated->line-bot-sdk)
  Using cached wrapt-1.16.0-cp312-cp312-win_amd64.whl.metadata (6.8 kB)
Using cached line_bot_sdk-3.7.0-py2.py3-none-any.whl (748 kB)
Using cached aiohttp-3.9.1-cp312-cp312-win_amd64.whl (362 kB)
Using cached requests-2.31.0-py3-none-any.whl (62 kB)
Using cached aenum-3.1.15-py3-none-any.whl (137 kB)
Using cached pydantic-2.5.3-py3-none-any.whl (381 kB)
Using cached pydantic_core-2.14.6-cp312-none-win_amd64.whl (1.9 MB)
Using cached urllib3-2.1.0-py3-none-any.whl (104 kB)
Using cached Deprecated-1.2.14-py2.py3-none-any.whl (9.6 kB)
Using cached annotated_types-0.6.0-py3-none-any.whl (12 kB)
Using cached attrs-23.2.0-py3-none-any.whl (60 kB)
Using cached certifi-2023.11.17-py3-none-any.whl (162 kB)
Using cached charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl (100 kB)
Using cached frozenlist-1.4.1-cp312-cp312-win_amd64.whl (50 kB)
Using cached idna-3.6-py3-none-any.whl (61 kB)
Using cached typing_extensions-4.9.0-py3-none-any.whl (32 kB)
Using cached wrapt-1.16.0-cp312-cp312-win_amd64.whl (37 kB)
Using cached yarl-1.9.4-cp312-cp312-win_amd64.whl (76 kB)
Building wheels for collected packages: multidict
  Building wheel for multidict (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building wheel for multidict (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [74 lines of output]
      *********************
      * Accelerated build *
      *********************
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build\lib.win-amd64-cpython-312
      creating build\lib.win-amd64-cpython-312\multidict
      copying multidict\_abc.py -> build\lib.win-amd64-cpython-312\multidict
      copying multidict\_compat.py -> build\lib.win-amd64-cpython-312\multidict
      copying multidict\_multidict_base.py -> build\lib.win-amd64-cpython-312\multidict
      copying multidict\_multidict_py.py -> build\lib.win-amd64-cpython-312\multidict
      copying multidict\__init__.py -> build\lib.win-amd64-cpython-312\multidict
      running egg_info
      writing multidict.egg-info\PKG-INFO
      writing dependency_links to multidict.egg-info\dependency_links.txt
      writing top-level names to multidict.egg-info\top_level.txt
      reading manifest file 'multidict.egg-info\SOURCES.txt'
      reading manifest template 'MANIFEST.in'
      warning: no previously-included files matching '*.pyc' found anywhere in distribution
      warning: no previously-included files found matching 'multidict\_multidict.html'
      warning: no previously-included files found matching 'multidict\*.so'
      warning: no previously-included files found matching 'multidict\*.pyd'
      warning: no previously-included files found matching 'multidict\*.pyd'
      no previously-included directories found matching 'docs\_build'
      adding license file 'LICENSE'
      writing manifest file 'multidict.egg-info\SOURCES.txt'
      C:\Users\tony1\AppData\Local\Temp\pip-build-env-jkzgbslr\overlay\Lib\site-packages\setuptools\command\build_py.py:207: _Warning: Package 'multidict._multilib' is absent from the `packages` configuration.
      !!

              ********************************************************************************
              ############################
              # Package would be ignored #
              ############################
              Python recognizes 'multidict._multilib' as an importable package[^1],
              but it is absent from setuptools' `packages` configuration.

              This leads to an ambiguous overall configuration. If you want to distribute this
              package, please make sure that 'multidict._multilib' is explicitly added
              to the `packages` configuration field.

              Alternatively, you can also rely on setuptools' discovery methods
              (for example by using `find_namespace_packages(...)`/`find_namespace:`
              instead of `find_packages(...)`/`find:`).

              You can read more about "package discovery" on setuptools documentation page:

              - https://setuptools.pypa.io/en/latest/userguide/package_discovery.html

              If you don't want 'multidict._multilib' to be distributed and are
              already explicitly excluding 'multidict._multilib' via
              `find_namespace_packages(...)/find_namespace` or `find_packages(...)/find`,
              you can try to use `exclude_package_data`, or `include-package-data=False` in
              combination with a more fine grained `package-data` configuration.

              You can read more about "package data files" on setuptools documentation page:

              - https://setuptools.pypa.io/en/latest/userguide/datafiles.html


              [^1]: For Python, any directory (with suitable naming) can be imported,
                    even if it does not contain any `.py` files.
                    On the other hand, currently there is no concept of package data
                    directory, all directories are treated like packages.
              ********************************************************************************

      !!
        check.warn(importable)
      copying multidict\__init__.pyi -> build\lib.win-amd64-cpython-312\multidict
      copying multidict\py.typed -> build\lib.win-amd64-cpython-312\multidict
      running build_ext
      building 'multidict._multidict' extension
      error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for multidict  
Failed to build multidict
ERROR: Could not build wheels for multidict, which is required to install pyproject.toml-based projects

這些訊息令人一頭霧水, 似乎是與沒有安裝 Visual C++ 有關, 我搜尋到下面這篇文章, 發現有可能是 Python 版本的問題 : 


我從回覆訊息中讀到有人從舊 Python 版本升版至 v3.12 時也出現此問題 : 




我的本機 Python 版本剛好就是 v3.12 : 

C:\Users\tony1>python 
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

檢查 Thonny 自帶的 Python 版本是 v3.10, 在 Thonny 安裝 line-bot-sdk 就完全沒問題. 可見版本最新不見得最好用啊!

2024 年第 4 周記事

時光匆匆, 2024 的第一個月即將結束, 本周的閒暇時間都花在 Line Bot 的測試, 對整個設定流程已很清楚, 但就是卡在後端應用伺服器上 Flask 程式一直跑不出來, 到周末才搞定. 

周日本來要整理鄉下書房, 但爸說門前的水圳上以前母親架的木頭 (搭來種絲瓜用的) 崩了, 上面積壓了一堆砍下來的蓮霧與龍眼樹枝垮下來阻礙了河道暢通, 要我清一清水圳, 拿了鋤頭與畚箕穿上雨鞋下水去抬, 發現根本動不了, 上面堆積的枯樹枝葉太重了. 於是先將枯枝拿到田裡去燒掉, 然後用鋤頭挖淤泥, 忙了三個小時才清完, 弄得全身髒兮兮不說, 抬淤泥去田裡倒搞得腰酸背痛, 不知是老了還是欠操. 

本周還是持續埋頭測試 Line 聊天機器人, 本來以為照書依樣畫葫蘆很快就能搞定, 結果除了搞懂 Line Bot 設定與流程花了很多時間, 實際用 Flask 測試時狀況一大堆, 先是 Flask 網站無回應, 然後是 ngrok 新版指令問題, 還有 Line Bot SDK 也是出新版, 與書上範例有所不同 ... 弄了兩周連一個機器人都沒影.  

不過週六下午參加了 MQTT 社友陳文舟老師的收費 GPT 機器人課程 "人人都有自己的 GPT AI 機器人", 倒是一個下午就簡單弄出一個連結 GPT4 的機器人, 開心! 好在過去兩周摸熟 Line Bot 設定流程, 才能快速上手. 此課程使用 coze.com 所提供的平台, 免寫程式只要了解設定流程即可做出一個聊天機器人, 實在太帥了, 期待下集. 

本周發現 Netflix 的一部金賢珠與朴喜洵主演的迷你韓劇 "遺贈的秘密", 只有 6 集, 適合愛推理, 適合下班後想繼續把腦燒壞的人, 我已看到一半, 好看. 

峰大師要嫁女兒 (珠珠) 了, 周日晚上拿了喜餅放在管理室, 日期訂在 3/23 (六). 



2024年1月28日 星期日

momo 買書一本 : ChatGPT原理-從PyTorch中的NLP功能讓你一腳跨入自然語言

上周末這本書 momo 有單日優惠價 611 元 (約 69 折) 但我忘記下單, 就一直放在購物車, 今天收到 momo 的降價通知信又有 611 了, 趕緊把握機會買下來 :





因還有 1021 元 momo 幣, 先用掉其中的零頭 21 元, 實付 590 元 :





直接從 69 折變 67 折好爽 (有夠阿 Q, 呵呵). 

2024年1月27日 星期六

Python 學習筆記 : Flask 網站在本機 localhost 無回應的問題

最近在我的 LG 筆電 (Win 11) 測試 Line Bot 時, 利用 Flask 在本機建立一個網站當作後端應用伺服器, 但光是一個基本的 Flask 網站, 運行後用 http://localhot:port 或 http://127.0.0.1:port 瀏覽都一直轉圈圈沒有顯示網頁, 很久很久之後 (time out) 才顯示 "網站無回應". 開始運行時防火牆會詢問是否要允許存取, 我都有勾選公用與私用皆允許啊! 真奇怪, 以前這樣做都不曾有此問題, 參考 :


原先以為是 Win 11 的問題, 但我在同樣是 Win 11 的舊筆電 Acer Swift 5 上跑卻可順利顯示網頁, 比較兩個 Flask 版本也同樣是 v3.1.0, 看來應該與作業系統無關. 晚上回到鄉下, 用那台 LEMEL 老電腦跑也是不行 (不管是用命令列用 python app.py 執行還是在 Thonny 按 Play 見執行都一樣), 況且其 Flask 版本還是較舊的 v2.3.2, 所以應該與 Flask 版本無關, 總之是原因不明. 

我用谷歌大神探索解決辦法時找到 下面這兩篇文章 :


作者是在命令列用 flask run -h localhost -p 3000 的指令 (指定 host 為 localhost, 埠號為 3000) 執行 Flask 應用程式的, 但我用此指令執行卻出現 "Could not locate a Flask application" 的錯誤訊息 : 

D:\Python\flask>flask run -h localhost -p 3000  
Usage: flask run [OPTIONS]
Try 'flask run --help' for help.

Error: Could not locate a Flask application. Use the 'flask --app' option, 'FLASK_APP' environment variable, or a 'wsgi.py' or 'app.py' file in the current directory.

搜尋此訊息找到下面這篇文章 :


原來 flask run 指令固定會到目前目錄下找 app.py 來執行, 我原來的 Flask 應用程式檔名為 flask_app.py, 把它改成 app.py 之後就可順利執行了

D:\Python\flask>flask run -h localhost -p 3000    
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://localhost:3000  
Press CTRL+C to quit
127.0.0.1 - - [27/Jan/2024 20:50:38] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2024 20:50:38] "GET /favicon.ico HTTP/1.1" 404 -

不管是用 http://localhost:3000 還是 http://127.0.0.1:3000 都能順利顯示網頁 :





回到我的 LG 筆電依照上述辦法將 Flask 應用程式名稱改為 app.py, 執行 flask run 指令後用瀏覽器連線 127.0.0.1, 結果就能順利顯示網頁了. 結論是 : 
  • 在本機測試 Flask 應用程式時最好使用 flask run 指令.
  • Flask 應用程式檔名要用 app.py. 
雖然尚不知用 python 指令執行 Flask 應用程式在某些電腦可以順利顯示網頁, 但某些電腦卻不行的原因, 但至少找到了解決方案, 開心! 

2024年1月26日 星期五

好站 : Flask想上線? 你還需要一些酷東西

最近在學習 Line Bot 時要用到 Flask, 在搜尋資料時找到下面這篇教學, 作者以豐富的圖解說明 Web Server, WSGI Server 與 Apllication Server 的差異, 以及 HTTP 請求回應流程, 說明淺顯易懂, 值得一讀 :



市圖還書 1 本 : 創客.自造者工作坊 : 用AI影像辨識學機器學習

本書使用 p5.js + ml5.js 實作網頁上的機器學習, 我只看到前三章, 因有人預約需還, 下次再借回來 : 
以前都以為 p5.js 只是互動藝術工具而已, 原來也可以作為 GUI, 而且具有互動性. 參見 :

2024年1月25日 星期四

好站 : PIP教學:安裝、更新和移除Python套件

今天在測試 Flask 的版本差異時找到下面這篇教學, 把 Python 的套件安裝程式 pip 用法整理得非常完整又易懂, 特地記下來存參 :


2024年1月24日 星期三

高雄市立圖書館書籍推薦

上回去河堤還書時跟館員閒聊得知, 如果有覺得不錯的書可以推薦給圖書館購買, 當時忘記問要在市圖網站哪裡推薦, 今天線上續借時發現下面這本書預約人數達 6 人 : 


亦即現在預約要半年後才會輪到我, 全館只有一本實在僧多粥少, 於是搜尋了一下終於找到推薦網址如下 : 


不過一個帳號每個月最多只能推薦 5 本. 

2024年1月22日 星期一

如何將英文 PDF 翻譯成繁體中文

最近水某要我幫她將英文的臨床研究計畫書翻成中文, 我使用 Google 翻譯上傳 WORD 檔很快就可下載翻譯後的文件, 非常好用 : 





把待翻譯的文件拖曳到左邊的框框, 然後按 "翻譯" 鈕即可. 哇, AI 的進步讓翻譯變成只是舉手之勞, 不過翻譯結果有些地方還是需要細阿給一下. 

既然 WORD 檔可以, 那 PDF 應該也可以吧? 我找了一個英文電子書上傳, 結果也是一分鐘不到就把 300 多頁的電子書繁體化ㄟ (文字沒問題, 但公式格式似乎不佳), 我看以後翻譯外文書大概一個月內就可以完成編輯出版了. 

我又用 chateverwhere 來翻譯, 結果它居然說不能處理 PDF 檔, 有可能是我用免費版的關係. 另外 Bard 則是無法翻譯超過 300 頁的 PDF 檔. 

也可以用 Google 雲端硬碟的 "工具/翻譯文件" 來翻, 結果與用谷歌翻譯一樣, 參考 :


2024年1月21日 星期日

2024 年第 3 周記事

哇, 不是才跨年嗎? 居然已過了三周, 真是太可怕了. 離過年不到三周, 得開始大掃除, 我週六早上便回鄉下, 下午開始整理庫房, 裡面堆了非常多可回收的塑膠罐, 袋子與紙箱, 還有很多母親以前的菜種子, 有些東西放太久已不堪使用, 全部丟垃圾袋與回收袋, 整理東西最重要的就是斷捨離. 下周整理重點是舊衣服與書房. 

今天下午在整理庫房時發現一個掛在牆上的紙袋, 拿下一看居然是兩把沖天炮, 不知是哪年過年買給小狐狸們玩卻沒用完的, 找來打火機試射發現幾乎都可以射上去, 但不見得會爆, 應該是放了很多年裡面有點受潮 :


 


放了一支又一支無法停下來, 真是太好玩了. 小時候家裡窮沒機會玩沖天炮, 我是趁陪小狐狸們長大的過程中補玩的, 哈哈. 

上週姐姐回來高雄投票, 週日本想好好推一下進度, 但卻陪姊姊看了一整天后宮甄環傳, 然後在接下來的一周都看, 終於在周五晚上跟菁菁一起把結局看完. 這部電視劇十年前很轟動, 但我沒看, 但看了後面的延禧攻略. 甄環傳寫的是雍正朝的後宮, 而延禧則是乾隆朝. 晚上回來又看到水某在看韓劇 "烈女朴氏契約結婚傳", 是女神李世榮的最新作品 (穿越劇), 但現在沒時間, 先記下來過年時再看.  

本周暫停 Azure 的學習腳步, 回頭學 Line Bot, 之前學一半就停下來, 因為接下來要配合 GPT API 使用. 

2024年1月19日 星期五

高科大還書 2 本 : 一步到位! Python 程式設計 & Deep Learning深度學習基礎

因有兩本預約書到館, 中午午休時拿下面兩本書去交換 :
No.1 只剩最後一章 (16) 關於 SciPy 的還沒看, No.2 有關於 RNN/LSTM 的詳解, 這兩本都會回借 (等消化完其他書). 

好書 : GPT 語言模型大揭密-OpenAI API 全攻略

此書借自母校圖書館, 因有人預約所以趕緊讀完後要拿去還了 :



Source : 天瓏


此書譯自 Packt 於 2023 年 2 月出版的這本書 : 



Source : 天瓏



不過關於 OpenAI API 的介紹其實是第三章, 後面兩章都是跟企業如何應用 ChatGPT 有關, 我就瀏覽而已. 以下是讀後摘要 :
  1. GPT=Generative Pre-trained Transformer (生成式預訓練變換器)
  2. GPT 模型是由位於美國舊金山的 AI 公司 OpenAI 所建立, 其目標是創造一個不受限於特定任務, 能像人類一樣在各種任務上表現出色的通用人工智慧產品. OpenAI 在 2018 年發表的 GPT-1 模型研究報告中指出, 結合 Transformer 與非監督式預訓練可以實現強大的自然語言理解能力, 並且可在少量語料的微調下執行各種 NLP 任務.  
  3. ChatGPT 可以完成 NLP 的四大任務 :
    (1). 分類 (例如情緒分析, 垃圾郵件偵測)
    (2). 命名實體 (NER) 辨識
    (3). 摘要 (summarization)
    (4). 文本生成 (text gerneration)
  4. GPT 演化史 :
    2018-06 : 發表 GPT-1, 使用 BooksCorpus 訓練, 包含 1.17 億個參數. 
    2019-02 : 發表 GPT-2, 包含 15 億個參數, 可進行多重任務操作. 
    2020-05 : 發表 GPT-3 論文 (https://arxiv.org/abs/2005.14165), 包含 1750 億個參數
    2020-06 : 發布 OpenAI API 之 GPT3 使用權限
  5. NLP=計算語言學+機器學習, 可識別上下文, 理解自然語言意圖之智慧機器.
  6. GPT-3 是一個通用的大語言模型, 在 GPT-3 之前並沒有一個語言模型能在各種 NLP 任務上讓人滿意. 
  7. 一個 AI 大語言模型 (LLM) 是通過大型語料訓練而得, 就像 Gladwell 在 "異數 (Outlier)" 這本書所說的 10000 小時練習變成專家, 大語言模型就是經過數十萬小時學習的人類知識專家. 
  8. LLM 的微調 (fine-tuning) 是使用專門的資料集對 LLM 進行額外的訓練, 可以將預訓練模型進一步調整以符合特定需求, 這比從頭開始訓練更快更有效率.
  9. GPT-3 是在五個資料集的文本語料庫訓練而得 :
    (1). Common Crawl : 主要是 8 年網路爬蟲之網頁資料
    (2). WebTex2 : OpenAI 內部精選的高品質網頁資料.
    (3/4). Book1 & Book2 : 包含數萬本不同主題之書籍
    (5). Wikipedia : 至 2019 年為止之英語維基百科文本約 580 萬篇
    這些語料庫合計約 1 兆個單字, 其中英語約 93.7%, 德語 1.2%, 法語 1%.
  10. LLM 的突破性進展來自於 Google 於 2017 年發表的一種可以快速處理文本這種序列式資料的深度神經網路 Transformer (轉換器), 它是一種由編碼器 (encoder) 與解碼器 (decoder) 所組成的 seq2seq 結構, 但放棄了傳統的 RNN 與 CNN, 而是採用注意力 (attention mechanism) 機制來平行處理序列的轉換. Transformer 的發明最初是為了改善 AI 在機器翻譯上的表現. 不過 GPT 模型只使用了 Transformer 神經網路中的解碼器部分
  11. 注意力機制模仿人類大腦在處理序列資料時會集中注意力於序列中的特定部分, 使用機率來表示序列中最相關的部分. 例如 "The cat sat on the mat once it ate the mouse" 中的 it 是指 cat 還是 mat? Tranformer 會用機率來表示 it 與 cat 強烈相關, 這就是注意力. 注意力機制讓 Transformer 能濾掉噪音專注於重要的訊息, 將語意相關但沒有明顯標記指向彼此的兩個單詞連接起來. 與其它的神經網路相比, Transformer 更能理解句子中單詞的上下文 (context). 
  12. Transformer 有兩種注意力機制 :
    (1). 自注意力機制 (self-attention) : 一個句子中各單詞間的關係
    (2). 編碼器-解碼器注意力機制 : 從來源句到目標句單詞之間的關係
  13. GPT-1 在 NLP 的零樣本 (zero-shot) 任務中表現良好. 所謂零樣本學習能力是指模型在沒有先前看過任務範例的情況下執行一項任務的能力. 
  14. GPT-2 是在比 GPT-1 更大的資料集 (40GB 文本) 與更多參數 (15 億) 上訓練, 其研究報告指出, 這可以提升語言模型理解任務的能力, 它與 GPT-1 不同之處為可進行多重任務操作 (multitask). 


2024年1月18日 星期四

註冊氣象資料開放平台會員與取得 API 授權碼

去年在線上課程中曾看過老師使用中央氣象局的象資料開放平台為範例來講解如何使用 Python 程式透過 API 來擷取網路上的公開資料, 上課時間緊湊也沒機會實作, 今天測試完 Postman 想說順勢註冊一下會員來取得授權碼, 以便後續用 Python 來練習抓資料.  

氣象資料開放平台網址如下 : 





氣象資料開放平台已改版為須註冊為會員, 然後申請 API 金鑰才能查詢 (以前可以直接抓), 故要先按右上角的 "登入/註冊" 鈕進入登入頁, 初次使用者可以使用 Facebook 帳號登入, 或選擇 "氣象會員登入", 按底下的 "加入會員" : 




填好後按 "送出" : 




送出成功會收到一封確認信, 開啟 Email 按確認超連結即完成註冊 : 




按 "前往資料開放平台" 超連結前往 API 授權碼頁面, 按 "取得授權碼" 鈕會在右邊出現授權碼, 將其複製到安全的地方保存 : 




有了這個授權碼即可透過它來抓平台上的氣象資料了, 用法參考開發手冊說明 : 


不過還先不用寫程式, 此平台已實作 Web 介面讓我們可以立刻輸入授權碼後擷取資料 : 





可選的參數很多, 但都有預設值, 為了減少傳回值數量, 選擇 LocationName 為高雄市, 然後按底下的 "Execute" 鈕即可, 回應訊息如下 :


{
  "success": "true",
  "result": {
    "resource_id": "F-C0032-001",
    "fields": [
      {
        "id": "datasetDescription",
        "type": "String"
      },
      {
        "id": "locationName",
        "type": "String"
      },
      {
        "id": "parameterName",
        "type": "String"
      },
      {
        "id": "parameterValue",
        "type": "String"
      },
      {
        "id": "parameterUnit",
        "type": "String"
      },
      {
        "id": "startTime",
        "type": "Timestamp"
      },
      {
        "id": "endTime",
        "type": "Timestamp"
      }
    ]
  },
  "records": {
    "datasetDescription": "三十六小時天氣預報",
    "location": [
      {
        "locationName": "高雄市",
        "weatherElement": [
          {
            "elementName": "Wx",
            "time": [
              {
                "startTime": "2024-01-18 12:00:00",
                "endTime": "2024-01-18 18:00:00",
                "parameter": {
                  "parameterName": "晴時多雲",
                  "parameterValue": "2"
                }
              },
              {
                "startTime": "2024-01-18 18:00:00",
                "endTime": "2024-01-19 06:00:00",
                "parameter": {
                  "parameterName": "晴時多雲",
                  "parameterValue": "2"
                }
              },
              {
                "startTime": "2024-01-19 06:00:00",
                "endTime": "2024-01-19 18:00:00",
                "parameter": {
                  "parameterName": "多雲",
                  "parameterValue": "4"
                }
              }
            ]
          },
          {
            "elementName": "PoP",
            "time": [
              {
                "startTime": "2024-01-18 12:00:00",
                "endTime": "2024-01-18 18:00:00",
                "parameter": {
                  "parameterName": "0",
                  "parameterUnit": "百分比"
                }
              },
              {
                "startTime": "2024-01-18 18:00:00",
                "endTime": "2024-01-19 06:00:00",
                "parameter": {
                  "parameterName": "10",
                  "parameterUnit": "百分比"
                }
              },
              {
                "startTime": "2024-01-19 06:00:00",
                "endTime": "2024-01-19 18:00:00",
                "parameter": {
                  "parameterName": "20",
                  "parameterUnit": "百分比"
                }
              }
            ]
          },
          {
            "elementName": "MinT",
            "time": [
              {
                "startTime": "2024-01-18 12:00:00",
                "endTime": "2024-01-18 18:00:00",
                "parameter": {
                  "parameterName": "24",
                  "parameterUnit": "C"
                }
              },
              {
                "startTime": "2024-01-18 18:00:00",
                "endTime": "2024-01-19 06:00:00",
                "parameter": {
                  "parameterName": "20",
                  "parameterUnit": "C"
                }
              },
              {
                "startTime": "2024-01-19 06:00:00",
                "endTime": "2024-01-19 18:00:00",
                "parameter": {
                  "parameterName": "20",
                  "parameterUnit": "C"
                }
              }
            ]
          },
          {
            "elementName": "CI",
            "time": [
              {
                "startTime": "2024-01-18 12:00:00",
                "endTime": "2024-01-18 18:00:00",
                "parameter": {
                  "parameterName": "舒適"
                }
              },
              {
                "startTime": "2024-01-18 18:00:00",
                "endTime": "2024-01-19 06:00:00",
                "parameter": {
                  "parameterName": "稍有寒意至舒適"
                }
              },
              {
                "startTime": "2024-01-19 06:00:00",
                "endTime": "2024-01-19 18:00:00",
                "parameter": {
                  "parameterName": "稍有寒意至舒適"
                }
              }
            ]
          },
          {
            "elementName": "MaxT",
            "time": [
              {
                "startTime": "2024-01-18 12:00:00",
                "endTime": "2024-01-18 18:00:00",
                "parameter": {
                  "parameterName": "26",
                  "parameterUnit": "C"
                }
              },
              {
                "startTime": "2024-01-18 18:00:00",
                "endTime": "2024-01-19 06:00:00",
                "parameter": {
                  "parameterName": "24",
                  "parameterUnit": "C"
                }
              },
              {
                "startTime": "2024-01-19 06:00:00",
                "endTime": "2024-01-19 18:00:00",
                "parameter": {
                  "parameterName": "26",
                  "parameterUnit": "C"
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

可見氣象資料放在 ['result']['records'] 裡面. 回應訊息可以貼到 JSON Viewer 整理 :





參考 :