🎬 Crea ed esegui il deployment di un AI Motion Lab con Gemini, Veo e Cloud Run

1. Introduzione

Cosa creerai

Gemini Motion Lab è un'esperienza di chiosco live basata sull'AI. Un utente registra un breve video di danza o movimento e il sistema:

  1. Analizza il movimento utilizzando Gemini (parti del corpo, fasi, tempo, energia)
  2. Genera un'immagine stilizzata dell'avatar utilizzando Nano Banana (Gemini Flash Image)
  3. Crea un video AI utilizzando Veo che ricrea il movimento con l'avatar
  4. Compone un video affiancato (originale + generato con l'AI)
  5. Condivide il risultato tramite un codice QR su una pagina ottimizzata per il mobile

Al termine di questo codelab, avrai eseguito il deployment della demo completa su Google Cloud Run e avrai compreso la pipeline di AI che la alimenta.

Panoramica dell'architettura

Demo finale:

cover

Tecnologie di base

Componente

Tecnologia

Finalità

Analisi del movimento

Gemini Flash

Analizzare il video per movimento del corpo, fasi e stile

Generazione di avatar

Gemini Flash Image (Nano Banana)

Genera un avatar stilizzato 1024×1024 da un fotogramma chiave

Generazione di video

Veo 3.1

Crea un video AI dal prompt dell'avatar e del movimento

Backend

FastAPI + Python 3.11

Server API con orchestrazione della pipeline asincrona

Frontend

React + Vite + TypeScript

Interfaccia utente del kiosk con registrazione della videocamera e stato live

Hosting

Cloud Run

Deployment serverless containerizzato

Spazio di archiviazione

Google Cloud Storage

Caricamenti di video, frame, output tagliati e composti

2. 📦 Clona il repository

1. Apri editor di Cloud Shell

👉 Apri Cloud Shell Editor nel browser.

Se il terminale non viene visualizzato nella parte inferiore dello schermo:

  • Fai clic su Visualizza.
  • Fai clic su Terminale.

2. Clona il codice

👉💻 Nel terminale, clona il repository:

cd ~
git clone https://github.com/cuppibla/gemini-motion-lab-starter.git
cd gemini-motion-lab-starter

3. Esplora la struttura del progetto

Dai un'occhiata rapida al layout del repository:

gemini-motion-lab-starter/
├── backend/                     # FastAPI backend (Python 3.11)
   ├── app/
      ├── main.py              # FastAPI app entry point
      ├── config.py            # Environment-based settings
      ├── routers/             # API endpoints (upload, analyze, generate, share...)
      ├── services/            # Business logic (Gemini, Veo, storage, pipeline...)
      └── prompts/             # AI prompt templates
   ├── Dockerfile
   └── pyproject.toml
├── frontend/                    # React + Vite + TypeScript
   ├── src/                     # React components
   ├── public/                  # Static assets
   ├── Dockerfile
   └── nginx.conf
├── init.sh                      # Create GCP project & link billing
├── billing-enablement.py        # Auto-link billing account
├── setup.sh                     # Create GCS bucket, service account, .env
└── scripts/                     # Utility scripts

3. 🛠️ Richiedi crediti e crea un progetto Google Cloud

Parte 1: richiedi i tuoi crediti di fatturazione

👉 Richiedi il credito del tuo account di fatturazione utilizzando il tuo account Gmail.

Parte 2: crea un nuovo progetto

👉💻 Nel terminale, rendi eseguibile lo script init ed eseguilo:

cd ~/gemini-motion-lab-starter
chmod +x init.sh
./init.sh

Lo script init.sh:

  1. Crea un nuovo progetto Google Cloud con il prefisso gemini-motion-lab
  2. Salva l'ID progetto in ~/project_id.txt
  3. Installa le dipendenze di fatturazione e collega automaticamente il tuo account di fatturazione

Parte 3: configura il progetto e abilita le API

👉💻 Imposta l'ID progetto nel terminale:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Abilita le API Cloud di Google necessarie per questo progetto (questa operazione richiede circa 1-2 minuti):

gcloud services enable \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    aiplatform.googleapis.com \
    storage.googleapis.com \
    artifactregistry.googleapis.com

4. 🧠 [SOLO LETTURA] Informazioni sull'architettura

Questa sezione spiega come funziona la pipeline AI end-to-end. Nessuna azione necessaria: leggi per comprendere il sistema prima dell'implementazione.

La pipeline AI

Quando un utente registra un clip di movimento al chiosco, vengono eseguite cinque fasi in sequenza:

Fase 1: caricamento del video

Il frontend registra un clip WebM di 5 secondi dalla videocamera dell'utente e lo carica su Google Cloud Storage tramite l'endpoint /api/upload del backend.

POST /api/upload/{video_id}    gs://BUCKET/uploads/{video_id}.webm

Fase 2: analisi del movimento di Gemini

Il backend invia il video caricato a Gemini Flash (gemini-3-flash-preview) per l'analisi strutturata.

Come funziona (backend/app/services/gemini_service.py):

Il servizio utilizza client.models.generate_content() dell'SDK Vertex AI con il video come input Part.from_uri e un prompt strutturato. response_mime_type="application/json" garantisce che Gemini restituisca un JSON analizzabile. Il modello utilizza anche ThinkingConfig(thinking_budget=1024) per un migliore ragionamento sulle fasi del movimento.

# Simplified from gemini_service.py
response = client.models.generate_content(
    model="gemini-3-flash-preview",
    contents=[
        types.Part.from_uri(file_uri=gcs_uri, mime_type="video/webm"),
        MOTION_ANALYSIS_PROMPT,  # detailed prompt template
    ],
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        thinking_config=types.ThinkingConfig(thinking_budget=1024),
    ),
)
analysis = json.loads(response.text)

Fase 3: generazione dell'avatar Nano Banana

Utilizzando il fotogramma migliore estratto dal video, Gemini Flash Image (gemini-3.1-flash-image-preview) genera un avatar stilizzato 1024×1024.

Come funziona (backend/app/services/nano_banana_service.py):

# Simplified from nano_banana_service.py
response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents=[
        types.Content(role="user", parts=[
            types.Part.from_bytes(data=frame_bytes, mime_type="image/png"),
            types.Part.from_text(text=avatar_prompt),
        ])
    ],
    config=types.GenerateContentConfig(
        response_modalities=["IMAGE"],
        image_config=types.ImageConfig(
            aspect_ratio="1:1",
            output_mime_type="image/png",
        ),
    ),
)

Il PNG dell'avatar generato viene caricato in GCS e passato alla fase successiva.

Fase 4: generazione di video con Veo

L'immagine dell'avatar viene utilizzata come asset di riferimento per Veo 3.1 (veo-3.1-fast-generate-001) per generare un video AI di 8 secondi.

Come funziona (backend/app/services/veo_service.py):

# Simplified from veo_service.py
config = GenerateVideosConfig(
    reference_images=[
        VideoGenerationReferenceImage(
            image=Image(gcs_uri=avatar_gcs_uri, mime_type="image/png"),
            reference_type="ASSET",
        )
    ],
    aspect_ratio="16:9",
    duration_seconds=8,
    output_gcs_uri=f"gs://{BUCKET}/output/{video_id}/",
)
operation = client.models.generate_videos(
    model="veo-3.1-fast-generate-001",
    prompt=veo_prompt,
    config=config,
)

La generazione di Veo è asincrona: restituisce immediatamente un ID operazione. Il backend esegue il polling dell'operazione fino al completamento (fino a 10 minuti).

Fase 5: pipeline di post-elaborazione

Una volta completata l'operazione, Veo esegue automaticamente la pipeline in background (backend/app/services/pipeline.py):

  1. Taglia l'output di Veo di 8 secondi a 3 secondi
  2. Componi un video affiancato (registrazione originale a sinistra, video AI a destra)
  3. Carica il video composto su GCS.
  4. Rilascia lo slot della coda

Questa pipeline viene eseguita in background asyncio.Task, quindi il frontend del chiosco non deve attendere.

Il sistema di coda

Poiché la generazione di Veo richiede molte risorse, il sistema impone un massimo di 3 job simultanei:

# backend/app/routers/queue.py
MAX_CONCURRENT_JOBS = 3

@router.get("/queue/status")
async def queue_status():
    return {
        "active_jobs": len(_active_jobs),
        "max_jobs": MAX_CONCURRENT_JOBS,
        "available": len(_active_jobs) < MAX_CONCURRENT_JOBS,
    }

Il frontend controlla GET /api/queue/status prima di consentire a un nuovo utente di avviare una sessione. Quando una pipeline viene completata e chiama complete(video_id), lo slot si apre per l'utente successivo.

Cloud Run - Container serverless

Sia il backend che il frontend vengono implementati come servizi Cloud Run:

Servizio

Finalità

Configurazione della chiave

Backend

Server API FastAPI

2 GiB di memoria (per l'elaborazione video tramite ffmpeg)

Frontend

App React statica gestita da Nginx

Memoria predefinita

5. ⚙️ Esegui lo script di configurazione

1. Esegui la configurazione automatica

Lo script setup.sh crea le risorse cloud richieste e genera il file .env.

👉💻 Rendi eseguibile lo script ed eseguilo:

cd ~/gemini-motion-lab-starter
chmod +x setup.sh
./setup.sh

2. Concedi ruoli IAM

Ora concedi le autorizzazioni necessarie al service account.

👉💻 Esegui questi comandi per impostare l'ID progetto e concedere tutti e tre i ruoli:

export PROJECT_ID=$(cat ~/project_id.txt)

# 1. Storage Admin — upload/download videos and frames
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:gemini-motion-lab-sa@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/storage.admin"

# 2. Vertex AI User — call Gemini and Veo models
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:gemini-motion-lab-sa@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"

# 3. Service Account Token Creator — generate signed URLs for GCS
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
COMPUTE_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"

gcloud iam service-accounts add-iam-policy-binding \
  gemini-motion-lab-sa@${PROJECT_ID}.iam.gserviceaccount.com \
  --project=$PROJECT_ID \
  --member="serviceAccount:${COMPUTE_SA}" \
  --role="roles/iam.serviceAccountTokenCreator"

3. Verifica del file .env

👉💻 Controlla il file .env generato:

cat .env

Dovresti vedere:

GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1
GCS_BUCKET=gemini-motion-lab-your-project-id
GCS_SIGNING_SA=gemini-motion-lab-sa@your-project-id.iam.gserviceaccount.com
GOOGLE_GENAI_USE_VERTEXAI=true
MOCK_AI=false

6. 🚀 Esegui il deployment del backend

1. Informazioni sul Dockerfile di backend

Prima del deployment, vediamo com'è fatto il container:

# backend/Dockerfile
FROM python:3.11-slim                           # Python base image
RUN apt-get update && apt-get install -y \
    ffmpeg libgl1 libglib2.0-0 \                # ffmpeg for video processing
    && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir .                # Install Python dependencies
COPY app/ ./app/                                # Copy application code
EXPOSE 8080
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]

2. Esegui il deployment in Cloud Run

👉💻 Carica le variabili di ambiente ed esegui il deployment:

source .env

cd ~/gemini-motion-lab-starter/backend

gcloud run deploy gemini-motion-lab-backend \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --min-instances 1 \
  --max-instances 3 \
  --memory 2Gi \
  --port 8080 \
  --project $GOOGLE_CLOUD_PROJECT \
  --set-env-vars "GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GCS_BUCKET=$GCS_BUCKET,GCS_SIGNING_SA=$GCS_SIGNING_SA,GOOGLE_GENAI_USE_VERTEXAI=$GOOGLE_GENAI_USE_VERTEXAI,MOCK_AI=$MOCK_AI"

L'operazione richiede circa 3-5 minuti. Cloud Build:

  1. Caricare il codice sorgente
  2. Crea l'immagine Docker
  3. Esegui il push in Artifact Registry
  4. Esegui il deployment in Cloud Run

3. Salva l'URL di backend

👉💻 Una volta eseguito il deployment, salva l'URL di backend:

BACKEND_URL=$(gcloud run services describe gemini-motion-lab-backend \
  --region us-central1 \
  --format="value(status.url)" \
  --project $GOOGLE_CLOUD_PROJECT)

echo "Backend URL: $BACKEND_URL"

4. Aggiorna l'URL di condivisione del backend

Il backend genera codici QR in modo che gli utenti possano scaricare i propri video. Per farlo, deve conoscere il proprio URL pubblico.

👉💻 Aggiorna la configurazione del backend con il relativo URL:

gcloud run services update gemini-motion-lab-backend \
  --region us-central1 \
  --update-env-vars PUBLIC_BASE_URL=$BACKEND_URL \
  --project $GOOGLE_CLOUD_PROJECT

5. Verifica il backend

👉💻 Testa l'endpoint di integrità:

curl $BACKEND_URL/api/health

Output previsto:

{"status":"ok"}

👉💻 Controlla lo stato della coda:

curl $BACKEND_URL/api/queue/status

Output previsto:

{"active_jobs":0,"max_jobs":3,"available":true}

7. 🎨 Esegui il deployment del frontend

1. Comprendere il Dockerfile del frontend

Il frontend utilizza una compilazione in più fasi: prima compila l'app React, poi la pubblica con Nginx:

# frontend/Dockerfile
FROM node:20-alpine AS builder               # Stage 1: Build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_API_BASE=https://...                # Backend URL baked at build time
ENV VITE_API_BASE=$VITE_API_BASE
RUN npm run build                            # Produces static files in /app/dist

FROM nginx:alpine                            # Stage 2: Serve
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080

2. Esegui il deployment in Cloud Run

👉💻 Innanzitutto, scrivi l'URL di backend in un file .env in modo che Vite possa incorporarlo al tempo di compilazione:

cd ~/gemini-motion-lab-starter/frontend
echo "VITE_API_BASE=$BACKEND_URL" > .env

👉💻 Ora esegui il deployment del frontend:

gcloud run deploy gemini-motion-lab-frontend \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --min-instances 1 \
  --max-instances 3 \
  --port 8080 \
  --project $GOOGLE_CLOUD_PROJECT

L'operazione richiede circa 2-3 minuti.

3. Recuperare l'URL frontend

👉💻 Recupera e apri l'URL del frontend:

FRONTEND_URL=$(gcloud run services describe gemini-motion-lab-frontend \
  --region us-central1 \
  --format="value(status.url)" \
  --project $GOOGLE_CLOUD_PROJECT)

echo "🎬 Your Gemini Motion Lab is live at: $FRONTEND_URL"

👉 Apri l'URL nel browser: dovresti visualizzare l'interfaccia del chiosco Gemini Motion Lab.

8. 🎮 [FACOLTATIVO] Gioca con la demo

1. Registrare un movimento

  1. Apri l'URL frontend nel browser (preferibilmente Chrome per il miglior supporto della videocamera).
  2. Fai clic su Avvia per iniziare la registrazione.
  3. Balla o muoviti per circa 5 secondi. I movimenti ampi delle braccia e le pose dinamiche sono le più efficaci.
  4. La registrazione verrà interrotta e caricata automaticamente

2. Guarda la pipeline di AI

Dopo il caricamento, vedrai l'esecuzione della pipeline in tempo reale:

Fase

Che cosa sta succedendo

Durata

Analisi in corso…

Gemini Flash analizza il tuo video alla ricerca di schemi di movimento

~5-10s

Generazione dell'avatar in corso…

Nano Banana crea un avatar stilizzato a partire dal tuo fotogramma migliore

~8-12s

Creazione del video in corso…

Veo 3.1 genera un video AI a partire dal prompt dell'avatar e del movimento

~60-120 sec

Composizione…

ffmpeg taglia e crea un confronto fianco a fianco

~5-10s

3. Condividere la tua creazione

Al termine della pipeline:

  1. Sullo schermo del chiosco appare un codice QR.
  2. Scansiona il codice QR con lo smartphone
  3. Visualizzerai una pagina di condivisione ottimizzata per il mobile con il video composto.

4. Controllare i log di backend

👉💻 Scopri cosa è successo dietro le quinte:

gcloud logging read \
  "resource.type=cloud_run_revision AND resource.labels.service_name=gemini-motion-lab-backend" \
  --limit=30 \
  --project $GOOGLE_CLOUD_PROJECT \
  --format="value(timestamp,textPayload)" \
  --freshness=10m

Vedrai le righe di log che tracciano la pipeline:

Pipeline started for video_id=abc123
Gemini model used: gemini-3-flash-preview
Avatar generated: style=pixel-hero size=450KB time=8.2s
Veo model used: veo-3.1-fast-generate-001
Pipeline: Veo complete for video_id=abc123
Pipeline: trimmed video uploaded
Pipeline: composed video uploaded
Pipeline complete for video_id=abc123

5. Monitorare la coda

👉💻 Controlla quanti job sono in esecuzione:

curl $BACKEND_URL/api/queue/status

Se 3 sessioni sono attive contemporaneamente, la risposta mostrerà:

{"active_jobs":3,"max_jobs":3,"available":false}

Ai nuovi utenti verrà chiesto di attendere l'apertura di un posto.

9. 🎉 Conclusione

Cosa hai creato

Analisi del movimento AI: Gemini Flash analizza il video per movimento, tempo e stile

Generazione di avatar: Nano Banana crea avatar stilizzati a partire dai fotogrammi dei video

Creazione di video AI: Veo 3.1 genera nuovi video che corrispondono al movimento dell'utente

Pipeline asincrona: elaborazione in background con gestione delle code (max 3 simultanee)

Composizione affiancata: composizione video basata su ffmpeg

Deployment di Cloud Run: serverless, scalabilità automatica, nessuna gestione dei server

Concetti chiave che hai imparato

  1. Gemini Multimodal: invio di video come input e ricezione di analisi JSON strutturate
  2. Nano Banana (generazione di immagini di Gemini): utilizzo di immagini di riferimento e prompt di stile per generare avatar
  3. Veo 3.1: generazione di video asincrona con asset di riferimento e prompt di testo
  4. Cloud Run: deployment di container con variabili di ambiente e scalabilità automatica
  5. Pattern pipeline asincrona: attività in background fire-and-forget con asyncio.Task per operazioni di AI a lunga esecuzione
  6. Gestione delle code: limitazione della frequenza dei job di AI simultanei per controllare i costi e le quote API

Riepilogo dell'architettura

Passaggi successivi

  • Aggiungere altri stili di avatar: modifica backend/app/prompts/avatar_generation.py
  • Personalizzare il prompt di Veo: modifica backend/app/prompts/video_generation.py
  • Esegui localmente in modalità simulazione: imposta MOCK_AI=true in .env per lo sviluppo senza chiamate API
  • Scalabilità per gli eventi: aumenta --max-instances e MAX_CONCURRENT_JOBS

Risorse