🎬 Crea e implementa un laboratorio de movimiento con IA con Gemini, Veo y Cloud Run

1. Introducción

Qué compilará

Gemini Motion Lab es una experiencia interactiva potenciada por IA. Un usuario graba un clip corto de baile o movimiento, y el sistema hace lo siguiente:

  1. Analiza el movimiento con Gemini (partes del cuerpo, fases, ritmo, energía).
  2. Genera una imagen de avatar estilizada con Nano Banana (Gemini Flash Image)
  3. Crea un video de IA con Veo que recrea el movimiento con el avatar.
  4. Compone un video en paralelo (original y generado por IA)
  5. Comparte el resultado a través de un código QR en una página optimizada para dispositivos móviles.

Al final de este codelab, habrás implementado la demostración completa en Google Cloud Run y comprenderás la canalización de IA que la impulsa.

Descripción general de la arquitectura

Demostración final:

versión de canción

Tecnologías principales

Componente

Tecnología

Objetivo

Análisis de movimiento

Gemini Flash

Analiza el video para detectar el movimiento corporal, las fases y el estilo.

Generación de avatares

Gemini Flash Image (Nano Banana)

Genera un avatar estilizado de 1,024 × 1,024 a partir de un fotograma clave

Generación de video

Veo 3.1

Crea un video con IA a partir del avatar y la instrucción de movimiento

Backend

FastAPI + Python 3.11

Servidor de API con organización de canalizaciones asíncronas

Frontend

React + Vite + TypeScript

IU de kiosko con grabación de cámara y estado en vivo

Hosting

Cloud Run

Implementación sin servidores alojada en contenedores

Almacenamiento

Google Cloud Storage

Cargas de videos, fotogramas y salidas recortadas y compuestas

2. 📦 Clona el repositorio

1. Abre el editor de Cloud Shell

👉 Abre el Editor de Cloud Shell en tu navegador.

Si la terminal no aparece en la parte inferior de la pantalla, haz lo siguiente:

  • Haz clic en Ver.
  • Haz clic en Terminal.

2. Clona el código

👉💻 En la terminal, clona el repositorio:

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

3. Explora la estructura del proyecto

Echa un vistazo rápido al diseño del repositorio:

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. 🛠️ Reclama créditos y crea un proyecto de GCP

Parte 1: Reclama tus créditos de facturación

👉 Reclama el crédito de tu cuenta de facturación con tu cuenta de Gmail.

Parte 2: Crea un proyecto nuevo

👉💻 En la terminal, haz que la secuencia de comandos de inicialización sea ejecutable y ejecútala:

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

La secuencia de comandos init.sh hará lo siguiente:

  1. Crea un proyecto de GCP nuevo con el prefijo gemini-motion-lab.
  2. Guarda el ID del proyecto en ~/project_id.txt.
  3. Instala dependencias de facturación y vincula automáticamente tu cuenta de facturación

Parte 3: Configura el proyecto y habilita las APIs

👉💻 Establece tu ID del proyecto en la terminal:

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

👉💻 Habilita las APIs de Google Cloud necesarias para este proyecto (esto tarda entre 1 y 2 minutos):

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

4. 🧠 [SOLO LECTURA] Información sobre la arquitectura

En esta sección, se explica cómo funciona la canalización de IA de extremo a extremo. No se requiere ninguna acción: Solo lee para comprender el sistema antes de la implementación.

La canalización de IA

Cuando un usuario graba un clip de movimiento en la estación, se ejecutan cinco etapas en secuencia:

Etapa 1: Carga de videos

El frontend graba un clip de WebM de 5 segundos desde la cámara del usuario y lo sube a Google Cloud Storage a través del extremo /api/upload del backend.

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

Etapa 2: Análisis de movimiento con Gemini

El backend envía el video subido a Gemini Flash (gemini-3-flash-preview) para su análisis estructurado.

Cómo funciona (backend/app/services/gemini_service.py):

El servicio usa client.models.generate_content() del SDK de Vertex AI con el video como entrada Part.from_uri y una instrucción estructurada. El parámetro response_mime_type="application/json" garantiza que Gemini devuelva un JSON analizable. El modelo también usa ThinkingConfig(thinking_budget=1024) para razonar mejor sobre las fases de movimiento.

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

Etapa 3: Generación de avatares con Nano Banana

Con el mejor fotograma extraído del video, Gemini Flash Image (gemini-3.1-flash-image-preview) genera un avatar estilizado de 1,024 × 1,024.

Cómo funciona (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",
        ),
    ),
)

El PNG del avatar generado se sube a GCS y se pasa a la siguiente etapa.

Etapa 4: Generación de video con Veo

La imagen del avatar se usa como un recurso de referencia para Veo 3.1 (veo-3.1-fast-generate-001) y generar un video de IA de 8 segundos.

Cómo funciona (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 generación de Veo es asíncrona, ya que muestra un ID de operación de inmediato. El backend sondea la operación hasta que se completa (hasta 10 minutos).

Etapa 5: Canalización de posprocesamiento

Una vez que Veo completa la tarea, se ejecuta automáticamente la canalización en segundo plano (backend/app/services/pipeline.py):

  1. Corta el video de 8 s generado por Veo a 3 segundos.
  2. Compón un video en paralelo (grabación original a la izquierda y video de IA a la derecha).
  3. Sube el video compuesto a GCS.
  4. Libera el espacio de la fila.

Esta canalización se ejecuta como un asyncio.Task en segundo plano, por lo que el frontend del kiosco no necesita esperar.

El sistema de filas

Dado que la generación de Veo requiere muchos recursos, el sistema aplica un máximo de 3 trabajos simultáneos:

# 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,
    }

El frontend realiza una verificación de GET /api/queue/status antes de permitir que un usuario nuevo inicie una sesión. Cuando se completa una canalización y se llama a complete(video_id), la ranura se abre para el siguiente usuario.

Cloud Run: Contenedores sin servidores

Tanto el backend como el frontend se implementan como servicios de Cloud Run:

Servicio

Objetivo

Configuración de la llave

Backend

Servidor de la API de FastAPI

2 GiB de memoria (para el procesamiento de video a través de ffmpeg)

Frontend

App de React estática publicada por Nginx

Memoria predeterminada

5. ⚙️ Ejecutar secuencia de comandos de configuración

1. Ejecuta la configuración automática

La secuencia de comandos setup.sh crea los recursos de Cloud necesarios y genera tu archivo .env.

👉💻 Haz que la secuencia de comandos sea ejecutable y ejecútala:

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

2. Otorga roles de IAM

Ahora otorga los permisos necesarios a la cuenta de servicio.

👉💻 Ejecuta los siguientes comandos para establecer el ID del proyecto y otorgar los tres roles:

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 tu archivo de .env

👉💻 Comprueba el archivo .env generado:

cat .env

Deberías ver lo siguiente:

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. 🚀 Implementa el backend

1. Información sobre el Dockerfile de backend

Antes de la implementación, veamos cómo se ve el contenedor:

# 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. Implementa en Cloud Run

👉💻 Carga tus variables de entorno y realiza la implementación:

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"

Este proceso tarda entre 3 y 5 minutos. Cloud Build hará lo siguiente:

  1. Sube tu código fuente
  2. Compila la imagen de Docker
  3. Envía el contenedor a Artifact Registry
  4. Implementa en Cloud Run

3. Cómo guardar la URL del backend

👉💻 Una vez que se implemente, guarda la URL del 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. Actualiza la URL de uso compartido del backend

El backend genera códigos QR para que los usuarios puedan descargar sus videos. Para ello, debe conocer su propia URL pública.

👉💻 Actualiza la configuración del backend con su propia 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 el backend

👉💻 Prueba el extremo de estado:

curl $BACKEND_URL/api/health

Resultado esperado:

{"status":"ok"}

👉💻 Verifica el estado de la fila:

curl $BACKEND_URL/api/queue/status

Resultado esperado:

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

7. 🎨 Implementa el frontend

1. Información sobre el Dockerfile del frontend

El frontend usa una compilación de varias etapas: primero compila la app de React y, luego, la entrega 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. Implementa en Cloud Run

👉💻 Primero, escribe la URL de backend en un archivo .env para que Vite pueda incorporarla en el tiempo de compilación:

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

👉💻 Ahora implementa el 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

Este proceso tarda entre 2 y 3 minutos.

3. Obtén la URL de frontend

👉💻 Recupera y abre la 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"

👉 Abre la URL en tu navegador. Deberías ver la interfaz de la estación de Gemini Motion Lab.

8. 🎮 [OPCIONAL] Juega con la demostración

1. Cómo grabar un movimiento

  1. Abre la URL de frontend en tu navegador (preferentemente Chrome para obtener la mejor compatibilidad con la cámara).
  2. Haz clic en Iniciar para comenzar a grabar.
  3. Baila o muévete durante unos 5 segundos. Los movimientos grandes de los brazos y las poses dinámicas funcionan mejor.
  4. La grabación se detendrá y subirá automáticamente.

2. Observa la canalización de IA

Después de la carga, verás la ejecución de la canalización en tiempo real:

Fase

Qué sucede

Duración

Analizando…

Gemini Flash analiza tu video en busca de patrones de movimiento

Entre 5 y 10 s

Generando avatar…

Nano Banana crea un avatar estilizado a partir de tu mejor fotograma

Aprox. 8 a 12 s

Creando video…

Veo 3.1 genera un video de IA a partir del avatar y la instrucción de movimiento.

Entre 60 y 120 s

Redactando…

ffmpeg recorta y crea una comparación en paralelo

Entre 5 y 10 s

3. Comparte tu creación

Una vez que se complete la canalización, haz lo siguiente:

  1. Aparecerá un código QR en la pantalla de la estación de carga.
  2. Escanea el código QR con tu teléfono.
  3. Verás una página para compartir optimizada para dispositivos móviles con el video que creaste.

4. Verifica los registros de backend

👉💻 Mira lo que sucedió tras bambalinas:

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

Verás líneas de registro que rastrean la canalización:

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. Supervisa la fila

👉💻 Comprueba cuántos trabajos se están ejecutando:

curl $BACKEND_URL/api/queue/status

Si hay 3 sesiones activas de forma simultánea, la respuesta mostrará lo siguiente:

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

A los usuarios nuevos se les pedirá que esperen hasta que se abra un espacio.

9. 🎉 Conclusión

Qué compilaste

Análisis de movimiento con IA: Gemini Flash analiza el movimiento, el ritmo y el estilo de los videos.

Generación de avatares: Nano Banana crea avatares estilizados a partir de fotogramas de video.

Generación de video con IA: Veo 3.1 genera videos nuevos que coinciden con el movimiento del usuario.

Async Pipeline: Procesamiento en segundo plano con administración de filas (máx. 3 procesos simultáneos)

Composición en paralelo: Composición de video con tecnología de ffmpeg

Implementación de Cloud Run: Sin servidores, con ajuste de escala automático y sin administración de servidores

Conceptos clave que aprendiste

  1. Gemini Multimodal: Envía videos como entrada y recibe análisis estructurados en formato JSON
  2. Nano Banana (generación de imágenes con Gemini): Uso de imágenes de referencia y mensajes de estilo para generar avatares
  3. Veo 3.1: Generación asíncrona de videos con recursos de referencia y mensajes de texto
  4. Cloud Run: Implementación de contenedores con variables de entorno y escalamiento automático
  5. Patrón de canalización asíncrona: Tareas en segundo plano de activación y recuperación con asyncio.Task para operaciones de IA de larga duración
  6. Administración de filas: Limita la frecuencia de los trabajos simultáneos de IA para controlar los costos y las cuotas de la API

Recap de arquitectura

¿Qué sigue?

  • Agregar más estilos de avatar: Edita backend/app/prompts/avatar_generation.py.
  • Personaliza la instrucción de Veo: Edita backend/app/prompts/video_generation.py
  • Ejecuta de forma local en modo de simulación: Establece MOCK_AI=true en .env para el desarrollo sin llamadas a la API
  • Escala para eventos: Aumenta --max-instances y MAX_CONCURRENT_JOBS

Recursos