สร้างแอปการกู้คืนรูปภาพโดยใช้ Genkit Go และ Nano Banana Pro

1. บทนำ

ใน Codelab นี้ เราจะสร้าง GlowUp ซึ่งเป็นเครื่องมือการกู้คืนรูปภาพ GlowUp ใช้ AI เพื่อกู้คืนรูปภาพเก่า เสียหาย หรือขาวดำ สร้างรูปภาพสีคุณภาพสูงระดับ 4K คุณสามารถใช้เครื่องมือนี้เพื่อทำให้รูปภาพครอบครัวกลับมามีชีวิตอีกครั้ง หรือแม้แต่ปรับใช้เพื่อกู้คืนภาพวาด ภาพวาด ภาพวาด หรือรูปภาพรูปแบบอื่นๆ ที่เสียหาย

คุณจะใช้ Genkit Go เพื่อใช้ตรรกะของแอปพลิเคชัน และใช้ Gemini 3 Pro Image (หรือที่เรียกว่า Nano Banana Pro) เป็นโมเดลเพื่อประมวลผลรูปภาพ

ข้อกำหนดเบื้องต้น

  • ความรู้พื้นฐานเกี่ยวกับภาษาโปรแกรม Go
  • ความรู้พื้นฐานเกี่ยวกับคอนโซล Google Cloud

สิ่งที่คุณจะได้เรียนรู้

  • วิธีพัฒนาแอปพลิเคชัน Genkit ใน Go
  • แนวคิดพื้นฐานของ Genkit เช่น โฟลว์ ปลั๊กอิน และพรอมต์
  • วิธีเขียนพรอมต์ด้วยเทมเพลต Handlebars
  • วิธีรับข้อมูลรูปภาพจากคำตอบของโมเดล

สิ่งที่คุณต้องมี

คุณสามารถทำเวิร์กช็อปนี้ได้ทั้งหมดภายใน Google Cloud Shell ซึ่งมาพร้อมกับทรัพยากร Dependency ที่จำเป็นทั้งหมด (gcloud CLI, ตัวแก้ไขโค้ด, Go, Gemini CLI) ที่ติดตั้งไว้ล่วงหน้า

หรือหากต้องการทำงานในเครื่องของคุณเอง คุณจะต้องมีสิ่งต่อไปนี้

  • ชุดเครื่องมือ Go (เวอร์ชัน 1.24 ขึ้นไป)
  • Node.js v20 ขึ้นไป (สำหรับ genkitCLI)
  • เทอร์มินัลที่ติดตั้ง gcloud CLI
  • IDE สำหรับแก้ไขโค้ด เช่น VS Code หรือ IDE ที่คล้ายกัน
  • แนะนำ: เอเจนต์การเขียนโค้ด เช่น Gemini CLI หรือ Antigravity

เทคโนโลยีหลัก

ดูข้อมูลเพิ่มเติมเกี่ยวกับเทคโนโลยีที่เราจะใช้ได้ที่นี่

  • Gemini Nano Banana Pro (Gemini 3 Pro Image): โมเดลที่ขับเคลื่อนกระบวนการกู้คืนของเรา
  • Genkit Go: ชุดเครื่องมือของเราสำหรับการจัดระเบียบการเรียกใช้โมเดล

2. การตั้งค่าสภาพแวดล้อม

เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้ การตั้งค่าสภาพแวดล้อมแบบเรียนรู้ด้วยตนเอง หากต้องการเรียกใช้ Codelab นี้ในเครื่องของคุณเอง หรือเริ่ม Cloud Shell หากต้องการเรียกใช้ Codelab นี้ในระบบคลาวด์ทั้งหมด

การตั้งค่าสภาพแวดล้อมแบบเรียนรู้ด้วยตนเอง

  1. ลงชื่อเข้าใช้ Google Cloud Console แล้วสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • ชื่อโปรเจ็กต์คือชื่อที่แสดงสำหรับผู้เข้าร่วมโปรเจ็กต์นี้ ซึ่งเป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ คุณอัปเดตได้ทุกเมื่อ
  • รหัสโปรเจ็กต์จะไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมดและเปลี่ยนแปลงไม่ได้ (เปลี่ยนไม่ได้หลังจากตั้งค่าแล้ว) Cloud Console จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ซึ่งโดยปกติแล้วคุณไม่จำเป็นต้องสนใจว่าสตริงนั้นคืออะไร ใน Codelab ส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยทั่วไปจะระบุเป็น PROJECT_ID) หากไม่ชอบรหัสที่สร้างขึ้น คุณอาจสร้างรหัสแบบสุ่มอีกรหัสหนึ่งได้ หรือคุณอาจลองใช้ชื่อของคุณเองและดูว่ามีชื่อนั้นหรือไม่ คุณจะเปลี่ยนแปลงรหัสนี้หลังจากขั้นตอนนี้ไม่ได้ และรหัสจะคงอยู่ตลอดระยะเวลาของโปรเจ็กต์
  • โปรดทราบว่ายังมีค่าที่ 3 ซึ่งคือหมายเลขโปรเจ็กต์ที่ API บางตัวใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 นี้ได้ในเอกสารประกอบ
  1. จากนั้นคุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของ Cloud การทำตาม Codelab นี้จะไม่มีค่าใช้จ่ายมากนัก หรืออาจไม่มีค่าใช้จ่ายเลย หากต้องการปิดทรัพยากรเพื่อหลีกเลี่ยงการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่สร้างขึ้นหรือลบโปรเจ็กต์ได้ ผู้ใช้ Google Cloud รายใหม่มีสิทธิ์เข้าร่วมโปรแกรมช่วงทดลองใช้ฟรีมูลค่า$300 USD

เริ่มต้น Cloud Shell

แม้ว่าคุณจะใช้งาน Google Cloud จากระยะไกลจากแล็ปท็อปได้ แต่ใน Codelab นี้คุณจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์

จาก Google Cloud Console ให้คลิกไอคอน Cloud Shell ในแถบเครื่องมือด้านขวาบน

เปิดใช้งาน Cloud Shell

การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมจะใช้เวลาเพียงไม่กี่นาที เมื่อเสร็จแล้ว คุณควรเห็นข้อความคล้ายกับตัวอย่างต่อไปนี้

ภาพหน้าจอของเทอร์มินัล Google Cloud Shell ที่แสดงว่าสภาพแวดล้อมเชื่อมต่อแล้ว

เครื่องเสมือนนี้มาพร้อมเครื่องมือพัฒนาซอฟต์แวร์ทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักแบบถาวรขนาด 5 GB และทำงานบน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก คุณสามารถทำงานทั้งหมดใน Codelab นี้ได้ภายในเบราว์เซอร์ คุณไม่จำเป็นต้องติดตั้งอะไร

3. การตั้งค่าโปรเจ็กต์

สร้างโปรเจ็กต์

ก่อนอื่นเราต้องสร้างไดเรกทอรีใหม่สำหรับโปรเจ็กต์และเริ่มต้นโมดูล Go เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

mkdir -p glowup && cd glowup
go mod init glowup

ติดตั้ง Genkit CLI

ตอนนี้เราต้องติดตั้ง Genkit CLI ซึ่งจะช่วยให้คุณเข้าถึงเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ในเครื่องได้ รวมถึง UI สำหรับนักพัฒนาซอฟต์แวร์ ในหน้าต่างเทอร์มินัล ให้พิมพ์

curl -sL cli.genkit.dev | bash

กำหนดค่าตัวแปรสภาพแวดล้อม

ตรวจสอบว่าคุณได้ตั้งค่าข้อมูลเข้าสู่ระบบ Google Cloud ที่ถูกต้องแล้ว แทนที่ your-project-id ด้วยรหัสโปรเจ็กต์จริง ต้องเปิดglobalเมื่อใช้โมเดลเวอร์ชันตัวอย่างของ Gemini 3 Pro (Nano Banana Pro เป็นหนึ่งในนั้น)

export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_CLOUD_LOCATION=global

เรียกใช้คำสั่งต่อไปนี้ในโหมด Shell เพื่อเปิดใช้ Vertex AI API

gcloud services enable aiplatform.googleapis.com

และหากเรียกใช้จากเครื่องในพื้นที่ (ไม่ได้อยู่ใน Cloud Shell) คุณจะต้องตรวจสอบสิทธิ์ด้วยคำสั่ง gcloud ดังนี้

gcloud auth application-default login

4. สร้างแอปพลิเคชัน Genkit แรก

Genkit เป็นเฟรมเวิร์กแบบโอเพนซอร์สที่ออกแบบมาเพื่อช่วยนักพัฒนาซอฟต์แวร์สร้าง ทดสอบ และตรวจสอบแอปพลิเคชันที่ทำงานด้วยระบบ AI ที่พร้อมใช้งานจริง ในส่วนนี้ เราจะสร้างแอปพลิเคชัน "Hello World" อย่างง่ายเพื่อช่วยให้คุณคุ้นเคยกับเฟรมเวิร์กก่อนที่จะเจาะลึกตรรกะการคืนค่ารูปภาพ

คำศัพท์ของ Genkit

ก่อนเริ่มทำงานกับ Genkit คุณควรทำความเข้าใจคำศัพท์สำคัญ 2-3 คำต่อไปนี้

  • ปลั๊กอิน: ใช้เพื่อขยายความสามารถของ Genkit คุณจะลงทะเบียนโมเดล AI เพื่อขับเคลื่อนแอปพลิเคชันผ่านปลั๊กอิน
  • โฟลว์: องค์ประกอบสถาปัตยกรรมหลักของ Genkit โดยปกติแล้วโฟลว์จะรับอินพุต ประมวลผล และแสดงผลลัพธ์ คุณไม่จำเป็นต้องใช้โมเดล แต่ส่วนใหญ่แล้วคุณจะใช้โมเดลภายในโฟลว์
  • พรอมต์: เทมเพลตการโต้ตอบที่จัดเก็บในรูปแบบ dotprompt (บันทึกเป็นไฟล์ *.prompt) ซึ่งไม่เพียงมีคำสั่งของโมเดล แต่ยังมีการกำหนดค่า เช่น ชื่อโมเดล พารามิเตอร์ของโมเดล อินพุต และเอาต์พุต

การเชื่อมต่อกับโมเดล AI

Genkit ใช้ปลั๊กอินเพื่อเชื่อมต่อโค้ดกับผู้ให้บริการโมเดล มีปลั๊กอินสำหรับผู้ให้บริการโมเดลรายใหญ่ทั้งหมด ซึ่งรวมถึง Google, Anthropic และ OpenAI นอกจากนี้ คุณยังใช้ปลั๊กอินเพื่อเชื่อมต่อกับโมเดลในเครื่อง (เช่น ใช้ Ollama) หรือเพื่อขยายความสามารถของ Genkit (เช่น เชื่อมต่อกับเซิร์ฟเวอร์ MCP) ได้ด้วย

หากต้องการเข้าถึงโมเดลของ Google คุณควรใช้ปลั๊กอิน googlegenai โดยรองรับ 2 แบ็กเอนด์ ได้แก่

  • Google AI: เหมาะที่สุดสำหรับการสร้างต้นแบบ ใช้คีย์ API
  • Vertex AI (Google Cloud): แนะนำสำหรับเวอร์ชันที่ใช้งานจริง ใช้รหัสโปรเจ็กต์และตำแหน่ง

ในโค้ดแล็บนี้ เราจะใช้การตรวจสอบสิทธิ์ Vertex AI โดยอ้างอิงโปรเจ็กต์ที่คุณสร้างขึ้นในช่วงต้นของแล็บ

การสร้างโฟลว์สำหรับผู้ทักทาย

ก่อนที่จะเจาะลึกขั้นตอนการกู้คืนรูปภาพด้วยฟีเจอร์ Glow Up เรามาสร้างโฟลว์พื้นฐานเพื่อให้คุ้นเคยกับแนวคิดและตรวจสอบว่าการตั้งค่าของเราทำงานได้อย่างถูกต้อง

โฟลว์เป็นฟังก์ชัน Genkit พิเศษที่ห่อหุ้มตรรกะ AI เพื่อให้

  • อินพุตและเอาต์พุตที่ปลอดภัยต่อประเภท: กําหนดสคีมาโดยใช้โครงสร้าง Go สําหรับการตรวจสอบแบบคงที่และรันไทม์
  • การรองรับการสตรีม: สตรีมการตอบกลับบางส่วนหรือข้อมูลที่กำหนดเอง
  • การผสานรวม UI ของนักพัฒนาแอป: ทดสอบและแก้ไขข้อบกพร่องของโฟลว์ด้วยการติดตามด้วยภาพ
  • การติดตั้งใช้งานที่ง่ายดาย: ทำให้ใช้งานได้เป็นปลายทาง HTTP ในแพลตฟอร์มใดก็ได้

เปิด IDE แล้วสร้างไฟล์ main.go ในไดเรกทอรีโปรเจ็กต์ หากใช้ Cloud Shell คุณสามารถใช้คำสั่งต่อไปนี้

cloudshell edit main.go

จากนั้นเพิ่มโค้ดต่อไปนี้

main.go

package main

import (
        "context"
        "log"
        "os"
        "os/signal"
        "syscall"

        "github.com/firebase/genkit/go/genkit"
        "github.com/firebase/genkit/go/ai"
        "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
        ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
        defer cancel()

        // Initialize Genkit with the Vertex AI plugin
        g := genkit.Init(ctx,
                genkit.WithPlugins(&googlegenai.VertexAI{}),
        )

        // Define the greeter flow
        genkit.DefineFlow(g, "greeter", func(ctx context.Context, name string) (string, error) {
                text, err := genkit.GenerateText(ctx, g,
                        ai.WithModelName("vertexai/gemini-2.5-pro"),
                        ai.WithPrompt("Say a warm and creative hello to %s", name),
                )
                if err != nil {
                        return "", err
                }

                return text, nil
        })

        // Register the flow here in the next steps
        log.Println("GlowUp initialized. Ready for flows.")
        <-ctx.Done()
}

บันทึกไฟล์ แล้วเรียกใช้ go mod tidy เพื่ออัปเดตทรัพยากร Dependency

go mod tidy

โค้ดด้านบนจะเริ่มต้น Genkit ด้วยปลั๊กอิน Vertex AI กําหนดโฟลว์ชื่อ "greeter" แล้วรออย่างไม่มีกําหนดใน <-ctx.Done() เราจะระงับการดำเนินการไว้เพื่อให้โปรแกรมนี้ไม่สิ้นสุดทันที เนื่องจากเราไม่ได้ให้คำสั่งใดๆ เพื่อดำเนินการตามโฟลว์จริงๆ

ซึ่งหมายความว่าหากคุณเรียกใช้โปรแกรมนี้ในตอนนี้ โปรแกรมจะไม่ทํางานด้วยตัวเองมากนัก เราจึงต้องเรียกใช้โฟลว์ด้วยวิธีใดวิธีหนึ่ง แม้ว่าในแอปพลิเคชันการผลิตจริง เราจะห่อหุ้มโฟลว์นี้ในเว็บเซิร์ฟเวอร์หรือแอป CLI แต่ในระหว่างการพัฒนา เราสามารถใช้ genkit CLI เพื่อช่วยเราพัฒนาและเพิ่มประสิทธิภาพโฟลว์ได้

genkit CLI ได้รับการพัฒนาขึ้นเพื่อช่วยเราทดสอบโมเดล พรอมต์ โฟลว์ และคอมโพเนนต์อื่นๆ ของสแต็ก Genkit นอกจากนี้ ยังรองรับการติดตามอย่างเต็มรูปแบบ ซึ่งสะดวกมากเมื่อคุณต้องการทำความเข้าใจวิธีการทำงานของแอปพลิเคชันเบื้องหลัง หากต้องการเปิดตัวโฟลว์การต้อนรับโดยใช้ CLI ของ genkit ให้เรียกใช้คำสั่งต่อไปนี้

genkit start -- go run main.go

ซึ่งจะเปิดใช้งานปลายทาง Telemetry API และ UI สำหรับนักพัฒนาแอป คุณควรเห็นข้อความคล้ายกับข้อความต่อไปนี้

$ genkit start -- go run main.go
Telemetry API running on http://localhost:4033
Project root: /home/daniela/glowup
Genkit Developer UI: http://localhost:4000

หากคุณเปิด localhost:4000 ในเบราว์เซอร์เพื่อเปิดใช้ UI สำหรับนักพัฒนาซอฟต์แวร์ คุณควรเห็นหน้าจอแบบนี้

93d9bd9e1bd6627d.png

โปรดใช้เวลาสำรวจ UI สำหรับนักพัฒนาแอป คุณอาจทริกเกอร์โฟลว์ "ผู้ทักทาย" เพียงครั้งเดียวเพื่อดูวิธีการทำงาน

การใช้เทมเพลตพรอมต์

แม้ว่าคุณจะฮาร์ดโค้ดพรอมต์ในการเรียกใช้โมเดลได้เหมือนที่เราทำในตัวอย่างก่อนหน้า แต่แนวทางที่ดีกว่าคือการสร้างเทมเพลตพรอมต์เพื่อจัดเก็บพรอมต์ทั้งหมดของแอปพลิเคชันในลักษณะรวมศูนย์ ซึ่งไม่เพียงช่วยให้ค้นหาได้ง่ายขึ้นเมื่อทำการบำรุงรักษาโค้ด แต่ยังช่วยให้คุณทดสอบพรอมต์ได้อย่างอิสระจากโฟลว์ด้วย

Genkit ใช้รูปแบบ dotprompt แบบโอเพนซอร์สที่บันทึกเป็นไฟล์ *.prompt เพื่อกำหนดเทมเพลตพรอมต์ .prompt ไฟล์ประกอบด้วย 2 ส่วน ได้แก่

  1. Frontmatter: บล็อก YAML ที่กำหนดโมเดล พารามิเตอร์ของโมเดล และทั้งสคีมาอินพุตและเอาต์พุต
  2. เนื้อหา: เนื้อหาของพรอมต์เอง ซึ่งสามารถสร้างเป็นเทมเพลตได้โดยใช้ไวยากรณ์ "Handlebars" เช่น หากคุณกำหนดอินพุตชื่อ variable-name คุณจะอ้างอิงอินพุตนั้นในเนื้อหาเป็น {{variable-name}} ได้

โครงสร้างไดเรกทอรีของโปรเจ็กต์จะมีลักษณะดังนี้

glowup/
 ├── main.go        
 └── prompts/
      └── greeter.prompt

มาดูตัวอย่างการใช้งานกัน ก่อนอื่นให้สร้างโฟลเดอร์เพื่อจัดเก็บพรอมต์โดยทำดังนี้

mkdir -p prompts

จากนั้นสร้างไฟล์ greeter.prompt โดยทำดังนี้

cloudshell edit prompts/greeter.prompt

และแทรกเนื้อหาต่อไปนี้

greeter.prompt

ec9fc82a98604123.png

พรอมต์นี้แสดงฟีเจอร์บางอย่างของภาษาเทมเพลต ก่อนอื่น เราจะระบุโมเดล vertexai/gemini-2.5-flash ในส่วนหน้า หากต้องการระบุโมเดล คุณต้องใช้การตั้งชื่อที่กำหนดไว้ในเอกสารประกอบของปลั๊กอินที่เกี่ยวข้อง

ส่วนการกำหนดค่าช่วยให้เรากำหนดค่าพารามิเตอร์ของโมเดลได้ เราใช้อุณหภูมิ 1.9 เพื่อให้โมเดลมีความคิดสร้างสรรค์มากขึ้น อุณหภูมิมีตั้งแต่ 0 (เอาต์พุตที่สอดคล้องกันมากขึ้น) ถึง 2 (เอาต์พุตที่สร้างสรรค์มากขึ้น) โดยปกติแล้ว พารามิเตอร์นี้และพารามิเตอร์อื่นๆ ของโมเดลจะเผยแพร่ในเอกสารข้อมูลโมเดลของโมเดล ตัวอย่างเช่น นี่คือชีตโมเดลสำหรับ gemini-2.5-flash

ส่วนอินพุตช่วยให้เราสามารถระบุอาร์กิวเมนต์สำหรับพรอมต์ได้ ในกรณีนี้ เราจะกำหนดชื่อเป็นสตริง หลังจากส่วนหน้า เราก็มีเนื้อหาของพรอมต์ บล็อกแรกในที่นี้กำหนดพรอมต์ของระบบ และบล็อกที่ 2 คือพรอมต์ของผู้ใช้ องค์ประกอบทั้งหมดนี้รวมกันช่วยให้ใช้เทคนิคการแจ้งที่มีประสิทธิภาพสูงได้ คุณดูเอกสารประกอบฉบับสมบูรณ์สำหรับ dotprompt ได้ที่นี่

ตอนนี้เรามาปรับgreeterโฟลว์เพื่อใช้พรอมต์ที่เราเพิ่งสร้างกัน

main.go

package main

import (
        "context"
        "os"
        "os/signal"
        "syscall"

        "github.com/firebase/genkit/go/ai"
        "github.com/firebase/genkit/go/genkit"
        "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
        ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
        defer cancel()

        // Initialize Genkit with the Vertex AI plugin
        g := genkit.Init(ctx,
                genkit.WithPlugins(&googlegenai.VertexAI{}),
                genkit.WithDefaultModel("vertexai/gemini-2.5-flash"),
        )

        // Define the greeter flow
        genkit.DefineFlow(g, "greeter", func(ctx context.Context, name *string) (string, error) {
                prompt := genkit.LookupPrompt(g, "greeter")

                input := map[string]any{
                        "name": name,
                }

                resp, err := prompt.Execute(ctx, ai.WithInput(input))
                if err != nil {
                        return "", err
                }
                return resp.Text(), nil
        })

        <-ctx.Done()
}

ลองเรียกใช้โฟลว์จากบรรทัดคำสั่งโดยมีและไม่มีชื่อเพื่อดูความแตกต่าง การเรียกใช้ที่ไม่มีชื่อ

genkit flow:run greeter

ตัวอย่างเอาต์พุต

$ genkit flow:run greeter
Telemetry API running on http://localhost:4035
Running '/flow/greeter' (stream=false)...
Result:
"Hello there, absolutely delightful human!\n\nThe very moment your message arrived, the day instantly sparkled a little brighter. It's not just nice, it's genuinely **wonderful** to meet you!\n\nMay your entire day be filled with unexpected pockets of joy, effortless triumphs, and all the happiness you truly deserve! We're thrilled to have you here!"

และมีชื่อ

genkit flow:run greeter '{"name":"Daniela"}'

ตัวอย่างเอาต์พุต

$ genkit flow:run greeter '{"name":"Daniela"}'
Telemetry API running on http://localhost:4035
Running '/flow/greeter' (stream=false)...
Result:
"Well hello there, Daniela! What a truly beautiful name, and what an absolute pleasure it is to meet you!\n\nRight from this moment, I just know your day is going to be brimming with positive energy and wonderful surprises. May it be filled with brilliant ideas, joyful moments, and the delightful realization that you're an amazing person doing incredible things. So glad you're here!"

คุณจะเห็นว่าเทมเพลตทำงานได้ตามที่คาดไว้ เราพร้อมที่จะยกระดับโปรเจ็กต์นี้ไปอีกขั้นแล้ว

5. การกู้คืนรูปภาพด้วย Nano Banana Pro

พรอมต์การกู้คืน

เมื่อคุ้นเคยกับองค์ประกอบพื้นฐานของ Genkit แล้ว ก็ได้เวลาสร้างพรอมต์การคืนค่ารูปภาพ

สร้างไฟล์ชื่อ glowup.prompt ในไดเรกทอรีพรอมต์ แล้ววางเนื้อหาต่อไปนี้ลงในไฟล์

glowup.prompt

fd0f1551466c8138.png

ข้อความแจ้งการกู้คืนมีรูปแบบเดียวกับข้อความแจ้ง "ผู้ต้อนรับ" ของเรา โดยมีความแตกต่างที่สำคัญเพียง 2 ประการ ดังนี้

  • ขนาดรูปภาพ: พร็อพเพอร์ตี้ imageSize ของ imageConfig เป็นพารามิเตอร์เฉพาะโมเดลของ Nano Banana Pro ซึ่งช่วยให้เราสามารถระบุขนาดเอาต์พุตเป็น 1K, 2K หรือ 4K ได้
  • อินพุตสื่อ: เราใช้เทมเพลต {{ media }} เพื่อแทรกรูปภาพในพรอมต์ของผู้ใช้ เทคนิคนี้ช่วยให้เราส่งพรอมต์แบบหลายโมดัล (ข้อความ + รูปภาพ) ไปยังโมเดลได้

คุณทดสอบพรอมต์นี้ได้ใน UI สำหรับนักพัฒนาแอป คุณสามารถปรับแต่งเพื่อดูว่าส่งผลต่อเอาต์พุตอย่างไร

ขั้นตอนการกู้คืนรูปภาพ

เมื่อพรอมต์การกู้คืนพร้อมแล้ว เรามาสร้างแอปพลิเคชัน CLI กัน แทนที่เนื้อหาของ main.go ด้วยโค้ดด้านล่าง

main.go

package main

import (
        "context"
        "encoding/base64"
        "errors"
        "flag"
        "fmt"
        "log"
        "mime"
        "os"
        "os/signal"
        "strings"
        "syscall"

        "github.com/firebase/genkit/go/ai"
        "github.com/firebase/genkit/go/genkit"
        "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
        url := flag.String("url", "", "url of the image to restore")
        contentType := flag.String("contentType", "image/jpeg", "content type of the image (default: image/jpeg)")
        flag.Parse()

        ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
        defer cancel()

        // Initialize Genkit with the Vertex AI plugin
        g := genkit.Init(ctx,
                genkit.WithPlugins(&googlegenai.VertexAI{}),
        )

        // Input schema for the glowUp flow
        type Input struct {
                URL         string `json:"url,omitempty"`
                ContentType string `json:"contentType,omitempty"`
        }

        glowup := genkit.DefineFlow(g, "glowUp", func(ctx context.Context, input Input) (string, error) {
                // 1. Retrieve prompt
                prompt := genkit.LookupPrompt(g, "glowup")
                if prompt == nil {
                        return "", errors.New("prompt 'glowup' not found")
                }

                resp, err := prompt.Execute(ctx, ai.WithInput(input))
                if err != nil {
                        return "", fmt.Errorf("generation failed: %w", err)
                }

                return resp.Media(), nil
        })

        // triggers the flow and returns the encoded response from the model
        out, err := glowup.Run(ctx, Input{URL: *url, ContentType: *contentType})
        if err != nil {
                log.Fatalln(err)
        }

        // decodes image data and returns the appropriate file extension
        data, ext, err := decode(out)
        if err != nil {
                log.Fatalln(err)
        }

        // writes restored file to disk
        filename := "restored" + ext
        if err := os.WriteFile(filename, data, 0644); err != nil {
                log.Fatalln(err)
        }
}

// decode returns the decoded data and the file extension appropriate for the mime type
func decode(text string) ([]byte, string, error) {
        if !strings.HasPrefix(text, "data:") {
                return nil, "", errors.New("unsupported enconding format")
        }
        text = strings.TrimPrefix(text, "data:")
        parts := strings.Split(text, ";base64,")

        mimeType := parts[0]
        decoded, err := base64.StdEncoding.DecodeString(parts[1])
        if err != nil {
                return nil, "", err
        }

        ext, err := mime.ExtensionsByType(mimeType)
        if err != nil {
                return nil, "", err
        }

        return decoded, ext[0], nil
}

โค้ดมีโครงสร้างคล้ายกับโฟลว์ greeter มาก แต่คราวนี้ได้รับการดัดแปลงให้ทำงานเป็นแอปพลิเคชัน CLI แบบสแตนด์อโลน แทนที่จะบล็อกตลอดไป ระบบจะเรียกใช้โฟลว์ glowUp ถอดรหัสเอาต์พุต และบันทึกข้อมูลไบนารีที่ได้ลงในดิสก์

เราต้องถอดรหัสเอาต์พุตเนื่องจากโมเดลจะแสดงผลข้อมูลรูปภาพในรูปแบบต่อไปนี้

data:<mime type>;base64,<base64 encoded image>

คุณจะเห็นในฟังก์ชัน decode ว่าเราใช้การจัดการสตริงเพื่อแยกประเภท MIME และส่วนรูปภาพที่เข้ารหัส จากนั้นเราจะใช้ฟังก์ชัน mime.ExtensionByType และ base64.DecodeString เพื่อดึงข้อมูลที่เราต้องการบันทึกไฟล์

การทดสอบขั้นตอนการกู้คืน

ตอนนี้ก็ถึงเวลาเรียกใช้โฟลว์นี้กับรูปภาพจริงแล้ว หากไม่มีรูปภาพเก่าที่ต้องการกู้คืน คุณสามารถลองใช้รูปภาพโดเมนสาธารณะนี้ที่ดึงมาจากเว็บไซต์หอสมุดรัฐสภา

f0fc83a81e88052a.png

นี่คือลิงก์โดยตรงไปยังภาพถ่ายเพื่อส่งไปยังโฟลว์: https://tile.loc.gov/storage-services/service/pnp/fsa/8c01000/8c01700/8c01765v.jpg

export IMAGE_URL="https://tile.loc.gov/storage-services/service/pnp/fsa/8c01000/8c01700/8c01765v.jpg"
go run main.go --url $IMAGE_URL

และนี่คือเอาต์พุตที่กู้คืนและใส่สี

5ed7bfcf6d26313c.png

สำเร็จ!

6. การติดตั้งใช้งาน glowUp เป็นบริการบนเว็บ

หากต้องการแสดงโฟลว์ในบริการเว็บแทนที่จะเป็นแอปพลิเคชันบรรทัดคำสั่ง Genkit มีวิธีที่สะดวกในการแปลงโฟลว์เป็นปลายทางโดยใช้genkit.Handlerอะแดปเตอร์ โค้ดด้านล่างจะลงทะเบียนโฟลว์ glowUp เป็นปลายทาง glowUp โดยใช้ genkit.Handler

คุณสามารถเปิดเผยฟังก์ชันเหล่านี้ด้วยเซิร์ฟเวอร์ HTTP ปกติได้ตามปกติโดยใช้แพ็กเกจ http จากไลบรารีมาตรฐาน แต่ Genkit ยังมีปลั๊กอิน server ที่ช่วยจัดการโค้ดมาตรฐานของเซิร์ฟเวอร์ที่พบบ่อยบางส่วน เช่น การจัดการสัญญาณปิดระบบอย่างราบรื่น

แทนที่เนื้อหาของ main.go ด้วยโค้ดด้านล่างเพื่อสร้างเว็บเซิร์ฟเวอร์

package main

import (
        "context"
        "errors"
        "fmt"
        "log"
        "net/http"
        "os"

        "github.com/firebase/genkit/go/ai"
        "github.com/firebase/genkit/go/genkit"
        "github.com/firebase/genkit/go/plugins/googlegenai"
        "github.com/firebase/genkit/go/plugins/server"
)

func main() {
        ctx := context.Background()

        PORT := os.Getenv("PORT")
        if PORT == "" {
                PORT = "8080"
        }

        listenAddr := ":" + PORT

        // Initialize Genkit with the Vertex AI plugin
        g := genkit.Init(ctx,
                genkit.WithPlugins(&googlegenai.VertexAI{}),
        )

        // Input schema for the glowUp flow
        type Input struct {
                URL         string `json:"url,omitempty"`
                ContentType string `json:"contentType,omitempty"`
        }

        genkit.DefineFlow(g, "glowUp", func(ctx context.Context, input Input) (string, error) {
                prompt := genkit.LookupPrompt(g, "glowup")
                if prompt == nil {
                        return "", errors.New("prompt 'glowup' not found")
                }

                resp, err := prompt.Execute(ctx, ai.WithInput(input))
                if err != nil {
                        return "", fmt.Errorf("generation failed: %w", err)
                }

                return resp.Media(), nil
        })

        log.Printf("GlowUp Flow Server started. Listening on %s", listenAddr)
        mux := http.NewServeMux()
        for _, flow := range genkit.ListFlows(g) {
                mux.HandleFunc("POST /"+flow.Name(), genkit.Handler(flow))
        }

        if err := server.Start(ctx, listenAddr, mux); err != nil {
                // Check if the error is due to context cancellation
                if ctx.Err() != nil {
                        log.Println("GlowUp server shutting down gracefully...")
                        return
                }
                log.Fatal(err)
        }
}

คุณจะเรียกใช้บริการนี้ในเครื่องหรือในระบบคลาวด์ก็ได้ หากต้องการเรียกใช้ในเครื่อง คุณเพียงแค่เรียกใช้ไฟล์โดยตรงเนื่องจากตอนนี้โปรแกรมเสร็จสมบูรณ์แล้ว เราจึงไม่จำเป็นต้องเปิดใช้ผ่าน Genkit CLI เช่น

go run main.go

เนื่องจากเป็นการดำเนินการที่บล็อก คุณจึงต้องเปิดเทอร์มินัลที่ 2 เพื่อทดสอบ วิธีที่เร็วที่สุดคือการใช้คำสั่ง curl

curl -sS -X POST http://localhost:8080/glowUp \
     -H "Content-Type: application/json" \
     -d '{"data":{"url": $IMAGE_URL, "contentType":"image/jpeg"}}' \
     > result.json

เนื่องจากนี่คือการตอบกลับของเซิร์ฟเวอร์ เราจึงต้องถอดรหัสรูปภาพ Base64 ดังนี้

cat result.json | jq -r '.result' | awk -F ',' '{print $2}' | base64 -d > restored.png

ติดตั้งใช้งานเว็บเซอร์วิสใน Cloud Run

แม้ว่าเซิร์ฟเวอร์นี้จะ "ทำงานในเครื่องของฉัน" ได้ แต่ในอุดมคติแล้ว เราควรจะติดตั้งใช้งานเซิร์ฟเวอร์นี้ที่อื่นซึ่งผู้ใช้ทุกคนเข้าถึงได้ วิธีที่สะดวกที่สุดวิธีหนึ่งในการทำให้บริการเช่นนี้ใช้งานได้คือการใช้ฟีเจอร์การทำให้ใช้งานได้จากแหล่งข้อมูลของ Cloud Run ฟีเจอร์นี้ช่วยให้คุณไม่ต้องสร้างคอนเทนเนอร์ด้วยตนเอง เนื่องจากทุกอย่างเป็นแบบอัตโนมัติ

หากต้องการทำให้บริการนี้ใช้งานได้ใน Cloud Run โดยใช้การทำให้ใช้งานได้จากแหล่งที่มา ให้เรียกใช้คำสั่งต่อไปนี้ (แทนที่รหัสโปรเจ็กต์ด้วยรหัสของคุณเอง)

gcloud run deploy glowup --source . --region us-central1 --no-allow-unauthenticated --set-env-vars GOOGLE_GENAI_USE_VERTEXAI=True,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT

การติดตั้งใช้งานอาจใช้เวลาสักครู่จึงจะเสร็จสมบูรณ์ เมื่อเสร็จแล้ว คุณสามารถทดสอบปลายทางได้โดยส่งคำขออีกรายการผ่าน curl ดังนี้

GLOWUP_URL=$(gcloud run services describe glowup --region us-central1 --format='value(status.url)')

curl -X POST "$GLOWUP_URL/glowUp" \
     -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
     -H "Content-Type: application/json" \
     -d "{\"data\":{\"url\":\"$IMAGE_URL\", \"contentType\":\"image/jpeg\"} }" \
     > result.json

อีกครั้ง เราต้องถอดรหัสรูปภาพ Base64:

cat result.json | jq -r '.result' | awk -F ',' '{print $2}' | base64 -d > restored_cloudrun.png

ตอนนี้เรามีเว็บเซิร์ฟเวอร์กู้คืนรูปภาพที่ใช้งานได้อย่างเต็มรูปแบบแล้ว

ไม่บังคับ: "Vibe Coding" แอปพลิเคชันไคลเอ็นต์

การเขียนโค้ดด้วยตนเองเป็นเรื่องสนุก แต่ก็อาจเป็นเรื่องท้าทายได้เช่นกันหากคุณไม่เคยทำโปรเจ็กต์บางประเภทมาก่อน โชคดีที่ปัจจุบันเรามี Agent การเขียนโค้ดที่ช่วยเร่งกระบวนการนี้ได้

ในขั้นตอนนี้ เราจะขอให้ Gemini CLI (หรือเอเจนต์การเขียนโค้ดที่คุณชื่นชอบ) ทำงานให้เราแทนที่จะเขียนโค้ดเอง ใช้พรอมต์ต่อไปนี้

GlowUp is a photo restoration service that takes a restoration request as input and returns a restored picture as output. Your task is to create a client application that uses this server to process image urls and save a restored file locally.

TODO:
- Write a CLI application that receives three arguments: an url (required), content type (optional, defaults to image/jpeg) and addr (server address, optional, defaults to localhost:8080)
- The CLI should send a POST request to the /glowUp endpoint in the server with the body '{"data":{"url": <url>, "contentType": <contentType>} }'
- The server response should be parsed by stripping the "data:" prefix. The remainder will have the format <mimeType>;base64,<encoded imageData>
- Extract the mime type and convert to a file extension using the mime package
- Extract the image data and decode it using the base64 package
Save a file named "restored" + the detected file extension

Acceptance Criteria:
- The client builds successfully
- Use the client to restore the image https://tile.loc.gov/storage-services/service/pnp/fsa/8c01000/8c01700/8c01765v.jpg
- Check that restored.png exists after processing the image above

ตัวแทนอาจต้องจัดระเบียบไฟล์ใหม่เล็กน้อยเนื่องจากเราไม่สามารถมีฟังก์ชัน "main" 2 รายการในโมดูลเดียวกันได้ ดูการทำงานของโมเดลและชี้นำให้ไปสู่การติดตั้งใช้งานที่ถูกต้องโดยให้โค้ดหรือข้อมูลโค้ดฝั่งเซิร์ฟเวอร์หากจำเป็น

การทำความสะอาดหลังการทดลอง

7. บทสรุป

ยินดีด้วย คุณสร้างแอปการคืนค่ารูปภาพที่มีความเที่ยงตรงสูงโดยใช้ Genkit และ Nano Banana Pro ได้สำเร็จแล้ว

ในโค้ดแล็บนี้ คุณได้เรียนรู้วิธีทำสิ่งต่อไปนี้

  • กำหนดค่าสภาพแวดล้อมเพื่อพัฒนาแอปพลิเคชัน Genkit Go
  • สร้างพรอมต์แบบมัลติโมดัลด้วย dotprompt
  • สร้างโฟลว์ Genkit โดยใช้เทมเพลตพรอมต์
  • ใช้ Nano Banana Pro เพื่อประมวลผลรูปภาพ
  • แพ็กเกจโฟลว์ Genkit เป็นแอปพลิเคชันบรรทัดคำสั่งและบริการบนเว็บ
  • ทำให้แอปพลิเคชัน Genkit ใช้งานได้กับ Cloud Run

เมื่อทดสอบเสร็จแล้ว อย่าลืมทำความสะอาดสภาพแวดล้อม

ขั้นตอนถัดไป

คุณสามารถเรียนรู้ต่อไปได้โดยสำรวจ Codelab อื่นๆ ในแพลตฟอร์มนี้ หรือปรับปรุง GlowUp ด้วยตนเอง

หากต้องการไอเดียในการปรับปรุง ลองทำสิ่งต่อไปนี้

  • เปิดใช้ glowUp CLI เพื่อกู้คืนไฟล์ในเครื่อง
  • สร้างฟรอนท์เอนด์สำหรับบริการเว็บ GlowUp
  • ตรวจหาประเภท MIME จากข้อมูลโดยอัตโนมัติ
  • ดำเนินการประมวลผลรูปภาพประเภทอื่นๆ (จากรูปภาพเป็นภาพวาด จากภาพวาดเป็นรูปภาพ จากภาพร่างเป็นภาพสุดท้าย ฯลฯ
  • สร้างหรือปรับปรุงไคลเอ็นต์ (อาจสร้างแอปสมาร์ทโฟน)

ทุกอย่างเป็นไปได้ หากรู้สึกว่าการเขียนโค้ดด้วยตัวเองเป็นเรื่องยาก คุณสามารถขอความช่วยเหลือจากเอเจนต์การเขียนโค้ด เช่น Gemini CLI หรือ Antigravity ได้เสมอ และหากต้องการทำสิ่งต่างๆ เพิ่มเติมด้วย Genkit การจับคู่เอเจนต์การเขียนโค้ดกับเซิร์ฟเวอร์ MCP ของ Genkit จะช่วยให้ชีวิตของคุณง่ายขึ้นมาก

สุดท้ายนี้ หากต้องการเข้าถึงโค้ดทั้งหมดสำหรับที่เก็บนี้ คุณจะดูได้ที่นี่

ขอให้สนุกกับการเขียนโค้ด