> 給勁園工程端的 Claude / 工程師看。目的：把 kids-ai-lab demo 網站從 Cloudflare Pages（`kids-ai-lab.pages.dev`）搬到勁園自己的主機環境。
> 這份文件是「照著做就能動」的施工依據，不是行銷/教材說明——教材內容、學習目標請看 `trial-course/` 與各章節內文。

---

## 0. 先看這個：你其實可能不需要「搬機器」

在動手之前，請先確認你們真正要的是哪一種：

| 選項 | 要做什麼 | 需要重寫後端嗎 |
|---|---|---|
| **A. 掛自己的網域** | 在 Cloudflare Pages 專案上加 Custom Domain（例：`kids.jinyuan.com.tw`），DNS 指過來就好，網站本體還是跑在 Cloudflare | **不用**，最快、風險最低 |
| **B. 真的搬進勁園自己的主機**（本文件主要處理的情境） | 把整包靜態檔案複製過去自己的 server / Nginx / Node，自己跑 | **要**，因為有 3 支後端 API 目前是 Cloudflare 專屬服務 |

如果只是想要「掛自己家的網址」而不是 `.pages.dev`，選 A，5 分鐘搞定，跳過本文件其餘部分，直接跟 colombo 說要哪個網域即可。

如果是真的要把整個服務搬進勁園自己管的主機（例如要離開 Cloudflare、或有資安/資料落地要求），才需要繼續往下看——**這種情況下後端要重寫，見第 2 節**。

> 預設勁園主機上已經有自己的 AI 模型可用（企業等級主機、多種模型），所以本文件**不假設你們缺 LLM/圖像理解能力**，只需要知道要怎麼接上去。

---

## 1. 這是什麼站台

- 14 個獨立的 AI 互動教學 demo + 1 個總覽首頁 + 教師後台預覽 + 教師版教案（`trial-course/`）
- **純靜態 HTML/JS，沒有 build step**：每個 demo 是一個 `index.html`，直接載入 CDN（`cdn.jsdelivr.net` 的 p5.js、`unpkg.com` 的 ml5.js 等），瀏覽器端執行，不需要 npm install / webpack 之類的建置流程
- 唯一的「後端」是 3 支 Cloudflare Pages Functions（放在 `functions/api/`），處理需要呼叫 AI 模型的 demo

目錄結構：
```
demo/
├── index.html                總覽首頁
├── 01-1-ai-map/ ... 07-2-cyber-quest/   14 個 demo（各自獨立資料夾）
├── teacher-dashboard/        教師後台預覽（模擬資料，無後端依賴）
├── trial-course/             教師教案（純內容頁，無後端依賴）
├── shared/                   共用 CSS + 共用後端呼叫層 backend.js
├── functions/api/            ⚠️ 後端邏輯所在，見下方
└── wrangler.toml             Cloudflare 專屬設定檔，搬家後這支不再需要
```

---

## 2. ⚠️ 搬家前要處理的後端依賴

14 個 demo 裡有 **7 個**依賴後端 API（其餘都是純前端、複製檔案就能跑）：

| API | 呼叫的 demo | 現在怎麼實作 | 搬家要做什麼 |
|---|---|---|---|
| `/api/llm` | 07-1 面具、05-1 用臉開車、05-2 AI 學開車、02-1 認教具、04-2 虛空畫家、04-1 虛空鋼琴、**01-2 多家 AI 大對比** | Cloudflare Workers AI（`env.AI` binding，免外部金鑰，llama 系列模型） | **重寫**：換成你們主機上現成的 LLM，介面維持「收 `{prompt, system, max_tokens, temperature}`、回 `{text}`」不用動前端。⚠️ **01-2 是特例**：這個 demo 的教學重點是「同一問題、3 個不同國家的 AI 答案不一樣」，前端會用 `model` 參數指定 3 個不同模型同時打三次。搬家後的替代方案**至少要能提供 3 個風格明顯不同的模型**（不能只接一個模型然後三個欄位都回同樣的答案），不然這個 demo 的教學效果會失真——這點要特別跟工程確認你們主機上是不是真的有「3 種不同風格」的模型可選，不是只有 1 個 |
| `/api/vision` | 02-2 AI 出題尋寶、04-2 虛空畫家 | Cloudflare Workers AI 視覺模型（`llama-3.2-11b-vision` 等） | **重寫**：換成你們主機上有視覺理解能力的模型，介面維持「收 `{image(base64), prompt, max_tokens}`、回 `{text}`」 |
| `/api/story` | 03-1 分岔故事性向測驗 | 呼叫我們自己維護的一個內部 AI 服務（外部網域，你們接不到、也不需要接） | **重寫**：改成呼叫你們主機上的 LLM。prompt 邏輯全部照抄 `functions/api/story.js` 裡的角色設定字串（那一大段「你是兒童 AI 教育課程裡的說書人 AI…」），貼到你們自己的呼叫裡當 system prompt 用即可，不需要知道我們原本接的是哪個服務 |

**唯一需要麻煩勁園工程確認的一件事**（其他都可以直接假設「你們主機上已經有能用的模型」）：

> **「你們放這個網站的主機，是用什麼環境跑的？是 Node.js（Express 之類）、PHP、Nginx 反向代理到其他服務，還是別的？我們要把 3 個小後端功能（都是『收一段文字或圖片、丟給 AI 模型、把結果回傳』這種簡單邏輯）改寫成你們主機看得懂的語言，需要先知道你們是哪種環境。」**

這句可以直接轉給勁園工程師。答案決定 `functions/api/llm.js` / `vision.js` / `story.js` 這三支要重寫成 Node route、PHP endpoint、或其他形式——**邏輯本身很簡單**（收 prompt、丟給模型、回文字），現有的 3 支 `functions/api/*.js` 原始碼就是最完整的規格書，prompt 內容、輸入輸出格式都在裡面，直接讀就能照樣重現，不需要再跟 LL 這邊要任何額外資料。

---

## 3. 完全不需要動的部分（7 個純前端 demo + 靜態頁）

`01-1-ai-map`、`02-1-teachable`（僅本地鏡頭+瀏覽器內模型）、`06-1-data-viz`、`06-2-health-classify`（讀 `shared/data/flu-check.csv` 靜態檔）、`07-1-face-mask`*、`teacher-dashboard/`、`trial-course/`

> ⚠️ `01-2-ai-compare` **不在此列**——雖然介面看起來單純（一個輸入框 + 三張卡片），但三張卡片的回答**全部**來自 `/api/llm`（分別打 3 個不同模型），整頁核心功能都是後端依賴，不是「大致不用動、局部要接」，是整頁都要接。已移到第 2 節表格處理。

> 標 `*` 的請對照第 2 節表格——部分 demo 名稱重複出現是因為同一頁裡有些功能需要 API、有些不需要，實際以 `shared/backend.js` 的 `askLLM/askStory/genImage` 呼叫點為準。

這些檔案**複製過去、用任何靜態檔伺服器（Nginx / Apache / `serve` 都行）跑起來就好**，不涉及本文件第 2 節的任何決策。

---

## 4. 搬家步驟（知道主機技術棧之後）

1. 複製整個 `demo/` 目錄到目標主機（`wrangler.toml` 可以留著當歷史記錄，不影響非 CF 環境運作，但實際不會被讀取）
2. 用靜態檔伺服器 serve 整個目錄（首頁是 `index.html`）
3. 依第 2 節決策，把 `functions/api/llm.js`、`vision.js`、`story.js` 三支的邏輯移植成你們主機技術棧的等效實作（Node/Express route、PHP endpoint 等皆可），**保持路徑 `/api/llm`、`/api/vision`、`/api/story` 不變**——前端 `shared/backend.js` 是寫死打這三個相對路徑，改路徑就要同步改這支檔案
4. 三支後端各自需要的環境變數（依你們選的供應商而定，例如 `OPENAI_API_KEY` 或自架模型的內網位址）用你們主機慣用的方式（`.env` / 環境變數 / secret manager）注入，**不要寫進程式碼或前端**
5. 部署完成後，逐一開 14 個 demo 網址手動測一輪：7 個純前端的應該直接能玩；7 個吃 API 的要實際觸發一次 AI 呼叫（例如 03-1 選一個故事分支、02-1 開鏡頭教一個物品、01-2 問一個問題看三家都答得出來）確認後端真的通

---

## 5. 已知非阻塞的小事

- `shared/backend.js` 裡还留了 `/api/img`（`genImage()`）的呼叫路徑，但目前**沒有任何 demo 實際觸發它**，也沒有對應的 `functions/api/img.js`——這是預留但未上線的功能，搬家時可以忽略，不用實作
- `README.md` 內容偏舊（還寫「純前端無後端」），已過時，**請以本文件 + `functions/api/` 原始碼為準**，不要看 README

---

*本文件對應版本：2026-07-22，demo repo（獨立 git）當前狀態。若之後 demo 增修（尤其是新增 API 呼叫），這份文件要同步更新。*
