feat(photos): Google 相簿 → 相片簡報/影片/PPTX(Smart Photo-to-Deck 完整功能)#95
Merged
Conversation
…Auth Google 相簿 → 相片簡報功能的後端核心 (階段一+二)。全 offline-first: mock/fake 可測, 不打真 Gemini / 不需真 OAuth。 - core/photo_deck.py: 一組照片 → Gemini vision (複用 infocards.gemini.generate_json 多模態 + response_schema) 做品質過濾 / 逐張 caption / 取標題 → 組 sections/slides deck (bg_image=照片路徑, narration=caption)。送前用 Pillow 縮到 ≤1024px 分批; prompt 硬限「只描述明確可見元素」防幻覺; max_select 依 score 全域挑選。deck 直接 可餵 slide_pptx.deck_to_pptx / 既有 render / infocards。 - core/google_photos.py: Google Photos Picker API 薄層 (sessions.create/get, mediaItems.list 翻頁, baseUrl=d 下載, 只收圖片跳過影片)。OAuth 沿用 publish.py 的 InstalledAppFlow + token 模式, 但獨立 scope (photospicker.mediaitems.readonly) + 獨立 photos_token.json; 缺 token 丟 OAuthBootstrapRequired (route 回 412)。 HTTP 層 session 可注入 → 單元測試不需真 OAuth。 - tools/photos_auth.py: 一次性 CLI 授權腳本 (python -m tools.photos_auth) 產 token。 - .gitignore: photos_token.json; requirements.txt: 正式宣告 google-api-python-client / google-auth-oauthlib (先前已裝未宣告)。 - 測試: downscale / 分析(mock) / max_select / deck 組裝 / 餵 PPTX; picker session / 分頁 / 下載過濾影片 / OAuth 412 gate。共 13 案綠。 註: 2025-04 Google 移除 photoslibrary.readonly, 故走 Picker API (使用者自選照片)。 路由 + job 整合 + /app UI 為後續 PR。 Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01MGT1mi2KPYyD76U1BKEhMo
把相片簡報接進既有 job pipeline: 新來源 google_photos 走 ingest(下載+deck) →
既有 render, 因此影片 render / PPTX 匯出 / SlideEditor 編輯 / YouTube 上傳全部
免費繼承。
- schemas: SourceType.GOOGLE_PHOTOS; JobSource.session_id; JobOptions.photo_title_hint
/ photo_max_select。
- runner: _run_ingest_photos (下載 Picker 選中照片 → photos_to_deck → 寫 deck.json);
path-check 豁免 google_photos (無本機檔); render 分支讓 google_photos 跟 slides_pdf
走同一條 SlideRenderer (照片鋪底 + caption 旁白)。
- routes/google_photos.py: GET /status (是否已授權)、POST /session (建 Picker,
回 picker_uri)、GET /session/{id} (輪詢選好沒)、POST /generate (建 job)。未授權
回 412 (對齊 youtube 慣例)。
- main.py 註冊 router。
- 測試: ingest(mock) 建 deck / 無照片 raise; 路由 status(授權/未授權)、session 412、
generate 建 job。共 6 案; 相關 runner/jobs 套件一併綠 (110 passed)。
影片 = job mp4 artifact; PPTX = 既有 GET /jobs/{id}/pptx; caption 可在 SlideEditor 編。
/app UI (開 Picker → 進度 → 產出) 為下一個 PR。
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGT1mi2KPYyD76U1BKEhMo
/app 新增 google_photos 來源: 授權檢查 → 開 Picker 選照片 → 輪詢 → 產生。 - PhotoSourcePanel.tsx: 三步驟面板 — ① status 檢查 (未授權提示跑 tools.photos_auth); ② createPhotoSession → 開 picker_uri 新分頁 + 輪詢 media_items_set; ③ 選好後填 主題脈絡 / 最多張數 / 是否停審 → generatePhotos 建 job。 - CreateJobForm: 加 google_photos 來源選項; isPhotos 時以面板取代一般 file/url 表單 與所有選項/送出鈕。 - api.ts: photosStatus / createPhotoSession / pollPhotoSession / generatePhotos。 - types + SourceBadge 加 google_photos。 tsc 0 error; vite build 通過。後端 19 案綠。 Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01MGT1mi2KPYyD76U1BKEhMo
dofliu
marked this pull request as ready for review
July 7, 2026 12:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
這個 PR 做什麼
新功能「連結 Google 相簿 → AI 選圖+配文 → 相片簡報(影片 + 可匯出 PPTX)」,完整接在現有 eduStudio 架構上(core + 後端路由/job +
/appUI)。全 offline-first:mock/fake 可測,CI 不打真 Gemini、不需真 OAuth。架構(最大化複用既有積木)
google_photos是一個新SourceType,走既有 job pipeline:ingest(下載選中照片 → vision 選圖+配文 → deck)→ 既有 render。因此 影片 render / PPTX 匯出(/jobs/{id}/pptx)/ SlideEditor 編 caption / YouTube 上傳全部免費繼承。變更
① 核心(
core/)photo_deck.py— 複用infocards.gemini.generate_json(多模態 +response_schema)做品質過濾(模糊/曝光/重複)、逐張 caption、取標題;送前 Pillow 縮 ≤1024px 分批;prompt 硬限「只描述明確可見元素」防幻覺;max_select依 score 全域挑選 → 組 sections/slides deck。google_photos.py— Photos Picker 薄層(sessions.create/get、mediaItems.list翻頁、baseUrl=d下載、跳過影片);OAuth 沿用publish.py模式但獨立 scope(photospicker.mediaitems.readonly)+ 獨立photos_token.json;缺 token → 412。tools/photos_auth.py— 一次性 CLI 授權。② 後端整合(
server/)SourceType.GOOGLE_PHOTOS+JobSource.session_id+JobOptions.photo_title_hint/photo_max_select。runner._run_ingest_photos(下載+deck);render 分支讓 photos 跟 slides 走同一條 SlideRenderer(照片鋪底 + caption 旁白)。routes/google_photos.py:GET /status、POST /session、GET /session/{id}、POST /generate。③
/appUIPhotoSourcePanel.tsx:授權檢查 → 開 Picker 選照片 → 輪詢 → 填主題/張數/停審 → 產生。CreateJobForm加google_photos來源;api.ts四個端點;types/SourceBadge。測試(全 mock/fake,25+ 案綠)
downscale/分析/
max_select/deck 組裝/餵deck_to_pptx;picker session/分頁/下載過濾影片/OAuth 412;ingest(mock) 建 deck/路由 status·session·generate。相關 runner/jobs 套件一併綠。前端tsc0 error、vite build通過。使用者前置(做一次)
Google Cloud:啟用 Photos Picker API → OAuth 同意畫面加 scope(測試中把自己加 Test users)→ client_secret JSON 放專案根 → 本機跑
python -m tools.photos_auth。使用流程
/app→ 新增 Job →google_photos→ 開相簿選照片 → 產生 → 影片在 job 頁預覽、「📊 匯出 PPTX」下載、caption 可在 SlideEditor 微調重渲染。後續(可選)
🤖 Generated with Claude Code