Boas-vindas a mais um curso sobre Next.js. Desta vez, vamos construir um chatbot.
Meu nome é Vinicios Neves, instrutor da Alura.
Audiodescrição: Vinicios se identifica como um homem branco. É careca e possui barba e bigode. No rosto, usa óculos de armação quadrada, preta e grossa. No corpo, veste uma camisa azul-escuro. Está sentado em uma cadeira gamer, cinza e preta. Ao fundo, uma parede lisa, iluminada em tons de azul e rosa.
Neste curso, vamos implementar o Vidy, um assistente virtual que fala sobre filmes. Ao concluir o projeto, poderemos pedir a ele recomendações de filmes com robôs gigantes, por exemplo, e ele responderá com essas indicações.
Vamos desenvolvê-lo do zero, utilizando o SDK da Vercel. Focaremos em um misto entre a interface de pessoa usuária e o lado do servidor.
Prepare-se para começar. Esperamos você na primeira aula.
Começaremos a construir chatbot para conversar especificamente sobre filmes. O objetivo deste vídeo é utilizar o Vercel e a SDK, sem focar muito no CSS e na componentização dos elementos em React.
Para isso, disponibilizamos um projeto base pronto. O URL estará disponível com mais detalhes na atividade de preparação do ambiente.
Ao carregar o GitHub, podemos clicar no botão verde denominado "Code" para expandi-lo e clicar em "Download ZIP" para baixar a pasta zip e descompactá-la. No caso, faremos o clone, copiando o endereço HTTPS sugerido pelo GitHub acima da opção de download.
Abrindo o terminal da nossa máquina, vamos configurá-lo na área de trabalho. Ao listar as pastas, verificaremos que não há nada lá dentro.
Nesse local, executaremos o comando abaixo para clonar o projeto base.
git clone
Após alguns segundos, entraremos na pasta com cd
mais o nome da pasta e, em seu interior, executaremos o comando abaixo, que é um atalho para npm install
. Isso instalará todos os pacotes necessários para o projeto rodar.
npm i
Após a instalação, limparemos o terminal e abriremos o VSCode na pasta. O VSCode já está configurado para funcionar e interagir com o terminal.
Executaremos code .
para abrir o VS Code diretamente na pasta onde executamos o comando npm install
.
code .
Acessando a aba do explorador, na lateral esquerda, visualizaremos projeto, um Next.js normal. Acessanod o arquivo package.json
dentro da pasta "src", verificaremos as versões dos frameworks:
Quando rodamos npm install
, esses pacotes foram instalados no node_modules
.
Após essas etapas, podemos voltar ao terminal e executar o comando abaixo para levantar o projeto.
npm run dev
Após um momento, o servidor estará disponível na porta 3000. Copiaremos o endereço disponibilizado e colaremos no navegador.
http://localhost:3000
Após carregar essa página no navegador, veremos a estrutura do chatbot.
A estrutura base está implementada, mas é apenas visual, sem comportamento. Ao enviar uma mensagem no campo de texto inferior, nada acontece, O Next.js apenas recarrega a página.
Com o projeto base rodando, começamos a implementar o chatbot. Voltando ao terminal, abriremos uma nova aba para não interromper o npm run dev
em execução. Na nova aba, rodaremos o comando abaixo para instalar a biblioteca AI, o Vercel SDK, que configuraremos para controlar o fluxo do front-end ao back-end, processando com a LLM desejada.
npm i ai
Com a biblioteca instalada, o terminal confirmará a adição dos pacotes sem vulnerabilidades.
added 60 packages, and audited 461 packages in 6s
202 packages are looking for funding
run
npm fund
for detailsfound 0 vulnerabilities
Voltando ao explorador do VSCode, acessando o caminho de pastas "src > app", abriremos o arquivo page
. Há apenas um componente na página, o ChatContainer
.
Clicando no nome dele com "Command + Clique esquerdo" (ou "Ctrl + clique esquerdo" no Windows), abriremos o arquivo index.jsx
no caminho de pastas "src > components > ChatContainer", que exibirá o bloco ChatContainer
.
Dentro deste bloco, há mensagens hardcoded, ou seja, uma lista fixa de mensagens, além do ChatHeader
, das mensagens em si e do formulário.
Clicando no ChatForm
com "Command + clique esquerdo", acessaremos o arquivo index.jsx
do formulário HTML (form
), dentro do caminho de pastas "src > components > ChatForm". Nesse arquivo, notaremos que o formulário contém o input
e o botão para enviar a mensagem.
Precisamos conectar essa estrutura ao SDK.
Deixaremos esse arquivo do "ChatForm" aberto e voltaremos ao index.jsx
do ChatContainer
. Ao instalar a biblioteca AI, recebemos um hook chamado useChat()
. Podemos adicioná-lo entre as chaves do ChatContainer
, abaixo do bloco messages
.
index.jsx
da pasta "ChatContainer":
export const ChatContainer = () => {
const messages = [
]
useChat()
// Código omitido
};
Se o VSCode não sugerir opções de autocomplete, basta importar manualmente com import { useChat } from 'ai/react'
no final da relação de import
s.
import Button from '../Button';
import ChatBubble from '../ChatBubble';
import { ChatForm } from '../ChatForm';
import { ChatHeader } from '../ChatHeader';
import { IconStop } from '../Icons';
import { Loader } from '../Loader';
import { RetryButton } from '../RetryButton';
import styles from './container.module.css';
import { useChat } from 'ai/react'
O hook useChat()
retornará um objeto com tudo que precisamos. Podemos fazer destructuring para separar as partes necessárias com const {} = useChat()
.
O useChat()
nos fornecerá entre as chaves uma lista de messagens
. As mensagens agora vêm do hook, portanto, podemos remover a lista fixa messages
acima dele.
export const ChatContainer = () => {
const { messages } = useChat()
// Código omitido
};
Salvaremos e verificaremos no navegador se há erros. Acessando a guia "Console" na aba de inspeção, não há erros, o que é um bom sinal. No terminal que executa o npm run dev
, tudo também funciona corretamente.
Precisamos controlar os valores do input no lado da clientela. Com um componente React controlado, passamos um value
e um onChange
. O useChat()
fornece input
e handleInputChange
, portanto, os adicionaremos dentro do objeto, após messages
.
O input
tem um valor e um evento onChange
disparado com o HTML quando a pessoa usuária digita.
Além do input
e handleInputChange
, trataremos a submissão do formulário com handleSubmit
do useChat()
.
export const ChatContainer = () => {
const { messages, input, handleInputChange, handleSubmit } = useChat()
// Código omitido
};
No ChatForm
, anotamos use client
, pois com onChange
no input da linha 11, o Next.js 14+ exige essa anotação para componentes do lado do cliente.
Descendo o código até a tag ChatForm
, passaremos antes da barra e do sinal de maior um input={input}
para o JSX, informando o mesmo nome para manter a coerência. Faremos o mesmo para handleInputChange
e handleSubmit
.
export const ChatContainer = () => {
const { messages, input, handleInputChange, handleSubmit } = useChat()
return (
<section className={styles.container}>
<ChatHeader />
<div className={styles.chat}>
{messages.map((msg) => (
<ChatBubble
key={msg.id}
message={msg.message}
isUser={msg.isUser}
onRemove={() => console.log('remove message', msg.id)}
/>
))}
</div>
<ChatForm
input={input}
handleInputChange={handleInputChange}
handleSubmit={handleSubmit}
/>
</section>
);
};
Com isso, temos o componente de ordem maior que gerirá o estado e "cascateará" (enviará em fluxo, de cima para baixo) o que for necessário.
Após enviar ao ChatForm
o que precisamos, vamos acessá-lo. Voltando ao arquivo index.jsx
da pasta "ChatForm", anotaremos o 'use client'
na linha 1, pois adicionaremos um onChange
e um value
dentro da tag input
, abaixo do required
.
index.jsx
da pasta "ChatForm":
'use client'
import styles from './chat.module.css'
import { IconSend } from "../Icons"
export const ChatForm = () => {
return (<form className={styles.form}>
<input
className={styles.input}
placeholder="Digite sua mensagem..."
required
onChange={}
value={}
/>
<button className={styles.btn}>
<IconSend />
</button>
</form>)
}
Quando temos um onChange
, precisamos anotá-lo como use client
ao utilizar o ecossistema do Next na versão 14 e posteriores para evitar erros. Caso contrário, o Next informará que não podemos fazer isso no componente do lado do servidor.
Por fim, acessando a linha que retorna o formulário, em adicionaremos após o className
um onSubmit
. Podemos notar que onChange
, value
e onSubmit
são propriedades nativas do HTML.
'use client'
import styles from './chat.module.css'
import { IconSend } from "../Icons"
export const ChatForm = () => {
return (<form className={styles.form} onSubmit={}>
<input
className={styles.input}
placeholder="Digite sua mensagem..."
required
onChange={}
value={}
/>
<button className={styles.btn}>
<IconSend />
</button>
</form>)
}
Em seguida, podemos recolher o que recebemos via props (propriedades). Na linha que inicia a const ChatForm
, entre os parênteses iniciais, adicionaremos um par de chaves com Input
, handleInputChange
e handleSubmit
.
Por fim, "cascatearemos" os três itens, adicionando-os entre as chaves dos três elementos HTML correspondentes, dentro do JSX. O submit
será chamado quando o formulário for submetido em onSubmit={}
, o handleInputChange
será no onChange={}
do input
e o valor é o input
em si, no value={}
.
'use client'
import styles from './chat.module.css'
import { IconSend } from "../Icons"
export const ChatForm = ({ input, handleInputChange, handleSubmit }) => {
return (<form className={styles.form} onSubmit={handleSubmit}>
<input
className={styles.input}
placeholder="Digite sua mensagem..."
required
onChange={handleInputChange}
value={input}
/>
<button className={styles.btn}>
<IconSend />
</button>
</form>)
}
Com isso, conectamos todos os valores entregues pelo React Hook useChat
do chatContainer
à nossa marcação.
Recarregaremos no navegador a página da aplicação e notaremos que ainda não há erros no console, nem no terminal da nossa máquina.
Com a infraestrutura pronta, a biblioteca AI instalada, implementamos useChat()
, obtendo tudo necessário do lado do cliente: input
, onChange
, onSubmit
e as mensagens.
A seguir, precisamos lidar com o lado do servidor ao submeter o formulário, capturando-o e processando-o de alguma forma.
Agora que já temos o lado do cliente implementado, vamos seguir para o lado do servidor. Quando alguém acessar e carregar nosso formulário e enviar uma mensagem, por exemplo, "Olá", essa mensagem deve chegar a algum lugar. O próprio navegador já indicou que falta implementar algo, que é o POST para nossa rota /api/chat
. Precisamos implementar essa lógica.
Vamos usar um recurso do Next.js para API Routes e implementar a rota /api/chat
. No VS Code, dentro da pasta "app", que é nosso app router, criaremos um novo arquivo. Dentro da pasta "app", criaremos uma pasta chamada "api", e dentro dela, outra pasta chamada "chat". Esse caminho, "api/chat", indicará ao Next.js qual rota a função que vamos implementar responderá. Dentro dessa pasta, criaremos um arquivo "route.js".
Precisamos implementar para indicar ao Next.js a qual verbo HTTP vamos responder. Faremos um export
de uma função assíncrona, async function POST
. Quando fazemos um export
de uma função assíncrona POST
, o Next.js já sabe que, se alguém fizer um post para essa rota, ele responderá com o resultado dessa função.
Também precisaremos do que vier na requisição, pois teremos que pegar o input dado pela pessoa usuária. Chamaremos isso de request
, que é a requisição recebida como parâmetro.
export async function POST(request) {
}
Precisamos agora dar dois passos: primeiro, receber o input, ou seja, a mensagem enviada, e depois processá-la com algum modelo e enviar a resposta. Para esse processamento e envio da resposta, utilizaremos a OpenAI.
Para usar a OpenAI, precisamos instalar uma biblioteca específica. A biblioteca que instalamos no último vídeo não se relaciona de forma específica aos modelos existentes hoje no mercado. Cada modelo tem uma sub-biblioteca específica conforme o modelo.
No terminal, que deixamos aberto no último vídeo, um deles ainda está rodando o npm run dev
, e temos outro que não está rodando nada. Vamos pedir para esse segundo terminal instalar @ai-sdk/openai
, que é a biblioteca que nos permitirá implementar o modelo do ChatGPT ou alguma variante dele, como o 3.5 ou 4.
Após a instalação, podemos começar a importar elementos. Primeiro, pegaremos o que veio do nosso front-end. Faremos um const
preparado, pegando isso do nosso request
para obter um JSON da requisição, ou seja, o corpo da mensagem. Faremos um await request.json()
, pois é assíncrono. Essa é a requisição que o Next.js entrega, e quando pedimos .json()
, ele nos envia tudo que está no corpo da mensagem.
Para utilizar o combo, abriremos o componente "ChatContainer". Dentro dele, temos um index.jsx
, onde implementamos o useChat()
. Quando submetemos, ou seja, no handleSubmit
, ele nos entrega todas as mensagens disponíveis daquele chat. Vamos pegar essas mensagens, messages
, do corpo da requisição e agora podemos pedir para nosso modelo interpretá-las.
Vamos importar da biblioteca que acabamos de instalar, @ai-sdk/openai
, o openAI
. Esse é o objeto de configuração que utilizaremos para definir qual modelo usaremos no processamento.
import { openai } from '@ai-sdk/openai'
export async function POST(request) {
const { messages } = await request.json()
}
Sabendo que esse é o modelo, começaremos a combinar a biblioteca AI com essa específica, ou seja, a genérica com o modelo específico. O processo de gerar essa resposta demora um pouco, então queremos fazer o que chamamos de stream, ou seja, enquanto o servidor gera a resposta, ele mantém a conexão aberta entre o cliente e o servidor, enviando e avisando quando termina.
A stream é uma API que qualquer requisição normal pode usar, não apenas as relacionadas à inteligência artificial.
Qualquer requisição que envolva um processamento longo, envio ou download de um arquivo grande, pode usar esse stream. Deixaremos uma atividade para quem quiser entender mais sobre como uma stream funciona nos bastidores.
Queremos implementar um streamText
. O VS Code nos ajudará com isso, pois o streamText
da biblioteca AI, nosso SDK, cuidará de tudo, permitindo que foquemos na regra de negócio: qual modelo usar, o que responder, etc.
O streamText
espera alguns parâmetros de configuração, um deles é o modelo. Passaremos o openai
, importado na linha 1, como função, indicando qual modelo disponível na OpenAI queremos usar. O VS Code sugere desde o GPT 3.5 turbo até o 4o. Usaremos o 4o.
Após passar o modelo, precisamos dizer ao streamText
quais mensagens serão usadas para gerar a resposta. Ele espera um array de messages
. Não podemos passar as messages
diretamente como um objeto JSON. A própria biblioteca AI fornece uma função que converte esse objeto JSON para o formato que o streamText
precisa. Chamaremos essa função convertToCoreMessages
, passando as mensagens que pegamos na linha 5.
O streamText
recebe como configuração o modelo, estamos usando o GPT-4o da OpenAI, mas poderíamos usar qualquer outro disponível no mercado, fechado ou aberto. Ele também recebe uma lista de mensagens, que é o que estamos focando em implementar nesse chatbot.
import { openai } from '@ai-sdk/openai'
import { convertToCoreMessages, streamText } from 'ai'
export async function POST(request) {
const { messages } = await request.json()
const result = await streamText({
model: openai('gpt-4o'),
messages: convertToCoreMessages(messages)
})
}
Guardaremos o resultado dessa stream em uma constante result
. Como tudo está em inglês, manteremos assim. Sendo assíncrono, faremos um await
. Quando começarmos a ter um resultado, podemos retornar para o front-end. Faremos um return
do result
, deixando que seja streamado, mantendo a conexão aberta enquanto não finaliza.
O método que usaremos para fazer essa ponte do stream é o toDataStreamResponse
. Invocando esse método, implementamos nosso endpoint, nossa API, que receberá o resultado de um formulário. Pegaremos as mensagens, usaremos o streamText
para passar o modelo, todas as mensagens convertidas, e retornaremos isso para o front-end.
import { openai } from '@ai-sdk/openai'
import { convertToCoreMessages, streamText } from 'ai'
export async function POST(request) {
const { messages } = await request.json()
const result = await streamText({
model: openai('gpt-4o'),
messages: convertToCoreMessages(messages)
})
return result.toDataStreamResponse()
}
Escrevemos bastante código, vamos testar no Chrome. Voltando ao Chrome, recarregaremos a página, o navegador está aberto na localhost:3000
. Pediremos, por exemplo, "Me diz quais os filmes mais premiados do Oscar" e veremos se ele responde.
Na aba "Network" de "Inspecionar", podemos ver o que está acontecendo. O chat retornou o que precisávamos, embora a resposta esteja grande. Algo está funcionando, mas a conexão com a parte visual do nosso código não está encaixando.
Precisamos resolver isso. A resposta parece estar chegando, mas ainda não conseguimos exibi-la no chat. Vamos resolver esse bug no próximo vídeo.
O curso Vercel IA SDK: construindo um Chatbot com Next.js possui 101 minutos de vídeos, em um total de 42 atividades. Gostou? Conheça nossos outros cursos de IA para Front End em Inteligência Artificial, ou leia nossos artigos de Inteligência Artificial.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.