Logo
Published on

第一次學 Kotlin Koog AI 就上手 Day 10:讓 AI 看見世界:圖像內容處理

在前一篇文章中,我們學習了如何開發能與外部世界互動的自定義工具。今天我們將探索一個新領域:讓 AI 具備「視覺」能力。Koog 框架提供了強大的圖像處理功能,能夠讓我們的 AI Agent 理解和分析各種視覺內容,從簡單的圖片描述到複雜的文字提取,開啟無限的應用可能

為什麼圖像處理如此重要?

在現代數位世界中,視覺資訊無處不在。從社群媒體的照片、工作文件的截圖,到產品目錄的圖片,我們每天都在處理大量的視覺內容。傳統的 AI 只能處理文字,但現在的 AI 已經能夠「看見」並理解圖像,這為我們帶來了全新的應用場景

  • 文件自動化:自動讀取身分證件、發票、合約等文件
  • 內容管理:智慧分類和標籤照片、圖表、設計稿
  • 教育輔助:解析數學題目、科學圖表、歷史文物
  • 商業應用:產品識別、品質檢測、客戶服務

基礎圖像分析器

讓我們從最基本的圖像分析開始,建立一個簡單易用的 ImageAnalyzer

class ImageAnalyzer(private val client: OpenAILLMClient) {

    /**
     * 判斷路徑是否為 URL
     */
    private fun isURL(path: String): Boolean {
        return path.startsWith("http://") || path.startsWith("https://")
    }

    /**
     * 基本圖像描述功能
     * 接收圖片路徑或 URL,返回詳細的圖像描述
     */
    suspend fun describeImage(
        imagePath: String,
        detailLevel: String = "詳細"
    ): String {
        val response = client.execute(
            prompt = prompt("multimodel") {
                user {
                    text("請${detailLevel}地描述這張圖片的內容,包括:")
                    text("- 主要物件和人物")
                    text("- 場景和背景")
                    text("- 色彩和構圖")
                    text("- 整體氛圍和感受")

                    // 這是 Koog 的核心語法:直接在 prompt 中加入圖片
                    attachments {
                        if (isURL(imagePath)) {
                            image(imagePath) // 網路 URL 直接使用
                        } else {
                            image(Path(imagePath)) // 本地檔案路徑需使用 Path
                        }
                    }
                }
            },
            // 使用支援視覺的模型
            model = OpenAIModels.CostOptimized.GPT4_1Mini
        )

        return response.first().content
    }

    /**
     * 圖像文字提取功能(OCR)
     * 從圖片中準確提取所有文字內容
     */
    suspend fun extractText(imagePath: String): String {
        val response = client.execute(
            prompt = prompt("multimodel") {
                user {
                    text("請準確提取這張圖片中的所有文字內容。")
                    text("要求:")
                    text("1. 保持原有的格式和排版")
                    text("2. 區分不同的文字區塊")
                    text("3. 如果是表格,請用適當的格式呈現")
                    text("4. 如果看不清楚某些文字,請標註 [不清楚]")

                    // 這是 Koog 的核心語法:直接在 prompt 中加入圖片
                    attachments {
                        if (isURL(imagePath)) {
                            image(imagePath) // 網路 URL 直接使用
                        } else {
                            image(Path(imagePath)) // 本地檔案路徑需使用 Path
                        }
                    }
                }
            },
            model = OpenAIModels.CostOptimized.GPT4_1Mini
        )

        return response.first().content
    }
}

基礎圖像分析器使用範例

讓我們看看如何在實際應用中使用 ImageAnalyzer

suspend fun main() {
    // 建立 OpenAI 客戶端和圖像分析器
     val client = OpenAILLMClient(ApiKeyManager.openAIApiKey!!)
     val analyzer = ImageAnalyzer.ImageAnalyzer(client)

     println("=== Koog 圖像處理範例 ===\n")

     // 範例 1:描述一張風景照片
     println("1. 圖像內容描述")
     val description = analyzer.describeImage(
         imagePath = "https://images.pexels.com/photos/1172064/pexels-photo-1172064.jpeg",
         detailLevel = "簡潔"
     )
     println("圖片描述:$description\n")

     // 範例 2:從截圖中提取文字(如程式碼截圖)
     println("2. 文字提取(OCR)")
     val extractedText = analyzer.extractText(
         imagePath = "/Users/cash/Downloads/ocr.png"
     )
     println("提取的文字:\n$extractedText\n")
}

執行 AI 回應內容

圖片內容描述,我使用的是這張圖片

文字提取(OCR),我使用的是這張

=== Koog 圖像處理範例 ===

1. 圖像內容描述
圖片描述:- 主要物件和人物:圖片中央有一棟木造小屋,周圍環繞著多棵樹木,沒有出現人物。
- 場景和背景:小屋坐落於綠意盎然的山坡上,背景是一片茂密的森林。
- 色彩和構圖:以豐富的綠色為主調,層次分明,畫面上方為深綠色森林,下方為明亮的草地,整體構圖平衡且有深度。
- 整體氛圍和感受:給人寧靜、悠閒且貼近自然的感覺,彷彿是遠離都市喧囂的世外桃源。

2. 文字提取(OCR提取的文字:

// 建立 OpenAI 客戶端和圖像分析器
val client = OpenAIILMClient(ApiKeyManager.openAIApiKey!!)
val analyzer = ImageAnalyzer.ImageAnalyzer(client)

println("=== Koog 圖像處理範例 ===\n")

進階圖像處理:使用 Attachment API

除了前面介紹的簡化語法,Koog 還提供了更靈活的 Attachment API,讓我們能夠更精確地控制圖像處理過程。這種方式特別適合需要處理不同圖像來源或需要更多控制參數的場景

AttachmentContent 類型說明

Koog 提供了多種內容來源類型,讓我們能夠靈活處理不同的圖像來源

AttachmentContent.URL

// 直接從網路 URL 載入圖片
AttachmentContent.URL("https://www.pexels.com/zh-tw/photo/1172064/")

AttachmentContent.Binary.Bytes

// 從本地檔案讀取為 byte array
val imageBytes = Files.readAllBytes(Path("/path/to/image.jpg"))
AttachmentContent.Binary.Bytes(imageBytes)

AttachmentContent.Binary.Base64

// 處理 Base64 編碼的圖片資料
AttachmentContent.Binary.Base64("iVBORw0KGgoAAAANSUhEUgAA...")

進階圖像分析器

class AdvancedImageAnalyzer(private val client: OpenAILLMClient) {

    /**
     * 使用 Attachment API 的進階圖像描述
     * 支援更多參數控制和圖像來源類型
     */
    suspend fun describeImageAdvanced(
        imagePath: String,
        fileName: String? = null,
        format: String = "jpg"
    ): String {
        val response = client.execute(
            prompt = prompt("multimodel"){
                user(
                    content = "請詳細描述這張圖片的內容",
                    attachments = listOf(
                        when {
                            imagePath.startsWith("http") -> {
                                // 網路 URL 圖片
                                Attachment.Image(
                                    content = AttachmentContent.URL(imagePath),
                                    format = format,
                                    fileName = fileName ?: "network_image.$format"
                                )
                            }
                            else -> {
                                // 本地檔案,讀取為 byte array
                                val imageBytes = Files.readAllBytes(Path(imagePath))
                                Attachment.Image(
                                    content = AttachmentContent.Binary.Bytes(imageBytes),
                                    format = format,
                                    fileName = fileName ?: Path(imagePath).fileName.toString()
                                )
                            }
                        }
                    )
                )
            },
            model = OpenAIModels.CostOptimized.GPT4_1Mini
        )

        return response.first().content
    }

    /**
     * 批次處理多張圖片
     */
    suspend fun batchImageAnalysis(
        imagePaths: List<String>,
        prompt: String = "比較這些圖片的異同點"
    ): String {
        val attachments = imagePaths.mapIndexed { index, path ->
            when {
                path.startsWith("http") -> {
                    Attachment.Image(
                        content = AttachmentContent.URL(path),
                        format = getImageFormat(path),
                        fileName = "image_$index.${getImageFormat(path)}"
                    )
                }
                else -> {
                    val imageBytes = Files.readAllBytes(Path(path))
                    Attachment.Image(
                        content = AttachmentContent.Binary.Bytes(imageBytes),
                        format = getImageFormat(path),
                        fileName = Path(path).fileName.toString()
                    )
                }
            }
        }

        val response = client.execute(
            prompt = prompt("multimodel") {
                user(
                    content = prompt,
                    attachments = attachments
                )
            },
            model = OpenAIModels.CostOptimized.GPT4_1Mini
        )

        return response.first().content
    }

    private fun getImageFormat(path: String): String {
        return path.substringAfterLast(".", "jpg").lowercase()
    }
}

進階圖像分析器使用範例

suspend fun main() {
    val client = OpenAILLMClient(ApiKeyManager.openAIApiKey!!)
    val analyzer = AdvancedImageAnalyzer(client)

    // 範例 1:處理網路圖片
    println("=== 網路圖片分析 ===")
    val urlResult = analyzer.describeImageAdvanced(
        imagePath = "https://images.pexels.com/photos/1172064/pexels-photo-1172064.jpeg",
        fileName = "landscape.jpg",
        format = "jpg"
    )
    println(urlResult)

    // 範例 2:處理本地檔案
    println("\n=== 本地檔案分析 ===")
    val localResult = analyzer.describeImageAdvanced(
        imagePath = "/Users/cash/Downloads/ocr.png",
        format = "png"
    )
    println(localResult)

    // 範例 3:批次處理多張圖片
    println("\n=== 批次圖片比較 ===")
    val imagePaths = listOf(
        "https://images.pexels.com/photos/1172064/pexels-photo-1172064.jpeg",
        "/Users/cash/Downloads/ocr.png"
    )
    val batchResult = analyzer.batchImageAnalysis(
        imagePaths = imagePaths,
        prompt = "比較這兩張圖片的風格、色調和主題"
    )
    println(batchResult)
}

執行 AI 回應內容

這裡使用的圖片,和前面的一樣,就不在列出

=== 網路圖片分析 ===
這張圖片展示了一間位於山坡上的木屋,周圍環繞著濃密的綠色植被。山坡綠草如茵,分布著零星的小樹和灌木。木屋呈現傳統設計,屋頂是深色的,窗戶白色框架,顯得古樸而安靜。背景是一片茂密的森林,高大的針葉樹和闊葉樹錯落有致,形成濃密的綠蔭,給人一種幽靜、自然且遠離城市喧囂的感覺。整體畫面清新靜謐,表達出與大自然和諧共處的意境。

=== 本地檔案分析 ===
這張圖片內容是一段以 Kotlin 語言撰寫的程式碼,展示了如何建立 OpenAI 客戶端和圖像分析器。程式碼中包含以下部分:

1. 註解(以 `//` 開頭):
   - 說明程式碼的用途:「建立 OpenAI 客戶端和圖像分析器」

2. 第一行程式碼:
   val client = OpenAI LLMClient(ApiKeyManager.openAIApiKey!!)

   - 使用 `val` 宣告一個常數 `client`
   - 透過 `OpenAILLMClient` 類別來建立客戶端物件,並傳入 API 金鑰(由 `ApiKeyManager.openAIApiKey!!` 提供)
   - 其中 `!!` 表示強制解包,確保 API 金鑰不是 null

3. 第二行程式碼:
   val analyzer = ImageAnalyzer.ImageAnalyzer(client)

   - 建立圖像分析器物件,名稱為 `analyzer`
   - 使用 `ImageAnalyzer.ImageAnalyzer` 類別,並將剛剛建立的 `client` 傳入建構子

4. 第三行程式碼:
   println("=== Koog 圖像處理範例 ===\n")

   - 輸出一行文字提示:「=== Koog 圖像處理範例 ===」,並加上一個換行符號

整體來說,這段程式碼示範如何初始化 OpenAILLM 客戶端及圖像分析工具,並在終端或控制台打印一段提示文字。

=== 批次圖片比較 ===
這兩張圖片風格、色調和主題截然不同:

1. 風格:
- 第一張:自然風格,拍攝手法偏向風景攝影,強調自然和寧靜。
- 第二張:數位風格,是程式碼截圖,偏技術和現代感。

2. 色調:
- 第一張:色彩明亮以綠色系為主,有自然光的柔和感。
- 第二張:主色調是深色背景搭配多色程式語言關鍵字高亮(紫、橘、綠等)。

3. 主題:
- 第一張:主題是自然環境與孤獨的木屋,帶有恬靜和放鬆氛圍。
- 第二張:主題是程式碼範例與技術展示,聚焦於OpenAI和圖片分析。

總結:第一張偏向自然與風景攝影,美感和情緒渲染強烈;第二張則是數位技術類,比較理性、冷靜和功能性。

兩種方法的比較

功能特色簡化語法 (image())Attachment API
使用難度簡單直觀稍微複雜
參數控制基本完整控制
圖像來源URL + 本地檔案URL + Bytes + Base64 + 文字
批次處理需要多次調用原生支援
檔案資訊自動推斷可指定格式、檔名等
適用場景快速原型開發生產環境應用

使用建議

  • 快速原型:使用簡化的 image() 語法
  • 生產應用:使用 Attachment API 以獲得更好的控制
  • 批次處理:優先考慮 Attachment API 的批次功能
  • 網頁整合:Base64 支援對於網頁上傳的圖片很有用

注意事項

在本篇的範例中,為了簡單方便,我們並沒有考慮到使用者上傳圖片時可能遇到的各種錯誤情況。在正式的程式碼中,建議一併考慮並實作以下錯誤處理

  • 檔案驗證:檢查圖片檔案是否存在
  • 格式檢查:確認檔案格式是否支援(jpg, png, gif 等)
  • 大小限制:確保檔案大小未超過 API 限制
  • 網路問題:處理網路圖片載入失敗的情況
  • API 調用錯誤:處理 AI 服務的回應錯誤

總結

今天我們學習了 Koog 框架的圖像處理能力,掌握了

  • 基礎圖像分析:使用簡化的 image() 語法進行圖片描述和文字提取(OCR)
  • 進階 Attachment API:透過結構化的 API 處理不同圖像來源(URL、Bytes、Base64)
  • 批次處理功能:同時分析多張圖片並進行比較
  • 實際應用場景:從照片分析到文件 OCR 的具體實作
  • 兩種方法比較:了解何時使用簡化語法或 Attachment API

圖像處理為 AI 應用開啟了全新的可能性。從簡單的照片描述到複雜的文件分析,從教育輔助到商業自動化,視覺 AI 正在改變我們與數位內容互動的方式

掌握了圖像處理能力後,下一篇文章我們將探索 Koog 框架的另一個重要多媒體處理領域:文件處理。我們將學習如何讓 AI 讀懂 PDF、Word 文檔等各種文件格式,並實現 AI 處理文件摘要、關鍵資訊提取等功能。這對於處理商業報告、學術論文、技術文檔等場景將非常有用

參考資料


支持創作

如果這篇文章對您有幫助,歡迎透過 贊助連結 支持我持續創作優質內容。您的支持是我前進的動力!


圖片來源:www.pexels.com 以及 AI 產生