Analyser des données multimodales avec SQL et Python

Ce tutoriel explique comment analyser des données multimodales à l'aide de requêtes SQL et de fonctions définies par l'utilisateur (UDF) Python.

Ce tutoriel utilise le catalogue de produits de l'ensemble de données public de la boutique pour animaux de compagnie Cymbal.

Objectifs

  • Utilisez des valeurs ObjectRef pour stocker des données d'image avec des données structurées dans une table standard BigQuery.
  • Générez du texte à partir des données d'image d'une table standard à l'aide de la fonction AI.GENERATE_TABLE.
  • Transformez des images existantes pour créer de nouvelles images à l'aide d'une fonction définie par l'utilisateur Python.
  • Divisez les fichiers PDF en sections pour une analyse plus approfondie à l'aide d'une fonction définie par l'utilisateur Python.
  • Utilisez un modèle Gemini et la fonction ML.GENERATE_TEXT pour analyser les données PDF segmentées.
  • Générez des embeddings basés sur les données d'image d'une table standard à l'aide de la fonction ML.GENERATE_EMBEDDING.
  • Traitez des données multimodales ordonnées à l'aide de tableaux de valeurs ObjectRef.

Coûts

Dans ce document, vous utilisez les composants facturables suivants 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.

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Pour en savoir plus, consultez les pages des tarifs suivantes:

Avant de commencer

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

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

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

    Enable the APIs

Rôles requis

Pour obtenir les autorisations nécessaires pour suivre ce tutoriel, demandez à votre administrateur de vous accorder les rôles IAM suivants:

Pour en savoir plus sur l'attribution de rôles, consultez Gérer l'accès aux projets, aux dossiers et aux organisations.

Vous pouvez également obtenir les autorisations requises avec des rôles personnalisés ou d'autres rôles prédéfinis.

Configurer

Dans cette section, vous allez créer l'ensemble de données, la connexion, les tables et les modèles utilisés dans ce tutoriel.

Créer un ensemble de données

Créez un ensemble de données BigQuery pour contenir les objets que vous créez dans ce tutoriel:

  1. Dans la console Google Cloud , accédez à la page BigQuery.

    Accéder à BigQuery

  2. Dans le volet Explorer, sélectionnez votre projet.

  3. Développez l'option Actions, puis cliquez sur Créer un ensemble de données. Le volet Créer un ensemble de données s'ouvre.

  4. Dans le champ ID de l'ensemble de données, saisissez cymbal_pets.

  5. Cliquez sur Créer un ensemble de données.

Créer un bucket

Créez un bucket Cloud Storage pour stocker les objets transformés:

  1. Accédez à la page Buckets.

    Accéder à la page "Buckets"

  2. Cliquez sur Créer.

  3. Sur la page Créer un bucket, dans la section Premiers pas, saisissez un nom unique qui répond aux exigences de dénomination des buckets.

  4. Cliquez sur Créer.

Créer une connexion

Créez une connexion de ressource cloud et obtenez le compte de service de la connexion. BigQuery utilise cette connexion pour accéder aux objets de Cloud Storage:

  1. Accédez à la page BigQuery.

    Accéder à BigQuery

  2. Dans le volet Explorateur, cliquez sur  Ajouter des données.

    La boîte de dialogue Ajouter des données s'ouvre.

  3. Dans le volet Filtrer par, dans la section Type de source de données, sélectionnez Applications d'entreprise.

    Vous pouvez également saisir Vertex AI dans le champ Rechercher des sources de données.

  4. Dans la section Sources de données sélectionnées, cliquez sur Vertex AI.

  5. Cliquez sur la fiche de solution Modèles Vertex AI: fédération BigQuery.

  6. Dans la liste Type de connexion, sélectionnez Modèles distants Vertex AI, fonctions distantes et BigLake (ressource Cloud).

  7. Dans le champ ID de connexion, saisissez cymbal_conn.

  8. Cliquez sur Créer une connexion.

  9. Cliquez sur Accéder à la connexion.

  10. Dans le volet Informations de connexion, copiez l'ID du compte de service à utiliser à l'étape suivante.

Accorder des autorisations au compte de service de la connexion

Attribuez au compte de service de la connexion les rôles appropriés pour accéder à d'autres services. Vous devez accorder ces rôles dans le projet que vous avez créé ou sélectionné dans la section Avant de commencer. L'attribution des rôles dans un autre projet génère l'erreur bqcx-1234567890-xxxx@gcp-sa-bigquery-condel.iam.gserviceaccount.com does not have the permission to access resource.

Accorder des autorisations sur le bucket Cloud Storage

Accordez au compte de service l'accès aux objets du bucket que vous avez créé:

  1. Accédez à la page Buckets.

    Accéder à la page "Buckets"

  2. Cliquez sur le nom du bucket que vous avez créé.

  3. Cliquez sur Autorisations.

  4. Cliquez sur Accorder l'accès. La boîte de dialogue Accorder l'accès s'ouvre.

  5. Dans le champ Nouveaux comptes principaux, saisissez l'ID du compte de service que vous avez copié précédemment.

  6. Dans le champ Sélectionner un rôle, sélectionnez Cloud Storage, puis Utilisateur d'objets Storage.

  7. Cliquez sur Enregistrer.

Accorder des autorisations pour utiliser les modèles Vertex AI

Accordez au compte de service l'accès aux modèles Vertex AI:

  1. Accédez à la page IAM et administration.

    Accéder à IAM et administration

  2. Cliquez sur Accorder l'accès. La boîte de dialogue Accorder l'accès s'ouvre.

  3. Dans le champ Nouveaux comptes principaux, saisissez l'ID du compte de service que vous avez copié précédemment.

  4. Dans le champ Sélectionner un rôle, sélectionnez Vertex AI, puis Utilisateur Vertex AI.

  5. Cliquez sur Enregistrer.

Créer les tables d'exemples de données

Créez des tables pour stocker les informations sur les produits pour animaux de compagnie de Cymbal.

Créer la table products

Créez une table standard contenant les informations sur les produits pour animaux de compagnie de Cymbal:

  1. Dans la console Google Cloud , accédez à la page BigQuery.

    Accéder à BigQuery

  2. Dans l'éditeur de requêtes, exécutez la requête suivante pour créer la table products:

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

Créer la table product_images

Créez une table d'objets contenant les images des produits pour animaux de compagnie de Cymbal:

  • Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la table 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);

Créer la table product_manuals

Créez une table d'objets contenant les manuels des produits pour animaux de compagnie de Cymbal:

  • Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la table 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']);

Créer un modèle de génération de texte

Créez un modèle distant BigQuery ML représentant un modèle Gemini Vertex AI:

  • Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer le modèle distant:

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

Créer un modèle de génération d'embeddings

Créez un modèle distant BigQuery ML représentant un modèle d'embedding multimodal Vertex AI:

  • Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer le modèle distant:

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

Créer une table products_mm avec des données multimodales

Créez une table products_mm contenant une colonne image renseignée avec des images de produits de la table d'objets product_images. La colonne image créée est une colonne STRUCT qui utilise le format ObjectRef.

  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la table products_mm et renseigner la colonne 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. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour afficher les données de la colonne image:

    SELECT product_name, image
    FROM cymbal_pets.products_mm`

    Les résultats ressemblent à ce qui suit :

    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | 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}}     |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | ...                            | ...                                  | ...           |                               | ...                                            |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    

Générer des informations produit à l'aide d'un modèle Gemini

Utilisez un modèle Gemini pour générer les données suivantes pour les produits de la animalerie:

  • Ajoutez une colonne image_description au tableau products_mm.
  • Renseignez les colonnes animal_type, search_keywords et subcategory de la table products_mm.
  • Exécutez une requête qui renvoie une description de chaque marque de produits, ainsi qu'un nombre de produits de cette marque. La description de la marque est générée en analysant les informations sur les produits de cette marque, y compris les images des produits.
  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer et renseigner la colonne 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. Dans l'éditeur de requêtes de la page BigQuery, exécutez la requête suivante pour mettre à jour les colonnes animal_type, search_keywords et subcategory avec les données générées:

    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. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour afficher les données générées:

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

    Les résultats ressemblent à ce qui suit :

    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    | 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. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour générer une description de chaque marque de produits, ainsi qu'un nombre de produits de cette marque:

    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;

    Les résultats ressemblent à ce qui suit :

    +--------------+-------------------------------------+-----+
    | 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.. |     |
    +--------------+-------------------------------------+-----+
    |  ...         | ...                                 |...  |
    +--------------+-------------------------------------+-----+
    

Créer une fonction définie par l'utilisateur Python pour transformer les images de produits

Créez une fonction définie par l'utilisateur Python pour convertir les images produit en niveaux de gris.

La fonction définie par l'utilisateur Python utilise des bibliothèques Open Source et une exécution parall��le pour transformer plusieurs images simultanément.

  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la UDF 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
    """;

Transformer les images de produits

Créez la table products_grayscale avec une colonne ObjectRef contenant les chemins de destination et les autoriseurs pour les images en niveaux de gris. Le chemin de destination est dérivé du chemin d'image d'origine.

Une fois la table créée, exécutez la fonction to_grayscale pour créer les images en niveaux de gris, les écrire dans un bucket Cloud Storage, puis renvoyer des valeurs ObjectRefRuntime contenant des URL d'accès et des métadonnées pour les images en niveaux de gris.

  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la table 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;

    Remplacez BUCKET par le nom du bucket que vous avez créé.

  2. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer les images en niveaux de gris, les écrire dans un bucket Cloud Storage, puis renvoyer des valeurs ObjectRefRuntime contenant des URL d'accès et des métadonnées pour les images en niveaux de gris:

    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;

    Les résultats ressemblent à ce qui suit :

    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | 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"}}                 |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    |  ...                                                                                                                                                                  |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    

Créer une fonction définie par l'utilisateur Python pour diviser les données PDF

Créez une fonction définie par l'utilisateur Python pour diviser les objets PDF contenant les manuels des produits Cymbal en plusieurs parties.

Les fichiers PDF sont souvent très volumineux et peuvent ne pas tenir dans un seul appel à un modèle d'IA générative. En segmentant les fichiers PDF, vous pouvez stocker les données PDF dans un format prêt à être modélisé pour faciliter l'analyse.

  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la UDF 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
    """;

Analyser des données PDF

Exécutez la fonction chunk_pdf pour diviser les données PDF dans la table product_manuals, puis créez une table product_manual_chunk_strings contenant un bloc PDF par ligne. Utilisez un modèle Gemini sur les données product_manual_chunk_strings pour résumer les informations légales figurant dans les manuels des produits.

  1. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour créer la table 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. Dans l'éditeur de requêtes de la page BigQuery, exécutez la requête suivante pour analyser les données PDF à l'aide d'un modèle 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));

    Les résultats ressemblent à ce qui suit :

    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | 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:**                                                                                                         |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ...                                                                                                                                       |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    

Générez des embeddings à partir de données d'image, puis utilisez-les pour renvoyer des images similaires à l'aide de la recherche vectorielle.

Dans un scénario de production, nous vous recommandons de créer un index vectoriel avant d'exécuter une recherche vectorielle. Un index vectoriel vous permet d'effectuer la recherche vectorielle plus rapidement, avec le compromis de réduire le rappel et donc de renvoyer des résultats plus approximatifs.

  1. Dans l'éditeur de requêtes de la page BigQuery, exécutez la requête suivante pour créer la table 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. Dans l'éditeur de requête de la page BigQuery, exécutez la requête suivante pour effectuer une recherche vectorielle afin de renvoyer des images de produits similaires à l'image d'entrée donnée:

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

    Les résultats ressemblent à ce qui suit :

    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | 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--------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | ...             | ...             | ...            | ...                                          | ...                | ...                           | ...                                            | ...            |
    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    

Traiter des données multimodales ordonnées à l'aide de tableaux de valeurs ObjectRef

Ce guide vous explique comment effectuer les tâches suivantes :

  1. Recréez le tableau product_manuals afin qu'il contienne à la fois un fichier PDF pour le manuel produit Crittercuisine 5000 et des fichiers PDF pour chaque page de ce manuel.
  2. Créez un tableau qui met en correspondance le manuel avec ses segments. La valeur ObjectRef représentant le manuel complet est stockée dans une colonne STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>. Les valeurs ObjectRef qui représentent les pages de manuel sont stockées dans une colonne ARRAY<STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>.
  3. Analysez un tableau de valeurs ObjectRef pour renvoyer une seule valeur générée.
  4. Analysez un tableau de valeurs ObjectRef séparément et renvoyez une valeur générée pour chaque valeur du tableau.

Dans le cadre des tâches d'analyse, vous convertissez le tableau de valeurs ObjectRef en liste ordonnée de valeurs ObjectRefRuntime, puis transmettez cette liste à un modèle Gemini, en spécifiant les valeurs ObjectRefRuntime dans la requête. Les valeurs ObjectRefRuntime fournissent des URL signées que le modèle utilise pour accéder aux informations sur les objets dans Cloud Storage.

Pour traiter des données multimodales ordonnées à l'aide de tableaux de valeurs ObjectRef, procédez comme suit:

  1. Accédez à la page BigQuery.

    Accéder à BigQuery

  2. Dans l'éditeur de requêtes, exécutez la requête suivante pour recréer la table 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. Dans l'éditeur de requêtes, exécutez la requête suivante pour écrire des données PDF dans la table 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. Dans l'éditeur de requêtes, exécutez la requête suivante pour afficher les données PDF dans la table map_manual_to_chunks:

    SELECT *
    FROM cymbal_pets.map_manual_to_chunks;

    Les résultats ressemblent à ce qui suit :

    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    | 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. Dans l'éditeur de requête, exécutez la requête suivante pour générer une seule réponse à partir d'un modèle Gemini basé sur l'analyse d'un tableau de valeurs 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));

    Les résultats ressemblent à ce qui suit :

    +-------------------------------------------+
    | 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. Dans l'éditeur de requête, exécutez la requête suivante pour générer plusieurs réponses à partir d'un modèle Gemini basé sur l'analyse d'un tableau de valeurs 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));

    Les résultats ressemblent à ce qui suit :

    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    | 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.                        |
    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    

Effectuer un nettoyage

  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.