在 Telegram 對機器人輸入 text="誠實",大約一分鐘後會收到一個 HTML 檔,打開就是一本四頁的圖文繪本。整條流程跑在 n8n 上,沒有自己寫後端,使用者也不需要碰任何 Prompt。
這篇記錄系統怎麼拆、幾個設計為什麼這樣做,以及目前已知的限制。工作流 JSON 和成品範例放在文末。
1. 系統架構 #
| 層 | 工具 | 負責什麼 |
|---|---|---|
| 介面 | Telegram Bot API | 接收主題,回傳成品檔案 |
| 流程 | n8n(自架) | 輸入過濾、迴圈控制、資料整理 |
| 文字 | Groq API,llama-3.3-70b-versatile |
改編故事,輸出固定格式的 JSON |
| 圖像 | Replicate,flux-1.1-pro |
依每頁的提示詞生成插圖 |
| 封裝 | n8n Code 節點 | 組成單一 HTML 檔 |
流程如下:
Telegram Trigger
↓
Switch ── /start ──→ 回傳使用說明
│
└─ text="..." ─→ 回覆「正在撰寫中」
↓
Groq:生成故事 JSON
↓
Code:解析 JSON、組裝每頁 Prompt
↓
Loop Over Pages(共 4 次)
↓
Replicate:生成插圖 → 等待 10 秒 → 合併文字與圖片
↓
Code:組成 HTML
↓
Telegram:傳送檔案
2. 三個設計決定 #
輸入過濾 #
Telegram Bot 什麼訊息都會收到。如果每則都丟給 LLM,除了浪費額度,還會產出莫名其妙的故事。所以 Switch 節點只放行兩種訊息:以 /start 開頭的,回使用說明;符合下面這個 Regex 的,才進入生成流程。
^text=".*"$
其他訊息一律不處理。格式雖然不親切,但判斷成本是零,不必再多花一次模型呼叫去分類意圖。
角色一致性:把外觀交給程式,不交給模型 #
圖像模型每次生成都是獨立的。如果每頁提示詞只寫「一個男孩」,四張圖會畫出四個長得不一樣的人。做法是把「誰長什麼樣子」從 LLM 手上拿走:
- 主角:外觀固定寫在 Code 節點裡,是一個六歲男孩,圓臉、黑色短髮、白上衣、藍短褲。LLM 被明確禁止描述主角。
- 反派或配角:由 LLM 在
character_bank裡設計一次,之後每頁只標記這個角色有沒有出場,由程式在對應頁面接上描述。 - 畫風:同樣是固定字串(童書插畫、水彩質感、溫暖氛圍)。
- 種子:以 Telegram 的
message_id乘上一個固定數字作為 seed,同一則訊息的四張圖共用同一個 seed,重跑結果也一致,方便除錯。
每頁最後送給 Flux 的 Prompt 順序是:動作與場景、主角描述、反派描述(有出場才加)、畫風。動作放最前面,是因為提示詞靠前的部分權重較高,希望畫面先反映劇情,再套用角色設定。
這個方法不能保證四張臉完全一樣,但比讓模型自己描述穩定得多。
固定格式的 JSON #
Groq 的請求用了 response_format: json_object,System Prompt 也明確規定輸出結構:
{
"story_title": "故事標題",
"character_bank": {
"main_hero": "",
"villain": "反派外觀關鍵字"
},
"pages": [
{
"page": 1,
"text_zh": "這一頁的故事文字",
"prompt": "動作與場景",
"characters_present": ["villain"]
}
]
}
這樣故事文字和繪圖提示詞可以分開處理。即使有 JSON 模式,解析節點仍會先去掉可能出現的 Markdown 程式碼框,解析失敗時直接拋出錯誤並附上原始內容,不讓流程默默壞掉。
3. 部署步驟 #
需要準備 #
- 一個可運作的 n8n(自架方式可參考這篇)
- Telegram Bot Token,向 @BotFather 申請
- Groq API Key
- Replicate API Token
匯入與設定 #
- 下載文末的
ai-storybook-wizard.json - 在 n8n 選擇 Import from File 匯入
- 在 Telegram 相關節點選擇自己的 Telegram Credential
- 在 Groq 與 Replicate 的 HTTP Request 節點,把 Header 中的佔位字串換成自己的金鑰
- 切換為 Active
匯出的 JSON 裡只有佔位字串,沒有真實金鑰。換成自己的金鑰時,建議改用 n8n 的 Credentials 管理,不要直接留在節點參數裡,否則之後再匯出或分享工作流時很容易外洩。
使用 #
對機器人輸入:
text="勇氣"
text="迷路的太空人"
text="不想刷牙的小鱷魚"
等待時間大約 30 到 60 秒,主要花在四次圖片生成加上每次之間的 10 秒等待。
4. 常見問題 #
| 狀況 | 處理方式 |
|---|---|
| 機器人完全沒反應 | 確認工作流已 Active;確認 Telegram Credential 正確;自架時 Webhook 必須是 Telegram 連得到的公開 HTTPS 網址,內網 IP 不行;到 Executions 頁面看有沒有收到事件 |
| 節點報「JSON 解析失敗」 | 錯誤訊息會附上模型的原始輸出,通常是輸出被截斷(max_tokens 不夠)或結構不符,先看那段內容 |
| 插圖空白 | 確認 Replicate Token 有效且帳戶有餘額;如果是事後才打開舊的 HTML,是圖片網址已過期(見下一節) |
| 輸入主題沒反應 | 確認格式含有 text= 與前後雙引號,並且是半形字元 |
5. 已知限制與後續 #
- 圖片網址會過期。 HTML 裡的插圖是引用 Replicate 回傳的網址,不是內嵌,所以舊繪本過一段時間後圖片會失效。要長期保存的話,應該在組裝前把圖片下載並轉成 base64 內嵌,代價是檔案變大。
- 生成是依序進行的。 四頁圖片逐張生成,每張之後還固定等 10 秒,總時間因此偏長。改成並行可以縮短,但要先確認 Replicate 的速率限制。
- 主角是固定的。 目前只有一個預設角色,尚未支援自訂主角。
- 只有中文。 多語言輸出還沒做。
下載與範例 #
範例是一次完整的實際輸出,共四頁。使用的模型為 Meta Llama 3.3(經由 Groq)與 Black Forest Labs Flux 1.1 Pro(經由 Replicate)。