Codelab: Crea una app contextual de recomendación de posturas de yoga con Firestore, Búsqueda de vectores, Langchain y Gemini (versión de Python)

1. Introducción

En este codelab, compilarás una aplicación que usa la búsqueda vectorial para recomendar posturas de yoga.

En el codelab, seguirás un enfoque paso a paso de la siguiente manera:

  1. Utiliza un conjunto de datos existente de Hugging Face con posturas de yoga (formato JSON).
  2. Mejora el conjunto de datos con una descripción de campo adicional que usa Gemini para generar descripciones de cada una de las poses.
  3. Usa Langchain para crear un documento y la integración de Langchain de Firestore para crear la colección y las incorporaciones en Firestore.
  4. Crea un índice compuesto en Firestore para permitir la búsqueda de vectores.
  5. Utiliza la búsqueda vectorial en una aplicación de Flask que reúne todo, como se muestra a continuación:

84e1cbf29cbaeedc.png

Actividades

  • Diseña, compila e implementa una aplicación web que emplee Vector Search para recomendar posturas de yoga.

Qué aprenderás

  • Cómo usar Gemini para generar contenido de texto y, en el contexto de este codelab, generar descripciones para posturas de yoga
  • Cómo usar Langchain Document Loader para Firestore para cargar registros de un conjunto de datos mejorado de Hugging Face en Firestore junto con incorporaciones de vectores
  • Cómo usar Langchain Vector Store para Firestore para buscar datos según una consulta en lenguaje natural
  • Cómo usar la API de Google Cloud Text-to-Speech para generar contenido de audio

Requisitos

  • Navegador web Chrome
  • Una cuenta de Gmail
  • Un proyecto de Cloud con la facturación habilitada

Este codelab, diseñado para desarrolladores de todos los niveles (incluidos los principiantes), usa Python en su aplicación de ejemplo. Sin embargo, no es necesario tener conocimientos de Python para comprender los conceptos presentados.

2. Antes de comenzar

Crea un proyecto

  1. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto .
  3. Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en Google Cloud y que viene precargado con bq. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud.

Imagen del botón Activar Cloud Shell

  1. Una vez que te conectes a Cloud Shell, verifica que ya te autenticaste y que el proyecto se configuró con tu ID del proyecto usando el siguiente comando:
gcloud auth list
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto.
gcloud config list project
  1. Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>
  1. Habilita las APIs requeridas con el comando que se muestra a continuación. Este proceso puede tardar unos minutos, así que ten paciencia.
gcloud services enable firestore.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudfunctions.googleapis.com \
                       aiplatform.googleapis.com \
                       texttospeech.googleapis.com

Cuando el comando se ejecute correctamente, deberías ver un mensaje similar al que se muestra a continuación:

Operation "operations/..." finished successfully.

La alternativa al comando de gcloud es buscar cada producto en la consola o usar este vínculo.

Si olvidas alguna API, siempre puedes habilitarla durante el curso de la implementación.

Consulta la documentación para ver los comandos y el uso de gcloud.

Clona el repositorio y configura los parámetros del entorno

El siguiente paso es clonar el repositorio de muestra al que haremos referencia en el resto del codelab. Si suponemos que estás en Cloud Shell, ejecuta el siguiente comando desde tu directorio principal:

git clone https://github.com/rominirani/yoga-poses-recommender-python

Para iniciar el editor, haz clic en Abrir editor en la barra de herramientas de la ventana de Cloud Shell. Haz clic en la barra de menú en la esquina superior izquierda y selecciona Archivo → Abrir carpeta, como se muestra a continuación:

66221fd0d0e5202f.png

Selecciona la carpeta yoga-poses-recommender-python y verás que se abre con los siguientes archivos, como se muestra a continuación:

44699efc7fb1b911.png

Ahora debemos configurar las variables de entorno que usaremos. Haz clic en el archivo config.template.yaml y deberías ver el contenido como se muestra a continuación:

project_id: your-project-id
location: us-central1
gemini_model_name: gemini-1.5-flash-002
embedding_model_name: text-embedding-004
image_generation_model_name: imagen-3.0-fast-generate-002
database: (default)
collection: poses
test_collection: test-poses
top_k: "3"

Actualiza los valores de project_id y location según lo que seleccionaste cuando creaste el proyecto de Google Cloud y la región de la base de datos de Firestore. Lo ideal sería que los valores de location fueran los mismos para el proyecto de Google Cloud y la base de datos de Firestore, por ejemplo, us-central1.

Para los fines de este codelab, usaremos los valores preconfigurados (excepto, por supuesto, project_id y location, que debes establecer según tu configuración).

Guarda este archivo como config.yaml en la misma carpeta que el archivo config.template.yaml.

El último paso es crear un entorno de Python que usaremos de forma local con todas las dependencias de Python configuradas para nosotros. Echa un vistazo al archivo pyproject.toml que contiene los detalles de la misma, cuyo contenido se muestra a continuación:

dependencies = [
    "datasets>=3.2.0",
    "flask>=3.1.0",
    "google-cloud-aiplatform>=1.78.0",
    "google-cloud-texttospeech>=2.24.0",
    "langchain-community>=0.3.15",
    "langchain-core>=0.3.31",
    "langchain-google-community>=2.0.4",
    "langchain-google-firestore>=0.5.0",
    "langchain-google-vertexai>=2.0.7",
    "pydantic-settings>=2.7.1",
    "pyyaml>=6.0.2",
    "tenacity>=9.0.0",
]

Estas dependencias ya están bloqueadas en la versión de requirements.txt.. En resumen, debemos crear un entorno virtual de Python con las dependencias del paquete de Python en requirements.txt para que se instalen en el entorno virtual. Para ello, ve a Command Palette (Ctrl + Mayúsculas + P) en el IDE de Cloud Shell y escribe Python: Create Environment. Sigue los próximos pasos para seleccionar un archivo Virtual Environment(venv), Python 3.x interpreter y requirements.txt.

Una vez que se cree el entorno, deberemos activarlo con el siguiente comando:

source .venv/bin/activate

Deberías ver (.venv) en la consola. P.ej., -> (.venv) yourusername@cloudshell:

¡Excelente! Ahora sí, podemos continuar con la tarea de configurar la base de datos de Firestore.

3. Configura Firestore

Cloud Firestore es una base de datos de documentos sin servidores completamente administrada que usaremos como backend para los datos de nuestra aplicación. Los datos de Cloud Firestore se estructuran en colecciones de documentos.

Inicialización de la base de datos de Firestore

Visita la página de Firestore en la consola de Cloud.

Si no inicializaste una base de datos de Firestore antes en el proyecto, haz clic en Create Database para crear la base de datos default. Durante la creación de la base de datos, usa los siguientes valores:

  • Modo de Firestore: Native.
  • Selecciona Region como el tipo de ubicación y la ubicación us-central1 para la región.
  • En el caso de las reglas de seguridad, elige Test rules.
  • Crea la base de datos.

61d0277510803c8d.png

En la siguiente sección, sentaremos las bases para crear una colección llamada poses en nuestra base de datos predeterminada de Firestore. Esta colección contendrá datos de muestra (documentos) o información sobre posturas de yoga, que luego usaremos en nuestra aplicación.

Con esto, se completa la sección de configuración de la base de datos de Firestore.

4. Prepara el conjunto de datos de posturas de yoga

Nuestra primera tarea es preparar el conjunto de datos de posturas de yoga que usaremos para la aplicación. Comenzaremos con un conjunto de datos existente de Hugging Face y, luego, lo mejoraremos con información adicional.

Consulta el conjunto de datos de Hugging Face para posturas de yoga. Ten en cuenta que, si bien este codelab usa uno de los conjuntos de datos, puedes usar cualquier otro y seguir las mismas técnicas que se demostraron para mejorar el conjunto de datos.

298cfae7f23e4bef.png

Si vamos a la sección Files and versions, podemos obtener el archivo de datos JSON para todas las poses.

3fe6e55abdc032ec.png

Descargamos el archivo yoga_poses.json y te lo proporcionamos. Este archivo se llama yoga_poses_alldata.json y se encuentra en la carpeta /data.

Ve al archivo data/yoga_poses.json en el editor de Cloud Shell y observa la lista de objetos JSON, en la que cada objeto JSON representa una postura de yoga. Tenemos un total de 3 registros, y a continuación se muestra un registro de muestra:

{
   "name": "Big Toe Pose",
   "sanskrit_name": "Padangusthasana",
   "photo_url": "https://pocketyoga.com/assets/images/full/ForwardBendBigToe.png",
   "expertise_level": "Beginner",
   "pose_type": ["Standing", "Forward Bend"]
 }

Ahora es un buen momento para presentar Gemini y cómo podemos usar el modelo predeterminado para generar un campo description para él.

En el Editor de Cloud Shell, ve al archivo generate-descriptions.py. El contenido de este archivo se muestra a continuación:

import json
import time
import logging
import vertexai
from langchain_google_vertexai import VertexAI
from tenacity import retry, stop_after_attempt, wait_exponential
from settings import get_settings

settings = get_settings()
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
# Initialize Vertex AI SDK
vertexai.init(project=settings.project_id, location=settings.location)
logging.info("Done Initializing Vertex AI SDK")


@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=4, max=10),
)
def generate_description(pose_name, sanskrit_name, expertise_level, pose_types):
    """Generates a description for a yoga pose using the Gemini API."""

    prompt = f"""
    Generate a concise description (max 50 words) for the yoga pose: {pose_name}
    Also known as: {sanskrit_name}
    Expertise Level: {expertise_level}
    Pose Type: {", ".join(pose_types)}

    Include key benefits and any important alignment cues.
    """
    try:
        model = VertexAI(model_name=settings.gemini_model_name, verbose=True)
        response = model.invoke(prompt)
        return response
    except Exception as e:
        logging.info(f"Error generating description for {pose_name}: {e}")
        return ""


def add_descriptions_to_json(input_file, output_file):
    """Loads JSON data, adds descriptions, and saves the updated data."""

    with open(input_file, "r") as f:
        yoga_poses = json.load(f)

    total_poses = len(yoga_poses)
    processed_count = 0

    for pose in yoga_poses:
        if pose["name"] != " Pose":
            start_time = time.time()  # Record start time
            pose["description"] = generate_description(
                pose["name"],
                pose["sanskrit_name"],
                pose["expertise_level"],
                pose["pose_type"],
            )
            end_time = time.time()  # Record end time

            processed_count += 1
            end_time = time.time()  # Record end time
            time_taken = end_time - start_time
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )

        else:
            pose["description"] = ""
            processed_count += 1
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )
        # Adding a delay to avoid rate limit
        time.sleep(30)

    with open(output_file, "w") as f:
        json.dump(yoga_poses, f, indent=2)


def main():
    # File paths
    input_file = "./data/yoga_poses.json"
    output_file = "./data/yoga_poses_with_descriptions.json"

    # Add descriptions and save the updated JSON
    add_descriptions_to_json(input_file, output_file)


if __name__ == "__main__":
    main()

Esta aplicación agregará un nuevo campo description a cada registro JSON de la postura de yoga. Obtendrá la descripción a través de una llamada al modelo de Gemini, en la que le proporcionaremos la instrucción necesaria. El campo se agrega al archivo JSON y el archivo nuevo se escribe en el archivo data/yoga_poses_with_descriptions.json.

Veamos los pasos principales:

  1. En la función main(), verás que invoca la función add_descriptions_to_json y proporciona el archivo de entrada y el archivo de salida esperados.
  2. La función add_descriptions_to_json hace lo siguiente para cada registro JSON, es decir, la información de la publicación de yoga:
  3. Extrae pose_name, sanskrit_name, expertise_level y pose_types.
  4. Invoca la función generate_description que crea una instrucción y, luego, invoca la clase del modelo Langchain VertexAI para obtener el texto de respuesta.
  5. Luego, este texto de respuesta se agrega al objeto JSON.
  6. Luego, la lista de objetos JSON actualizada se escribe en el archivo de destino.

Ejecutemos esta aplicación. Inicia una nueva ventana de terminal (Ctrl + Mayúsculas + C) y ejecuta el siguiente comando:

python generate-descriptions.py

Si se te solicita alguna autorización, proporciónala.

Verás que la aplicación comienza a ejecutarse. Agregamos una demora de 30 segundos entre los registros para evitar las cuotas de límite de frecuencia que podrían existir en las cuentas nuevas de Google Cloud, así que ten paciencia.

A continuación, se muestra un ejemplo de una ejecución en curso:

8e830d9ea9b6c60.png

Una vez que los 3 registros se hayan mejorado con la llamada a Gemini, se generará un archivo data/yoga_poses_with_description.json. Puedes echarle un vistazo.

Ahora tenemos listo nuestro archivo de datos, y el siguiente paso es comprender cómo completar una base de datos de Firestore con él, junto con la generación de incorporaciones.

5. Importa datos a Firestore y genera embeddings de vectores

Tenemos el archivo data/yoga_poses_with_description.json y ahora debemos propagar la base de datos de Firestore con él y, lo que es más importante, generar los embeddings de vectores para cada uno de los registros. Los embeddings de vectores serán útiles más adelante cuando tengamos que realizar una búsqueda de similitud en ellos con la consulta del usuario que se proporcionó en lenguaje natural.

Usaremos los componentes de Langchain Firestore para implementar el proceso anterior.

Para hacerlo, sigue estos pasos:

  1. Convertiremos la lista de objetos JSON en una lista de objetos Langchain Document. Cada documento tendrá dos atributos: page_content y metadata. El objeto de metadatos contendrá todo el objeto JSON que tiene atributos como name, description, sanskrit_name, etcétera. El page_content será un texto de cadena que será una concatenación de algunos campos.
  2. Una vez que tengamos una lista de objetos Document, usaremos la clase FirestoreVectorStore de Langchain y, específicamente, el método from_documents con esta lista de documentos, un nombre de colección (usaremos la variable TEST_COLLECTION que apunta a test-poses), una clase de Vertex AI Embedding y los detalles de conexión de Firestore (nombres PROJECT_ID y DATABASE). Esto creará la colección y también generará un campo embedding para cada uno de los atributos.

A continuación, se muestra el código de import-data.py (se truncaron partes del código para mayor brevedad):

... 

def create_langchain_documents(poses):
   """Creates a list of Langchain Documents from a list of poses."""
   documents = []
   for pose in poses:
       # Convert the pose to a string representation for page_content
       page_content = (
           f"name: {pose.get('name', '')}\n"
           f"description: {pose.get('description', '')}\n"
           f"sanskrit_name: {pose.get('sanskrit_name', '')}\n"
           f"expertise_level: {pose.get('expertise_level', 'N/A')}\n"
           f"pose_type: {pose.get('pose_type', 'N/A')}\n"
       ).strip()
       # The metadata will be the whole pose
       metadata = pose

       document = Document(page_content=page_content, metadata=metadata)
       documents.append(document)
   logging.info(f"Created {len(documents)} Langchain documents.")
   return documents

def main():
    all_poses = load_yoga_poses_data_from_local_file(
        "./data/yoga_poses_with_descriptions.json"
    )
    documents = create_langchain_documents(all_poses)
    logging.info(
        f"Successfully created langchain documents. Total documents: {len(documents)}"
    )

    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore.from_documents(
        client=client,
        collection=settings.test_collection,
        documents=documents,
        embedding=embedding,
    )
    logging.info("Added documents to the vector store.")


if __name__ == "__main__":
    main()

Ejecutemos esta aplicación. Inicia una nueva ventana de terminal (Ctrl + Mayúsculas + C) y ejecuta el siguiente comando:

python import-data.py

Si todo sale bien, deberías ver un mensaje similar al siguiente:

2025-01-21 14:50:06,479 - INFO - Added documents to the vector store.

Para verificar si los registros se insertaron correctamente y si se generaron las incorporaciones, visita la página de Firestore en la consola de Cloud.

504cabdb99a222a5.png

Haz clic en la base de datos (predeterminada). Debería mostrar la colección test-poses y varios documentos en esa colección. Cada documento es una postura de yoga.

d0708499e403aebc.png

Haz clic en cualquiera de los documentos para investigar los campos. Además de los campos que importamos, también encontrarás el campo embedding, que es un campo de vector que se generó automáticamente para ti a través de la clase VertexAIEmbeddings de Langchain que usamos, en la que proporcionamos el modelo de incorporación text-embedding-004 de Vertex AI.

d67113e2dc63cd6b.png

Ahora que subimos los registros a la base de datos de Firestore con los embeddings, podemos pasar al siguiente paso y ver cómo realizar una búsqueda de similitud de vectores en Firestore.

6. Importa posturas de yoga completas a la colección de la base de datos de Firestore

Ahora crearemos la colección poses, que es una lista completa de 160 posturas de yoga para las que generamos un archivo de importación de base de datos que puedes importar directamente. Esto se hace para ahorrar tiempo en el lab. El proceso para generar la base de datos que contiene la descripción y las incorporaciones es el mismo que vimos en la sección anterior.

Sigue los pasos que se indican a continuación para importar la base de datos:

  1. Crea un bucket en tu proyecto con el comando gsutil que se indica a continuación. Reemplaza la variable <PROJECT_ID> en el siguiente comando por el ID de tu proyecto de Google Cloud.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
  1. Ahora que se creó el bucket, debemos copiar la exportación de la base de datos que preparamos en este bucket antes de poder importarla a la base de datos de Firebase. Usa el siguiente comando:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615  gs://<PROJECT_ID>-my-bucket

Ahora que tenemos los datos para importar, podemos pasar al paso final de importar los datos a la base de datos de Firebase (default) que creamos.

  1. Usa el siguiente comando de gcloud:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615

La importación tardará unos segundos y, cuando esté lista, podrás validar tu base de datos y colección de Firestore. Para ello, visita https://console.cloud.google.com/firestore/databases, selecciona la base de datos default y la colección poses, como se muestra a continuación:

a8f5a6ba69bec69b.png

Con esto, se completa la creación de la colección de Firestore que usaremos en nuestra aplicación.

7. Realiza una búsqueda de similitud de vectores en Firestore

Para realizar una búsqueda de similitud de vectores, tomaremos la consulta del usuario. Un ejemplo de esta consulta puede ser "Suggest me some exercises to relieve back pain".

Echa un vistazo al archivo search-data.py. La función clave que se debe observar es la de búsqueda, que se muestra a continuación. En un nivel superior, crea una clase de embedding que se usará para generar el embedding de la búsqueda del usuario. Luego, usa la clase FirestoreVectorStore para invocar su función similarity_search.

def search(query: str):
    """Executes Firestore Vector Similarity Search"""
    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore(
        client=client, collection=settings.collection, embedding_service=embedding
    )

    logging.info(f"Now executing query: {query}")
    results: list[Document] = vector_store.similarity_search(
        query=query, k=int(settings.top_k), include_metadata=True
    )
    for result in results:
        print(result.page_content)

Antes de ejecutar esta acción con algunos ejemplos de consultas, primero debes generar un índice compuesto de Firestore, que es necesario para que tus búsquedas se realicen correctamente. Si ejecutas la aplicación sin crear el índice, se mostrará un error que indica que primero debes crear el índice con el comando para crearlo.

A continuación, se muestra el comando gcloud para crear el índice compuesto:

gcloud firestore indexes composite create --project=<YOUR_PROJECT_ID> --collection-group=poses --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding

El índice tardará unos minutos en completarse, ya que hay más de 150 registros en la base de datos. Una vez que se complete, puedes ver el índice con el siguiente comando:

gcloud firestore indexes composite list

Deberías ver el índice que acabas de crear en la lista.

Prueba el siguiente comando ahora:

python search-data.py --prompt "Recommend me some exercises for back pain relief"

Deberías recibir algunas recomendaciones. A continuación, se muestra un ejemplo de ejecución:

2025-01-21 15:48:51,282 - INFO - Now executing query: Recommend me some exercises for back pain relief
name: Supine Spinal Twist Pose
description: A gentle supine twist (Supta Matsyendrasana), great for beginners.  Releases spinal tension, improves digestion, and calms the nervous system.  Keep shoulders flat on the floor and lengthen the spine.

sanskrit_name: Supta Matsyendrasana
expertise_level: Beginner
pose_type: ['Supine', 'Twist']
name: Cow Pose
description: Cow Pose (Bitilasana) is a gentle backbend, stretching the chest, shoulders, and abdomen.  Maintain a neutral spine, lengthen the tailbone, and avoid hyperextension.  Benefits include improved posture and stress relief.

sanskrit_name: Bitilasana
expertise_level: Beginner
pose_type: ['Arm Leg Support', 'Back Bend']
name: Locust I Pose
description: Locust Pose I (Shalabhasana A) strengthens the back, glutes, and shoulders.  Lie prone, lift chest and legs simultaneously, engaging back muscles.  Keep hips grounded and gaze slightly forward.

sanskrit_name: Shalabhasana A
expertise_level: Intermediate
pose_type: ['Prone', 'Back Bend']

Una vez que esto funcione, habremos comprendido cómo usar la base de datos de vectores de Firestore para subir registros, generar embeddings y realizar una búsqueda de similitud vectorial. Ahora podemos crear una aplicación web que integrará la búsqueda de vectores en un frontend web.

8. La aplicación web

La aplicación web de Flask en Python está disponible en el archivo main.py, y el archivo HTML de frontend está presente en templates/index.html..

Te recomendamos que revises ambos archivos. Comienza con el archivo main.py que contiene el controlador /search, que toma la instrucción que se pasó desde el archivo index.html HTML de frontend. Luego, se invoca el método de búsqueda, que realiza la búsqueda de similitud de vectores que vimos en la sección anterior.

Luego, la respuesta se envía de vuelta a index.html con la lista de recomendaciones. Luego, index.html muestra las recomendaciones como diferentes tarjetas.

Ejecuta la aplicación de manera local

Inicia una nueva ventana de terminal (Ctrl + Mayúsculas + C) o cualquier ventana de terminal existente y ejecuta el siguiente comando:

python main.py

A continuación, se muestra una ejecución de muestra:

 * Serving Flask app 'main'
 * Debug mode: on
2025-01-21 16:02:37,473 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.4:8080
2025-01-21 16:02:37,473 - INFO - Press CTRL+C to quit
2025-01-21 16:02:37,474 - INFO -  * Restarting with stat
2025-01-21 16:02:41,462 - WARNING -  * Debugger is active!
2025-01-21 16:02:41,484 - INFO -  * Debugger PIN: 440-653-555

Una vez que esté en funcionamiento, haz clic en el botón Vista previa en la Web que se muestra a continuación para visitar la URL principal de la aplicación:

de297d4cee10e0bf.png

Debería mostrarte el archivo index.html publicado, como se muestra a continuación:

20240a0e885ac17b.png

Proporciona una búsqueda de ejemplo (por ejemplo, Provide me some exercises for back pain relief) y haz clic en el botón Search. Esto debería recuperar algunas recomendaciones de la base de datos. También verás un botón Play Audio, que generará una transmisión de audio basada en la descripción que podrás escuchar directamente.

789b4277dc40e2be.png

9. (Opcional) Implementa en Google Cloud Run

Nuestro paso final será implementar esta aplicación en Google Cloud Run. A continuación, se muestra el comando de implementación. Asegúrate de reemplazar los valores de la variable (<<YOUR_PROJECT_ID>>) por los que son específicos de tu proyecto antes de implementarlo. Estos son los valores que podrás recuperar del archivo config.yaml.

gcloud run deploy yogaposes --source . \
  --port=8080 \
  --allow-unauthenticated \
  --region=us-central1 \
  --platform=managed  \
  --project=<<YOUR_PROJECT_ID>> \
  --env-vars-file=config.yaml

Ejecuta el comando anterior desde la carpeta raíz de la aplicación. También es posible que se te solicite que habilites las APIs de Google Cloud y que confirmes varios permisos. Si es así, hazlo.

El proceso de implementación tardará entre 5 y 7 minutos en completarse, así que ten paciencia.

3a6d86fd32e4a5e.png

Una vez que se implemente correctamente, el resultado de la implementación proporcionará la URL del servicio de Cloud Run. Tendrá el siguiente formato:

Service URL: https://yogaposes-<<UNIQUEID>.us-central1.run.app

Visita esa URL pública y deberías ver la misma aplicación web implementada y en ejecución correctamente.

84e1cbf29cbaeedc.png

También puedes visitar Cloud Run desde la consola de Google Cloud y verás la lista de servicios en Cloud Run. El servicio yogaposes debe ser uno de los servicios (si no el único) que se enumeran allí.

f2b34a8c9011be4c.png

Para ver los detalles del servicio, como la URL, las configuraciones, los registros y mucho más, haz clic en el nombre del servicio específico (yogaposes en nuestro caso).

faaa5e0c02fe0423.png

Con esto, se completa el desarrollo y la implementación de nuestra aplicación web de recomendación de posturas de yoga en Cloud Run.

10. Felicitaciones

¡Felicitaciones! Compilaste correctamente una aplicación que sube un conjunto de datos a Firestore, genera los embeddings y realiza una búsqueda de similitud de vectores basada en la consulta de los usuarios.

Documentos de referencia