App zur Fotorestaurierung mit Genkit Go und Nano Banana Pro erstellen

1. Einführung

In diesem Codelab erstellen wir GlowUp, ein Tool zur Fotorestaurierung. GlowUp nutzt KI, um alte, beschädigte oder Schwarz-Weiß-Fotos zu restaurieren und hochwertige 4K-Farbbilder zu erstellen. Mit diesem Tool können Sie Ihren Familienfotos neues Leben einhauchen oder es anpassen, um beschädigte Illustrationen, Zeichnungen, Gemälde oder andere Arten von Bildern zu restaurieren.

Sie verwenden Genkit Go, um die Anwendungslogik zu implementieren, und Gemini 3 Pro Image (auch bekannt als Nano Banana Pro) als Modell zum Verarbeiten der Fotos.

Vorbereitung

  • Grundlegende Kenntnisse der Programmiersprache Go
  • Grundkenntnisse der Google Cloud Console

Lerninhalte

  • Genkit-Anwendungen in Go entwickeln
  • Grundlegende Genkit-Konzepte wie Flows, Plug‑ins und Prompts
  • Prompts mit Handlebars-Vorlagen schreiben
  • Bilddaten aus Modellantworten abrufen

Voraussetzungen

Dieser Workshop kann vollständig in der Google Cloud Shell durchgeführt werden, in der alle erforderlichen Abhängigkeiten (gcloud CLI, Code-Editor, Go, Gemini CLI) vorinstalliert sind.

Alternativ benötigen Sie Folgendes, wenn Sie lieber auf Ihrem eigenen Computer arbeiten möchten:

  • Die Go-Toolchain (Version 1.24 oder höher)
  • Node.js v20 oder höher (für die genkit-Befehlszeile)
  • Ein Terminal mit installiertem gcloud-CLI
  • Eine IDE zum Bearbeiten Ihres Codes, z. B. VS Code
  • Empfohlen:Ein Coding-Agent wie die Gemini CLI oder Antigravity

Wichtige Technologien

Hier finden Sie weitere Informationen zu den Technologien, die wir verwenden:

  • Gemini Nano Banana Pro (Gemini 3 Pro Image): Das Modell, das unseren Wiederherstellungsprozess unterstützt
  • Genkit Go: unser Toolkit zum Orchestrieren von Modellaufrufen

2. Umgebung einrichten

Wählen Sie eine der folgenden Optionen aus: Umgebung selbst einrichten, wenn Sie dieses Codelab auf Ihrem eigenen Computer ausführen möchten, oder Cloud Shell starten, wenn Sie dieses Codelab vollständig in der Cloud ausführen möchten.

Umgebung zum selbstbestimmten Lernen einrichten

  1. Melden Sie sich in der Google Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Der Projektname ist der Anzeigename für die Teilnehmer dieses Projekts. Es handelt sich um einen String, der nicht von Google APIs verwendet wird. Sie können sie jederzeit aktualisieren.
  • Die Projekt-ID ist für alle Google Cloud-Projekte eindeutig und unveränderlich (kann nach dem Festlegen nicht mehr geändert werden). In der Cloud Console wird automatisch ein eindeutiger String generiert. Normalerweise ist es nicht wichtig, wie dieser String aussieht. In den meisten Codelabs müssen Sie auf Ihre Projekt-ID verweisen (in der Regel als PROJECT_ID angegeben). Wenn Ihnen die generierte ID nicht gefällt, können Sie eine andere zufällige ID generieren. Alternativ können Sie es mit einem eigenen Namen versuchen und sehen, ob er verfügbar ist. Sie kann nach diesem Schritt nicht mehr geändert werden und bleibt für die Dauer des Projekts bestehen.
  • Zur Information: Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu diesen drei Werten
  1. Als Nächstes müssen Sie die Abrechnung in der Cloud Console aktivieren, um Cloud-Ressourcen/-APIs zu verwenden. Die Durchführung dieses Codelabs kostet wenig oder gar nichts. Wenn Sie Ressourcen herunterfahren möchten, um Kosten zu vermeiden, die über diese Anleitung hinausgehen, können Sie die erstellten Ressourcen oder das Projekt löschen. Neue Google Cloud-Nutzer können am kostenlosen Testzeitraum mit einem Guthaben von 300$ teilnehmen.

Cloud Shell starten

Während Sie Google Cloud von Ihrem Laptop aus per Fernzugriff nutzen können, wird in diesem Codelab Google Cloud Shell verwendet, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.

Klicken Sie in der Google Cloud Console rechts oben in der Symbolleiste auf das Cloud Shell-Symbol:

Cloud Shell aktivieren

Die Bereitstellung und Verbindung mit der Umgebung sollte nur wenige Augenblicke dauern. Anschließend sehen Sie in etwa Folgendes:

Screenshot des Google Cloud Shell-Terminals, auf dem zu sehen ist, dass die Umgebung verbunden ist

Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft in Google Cloud, was die Netzwerkleistung und Authentifizierung erheblich verbessert. Alle Aufgaben in diesem Codelab können in einem Browser ausgeführt werden. Sie müssen nichts installieren.

3. Projekt einrichten

Projekt erstellen

Zuerst müssen wir ein neues Verzeichnis für Ihr Projekt erstellen und das Go-Modul initialisieren. Führen Sie im Terminal die folgenden Befehle aus:

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

Genkit CLI installieren

Als Nächstes müssen wir die Genkit CLI installieren. Dadurch erhalten Sie Zugriff auf lokale Entwicklertools, einschließlich der Entwickler-UI. Geben Sie in Ihrem Terminalfenster Folgendes ein:

curl -sL cli.genkit.dev | bash

Umgebungsvariablen konfigurieren

Prüfen Sie, ob Sie die richtigen Google Cloud-Anmeldedaten eingerichtet haben. Ersetzen Sie your-project-id durch Ihre tatsächliche Projekt-ID. Der Standort muss global sein, wenn Sie Gemini 3 Pro-Vorabversionen verwenden (Nano Banana Pro ist eine davon).

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

Führen Sie den folgenden Befehl im Shell-Modus aus, um die Vertex AI API zu aktivieren:

gcloud services enable aiplatform.googleapis.com

Wenn Sie das Skript auf Ihrem lokalen Computer (nicht in Cloud Shell) ausführen, müssen Sie sich mit dem gcloud-Befehl authentifizieren:

gcloud auth application-default login

4. Erste Genkit-Anwendung erstellen

Genkit ist ein Open-Source-Framework, mit dem Entwickler produktionsreife KI-basierte Anwendungen erstellen, bereitstellen und überwachen können. In diesem Abschnitt erstellen wir eine einfache „Hello World“-Anwendung, damit Sie sich mit dem Framework vertraut machen können, bevor wir uns mit der Logik für die Fotorestaurierung befassen.

Genkit-Terminologie

Bevor Sie mit Genkit arbeiten, sollten Sie sich mit einigen wichtigen Begriffen vertraut machen:

  • Plug-ins:werden verwendet, um die Funktionen von Genkit zu erweitern. Unter anderem registrieren Sie über Plug-ins KI-Modelle, die Ihre Anwendung unterstützen.
  • Flows:die architektonische Hauptkomponente von Genkit. Ein typischer Ablauf nimmt eine Eingabe entgegen, verarbeitet sie und gibt eine Ausgabe zurück. Dafür ist nicht unbedingt ein Modell erforderlich, aber in den meisten Fällen werden Sie Modelle in Ihren Abläufen verwenden.
  • Prompts:Interaktionsvorlagen, die im dotprompt-Format gespeichert sind (als *.prompt-Dateien). Sie enthalten nicht nur die Modellanweisungen, sondern auch Konfigurationen wie Modellname, Modellparameter, Ein- und Ausgaben.

Verbindung zu KI-Modellen herstellen

Genkit verwendet Plug-ins, um Ihren Code mit Modellanbietern zu verbinden. Es gibt Plug-ins für alle wichtigen Modellanbieter, darunter Google, Anthropic und OpenAI.Sie können Plug-ins auch verwenden, um eine Verbindung zu lokalen Modellen herzustellen (z.B. mit Ollama) oder die Funktionen von Genkit zu erweitern (z.B. eine Verbindung zu MCP-Servern herstellen).

Für den Zugriff auf Google-Modelle sollten Sie das googlegenai-Plug-in verwenden. Es werden zwei Backends unterstützt:

  • Google AI: Am besten für Prototyping geeignet. Verwendet einen API-Schlüssel.
  • Vertex AI (Google Cloud): Empfohlen für die Produktion. Verwendet Projekt-ID und Standort.

In diesem Codelab verwenden wir die Vertex AI-Authentifizierung, die auf das Projekt verweist, das Sie am Anfang des Labs erstellt haben.

Begrüßungsablauf erstellen

Bevor wir uns den Ablauf zur Fotorestaurierung mit Glow Up genauer ansehen, erstellen wir einen einfachen Ablauf, um uns mit den Konzepten vertraut zu machen und sicherzustellen, dass unsere Einrichtung ordnungsgemäß funktioniert.

Ein Flow ist eine spezielle Genkit-Funktion, die Ihre KI-Logik umschließt und Folgendes bietet:

  • Typsichere Ein- und Ausgaben:Schemas mit Go-Structs für die statische und Laufzeitvalidierung definieren
  • Streaming-Unterstützung:Teilantworten oder benutzerdefinierte Daten streamen
  • Integration der Entwickler-UI:Abläufe mit visuellen Traces testen und debuggen
  • Einfache Bereitstellung:Bereitstellung als HTTP-Endpunkte auf jeder Plattform

Öffnen Sie Ihre IDE und erstellen Sie im Projektverzeichnis eine Datei mit dem Namen main.go. Wenn Sie Cloud Shell verwenden, können Sie den folgenden Befehl verwenden:

cloudshell edit main.go

Fügen Sie dann den folgenden Code hinzu:

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

Speichern Sie die Datei und führen Sie dann „go mod tidy“ aus, um die Abhängigkeiten zu aktualisieren:

go mod tidy

Mit dem Code oben wird Genkit mit dem VertexAI-Plug-in initialisiert, ein Ablauf namens „greeter“ definiert und dann unendlich lange auf <-ctx.Done() gewartet. Wir halten die Ausführung an, damit dieses Programm nicht sofort beendet wird, da wir ihm keine Anweisungen zur tatsächlichen Ausführung des Ablaufs geben.

Wenn Sie dieses Programm also so ausführen, wie es jetzt ist, passiert nicht viel – wir müssen den Ablauf irgendwie aufrufen. In einer echten Produktionsanwendung würden wir diesen Ablauf in einen Webserver oder eine CLI-Anwendung einbinden. Während der Entwicklung können wir jedoch die genkit-CLI verwenden, um den Ablauf zu entwickeln und zu optimieren.

Die genkit-CLI wurde entwickelt, um uns beim Testen von Modellen, Prompts, Abläufen und anderen Komponenten des Genkit-Stacks zu unterstützen. Außerdem werden Traces vollständig unterstützt, was sehr praktisch ist, wenn Sie wissen möchten, wie die Anwendung im Hintergrund funktioniert. Führen Sie den folgenden Befehl aus, um den Begrüßungsablauf mit der genkit-CLI zu starten:

genkit start -- go run main.go

Dadurch werden die Telemetry API- und Developer UI-Endpunkte gestartet. Auf dem Bildschirm sollte Folgendes zu sehen sein:

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

Wenn Sie localhost:4000 in Ihrem Browser öffnen, wird die Entwicklungsoberfläche gestartet. Sie sollten Folgendes sehen:

93d9bd9e1bd6627d.png

Nehmen Sie sich Zeit, die Entwickler-UI zu erkunden. Vielleicht lösen Sie den „Greeter“-Flow einmal aus, um zu sehen, wie er funktioniert.

Prompt-Vorlagen verwenden

Sie können Ihre Prompts zwar wie im vorherigen Beispiel in Modellaufrufen fest codieren, es ist jedoch besser, Promptvorlagen zu erstellen, um alle Prompts Ihrer Anwendung zentral zu speichern. So lassen sie sich nicht nur leichter finden, wenn Sie den Code warten, sondern Sie können auch unabhängig von den Abläufen mit den Prompts experimentieren.

Zum Definieren von Prompt-Vorlagen verwendet Genkit das Open-Source-Format dotprompt, das als *.prompt-Dateien gespeichert wird. Eine .prompt-Datei besteht aus zwei Teilen:

  1. Frontmatter:Ein YAML-Block, der das Modell, die Modellparameter sowie die Ein- und Ausgabeschemas definiert.
  2. Body: Der Hauptteil des Prompts selbst, der mit der Handlebars-Syntax als Vorlage verwendet werden kann. Wenn Sie beispielsweise eine Eingabe mit dem Namen variable-name definieren, können Sie im Textkörper mit {{variable-name}} darauf verweisen.

Die Verzeichnisstruktur des Projekts sieht so aus:

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

Sehen wir uns das in der Praxis an. Erstellen Sie zuerst den Ordner zum Speichern Ihrer Prompts:

mkdir -p prompts

Erstellen Sie dann eine greeter.prompt-Datei:

cloudshell edit prompts/greeter.prompt

Fügen Sie den folgenden Inhalt ein:

greeter.prompt

ec9fc82a98604123.png

Dieser Prompt zeigt einige der Funktionen der Vorlagensprache. Zuerst geben wir das Modell vertexai/gemini-2.5-flash im Frontmatter an. Wenn Sie ein Modell angeben möchten, müssen Sie die in der jeweiligen Plug-in-Dokumentation definierte Nomenklatur verwenden.

Im Konfigurationsabschnitt können wir die Modellparameter konfigurieren. Wir verwenden die Temperatur 1,9, damit das Modell kreativer sein kann. Die Temperatur reicht von 0 (einheitlichere Ausgaben) bis 2 (kreativere Ausgaben). Dieser und andere Modellparameter werden in der Regel im Datenblatt des Modells veröffentlicht. Hier ist beispielsweise das Datenblatt für das Modell gemini-2.5-flash.

Im Eingabebereich können wir Argumente für den Prompt angeben. In diesem Fall definieren wir den Namen als String. Nach dem Frontmatter folgt der Prompt-Text. Im ersten Block wird der System-Prompt definiert, im zweiten der Nutzer-Prompt. Alle diese Elemente zusammen ermöglichen einige sehr leistungsstarke Prompting-Techniken. Die vollständige Dokumentation für dotprompt finden Sie hier.

Passen wir nun den greeter-Ablauf an, damit der Prompt verwendet wird, den wir gerade erstellt haben:

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

Führen Sie den Ablauf über die Befehlszeile aus, einmal mit und einmal ohne Namen, um den Unterschied zu sehen. Laufen ohne Namen:

genkit flow:run greeter

Beispielausgabe:

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

Und mit einem Namen:

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

Beispielausgabe:

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

Wie Sie sehen, hat die Vorlage wie erwartet funktioniert. Wir sind bereit, dieses Projekt auf die nächste Stufe zu heben.

5. Bilder mit Nano Banana Pro wiederherstellen

Der Restaurierungs-Prompt

Nachdem Sie sich mit den Bausteinen von Genkit vertraut gemacht haben, können Sie nun den Prompt für die Fotowiederherstellung erstellen.

Erstellen Sie im Verzeichnis „Prompts“ eine Datei mit dem Namen glowup.prompt und fügen Sie den folgenden Inhalt ein:

glowup.prompt

fd0f1551466c8138.png

Der Aufforderungstext für die Wiederherstellung folgt demselben Muster wie unser „Begrüßungs“-Aufforderungstext, mit nur wenigen bemerkenswerten Unterschieden:

  • Bildgröße:Die imageSize-Eigenschaft von imageConfig ist ein modellspezifischer Parameter von Nano Banana Pro. So können wir die Ausgabegröße als 1K, 2K oder 4K angeben.
  • Media-Eingabe:Wir verwenden die Vorlage {{ media }}, um das Foto in die Nutzeraufforderung einzufügen. Mit dieser Technik können wir multimodale Prompts (Text + Bild) an das Modell senden.

Sie können diesen Prompt in der Entwickler-UI testen. Sie können die Einstellungen anpassen, um zu sehen, wie sich das auf die Ausgabe auswirkt.

Ablauf der Bildwiederherstellung

Nachdem wir den Wiederherstellungs-Prompt erstellt haben, können wir nun unsere CLI-Anwendung entwickeln. Ersetzen Sie den Inhalt von main.go durch den folgenden Code:

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
}

Der Code ähnelt in der Struktur sehr dem greeter-Ablauf, ist aber dieses Mal so angepasst, dass er als eigenständige CLI-Anwendung ausgeführt werden kann. Anstatt für immer zu blockieren, wird der glowUp-Ablauf ausgeführt, die Ausgabe decodiert und die resultierenden Binärdaten auf der Festplatte gespeichert.

Wir müssen die Ausgabe decodieren, da das Modell die Bilddaten im folgenden Format zurückgibt:

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

In der Funktion decode sehen Sie, dass wir Stringbearbeitung verwenden, um den MIME-Typ und die codierten Bildteile aufzuteilen. Anschließend verwenden wir die Funktionen mime.ExtensionByType und base64.DecodeString, um die Informationen zu extrahieren, die wir zum Speichern der Datei benötigen.

Wiederherstellungsvorgang testen

Jetzt ist es endlich an der Zeit, diesen Ablauf mit einem echten Bild auszuführen. Wenn Sie keine alten Fotos haben, die restauriert werden müssen, können Sie dieses Bild aus dem öffentlichen Bereich verwenden, das von der Website der Library of Congress stammt:

f0fc83a81e88052a.png

Hier ist der direkte Link zum Foto, das an den Flow übergeben werden soll: 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

Hier sehen Sie die wiederhergestellte und kolorierte Ausgabe:

5ed7bfcf6d26313c.png

Fertig!

6. glowUp als Webdienst bereitstellen

Wenn Sie Ihre Abläufe nicht in einer Befehlszeilenanwendung, sondern in einem Webdienst verfügbar machen möchten, bietet Genkit eine praktische Möglichkeit, Abläufe mithilfe des genkit.Handler-Adapters in Endpunkte zu konvertieren. Im folgenden Code wird der glowUp-Ablauf als glowUp-Endpunkt mit genkit.Handler registriert.

Sie können sie mit einem regulären HTTP-Server wie gewohnt über das http-Paket aus der Standardbibliothek bereitstellen. Genkit bietet aber auch ein server-Plug-in, das bei einigen der gängigen Server-Boilerplate-Codes hilft, z. B. beim ordnungsgemäßen Verarbeiten von Herunterfahrsignalen.

Ersetzen Sie den Inhalt von main.go durch den unten stehenden Code, um Ihren Webserver zu erstellen.

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

Sie können diesen Dienst entweder lokal oder in der Cloud ausführen. Für die lokale Ausführung können Sie die Datei einfach direkt ausführen, da das Programm jetzt vollständig ist. Es ist also nicht erforderlich, es über die Genkit-Befehlszeilenschnittstelle zu starten. Beispiel:

go run main.go

Da es sich um einen blockierenden Vorgang handelt, müssen Sie ein zweites Terminal starten, um ihn zu testen. Am schnellsten geht es mit dem curl-Befehl:

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

Da es sich um eine Serverantwort handelt, müssen wir das Base64-Bild decodieren:

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

Webdienst in Cloud Run bereitstellen

Es ist in Ordnung, dass dieser Server auf meinem Computer funktioniert, aber im Idealfall würden wir ihn an einem anderen Ort bereitstellen, der für alle unsere Nutzer zugänglich ist. Eine der einfachsten Möglichkeiten, solche Dienste bereitzustellen, ist die Funktion „Aus der Quelle bereitstellen“ von Cloud Run. Mit dieser Funktion müssen Sie den Container nicht einmal selbst erstellen, da alles automatisiert wird.

Wenn Sie diesen Dienst mit der Bereitstellung aus der Quelle in Cloud Run bereitstellen möchten, führen Sie den folgenden Befehl aus und ersetzen Sie die Projekt-ID durch Ihre eigene:

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

Die Bereitstellung kann einige Minuten dauern. Wenn Sie fertig sind, können Sie den Endpunkt testen, indem Sie eine weitere Anfrage über curl senden:

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

Auch hier müssen wir das Base64-Bild decodieren:

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

Jetzt haben wir einen voll funktionsfähigen Webserver für die Fotorestaurierung.

Optional: Clientanwendung mit „Vibe“ codieren

Das Schreiben von Code kann Spaß machen, aber auch eine Herausforderung sein, wenn Sie noch nie einen bestimmten Projekttyp bearbeitet haben. Glücklicherweise gibt es heute Coding-Assistenten, die uns helfen können, den Prozess zu beschleunigen.

In diesem Schritt schreiben wir den Code nicht selbst, sondern bitten Gemini CLI (oder einen anderen Coding-Agenten) darum, die Arbeit für uns zu erledigen. Verwenden Sie den folgenden Prompt:

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

Der Agent muss die Dateien möglicherweise etwas umorganisieren, da es nicht möglich ist, zwei Funktionen mit dem Namen „main“ im selben Modul zu haben. Beobachten Sie, wie der Agent arbeitet, und lenken Sie ihn bei Bedarf in die richtige Richtung, indem Sie ihm den Servercode oder Code-Snippets zur Verfügung stellen.

Nach dem Lab bereinigen

7. Fazit

Glückwunsch! Sie haben mit Genkit und Nano Banana Pro erfolgreich eine App zur Fotorestaurierung mit hoher Wiedergabetreue erstellt.

In diesem Codelab haben Sie Folgendes gelernt:

  • Umgebung für die Entwicklung von Genkit Go-Anwendungen konfigurieren
  • Multimodale Prompts mit dotprompt erstellen
  • Genkit-Flows mit Eingabeaufforderungsvorlagen erstellen
  • Bilder mit Nano Banana Pro verarbeiten
  • Genkit-Flows als Befehlszeilenanwendungen und Webservices verpacken
  • Genkit-Anwendungen in Cloud Run bereitstellen

Denken Sie daran, die Umgebung nach Abschluss der Tests zu bereinigen.

Nächste Schritte

Sie können Ihre Lernreise fortsetzen, indem Sie sich andere Codelabs auf dieser Plattform ansehen oder glowUp selbst verbessern.

Wenn Sie Ideen für Verbesserungen benötigen, können Sie Folgendes ausprobieren:

  • glowUp CLI aktivieren, um lokale Dateien wiederherzustellen
  • Frontend für den GlowUp-Webdienst erstellen
  • MIME-Typ automatisch aus den Daten erkennen
  • Andere Arten der Bildbearbeitung durchführen (z. B. von Foto zu Zeichnung, von Zeichnung zu Foto, von Skizze zu fertigem Kunstwerk)
  • Client erstellen oder verbessern (vielleicht eine Smartphone-App entwickeln?)

Die Möglichkeiten sind einfach endlos. Wenn Sie sich nicht sicher sind, ob Sie das alleine schaffen, können Sie jederzeit einen Coding-Agenten wie die Gemini CLI oder Antigravity hinzuziehen. Wenn Sie mehr mit Genkit machen möchten, können Sie mit dem Genkit MCP-Server codierte Agents erstellen, die Ihnen die Arbeit erheblich erleichtern.

Wenn Sie auf den vollständigen Code für dieses Repository zugreifen möchten, finden Sie ihn hier.

Viel Spaß beim Programmieren!