Stephen 的戰地筆記

Slack Bot 開發歷程:Menu AI 菜單優化工具


Image generated using ChatGPT and DALL·E

專案背景與動機

在餐飲業中,一份優化的菜單往往能顯著影響營收表現。然而,許多餐廳業主或業務人員缺乏菜單設計的專業知識,或是沒有足夠的時間進行深入分析。這個痛點促使我思考:能否利用 AI 技術,建立一個簡單易用的工具,協助餐廳業主快速獲得專業的菜單優化建議?

在與 AI 工具深入接觸後,我發現 Gemini 和 OCR 技術已經成熟到足以處理菜單分析的複雜任務。最初的構想是建立一個網頁應用,但在與潛在使用者討論後,發現一個更直接的需求:他們希望能在日常已經使用的 Slack 環境中完成所有操作,避免在多個工具間切換的麻煩。

這個洞察引領我轉向開發一個專門的 Slack Bot,讓使用者只需上傳菜單檔案並提供簡單背景資訊,就能獲得 AI 驅動的菜單優化建議,甚至直接匯出可用的 Excel 格式結果。

技術選型與架構設計

核心功能需求

經過與使用者的深入討論,我確定了以下核心功能需求:

  1. 支援多種格式的菜單上傳(圖片、PDF、CSV、文字檔)
  2. 自動辨識菜單內容(OCR)
  3. 根據餐廳特定需求提供客製化優化建議
  4. 支援多輪對話,讓使用者能進一步提問或要求調整
  5. 提供結構化的輸出格式,包含 Markdown 摘要和 Excel 匯出

技術棧選擇

基於這些需求,我選擇了以下技術組合:

  • Slack Bot 框架:@slack/bolt,採用 Socket Mode 連接
  • OCR 技術:Google Cloud Vision API
  • AI 模型:Google Gemini 1.5 Pro
  • 資料庫:PostgreSQL(透過 Zeabur 服務)
  • 後端:Node.js + Express(CommonJS 模式)
  • Excel 處理:ExcelJS
  • 部署平台:Zeabur

資料庫設計

為了管理使用者與 Bot 的互動狀態和對話歷史,我設計了三個主要的資料表:

  1. menus:儲存上傳的菜單檔案路徑與名稱
  2. conversations:記錄 Slack 互動的對話 ID、對應菜單、頻道 ID、討論串時間戳和狀態
  3. messages:儲存使用者和 AI 的對話紀錄

這種設計允許 Bot 在多個頻道、多個討論串中同時服務不同使用者,並保持對話上下文的連貫性。

開發過程中的主要挑戰

Slack 互動流程的優化

最初,我嘗試監聽 Slack 的 file_shared 事件,希望在使用者上傳檔案時自動觸發 Bot。然而,這種方式難以獲取完整的使用者互動上下文。

經過多次調整,最終採用了更為直覺的流程:

  1. 使用者在 Slack 頻道中上傳菜單檔案,並在同一條訊息中 @提及 Bot
  2. Bot 自動處理附加的檔案,並在討論串中詢問餐廳背景資訊
  3. 使用者在討論串中回覆背景資訊,Bot 立即分析並提供建議
  4. 使用者可在同一討論串中繼續對話或要求匯出 Excel

這種設計更符合 Slack 使用者的自然行為模式,大幅降低了學習成本。

OCR 與文件處理的挑戰

處理各種格式的菜單文件是一個重大挑戰。最終實現的流程如下:

  1. 從 Slack 下載檔案到伺服器暫存目錄
  2. 根據檔案類型選擇處理方式:
  • 圖片和 PDF:使用 Google Cloud Vision API 進行 OCR
  • CSV/TXT:直接讀取文字內容
  1. 將辨識結果與使用者提供的背景資訊組合,傳送給 Gemini API

值得一提的是,OCR 技術雖然成熟,但對於格式複雜的菜單仍有辨識誤差。為了提高準確度,在 Gemini Prompt 中加入了對潛在錯誤的容錯處理指導。

Prompt 工程的迭代

AI 輸出品質很大程度上取決於 Prompt 的設計。在專案中,我為不同的使用場景設計了多個專用 Prompt:

  1. 主要分析 Prompt:核心任務是菜單分析和優化,要求輸出結構化的 Markdown 建議
  2. Excel 匯出 Prompt:要求 Gemini 輸出符合特定欄位的 JSON 格式資料
  3. 統整建議 Prompt:用於生成最新的綜合建議摘要

這些 Prompt 經過多次使用者測試和迭代,不斷優化直到能穩定輸出符合預期的結果。其中最大的挑戰是確保 AI 始終遵循指定的輸出格式,特別是在 JSON 輸出方面。

模組系統與部署問題

在開發後期,我遇到了一個意外的挑戰:最初使用的 ES Module (import) 在 Zeabur 部署時出現問題,與某些 CommonJS 套件(如 pg, @slack/bolt)產生衝突。

經過多次嘗試,最終解決方案是將整個專案轉換為 CommonJS (require) 格式,並修正相關的模組引用。這一過程雖然繁瑣,但也讓我深入理解了 Node.js 的模組系統差異。

功能實現細節

Slack Bot 與使用者互動

Bot 的核心是一個狀態機,根據 conversations 表中的 status 欄位決定處理邏輯:

  1. pending_info:等待使用者提供背景資訊的狀態
  2. active:進行中的對話狀態,可接受進一步的問題或指令

使用者可以在對話狀態下輸入兩個特殊指令:

  • 統整建議:獲取最新的 Markdown 格式建議摘要
  • 提供 excel:生成並下載優化後的菜單 Excel 檔案

Excel 匯出的客製化

Excel 匯出功能經過多次調整,最終版本包含以下特點:

  1. 要求 Gemini 輸出嚴格符合指定欄位的 JSON 格式資料
  2. 使用 ExcelJS 處理 JSON 資料,生成 Excel 檔案
  3. 對資料進行多項客製化處理:
  • 只保留包含 (+數字) 的標籤(加價項目)
  • 移除商品名稱中的 emoji
  • 設定標準稅別和稅率

這些微調確保了生成的 Excel 檔案能直接匯入到餐廳的點餐系統中,最大程度減少了手動調整的工作量。

成果與效益

Menu AI Bot 上線後獲得了使用者的積極反饋。平均而言,Bot 能在使用者上傳菜單後 1–2 分鐘內提供初步分析,大幅縮短了原本可能需要數小時的人工菜單分析過程。

具體效益包括:

  1. 時間效率:菜單優化流程從原本需要數小時縮短至幾分鐘
  2. 分析深度:AI 能同時考慮定價策略、菜品分類、視覺呈現等多個維度
  3. 操作便利性:使用者無需離開 Slack,完成從上傳到獲取建議的全流程
  4. 輸出實用性:直接生成可用的 Excel 格式,減少了後續處理工作

反思與經驗總結

1. 用戶需求為先

專案最初設想的網頁應用方向,到後來轉向 Slack Bot 的過程,再次證明了「以用戶需求為中心」的重要性。在技術選型和功能設計上,應優先考慮用戶的實際工作流程和習慣,而非技術的先進性。

2. AI Prompt 工程的關鍵性

在 AI 應用開發中,Prompt 設計的重要性往往被低估。本專案中,大量時間投入在 Prompt 的迭代優化上,最終證明這是確保 AI 輸出品質和一致性的關鍵環節。特別是在需要結構化輸出(如 JSON)的場景中,精確的 Prompt 指導至關重要。

3. 模組系統與依賴管理

Node.js 的 ESM 與 CommonJS 混用環境仍存在不少挑戰,特別是在部署階段可能出現預期外的問題。在選擇技術棧時,應充分考慮不同套件間的兼容性,以及部署環境的特性。

4. 錯誤處理與容錯設計

在整合多個外部服務(Slack API、Google Cloud Vision、Gemini API)的應用中,穩健的錯誤處理機制至關重要。專案實現了多層錯誤捕獲和重試機制,確保即使在某個服務暫時不可用時,也能提供合理的用戶體驗。

結語

Menu AI Bot 的開發歷程展示了如何將先進的 AI 技術與實際業務需求相結合,創造出真正有價值的應用。從最初的概念到最終的實現,專案經歷了多次轉向和調整,但始終保持著「協助餐廳優化菜單」的核心目標。

這個專案也印證了一點:技術的價值不在於其複雜度,而在於能否有效解決實際問題。通過將 OCR、AI 和 Slack 整合到一個無縫的工作流程中,我們成功地將複雜技術轉化為簡單易用的工具,為餐飲業者創造了實際價值。

在 AI 賦能的時代,我們有更多機會通過整合現有技術,快速構建解決特定領域問題的專用工具。Menu AI Bot 只是這一趨勢的一個小小實例,未來還有更多可能性等待探索。


本文由作者與 AI 助手 Claude 合作撰寫