Analizar datos multimodales con funciones definidas por el usuario de SQL y Python

En este tutorial se muestra cómo analizar datos multimodales mediante consultas de SQL y funciones definidas por el usuario (FDU) de Python.

En este tutorial se usa el catálogo de productos del conjunto de datos público de la tienda de mascotas Cymbal.

Objetivos

  • Usa valores de ObjectRef para almacenar datos de imagen junto con datos estructurados en una tabla estándar de BigQuery.
  • Genera texto a partir de datos de imagen de una tabla estándar mediante la función AI.GENERATE_TABLE.
  • Transforma imágenes que ya tengas para crear otras nuevas mediante una función definida por el usuario (UDF) de Python.
  • Divide PDFs en fragmentos para analizarlos más a fondo usando una función definida por el usuario de Python.
  • Usa un modelo de Gemini y la función ML.GENERATE_TEXT para analizar los datos del PDF en fragmentos.
  • Genera incrustaciones basadas en datos de imagen de una tabla estándar mediante la función ML.GENERATE_EMBEDDING.
  • Procesa datos multimodales ordenados mediante matrices de valores ObjectRef.

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

  • BigQuery: you incur costs for the data that you process in BigQuery.
  • BigQuery Python UDFs: you incur costs for using Python UDFs.
  • Cloud Storage: you incur costs for the objects stored in Cloud Storage.
  • Vertex AI: you incur costs for calls to Vertex AI models.

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Para obtener más información, consulta las siguientes páginas de precios:

Antes de empezar

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. Enable the BigQuery, BigQuery Connection, Cloud Storage, and Vertex AI APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

Roles obligatorios

Para obtener los permisos que necesitas para completar este tutorial, pide a tu administrador que te conceda los siguientes roles de gestión de identidades y accesos:

Para obtener más información sobre cómo conceder roles, consulta el artículo Gestionar el acceso a proyectos, carpetas y organizaciones.

También puedes conseguir los permisos necesarios a través de roles personalizados u otros roles predefinidos.

Configurar

En esta sección, creará el conjunto de datos, la conexión, las tablas y los modelos que se usan en este tutorial.

Crear conjunto de datos

Crea un conjunto de datos de BigQuery para que contenga los objetos que crees en este tutorial:

  1. En la Google Cloud consola, ve a la página BigQuery.

    Ir a BigQuery

  2. En el panel Explorador, selecciona tu proyecto.

  3. Abre la opción Acciones y haz clic en Crear conjunto de datos. Se abrirá el panel Crear conjunto de datos.

  4. En ID de conjunto de datos, escribe cymbal_pets.

  5. Haz clic en Crear conjunto de datos.

Crear un segmento

Crea un segmento de Cloud Storage para almacenar los objetos transformados:

  1. Ve a la página Segmentos.

    Ir a Contenedores

  2. Haz clic en Crear.

  3. En la página Crear un contenedor, en la sección Empezar, introduce un nombre único a nivel global que cumpla los requisitos de los nombres de los contenedores.

  4. Haz clic en Crear.

Crear una conexión

Crea una conexión de recursos de Cloud y obtén la cuenta de servicio de la conexión. BigQuery usa la conexión para acceder a los objetos de Cloud Storage:

  1. Ve a la página BigQuery.

    Ir a BigQuery

  2. En el panel Explorador, haz clic en Añadir datos.

    Se abrirá el cuadro de diálogo Añadir datos.

  3. En el panel Filtrar por, en la sección Tipo de fuente de datos, selecciona Aplicaciones empresariales.

    También puede introducir Vertex AI en el campo Buscar fuentes de datos.

  4. En la sección Fuentes de datos destacadas, haga clic en Vertex AI.

  5. Haz clic en la tarjeta de solución Modelos de Vertex AI: federación de BigQuery.

  6. En la lista Tipo de conexión, selecciona Modelos remotos, funciones remotas y BigLake (recurso de Cloud) de Vertex AI.

  7. En el campo Connection ID (ID de conexión), escribe cymbal_conn.

  8. Haga clic en Crear conexión.

  9. Haz clic en Ir a la conexión.

  10. En el panel Información de conexión, copie el ID de la cuenta de servicio para usarlo en un paso posterior.

Conceder permisos a la cuenta de servicio de la conexión

Concede a la cuenta de servicio de la conexión los roles adecuados para acceder a otros servicios. Debes asignar estos roles en el mismo proyecto que has creado o seleccionado en la sección Antes de empezar. Si se conceden los roles en otro proyecto, se produce el error bqcx-1234567890-xxxx@gcp-sa-bigquery-condel.iam.gserviceaccount.com does not have the permission to access resource.

Conceder permisos en el segmento de Cloud Storage

Da a la cuenta de servicio acceso para usar los objetos del segmento que has creado:

  1. Ve a la página Segmentos.

    Ir a Contenedores

  2. Haz clic en el nombre del segmento que has creado.

  3. Haz clic en Permisos.

  4. Haz clic en Conceder acceso. Se abrirá el cuadro de diálogo Dar acceso.

  5. En el campo Nuevos principales, introduce el ID de la cuenta de servicio que has copiado anteriormente.

  6. En el campo Selecciona un rol, elige Cloud Storage y, a continuación, selecciona Usuario de objetos de Storage.

  7. Haz clic en Guardar.

Conceder permisos para usar modelos de Vertex AI

Da acceso a la cuenta de servicio para usar los modelos de Vertex AI:

  1. Ve a la página IAM y administración.

    Ir a IAM y administración

  2. Haz clic en Conceder acceso. Se abrirá el cuadro de diálogo Dar acceso.

  3. En el campo Nuevos principales, introduce el ID de la cuenta de servicio que has copiado anteriormente.

  4. En el campo Selecciona un rol, elige Vertex AI y, a continuación, Usuario de Vertex AI.

  5. Haz clic en Guardar.

Crear las tablas de datos de ejemplo

Crea tablas para almacenar la información de los productos de mascotas de Cymbal.

Crea la tabla products.

Crea una tabla estándar que contenga la información de los productos de mascotas de Cymbal:

  1. En la Google Cloud consola, ve a la página BigQuery.

    Ir a BigQuery

  2. En el editor de consultas, ejecuta la siguiente consulta para crear la tabla products:

    LOAD DATA OVERWRITE cymbal_pets.products
    FROM
      FILES(
        format = 'avro',
        uris = [
          'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/tables/products/products_*.avro']);

Crea la tabla product_images.

Crea una tabla de objetos que contenga las imágenes de los productos de Cymbal Pets:

  • En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla product_images:

    CREATE OR REPLACE EXTERNAL TABLE cymbal_pets.product_images
      WITH CONNECTION `us.cymbal_conn`
      OPTIONS (
        object_metadata = 'SIMPLE',
        uris = ['gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/images/*.png'],
        max_staleness = INTERVAL 30 MINUTE,
        metadata_cache_mode = AUTOMATIC);

Crea la tabla product_manuals.

Crea una tabla de objetos que contenga los manuales de los productos de mascotas de Cymbal:

  • En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla product_manuals:

    CREATE OR REPLACE EXTERNAL TABLE cymbal_pets.product_manuals
      WITH CONNECTION `us.cymbal_conn`
      OPTIONS (
        object_metadata = 'SIMPLE',
        uris = ['gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/documents/*.pdf']);

Crear un modelo de generación de texto

Crea un modelo remoto de BigQuery ML que represente un modelo Gemini de Vertex AI:

  • En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear el modelo remoto:

    CREATE OR REPLACE MODEL `cymbal_pets.gemini`
      REMOTE WITH CONNECTION `us.cymbal_conn`
      OPTIONS (ENDPOINT = 'gemini-2.0-flash');

Crear un modelo de generación de embeddings

Crea un modelo remoto de BigQuery ML que represente un modelo de inserciones multimodal de Vertex AI:

  • En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear el modelo remoto:

    CREATE OR REPLACE MODEL `cymbal_pets.embedding_model`
      REMOTE WITH CONNECTION `us.cymbal_conn`
      OPTIONS (ENDPOINT = 'multimodalembedding@001');

Crear una tabla products_mm con datos multimodales

Crea una tabla products_mm que contenga una columna image rellenada con imágenes de producto de la tabla de objetos product_images. La columna image que se crea es una columna STRUCT que usa el formato ObjectRef.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla products_mm y rellenar la columna image:

    CREATE OR REPLACE TABLE cymbal_pets.products_mm
    AS
    SELECT products.* EXCEPT (uri), ot.ref AS image FROM cymbal_pets.products
    INNER JOIN cymbal_pets.product_images ot
    ON ot.uri = products.uri;
  2. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para ver los datos de la columna image:

    SELECT product_name, image
    FROM cymbal_pets.products_mm

    Los resultados deberían ser similares a los siguientes:

    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | product_name                   | image.uri                            | image.version | image.authorizer              | image.details                                  |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    |  AquaClear Aquarium Background | gs://cloud-samples-data/bigquery/    | 1234567891011 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"image/png",   |
    |                                | tutorials/cymbal-pets/images/        |               |                               | "md5_hash":"494f63b9b137975ff3e7a11b060edb1d", |
    |                                | aquaclear-aquarium-background.png    |               |                               | "size":1282805,"updated":1742492680017000}}    |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    |  AquaClear Aquarium            | gs://cloud-samples-data/bigquery/    | 2345678910112 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"image/png",   |
    |  Gravel Vacuum                 | tutorials/cymbal-pets/images/        |               |                               | "md5_hash":"b7bfc2e2641a77a402a1937bcf0003fd", |
    |                                | aquaclear-aquarium-gravel-vacuum.png |               |                               | "size":820254,"updated":1742492682411000}}     |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | ...                            | ...                                  | ...           |                               | ...                                            |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    

Generar información de producto con un modelo de Gemini

Usa un modelo de Gemini para generar los siguientes datos de los productos de la tienda de mascotas:

  • Añada una columna image_description a la tabla products_mm.
  • Rellene las columnas animal_type, search_keywords y subcategory de la tabla products_mm.
  • Ejecuta una consulta que devuelva una descripción de cada marca de producto y el número de productos de esa marca. La descripción de la marca se genera analizando la información de todos los productos de esa marca, incluidas las imágenes de los productos.
  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear y rellenar la columna image_description:

    CREATE OR REPLACE TABLE cymbal_pets.products_mm
    AS
    SELECT
      product_id,
      product_name,
      brand,
      category,
      subcategory,
      animal_type,
      search_keywords,
      price,
      description,
      inventory_level,
      supplier_id,
      average_rating,
      image,
      image_description
    FROM
      AI.GENERATE_TABLE(
        MODEL `cymbal_pets.gemini`,
        (
          SELECT
            ('Can you describe the following image?', OBJ.GET_ACCESS_URL(image, 'r')) AS prompt,
            *
          FROM
            cymbal_pets.products_mm
        ),
        STRUCT('image_description STRING' AS output_schema));
  2. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para actualizar las columnas animal_type, search_keywords y subcategory con los datos generados:

    UPDATE cymbal_pets.products_mm p
    SET
      p.animal_type = s.animal_type,
      p.search_keywords = s.search_keywords,
      p.subcategory = s.subcategory
    FROM
      (
        SELECT
          animal_type,
          search_keywords,
          subcategory,
          uri
        FROM
          AI.GENERATE_TABLE(
            MODEL `cymbal_pets.gemini`,
            (
              SELECT
                (
                  'For the image of a pet product, concisely generate the following metadata.'
                    '1) animal_type and 2) 5 SEO search keywords, and 3) product subcategory',
                  OBJ.GET_ACCESS_URL(image, 'r'),
                  description) AS prompt,
                image.uri AS uri,
              FROM cymbal_pets.products_mm
            ),
            STRUCT(
              'animal_type STRING, search_keywords ARRAY<STRING>, subcategory STRING' AS output_schema,
              100 AS max_output_tokens))
      ) s
    WHERE p.image.uri = s.uri;
  3. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para ver los datos generados:

    SELECT
      product_name,
      image_description,
      animal_type,
      search_keywords,
      subcategory,
    FROM cymbal_pets.products_mm;

    Los resultados deberían ser similares a los siguientes:

    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    | product_name                   | image.description                   | animal_type | search_keywords        | subcategory      |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    |  AquaClear Aquarium Background | The image shows a colorful coral    | fish        | aquarium background    | aquarium decor   |
    |                                | reef backdrop. The background is a  |             | fish tank backdrop     |                  |
    |                                | blue ocean with a bright light...   |             | coral reef decor       |                  |
    |                                |                                     |             | underwater scenery     |                  |
    |                                |                                     |             | aquarium decoration    |                  |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    |  AquaClear Aquarium            | The image shows a long, clear       | fish        | aquarium gravel vacuum | aquarium         |
    |  Gravel Vacuum                 | plastic tube with a green hose      |             | aquarium cleaning      | cleaning         |
    |                                | attached to one end. The tube...    |             | aquarium maintenance   |                  |
    |                                |                                     |             | fish tank cleaning     |                  |
    |                                |                                     |             | gravel siphon          |                  |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    | ...                            | ...                                 | ...         |  ...                   | ...              |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    
  4. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para generar una descripción de cada marca de producto y un recuento del número de productos de esa marca:

    SELECT
      brand,
      brand_description,
      cnt
    FROM
      AI.GENERATE_TABLE(
        MODEL `cymbal_pets.gemini`,
        (
          SELECT
            brand,
            COUNT(*) AS cnt,
            (
              'Use the images and text to give one concise brand description for a website brand page.'
                'Return the description only.',
              ARRAY_AGG(OBJ.GET_ACCESS_URL(image, 'r')),
              ARRAY_AGG(description),
              ARRAY_AGG(category),
              ARRAY_AGG(subcategory)) AS prompt
          FROM cymbal_pets.products_mm
          GROUP BY brand
        ),
        STRUCT('brand_description STRING' AS output_schema))
    ORDER BY cnt DESC;

    Los resultados deberían ser similares a los siguientes:

    +--------------+-------------------------------------+-----+
    | brand        | brand.description                   | cnt |
    +--------------+-------------------------------------+-----+
    |  AquaClear   | AquaClear is a brand of aquarium    | 33  |
    |              | and pond care products that offer   |     |
    |              | a wide range of solutions for...    |     |
    +--------------+-------------------------------------+-----+
    |  Ocean       | Ocean Bites is a brand of cat food  | 28  |
    |  Bites       | that offers a variety of recipes    |     |
    |              | and formulas to meet the specific.. |     |
    +--------------+-------------------------------------+-----+
    |  ...         | ...                                 |...  |
    +--------------+-------------------------------------+-----+
    

Crear una función definida por el usuario (UDF) de Python para transformar imágenes de producto

Crea una función definida por el usuario (UDF) de Python para convertir imágenes de productos a escala de grises.

La FDU de Python usa bibliotecas de código abierto y también usa la ejecución paralela para transformar varias imágenes simultáneamente.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la función definida por el usuario to_grayscale:

    CREATE OR REPLACE FUNCTION cymbal_pets.to_grayscale(src_json STRING, dst_json STRING)
    RETURNS STRING
    LANGUAGE python
    WITH CONNECTION `us.cymbal_conn`
    OPTIONS (entry_point='to_grayscale', runtime_version='python-3.11', packages=['numpy', 'opencv-python'])
    AS """
    
    import cv2 as cv
    import numpy as np
    from urllib.request import urlopen, Request
    import json
    
    # Transform the image to grayscale.
    def to_grayscale(src_ref, dst_ref):
      src_json = json.loads(src_ref)
      srcUrl = src_json["access_urls"]["read_url"]
    
      dst_json = json.loads(dst_ref)
      dstUrl = dst_json["access_urls"]["write_url"]
    
      req = urlopen(srcUrl)
      arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
      img = cv.imdecode(arr, -1) # 'Load it as it is'
    
      # Convert the image to grayscale
      gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
      # Send POST request to the URL
      _, img_encoded = cv.imencode('.png', gray_image)
    
      req = Request(url=dstUrl, data=img_encoded.tobytes(), method='PUT', headers = {
          "Content-Type": "image/png",
      })
      with urlopen(req) as f:
          pass
      return dst_ref
    """;

Transformar imágenes de productos

Crea la tabla products_grayscale con una columna ObjectRef que contenga las rutas de destino y los autorizadores de las imágenes en escala de grises. La ruta de destino se deriva de la ruta de la imagen original.

Después de crear la tabla, ejecuta la función to_grayscale para crear las imágenes en escala de grises, escríbelas en un segmento de Cloud Storage y, a continuación, devuelve los valores ObjectRefRuntime que contienen las URLs de acceso y los metadatos de las imágenes en escala de grises.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla products_grayscale:

    CREATE OR REPLACE TABLE cymbal_pets.products_grayscale
    AS
    SELECT
      product_id,
      product_name,
      image,
      OBJ.MAKE_REF(
        CONCAT('gs://BUCKET/cymbal-pets-images/grayscale/', REGEXP_EXTRACT(image.uri, r'([^/]+)$')),
        'us.cymbal_conn') AS gray_image
    FROM cymbal_pets.products_mm;

    Sustituye BUCKET por el nombre del cubo que has creado.

  2. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear las imágenes en escala de grises, escribirlas en un contenedor de Cloud Storage y, a continuación, devuelve los valores de ObjectRefRuntime que contienen las URLs de acceso y los metadatos de las imágenes en escala de grises:

    SELECT cymbal_pets.to_grayscale(
      TO_JSON_STRING(OBJ.GET_ACCESS_URL(image, 'r')),
      TO_JSON_STRING(OBJ.GET_ACCESS_URL(gray_image, 'rw')))
    FROM cymbal_pets.products_grayscale;

    Los resultados deberían ser similares a los siguientes:

    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | f0                                                                                                                                                                    |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | {"access_urls":{"expiry_time":"2025-04-26T03:00:48Z",                                                                                                                 |
    | "read_url":"https://storage.googleapis.com/mybucket/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_read URL_information",       |
    | "write_url":"https://storage.googleapis.com/myproject/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_write URL_information"},   |
    | "objectref":{"authorizer":"myproject.region.myconnection","uri":"gs://myproject/cymbal-pets-images/grayscale/ocean-bites-salmon-&-tuna-cat-food.png"}}                |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | {"access_urls":{"expiry_time":"2025-04-26T03:00:48Z",                                                                                                                 |
    | "read_url":"https://storage.googleapis.com/mybucket/cymbal-pets-images%2Fgrayscale%2Ffluffy-buns-guinea-pig-tunnel.png?additional _read URL_information",             |
    | "write_url":"https://storage.googleapis.com/myproject/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_write_URL_information"},   |
    | "objectref":{"authorizer":"myproject.region.myconnection","uri":"gs://myproject/cymbal-pets-images%2Fgrayscale%2Ffluffy-buns-guinea-pig-tunnel.png"}}                 |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    |  ...                                                                                                                                                                  |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    

Crear una FDU de Python para dividir datos de PDF en fragmentos

Crea una función definida por el usuario (UDF) de Python para dividir en partes los objetos PDF que contengan los manuales de los productos de mascotas de Cymbal.

Los PDFs suelen ser muy grandes y es posible que no quepan en una sola llamada a un modelo de IA generativa. Al dividir los PDFs en fragmentos, puedes almacenar los datos de los PDFs en un formato listo para el modelo para facilitar el análisis.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la función definida por el usuario chunk_pdf:

    -- This function chunks the product manual PDF into multiple parts.
    -- The function accepts an ObjectRefRuntime value for the PDF file and the chunk size.
    -- It then parses the PDF, chunks the contents, and returns an array of chunked text.
    CREATE OR REPLACE FUNCTION cymbal_pets.chunk_pdf(src_json STRING, chunk_size INT64, overlap_size INT64)
    RETURNS ARRAY<STRING>
    LANGUAGE python
    WITH CONNECTION `us.cymbal_conn`
    OPTIONS (entry_point='chunk_pdf', runtime_version='python-3.11', packages=['pypdf'])
    AS """
    import io
    import json
    
    from pypdf import PdfReader  # type: ignore
    from urllib.request import urlopen, Request
    
    def chunk_pdf(src_ref: str, chunk_size: int, overlap_size: int) -> str:
      src_json = json.loads(src_ref)
      srcUrl = src_json["access_urls"]["read_url"]
    
      req = urlopen(srcUrl)
      pdf_file = io.BytesIO(bytearray(req.read()))
      reader = PdfReader(pdf_file, strict=False)
    
      # extract and chunk text simultaneously
      all_text_chunks = []
      curr_chunk = ""
      for page in reader.pages:
          page_text = page.extract_text()
          if page_text:
              curr_chunk += page_text
              # split the accumulated text into chunks of a specific size with overlaop
              # this loop implements a sliding window approach to create chunks
              while len(curr_chunk) >= chunk_size:
                  split_idx = curr_chunk.rfind(" ", 0, chunk_size)
                  if split_idx == -1:
                      split_idx = chunk_size
                  actual_chunk = curr_chunk[:split_idx]
                  all_text_chunks.append(actual_chunk)
                  overlap = curr_chunk[split_idx + 1 : split_idx + 1 + overlap_size]
                  curr_chunk = overlap + curr_chunk[split_idx + 1 + overlap_size :]
      if curr_chunk:
          all_text_chunks.append(curr_chunk)
    
      return all_text_chunks
    """;

Analizar datos de PDF

Ejecuta la función chunk_pdf para dividir los datos del PDF en la tabla product_manuals y, a continuación, crea una tabla product_manual_chunk_strings que contenga un fragmento del PDF por fila. Usa un modelo de Gemini en los datos de product_manual_chunk_strings para resumir la información legal que se encuentra en los manuales del producto.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla product_manual_chunk_strings:

    CREATE OR REPLACE TABLE cymbal_pets.product_manual_chunk_strings
    AS
    SELECT chunked
    FROM cymbal_pets.product_manuals,
    UNNEST (cymbal_pets.chunk_pdf(
      TO_JSON_STRING(
        OBJ.GET_ACCESS_URL(OBJ.MAKE_REF(uri, 'us.cymbal_conn'), 'r')),
        1000,
        100
    )) as chunked;
  2. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para analizar los datos del PDF con un modelo de Gemini:

    SELECT
      ml_generate_text_llm_result
    FROM
      ML.GENERATE_TEXT(
        MODEL `cymbal_pets.gemini`,
        (
          SELECT
            (
              'Can you summarize the product manual as bullet points? Highlight the legal clauses',
              chunked) AS prompt,
          FROM cymbal_pets.product_manual_chunk_strings
        ),
        STRUCT(
          TRUE AS FLATTEN_JSON_OUTPUT));

    Los resultados deberían ser similares a los siguientes:

    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ml_generate_text_llm_result                                                                                                               |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ## CritterCuisine Pro 5000 Automatic Pet Feeder Manual Summary:                                                                           |
    |                                                                                                                                           |
    | **Safety:**                                                                                                                               |
    |                                                                                                                                           |
    | * **Stability:** Place feeder on a level, stable surface to prevent tipping.                                                              |
    | * **Power Supply:** Only use the included AC adapter. Using an incompatible adapter can damage the unit and void the warranty.            |
    | * **Cord Safety:** Keep the power cord out of reach of pets to prevent chewing or entanglement.                                           |
    | * **Children:** Supervise children around the feeder. This is not a toy.                                                                  |
    | * **Pet Health:** Consult your veterinarian before using an automatic feeder if your pet has special dietary needs, health conditions, or |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ## Product Manual Summary:                                                                                                                |
    |                                                                                                                                           |
    | **6.3 Manual Feeding:**                                                                                                                   |
    |                                                                                                                                           |
    | * Press MANUAL button to dispense a single portion (Meal 1 size). **(Meal Enabled)**                                                      |
    |                                                                                                                                           |
    | **6.4 Recording a Voice Message:**                                                                                                        |
    |                                                                                                                                           |
    | * Press and hold VOICE button.                                                                                                            |
    | * Speak clearly into the microphone (up to 10 seconds).                                                                                   |
    | * Release VOICE button to finish recording.                                                                                               |
    | * Briefly press VOICE button to play back the recording.                                                                                  |
    | * To disable the voice message, record a blank message (hold VOICE button for 10 seconds without speaking). **(Meal Enabled)**            |
    |                                                                                                                                           |
    | **6.5 Low Food Level Indicator:**                                                                                                         |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ...                                                                                                                                       |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    

Genera incrustaciones a partir de datos de imagen y, a continuación, úsalas para devolver imágenes similares mediante la búsqueda de vectores.

En un entorno de producción, te recomendamos que crees un índice vectorial antes de realizar una búsqueda vectorial. Un índice de vectores te permite realizar la búsqueda de vectores más rápidamente, pero a cambio se reduce la recuperación y, por lo tanto, se devuelven resultados más aproximados.

  1. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla products_embeddings:

    CREATE OR REPLACE TABLE cymbal_pets.products_embedding
    AS
    SELECT product_id, ml_generate_embedding_result as embedding, content as image
    FROM ML.GENERATE_EMBEDDING(
    MODEL `cymbal_pets.embedding_model`,
      (
        SELECT OBJ.GET_ACCESS_URL(image, 'r') as content, image, product_id
        FROM cymbal_pets.products_mm
      ),
      STRUCT ()
    );
  2. En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para realizar una búsqueda de vectores que devuelva imágenes de productos similares a la imagen de entrada proporcionada:

    SELECT *
    FROM
    VECTOR_SEARCH(
      TABLE cymbal_pets.products_embedding,
      'embedding',
      (SELECT ml_generate_embedding_result as embedding FROM ML.GENERATE_EMBEDDING(
        MODEL `cymbal_pets.embedding_model`,
        (SELECT OBJ.FETCH_METADATA(OBJ.MAKE_REF('gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/images/cozy-naps-cat-scratching-post-with-condo.png', 'us.cymbal_conn')) as content)
      ))
    );

    Los resultados deberían ser similares a los siguientes:

    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | query.embedding | base.product_id | base.embedding | base.image.uri                               | base.image.version | base.image.authorizer         | base.image.details                             | distance       |
    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | -0.0112330541   | 181             | -0.0112330541  | gs://cloud-samples-data/bigquery/            | 12345678910        | myproject.region.myconnection | {"gcs_metadata":{"content_type":               | 0.0            |
    | 0.0142525584    |                 |  0.0142525584  | tutorials/cymbal-pets/images/                |                    |                               | "image/png","md5_hash":"21234567hst16555w60j", |                |
    | 0.0135886827    |                 |  0.0135886827  | cozy-naps-cat-scratching-post-with-condo.png |                    |                               | "size":828318,"updated":1742492688982000}}     |                |
    | 0.0149955815    |                 |  0.0149955815  |                                              |                    |                               |                                                |                |
    | ...             |                 |  ...           |                                              |                    |                               |                                                |                |
    |                 |                 |                |                                              |                    |                               |                                                |                |
    |                 |                 |                |                                              |                    |                               |                                                |                |
    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | -0.0112330541   | 187             | -0.0190353896  | gs://cloud-samples-data/bigquery/            | 23456789101        | myproject.region.myconnection | {"gcs_metadata":{"content_type":               | 0.4216330832.. |
    | 0.0142525584    |                 |  0.0116206668  | tutorials/cymbal-pets/images/                |                    |                               | "image/png","md5_hash":"7328728fhakd9937djo4", |                |
    | 0.0135886827    |                 |  0.0136198215  | cozy-naps-cat-scratching-post-with-bed.png   |                    |                               | "size":860113,"updated":1742492688774000}}     |                |
    | 0.0149955815    |                 |  0.0173457414  |                                              |                    |                               |                                                |                |
    | ...             |                 |  ...           |                                              |                    |                               |                                                |                |
    |                 |                 |                |                                              |                    |                               |                                                |                |
    |                 |                 |                |                                              |                    |                               |                                                |                |
    +---------C--------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | ...             | ...             | ...            | ...                                          | ...                | ...                           | ...                                            | ...            |
    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    

Procesar datos multimodales ordenados mediante matrices de valores ObjectRef

En esta sección se explica cómo completar las siguientes tareas:

  1. Vuelve a crear la tabla product_manuals para que contenga un archivo PDF del manual del producto Crittercuisine 5000 y archivos PDF de cada página de ese manual.
  2. Crea una tabla que asigne el manual a sus fragmentos. El valor ObjectRef que representa el manual completo se almacena en una columna STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>. Los valores ObjectRef que representan las páginas del manual se almacenan en una columna ARRAY<STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>.
  3. Analiza una matriz de valores ObjectRef para devolver un único valor generado.
  4. Analiza un array de valores ObjectRef por separado y devuelve un valor generado por cada valor del array.

Como parte de las tareas de análisis, convierte la matriz de valores ObjectRef en una lista ordenada de valores ObjectRefRuntime y, a continuación, pasa esa lista a un modelo de Gemini, especificando los valores ObjectRefRuntime como parte de la petición. Los valores de ObjectRefRuntime proporcionan URLs firmadas que el modelo usa para acceder a la información de los objetos en Cloud Storage.

Sigue estos pasos para procesar datos multimodales ordenados mediante arrays de valores ObjectRef:

  1. Ve a la página BigQuery.

    Ir a BigQuery

  2. En el editor de consultas, ejecuta la siguiente consulta para volver a crear la tabla product_manuals:

    CREATE OR REPLACE EXTERNAL TABLE `cymbal_pets.product_manuals`
      WITH CONNECTION `us.cymbal_conn`
      OPTIONS (
        object_metadata = 'SIMPLE',
        uris = [
            'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/documents/*.pdf',
            'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/document_chunks/*.pdf']);
  3. En el editor de consultas, ejecuta la siguiente consulta para escribir datos PDF en la tabla map_manual_to_chunks:

    -- Extract the file and chunks into a single table.
    -- Store the chunks in the chunks column as array of ObjectRefs (ordered by page number)
    CREATE OR REPLACE TABLE cymbal_pets.map_manual_to_chunks
    AS
    SELECT ARRAY_AGG(m1.ref)[0] manual, ARRAY_AGG(m2.ref ORDER BY m2.ref.uri) chunks
    FROM cymbal_pets.product_manuals m1
    JOIN cymbal_pets.product_manuals m2
      ON
        REGEXP_EXTRACT(m1.uri, r'.*/([^.]*).[^/]+')
        = REGEXP_EXTRACT(m2.uri, r'.*/([^.]*)_page[0-9]+.[^/]+')
    GROUP BY m1.uri;
  4. En el editor de consultas, ejecuta la siguiente consulta para ver los datos del PDF en la tabla map_manual_to_chunks:

    SELECT *
    FROM cymbal_pets.map_manual_to_chunks;

    Los resultados deberían ser similares a los siguientes:

    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    | manual.uri                          | manual.version                 | manual.authorizer                 | manual.details                                       | chunks.uri                                | chunks.version                  | chunks.authorizer                  | chunks.details                                        |
    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    | gs://cloud-samples-data/bigquery/   | 1742492785900455               | myproject.region.myconnection     | {"gcs_metadata":{"content_type":"application/pef",   | gs://cloud-samples-data/bigquery/         | 1745875761227129                | myproject.region.myconnection      | {"gcs_metadata":{"content_type":"application/pdf",    |
    | tutorials/cymbal-pets/documents/    |                                |                                   | "md5_hash":"c9032b037693d15a33210d638c763d0e",       | tutorials/cymbal-pets/documents/          |                                 |                                    | "md5_hash":"5a1116cce4978ec1b094d8e8b49a1d7c",        |
    | crittercuisine_5000_user_manual.pdf |                                |                                   | "size":566105,"updated":1742492785941000}}           | crittercuisine_5000_user_manual_page1.pdf |                                 |                                    | "size":504583,"updated":1745875761266000}}            |
    |                                     |                                |                                   |                                                      +-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    |                                     |                                |                                   |                                                      | crittercuisine_5000_user_manual_page1.pdf | 1745875760613874                | myproject.region.myconnection      | {"gcs_metadata":{"content_type":"application/pdf",    |
    |                                     |                                |                                   |                                                      | tutorials/cymbal-pets/documents/          |                                 |                                    | "md5_hash":"94d03ec65d28b173bc87eac7e587b325",        |
    |                                     |                                |                                   |                                                      | crittercuisine_5000_user_manual_page2.pdf |                                 |                                    | "size":94622,"updated":1745875760649000}}             |
    |                                     |                                |                                   |                                                      +-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    |                                     |                                |                                   |                                                      | ...                                       | ...                             |  ...                               | ...                                                   |
    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    
  5. En el editor de consultas, ejecuta la siguiente consulta para generar una única respuesta de un modelo de Gemini basada en el análisis de una matriz de valores de ObjectRef:

    WITH
      manuals AS (
        SELECT
          OBJ.GET_ACCESS_URL(manual, 'r') AS manual,
          ARRAY(
            SELECT OBJ.GET_ACCESS_URL(chunk, 'r') AS chunk
            FROM UNNEST(m1.chunks) AS chunk WITH OFFSET AS idx
            ORDER BY idx
          ) AS chunks
        FROM cymbal_pets.map_manual_to_chunks AS m1
      )
    SELECT ml_generate_text_llm_result AS Response
    FROM
      ML.GENERATE_TEXT(
        MODEL `cymbal_pets.gemini`,
        (
          SELECT
            (
              'Can you provide a page by page summary for the first 3 pages of the attached manual? Only write one line for each page. The pages are provided in serial order',
              manuals.chunks) AS prompt,
          FROM manuals
        ),
        STRUCT(TRUE AS FLATTEN_JSON_OUTPUT));

    Los resultados deberían ser similares a los siguientes:

    +-------------------------------------------+
    | Response                                  |
    +-------------------------------------------+
    | Page 1: This manual is for the            |
    | CritterCuisine Pro 5000 automatic         |
    | pet feeder.                               |
    | Page 2: The manual covers safety          |
    | precautions, what's included,             |
    | and product overview.                     |
    | Page 3: The manual covers assembly,       |
    | initial setup, and programming the clock. |
    +-------------------------------------------+
    
  6. En el editor de consultas, ejecuta la siguiente consulta para generar varias respuestas de un modelo de Gemini basadas en el análisis de una matriz de valores de ObjectRef:

    WITH
      input_chunked_objrefs AS (
        SELECT row_id, offset, chunk_ref
        FROM
          (
            SELECT ROW_NUMBER() OVER () AS row_id, * FROM `cymbal_pets.map_manual_to_chunks`
          ) AS indexed_table
        LEFT JOIN
          UNNEST(indexed_table.chunks) AS chunk_ref
          WITH OFFSET
      ),
      get_access_urls AS (
        SELECT row_id, offset, chunk_ref, OBJ.GET_ACCESS_URL(chunk_ref, 'r') AS ObjectRefRuntime
        FROM input_chunked_objrefs
      ),
      valid_get_access_urls AS (
        SELECT *
        FROM get_access_urls
        WHERE ObjectRefRuntime['runtime_errors'] IS NULL
      ),
      ordered_output_objrefruntime_array AS (
        SELECT ARRAY_AGG(ObjectRefRuntime ORDER BY offset) AS ObjectRefRuntimeArray
        FROM valid_get_access_urls
        GROUP BY row_id
      )
    SELECT
      page1_summary,
      page2_summary,
      page3_summary
    FROM
      AI.GENERATE_TABLE(
        MODEL `cymbal_pets.gemini`,
        (
          SELECT
            (
              'Can you provide a page by page summary for the first 3 pages of the attached manual? Only write one line for each page. The pages are provided in serial order',
              ObjectRefRuntimeArray) AS prompt,
          FROM ordered_output_objrefruntime_array
        ),
        STRUCT(
          'page1_summary STRING, page2_summary STRING, page3_summary STRING' AS output_schema));

    Los resultados deberían ser similares a los siguientes:

    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    | page1_summary                                 | page2_summary                             | page3_summary                                      |
    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    | This manual provides an overview of the       | This section explains how to program      | This page covers connecting the feeder to Wi-Fi    |
    | CritterCuisine Pro 5000 automatic pet feeder, | the feeder's clock, set feeding           | using the CritterCuisine Connect app,  remote      |
    | including its features, safety precautions,   | schedules, copy and delete meal settings, | feeding, managing feeding schedules, viewing       |
    | assembly instructions, and initial setup.     | manually feed your pet, record            | feeding logs, receiving low food alerts,           |
    |                                               | a voice message, and understand           | updating firmware, creating multiple pet profiles, |
    |                                               | the low food level indicator.             | sharing access with other users, and cleaning      |
    |                                               |                                           | and maintaining the feeder.                        |
    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    

Limpieza

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.