2022 工作上最大的成就,莫過於花費超過 200 小時的專案「海洋生物資料庫」正式上線,除了感謝業主 Spark 的信任之外,也要感謝 Hend Desgin 的 Hend 提供設計協助以及 WPBrewer 的昱程幫我搞定最頭痛的資料庫同步,有信賴我的業主以及值得信賴的夥伴一起工作,這是身為接案者夢寐以求的境界啊~當潛水攝影師遇上生物科學家
這個專案在 2022 二月份開始啟動,靠著 Spark 一大疊的手繪稿開始打造他理想中的平台,之所以會有這個資料庫是因為他發現到潛水愛好者常常拍了很美麗的海洋生物,但卻不知道牠是什麼物種,而這些美麗的照片就這樣躺在攝影師的 D 槽裡(我的 D 槽都是放…)。
另一方面,Spark 團隊在拍攝許多海洋記錄片時,發現到學術研究單位往往缺少物種的照片進行研究,因為研究員很少下水 ( ? ),因此他想到如果可以把在D槽裡的照片上傳平台,再交由研究員進行分類,這對於台灣的海洋研究會是巨大的貢獻。
尤其當研究員發現某些照片是稀有物種時,才知道原來牠們在台灣海域也會出現,有些甚至是台灣首次紀錄種,於是 Spark 就這樣開始了他的燒錢之路XD
事實上在規劃這個平台前,海洋生物資料庫的雛形已經誕生,但當時採用的介面在搜尋物種時需要切換頁面,並且由於搜尋欄位彼此間互相關聯,也就是要用 C 條件篩選必須要先選擇 B 條件,而 B 條件的選項也會根據 A 欄位來決定。
以下圖為例子,要用「生物名稱」篩選照片必須要先選擇「生物分類」以及「生物所屬科」:
因為物種量非常龐大,每一次要取得下拉選單的選項都要花上一點時間,這些小地方累積起來造成整個搜尋體驗並不是非常好。其次,要維護龐大的物種資料使用 WordPress 後台不太便利,尤其物種的歸屬是會持續調整的,這時候對於維護人員來說更新資料時要處理兩次工:先從試算表裡面查到更新後的資料,再將物種從後台更新,萬一更新資料多很容易發生錯誤。
但即使有以上這些問題,他們還是蒐集到上千張的照片,於是 Spark 決定將其改版,以打造更友善的使用者介面為目標。忘不了那天聽 Spark 描述關於這個平台的願景以及對於台灣海洋研究的貢獻,除了一不小心就被圈粉以外,我的經驗告訴我新的版本不應該只是單純用外掛放在原本的媒體網站作為附屬,而是要有獨立的平台才有擴充的空間。
因此這個專案從原本只是開發一支外掛,最後變成全客製化開發的獨立子網站。
專案開始後我逐一把 Spark 的需求手稿用 Figma 繪製成線框圖,藉此釐清每一個新功能的使用流程、操作介面以及預期結果,同時也先確認每個畫面中的資料該如何取得、顯示判斷邏輯等等,透過留言註記功能就能跟 Spark 即時討論:
等到線框圖的內容確認到八成以上,我就同步請 Hend 開始進行視覺設計,並把後台可以先處理的功能也同步進行開發,在設計稿完成的當下,網站的前端也已寫好基礎的框架,隨時能開始進行手刻佈景主題:
由於在規劃階段我已經知道該平台會有大量的即時讀取資料的需求,因此我第一個想法是要以 SPA ( Single Page Application ) 的角度下去開發,但以前有使用過 Vue.js 整合 WordPress 的經驗,發現到會延伸不少的問題,其中最關鍵的就是搜尋引擎最佳化。
雖然現在有不少的解決方案,但礙於不熟悉以及專案時程的考量,還是要採用能符合客戶需求的技術,最後我決定使用混搭式的 SPA,也就是在需要高度互動的介面時,使用 SPA 的架構,把特定區塊的內容全部交由前端來產出,但是換頁的機制還是走原本 WordPress 的作法,關鍵的資料顯示頁交由伺服器處理,藉此確保搜尋引擎能找得到物種資料。
前端框架我採用 Alpine.js 以及 Master CSS,這兩個技術我在其他文章有介紹過就不贅述。現在回過頭來看,比較值得討論的是採用 Master CSS,一開始看到這個新專案覺得超棒,實際寫起來也真的是飛快,但畢竟還是很新的專案,後續版本的更新有變動寫法。
本來想繼續沿用舊版本,但是會產生一些預期外的狀況,雖然影響不大但擔心會影響前端效能,最後還是忍不住,犧牲了一天假日把所有寫法全部翻新,等到好不容易搞定後我告訴自己以後專案一定要採用已經成熟的技術。
接下我分三個面向來介紹海洋生物資料庫:
首先最需要處理的是檢索功能,跟以往是以照片為主體,需要下拉選單逐層篩選的作法比起來,新版的操作邏輯是以物種為主體,只要點選頁籤就能切換分類,並且可以在同一個畫面即時預覽篩選結果:
並且還可以用更細的物種標籤來進一步篩選:
為了實現這樣流暢的使用體驗,底層的資訊架構做了很大的調整,在第一版的作法中我是把不同層級的物種分為不同的 Taxonomy,然後再將裡面的 Term 做關聯,因此在資料查詢時需要跨 Taxonomy 做邏輯判斷。
新版本則使用單一 Taxonomy 的多階層來組織,這在 API 的設計上單純許多,只要知道最底層的物種名稱就能回推它的主分類,因此在使用篩選介面時,會依序載入上方的主分類、根據主分類顯示左側欄的次分類,再根據次分類顯示畫面中間的科別,再用科別去取得物種名稱:
其次是站內搜尋功能會搜尋三種不同類型的資料,分別是物種、照片以及特定作者的照片:
因此現在使用者可以使用檢索功能、標籤篩選以及關鍵字搜尋來找到特定的資料,另外在物種的介紹頁還會一併顯示屬於該物種的照片,以及照片拍攝地點的熱視圖,這樣就能讓研究員知道原來該物種在特定季節會出現在某個海岸:
前面提到照片上傳後還需要研究員進行分類,相較於第一版只能進入單張照片做分類,新平台增加了快速分類的機制,讓研究員可以在同一個頁面中篩選還沒有被正確分類的照片,進而增加分類速度:
另外為了讓民間高手也能幫忙進行照片分類,新平台引入了社群分類機制,只要註冊網站會員,在瀏覽照片時也可以協助分類,但因為有可能民間高手的看法不同,所以有機會出現同一張照片卻是不同分類的狀況,這時候就會啟用一種投票機制,也就是多數決。
票數越高的分類會成為主要分類,如果票數平手時系統會主動發信給研究員,請他們進行最終裁決,進而增加整體資料庫的分類效率。以下圖為例就是日本龍蝦兩票勝出:
此外它還提供簡易的圖片編輯功能,像是裁切、旋轉、調色等等,如果攝影師在照片上傳後想要調整一下照片尺寸,可以直接在網站上搞定!
另外新版本也支援同一生物系列照片的功能,舊版本雖然也可以傳多圖,但每一張圖都會產生獨立的文章,而系列照片可以在同一文章中建立多張照片,這樣就讓能攝影師把拍攝同一生物不同角度的照片作為同一篇文章中的幻燈片進行展示。
系列照片:
切換為一圖一文章:
整個上傳流程真的花了我超多心血,前後來回測試不下上百次,為的就是要處理在實際上傳過程中所發生各種例外狀況,例外還要考慮到上傳後的照片資料修改,像是修改拍攝水溫、深度或是追加新照片等等,這部分我們是放在照片內頁來處理:
Uploadcare 的最大好處就是可以透過 CDN 網址來修改圖片的尺寸,藉此增加照片的讀取速度,像是列表頁就用 100×100 的縮圖,點擊燈箱後就用 2000×1000 的大尺寸來顯示,還可以做智慧裁切,像是把直的照片根據視覺焦點自動裁切為橫的,透過 Uploadcare 的 AI 功能讓我們只要換個路徑參數就能輕鬆辦到。
前面提到既有的物種資料是使用試算表進行維護的,所以一開始在跟 Spark 討論時,我就跟他建議說何不開一份 Google 試算表,然後透過 API 直接同步到網站,就能大幅省下人工作業的時間,他非常驚訝可以這樣做,而當我拿到物種資料後也讓我非常驚訝XD
上千筆的資料分為四個階層,同時還帶有學名以及自訂欄位,學名的部分要作為 Term 的代稱,並且還有規定的大小寫格式要處理,而這些資料都要可以一鍵自動同步到網站後台並且寫入物種的 Taxonomy,我開始有點覺得有抖,不知道自己有沒有辦法做得出來。
好加在我靠著槍手昱程,過沒多久他就幫我生出這個自動同步介面,只要輸入試算表 ID,要同步 sheet 的名稱與欄位範圍即可:
按下同步後就能將試算表資料自動寫入分類裡面,實際操作的感覺非常療癒,按完同步看到分類加入完成超爽快,並且也支援資料的新增與複寫,後來還有加入分類順序的功能,這一切只要在 Google 試算表上修改即可。
搞定千筆的分類資料後,下一個難關是怎麼把舊版的四千張圖片搬到 Uploadcare 上,礙於量的關係不太可能使用他們官方外掛來處理,因此一開始我是打算先把使用者從前台上傳的圖全部抓下來再傳過去,由於檔名帶有特定的後綴,所以理論上可以進主機直接下指令處理,但沒想到不是所有圖片都有後綴,因此這條路 GG。
第二招用 Uploadcare 他們家的 PHP SDK 透過 API 上傳,我先把所有四千張圖片&文章標題組成陣列,然後跑迴圈去打 wp_remote_request
,傳了 15 張之後直接噴 504 Gateway timeout,看來 API 不給大量圖片上傳。
第三招找到他們有提供一種 Proxy 的機制,只要用他們的 Proxy 網址後面接圖片路徑,就能在 User 請求該圖的當下自動把圖片傳去過去,所以想說進資料庫把圖片網址改成這樣:https://uc.proxy.co/https://site.com/photo.jpg
,但問題在於要在請求當下才會觸發,寫 API 去打這四千個網址一樣會 504。
最後找到他們有出一套 python 的程式叫做 migro,可以把所有要上傳的網址寫在一份 txt 裡面,執行後就能開始自動上傳,速度很快,四千張的圖大概半小時就傳完了
然後下一個問題時我該如何把原始圖片的路徑對應到 Uploadcare 上面的路徑,再次感謝 migro,它在跑完後會輸出一份 log,裡面就會一行一行寫好上傳後的路徑,用 VSCode 的選取相同字的功能,把它編排成像這樣的 array:
<?php
$reference = array(
array(
'old' => 'https://bluetrend.media/mcs/wp-content/uploads/2022/11/PA09099711-scaled.jpg',
'new' => 'https://ucarecdn.com/1f6bada1-c17a-43db-abf2-05d4bf551b2d/',
),
array(
'old' => 'https://bluetrend.media/mcs/wp-content/uploads/2022/11/PA09102611-scaled.jpg',
'new' => 'https://ucarecdn.com/88c2ffa4-74ce-461b-9be2-e4d6d2b022a3/',
),
)
然後再寫一支 API 去 Query 所有文章,用 foreach 去比對原始圖片路徑,比對後再抓新的路徑去更新圖片欄位,終於搞定四千張圖片的搬移。
這個平台從我們第一次討論到正式上線,大概花了快一年的時間,以前我也有案子做一年的經驗,但那是一段非常痛苦的回憶,主因還是我只拿三個月的薪水卻必須要工作一整年,更不用説中途的規格變更會讓我有多沮喪。
但自從改用敏捷式接案後讓我再也不用擔心規格變更或是後續的維護問題,反正就是做多少算多少,開發這個平台讓我一整年不用煩惱收入的來源,進而專心投入開發,當然這還是要感謝 Spark 團隊的信任,畢竟在台灣能接受這樣合作模式的公司還是少數。
目前這個平台還有很多計畫,而 Spark 也已將其申請專利,非常期待後續的發展,開發這平台除了認識不少海洋生物外,也第一次感受到自己在做的事情是能對台灣環境有所助益,非常與有榮焉,希望未來還有機會可以參與更多這類型的專案!