AI 自動整理 5,000 張照片實戰:用 Gemini/GPT 生成標題、描述與 Tag 的多模型應用

作者:

分類:

用 Gemini、GPT 搭配 EXIF、GPS 與 Google Maps Platform,自動整理近 5,000 張照片的開發實戰。

一開始開發自己的網路相簿時,我對 AI 的期待其實很單純:

把照片交給 Gemini 或 GPT, 配合GPS產生的地點作為輔助資訊,進而看懂照片後幫我產生一個標題、一段描述,再加幾個 Tag。

照片僅有地點,不容易引起共鳴,多了標題和描述,才有畫龍點睛之效;而tag則是可以將同一類型的跨相簿照片蒐集起來,例如主題若是「山岳」,可以把瑞士的馬特洪峰、義大利的多洛米堤、合歡山、中國大陸的稻城亞丁都串連在一起,可以因此點選其中一張,自動出現相同主題的其他照片,讓相簿的連結橫跨經緯。

如果只有十幾張照片,這件事確實很簡單。但當相簿裡累積到數千張、接近 5,000 張照片之後,我才發現真正困難的根本不是「AI 看不看得懂照片」,而是:

如何讓 AI 在處理第 5,000 張照片時,仍然遵守和第 1 張照片一樣的規則。

更麻煩的是,照片不只有「畫面內容」。一張旅遊照片可能同時牽涉 EXIF 拍攝時間、GPS 座標、國家與城市、真正的景點名稱、中文與外文地名、繁簡體中文、照片標題、照片描述、Tag,以及相簿所代表的整段旅程。

最後,我的 AI 相簿已經從最初的:

照片 → AI → 文字

逐漸演變成:

照片 + EXIF + GPS + Google Maps Platform
+ Gemini / GPT
+ 程式規則
+ 人工確認

這篇記錄的,就是這套系統一路披荊斬棘、修改到後來的結果。

目錄

AI 在我的相簿裡到底做什麼?

目前 AI 在我的 PhotoGallery 裡,已經不只是「幫照片寫一句話」,而是參與照片整理流程中的好幾個階段。

1. AI Vision:先理解照片

最基本的是把照片縮小成適合 AI Vision 分析的版本,再交給 Gemini 或 GPT。

AI 可以辨認照片中的:

  • 山岳
  • 湖泊
  • 建築
  • 教堂
  • 城堡
  • 動植物
  • 城市街景
  • 日出與日落
  • 雪景
  • 夜景
  • 人物活動

這些視覺資訊才是後續照片標題與描述真正的基礎。

2. 自動產生照片標題

照片標題不是單純把「地名 + 風景」組合起來,而是希望 AI 找出照片真正值得描述的主體。

例如:

Seceda 刀鋒般延伸的山稜

會比:

義大利多洛米堤 Seceda 風景

更像真正人工整理照片時會取的名稱。

而且後來我刻意加入一條規則:

照片標題不一定要包含地名。

只有當地名確實有助於辨識照片時才加入;如果要使用地名,則優先採用已經確認過的正式名稱。

3. 自動產生照片描述

描述會綜合照片畫面、已確認地點、相簿背景與拍攝時間,但最重要的原則是:

描述照片真正看得到的東西。

不要每張都寫:

這張照片捕捉了……

而是直接進入內容,例如:

午後陽光照亮鋸齒狀岩壁,前方草坡與山徑沿著坡面向谷地延伸,遠處高山仍可見殘雪。

4. 自動判斷 Tag

AI 也可以判斷:

  • 山岳
  • 湖泊
  • 夕陽
  • 建築
  • 夜景
  • 花卉
  • 街景

但後來我發現,Tag 反而不能完全交給生成式 AI,否則幾千張照片後會產生大量意思相同、寫法不同的 Tag。這部分後面會再詳細說明。

5. AI 輔助辨識照片地點

這是我認為 AI 應用在旅遊照片上很有趣的一項。

AI 可以從:

  • 建築外觀
  • 山形
  • 湖泊
  • 招牌
  • 紀念碑
  • 特殊地標

推測:

「這張照片可能在哪裡?」

但是現在的系統已經不允許 AI 直接決定正式地點。

它只能提出候選,列出高/中/低三種可信度。

6. 把大量人工工作變成「檢查異常」

如果只有 100 張照片,人工慢慢替每一張寫標題、描述與 Tag 還可以接受。

但照片數量來到:

5,000 張

工作量完全不同。

AI 真正帶來的價值,不是讓人工完全消失,而是:

把原本幾千次人工輸入,縮小成檢查異常結果與修正少數錯誤。

為什麼不能所有事情都交給 AI?

因為照片資料其實有不同的「真實來源」。

例如:

資料 比較可靠的來源
拍攝時間 EXIF
GPS 座標 EXIF
國家、城市與行政區 Google Geocoding
附近存在的真實景點 Google Places
照片畫面裡有什麼 AI Vision
自然中文標題與描述 Gemini / GPT
正式地名 已確認的資料庫內容

所以後來我不再問:

「哪一個 AI 最準?」

而是改問:

「這一種資料應該相信誰?」

這個觀念,是整套系統後來變得穩定的關鍵。

第一個問題:Klammsee(Klammsee)

這是很典型的生成式 AI 問題。

原本地點就是:

Klammsee

AI 為了遵守「中文名稱(英文名稱)」之類的格式,遇到沒有可靠的中文名稱,可能輸出:

Klammsee(Klammsee)

格式看起來非常工整,內容卻毫無意義。

所以現在的規則很簡單:

如果沒有可靠的中文名稱,就直接保留正式原文。

Klammsee 就是:

Klammsee

不需要再加一次 Klammsee。

第二個問題:「英文名稱相同」竟然出現在照片描述

更有趣的是,當 Prompt 告訴 AI:

如果沒有不同的英文名稱,不要重複。

模型偶爾竟然會把這個規則本身變成輸出:

The Garden of the Giant(英文名稱相同)Die barrierefreie Kabine(英文同名)

這是一個很好的例子:

AI 理解規則,不代表它永遠只會執行規則;有時候也會把規則本身拿來回答。

所以後來除了在 Prompt 中禁止這類內容,後端還會再次清除:

  • 英文名稱相同
  • 英文同名
  • 原文同名
  • 括號內外完全一樣的內容

這也是我後來開始接受的一件事:

Prompt 是第一道防線,程式規則才是最後一道防線。

第三個問題:Montreux 變成「蒙reux」

另一個讓人哭笑不得的案例是:

Montreux → 蒙reux

AI 顯然知道這個地名有中文譯名,也似乎知道開頭大概應該翻成「蒙」,但最後只翻了一半。

因此目前外國地名採用的原則是:

完整中文,或者完整原文。

例如:

蒙特勒

或:

Montreux

需要第一次補充正式原文時,可以寫成:

蒙特勒(Montreux)

但不能出現:

蒙reux

這種半中文、半拉丁字母的混合地名。

第四個問題:繁體中文不是逐字轉換

這個問題讓我真正發現:

「使用繁體中文」和「把所有字逐字轉成繁體」是完全不同的事情。

例如正式地名:

萬里桐

如果只是使用一般文字轉換規則,很可能因為「裡面」通常使用「裡」,而把它處理成:

萬裡桐

但「萬里桐」是一個正式地名,「里」本來就是名稱的一部分。

同樣地:

  • 埔里→埔裡
  • 萬里區→萬裡區
  • 皇后鎮→皇後鎮

都不能因為一般繁簡體規則而任意改字,我曾為此又將所有照片重新辨識一次。

另一方面,如果文字來源出現:

刀锋山

一般描述裡的「锋」確實應該正規化成「鋒」,但又不能因此把已確認的外國正式名稱、日文漢字或資料庫專有名詞全部一起改掉。

所以現在的處理方式變成:

  1. 先找出資料庫裡已確認的國家、城市、行政區與景點。
  2. 暫時保護這些正式地名。
  3. 再處理一般文章文字的繁簡體。
  4. 最後把正式地名放回去。

例如:

萬里桐的海岸风景

最後應該得到:

萬里桐的海岸風景

而不是:

萬裡桐的海岸風景

這也讓我體會到:

繁體中文處理其實是語意問題,不只是字碼轉換問題。

第五個問題:Unnamed Road 不是景點

照片有 GPS 後,可以利用 Reverse Geocoding 將座標轉成地址。

但有 GPS,不代表 Google 一定能找到有意義的地點名稱。

有時候回傳的會是:

  • Unnamed Road
  • Unknown Road
  • No Name
  • 無名道路
  • 未命名道路

如果把這些資訊直接交給 AI,它還可能很認真地寫進照片描述:

位於某某地區 Unnamed Road 附近……

不僅表示AI對於何謂是有意義的地點不甚清楚,也對照片相簿完全沒有價值。

因此現在只要遇到這些道路佔位名稱,就直接視為:

沒有細節地點資料。

寧可不填,也不要為了填滿欄位而留下沒有意義的地名。

第六個問題:AI 幻覺地點比不知道更危險

AI Vision 很擅長辨識:

  • 湖泊
  • 雪山
  • 教堂
  • 城堡

但:

「這是一座城堡」

和:

「這是新天鵝堡」

是完全不同難度的問題。

真正危險的是,AI 猜錯地點時通常不會回答得很荒謬。

反而可能給出一個:

非常合理、非常完整,而且看起來像真的錯誤答案。

因此目前地點辨識會要求 AI 同時給出信心度:

  • high
  • medium
  • low

如果只是普通山景、湖泊或街景,沒有足夠證據,就應該給:

low confidence

而不是硬猜一個地點。

AI + GPS + Google Maps 如何交叉判斷地點?

這也是目前 PhotoGallery 和最初版本最大的不同。

現在比較接近下面這個流程:

照片

├── EXIF
│ ├── 拍攝日期
│ └── GPS

├── AI Vision
│ ├── 畫面內容
│ └── 疑似地點

└── GPS

Google Geocoding
├── 國家
├── 城市
└── 行政區GPS + AI 候選

Google Places

真實 POI 候選

排除低價值地點

PhotoGallery

例如 AI 覺得照片可能是在京都清水寺附近,它並不能直接把「清水寺」寫進正式地點欄位。

比較合理的做法是先把:

Kiyomizu-dera Kyoto Japan

當成搜尋候選,再交給 Google Maps Platform 查詢是否真的存在,以及是否和照片 GPS 相符。

我另外也實作了 GPS 附近景點搜尋,但很快又遇到另一個問題:

GPS 最近的 POI,不一定是照片真正拍攝的東西。

距離最近的可能是:

  • 停車場
  • 加油站
  • EV 充電站
  • 公廁
  • 公車站
  • 道路設施

照片真正拍攝的卻可能是旁邊的:

  • 城堡
  • 湖泊
  • 觀景台
  • 山峰
  • 國家公園

所以 Nearby Search 還需要排除一部分對攝影相簿沒有價值的 POI,再讓真正有意義的景點排到前面。

關於我實際如何使用 Google Maps Platform、Geocoding API、Places API、Autocomplete、Nearby Search,以及後來如何利用 Field Mask、搜尋候選與 API request 設計降低費用,可以另外參考這篇:


Google Maps Platform API 應用於相簿 GPS 地點管理與 API 費用優化實戰

做到這裡之後,AI 的角色其實已經不是「告訴我這是哪裡」,而變成:

幫忙判斷照片內容與真實地理資料是否合理。

這是我後來比較喜歡的生成式 AI 使用方式:

讓 AI 做它擅長的判斷,而不是讓它自己創造事實。

每張照片都塞地名,反而不像人寫的

早期還有一個很明顯的問題:

只要 Prompt 裡提供了地點,AI 就很喜歡把地點放進標題。

結果同一本標題為「多洛米堤」的相簿裡可能全部都是:

多洛米堤的湖泊……
多洛米堤的黃昏……
這張照片攝於多洛米堤……
可見多洛米堤的山區壯闊的一面……

但真正人工整理照片時,不會這樣命名,因為會假定讀者已經知道該相簿的照片都是來自多洛米堤。

例如一張 Seceda 山景:

不希望:

多洛米堤 Seceda 壯麗山景

而比較希望是:

Seceda 刀鋒般延伸的山稜

同樣地:

不希望是:

多洛米堤的晨霧湖泊

而是:

晨霧中的 Braies 湖

所以現在相簿名稱只是提供背景資訊,不代表每張照片都必須重複寫進標題。

這樣產生的內容會比較像真正的人整理相簿,而不是大量模板產生的 SEO 關鍵字。

AI 描述為什麼很容易變成罐頭文?

大量生成照片描述之後,很快就會發現模型很喜歡某些句型:

這張照片捕捉了……

展現了……獨特風貌。

呈現了……迷人的一面。

只有一張照片時沒有問題。

但一本相簿如果 100 張照片全部這樣開頭,一眼就知道是機器批次產生。

所以目前描述規則會要求:

直接從照片真正看得到的景物開始寫。

例如不要:

這張照片捕捉了黃昏時分湖面的美麗景色。

而直接寫:

黃昏餘光沿著山稜落入湖面,平靜水面映出遠方雪峰與岸邊樹影。

描述長度大約控制在 100~140 個中文字,但不會直接在程式裡硬切第 140 個字。

一開始曾經指示AI控制字數,結果AI的語法就是直接切一刀:

substring(0, 140)

於是得到:

黃昏的陽光映照在湖面上,遠處山峰逐漸被……

這種被截斷的半句。

所以比較合理的方法是:

由 Prompt 控制理想篇幅,程式只設定較寬鬆的安全儲存上限。

Tag 最後為什麼不讓 AI 自己發明?

Tag 看起來是最適合 AI 的功能之一。

例如一張夕陽照片,AI 可能產生:

  • 夕陽
  • 日落
  • 黃昏
  • 晚霞
  • Golden Hour
  • 金色時刻

全部都合理。

問題是:

全部都合理,對資料庫來說反而是一場災難。

5,000 張照片後,可能出現幾百個意思幾乎一樣的 Tag。

因此我是先將5,000張照片的所有相片描敘文字檔交給AI分析,指定PhotoGallery 先建立自己的100個常見的Tag 詞庫,再讓 AI 從既有詞庫中選擇。

例如:

  • 主要分類最多選 1 個
  • Tag 最多選 3 個
  • 沒有把握可以少選
  • 詞庫裡不存在的 Tag,不准自己創造

這時生成式 AI 的角色就從:Content Generator變成:Classifier,反而可靠很多。

這也代表:

網站的分類語言由網站本身決定,而不是讓 AI 每次自由發揮。

為什麼重新生成時不能餵舊標題?

假設第一次 AI 判斷錯誤,把一張照片寫成:

少女峰下的湖泊

後來覺得不對,再按一次「重新生成」。

如果第二次 Prompt 又把舊標題:

少女峰下的湖泊

一起提供給 AI,模型很容易把它當成已知事實。

結果第二次生成仍然會圍繞:

少女峰

這就是資料污染。

所以目前重新產生標題與描述時,不會再把舊 AI 標題與舊描述當成輸入資料。

AI 必須重新根據:

  • 照片
  • GPS
  • 已確認的地點
  • 相簿背景

從零開始判斷。

這個改變看似很小,實際上比單純換成更強的 AI 模型還重要。

5,000 張照片後,AI API 成本開始變重要

只有 20 張照片時,每張都用最強模型跑一次,完全沒有問題。

但是到了 5,000 張:

每一個多餘的 API request,都要乘以 5,000。

所以現在除了 AI 品質,也必須考慮:

  • 照片是否需要先縮圖
  • 是否真的缺少標題
  • 是否真的缺少描述
  • Tag 是否需要重新分析
  • API 同時呼叫數
  • 429 Too Many Requests
  • Timeout
  • 5xx 暫時性錯誤
  • 失敗後 Retry
  • 背景 Queue

照片也不需要每次把數十 MB 的原始檔直接送給 AI。

比較合理的是先產生適合 AI Vision 使用的縮小圖片,再交給模型。

這同時可以改善:

  • 上傳速度
  • API 延遲
  • 記憶體使用
  • 圖片處理成本
  • 整批執行效率

到了這個規模之後,問題已經不只是:

Prompt Engineering

而開始變成真正的:

AI Engineering

為什麼需要多模型,而不是全部使用最強 AI?

大量處理照片時,我也不認為每張照片都需要使用最昂貴、推理能力最強的模型。

很多照片只是要:

  • 判斷山景
  • 辨識湖泊
  • 寫一段簡短描述
  • 從既有 Tag 裡選三個

這些工作,速度快、成本低的模型通常已經足夠。

只有比較困難的情況,例如:

  • 特殊建築
  • 複雜景點辨識
  • 畫面資訊很多
  • 第一個模型結果異常

才需要考慮使用更強的模型。

因此 PhotoGallery 後來把 Gemini 與 GPT 做成可切換的 AI Provider / Model。

這還有另一個優點:

整套系統不必綁死在某一家 AI 或某一個模型。

今天某個模型速度快、價格低,會想要作為預設。我曾以為GPT-5.6 Luna又快又便宜是首選,但是考量地名翻譯要接近我們熟悉的單詞,只好又用Gemini 3.5 Flash-Lite重新辨識一次。未來出現更適合的新模型,也不必重新設計整個照片資料庫。

真正值得保存的是Workflow,而不是某個模型名稱。

AI生成標題/敘述,可以有各種model以供切換。
AI生成標題/敘述,可以有各種model以供切換。

Prompt 寫得再完整,為什麼後端還是要檢查?

做到後來,我已經不再追求所謂:完美 Prompt。原因很簡單,

假設 AI 有:99% 遵守規則,看起來已經非常高。但是 5,000 張照片仍然代表可能有:50 張異常。

所以目前實際流程比較像:

Prompt

AI

Structured JSON

後端驗證

地名保護

括號去重

混合語言修正

繁體中文正規化

長度檢查

Tag 白名單

資料庫

也就是:

AI 的輸出不是完成品,而只是程式的一份輸入資料。

這個觀念改變之後,很多以前覺得只能靠 Prompt 解決的問題,反而變得容易處理。

AI 相簿真正困難的不是 AI

最初我想做的是:

AI 幫我整理照片。

做到接近 5,000 張之後,我的想法已經變成:

建立一個利用 AI 協助整理照片的系統。

兩者的差別非常大。

現在不同資料都有不同的可信來源:

資料 優先來源
拍攝日期 EXIF
GPS EXIF
國家/城市 Google Geocoding
真實 POI Google Places
照片畫面 AI Vision
地點合理性 GPS + Google + AI
標題/描述 AI + 程式規則
正式地名 已確認的資料庫
Tag 固定詞庫 + AI 分類

最後形成的其實是:

EXIF 提供事實

Google 提供地理資料

AI 負責理解畫面與生成文字

程式負責規則與驗證

人負責最後決定

回頭看,我反而覺得這才是生成式 AI 真正適合的使用方式。

不是要求它,什麼都幫我決定。

而是把 AI 放進一個有資料來源、有驗證、有規則、有 fallback 的系統裡。

當只有 10 張照片時,一個漂亮 Prompt 就足以讓人驚艷。

當資料量來到 5,000 張時,真正重要的已經不是偶爾產生一個很漂亮的標題,而是:

第 1 張和第 5,000 張都能維持接近相同的品質;AI 猜錯時不會污染資料庫;模型更換後,整套系統仍然可以繼續運作。

這才是我開發 AI 相簿一路修改到現在,最大的心得。


延伸閱讀:攝影網站建置學習順序

  1. WordPress 能做攝影網站,我為什麼還要在 Synology NAS 自己架一套?
  2. Synology NAS 多網站架構:Docker、Caddy、反向代理與 Umami
  3. AI 自動整理 5,000 張照片:Gemini、GPT、GPS 與 Tag 實戰
  4. Google Maps API 應用於照片 GPS 地點管理與費用優化
  5. 攝影網站 SEO 實戰:如何讓 Google 讀懂相簿與照片

這篇文章已有 44 次瀏覽

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *