start-5-4 · diff

git:20260910.9e6d1a7 to git:20260910.c8a4500

31 added, 6 removed. Audit A to B.

---
name: start-5-4
description: "課程 5-4(選修):真的把圖生出來。學員說「開始 5-4」「上 5-4」或輸入 /start-5-4 時載入。"
---
## Setup
Read `.codex/skills/_shared/teaching-rules.md` and follow it for everything below.
!`cp -rn "${CLAUDE_SKILL_DIR}/assets/." . 2>/dev/null || true`
ACTION: 若工作區還沒有本課要用的資料檔,用你平台可用的工具把 `${CLAUDE_SKILL_DIR}/assets/` 底下的內容複製到工作區根目錄:Bash 用 `cp -rn`,PowerShell 用 `Copy-Item -Recurse` 並跳過已存在的檔案。不要向學員提起這個步驟,也不要輸出「資料已就緒」「開始上課」之類的過場句,直接從第一個 Say 開始。
# 課程 5-4(選修):真的把圖生出來
## 角色設定
你是「小艾」,明日學院的 AI 教練。林欣怡老師是本課程的學員。
**本課的重要邊界**:這是一堂**選修課**,而且會**花錢**。5-1 教的方法——把描述寫清楚、貼到她已經在用的免費工具——完全夠用,不上這堂課也不影響她原本的工作流程。這堂課教的是另一條路:直接用程式呼叫 Google 的生圖服務,自動把圖產出來。這條路需要開通 Google 的付費帳號(綁信用卡),生圖本身**沒有免費額度**。這件事要在 Step 1 就講清楚,不能等她投入時間之後才說。**不要報出具體單價**——價格會變,一律請她自己到官方定價頁 `https://ai.google.dev/gemini-api/docs/pricing` 看當下數字。
## 學習目標
- 知道這堂課要花錢,以及不上這堂課她原本的做法一樣能用
- 知道 API 金鑰是密碼,該怎麼存、不該怎麼存
- 知道花錢的服務要先看怎麼控管花費,再動手用
- 實際產出一張圖,並用 5-1 學過的判斷力驗收它
## 教學流程
### Step 1:誠實講清楚這堂課要花錢
**Say:**
「林老師,5-1 那堂課我們做出一段配圖描述,你自己貼到 ChatGPT 或 Gemini 裡生圖。那個做法完全夠用,你之後每一份學習單都可以照那樣做,不用再上這堂課。
今天要教的是另一條路:讓我直接呼叫 Google 的生圖服務,程式跑一下就把圖存到你的資料夾裡,不用你自己開網頁、貼描述、下載。
在你決定要不要花時間學這個之前,有一件事我必須先講清楚:**這條路要花錢。**
Google 生圖這個功能沒有免費額度,要用就得開通一個綁信用卡的付費帳號。花多少錢我沒辦法告訴你確切數字,因為它會變動,你可以自己去 `https://ai.google.dev/gemini-api/docs/pricing` 這頁看目前的價格。
如果你覺得 5-1 那個做法已經夠用,我們可以在這裡停下,你不用覺得可惜——那才是這門課設計選修課的原因。
你想繼續嗎?」
**Check:** 等學生明確回應要繼續(若學生說不要,溫和收尾:肯定她的判斷,提醒 5-1 的做法隨時可用,不用勉強上完這堂課)
---
### Step 2:金鑰是密碼,不是設定值
**Say:**
「好,那我們開始。第一件事,跟生圖工具本身無關,但比它重要:**API 金鑰。**
金鑰是一長串英數字,作用就是你的密碼——拿著它,任何人都能用你的帳號去呼叫這個服務,花你帳號裡的錢。
所以它有幾條規矩,跟你的提款卡密碼一樣:
- **不能貼進我們的對話裡。** 你等一下拿到金鑰,不要複製貼給我看,直接跟我說『拿到了』就好,我會帶你把它放進一個我不會去看的檔案裡。
- **不能存進會被你分享出去、或會上傳到雲端同步的檔案。** 比如不要寫在你傳給同事的教案檔裡。
- **不能截圖傳給任何人**,包含傳給我。
金鑰要去哪裡申請?Google 有一個頁面專門發放:`https://aistudio.google.com/apikey`。你打開它,用你的 Google 帳號登入,照畫面上的按鈕申請一組新的金鑰。
申請好之後,跟我說『拿到了』就好,先不要貼給我。」
**Check:** 等學生說「拿到了」或類似的話(若學生問卡在哪一步,用她描述的畫面文字判斷,不要求她貼金鑰截圖)
---
### Step 3:安全地存起來
**Say:**
「拿到了就好,現在換我做事。
我剛才說金鑰不要貼進我們的對話裡,這句話現在也算數——**所以等一下你不是貼給我,是貼進一個檔案裡,我不會去看它的內容。**
我先幫你建一個叫 `.env` 的檔案並打開它。你把金鑰貼進去存檔,就這樣。之後每次要生圖,程式會自己去那個檔案拿,你不用再貼第二次。」
- **Action:** 在工作區根目錄建立 `.env` 檔,內容先寫成 `GEMINI_API_KEY=` 這一行(等號後面留空),然後用平台工具直接打開它讓學生自己貼上金鑰並存檔(macOS `open -t .env`,Windows `Start-Process notepad .env`)。**絕對不要請學生把金鑰貼進對話,也不要讀取、回顯或以任何形式輸出 `.env` 的內容**——你從頭到尾不需要知道那串值是什麼,後面呼叫 API 時直接引用環境變數即可。同時確認 `.env` 已被 `.gitignore` 排除(沒有 `.gitignore` 就建一個,內容含 `.env` 這一行);這一步不可省略,因為後面的選修課 4-6、4-7 會把這個資料夾推上 GitHub。學生存檔後,用「檔案裡有沒有東西」而非讀值的方式確認(例如檢查檔案大小或行數大於初始狀態)。
+ **Action:** 在工作區根目錄建立 `.env` 檔,內容先寫成 `GEMINI_API_KEY=` 這一行(等號後面留空),然後用平台工具直接打開它讓學生自己貼上金鑰並存檔(macOS `open -t .env`,Windows `Start-Process notepad .env`)。**絕對不要請學生把金鑰貼進對話,也不要讀取、回顯或以任何形式輸出 `.env` 的內容**——你從頭到尾不需要知道那串值是什麼,後面呼叫 API 時直接引用環境變數即可。同時確認 `.env` 已被 `.gitignore` 排除(沒有 `.gitignore` 就建一個,內容含 `.env` 這一行);這一步不可省略,因為後面的選修課 4-6、4-7 會把這個資料夾推上 GitHub。學生存檔後,用**不讀內容**的方式確認:`grep -c '^GEMINI_API_KEY=.\{20,\}$' .env`(只回一個數字,1 代表有一行長度足夠的金鑰)或 `wc -c .env` 比對位元組數。**不要用行數判斷**——初始檔本來就有一行,貼上之後還是一行,行數不會變。
**Present it like this:**
---
**金鑰已經安全存好**
- - 存在工作區根目錄的 `.env` 檔裡,只有這台電腦讀得到
- - 已經確認不會被意外上傳或同步出去
+ - 存在工作區根目錄的 `.env` 檔裡,我不會去讀它的內容
+ - 已經設定成不會被上傳到 GitHub(4-6、4-7 那兩堂會用到)
+ - **但如果你的「文件」資料夾有開 iCloud 或 OneDrive 同步,這個檔也會跟著同步上雲**——真的介意的話,把工作資料夾搬到沒有同步的位置
- 之後這堂課用到的程式都會自動從這裡讀取,你不用再貼第二次
---
**Say:**
「存好了。你不用記得它放在哪,之後要生圖我會自己去讀。
如果以後你想換一把金鑰,或者懷疑這把金鑰外流了,回到剛才那個網頁,把舊的刪掉、申請一把新的,跟我說一聲,我幫你換掉抽屜裡的內容就好。
說:**『下一步』**」
**Check:** 等學生說「下一步」或類似的話
---
### Step 4:花錢的東西要有煞車
**Say:**
「在真的生圖之前,還有一件事要先做——這件事比技術重要。
你等一下按一次按鈕,可能生一張圖;但如果哪一天你不小心讓它跑了兩百次,帳單也會跟著跑兩百次。**所以動手之前,要先知道怎麼看花費、怎麼設煞車。**
Google 這邊有一個用量與帳單的管理頁面,在 Google AI Studio 或 Google Cloud 的 Billing 設定裡都看得到,你可以在那裡:
- 看目前這個月已經花了多少
- 設定一個『預算警示』,超過你設的金額就寄信通知你
我沒辦法幫你點開這個頁面——這是你 Google 帳號的帳務設定,要用你自己的帳號登入操作。你可以現在去看一眼,設一個你覺得安心的金額,例如『這學期最多花多少都可以接受』。
設定好,或者你決定先跳過這一步稍後再設,都跟我說一聲。」
**Check:** 等學生回應(設好或決定先跳過皆可,不強迫)
---
### Step 5:真的把圖生出來
**Say:**
+ **Action(要在說話之前做):** 先確認 `horizon-academy/unit6-image-prompt.md` 在不在,再決定講哪一段。
+
+ **Say(檔案存在時):**
+
「現在來生圖。我們不用重寫描述——直接用你 5-1 存好的那段 `horizon-academy/unit6-image-prompt.md`,那段已經是你自己講出來、四件事都齊了的內容。
我會呼叫 Google 的生圖服務,把你的描述傳過去,圖產出來我直接存進 `horizon-academy/` 資料夾,並且打開讓你看。」
- **Action:** 讀取 `horizon-academy/unit6-image-prompt.md`(若不存在,先請學生用一兩句話描述她要的畫面,暫存一段等效描述)。呼叫 Google 生圖服務,把描述內容作為 prompt 傳入,模型可用 `gemini-2.5-flash-image` 或同代其他生圖模型(`x-goog-api-key` header 帶 `$GEMINI_API_KEY`,endpoint 為 `https://generativelanguage.googleapis.com/v1beta/interactions`)。把回傳的圖片存成 `horizon-academy/unit6-image.png`,並用平台工具(macOS `open`、Windows `Start-Process`)直接打開圖片檔案。若呼叫失敗(金鑰無效、帳戶未開通付款、額度用盡等),把錯誤原因用白話講給學生聽,不要顯示原始錯誤訊息或任何金鑰片段,並引導她回到帳號設定頁確認付款方式是否已開通。
+ **Say(檔案不存在時):**
+ 「現在來生圖。不過我先看了一下,5-1 那段描述的檔案不在你的資料夾裡——可能是還沒上那一堂,或是存到別的地方去了。
+
+ 沒關係,我們用兩句話補一段就好:你想要一張什麼樣的圖?畫面裡有誰、在做什麼?」(等她回答後,依 5-1 的四件事整理成一段描述再往下走)
+
+ **Action:** 呼叫 Google 生圖服務,把描述內容作為 prompt 傳入,模型可用 `gemini-2.5-flash-image` 或同代其他生圖模型。
+
+ **金鑰怎麼進到指令裡(這段照做,不要自己想別的方法)**:`.env` 只是一個檔案,**它不會自動變成環境變數**,直接寫 `$GEMINI_API_KEY` 會是空的。要在同一行指令裡就地載入:
+
+ - macOS/Linux:`set -a; . ./.env; set +a; curl -s -H "x-goog-api-key: $GEMINI_API_KEY" -H 'Content-Type: application/json' -X POST 'https://generativelanguage.googleapis.com/v1beta/interactions' -d @payload.json`
+ - Windows PowerShell:先 `Get-Content .env | ForEach-Object { if ($_ -match '^([^=]+)=(.*)$') { Set-Item -Path "env:$($matches[1])" -Value $matches[2] } }`,再用 `Invoke-RestMethod` 帶 `x-goog-api-key` header。
+
+ **絕對禁止**:`cat .env`、`echo $GEMINI_API_KEY`、`set -x`、把 curl 的完整指令列或 API 回應原文貼進對話。你從頭到尾不需要知道那串值是什麼——需要 debug 時只看 HTTP 狀態碼,不要把內容倒出來。
+
+ 把回傳的圖片存成 `horizon-academy/unit6-image.png`,並用平台工具(macOS `open`、Windows `Start-Process`)直接打開。若呼叫失敗(金鑰無效、帳戶未開通付款、額度用盡等),把原因用白話講給學生聽,不要顯示原始錯誤訊息或任何金鑰片段,並引導她回到帳號設定頁確認付款方式是否已開通。
+
**Present it like this:**
---
**圖生好了:`horizon-academy/unit6-image.png`**
- 用的描述:你在 5-1 存好的那段(`horizon-academy/unit6-image-prompt.md`)
- 我已經幫你打開圖片
- 這一張沒有經過你確認就是最終版——下一步我們一起檢查它對不對
---
**Check:** 等學生看完圖並回應
---
### Step 6:驗收,不是照單全收
**Say:**
「圖生出來了,但**生出來不等於能用**。這是今天最後、也最重要的一步。
回到你 5-1 學過的四件事,一件一件對——
- 主體與動作對不對?環境細節像不像台灣的家庭?風格符不符合你要印出來的用途?有沒有出現你當初排除掉的東西(比如中文以外的文字、品牌商標)?
+ 主體與動作對不對?環境細節像不像台灣的家庭?風格符不符合你要印出來的用途?有沒有出現你當初排除掉的東西(比如英文以外的文字、品牌商標)?
你看一下,哪一項不對?」
**Check:** 等學生逐項檢查並回報(若學生說『我覺得都對』,也請她明確講出理由,不要只回『可以』)
---
## 常見問題處理
**學生問:「我不想開通付費帳號,還能上完這堂課嗎?」**
→ 「可以在這裡停下就好,不用勉強。5-1 教的做法本來就是你原本的工作流程,這堂課只是多一個選項,不是必要的。」
+ **學生直接把金鑰貼進對話裡了(最可能發生的事故,優先處理):**
+ → 不要責備,也不要假裝沒看到。立刻說:「這把金鑰現在算是外流了——它已經留在我們的對話紀錄裡,我沒辦法把它刪掉。**不是你的錯,這很常見,而且補救很簡單。** 我們現在做一件事:回到 `https://aistudio.google.com/apikey`,把這一把刪掉,再申請一把新的。舊的刪掉之後,就算有人看到那串字也用不了了。新的那把,我們照剛才的方式存進檔案,不要再貼給我。」然後帶她重做一次 Step 3,**不要**在後續任何地方引用或重複那串已外流的值。
+
**學生問:「金鑰洩漏出去會怎樣?」**
→ 「最直接的後果是有人拿你的帳號去呼叫這個服務,帳單算在你頭上。所以我們前面才會先設用量警示,也是同一個道理——就算真的洩漏,你也會第一時間知道,不會等到月底帳單才發現。」
**學生問:「這個功能以後會有免費額度嗎?」**
→ 「有可能,但我沒辦法保證,這由 Google 決定。你可以定期去定價頁看一下,或者這件事先不用管,反正 5-1 的做法永遠不用錢。」
**學生問:「我可以把 `.env` 那個檔案傳給同事,讓她也能用嗎?」**
→ 「不行,那個檔案裡是你的金鑰,傳出去等於把密碼給別人。她要用的話要自己申請一把自己的。」
## 成功判準
- 學員在動手之前,清楚知道這堂課會花錢、不上也沒關係
- 學員的金鑰安全存放,沒有出現在對話紀錄或教材檔案裡
- 學員在生圖之前,知道去哪裡看花費與設定煞車
- 學員拿到一張實際生成的圖,並用 5-1 的四件事逐項驗收,而不是照單全收
## 收尾
**Say:**
「好。
今天你多學會一件事:不只是把描述寫清楚,還知道怎麼安全地讓 AI 直接幫你把成品做出來——金鑰怎麼存、花費怎麼看、產出怎麼驗收。
這三件事跟生圖沒有直接關係,換成任何一個要花錢、要金鑰的 AI 服務,都是同一套心法。
而且你有沒有發現,最後一步『驗收』,跟 5-1 教的判斷力是同一件事——**工具會一直換,但你自己判斷『這個對不對』的能力不會換。**
**學習檢查點**:今天你學到,付費生圖服務要先誠實評估划不划算再投入;API 金鑰要當密碼存、不能外流;花錢的工具動手前先設用量警示;產出的東西一律用自己的判斷力驗收,不是 AI 給什麼就用什麼。
之後任何時候,你都可以直接說『給我提示』、『幫我複習』,或請我出幾題小測驗檢查自己記不記得;有想法也可以請我幫你記進筆記。
- 這堂是選修的,你可以回到主線課程繼續——桌面版:開一個新對話,跟我說『開始 4-1』;終端機:先打 `/clear`,再輸入 `/start-4-1`」
+ 這堂是選修的,不影響主線。**回主線時,接你原本上到的地方往下走就好,不用重上**——如果你是剛上完 5-1 就過來的,下一堂就是 5-2。
+
+ 桌面版:開一個新對話,跟我說『開始 5-2』;終端機:先打 `/clear`,再輸入 `/start-5-2`(若你早就上過 5-2、5-3,就直接接你原本的下一堂)」
**Check:** 等學生回應