Olá pessoal, tudo bem? Hoje eu trouxe uma integração com o gemini e next pra criar um simples chat funcional e responsivo. A ideia aqui é fazer algo que seja simples de entender e implementar pra ser um dos teus primeiros projetos usando Gemini API.
🛠️ Tecnologias usadas:
⚡ Next.js
🎨 TailwindCSS – estilização moderna e responsiva
💬 Gemini API – modelo de linguagem da Google
💻 TypeScript – segurança e escalabilidade
Pra tu poder implementar esse projeto, pode dar fork no meu projeto no github aqui -> repo
e criar tua chave de api no -> aistudio
depois cria um arquivo chamado .env.local
e coloca essa chave que foi gerada lá.
GEMINI_API_KEY=tua-chave-aqui
🧐 analisando o projeto:
src/app/api/gemini/route.ts
import { NextRequest, NextResponse } from "next/server";
import { GoogleGenAI } from "@google/genai";
const ERROR_MESSAGE_500 = {
error: "Erro ao gerar mensagem. Verifique sua chave ou modelo.",
};
const MODEL = "gemini-2.0-flash";
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
export async function POST(req: NextRequest) {
const { message: contents } = await req.json();
try {
const result = await ai.models.generateContent({
model: MODEL,
contents,
});
return NextResponse.json(result.text);
} catch (err) {
console.error("Error:", err);
return NextResponse.json(ERROR_MESSAGE_500, { status: 500 });
}
}
Para que esse arquivo funcione, tu precisou usar o npm install @google/genai
. O await ai.models.generateContent
é a função que vai se comunicar com a api e trazer o conteúdo gerado de volta pra ti. Nela tu vai informar o model do gemini api que está usando, nesse caso a gente utilizou o gemini-2.0-flash
.
src/components/ChatMessage.tsx
Já o componente ChatMessage é bem simples, sua função é saber se a mensagem foi gerada pela api ou pela usuária:
import ReactMarkdown from "react-markdown";
const ChatMessage = ({
message,
isUser,
}: {
message: string;
isUser: boolean;
}) => {
return (
<div className={`flex ${isUser ? "justify-end" : "justify-start"} mb-4`}>
<div
className={`p-3 rounded-lg max-w-xs prose ${
isUser ? "bg-blue-500 text-white" : "bg-gray-200 text-black"
}`}
>
<ReactMarkdown>{message}</ReactMarkdown>
</div>
</div>
);
};
export default ChatMessage;
importante: ele também utiliza esse ReactMarkdown
pra interpretar e deixar a UI bonitinha com o que foi recebido em markdown.
Por fim: src/components/Chat.tsx
import { useRef, useState } from "react";
import ChatMessage from "./ChatMessage";
import { Button } from "./ui/button";
import { Card, CardContent, CardTitle } from "./ui/card";
import { Input } from "./ui/input";
type Msg = {
message: string;
isUser: boolean;
};
const Chat = () => {
const inputRef = useRef<HTMLInputElement>(null);
const [messages, setMessages] = useState<Msg[]>([]);
const handleSendMessage = (message: string | undefined) => {
if (!message) return;
setMessages((prev) => [...prev, { message, isUser: true }]);
inputRef.current!.value = "";
fetch("/api/gemini", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ message }),
})
.then((res) => res.json() as Promise<string>)
.then((message) => {
setMessages((prev) => [...prev, { message, isUser: false }]);
})
.catch((error) => {
console.error("Error:", error);
});
};
return (
<Card className="mb-4 max-h-[90vh] flex flex-col">
<CardContent className="flex flex-col max-h-[85vh]">
<CardTitle className="pb-2"> Converse com gemini</CardTitle>
<div className="flex flex-col overflow-y-scroll mb-4">
{messages.map(({ message, isUser }, index) => (
<ChatMessage message={message} isUser={isUser} key={index} />
))}
</div>
<form
className="flex gap-2"
onSubmit={(e) => {
e.preventDefault();
handleSendMessage(inputRef.current?.value);
}}
>
<Input
type="text"
placeholder="Digite sua mensagem..."
className="mb-4"
ref={inputRef}
/>
<Button className="bg-blue-500 text-white">Enviar</Button>
</form>
</CardContent>
</Card>
);
};
export default Chat;
Aqui nesse componente é onde as mensagens são digitadas, enviadas, recebidas e passadas pro ChatMessage.
o handleSendMessage
é quem controla isso basicamente. Nele tu pode notar que existe controle de estado e chamada de api.
🤝 Contribuições:
O projetinho está bem simples e com potencial pra muitas features! Manda tua PR com algumas sugestões!
💬 Feedback:
Me chama aqui nos comentários, ou dá uma olhada no projeto completo no GitHub:
🔗 github.com/analiseburtet/chat-next-gemini