Tworzenie aplikacji do przywracania zdjęć za pomocą Genkit Go i Nano Banana Pro

1. Wprowadzenie

W tym ćwiczeniu utworzymy GlowUp, czyli narzędzie do przywracania zdjęć. GlowUp wykorzystuje AI do przywracania starych, uszkodzonych lub czarno-białych zdjęć, tworząc wysokiej jakości kolorowe obrazy w rozdzielczości 4K. Możesz użyć tego narzędzia, aby odnowić stare rodzinne fotografie, a nawet przywrócić uszkodzone ilustracje, rysunki, obrazy lub inne formy obrazów.

Do wdrożenia logiki aplikacji użyjesz Genkit Go, a do przetwarzania zdjęć – modelu Gemini 3 Pro Image (znanego też jako Nano Banana Pro).

Wymagania wstępne

  • Podstawowa wiedza o języku programowania Go
  • Podstawowa znajomość konsoli Google Cloud

Czego się nauczysz

  • Jak tworzyć aplikacje Genkit w Go
  • podstawowe pojęcia związane z Genkit, takie jak automatyzacje, wtyczki i prompty;
  • Jak pisać prompty z użyciem szablonów Handlebars
  • Jak uzyskać dane obrazu z odpowiedzi modelu

Czego potrzebujesz

Te warsztaty można w całości przeprowadzić w Google Cloud Shell, które ma wstępnie zainstalowane wszystkie niezbędne zależności (gcloud CLI, edytor kodu, Go, interfejs wiersza poleceń Gemini).

Możesz też pracować na własnym urządzeniu. W tym celu potrzebujesz:

  • łańcuch narzędzi Go (wersja 1.24 lub nowsza),
  • Node.js w wersji 20 lub nowszej (w przypadku interfejsu genkit CLI)
  • terminal z zainstalowanym interfejsem wiersza poleceń gcloud,
  • IDE do edytowania kodu, np. VS Code lub podobne
  • Zalecane: agent do kodowania, np. interfejs wiersza poleceń Gemini lub Antigravity.

Kluczowe technologie

Więcej informacji o technologiach, z których będziemy korzystać, znajdziesz tutaj:

  • Gemini Nano Banana Pro (Gemini 3 Pro Image): model, który obsługuje nasz proces przywracania
  • Genkit Go: nasz zestaw narzędzi do koordynowania wywołań modeli

2. Konfiguracja środowiska

Wybierz jedną z tych opcji: Self-paced environment setup (Konfiguracja środowiska we własnym tempie), jeśli chcesz uruchomić ten przewodnik na własnym komputerze, lub Start Cloud Shell (Uruchom Cloud Shell), jeśli chcesz uruchomić go w całości w chmurze.

Samodzielne konfigurowanie środowiska

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Zawsze możesz ją zaktualizować.
  • Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić po ustawieniu. Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się tym przejmować. W większości ćwiczeń z programowania musisz odwoływać się do identyfikatora projektu (zwykle oznaczanego jako PROJECT_ID). Jeśli wygenerowany identyfikator Ci się nie podoba, możesz wygenerować inny losowy identyfikator. Możesz też spróbować własnej nazwy i sprawdzić, czy jest dostępna. Po tym kroku nie można go zmienić i pozostaje on taki przez cały czas trwania projektu.
  • Warto wiedzieć, że istnieje też trzecia wartość, numer projektu, której używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
  1. Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Wykonanie tego laboratorium nie będzie kosztować dużo, a może nawet nic. Aby wyłączyć zasoby i uniknąć naliczania opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub projekt. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

Uruchamianie Cloud Shell

Z Google Cloud można korzystać zdalnie na laptopie, ale w tym module praktycznym będziesz używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.

W konsoli Google Cloud kliknij ikonę Cloud Shell na pasku narzędzi w prawym górnym rogu:

Aktywowanie Cloud Shell

Uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil. Po zakończeniu powinno wyświetlić się coś takiego:

Zrzut ekranu terminala Google Cloud Shell pokazujący, że środowisko zostało połączone

Ta maszyna wirtualna zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Wszystkie zadania w tym laboratorium możesz wykonać w przeglądarce. Nie musisz niczego instalować.

3. Konfiguracja projektu

Tworzenie projektu

Najpierw musimy utworzyć nowy katalog projektu i zainicjować moduł Go. W terminalu uruchom te polecenia:

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

Instalowanie interfejsu wiersza poleceń Genkit

Teraz musimy zainstalować interfejs wiersza poleceń Genkit. Dzięki temu uzyskasz dostęp do lokalnych narzędzi dla programistów, w tym interfejsu programisty. W oknie terminala wpisz:

curl -sL cli.genkit.dev | bash

Konfigurowanie zmiennych środowiskowych

Sprawdź, czy masz prawidłowo skonfigurowane dane logowania do Google Cloud. Zastąp your-project-id rzeczywistym identyfikatorem projektu. Lokalizacja musi być global, gdy używasz modeli Gemini 3 Pro w wersji testowej (jednym z nich jest Nano Banana Pro).

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

Aby włączyć interfejs Vertex AI API, uruchom to polecenie w trybie powłoki:

gcloud services enable aiplatform.googleapis.com

Jeśli uruchamiasz polecenie na komputerze lokalnym (nie w Cloud Shell), musisz uwierzytelnić się za pomocą polecenia gcloud:

gcloud auth application-default login

4. Tworzenie pierwszej aplikacji Genkit

Genkit to platforma open source, która pomaga programistom tworzyć, wdrażać i monitorować gotowe do użycia w środowisku produkcyjnym aplikacje oparte na AI. W tej sekcji utworzymy prostą aplikację „Hello World”, aby pomóc Ci zapoznać się z platformą, zanim przejdziemy do logiki przywracania zdjęć.

Terminologia Genkit

Zanim zaczniesz korzystać z Genkit, warto poznać kilka kluczowych terminów:

  • Wtyczki: służą do rozszerzania możliwości Genkit. Za pomocą wtyczek możesz m.in. rejestrować modele AI, które będą obsługiwać Twoją aplikację.
  • Przepływy:główny element architektury Genkit. Typowy przepływ pracy polega na przyjęciu danych wejściowych, ich przetworzeniu i zwróceniu danych wyjściowych. Nie wymaga to koniecznie użycia modelu, ale w większości przypadków będziesz używać modeli w swoich przepływach.
  • Prompty: szablony interakcji zapisane w formacie dotprompt (zapisane jako pliki *.prompt). Zawierają one nie tylko instrukcje dotyczące modelu, ale także konfiguracje, takie jak nazwa modelu, parametry modelu, dane wejściowe i wyjściowe.

Nawiązywanie połączenia z modelami AI

Genkit używa wtyczek do łączenia kodu z dostawcami modeli. Dostępne są wtyczki do wszystkich głównych dostawców modeli, w tym Google, Anthropic i OpenAI. Możesz też używać wtyczek do łączenia się z modelami lokalnymi (np. za pomocą Ollamy) lub do rozszerzania możliwości Genkitu (np. łączenia się z serwerami MCP).

Aby uzyskać dostęp do modeli Google, użyj wtyczki googlegenai. Obsługuje 2 backendy:

  • Google AI: najlepsze do prototypowania. Używa klucza interfejsu API.
  • Vertex AI (Google Cloud): zalecana w środowiskach produkcyjnych. Korzysta z identyfikatora projektu i lokalizacji.

W tym ćwiczeniu w Codelabs użyjemy uwierzytelniania Vertex AI, odwołując się do projektu utworzonego na początku tego modułu.

Tworzenie przepływu powitania

Zanim zagłębimy się w proces przywracania zdjęć za pomocą funkcji Glow Up, zbudujmy podstawowy proces, aby zapoznać się z koncepcjami i upewnić się, że nasza konfiguracja działa prawidłowo.

Przepływ to specjalna funkcja Genkit, która otacza logikę AI, aby zapewnić:

  • Bezpieczne pod względem typów dane wejściowe i wyjściowe: definiuj schematy za pomocą struktur Go na potrzeby weryfikacji statycznej i w czasie działania.
  • Obsługa strumieniowania: strumieniowanie częściowych odpowiedzi lub danych niestandardowych
  • Integracja z interfejsem programisty: testowanie i debugowanie przepływów za pomocą śladów wizualnych.
  • Łatwe wdrażanie: wdrażaj jako punkty końcowe HTTP na dowolnej platformie.

Otwórz IDE i utwórz plik main.go w katalogu projektu. Jeśli używasz Cloud Shell, możesz użyć tego polecenia:

cloudshell edit main.go

Następnie dodaj ten kod:

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

Zapisz plik, a potem uruchom polecenie go mod tidy, aby zaktualizować zależności:

go mod tidy

Powyższy kod inicjuje Genkit za pomocą wtyczki VertexAI, definiuje przepływ o nazwie „greeter”, a następnie czeka w nieskończoność na <-ctx.Done(). Wstrzymujemy wykonanie, aby program nie zakończył się od razu, ponieważ nie podajemy mu żadnych instrukcji dotyczących wykonania przepływu.

Oznacza to, że jeśli uruchomisz ten program w obecnej postaci, nie będzie on działać samodzielnie – musimy jakoś wywołać przepływ. W prawdziwej aplikacji produkcyjnej ten przepływ umieścilibyśmy w serwerze WWW lub aplikacji CLI, ale podczas programowania możemy użyć interfejsu wiersza poleceń genkit, aby ułatwić sobie tworzenie i optymalizację przepływu.

genkit CLI zostało opracowane, aby pomóc nam testować modele, prompty, przepływy i inne komponenty stosu Genkit. Ma też pełną obsługę śladów, co jest bardzo wygodne, gdy chcesz zrozumieć, jak aplikacja działa w tle. Aby uruchomić przepływ powitalny za pomocą interfejsu wiersza poleceń genkit, uruchom to polecenie:

genkit start -- go run main.go

Spowoduje to uruchomienie interfejsu Telemetry API i punktów końcowych interfejsu deweloperskiego. Powinien pojawić się ekran podobny do tego:

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

Jeśli otworzysz localhost:4000 w przeglądarce, aby uruchomić interfejs Dev-UI. Powinien pojawić się ekran podobny do tego:

93d9bd9e1bd6627d.png

Poświęć trochę czasu na zapoznanie się z interfejsem programisty. Możesz uruchomić automatyzację „powitania” tylko raz, aby sprawdzić, jak działa.

Korzystanie z szablonów promptów

Możesz wprawdzie zakodować na stałe prompty w wywołaniach modelu, tak jak w poprzednim przykładzie, ale lepszym rozwiązaniem byłoby utworzenie szablonów promptów, aby przechowywać wszystkie prompty aplikacji w jednym miejscu. Ułatwia to nie tylko znajdowanie ich podczas konserwacji kodu, ale też pozwala eksperymentować z promptami niezależnie od przepływów.

Do definiowania szablonów promptów Genkit używa formatu open source dotprompt, który jest zapisywany jako pliki *.prompt. Plik .prompt składa się z 2 części:

  1. Wstęp: blok YAML, który definiuje model, parametry modelu oraz schematy wejściowe i wyjściowe.
  2. Treść: treść promptu, którą można szablonować za pomocą składni „handlebars”. Jeśli na przykład zdefiniujesz dane wejściowe o nazwie variable-name, możesz się do nich odwołać w treści jako {{variable-name}}.

Struktura katalogów projektu będzie wyglądać tak:

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

Zobaczmy, jak to wygląda w praktyce. Najpierw utwórz folder, w którym będziesz przechowywać prompty:

mkdir -p prompts

Następnie utwórz plik greeter.prompt:

cloudshell edit prompts/greeter.prompt

Wstaw tę treść:

greeter.prompt

ec9fc82a98604123.png

Ten prompt prezentuje kilka funkcji języka szablonu. Najpierw w nagłówku określamy model vertexai/gemini-2.5-flash. Aby określić model, musisz użyć nazewnictwa zdefiniowanego w dokumentacji odpowiedniej wtyczki.

Sekcja konfiguracji umożliwia skonfigurowanie parametrów modelu. Używamy temperatury 1,9, aby model mógł być bardziej kreatywny. Temperatura mieści się w zakresie od 0 (bardziej spójne wyniki) do 2 (bardziej kreatywne wyniki). Te i inne parametry modelu są zwykle publikowane w karcie modelu. Oto na przykład karta modelu gemini-2.5-flash.

W sekcji danych wejściowych możemy określić argumenty promptu. W tym przypadku definiujemy nazwę jako ciąg znaków. Po wstępie znajduje się treść promptu. Pierwszy blok zawiera prompt systemowy, a drugi – prompt użytkownika. Wszystkie te elementy razem umożliwiają stosowanie bardzo skutecznych technik promptowania. Pełną dokumentację znajdziesz dotprompt tutaj.

Teraz dostosujmy greeter, aby używać utworzonego prompta:

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

Spróbuj uruchomić przepływ z poziomu wiersza poleceń z nazwą i bez niej, aby zobaczyć różnicę. Uruchamianie bez nazwy:

genkit flow:run greeter

Przykładowe dane wyjściowe:

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

Z nazwą:

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

Przykładowe dane wyjściowe:

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

Widzisz, że szablon działa zgodnie z oczekiwaniami. Jesteśmy gotowi, aby przenieść ten projekt na wyższy poziom.

5. Przywracanie obrazów za pomocą Nano Banana Pro

The Restoration Prompt

Znasz już podstawowe elementy Genkit. Czas utworzyć prompt do przywracania zdjęć.

W katalogu prompts utwórz plik o nazwie glowup.prompt i wklej do niego tę zawartość:

glowup.prompt

fd0f1551466c8138.png

Prompt przywracania ma taki sam wzór jak prompt „powitalny”, ale z kilkoma istotnymi różnicami:

  • Rozmiar obrazu: właściwość imageSize parametru imageConfig jest parametrem Nano Banana Pro, który jest specyficzny dla tego modelu. Umożliwia określenie rozmiaru wyjściowego jako 1K, 2K lub 4K.
  • Dane wejściowe multimediów: używamy szablonu {{ media }}, aby wstawić zdjęcie do prompta użytkownika. Ta technika umożliwia wysyłanie do modelu promptów multimodalnych (tekst + obraz).

Możesz przetestować ten prompt w interfejsie programisty. Możesz go dostosować, aby sprawdzić, jak wpłynie to na wynik.

Proces przywracania obrazu

Gdy prompt przywracania będzie gotowy, możemy utworzyć aplikację CLI. Zastąp zawartość pliku main.go poniższym kodem:

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
}

Struktura kodu jest bardzo podobna do struktury przepływu greeter, ale tym razem jest on dostosowany do działania jako samodzielna aplikacja CLI. Zamiast blokować na zawsze, uruchomi przepływ glowUp, zdekoduje dane wyjściowe i zapisze wynikowe dane binarne na dysku.

Musimy zdekodować dane wyjściowe, ponieważ model zwraca dane obrazu w tym formacie:

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

W funkcji decode widać, że używamy operacji na ciągach znaków, aby podzielić typ MIME i zakodowane części obrazu. Następnie używamy funkcji mime.ExtensionByTypebase64.DecodeString, aby wyodrębnić informacje potrzebne do zapisania pliku.

Testowanie procesu przywracania

Teraz możesz wreszcie uruchomić ten proces z prawdziwym zdjęciem. Jeśli nie masz pod ręką starych zdjęć, które wymagają odnowienia, możesz spróbować z tym zdjęciem z domeny publicznej pobranym ze strony Biblioteki Kongresu:

f0fc83a81e88052a.png

Oto bezpośredni link do zdjęcia, który możesz przekazać do przepływu: 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

A oto odrestaurowane i pokolorowane dane wyjściowe:

5ed7bfcf6d26313c.png

Gotowe!

6. Wdrażanie glowUp jako usługi sieciowej

Jeśli zamiast aplikacji wiersza poleceń chcesz udostępniać przepływy w usłudze internetowej, Genkit zapewnia wygodny sposób przekształcania przepływów w punkty końcowe za pomocą genkit.Handler adaptera. Poniższy kod rejestruje przepływ glowUp jako punkt końcowy glowUp za pomocą genkit.Handler.

Możesz je udostępniać za pomocą zwykłego serwera HTTP, tak jak zwykle, używając pakietu http z biblioteki standardowej, ale Genkit udostępnia też wtyczkę server, która pomaga w niektórych typowych zadaniach związanych z serwerem, takich jak prawidłowe obsługiwanie sygnałów wyłączania.

Aby utworzyć serwer WWW, zastąp zawartość pliku main.go poniższym kodem.

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

Możesz uruchomić tę usługę lokalnie lub w chmurze. Aby uruchomić go lokalnie, możesz po prostu uruchomić plik bezpośrednio, ponieważ program jest już gotowy, więc nie musisz go uruchamiać za pomocą interfejsu Genkit CLI. Na przykład:

go run main.go

Jest to operacja blokująca, więc aby ją przetestować, musisz uruchomić drugi terminal. Najszybszym sposobem jest użycie polecenia curl:

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

Ponieważ jest to odpowiedź serwera, musimy zdekodować obraz w formacie base64:

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

Wdrażanie usługi internetowej w Cloud Run

To, że serwer „działa na moim komputerze”, jest w porządku, ale w idealnym świecie wdrożylibyśmy go gdzieś indziej, aby był dostępny dla wszystkich naszych użytkowników. Jednym z najwygodniejszych sposobów wdrażania takich usług jest korzystanie z funkcji wdrażania z kodu źródłowego w Cloud Run. Dzięki tej funkcji nie musisz nawet samodzielnie tworzyć kontenera, ponieważ wszystko jest zautomatyzowane.

Aby wdrożyć tę usługę w Cloud Run za pomocą wdrożenia ze źródła, wykonaj to polecenie (zastąp identyfikator projektu własnym):

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

Wdrożenie może potrwać kilka minut. Gdy skończysz, możesz przetestować punkt końcowy, wysyłając kolejne żądanie za pomocą 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

Ponownie musimy zdekodować obraz w formacie Base64:

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

Mamy już w pełni działający serwer WWW do przywracania zdjęć.

Opcjonalnie: „vibe coding” aplikacji klienta

Pisanie kodu ręcznie jest ciekawe, ale może być też trudne, jeśli nigdy wcześniej nie wykonywałeś(-aś) określonego typu projektu. Na szczęście mamy teraz agentów kodowania, którzy mogą przyspieszyć ten proces.

W tym kroku zamiast pisać kod samodzielnie poprosimy o to interfejs wiersza poleceń Gemini (lub innego ulubionego agenta do kodowania). Użyj tego prompta:

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

Agent może potrzebować nieco zmienić organizację plików, ponieważ w tym samym module nie mogą znajdować się 2 funkcje „main”. Obserwuj jego działanie i kieruj go w stronę właściwego wdrożenia, podając w razie potrzeby kod serwera lub fragmenty kodu.

Sprzątanie po zakończeniu modułu

7. Podsumowanie

Gratulacje! Udało Ci się utworzyć aplikację do przywracania zdjęć w wysokiej jakości za pomocą Genkit i Nano Banana Pro.

Z tego modułu dowiedzieliśmy się, jak:

  • Konfigurowanie środowiska do tworzenia aplikacji Genkit Go
  • Tworzenie promptów multimodalnych za pomocą dotprompt
  • Tworzenie przepływów Genkit za pomocą szablonów promptów
  • Przetwarzanie obrazów za pomocą Nano Banana Pro
  • Pakowanie przepływów Genkit jako aplikacji wiersza poleceń i usług internetowych
  • Wdrażanie aplikacji Genkit w Cloud Run

Po zakończeniu testowania pamiętaj o zwolnieniu miejsca w środowisku.

Dalsze kroki

Możesz kontynuować naukę, przeglądając inne codelaby na tej platformie lub samodzielnie ulepszając aplikację glowUp.

Jeśli potrzebujesz pomysłów na ulepszenia, możesz spróbować:

  • Włącz interfejs wiersza poleceń glowUp, aby przywrócić pliki lokalne
  • Tworzenie frontendu usługi internetowej GlowUp
  • Automatyczne wykrywanie typu MIME na podstawie danych
  • wykonywać inne rodzaje przetwarzania obrazów (np. przekształcanie zdjęcia w rysunek, rysunku w zdjęcie, szkicu w gotową grafikę itp.);
  • utworzyć lub ulepszyć klienta (może stworzyć aplikację na smartfona?),

Możliwości są nieograniczone. Jeśli pomysł samodzielnego tworzenia kodu Cię przeraża, zawsze możesz skorzystać z pomocy agenta do kodowania, takiego jak interfejs wiersza poleceń Gemini lub Antigravity. Jeśli chcesz robić więcej za pomocą Genkit, kodowanie agentów w połączeniu z serwerem Genkit MCP może znacznie ułatwić Ci pracę.

Pełny kod tego repozytorium znajdziesz tutaj.

Pozdrawiamy