Compilador de Bookshelf: Usa Gemini para compilar una Cloud Function de Java para una aplicación con Gemini

1. Introducción

¿Te gusta leer libros, pero te abruma la cantidad de opciones? Imagina tener una app potenciada por IA que no solo recomiende la lectura perfecta, sino que también ofrezca un resumen conciso según el género que elijas para darte una idea de la esencia del libro. En este codelab, te explicaré cómo compilar una app de este tipo con BigQuery y Cloud Functions con la tecnología de Gemini.

Descripción general del proyecto

Nuestro caso de uso se centra en estos 4 componentes clave:

  • Base de datos de libros: El vasto conjunto de datos públicos de BigQuery de libros de archivo en Internet funcionará como nuestro catálogo de libros completo.
  • Motor de resumen de IA: Google Cloud Functions, equipado con el modelo de lenguaje Gemini-Pro, generará resúmenes detallados adaptados a las solicitudes de los usuarios.
  • Integración con BigQuery: Es una función remota dentro de BigQuery que llama a nuestra Cloud Function para proporcionar resúmenes y temas de libros a pedido.
  • Interfaz de usuario: Una app web alojada en Cloud Run que ofrecerá una aplicación web para que los usuarios vean los resultados.

Dividiremos la implementación en 3 codelabs:

Codelab 1: Usa Gemini para compilar una Cloud Function en Java para una aplicación de Gemini.

Codelab 2: Usa Gemini para compilar aplicaciones de IA generativa solo en SQL con BigQuery.

Codelab 3: Usa Gemini para crear una aplicación web de Spring Boot en Java que interactúe con BigQuery.

2. Usa Gemini para compilar una app de IA generativa sin servidores en Java Cloud Function

Qué compilarás

Crearás un

  • Aplicación de Java Cloud Functions que implementa Gemini 1.0 Pro para tomar una instrucción específica como entrada en forma de array JSON y muestra una respuesta (valor JSON etiquetado como "replies").
  • Realizarás los pasos de compilación e implementación con la ayuda de Gemini

3. Requisitos

  • Un navegador, como Chrome o Firefox.
  • Un proyecto de Google Cloud con la facturación habilitada.

Estos son los requisitos previos:

Crea tu proyecto

  1. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información sobre cómo verificar si la facturación está habilitada en un proyecto.

Activa Cloud Shell

  1. Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en Google Cloud y que viene precargado con bq:

En la consola de Cloud, haz clic en Activar Cloud Shell en la esquina superior derecha: 6757b2fb50ddcc2d.png

  1. Una vez que te conectes a Cloud Shell, deberías ver que ya se te autenticó y que el proyecto ya se configuró con el ID de tu proyecto. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto.
gcloud config list project
  1. Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>

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

4. Habilita Gemini para Google Cloud y las APIs necesarias

Habilitar Gemini

  1. Navega a Gemini para Google Cloud en Marketplace para habilitar la API. También puedes usar el siguiente comando:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
  1. Visita la página de Gemini y haz clic en "Comenzar a chatear".

Importante: Sigue los pasos 1 y 2 de este codelab para comenzar a usar Gemini y habilitarlo en el IDE de Cloud Shell, respectivamente.

Habilita otras APIs necesarias

¿Cómo haríamos eso? Preguntémosle a Gemini, ¿de acuerdo? Pero antes de eso, recuerda lo siguiente:

Los LLM no son determinísticos. Así que, mientras pruebas estas instrucciones, la respuesta que recibas podría ser diferente a las que se muestran en la captura de pantalla.

Para ir a la consola de chat de Gemini, haz clic en el ícono "Abrir Gemini" que está en la esquina superior derecha, junto a la barra de búsqueda, en la consola de Google Cloud.

26e1491322855614.png

Escribe esta pregunta en la sección "Ingresa una instrucción aquí":

How do I enable the cloud functions api using a gcloud command? 

Deberías obtener una respuesta similar a la siguiente:

gcloud services enable cloudfunctions.googleapis.com

Cópiala (puedes usar el ícono de copiar en la parte superior del fragmento de comando) y ejecútala en la terminal de Cloud Shell para habilitar las Cloud Functions. Haz lo mismo para Cloud Run, ya que necesitamos ambos para compilar e implementar Cloud Functions:

gcloud services enable \
  cloudfunctions.googleapis.com \
  aiplatform.googleapis.com \
  run.googleapis.com \
  cloudbuild.googleapis.com

5. Prepara una plantilla de Cloud Functions con Gemini

En este punto, supongo que ya tienes habilitado Gemini en tu IDE de Cloud Shell.

Para abrir el editor de Cloud Shell, haz clic en el ícono Abrir editor en la esquina superior derecha de la terminal de Cloud Shell (por lo general, prefiero abrir la terminal y el editor en pestañas separadas en paralelo para poder escribir código en una y compilar en otra).

edd258384bc74f1f.png

Una vez que tengas el editor abierto, asegúrate de que el logotipo de Gemini, ubicado en la esquina inferior derecha de la consola del editor, esté activo (y no cancelado). Además, asegúrate de que tu proyecto de Google Cloud, en la esquina inferior izquierda, apunte al proyecto activo actual con el que quieres trabajar. Si están inactivos, haz clic en ellos, autoriza los proyectos y selecciona el proyecto de Google Cloud al que deseas dirigirlos para activarlos.

Una vez que ambos estén activos, haz clic en el nombre del proyecto en la esquina inferior izquierda y, en la lista emergente que se abre, titulada "Cloud Code", desplázate hacia abajo hasta "Nueva aplicación".

ca08602b576ebd57.png

En esa lista, selecciona la aplicación de Cloud Functions. En la lista que aparece, selecciona Java:

ac2b44245949da68.png

En la lista resultante, escribe el nombre del proyecto "duetai-gemini-calling" en lugar de helloworld y haz clic en OK.

bf9cfe86e35cdced.png

¡Hip, hip, hurra! Iniciaste tu aplicación sencilla de Cloud Functions en Java con Gemini y no hiciste mucho más que habilitar y activar los parámetros de configuración, ¿estamos de acuerdo?

Esta es la estructura del proyecto que deberías ver:

d56e410fb76f183f.png

En este momento, ya puedes implementar la función. Pero no es por eso que comenzamos esto. Avancemos y compilemos la implementación de la API de Gemini Pro en esta Cloud Function con el SDK de Java.

Ahora compilemos la funcionalidad para nuestro caso de uso, que es invocar el modelo de Gemini Pro en esta Cloud Function. Para ello, puedes agregar más instrucciones y desarrollar tu código de forma incremental con Gemini o escribir la lógica por tu cuenta. Voy a combinar ambos métodos.

6. Agregar dependencias

En la consola de chat de Gemini (la que se encuentra dentro del editor de código de Cloud en el panel izquierdo), escribe la siguiente instrucción:

what is the maven dependency for com.google.cloud.vertexai library

La razón por la que solicito específicamente el paquete com.google.cloud.vertexai es porque eso es lo que estoy usando en mi código fuente donde implemento el código de invocación de Gemini.

Obtuve este resultado:

62c4295b9b4654e9.png

 <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-vertexai</artifactId>
      <version>0.1.0</version>
    </dependency>

Cópialo y pégalo en el archivo pom.xml, justo antes de la etiqueta </dependencies>. Reemplaza la versión por 0.1.0 (puedes quitar la etiqueta <version> si usas la BOM de Spring Cloud GCP para administrar los números de versión de spring-cloud-gcp).

La sección de dependencia debería verse de la siguiente manera:

1800f10af9331210.png

Si es necesario, asegúrate de actualizar los números de versión para que coincidan con los anteriores. Si observas, también incluí otra dependencia junto con ella:

    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10</version>
    </dependency>

7. Modifica el punto de entrada y el nombre de la clase de la función

  1. Navega al archivo "launch.json" en la carpeta ".vscode". Edita el nombre de la función de "function-hello-world" a "function-gemini-calling".
  2. Actualiza el valor de entryPoint de "cloudcode.helloworld.HelloWorld" a "cloudcode.bookshelf.Bookshelf".
  3. Ahora, navega al archivo de clase Java "HelloWorld.java". Cambia el nombre del paquete a package cloudcode.biblioteca. En el error que aparece, haz clic en la bombilla amarilla y, luego, en la opción que dice "Move HelloWorld.java" para empaquetar cloudcode.biblioteca;.

38d721978bddc8a8.png

  1. Actualiza el nombre de la clase a Bookshelf. En el error que aparece, haz clic en la pequeña bombilla amarilla y selecciona "Rename file to Bookshelf.java". Selecciona esa opción.

8. Crea el método que llama a Gemini Pro

Implementaremos esta funcionalidad en la clase Bookshelf.java. Reemplaza Bookshelf.java por el siguiente código:

package cloudcode.bookshelf;
import java.io.BufferedWriter;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.cloud.vertexai.VertexAI;
import com.google.cloud.vertexai.api.GenerateContentResponse;
import com.google.cloud.vertexai.api.GenerationConfig;
import com.google.cloud.vertexai.generativeai.preview.GenerativeModel;
import com.google.cloud.vertexai.generativeai.preview.ResponseHandler;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import java.util.LinkedHashMap;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;

public class Bookshelf implements HttpFunction {
  private static final Gson gson = new Gson();

 @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    BufferedWriter writer = response.getWriter();

 // Get the request body as a JSON object.
 JsonObject requestJson = new Gson().fromJson(request.getReader(), JsonObject.class);
 JsonArray calls_array = requestJson.getAsJsonArray("calls");
 JsonArray calls = (JsonArray) calls_array.get(0);
 String context = calls.get(0).toString().replace("\"", "");

 //Invoke Gemini model
  String raw_result = callGemini(context);
  raw_result = raw_result.replace("\n","");
  String trimmed = raw_result.trim();
  List<String> result_list = Arrays.asList(trimmed);
  Map<String, List<String>> stringMap = new LinkedHashMap<>();
  stringMap.put("replies", result_list);
 
  // Serialization
  String return_value = gson.toJson(stringMap);
  writer.write(return_value);
    }
  public String callGemini(String context) throws IOException{
      String res = "";
        try (VertexAI vertexAi = new VertexAI("REPLACE_WITH_YOUR_PROJECT_ID", "us-central1"); ) {
          GenerationConfig generationConfig =
              GenerationConfig.newBuilder()
                  .setMaxOutputTokens(2048)
                  .setTemperature(0.4F)
                  .setTopK(32)
                  .setTopP(1)
                  .build();  
        GenerativeModel model = new GenerativeModel("gemini-pro", generationConfig, vertexAi);
        GenerateContentResponse response = model.generateContent(context);
        res = ResponseHandler.getText(response);
      }catch(Exception e){
        System.out.println(e);
        }
        return res;
    }
}

Esta clase espera una entrada en la estructura JSON como se muestra a continuación:

{ "calls": [["YOUR_PROMPT_HERE"]] }

Muestra una respuesta como la siguiente:

(Json) Map<String, List<String>> {"replies": ["response"]}

Prueba la opción de chat de Gemini en el editor de Cloud Shell, en el panel izquierdo, para explicar el código. Como alternativa, puedes seleccionar todo el código, hacer clic en la bombilla amarilla que se encuentra en la esquina superior izquierda de la selección y elegir la opción "Explicar esto".

66fb67507793e368.png

9. Implementa la función de Cloud Functions

Ahora que la función de Cloud Functions está lista, pidamos a Gemini cómo implementarla. Ve al chat de Gemini en el editor de Cloud Code y, luego, ingresa lo siguiente:

   How to deploy this Cloud Function with a gcloud command?

Recibí la siguiente respuesta:

9f9db98933841864.png

Ahora quiero investigar más a fondo. Así que le pedí a Gemini que me diera el comando completo de gcloud functions deploy. La respuesta es la siguiente:

b77701c00dc3eaf1.png

No puedo decir si recibirás la misma respuesta, pero me sorprendió ver que se completa con algunos detalles más, como se ve en la siguiente imagen:

Formato del cuerpo de la solicitud:

82bf20304143a374.png

y

Formato de la respuesta:

ade55b3de5d823a6.png

Ahora, implementemos la función ejecutando el comando de gcloud que Gemini nos dio. Para ello, debemos abrir la terminal de Cloud Shell. Puedes abrirlo en una nueva pestaña de https://console.cloud.google.com y asegurarte de que esté seleccionado el proyecto correcto. Para abrir la terminal de Cloud Shell, haz clic en el ícono Activate Cloud Shell en la esquina superior derecha de la consola y, luego, usa el siguiente comando para asegurarte de que te encuentras en la carpeta del proyecto correcta:

cd duetai-gemini-calling

Seguido del siguiente comando:

gcloud functions deploy bookshelf --runtime java17 --trigger-http --entry-point cloudcode.bookshelf.Bookshelf --allow-unauthenticated

Se te preguntará "¿Permitir invocaciones no autenticadas de la función nueva [bookshelf]?". Di "y" y presiona Intro. Luego, responde algunas preguntas, si corresponde. Se implementará tu Cloud Function sin servidores con la URL implementada: https://us-central1-*******.cloudfunctions.net/biblioteca.

Ahora invoquemos las funciones de Cloud Functions implementadas y probémosla.

Nota: Si omitiste accidentalmente la pregunta "Permitir invocaciones no autenticadas" o seleccionaste "N", no podrás acceder al resultado de Cloud Functions y verás un "error de permisos" sin otorgar parámetros de configuración de IAM adicionales. Así que presta atención a eso.

10. Llama a la Cloud Function implementada

Preguntémosle a Gemini. Ingresé la instrucción

How to call the deployed cloud function?

Obtuve el siguiente resultado: (es posible que veas la misma respuesta exacta o no, no dudes en experimentar con la instrucción y ver la diferencia en las respuestas).

1d2242715571fe6f.png

Sondea el chat con preguntas específicas sobre formas alternativas de invocar la función implementada, llamar con el comando gcloud, etcétera. Envié la siguiente instrucción:

how to call the deployed cloud function using gcloud

Recibí la siguiente respuesta: e7b29b2cfb57782c.png

Puedes usar esta respuesta ("gcloud functions call") desde la terminal con ajustes para que funcione en nuestro caso (como alternativa, intenta pasar los parámetros en la instrucción y comprueba si puedes obtener la llamada detallada de gcloud functions en respuesta):

gcloud functions call bookshelf --region=us-central1 --gen2 --data '{"calls":[["Hello! This is my test prompt."]]}'

Este es mi resultado:

6f396d915251db78.png

11. Limpia

Para borrar las funciones de Cloud Functions que creaste antes, haz clic en el botón BORRAR en la página de detalles de Cloud Functions.

12. Felicitaciones

Compilaste, implementaste y probaste correctamente una Cloud Functions de Java para llamar a Gemini 1.0 Pro con Gemini. Esta aplicación toma la instrucción de entrada relacionada con la recomendación de libros con el resumen y el tema de los libros.