Cómo integrar la API de Gemini 1.5 Pro en Next.js (App Router)

Guía práctica paso a paso de cómo consumir la API de IA multimodal de Google en Next.js, configurando claves de entorno, streaming de texto y llamadas multimodales.

El lanzamiento de la familia de modelos **Gemini 1.5** por parte de Google introdujo avances significativos para los desarrolladores, destacando una ventana de contexto de hasta 2 millones de tokens y soporte nativo para análisis multimodales (procesamiento de audio, video, imágenes y archivos PDF).

En este artículo, construiremos una integración profesional utilizando **Next.js App Router** y el SDK oficial de Google Generative AI para Node.js, mostrando cómo configurar controladores de rutas, procesar respuestas de forma segura e implementar streaming en tiempo real para mejorar la UX.

1. Configuración de Entorno e Instalación

Primero, necesitará obtener una clave de acceso (API Key) gratuita en el portal **Google AI Studio**. Con la clave lista, agréguela a su archivo de configuración de variables de entorno local .env.local:

GEMINI_API_KEY=tu_clave_aqui

En la carpeta de su proyecto de Next.js, instale el paquete del SDK oficial de Google:

npm install @google/generative-ai

2. Creando el Endpoint de API en Next.js (Route Handler)

Para mantener su clave de API protegida y evitar exponerla en el navegador de los visitantes, todas las llamadas a la API de Gemini deben realizarse a través de su servidor. Crearemos un Route Handler en Next.js que devuelva las respuestas mediante streaming utilizando Server-Sent Events (SSE).

Cree el archivo app/api/chat/route.ts:

import { GoogleGenerativeAI } from "@google/generative-ai";
import { NextResponse } from "next/server";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || "");

export async function POST(req: Request) {
  try {
    const { prompt } = await req.json();
    
    // Inicializa el modelo Gemini 1.5 Pro
    const model = genAI.getGenerativeModel({ model: "gemini-1.5-pro" });
    
    // Realiza la llamada generativa con streaming
    const result = await model.generateContentStream(prompt);
    
    // Configura el canal de streaming
    const encoder = new TextEncoder();
    const stream = new ReadableStream({
      async start(controller) {
        for await (const chunk of result.stream) {
          const text = chunk.text();
          controller.enqueue(encoder.encode(text));
        }
        controller.close();
      },
    });

    return new Response(stream, {
      headers: {
        "Content-Type": "text/plain; charset=utf-8",
        "Transfer-Encoding": "chunked",
      },
    });
  } catch (error) {
    return NextResponse.json({ error: "Error interno del servidor" }, { status: 500 });
  }
}

3. Consumiendo el Stream de IA en React (Client-Side Component)

En la parte cliente, leeremos el cuerpo de la respuesta como un stream de lectura (ReadableStream) para actualizar el estado del chat progresivamente, logrando el efecto de escritura en tiempo real.

Aquí un ejemplo de implementación del componente de chat:

"use client";

import { useState } from "react";

export default function ChatWindow() {
  const [prompt, setPrompt] = useState("");
  const [response, setResponse] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setResponse("");
    setLoading(true);

    try {
      const res = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ prompt }),
      });

      if (!res.body) return;
      const reader = res.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        const chunk = decoder.decode(value, { stream: true });
        setResponse((prev) => prev + chunk);
      }
    } catch (err) {
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="chat-container">
      <form onSubmit={handleSubmit}>
        <input 
          value={prompt} 
          onChange={(e) => setPrompt(e.target.value)} 
          placeholder="Escribe tu pregunta..." 
        />
        <button type="submit" disabled={loading}>Enviar</button>
      </form>
      <div className="output">{response}</div>
    </div>
  );
}

4. Llamadas Multimodales: Envío y análisis de imágenes

Para procesar archivos de medios (como fotos o capturas), convertiremos el archivo a formato Base64 y lo pasaremos al SDK de Gemini:

// Función auxiliar para formatear imágenes para el SDK de Gemini
function fileToGenerativePart(buffer: Buffer, mimeType: string) {
  return {
    inlineData: {
      data: buffer.toString("base64"),
      mimeType
    },
  };
}

// Ejecutando una llamada multimodal en el servidor
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
const imagePart = fileToGenerativePart(imageBuffer, "image/png");

const result = await model.generateContent([
  "Describe lo que ves en esta imagen y enumera posibles fallas de diseño de interfaz (UI).",
  imagePart
]);
console.log(result.response.text());

Conclusión

Integrar la API de Gemini 1.5 Pro en Next.js permite desarrollar soluciones avanzadas de inteligencia artificial con alto desempeño del lado servidor y pantallas interactivas de cara al usuario final. La combinación de rutas seguras, Server-Sent Events y soporte de multimodalidad nativa le otorga a sus flujos web un potencial enorme.