En ocasiones la creación de contenidos es un problema para presentar información en la web y por eso es importante, por no decir imprescindible conectar tu aplicación Laravel con una inteligencia artificial.
La integración con Gemini, el modelo de lenguaje de Google, te permite desbloquear un abanico de posibilidades para crear experiencias de usuario más completas y personalizadas.
En este artículo, te guiaremos paso a paso a través del proceso de integración de Gemini en tu proyecto Laravel, desde la configuración de la API hasta la implementación de funcionalidades avanzadas.
Empezamos!
Como siempre comenzamos creando un proyecto nuevo con la última versión de Laravel.
composer create-project laravel/laravel gemini
Lo primero que tenemos que hacer es instalar la paquetería correspondiente, mediante la herramienta Composer. En este caso, instalaremos la API de Gemini y además guzzle, para poder manejar de una forma más sencilla las llamadas a la API de Gemini.
composer require google-gemini-php/client
Lenguaje del código: JavaScript (javascript)
composer require guzzlehttp/guzzle
Lenguaje del código: JavaScript (javascript)
Una vez instalada la paquetería, nos vamos a Google, y buscamos nuestra API KEY.
Para ello accedemos al portal de AI Studio, con nuestra cuenta de usuario
Si no la tienes creada, has de seguir todos los pasos para el alta. Debes indicar un número de tarjeta de crédito, aunque no se te cobrará nada hasta que gastes tus créditos gratuitos. Si lo que estás haciendo son pruebas de desarrollo, no te preocupes, que para llegar a consumir un euro, hay que hacer muchas pruebas, con lo que tendrás para unas cuantas semanas antes de agotar los créditos gratuitos y en cualquier caso, nunca se te cobrará nada sin pedirte previamente autorización. Así que tranquilo.
Esta API Key la vamos a llevar a un sitio seguro, salvo que necesites disponer de una cuenta de la API por usuario, el lugar más adecuado es el fichero de variables de entorno.
Añadimos al final (puede ser en cualquier punto, pero mejor lo mantenemos ordenado) la siguiente línea, sustituyendo el texto a partir del igual por tu clave API.
GEMINI_API_KEY=…B3RY
A utilizar la API
Como cada cosa debe estar en su sitio dentro de Laravel, vamos a crear un controlador para gestionar las peticiones a la API y posteriormente disponbilizarlas en la web.
Creamos un controlador con
php artisan make:controller GeminiController
Lenguaje del código: CSS (css)
Y a partir de aquí vamos a jugar un poco con las opciones. Empezamos por lo más sencillo
Generación de texto
Creamos una función que sirva para obtener un texto de bienvenida a nuestra web y vamos a aprovechar para aprender un poco de historia. Le pediremos a nuestra inteligencia artificial que nos indique alguna de las efemérides más importantes del día actual.
Primero obtenemos la fecha actual a partir de Carbon (no de olvides de importar la clase) y nos quedamos con el día y el nombre del mes.
A continuación incluimos el día y el mes en el prompt que hemos creado al efecto y solicitamos a Gemini que nos devuelva un texto en base a nuestro prompt, que será lo que devolvamos a nuestra vista:
public static function getText(){
// Carbon::setLocale('es');
$fechaActual = Carbon::now();
$dia = $fechaActual->day;
$nombreMes = $fechaActual->monthName;
$prompt = "Dime una efeméride del día $dia de $nombreMes a nivel mundial y en España. Utiliza el formato 'Tal día como hoy, en España ... y a nivel mundial ...' siendo los tres puntos un texto breve sobre cada uno de los hechos relevalentes";
$apiKey = getenv('GEMINI_API_KEY');
$client = Gemini::client($apiKey);
$result = $client->geminiPro()->generateContent($prompt);
return view ('gemini.text', ['fecha' => "$dia de $nombreMes", 'result' => $result->text()]);
}
Lenguaje del código: PHP (php)
La línea comentada, te puede hacer falta si tu aplicación está internacionalizada y quieres asignar la configuración regional al idioma español solamente para este método. En mi caso no ha hecho falta, porque lo he indicado en el fichero .env.
Las rutas
Primero cambiamos la ruta de Welcome por una página base que se llamará inicio. Y también creamos la ruta que permitirá llamar a la función del controller que acabamos de crear.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\GeminiController;
Route::get('/', function () {
return view('inicio');
});
Route::get('/text', [GeminiController::class, 'getText'])->name('geminiGetText');
Lenguaje del código: HTML, XML (xml)
Las vistas
Primero una vista inicial que solamente contendrá
php artisan make:view inicio
Lenguaje del código: CSS (css)
Que tendrá simplemente un enlace a la ruta de geminiGetText
Y la correspondiente a nuestra primera interacción con IA
php artisan make:view gemini.text
Lenguaje del código: CSS (css)
En esta página, crearemos un espacio para indicar que hoy es el día que nos llega como parámetro $fecha y justo debajo, si nos ha devuelto información nuestra IA, indicaremos el contenido del primer texto propuesto. Esto llega en este formato por las características de Gemini, que permite generar varias alternativas o borradores para que seamos nosotros quienes elijamos. En este caso, confiaremos en su buen criterio y nos quedamos con la primera opción.
<html>
<body>
<h1>Hoy es {{$fecha}} </h1>
@if(isset($result))
<div>
{{$result}}
</div>
@endif
</body>
</html>
Lenguaje del código: HTML, XML (xml)
A probar
Pues vamos a probar. Como no sé en qué fecha vas a leer estas líneas, voy a utilizar una fecha al azar, el 5 de marzo (que es al azar, no porque sea mi cumpleaños). Y tenemos este resultado.
Ten cuidado, que en muchos casos, las inteligencias artificiales se ponen creativas y dan resultados un tanto imprecisos. Pero en cualquier caso, ya hemos visto como obtener un contenido nuevo, generado por inteligencia artificial sin nuestra intervención.
Si vas a poner esto al inicio de tu web pública, te recomiendo que solamente hagas una petición a la IA por día y guardes en una base de datos local el resultado. De esta forma, te ahorrarás unos cuantos tokens.
Interpretación de imágenes
Vamos a complicar un poco la llamada y para ello utilizaremos el modelo de análisis gráfico.
Creación de elementos
Nos vamos al controlador y utilizamos el método geminiProVision que es el que nos indica el propietario del paquete en su repositorio de GitHub.
Le indicamos como prompt que explique el contenido de la siguiente imagen y para ello elegimos una imagen de la web de CodeMotion, en concreto, la que corresponde a los segundos previos a la Keynote inaugural de la edición de 2023:
El segundo parámetro, en este caso es la imagen. Normalmente, las IA no entienden de urls y si lo hacen (Gemini sí que es capaz de interpretar el contenido de una url), no lo hacen del todo bien. Por este motivo, lo nos decantamos por obtener la imagen en formato base64 y pasarla como parámetro. En este caso, es una imagen de tipo jpg por lo que si queremos procesar un png o cualquier otro formato, debemos cambiar el MimeType.
Creamos la ruta en este caso añadimos la siguiente línea al fichero web.php
Route::get('/image', [GeminiController::class, 'getImageComment'])->name('geminiGetImage');
Lenguaje del código: PHP (php)
Creamos la página, también muy sencilla, a partir de la anterior. Le quitamos la fecha y poco más, con lo que queda algo así como:
<html>
<body>
<h1>Esto es lo que representa la imagen</h1>
@if(isset($result))
<div>
{{$result}}
</div>
@else
<p>No hay contenido disponible.</p>
@endif
</body>
</html>
Lenguaje del código: HTML, XML (xml)
Y vamos a probar
Ups!
El resultado no es el esperado, así que no nos queda más remedio que investigar cómo cambiar del modelo ProVision a 1.5 flash que nos recomienda el mensaje de error de Gemini.
Para ello debemos localizar dos ficheros y modificarlos. En nuestro código del controlador, estamos indicando que el modelo es ProVision con la instrucción geminiProVision, que se encuentra en el fichero /vendor/google-gemini-php/client/src/Client.php
<?php
declare(strict_types=1);
namespace Gemini;
use Gemini\Contracts\ClientContract;
use Gemini\Contracts\TransporterContract;
use Gemini\Data\Model;
use Gemini\Enums\ModelType;
use Gemini\Resources\ChatSession;
use Gemini\Resources\EmbeddingModel;
use Gemini\Resources\GenerativeModel;
use Gemini\Resources\Models;
final class Client implements ClientContract
{
/**
* Creates an instance with the given Transporter
*/
public function __construct(private readonly TransporterContract $transporter)
{
}
/**
* Lists available models.
*/
public function models(): Models
{
return new Models(transporter: $this->transporter);
}
public function generativeModel(ModelType|string $model): GenerativeModel
{
return new GenerativeModel(transporter: $this->transporter, model: $model);
}
public function geminiPro(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO);
}
public function geminiProVision(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO_VISION);
}
public function embeddingModel(ModelType|string $model = ModelType::EMBEDDING): EmbeddingModel
{
return new EmbeddingModel(transporter: $this->transporter, model: $model);
}
/**
* Contains an ongoing conversation with the model.
*/
public function chat(ModelType|string $model = ModelType::GEMINI_PRO): ChatSession
{
return new ChatSession(model: $this->generativeModel(model: $model));
}
// Añadido
public function geminiPro1_0(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO_1_0);
}
public function geminiProLatest1_0(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO_1_0_LATEST);
}
public function geminiPro1_5(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO_1_5);
}
public function geminiProFlash1_5(): GenerativeModel
{
return $this->generativeModel(model: ModelType::GEMINI_PRO_1_5_FLASH);
}
// Fin añadido
}
Lenguaje del código: HTML, XML (xml)
En este fichero añadiremos los modelos de Gemini posteriores a la creación del paquete, antes de la última llave de cierre, para que sean métodos disponibles en la clase Cliente.
Aquí hacemos referencia a los nombres de los modelos, o mejor dicho a unos valores definidos en la enumeración de modelos soportados por el paquete.
Agregamos estos modelos a la clase ModelType, al igual que en el caso anterior, lo hacemos justo antes de la última llave de cierre del fichero /vendor/google-gemini-php/client/src/Enums/ModelType.php
<?php
declare(strict_types=1);
namespace Gemini\Enums;
enum ModelType: string
{
case GEMINI_PRO = 'models/gemini-pro';
case GEMINI_PRO_VISION = 'models/gemini-pro-vision';
case EMBEDDING = 'models/embedding-001';
// Añadido
case GEMINI_PRO_1_0 = 'models/gemini-1.0-pro';
case GEMINI_PRO_1_0_LATEST = 'models/gemini-1.0-pro-latest';
case GEMINI_PRO_1_5 = 'models/gemini-1.5-pro';
case GEMINI_PRO_1_5_FLASH = 'models/gemini-1.5-flash';
// Fin añadido
}
Lenguaje del código: HTML, XML (xml)
Esta lista de la documentación de referencia que nos ofrece el proveedor de la API, en este caso, Google.
Por fin!
Ahora sí, probamos y nos describe el contenido de la imagen
Pues con esto, hemos logrado avanzar un paso más en nuestro conocimiento de Laravel. No sólo hemos incorporado una de las API más potentes de la inteligencia artificial a nuestro Laravel, sino que adicionalmente nos hemos encontrado con nuestro primer paquete desactualizado. Y como no nos gusta quedarnos a las puertas de finalizar un objetivo, nos hemos puesto manos a la obra a modificar el código de un paquete de terceros para hacer una pequeña adaptación que cubra nuestras necesidades del proyecto.
Ahora puedes seguir todos los paso o bien descargar directamente el repositorio de git desde aquí.