2026年7月24日 星期五

岡山之旅 Day 1 (7/24) : 出發

今天中午 12:40 從小港機場出發前往岡山自助旅行, 此行是應老同事阿中要求規劃的, 他在三月團旅第一次出國到日本之後便迷上那裏的美景, 有點日文根基的他開始拿回日語課本複習, 拜託我帶他在炎夏時跑一趟日本水蜜桃故鄉岡山, 從訂機票旅館, 登錄 VJW 到常用旅遊 App 用法都要手把手教會他, 學會後就能想飛就飛.

由於暑假到日本旅遊的人多, 所以我破天荒地在兩個月之前的五月中旬便完成了行程規劃 (之前都是拖到 1~2 周前, 細部行程更是前一天晚上才確定), 一起買好機票訂好旅館, 並預約了水蜜桃觀光果園的採果課程. 以往訂機票與旅館都是水某會處理, 這回得自己做, 對我也是一種學習. 行程規劃紀錄在這篇 :


虎航周一, 三, 五有班機直飛岡山桃太郎機場, 中午 12:40 起飛只要早上 10:30 前報到即可. 早上 9 點多水某載我到凹子底坐捷運到小港機場與阿中會合後辦理出境登機, 這也是我首次出國搭捷運. 抵達岡山已下午 16:30, 第一天就只是交通而已, 行程表如下 : 




2026年7月23日 星期四

岡山之旅 Day 0 (7/23) : 虎航自助報到

昨天接到虎航預辦登機通知 Email, 原來在出發前兩天就可以線上辦理自助報到, 上傳護照內頁圖檔驗證內容 (姓名, 生日, 護照號碼, 到期日等) 無誤後就可以下載電子登機證, 屆時到機場櫃台就可以直接託運行李, 不需要排隊報到了. 

按 Email 底下的 "預辦登機" 鈕 : 




填寫當初購票時取得之訂位代號 (Email 標題就有), 護照英文姓名 (不用輸入 -, 輸入也會被去除), 按 "開始報到" :






按去程航班右邊的 "可報到" 鈕 :




接下來是行李託運與安檢相關規定事項, 閱讀後勾選底下 "我已完整閱讀並同意以上事項" 後按 "下一步" :






接下來是要輸入護照資料, 如果可以用影印機掃描護照內頁最好, 辨識成功率較高 (但也要仔細檢查), 用手機拍照要橫拍, 光線也要注意才能順利辨識, 如果都失敗就用手動輸入 : 




檢視辨識資料是否正確 (錯誤資料可能影響登機) :




資料驗證過關後顯示已加購項目, 此處還可再加購, 若不需要就按左邊 "不加購到下一步" 鈕完成自助報到, 並顯示電子登機證下載超連結 : 




完成自助報到後, 虎航也會寄一封包含電子登機證 pdf 檔的 Email, 將此 pdf 存入手機, 有印表機最好也列印出來作為備份. 

iPhone 手機加入 eSIM 的方法

明天要跟老同事阿中前往日本岡山採水蜜桃, 主要是應其要求, 教他如何在日本自助旅行. 前天已購買中華電信行動漫遊方案 (暑假日本定量型 10 天 10GB 688 元), 今天上 KLOOK 為備用手機 iPhone SE2 買 eSIM 卡 (軟銀 6 天每日 1GB) :



付款完成後點右下角的 "帳戶" 點選 "我的訂單" 按此訂單進去就會出現 eSIM 卡的 QR 碼, 把它截圖印出來, 或傳送到同行家人手機 LINE 備用. 

到達目的地機場後, 開啟 iPhone 的 WiFi 功能連到家人或機場的免費 WiFi :




進入 "行動服務", 按底下的 "加入 eSIM" :




按 "使用行動條碼" :




拿出列印的 QR 碼或家人手機中的 QR 碼, 按 "掃描行動條碼" 掃描即可 :



掃描完成後開啟行動行動數據選擇此 eSIM 即可上網. 

iPhone 手機螢幕截圖方法

我的備用手機 iPhone SE2 有時需要螢幕截圖 (例如紀錄如何啟用 eSIM), 因為它有 HOME 鍵, 所以傳統截圖是同時按電源 + HOME 鍵即可, 但要同時按兩個鍵不方便, 也不好控制, 我今天問 Gemini , 原來可以用輕點背面 2 或 3 下方式截圖, 設定方法如下 : 

打開設定, 點選 "輔助使用" : 





點選身體動作項目下的 "觸控" :




開啟 "背面輕點" :




按點兩下或點三下, 勾選 "截圖" 即可 :




設定好後, 手指在手機背板輕敲兩下就可截圖了. 

2026年7月22日 星期三

Google Antigravity 學習筆記 : 重構 serverless 函式執行平台 (六)

前一篇在 Mapleboard 上成功地佈署了新版 serverless 平台, 驗證 API Key 功能正常, 整個專案重構來作業已近尾聲, 本篇要將專案提交上傳更新 GitHub 上的 repo (儲存庫). 

本系列全部文章索引參考 :



8. 提交新版 serverless 與上傳 GitHub : 

在提交之前, 我回顧了前面的測試過程, 發現剛開始時是從 https://github.com/tony1966/serverless.git 複製專案到 D:\antigravity_cli\projects 底下, 然後將其打上 tag 標記後建立一個新分支 api-token-auth, 再叫 agy 用 Claude 模型去重構此專案, 這就形成了 Nested Repository (巢狀儲存庫) : serverless 資料夾內自成一國 (裡面有自己的 .git), 而外層的 antigravity_cli 也有自己的 .git 現象. 

站在 D:\antigravity_cli 的角度看 projects/serverless 時, Git 預設只會把 serverless 當成一個被忽略的子目錄或是一個未追蹤的 gitlink, 兩邊的 Commit 完全是分開互不干擾的. 在 serverless 下提交並 push 時會上傳到 https://github.com/tony1966/serverless 上, 而非 Antigravity CLI 的 repo 庫https://github.com/tony1966/antigravity_cli. 雖然這種國中有國的情況並不少見, 但我想讓專案資料夾與儲存庫的關係單純點, 所以將此 serverless 專案剪下來貼到 D:\ 下, 與 D:\antigravity_cli\projects 分家. 

分家後的 serverless 也要有自己的 .gitignore, 所以我把 Antigravity CLI 大倉庫下的 .gitignore 複製一份來給它用 : 

# ==========================================
# Python 相關快取與編譯檔案
# ==========================================
__pycache__/
*.py[cod]
*$py.class
.pytest_cache/
.poetry/
.venv/
venv/
ENV/
env/

# ==========================================
# 專案實務資料與測試產出
# ==========================================
*.json
*.db
*.log

# ==========================================
# 開發工具與編輯器暫存檔
# ==========================================
.vscode/
.idea/
*.swp
*.bak
.DS_Store
Thumbs.db

# ==========================================
# 敏感資料與環境變數 (絕對不能上傳)
# ==========================================
.env
.env.local
.env.*.local
*.env

分家後的 serverless 專案結構如下 :

PS D:\> tree serverless /f   
列出磁碟區 新增磁碟區 的資料夾 PATH
磁碟區序號為 0000027B 1258:16B8
D:\SERVERLESS
│  .env
│  .gitignore
│  Procfile
│  requirements.txt
│  serverless.db
│  serverless.py
│  serverless_error.log
└─functions
    │  add_function.py
    │  add_table.py
    │  clear_stats.py
    │  delete_function.py
    │  delete_record.py
    │  drop_table.py
    │  edit_function.py
    │  execute_sql.py
    │  export_table.py
    │  hello.py
    │  list_functions.py
    │  list_tables.py
    │  save_function.py
    │  show_schema.py
    │  show_stats.py
    │  update_function.py
    │  view_table.py
    │  __init__.py
    │
    └─apps_backup
          add.py
          hello.py
          linebot_gemini.py
          linebot_gpt.py
          send_books_messages.py
          send_ksml_books_messages.py
          update_ksml_books.py

這樣便可進行 Git 提交作業了, 首先切換到專案目錄下 :

S D:\> cd serverless   

然後用 git add . 指令將所有變更加入暫存區, 把修改過的程式碼與新增的 .gitignore 檔加入追蹤 (.gitignore 內所舉的檔案除外) : 

PS D:\serverless> git add .   
warning: in the working copy of 'functions/save_function.py', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'functions/update_function.py', LF will be replaced by CRLF the next time Git touches it
PS D:\serverless>

報出的 warning 可以忽略. 

然後建立 Commit 紀錄, 將變更封裝並附上明確的功能說明 : 

PS D:\serverless> git commit -m "feat: implement serverless API core with API Key auth"   
[feature/api-token-auth df845ce] feat: implement serverless API core with API Key auth
 5 files changed, 172 insertions(+), 37 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 functions/hello.py

接下來是推送到 GitHub 遠端倉庫的 feature/api-token-auth 分支 (-u 參數會自動建立本地與遠端分支的追蹤關係) :

PS D:\serverless> git push -u origin feature/api-token-auth   
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 16 threads
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 8.71 KiB | 1.24 MiB/s, done.
Total 18 (delta 7), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (7/7), completed with 4 local objects.
remote:
remote: Create a pull request for 'feature/api-token-auth' on GitHub by visiting:
remote:      https://github.com/tony1966/serverless/pull/new/feature/api-token-auth
remote:
To https://github.com/tony1966/serverless.git
 * [new branch]      feature/api-token-auth -> feature/api-token-auth
branch 'feature/api-token-auth' set up to track 'origin/feature/api-token-auth'.

可見 18 個檔案物件已成功打包上傳 (其中包含新的 .gitignore 與 code), 且在 GitHub 成功建立獨立的 feature/api-token-auth 分支與追蹤關係. 這時到 GitHub 去察看此 repo :




可見 GitHub 遠端倉庫 tony1966/serverless 已經順利接收到了最新的變更, 而下方的是 main 分支 (正式生產環境) 的檔案列表, 顯示它依然維持 6 個月前的穩定版本, 只要此 feature/api-token-auth 分支尚未合併到 main 分支就不會影響目前依賴此 repo 的線上服務 (例如 render.com). 

目前暫時先做到這裡, 後續若準備好要把 API Key 驗證功能部署到 Render.com 時, 只要按右上角的 "Compare & pull request" 鈕, 檢查變更內容沒問題後按 "Create pull request" 鈕, 再按 "Merge pull request" 與 "Confirm merge" 鈕即可合併的 main 分支, 完成升版的最後一塊拼圖. 

如果要在終端機下指令合併, 順序如下 : 

# 切換到 main 分支
git checkout main

# 拉取遠端最新 main(確保同步)
git pull origin main

# 將 feature 分支合併進 main
git merge feature/api-token-auth

# 推送回 GitHub main 分支(會觸發 Render 自動部署)
git push origin main

註冊第三個 render.com 帳戶

上週完成 serverless 改版後本想先佈署到 Mapleboard 上, 做實際驗證後再提交上傳 GitHub, 但由於 Mapleboard 站台設定引發疑似光世代數據機的雞肋防火牆阻擋問題, 導致本地的圖書館爬蟲要更新 Mapleboard 的 serverless 資料庫時偶而被阻擋, 這讓我對自架網站可靠性動搖. 反觀我架在 render.com 上的 serverless 只要定時 trigger 卻很穩定在運行, 可見雲端還是比較可靠, 所以今天又註冊了一個 render.com 帳戶來做測試. 

本系列全部測試文章索引參考 :


首先到 render.com 官網按右上角的 Sign Up 鈕進入註冊頁面 :


這次使用 Google 帳戶註冊, 過程比用 email 簡單 :




選擇 Google 帳戶後按 "繼續" 即可 : 





註冊成功直接進入 Dashboard 頁面 :



2026年7月19日 星期日

博客來買書一本 : Gemini 投資理財全攻略

今天在博客來看到這本旗標的書 66 折, 這種好康當然不錯過 :





OpenPoint 折 55 點, 實付 340 元 (約 56 折), 至興店取貨. 

2026 年第 27 周記事

過去一周主要在忙著把我之前寫的 serverless 專案用 agy 重構 (選用 Claude 模型), Claude 的 Coding 能力真的沒話說, 三兩下就搞定了. 周末這兩天我把新版程式佈署到 Mapleboard 時遇到站台設定衝突的干擾, 我已一年多未接觸 Mapleboard 網站設定, 印象有點模糊了, 好在透過 Gemini 協助全面修正設定後已解決, serverless 平台重構算是告一段落了. 這如果是像剛開始創建時手刻的話, 恐怕要花上個把月, 現在沒 AI 真是沒法過日子了. 

週五下午請假載爸去署立醫院回診, 先去小太陽掛號拿降血壓藥, 半路上 QRV 居然熄火, 最近有兩三次怠速熄火紀錄, 只要重啟引擎即可, 但卻回卻出現引擎異常標誌, 所幸休息一下還能發動. 從署醫拿藥出來順路開到附近的 Nissan 保養廠, 初步檢修是曲軸位置與角度感知器異常造成, 因已四點多需留廠, 想說乾脆就順便做 15.5 萬公里保養, 原本也是預約周六要去大中廠保養的. 廠長先載我跟爸回家. 週六保養的技師來電, 表示檢查發現剎車分泵漏油須換, 四條輪胎胎紋已淺, 且雨刷不良建議更換, 這一次維修總共花了 22000, 真是大手筆. 廠長週六下午把車開回來, 說以後就近在他們廠保養就好, 不用去大中廠,我也覺得這樣較方便. 但若八月買 RAV4 的話, QRV 變成備用車, 保養週期會變長, 我可能會改到八百屋去做例行保養.  

本周向福利會寄出諮詢單後, 國都的業務已打電話報價 124 萬, 似乎是可以接受的價格, 下周聯繫時再談. 週四去高都賞車時業務提到希望 8/15 前能決定, 因為目前有銷售競賽. 如果高都下周打電話來, 就用這價格跟她往下談, 可以的話在高都買交車較方便.  

下周五要帶阿中去岡山了, 所以這幾天要複習一下行程並整理行李. 

Google Antigravity 學習筆記 : 重構 serverless 函式執行平台 (五)

經過前面的測試已驗證了重構後的程式碼基本上達成了讓平台具備 API Key 功能的目標, 在提交到 GitHub 之前, 想要先佈署到 Mapleboard 上更新 serverless 到具有 API Key 功能的最新版. 關於 Mapleboard 筆記參考 :


本系列全部文章索引參考 :



7. 在 Mapleboard 佈署新版 serverless : 

先用 VNC Cloud 遠端連線到 Mapleboard 桌面, 開啟終端機, 切換到 serverless 專案目錄下, 用 zip 指令把整個專案除指定之敏感檔案外全部壓縮成 zip 檔 : 

tony1966@LX2438:~/flask_apps/serverless$ zip -r serverless_v4.zip . -x "serverless.db" "serverless_error.log" "*.pyc" "__pycache__/*" ".env"

參數 -r 表示要遞迴壓縮, 即連同所有子資料夾 (如 functions/) 一起打包. serverless_backup.zip 是壓縮結果的檔檔名. 後面的 . . 代表壓縮當前目錄下的所有東西, -x 參數後面接的是排除 (不壓縮) 名單, 這裡排除了本地資料庫 (serverless.db), 日誌檔 (serverless_error.log), Python 快取檔, 以及含有敏感密碼的 .env 檔. 

然後用 WinSCP 連線 Mapleboard, 注意, 之前安裝 fail2ban 時為了提升資安, 已修改 SSH 埠 (不再是預設的 22), 埠號可用下列指令查得 :

tony1966@LX2438:~/flask_apps/serverless$ sudo nano /etc/fail2ban/jail.local  

設定 WinSCP 連線時除了要輸入固定 IP 外, 還要更改 SSH 埠號, 如果用 22 埠是無法連線的. 連線成功後, 先將上面備份的 zip 檔傳送至本地保存. 完成後將本地的 serverless.py 主程式與 functions 資料夾上傳到 Mapleboard 的 serverless 專案目錄下覆蓋舊版程式檔. 

由於主程式 serverless.py 有更改, 所以須用下例指令重啟服務才會運行新版程式 :

tony1966@LX2438:~/flask_apps/serverless$ sudo systemctl restart serverless

用瀏覽器測試 hello.py 函式 : 





在有登入情況下, 對函式的請求無需攜帶 API Key 即可順利執行;  如果沒有登入就會收到 401 錯誤, 例如 :



但修改前一篇的 deploy.py 的 URL 想要進行本地佈署 hello.py 卻出現連線異常與 404 等錯誤, 經查原來我的 Mapleboard 之前在架站時 Nginx 與站台 (主要是 hello 站台與 flask.tony1966.cc) 設定出現埠的衝突, 重啟 Nginx 出現 2~3 個 warning. 經過與 Gemini 討論後, 修改站台設定後終於解決此問題, Nginx 設定檔就徹底理順了, 摘要如下 : 
  • reject_ip 盡職地守在大門口擋掉所有奇奇怪怪的 IP 掃描.
  • flask.tony1966.cc 安全地走 HTTPS 連線, 讓新版 Serverless 平台, 樹莓派爬蟲與電腦部署都能順暢通訊. 
  • hello 站台也成功轉型, 乾乾淨淨地留在 443 埠當作你的 is_alive 測試通道 (Port 8080/8081).
站台清單檢視指令 : ls -l /etc/nginx/sites-enabled/
重啟 Nginx 伺服器指令 : sudo nginx -t
重新載入 Nginx 指令  : sudo systemctl reload nginx

佈署程式 deploy.py 的 URL 要改成 https://flask.tony1966.cc, 下面是佈署市圖爬蟲伺服端程式 update_ksml_books.py 的範例 (伺服端程式都不必為 serverless 升版做任何改變) : 

SERVER_URL="https://flask.tony1966.cc"
API_TOKEN="your-api-key"

# 2. 定義要佈署的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="update_ksml_books"
LOCAL_FILE_PATH="update_ksml_books.py"

再次執行 deploy.py 就順利將函式發佈到 serverless 平台上了 :

D:\python\test>python deploy.py  
🚀 正在將 update_ksml_books.py 更新至 https://flask.tony1966.cc...
✅ 函式更新成功!
伺服器回應: {'func_name': 'update_ksml_books', 'message': '模組 update_ksml_books 已成功更新'}

deploy.py 的完整內容如下 :

# deploy.py
import os
import requests

# 1. 設定伺服器資訊與 API Token
# 地端測試可用 http://127.0.0.1:5000,上雲端後改成你的 Render 網址
SERVER_URL="https://flask.tony1966.cc"
API_TOKEN="your-api-key"

# 2. 定義要佈署的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="update_ksml_books"
LOCAL_FILE_PATH="update_ksml_books.py"

def function_exists(func_name):
    """檢查遠端伺服器上的函式是否已存在(透過 GET 探測)"""
    url=f"{SERVER_URL}/function/{func_name}"
    headers={"X-API-Key": API_TOKEN}
    try:
        response=requests.get(url, headers=headers)
        # 404 表示不存在,其他狀態(200/400/500)表示檔案存在
        return response.status_code != 404
    except requests.exceptions.RequestException:
        return False  # 連線失敗時保守假設不存在

def deploy_function():
    # 檢查本地檔案是否存在
    if not os.path.exists(LOCAL_FILE_PATH):
        print(f"❌ 找不到本地檔案: {LOCAL_FILE_PATH}")
        return
    # 讀取本地最新的程式碼內容
    with open(LOCAL_FILE_PATH, "r", encoding="utf-8") as f:
        new_code=f.read()

    headers={
        "X-API-Key": API_TOKEN,
        "Content-Type": "application/json"
    }
    payload={
        "func_name": TARGET_FUNCTION_NAME,
        "code": new_code
    }

    # 3. 自動判斷:函式已存在 → update,不存在 → save(新增)
    if function_exists(TARGET_FUNCTION_NAME):
        url=f"{SERVER_URL}/function/update_function"
        action="更新"
    else:
        url=f"{SERVER_URL}/function/save_function"
        action="新增"

    print(f"🚀 正在將 {LOCAL_FILE_PATH} {action}至 {SERVER_URL}...")
    try:
        response=requests.post(url, json=payload, headers=headers)
        # 新增成功是 201,更新成功是 200
        if response.status_code in (200, 201):
            print(f"✅ 函式{action}成功!")
            print("伺服器回應:", response.json())
        else:
            print(f"❌ {action}失敗 (狀態碼: {response.status_code})")
            try:
                print("錯誤原因:", response.json())
            except ValueError:
                print("非 JSON 回應內容:", response.text)
    except requests.exceptions.RequestException as e:
        print(f"💥 連線發生異常: {e}")

if __name__ == "__main__":
    deploy_function()

市圖爬蟲程式本機版則需要配合 serverless 添加 API Key 功能而升版, 否則請求都會被 401 拒絕, 這部分記在另一篇.