Xây dựng ứng dụng khôi phục ảnh bằng Genkit Go và Nano Banana Pro

1. Giới thiệu

Trong lớp học lập trình này, chúng ta sẽ tạo GlowUp, một công cụ khôi phục ảnh. GlowUp sử dụng AI để khôi phục ảnh cũ, ảnh bị hỏng hoặc ảnh đen trắng, tạo ra những bức ảnh màu 4K chất lượng cao. Bạn có thể dùng công cụ này để làm mới ảnh gia đình, hoặc thậm chí điều chỉnh để khôi phục hình minh hoạ, bản vẽ, tranh vẽ hoặc các dạng hình ảnh khác bị hư hỏng.

Bạn sẽ sử dụng Genkit Go để triển khai logic ứng dụng và Gemini 3 Pro Image (còn gọi là Nano Banana Pro) làm mô hình xử lý ảnh.

Điều kiện tiên quyết

  • Kiến thức cơ bản về ngôn ngữ lập trình Go
  • Kiến thức cơ bản về bảng điều khiển Cloud

Kiến thức bạn sẽ học được

  • Cách phát triển các ứng dụng Genkit bằng Go
  • Các khái niệm cơ bản về Genkit như luồng, trình bổ trợ và câu lệnh
  • Cách viết câu lệnh bằng mẫu handlebar
  • Cách lấy dữ liệu hình ảnh từ câu trả lời của mô hình

Bạn cần có

Bạn có thể hoàn thành toàn bộ hội thảo này trong Google Cloud Shell. Công cụ này đi kèm với tất cả các phần phụ thuộc cần thiết (gcloud CLI, trình soạn thảo mã, Go, Gemini CLI) đã được cài đặt sẵn.

Ngoài ra, nếu muốn làm việc trên máy của riêng mình, bạn sẽ cần những thứ sau:

  • Chuỗi công cụ Go (phiên bản 1.24 trở lên)
  • Node.js phiên bản 20 trở lên (đối với giao diện dòng lệnh genkit)
  • Một thiết bị đầu cuối đã cài đặt CLI gcloud
  • Một IDE để chỉnh sửa mã của bạn, chẳng hạn như VS Code hoặc các IDE tương tự
  • Đề xuất: một tác nhân lập trình như Gemini CLI hoặc Antigravity

Công nghệ chính

Tại đây, bạn có thể tìm thêm thông tin về các công nghệ mà chúng tôi sẽ sử dụng:

  • Gemini Nano Banana Pro (Hình ảnh Gemini 3 Pro): mô hình hỗ trợ quy trình khôi phục của chúng tôi
  • Genkit Go: bộ công cụ của chúng tôi để điều phối các lệnh gọi mô hình

2. Thiết lập môi trường

Chọn một trong các lựa chọn sau: Thiết lập môi trường tự học nếu bạn muốn chạy lớp học lập trình này trên máy của riêng mình, hoặc Bắt đầu Cloud Shell nếu bạn muốn chạy lớp học lập trình này hoàn toàn trên đám mây.

Thiết lập môi trường theo tốc độ của riêng bạn

  1. Đăng nhập vào Google Cloud Console rồi tạo một dự án mới hoặc sử dụng lại một dự án hiện có. Nếu chưa có tài khoản Gmail hoặc Google Workspace, bạn phải tạo một tài khoản.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Tên dự án là tên hiển thị của những người tham gia dự án này. Đây là một chuỗi ký tự mà các API của Google không sử dụng. Bạn luôn có thể cập nhật thông tin này.
  • Mã dự án là mã duy nhất trên tất cả các dự án trên Google Cloud và không thể thay đổi (bạn không thể thay đổi mã này sau khi đã đặt). Cloud Console sẽ tự động tạo một chuỗi duy nhất; thường thì bạn không cần quan tâm đến chuỗi này. Trong hầu hết các lớp học lập trình, bạn sẽ cần tham chiếu đến Mã dự án (thường được xác định là PROJECT_ID). Nếu không thích mã nhận dạng được tạo, bạn có thể tạo một mã nhận dạng ngẫu nhiên khác. Hoặc bạn có thể thử tên người dùng của riêng mình để xem tên đó có được chấp nhận hay không. Bạn không thể thay đổi tên này sau bước này và tên này sẽ tồn tại trong suốt thời gian của dự án.
  • Để bạn nắm được thông tin, có một giá trị thứ ba là Số dự án mà một số API sử dụng. Tìm hiểu thêm về cả 3 giá trị này trong tài liệu.
  1. Tiếp theo, bạn cần bật tính năng thanh toán trong Cloud Console để sử dụng các tài nguyên/API trên đám mây. Việc thực hiện lớp học lập trình này sẽ không tốn nhiều chi phí, nếu có. Để tắt các tài nguyên nhằm tránh bị tính phí ngoài phạm vi hướng dẫn này, bạn có thể xoá các tài nguyên đã tạo hoặc xoá dự án. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí trị giá 300 USD.

Khởi động Cloud Shell

Mặc dù có thể vận hành Google Cloud từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, bạn sẽ sử dụng Google Cloud Shell, một môi trường dòng lệnh chạy trên Cloud.

Trên Bảng điều khiển Google Cloud, hãy nhấp vào biểu tượng Cloud Shell trên thanh công cụ ở trên cùng bên phải:

Kích hoạt Cloud Shell

Quá trình này chỉ mất vài phút để cung cấp và kết nối với môi trường. Khi quá trình này kết thúc, bạn sẽ thấy như sau:

Ảnh chụp màn hình cửa sổ dòng lệnh Google Cloud Shell cho thấy môi trường đã kết nối

Máy ảo này được trang bị tất cả các công cụ phát triển mà bạn cần. Nó cung cấp một thư mục chính có dung lượng 5 GB và chạy trên Google Cloud, giúp tăng cường đáng kể hiệu suất mạng và hoạt động xác thực. Bạn có thể thực hiện mọi thao tác trong lớp học lập trình này trong trình duyệt. Bạn không cần cài đặt bất cứ thứ gì.

3. Thiết lập dự án

Tạo dự án

Trước tiên, chúng ta cần tạo một thư mục mới cho dự án và khởi động mô-đun Go. Trong cửa sổ dòng lệnh, hãy chạy các lệnh sau:

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

Cài đặt Genkit CLI

Bây giờ, chúng ta cần cài đặt Genkit CLI. Nhờ đó, bạn có thể truy cập vào các công cụ dành cho nhà phát triển tại địa phương, bao gồm cả Giao diện người dùng dành cho nhà phát triển. Trong cửa sổ dòng lệnh, hãy nhập:

curl -sL cli.genkit.dev | bash

Định cấu hình các biến môi trường

Đảm bảo bạn đã thiết lập thông tin đăng nhập chính xác cho Google Cloud. Thay thế your-project-id bằng mã dự án thực tế của bạn. Vị trí phải là global khi sử dụng các mô hình Gemini 3 Pro Preview (Nano Banana Pro là một trong số đó).

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

Chạy lệnh sau ở chế độ shell để bật Vertex AI API:

gcloud services enable aiplatform.googleapis.com

Và nếu đang chạy từ máy cục bộ (không phải trên Cloud Shell), bạn sẽ cần xác thực bằng lệnh gcloud:

gcloud auth application-default login

4. Tạo ứng dụng Genkit đầu tiên

Genkit là một khung mã nguồn mở được thiết kế để giúp các nhà phát triển xây dựng, triển khai và giám sát các ứng dụng dựa trên AI sẵn sàng cho hoạt động sản xuất. Trong phần này, chúng ta sẽ tạo một ứng dụng "Xin chào thế giới" đơn giản để giúp bạn làm quen với khung này trước khi đi sâu vào logic khôi phục ảnh.

Thuật ngữ Genkit

Trước khi bắt đầu sử dụng Genkit, bạn cần hiểu rõ một số thuật ngữ chính:

  • Trình bổ trợ: dùng để mở rộng các chức năng của Genkit. Ngoài ra, thông qua các trình bổ trợ, bạn có thể đăng ký các mô hình AI để hỗ trợ ứng dụng của mình.
  • Luồng: thành phần kiến trúc chính của Genkit. Một quy trình điển hình sẽ nhận dữ liệu đầu vào, xử lý dữ liệu đó và trả về dữ liệu đầu ra. Bạn không nhất thiết phải sử dụng mô hình, nhưng hầu hết thời gian bạn sẽ sử dụng các mô hình trong luồng của mình.
  • Câu lệnh: mẫu tương tác được lưu trữ ở định dạng dotprompt (được lưu dưới dạng tệp *.prompt). Các tệp này không chỉ chứa hướng dẫn về mô hình mà còn chứa các cấu hình như tên mô hình, tham số mô hình, dữ liệu đầu vào và đầu ra.

Kết nối với các mô hình AI

Genkit sử dụng các trình bổ trợ để kết nối mã của bạn với các nhà cung cấp mô hình. Có các trình bổ trợ cho tất cả nhà cung cấp mô hình chính, bao gồm cả Google, Anthropic và OpenAI. Bạn cũng có thể sử dụng trình bổ trợ để kết nối với các mô hình cục bộ (ví dụ: sử dụng Ollama) hoặc để mở rộng các chức năng của Genkit (ví dụ: kết nối với các máy chủ MCP).

Để truy cập vào các mô hình của Google, bạn nên sử dụng trình bổ trợ googlegenai. Thư viện này hỗ trợ 2 chương trình phụ trợ:

  • Google AI: Phù hợp nhất để tạo nguyên mẫu. Sử dụng Khoá API.
  • Vertex AI (Google Cloud): Nên dùng cho phiên bản phát hành công khai. Sử dụng mã dự án và vị trí.

Trong lớp học lập trình này, chúng ta sẽ sử dụng quy trình xác thực Vertex AI tham chiếu đến dự án mà bạn đã tạo khi bắt đầu lớp học.

Tạo quy trình chào hỏi

Trước khi tìm hiểu sâu hơn về quy trình khôi phục ảnh Glow Up, hãy tạo một quy trình cơ bản để làm quen với các khái niệm và đảm bảo rằng chế độ thiết lập của chúng ta đang hoạt động đúng cách.

Luồng là một hàm đặc biệt của Genkit, bao bọc logic AI của bạn để cung cấp:

  • Đầu vào và đầu ra an toàn về kiểu: Xác định các giản đồ bằng cách sử dụng các cấu trúc Go để xác thực tĩnh và thời gian chạy
  • Hỗ trợ truyền trực tuyến: Truyền trực tuyến các phản hồi một phần hoặc dữ liệu tuỳ chỉnh
  • Tích hợp giao diện người dùng cho nhà phát triển: Kiểm thử và gỡ lỗi các luồng bằng dấu vết trực quan
  • Dễ dàng triển khai: Triển khai dưới dạng điểm cuối HTTP cho mọi nền tảng

Mở IDE và tạo một tệp main.go trong thư mục dự án. Nếu đang dùng cloudshell, bạn có thể dùng lệnh sau:

cloudshell edit main.go

Sau đó, hãy thêm mã sau:

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()
}

Lưu tệp rồi chạy go mod tidy để cập nhật các phần phụ thuộc:

go mod tidy

Đoạn mã trên khởi chạy Genkit bằng trình bổ trợ VertexAI, xác định một luồng có tên là "greeter" rồi chờ mãi trên <-ctx.Done(). Chúng ta đang giữ việc thực thi để chương trình này không kết thúc ngay lập tức, vì chúng ta không đưa ra bất kỳ hướng dẫn nào để thực sự thực thi quy trình.

Điều này có nghĩa là nếu bạn chạy chương trình này như hiện tại, chương trình sẽ không làm gì nhiều – chúng ta cần gọi quy trình theo cách nào đó. Mặc dù trong một ứng dụng sản xuất thực tế, chúng ta sẽ gói quy trình này trong một máy chủ web hoặc ứng dụng CLI, nhưng trong thời gian phát triển, chúng ta có thể sử dụng CLI genkit để giúp chúng ta phát triển và tối ưu hoá quy trình.

CLI genkit được phát triển để giúp chúng tôi kiểm thử các mô hình, câu lệnh, luồng và các thành phần khác của ngăn xếp Genkit. Ngoài ra, công cụ này còn hỗ trợ đầy đủ các dấu vết, rất thuận tiện khi bạn muốn tìm hiểu cách ứng dụng hoạt động bên trong. Để chạy quy trình chào hỏi bằng genkit CLI, hãy chạy lệnh sau:

genkit start -- go run main.go

Thao tác này sẽ khởi động các điểm cuối Telemetry API và Giao diện người dùng dành cho nhà phát triển. Bạn sẽ thấy như sau:

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

Nếu bạn mở localhost:4000 trên trình duyệt để chạy Dev-UI. Bạn sẽ thấy một màn hình như sau:

93d9bd9e1bd6627d.png

Hãy dành thời gian khám phá Giao diện người dùng dành cho nhà phát triển. Bạn có thể kích hoạt quy trình "lời chào" một lần để xem cách hoạt động.

Sử dụng mẫu câu lệnh

Mặc dù bạn có thể mã hoá cứng các câu lệnh trong lệnh gọi mô hình như chúng ta đã làm trong ví dụ trước, nhưng cách tiếp cận hiệu quả hơn là tạo các mẫu câu lệnh để lưu trữ tất cả câu lệnh của ứng dụng theo cách tập trung. Điều này không chỉ giúp bạn dễ dàng tìm thấy các câu lệnh khi bảo trì mã mà còn cho phép bạn thử nghiệm các câu lệnh độc lập với các luồng.

Để xác định mẫu câu lệnh, Genkit sử dụng định dạng dotprompt nguồn mở, được lưu dưới dạng tệp *.prompt. Tệp .prompt bao gồm hai phần:

  1. Phần đầu: Một khối YAML xác định mô hình, các tham số mô hình và cả lược đồ đầu vào lẫn đầu ra
  2. Nội dung: Nội dung của chính câu lệnh, có thể được tạo mẫu bằng cú pháp "handlebars". Ví dụ: nếu xác định một đầu vào có tên là variable-name, bạn có thể tham chiếu đầu vào đó trong phần nội dung dưới dạng {{variable-name}}.

Cấu trúc thư mục của dự án sẽ có dạng như sau:

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

Hãy xem ví dụ thực tế. Trước tiên, hãy tạo thư mục để lưu trữ câu lệnh:

mkdir -p prompts

Sau đó, hãy tạo tệp greeter.prompt:

cloudshell edit prompts/greeter.prompt

Và chèn nội dung sau:

greeter.prompt

ec9fc82a98604123.png

Câu lệnh này minh hoạ một số tính năng của ngôn ngữ mẫu. Trước tiên, chúng ta chỉ định mô hình vertexai/gemini-2.5-flash trong phần đầu. Để chỉ định một mô hình, bạn cần sử dụng quy tắc đặt tên được xác định trong tài liệu tương ứng của trình bổ trợ.

Phần config cho phép chúng ta định cấu hình các tham số mô hình. Chúng tôi đang sử dụng nhiệt độ 1,9 để cho phép mô hình sáng tạo hơn. Nhiệt độ dao động từ 0 (kết quả nhất quán hơn) đến 2 (kết quả sáng tạo hơn). Tham số này và các tham số khác của mô hình thường được xuất bản trong bảng thông số mô hình. Ví dụ: sau đây là trang thông tin mô hình cho gemini-2.5-flash.

Phần đầu vào cho phép chúng ta chỉ định các đối số cho câu lệnh. Trong trường hợp này, chúng ta sẽ xác định tên dưới dạng một chuỗi. Sau phần nội dung giới thiệu, chúng ta có phần nội dung của câu lệnh. Khối đầu tiên ở đây xác định câu lệnh hệ thống và khối thứ hai là câu lệnh của người dùng. Tất cả những yếu tố này kết hợp với nhau tạo nên một số kỹ thuật tạo câu lệnh rất mạnh mẽ. Bạn có thể xem toàn bộ tài liệu về dotprompt tại đây.

Giờ hãy điều chỉnh luồng greeter để sử dụng câu lệnh mà chúng ta vừa tạo:

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()
}

Hãy thử chạy quy trình này từ dòng lệnh, có và không có tên để xem sự khác biệt. Chạy mà không có tên:

genkit flow:run greeter

Ví dụ về đầu ra:

$ 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!"

Và với tên:

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

Ví dụ về đầu ra:

$ 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!"

Bạn có thể thấy rằng mẫu này hoạt động như mong đợi. Chúng tôi đã sẵn sàng đưa dự án này lên một tầm cao mới!

5. Khôi phục hình ảnh bằng Nano Banana Pro

Câu lệnh khôi phục

Giờ đây, bạn đã quen thuộc với các khối xây dựng của Genkit, đã đến lúc tạo câu lệnh khôi phục ảnh.

Tạo một tệp có tên là glowup.prompt trong thư mục prompts rồi dán nội dung sau vào tệp đó:

glowup.prompt

fd0f1551466c8138.png

Lời nhắc khôi phục tuân theo cùng một mẫu như lời nhắc "chào hỏi" của chúng tôi, chỉ có một vài điểm khác biệt đáng chú ý:

  • Kích thước hình ảnh: thuộc tính imageSize của imageConfig là một tham số dành riêng cho mô hình của Nano Banana Pro. Điều này cho phép chúng ta chỉ định kích thước đầu ra là 1K, 2K hoặc 4K.
  • Đầu vào đa phương tiện: chúng tôi đang sử dụng mẫu {{ media }} để chèn ảnh vào câu lệnh của người dùng. Kỹ thuật này cho phép chúng tôi gửi câu lệnh đa phương thức đến mô hình (văn bản + hình ảnh).

Bạn có thể kiểm thử câu lệnh này trên Giao diện người dùng dành cho nhà phát triển. Bạn có thể điều chỉnh mã này để xem mã ảnh hưởng đến kết quả như thế nào.

Quy trình khôi phục hình ảnh

Khi đã chuẩn bị xong lời nhắc khôi phục, giờ hãy tạo ứng dụng CLI. Thay thế nội dung của main.go bằng đoạn mã dưới đây:

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
}

Mã này có cấu trúc rất giống với flow greeter, nhưng lần này, mã được điều chỉnh để chạy dưới dạng một ứng dụng CLI độc lập. Thay vì chặn mãi mãi, nó sẽ chạy quy trình glowUp, giải mã đầu ra và lưu dữ liệu nhị phân kết quả vào ổ đĩa.

Chúng ta cần giải mã đầu ra vì mô hình trả về dữ liệu hình ảnh ở định dạng sau:

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

Bạn có thể thấy trong hàm decode rằng chúng ta đang dùng thao tác chuỗi để phân tách loại MIME và các phần hình ảnh được mã hoá. Sau đó, chúng ta sử dụng các hàm mime.ExtensionByTypebase64.DecodeString để trích xuất thông tin cần thiết để lưu tệp.

Kiểm thử quy trình khôi phục

Bây giờ, cuối cùng đã đến lúc chạy quy trình này với một bức ảnh thực! Nếu không có ảnh cũ nào cần khôi phục, bạn có thể thử với bức ảnh thuộc phạm vi công cộng này được lấy từ trang web của Thư viện Quốc hội Hoa Kỳ:

f0fc83a81e88052a.png

Đây là đường liên kết trực tiếp đến bức ảnh để truyền vào quy trình: 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

Sau đây là kết quả đã khôi phục và tô màu:

5ed7bfcf6d26313c.png

Thành công!

6. Triển khai glowUp dưới dạng dịch vụ web

Nếu bạn muốn hiển thị các luồng của mình trong một dịch vụ web thay vì một ứng dụng dòng lệnh, thì Genkit cung cấp một cách thuận tiện để chuyển đổi các luồng thành điểm cuối bằng cách sử dụng bộ chuyển đổi genkit.Handler. Đoạn mã dưới đây đăng ký luồng glowUp làm điểm cuối glowUp bằng cách sử dụng genkit.Handler.

Bạn có thể hiển thị các hàm này bằng một máy chủ HTTP thông thường như bình thường bằng cách sử dụng gói http trong thư viện chuẩn, nhưng Genkit cũng cung cấp một trình bổ trợ server giúp xử lý một số mã chuẩn máy chủ phổ biến, chẳng hạn như xử lý tín hiệu tắt một cách an toàn.

Thay thế nội dung của main.go bằng đoạn mã bên dưới để tạo máy chủ web.

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)
        }
}

Bạn có thể chạy dịch vụ này trên máy tính hoặc trên đám mây. Để chạy cục bộ, bạn chỉ cần chạy trực tiếp tệp vì chương trình hiện đã hoàn tất, nên chúng ta không cần khởi chạy tệp thông qua CLI genkit. Ví dụ:

go run main.go

Vì đây là một thao tác chặn, bạn cần khởi chạy một thiết bị đầu cuối thứ hai để kiểm thử thao tác này. Cách nhanh nhất là sử dụng lệnh curl:

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

Vì đây là phản hồi của máy chủ nên chúng ta cần giải mã hình ảnh base64:

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

Triển khai dịch vụ web lên Cloud Run

Máy chủ này "hoạt động trên máy của tôi" là điều bình thường, nhưng trong một thế giới lý tưởng, chúng ta sẽ triển khai máy chủ này ở một nơi khác mà tất cả người dùng đều có thể truy cập. Một trong những cách thuận tiện nhất để triển khai các dịch vụ như thế này là sử dụng tính năng triển khai từ nguồn của Cloud Run. Với tính năng này, bạn thậm chí không cần tự tạo vùng chứa, mọi thứ đều được tự động hoá.

Để triển khai dịch vụ này lên Cloud Run bằng cách triển khai từ nguồn, hãy thực thi lệnh sau (thay thế mã dự án bằng mã dự án của riêng bạn):

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

Quá trình triển khai có thể mất vài phút để hoàn tất. Sau khi hoàn tất, bạn có thể kiểm thử điểm cuối bằng cách gửi một yêu cầu khác thông qua 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

Một lần nữa, chúng ta cần giải mã hình ảnh base64:

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

Giờ đây, chúng ta đã có một máy chủ web khôi phục ảnh hoạt động đầy đủ!

Không bắt buộc: "Lập trình theo cảm hứng" cho một ứng dụng khách

Viết mã theo cách thủ công là một việc thú vị nhưng cũng có thể đầy thách thức nếu bạn chưa từng thực hiện một loại dự án nào đó trước đây. May mắn thay, ngày nay chúng ta có các tác nhân lập trình có thể giúp chúng ta đẩy nhanh quá trình này.

Trong bước này, thay vì tự viết mã, chúng ta sẽ hỏi Gemini CLI (hoặc tác nhân lập trình mà bạn yêu thích) làm việc cho chúng ta. Hãy sử dụng câu lệnh sau:

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

Có thể bạn cần sắp xếp lại các tệp một chút vì chúng ta không thể có hai hàm "main" trong cùng một mô-đun. Theo dõi cách nó hoạt động và hướng dẫn nó triển khai đúng cách bằng cách cung cấp mã hoặc đoạn mã máy chủ nếu cần.

Dọn dẹp sau khi làm thí nghiệm

7. Kết luận

Xin chúc mừng! Bạn đã tạo thành công một ứng dụng khôi phục ảnh có độ trung thực cao bằng Genkit và Nano Banana Pro,

Trong lớp học lập trình này, bạn đã tìm hiểu cách:

  • Định cấu hình môi trường để phát triển các ứng dụng Genkit Go
  • Tạo câu lệnh đa phương thức bằng dotprompt
  • Tạo luồng Genkit bằng mẫu câu lệnh
  • Sử dụng Nano Banana Pro để xử lý hình ảnh
  • Đóng gói các luồng Genkit dưới dạng ứng dụng dòng lệnh và dịch vụ web
  • Triển khai các ứng dụng Genkit lên Cloud Run

Sau khi kiểm thử xong, hãy nhớ dọn dẹp môi trường.

Các bước tiếp theo

Bạn có thể tiếp tục hành trình học tập bằng cách khám phá các lớp học lập trình khác trên nền tảng này hoặc tự mình cải thiện glowUp.

Nếu cần một số ý tưởng để cải thiện, bạn có thể thử:

  • Cho phép glowUp CLI khôi phục tệp trên máy
  • Tạo giao diện người dùng cho dịch vụ web GlowUp
  • Tự động phát hiện loại MIME từ dữ liệu
  • Thực hiện các loại xử lý hình ảnh khác (từ ảnh sang bản vẽ, từ bản vẽ sang ảnh, bản phác thảo sang tác phẩm nghệ thuật hoàn chỉnh, v.v.
  • Tạo hoặc cải thiện ứng dụng khách (có thể xây dựng một ứng dụng điện thoại thông minh?)

Bạn có vô số lựa chọn! Nếu cảm thấy hơi lo lắng khi tự mình thực hiện, bạn luôn có thể nhờ đến sự trợ giúp của một tác nhân lập trình như Gemini CLI hoặc Antigravity. Nếu bạn muốn làm được nhiều việc hơn với Genkit, thì việc kết hợp các tác nhân lập trình với Máy chủ MCP của Genkit có thể giúp bạn làm việc dễ dàng hơn nhiều.

Cuối cùng, nếu muốn truy cập vào toàn bộ mã cho kho lưu trữ này, bạn có thể xem tại đây.

Chúc bạn lập trình vui vẻ!