Créer une application de restauration de photos avec Genkit Go et Nano Banana Pro

1. Introduction

Dans cet atelier de programmation, nous allons créer GlowUp, un outil de restauration de photos. GlowUp utilise l'IA pour restaurer les photos anciennes, endommagées ou en noir et blanc, et créer des images couleur 4K de haute qualité. Vous pouvez utiliser cet outil pour redonner vie à vos photos de famille, ou même l'adapter pour restaurer des illustrations, des dessins, des peintures ou d'autres types d'images endommagées.

Vous utiliserez Genkit Go pour implémenter la logique de l'application et Gemini 3 Pro Image (également appelé Nano Banana Pro) comme modèle pour traiter les photos.

Prérequis

  • Connaissances de base du langage de programmation Go
  • Connaissances de base de la console Google Cloud

Points abordés

  • Développer des applications Genkit en Go
  • Concepts de base de Genkit, comme les flux, les plug-ins et les requêtes
  • Rédiger des requêtes avec des modèles Handlebars
  • Obtenir des données d'image à partir des réponses du modèle

Prérequis

Cet atelier peut être entièrement réalisé dans Google Cloud Shell, qui est préinstallé avec toutes les dépendances nécessaires (gcloud CLI, éditeur de code, Go, Gemini CLI).

Sinon, si vous préférez travailler sur votre propre machine, vous aurez besoin des éléments suivants :

  • Chaîne d'outils Go (version 1.24 ou ultérieure)
  • Node.js v20 ou version ultérieure (pour l'interface de ligne de commande genkit)
  • Un terminal avec la CLI gcloud installée
  • Un IDE pour modifier votre code, comme VS Code ou un outil similaire
  • Recommandé : un agent de codage tel que Gemini CLI ou Antigravity

Technologies clés

Vous trouverez ici plus d'informations sur les technologies que nous allons utiliser :

  • Gemini Nano Banana Pro (Gemini 3 Pro Image) : le modèle qui alimente notre processus de restauration
  • Genkit Go : notre boîte à outils pour orchestrer les appels de modèles

2. Configuration de l'environnement

Choisissez l'une des options suivantes : Configurer l'environnement à votre rythme si vous souhaitez exécuter cet atelier de programmation sur votre propre machine, ou Démarrer Cloud Shell si vous souhaitez exécuter cet atelier de programmation entièrement dans le cloud.

Configuration de l'environnement au rythme de chacun

  1. Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pourrez toujours le modifier.
  • L'ID du projet est unique parmi tous les projets Google Cloud et non modifiable une fois défini. La console Cloud génère automatiquement une chaîne unique (en général, vous n'y accordez d'importance particulière). Dans la plupart des ateliers de programmation, vous devrez indiquer l'ID de votre projet (généralement identifié par PROJECT_ID). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre de manière aléatoire. Vous pouvez également en spécifier un et voir s'il est disponible. Après cette étape, l'ID n'est plus modifiable et restera donc le même pour toute la durée du projet.
  • Pour information, il existe une troisième valeur (le numéro de projet) que certaines API utilisent. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
  1. Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour désactiver les ressources et éviter ainsi que des frais ne vous soient facturés après ce tutoriel, vous pouvez supprimer le projet ou les ressources que vous avez créées. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300 $.

Démarrer Cloud Shell

Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Google Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.

Dans la console Google Cloud, cliquez sur l'icône Cloud Shell dans la barre d'outils supérieure :

Activer Cloud Shell

Le provisionnement et la connexion à l'environnement prennent quelques instants seulement. Une fois l'opération terminée, le résultat devrait ressembler à ceci :

Capture d'écran du terminal Google Cloud Shell montrant que l'environnement est connecté

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez effectuer toutes les tâches de cet atelier de programmation dans un navigateur. Vous n'avez rien à installer.

3. Configuration du projet

Créer le projet

Tout d'abord, nous devons créer un répertoire pour votre projet et initialiser le module Go. Dans le terminal, exécutez les commandes suivantes :

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

Installer la CLI Genkit

Nous devons maintenant installer Genkit CLI. Vous avez ainsi accès aux outils de développement locaux, y compris à l'UI du développeur. Dans la fenêtre de terminal, saisissez :

curl -sL cli.genkit.dev | bash

Configurer les variables d'environnement

Assurez-vous d'avoir configuré les bons identifiants Google Cloud. Remplacez your-project-id par l'ID de votre projet. La valeur de l'emplacement doit être global lorsque vous utilisez les modèles Gemini 3 Pro Preview (Nano Banana Pro en fait partie).

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

Exécutez la commande suivante en mode shell pour activer l'API Vertex AI :

gcloud services enable aiplatform.googleapis.com

Si vous exécutez le script depuis votre machine locale (et non dans Cloud Shell), vous devrez vous authentifier avec la commande gcloud :

gcloud auth application-default login

4. Créer votre première application Genkit

Genkit est un framework Open Source conçu pour aider les développeurs à créer, déployer et surveiller des applications optimisées par l'IA prêtes pour la production. Dans cette section, nous allons créer une application "Hello World" simple pour vous aider à vous familiariser avec le framework avant de nous plonger dans la logique de restauration de photos.

Terminologie Genkit

Avant de commencer à utiliser Genkit, il est important de comprendre quelques termes clés :

  • Plug-ins : utilisés pour étendre les fonctionnalités de Genkit. C'est, entre autres, grâce aux plug-ins que vous enregistrez les modèles d'IA pour alimenter votre application.
  • Flux : composant architectural principal de Genkit. Un flux typique prend une entrée, la traite et renvoie une sortie. Il n'est pas forcément nécessaire d'utiliser un modèle, mais la plupart du temps, vous utiliserez des modèles dans vos flux.
  • Requêtes : modèles d'interaction stockés au format dotprompt (enregistrés en tant que fichiers *.prompt). Ils contiennent non seulement les instructions du modèle, mais aussi des configurations telles que le nom du modèle, les paramètres du modèle, les entrées et les sorties.

Se connecter aux modèles d'IA

Genkit utilise des plug-ins pour connecter votre code aux fournisseurs de modèles. Il existe des plug-ins pour tous les principaux fournisseurs de modèles, y compris Google, Anthropic et OpenAI. Vous pouvez également utiliser des plug-ins pour vous connecter à des modèles locaux (par exemple, à l'aide d'Ollama) ou pour étendre les capacités de Genkit (par exemple, vous connecter à des serveurs MCP).

Pour accéder aux modèles Google, vous devez utiliser le plug-in googlegenai. Il est compatible avec deux backends :

  • Google AI : idéal pour le prototypage. Utilise une clé API.
  • Vertex AI (Google Cloud) : recommandé pour la production. Utilise l'ID et l'emplacement du projet.

Dans cet atelier de programmation, nous allons utiliser l'authentification Vertex AI en référence au projet que vous avez créé au début de l'atelier.

Créer un flux d'accueil

Avant d'examiner plus en détail le flux de restauration de photos Glow Up, créons un flux de base pour nous familiariser avec les concepts et nous assurer que notre configuration fonctionne correctement.

Un flow est une fonction Genkit spéciale qui encapsule votre logique d'IA pour fournir :

  • Entrées et sorties avec sécurité du type : définissez des schémas à l'aide de structs Go pour la validation statique et au moment de l'exécution.
  • Prise en charge du streaming : diffusez des réponses partielles ou des données personnalisées.
  • Intégration de l'UI du développeur : testez et déboguez les flux avec des traces visuelles.
  • Déploiement facile : déployez des points de terminaison HTTP sur n'importe quelle plate-forme.

Ouvrez votre IDE et créez un fichier main.go dans le répertoire de votre projet. Si vous utilisez Cloud Shell, vous pouvez utiliser la commande suivante :

cloudshell edit main.go

Ajoutez ensuite le code suivant :

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

Enregistrez le fichier, puis exécutez "go mod tidy" pour mettre à jour vos dépendances :

go mod tidy

Le code ci-dessus initialise Genkit avec le plug-in Vertex AI, définit un flux nommé "greeter" (salutation) et attend ensuite indéfiniment sur <-ctx.Done(). Nous suspendons l'exécution pour que ce programme ne se termine pas immédiatement, car nous ne lui donnons aucune instruction pour exécuter réellement le flux.

Cela signifie que si vous exécutez ce programme tel qu'il est maintenant, il ne fera pas grand-chose en soi. Nous devons invoquer le flux d'une manière ou d'une autre. Dans une véritable application de production, nous encapsulerions ce flux dans un serveur Web ou une application CLI. Toutefois, pendant le développement, nous pouvons utiliser la CLI genkit pour nous aider à développer et à optimiser le flux.

La CLI genkit a été développée pour nous aider à tester les modèles, les requêtes, les flux et d'autres composants de la pile Genkit. Il est également entièrement compatible avec les traces, ce qui est très pratique lorsque vous souhaitez comprendre comment l'application fonctionne en interne. Pour lancer notre flux d'accueil à l'aide de la CLI genkit, exécutez la commande suivante :

genkit start -- go run main.go

Les points de terminaison de l'API Telemetry et de l'UI de développement seront alors lancés. L'écran qui s'affiche devrait ressembler à ce qui suit :

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

Si vous ouvrez localhost:4000 dans votre navigateur pour lancer l'UI de développement. Un écran semblable à celui-ci s'affiche :

93d9bd9e1bd6627d.png

Prenez le temps d'explorer l'interface utilisateur de développement. Vous pouvez déclencher le flux "greeter" une seule fois pour voir comment il fonctionne.

Utiliser des modèles de requêtes

Bien que vous puissiez coder en dur vos requêtes dans les appels de modèle, comme nous l'avons fait dans l'exemple précédent, une meilleure approche serait de créer des modèles de requêtes pour stocker toutes les requêtes de notre application de manière centralisée. Cela facilite non seulement leur recherche lors de la maintenance du code, mais vous permet également d'expérimenter avec les requêtes indépendamment des flux.

Pour définir des modèles de requêtes, Genkit utilise le format Open Source dotprompt, enregistré sous forme de fichiers *.prompt. Un fichier .prompt se compose de deux parties :

  1. Frontmatter : bloc YAML qui définit le modèle, les paramètres du modèle et les schémas d'entrée et de sortie
  2. Corps : corps de l'invite lui-même, qui peut être modélisé à l'aide de la syntaxe "handlebars". Par exemple, si vous définissez une entrée nommée variable-name, vous pouvez la référencer dans le corps en tant que {{variable-name}}.

La structure de répertoire du projet se présente comme suit :

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

Voyons comment cela se traduit dans la pratique. Commencez par créer le dossier dans lequel stocker vos requêtes :

mkdir -p prompts

Créez ensuite un fichier greeter.prompt :

cloudshell edit prompts/greeter.prompt

Insérez le contenu suivant :

greeter.prompt

ec9fc82a98604123.png

Cette requête présente quelques fonctionnalités du langage de modèle. Tout d'abord, nous spécifions le modèle vertexai/gemini-2.5-flash dans le frontmatter. Pour spécifier un modèle, vous devez utiliser la nomenclature définie dans la documentation du plug-in correspondant.

La section "config" nous permet de configurer les paramètres du modèle. Nous utilisons une température de 1,9 pour permettre au modèle d'être plus créatif. La température est comprise entre 0 (résultats plus cohérents) et 2 (résultats plus créatifs). Ce paramètre et d'autres sont généralement publiés dans la fiche du modèle. Par exemple, voici la fiche du modèle gemini-2.5-flash.

La section "input" nous permet de spécifier des arguments pour l'invite. Dans ce cas, nous définissons le nom comme une chaîne. Après le frontmatter, nous avons le corps de la requête. Le premier bloc définit le prompt système et le second, le prompt utilisateur. Tous ces éléments combinés permettent d'utiliser des techniques de requête très puissantes. Vous pouvez consulter la documentation complète de dotprompt ici.

Adaptons maintenant le flux greeter pour utiliser le prompt que nous venons de créer :

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

Essayez d'exécuter le flux à partir de la ligne de commande, avec et sans nom, pour voir la différence. Exécution sans nom :

genkit flow:run greeter

Exemple de résultat :

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

Et avec un nom :

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

Exemple de résultat :

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

Vous pouvez constater que le modèle a fonctionné comme prévu. Nous sommes prêts à passer à l'étape suivante !

5. Restaurer des images avec Nano Banana Pro

Invite de restauration

Maintenant que vous connaissez les blocs de construction de Genkit, il est temps de créer notre requête de restauration de photos.

Créez un fichier nommé glowup.prompt dans le répertoire des invites et collez-y le contenu suivant :

glowup.prompt

fd0f1551466c8138.png

L'invite de restauration suit le même schéma que notre invite d'accueil, avec quelques différences notables :

  • Taille de l'image : la propriété imageSize de imageConfig est un paramètre spécifique au modèle Nano Banana Pro. Il nous permet de spécifier la taille de sortie en 1 000, 2 000 ou 4 000.
  • Entrée média : nous utilisons le modèle {{ media }} pour insérer la photo dans la requête utilisateur. Cette technique nous permet d'envoyer des requêtes multimodales au modèle (texte + image).

Vous pouvez tester cette requête dans l'UI de développement. N'hésitez pas à le modifier pour voir comment cela affecte le résultat.

Flux de restauration d'images

Maintenant que l'invite de restauration est prête, créons notre application CLI. Remplacez le contenu de main.go par le code ci-dessous :

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
}

Le code est très semblable à la structure du flux greeter, mais il est cette fois adapté pour s'exécuter en tant qu'application CLI autonome. Au lieu de bloquer indéfiniment, il exécutera le flux glowUp, décodera la sortie et enregistrera les données binaires résultantes sur le disque.

Nous devons décoder la sortie, car le modèle renvoie les données d'image au format suivant :

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

Vous pouvez voir dans la fonction decode que nous utilisons la manipulation de chaînes pour diviser le type MIME et les parties d'image encodées. Nous utilisons ensuite les fonctions mime.ExtensionByType et base64.DecodeString pour extraire les informations dont nous avons besoin pour enregistrer le fichier.

Tester le flux de restauration

Il est enfin temps d'exécuter ce flux avec une vraie photo ! Si vous n'avez pas de vieilles photos à restaurer sous la main, vous pouvez essayer avec cette image du domaine public extraite du site Web de la Library of Congress :

f0fc83a81e88052a.png

Voici le lien direct vers la photographie à transmettre au flux : 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

Voici le résultat restauré et colorisé :

5ed7bfcf6d26313c.png

Opération réussie !

6. Déployer glowUp en tant que service Web

Si, au lieu d'une application en ligne de commande, vous souhaitez exposer vos flux dans un service Web, Genkit vous permet de convertir facilement des flux en points de terminaison à l'aide de l'adaptateur genkit.Handler. Le code ci-dessous enregistre le flux glowUp en tant que point de terminaison glowUp à l'aide de genkit.Handler.

Vous pouvez les exposer avec un serveur HTTP standard comme vous le feriez normalement en utilisant le package http de la bibliothèque standard, mais Genkit fournit également un plug-in server qui vous aide avec certains des modèles de serveur courants, comme la gestion des signaux d'arrêt de manière fluide.

Remplacez le contenu de main.go par le code ci-dessous pour créer votre serveur 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)
        }
}

Vous pouvez exécuter ce service localement ou dans le cloud. Pour l'exécuter en local, vous pouvez simplement exécuter le fichier directement, car le programme est désormais complet. Nous n'avons donc pas besoin de le lancer via l'interface de ligne de commande Genkit. Exemple :

go run main.go

Comme il s'agit d'une opération bloquante, vous devez lancer un deuxième terminal pour la tester. Le moyen le plus rapide consiste à utiliser la commande curl :

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

Comme il s'agit d'une réponse du serveur, nous devons décoder l'image en base64 :

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

Déployer le service Web sur Cloud Run

Il est acceptable que ce serveur "fonctionne sur ma machine", mais dans le monde idéal, nous le déploierions ailleurs, accessible à tous nos utilisateurs. L'un des moyens les plus pratiques de déployer des services comme celui-ci consiste à utiliser la fonctionnalité de déploiement à partir de la source de Cloud Run. Avec cette fonctionnalité, vous n'avez même pas besoin de créer le conteneur vous-même, tout est automatisé.

Pour déployer ce service sur Cloud Run à l'aide du déploiement à partir de la source, exécutez la commande suivante (remplacez l'ID du projet par le vôtre) :

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

Le déploiement peut prendre quelques minutes. Une fois que vous avez terminé, vous pouvez tester le point de terminaison en envoyant une autre requête via 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

Encore une fois, nous devons décoder l'image en base64 :

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

Nous disposons maintenant d'un serveur Web de restauration de photos entièrement fonctionnel.

Facultatif : "Vibe coding" d'une application cliente

Écrire du code manuellement est amusant, mais peut aussi être difficile si vous n'avez jamais réalisé un certain type de projet auparavant. Heureusement, nous disposons aujourd'hui d'agents de codage qui peuvent nous aider à accélérer le processus.

Dans cette étape, au lieu d'écrire le code nous-mêmes, nous allons demander à Gemini CLI (ou à votre agent de codage préféré) de le faire pour nous. Utilisez le prompt suivant :

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

L'agent devra peut-être réorganiser un peu les fichiers, car nous ne pouvons pas avoir deux fonctions "main" dans le même module. Observez son fonctionnement et orientez-le vers la bonne implémentation en lui fournissant le code ou des extraits de code du serveur si nécessaire.

Nettoyer après l'atelier

7. Conclusion

Félicitations ! Vous avez créé une application de restauration de photos haute fidélité à l'aide de Genkit et Nano Banana Pro.

Dans cet atelier de programmation, vous avez appris à :

  • Configurer votre environnement pour développer des applications Genkit Go
  • Créer des requêtes multimodales avec dotprompt
  • Créer des flows Genkit à l'aide de modèles de requêtes
  • Utiliser Nano Banana Pro pour traiter des images
  • Empaqueter les flux Genkit en tant qu'applications de ligne de commande et services Web
  • Déployer des applications Genkit sur Cloud Run

Une fois les tests terminés, n'oubliez pas de nettoyer l'environnement.

Étapes suivantes

Vous pouvez poursuivre votre parcours d'apprentissage en explorant d'autres ateliers de programmation sur cette plate-forme ou en améliorant glowUp par vous-même.

Si vous avez besoin d'idées pour améliorer votre application, vous pouvez essayer :

  • Activer glowUp CLI pour restaurer les fichiers locaux
  • Créer une interface pour le service Web GlowUp
  • Détecter automatiquement le type MIME à partir des données
  • Effectuer d'autres types de traitement d'image (d'une photo à un dessin, d'un dessin à une photo, d'un croquis à une œuvre finale, etc.)
  • Créer ou améliorer le client (par exemple, en développant une application pour smartphone)

Les possibilités sont infinies ! Si l'idée de vous lancer seul vous intimide un peu, vous pouvez toujours faire appel à un agent de codage comme Gemini CLI ou Antigravity. Et si vous souhaitez aller plus loin avec Genkit, les agents de codage associés au serveur MCP Genkit peuvent vous simplifier la vie.

Enfin, si vous souhaitez accéder au code complet de ce dépôt, vous le trouverez sur cette page.

À vous de jouer !