iT邦幫忙

0

# Day 20 使用 n8n Schedule 排程與 LINE Push API 實現午餐靈感推播

n8n
  • 分享至 

  • xImage
  •  

在昨天的文章中,我們透過 LINE Postback Action 與 SQLite 關聯資料庫,為美食 Agent 打造了個人專屬的收藏夾,讓使用者能一鍵收藏心儀的店家。

回顧過去 19 天的所有功能,系統的互動模式全部屬於**「被動響應(Passive Reply)」**:只有在使用者主動發送文字、點擊按鈕或分享位置時,機器人才會拿著單次有效的 replyToken 進行即時回覆。

但一個真正稱職的貼身生活助理,應該要具備**「主動關懷(Proactive Engagement)」**的能力!
例如:每到工作日的上午 11:30,當大家肚子開始咕嚕咕嚕叫、準備思考午餐時,Agent 能主動敲響使用者的聊天室:「嗨!午餐時間快到囉,今天推薦這家附近的日式定食,要不要試試看?」。

今天 Day 20,我們將學習如何利用 n8n 的 Schedule Trigger(Cron 定時排程) 結合 LINE Messaging API 的 Push Message 端點,打造全自動化的定時推播工作流!


一、Reply Message 與 Push Message 的核心差異

在設計主動推播前,必須先釐清 LINE Messaging API 兩種主要的發訊機制:

比較項目 Reply API (/v2/bot/message/reply) Push API (/v2/bot/message/push)
觸發情境 使用者主動傳訊或點擊按鈕 系統主動發起(定時排程、警報通知)
必要參數 replyToken(單次有效、數秒內過期) to(使用者的 LINE userId)
發送限制 依賴使用者事件,無法由系統隨時觸發 只要知道使用者的 userId,隨時皆可主動發送
官方計費 完全免費,不計入官方免費訊息額度 計入 LINE 官方帳號的免費推播額度(目前輕量方案每月 200 則)

💡 開發者秘訣:
個人開發與測試時,每個月 200 則 Push 額度相當夠用。只要目標對象是我們自己在 SQLite 中記錄的測試 userId,每天推播一次一個月也才消耗 30 則左右!


二、在 FastAPI 中新增「取得推播名單」端點 (app/routers/push.py)

為了讓 n8n 知道該把午餐推播發給誰、以及每個使用者的預設喜好地區,我們在微服務建立一個專門查詢活躍用戶的 API。

建立 app/routers/push.py:

from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from typing import List
from pydantic import BaseModel
from app.database import get_db
from app.models.memory import UserModel

router = APIRouter(
    prefix="/api/v1/push",
    tags=["Push Notification"]
)

class PushTargetUser(BaseModel):
    user_id: str
    favorite_cuisine: str
    default_budget: int
    preferred_location: str

@router.get("/subscribers", response_model=List[PushTargetUser])
async def get_push_subscribers(db: Session = Depends(get_db)):
    """
    獲取同意接收主動推播的使用者名單與其偏好設定
    """
    # 這裡先撈出資料庫中已建檔的使用者(未來可額外加入 is_push_enabled 布林開關)
    users = db.query(UserModel).all()

    subscribers = []
    for u in users:
        subscribers.append(
            PushTargetUser(
                user_id=u.line_user_id,
                favorite_cuisine=u.favorite_cuisine or "全部",
                default_budget=u.default_budget or 300,
                preferred_location="板橋區"  # 或由使用者歷史足跡推算
            )
        )
    return subscribers

在 app/main.py 中掛載該路由:

from app.routers import push
app.include_router(push.router)

三、在 n8n 中建立定時推播工作流 (Cron Workflow)

在 n8n 介面(http://localhost:5678 或你的雲端網址)點擊 Add workflow,建立名為 Daily Lunch Push Notification 的獨立工作流。

Step 1:新增 Schedule Trigger 節點

1.點擊 Add first step,搜尋並新增 Schedule Trigger。

2.觸發設定(Trigger Rules):

Trigger Interval:選擇 Weeks 或 Cron Expression。

Cron Expression:30 11 * * 1-5(代表每逢週一至週五的上午 11:30 準時觸發)。

時區確認:確認 n8n 設定中的時區為 Asia/Taipei(UTC+8)。

Step 2:新增 HTTP Request 取得推播對象清單

1.新增 HTTP Request 節點,命名為 Get Subscribers。

2.設定如下:

Method:GET

URL:http://host.docker.internal:8000/api/v1/push/subscribers(若在雲端則替換為 Render 網址)。

3.測試執行後,n8n 會取得一個包含多位使用者的 JSON 陣列。

Step 3:呼叫隨機盲盒推薦端點 (HTTP Request)

針對每一位使用者,呼叫我們在 Day 18 寫好的隨機抽籤 API:

1.新增 HTTP Request 節點,命名為 Get Random Lunch。

2.設定如下:

Method:POST

URL:http://host.docker.internal:8000/api/v1/recommend/random

JSON Body:

{
  "user_id": "={{ $json.user_id }}",
  "location": "={{ $json.preferred_location }}",
  "budget_max": {{ $json.default_budget }}
}

Step 4:組裝推播卡片與問候語 (Code 節點)

新增 Code 節點,命名為 Build Push Message,為午餐時段量身打造親切的問候排版:

const response = $input.first().json;
const subscriber = $('Get Subscribers').first().json;

if (!response.drawn_restaurant) {
  return []; // 若該區域查無餐廳則略過不推播
}

const shop = response.drawn_restaurant;
const mapUri = `[https://www.google.com/maps/search/?api=1&query=$](https://www.google.com/maps/search/?api=1&query=$){encodeURIComponent(shop.location + ' ' + shop.name)}`;

const greetingText = `☀️ 叮咚!午餐時間快到囉!\n\n` +
                     `今天中午不知道吃什麼嗎?小幫手為你挑選了這家:\n` +
                     `🍴【${shop.name}】\n` +
                     `⭐️ Google 評分:${shop.rating}\n` +
                     `💰 均消:約 ${shop.price_avg} 元\n` +
                     `📍 地址:${shop.location}\n\n` +
                     `祝你有個愉快的午餐時光!✨`;

return {
  target_user_id: subscriber.user_id,
  messages: [
    {
      type: "text",
      text: greetingText,
      quickReply: {
        items: [
          {
            type: "action",
            action: {
              type: "uri",
              label: "🗺️ 查看地圖導航",
              uri: mapUri
            }
          },
          {
            type: "action",
            action: {
              type: "message",
              label: "🎲 換一間推薦",
              text: "幫我隨便抽一間"
            }
          }
        ]
      }
    }
  ]
};

Step 5:呼叫 LINE Push Message API

這是最關鍵的一步,我們使用 Push API 主動發送訊息給指定的 userId:
1.新增 HTTP Request 節點,命名為 LINE Push Message。

2.參數配置:

Method:POST

URL:https://api.line.me/v2/bot/message/push

Authentication:Header Auth

Name:Authorization

Value:Bearer <你的_LINE_CHANNEL_ACCESS_TOKEN>

Headers:Content-Type: application/json

Specify Body:Using JSON

JSON 內容:

  "to": "={{ $json.target_user_id }}",
  "messages": "={{ $json.messages }}"
}

四、手動測試與定時發送驗收

Step 1:手動觸發測試

在 n8n 畫布中直接點擊下方的 Test workflow 按鈕(無需等待 11:30),模擬排程觸發:

1.n8n 節點依序亮起綠燈。

2.拿起手機,在完全沒有傳送任何訊息的前提下,LINE 聊天室立刻彈出推播通知!

3.訊息完整包含店名、地址、均消,底部更附帶「🗺️ 查看地圖導航」與「🎲 換一間推薦」的 Quick Reply 按鈕。

Step 2:啟用自動排程

在 n8n 畫布右上角將工作流切換為 Active。
每週一到週五的上午11:30,伺服器就會在雲端自動喚醒工作流,準時將今日午餐靈感推送到每一位用戶的手機中!
今日結語與明日預告
今天我們讓美食 Agent 跨出了重大的一步:

搞懂了 LINE Reply API 與 Push API 的架構與權限差異。

利用 n8n Schedule Trigger 實現無伺服器、免寫 Cron Daemon 的優雅排程管理。

整合了先前的隨機盲盒演算法與 Quick Reply,打造出極具人情味的主動式午餐小秘書!

至此,我們已經完成了功能面(定位、FSM 多輪對話、轉盤抽籤、收藏夾、主動推播)的全面升級!
但隨著系統開放給更多人使用,外部的惡意攻擊與流量爆發隨之而來。
明天 Day 21,我們將正式進入企業級資安與穩定性防護模組:在 FastAPI 中加入 Rate Limiting(慢速限流防護),防止惡意使用者高頻率刷流量燒乾 Google 與 LLM API 額度! 敬請期待!


*提醒邦友,使用第三方服務/API 時,請務必評估資安風險與隱私保護
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言