Como integrar a API do Gemini 1.5 Pro no Next.js (App Router)

Guia prático passo a passo de como consumir a API de IA multimodal do Google no Next.js, configurando chaves de ambiente, streaming de texto e chamadas multimodais.

O lançamento da família de modelos **Gemini 1.5** pelo Google trouxe avanços significativos para desenvolvedores de software, com destaque para uma janela de contexto gigante de até 2 milhões de tokens e suporte nativo a análises multimodais (leitura de áudio, vídeo, imagens e PDFs).

Neste artigo, vamos construir uma integração profissional utilizando o **Next.js App Router** e o SDK oficial do Google Generative AI para Node.js, mostrando como configurar rotas de API, tratar respostas de forma segura e implementar a renderização de streaming palavra por palavra para melhorar a UX.

1. Configuração do Ambiente e Instalação

Primeiro, você precisará obter uma chave de acesso (API Key) gratuita no **Google AI Studio**. Com a chave em mãos, adicione-a ao seu arquivo de configuração de ambiente local .env.local:

GEMINI_API_KEY=sua_chave_aqui

No diretório do seu projeto Next.js, instale o pacote do SDK oficial da Google:

npm install @google/generative-ai

2. Criando o Endpoint de API no Next.js (Route Handler)

Para manter sua chave de API protegida e evitar expô-la no navegador do cliente, todas as chamadas à API do Gemini devem ser feitas através do servidor. Vamos criar um Route Handler no Next.js que retorna as respostas via streaming utilizando Server-Sent Events (SSE).

Crie o arquivo 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 o modelo Gemini 1.5 Pro
    const model = genAI.getGenerativeModel({ model: "gemini-1.5-pro" });
    
    // Executa a chamada gerando stream
    const result = await model.generateContentStream(prompt);
    
    // Configura o stream de resposta
    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: "Erro interno do servidor" }, { status: 500 });
  }
}

3. Consumindo o Stream de IA no Componente React (Client-Side)

No frontend, vamos ler o corpo da resposta como um stream de leitura (ReadableStream) para atualizar o estado da tela progressivamente, garantindo que o usuário veja a IA digitando em tempo real.

Veja a implementação básica do 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="Escreva sua pergunta..." 
        />
        <button type="submit" disabled={loading}>Enviar</button>
      </form>
      <div className="output">{response}</div>
    </div>
  );
}

4. Chamadas Multimodais: Enviando Imagens

Para analisar mídias (como fotos ou capturas de tela), precisamos converter o arquivo enviado em um buffer do tipo Base64 e passá-lo como parte do array de conteúdo do SDK do Gemini:

// Função auxiliar para estruturar arquivos de imagem para o Gemini
function fileToGenerativePart(buffer: Buffer, mimeType: string) {
  return {
    inlineData: {
      data: buffer.toString("base64"),
      mimeType
    },
  };
}

// Executando chamada multimodal no servidor
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
const imagePart = fileToGenerativePart(imageBuffer, "image/png");

const result = await model.generateContent([
  "Descreva o que você enxerga nesta imagem e liste possíveis bugs de UI.",
  imagePart
]);
console.log(result.response.text());

Conclusão

Integrar o Gemini 1.5 Pro no Next.js permite que você construa soluções de inteligência artificial de ponta com excelente performance de carregamento no servidor e interfaces interativas no navegador. A combinação de rotas de API seguras, streaming de conteúdo SSE e recursos multimodais nativos abre um leque imenso de aplicações para otimizar os fluxos da sua aplicação web.