Construindo um Chatbot
Frontend + IA
Interface mínima de chat — campo, envio, loading e exibição de respostas.
Nesta aula você vai
- Montar UI de chat sem biblioteca pesada
- Enviar mensagem via fetch ao backend
- Tratar estados loading, erro e empty
Frontend + IA
Objetivos
- Criar interface mínima que stakeholders entendem
- Nunca chamar API do LLM direto do browser
HTML + CSS mínimo
<div id="chat">
<div id="messages" aria-live="polite"></div>
<form id="form">
<input id="input" type="text" placeholder="Digite sua pergunta..." autocomplete="off" />
<button type="submit">Enviar</button>
</form>
</div>
JavaScript (cliente)
const messagesEl = document.getElementById('messages');
const form = document.getElementById('form');
const input = document.getElementById('input');
function append(role, text) {
const div = document.createElement('div');
div.className = `msg msg--${role}`;
div.textContent = text;
messagesEl.appendChild(div);
messagesEl.scrollTop = messagesEl.scrollHeight;
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
const text = input.value.trim();
if (!text) return;
input.value = '';
append('user', text);
append('assistant', '...'); // placeholder loading
try {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text }),
});
const data = await res.json();
messagesEl.lastChild.textContent = data.reply ?? data.error;
} catch {
messagesEl.lastChild.textContent = 'Erro de conexão. Tente novamente.';
}
});
Estados obrigatórios
| Estado | UX |
|---|---|
| Idle | Input habilitado |
| Loading | Botão disabled, indicador visual |
| Error | Mensagem clara, input reabilitado |
| Empty | Sugestão: "Pergunte sobre pedidos ou produtos" |
Segurança no frontend
- Sanitize exibição (
textContent, nãoinnerHTMLcom resposta da IA) - Limite tamanho do input (ex: 2.000 chars)
- CSRF token se usar cookies de sessão
React/Vue — mesmo princípio
const [messages, setMessages] = useState([]);
const [loading, setLoading] = useState(false);
async function send(text) {
setMessages(m => [...m, { role: 'user', content: text }]);
setLoading(true);
try {
const { reply } = await fetch('/api/chat', { ... }).then(r => r.json());
setMessages(m => [...m, { role: 'assistant', content: reply }]);
} finally {
setLoading(false);
}
}
Resumo
- UI simples: lista + input + submit
- Frontend → seu
/api/chat, não OpenAI - Loading e erro são parte do produto, não detalhe
textContent/ escape para evitar XSS na resposta do modelo