Biz Next.js Chatbot OpenRouter — Instale chatbot AI flutuante no site em 1 minuto
Esta skill insere um chatbot AI em forma de widget flutuante em um projeto Next.js existente. O widget fica no canto inferior direito, responsivo em 3 tamanhos de tela, chama LLMs via OpenRouter com base de conhecimento a partir de FAQ + documentos do curso/produto, renderiza Markdown no balão do assistente (negrito para números/preços, listas com marcadores, links clicáveis, código inline) usando react-markdown + remark-gfm, e extrai e salva leads automaticamente (nome + telefone + e-mail) no KV (Upstash Redis / Vercel KV) quando o usuário fornece todas as informações no chat — o administrador pode visualizá-los através do painel /admin. Objetivo: solopreneur / criador de cursos com bot de suporte automático 24/7 + captura passiva de leads diretamente na landing page de venda do curso, sem perder visitantes que perguntam via chat.
Espírito: Detecta automaticamente tudo que é possível (versão do Next.js, App/Pages Router, TS/JS, Tailwind/CSS), pergunta ao usuário apenas 4 coisas realmente necessárias: (1) qual projeto, se houver vários, (2) FAQ, (3) documentos do produto, (4) tom/nome da marca. O resto é código → funcionando em minutos.
Quando usar
O usuário deseja:
- Adicionar um chatbot AI de suporte ao cliente na landing page de venda de cursos / serviços
- Reduzir a carga de responder perguntas repetitivas (preço, cronograma, reembolso, público-alvo...)
- Um widget de chat compacto no canto inferior direito, sem obstruir o conteúdo
- Um chatbot que entenda precisamente o conteúdo do curso / produto (orientado a FAQ)
- Já possui um projeto Next.js (acabou de executar
/biz-sales-page-layoutou um projeto antigo)
Quando NÃO usar
- Projeto não é Next.js (React puro Vite, Vue, Svelte, HTML simples) → esta skill é especializada em Next.js. Pode ser adaptada, mas não é ideal.
- Necessita de chatbot com RAG (retrieval-augmented) e base de conhecimento com milhares de páginas → requer banco de dados vetorial (Pinecone/Supabase pgvector); esta skill usa um system prompt simples, adequado para conhecimento de até 20 mil tokens.
- Necessita de chatbot com voz / multimodal (envio de imagens) → esta skill é apenas texto.
- Necessita de chatbot que salve histórico de chat por usuário em um banco de dados → esta skill é stateless, com sessão efêmera; pode ser estendida posteriormente.
- Backend não é compatível com Vercel (necessita de long polling, WebSocket persistente) → OpenRouter streaming funciona bem no Vercel Edge, mas se precisar de WebSocket dedicado, é diferente.
O que o usuário receberá
Após a execução da skill:
-
Novos arquivos no projeto Next.js do usuário:
components/Chatbot.tsx(ou.jsx) — interface do widget (renderiza Markdown viareact-markdown+remark-gfm)app/api/chat/route.ts(App Router) OUpages/api/chat.ts(Pages Router) — proxy da API para chamar OpenRouter + extrair lead automaticamente após o streamlib/chatbot-knowledge.ts(ou.js) — base de conhecimento + system prompt (inclui bloco de FORMATAÇÃO DE RESPOSTA + bloco de COLETA ATIVA DE LEAD)lib/chat-lead.ts— CRIADO apenas se o projeto tiver KV/Upstash — extrator e salvador, deduplicação por telefone, TTL de 90 dias, namespacechat-lead:{telefone}- Estilos Markdown
.chatbot-mdanexados aapp/globals.css(a partir detemplates/chatbot-markdown-styles.css) .env.localcriado/atualizado comOPENROUTER_API_KEY=(placeholder).env.example(se ainda não existir) para documentar as variáveis de ambiente- Montagem do
<Chatbot />emapp/layout.tsxoupages/_app.tsx
-
Pacotes adicionais instalados (via gerenciador de pacotes detectado pelo arquivo de lock):
react-markdown— renderiza Markdown com segurança (sem necessidade dedangerouslySetInnerHTML)remark-gfm— GitHub Flavored Markdown (tabelas, links automáticos, texto tachado)
-
Instruções claras ao final da sessão:
- 3 passos que o usuário deve fazer manualmente: (a) obter a chave da API OpenRouter, (b) colar no
.env.local, (c)npm run devpara testar - Como alternar entre os modelos Gemini e Sonnet
- Como atualizar a base de conhecimento posteriormente
- 3 passos que o usuário deve fazer manualmente: (a) obter a chave da API OpenRouter, (b) colar no
Fluxo de trabalho
Passo 1 — Detectar projeto Next.js
Procurar por projetos Next.js candidatos. Executar:
# Procurar package.json que contenha "next" nas dependências, profundidade máxima 4
find /Users/tonyhoang/Documents/GitHub -maxdepth 4 -name "package.json" -not -path "*/node_modules/*" 2>/dev/null | xargs grep -l '"next"' 2>/dev/null | head -20
(Se o usuário estiver em um diretório de trabalho específico, priorizar a busca a partir do cwd; fallback para ~/Documents/GitHub se não encontrar.)
Ramificações:
- 0 projetos: Informar o usuário e parar. Sugerir: "Você tem algum projeto Next.js? Se não, gostaria que eu criasse um novo com
/biz-sales-page-layoute depois voltássemos?" - 1 projeto: Confirmar o caminho com o usuário antes de prosseguir: "Instalarei o chatbot em [caminho]. Tudo bem?"
- ≥ 2 projetos: Listar caminhos + nomes (
namedo package.json) em uma lista numerada e pedir para o usuário escolher: "Encontrei N projetos Next.js. Em qual você gostaria de instalar?"
Passo 2 — Analisar o contexto do projeto
Após o usuário confirmar o projeto, ler:
-
package.json→ verificar:- TypeScript (há
typescriptnas dependências?) - Tailwind (há
tailwindcssnas devDependências?) - Gerenciador de pacotes (arquivo de lock:
pnpm-lock.yaml→ pnpm,yarn.lock→ yarn, padrãonpm) - Versão do Next.js
- TypeScript (há
-
Estrutura de diretórios → verificar:
- Diretório
app/existe → App Router - Diretório
pages/existe (eapp/não existe) → Pages Router - Ambos existem → priorizar App Router para novos arquivos (Next.js está migrando para ele)
- Wrapper
src/→ ajustar caminhos (ex.:src/app/,src/components/)
- Diretório
-
tsconfig.json→ verificar alias de caminho (@/*→./src/*ou./*) -
.env.local,.env.example→ verificar se já existem -
Disponibilidade de KV/Upstash (para captura automática de leads):
package.jsonpossui@upstash/redisOU@vercel/kv→ tem KV → CRIAR chat-lead.ts + conectar à rota- Existe arquivo
src/lib/kv.ts(oulib/kv.ts) exportandokv→ usar o helper existente (padrão do campo) - Não tem KV → PULAR criação de chat-lead.ts, informar usuário: "O projeto ainda não possui KV — a captura automática de leads não será ativada. Posso executar
/biz-setup-sepay-paymentpara instalar o KV primeiro e depois voltar para ativar a captura, ou podemos pular."
Guardar essas observações em uma pequena tabela para usar nas próximas etapas.
Passo 3 — Coletar a base de conhecimento do usuário
Fazer 4 perguntas ao usuário (agrupadas em uma única mensagem para evitar idas e vindas):
Para o chatbot responder com precisão, preciso de 4 coisas:
1. **FAQ** — lista de perguntas frequentes + respostas (preço, cronograma, reembolso, público-alvo, tempo de estudo, suporte pós-curso...).
Você pode colar o conteúdo diretamente aqui OU informar o caminho do arquivo (.md / .txt / .docx).
2. **Documentos do produto / curso** — descrição detalhada do curso: nome, conteúdo de cada módulo, resultados esperados, instrutor, bônus, tiers de preço se houver.
Também pode colar ou informar o caminho do arquivo.
3. **Nome da marca + tom** — Nome da marca/curso para o chatbot se apresentar (ex.: "assistente da AI Mastery"). Tom do bot: amigável (padrão) / formal / casual.
4. **Modelo** — padrão `google/gemini-3-flash-preview` (rápido, barato, bom o suficiente para suporte). Se preferir `anthropic/claude-sonnet-4.6` (maior qualidade, ~10x mais caro) para estágios iniciais com baixo volume, me avise.
Pode responder tudo de uma vez?
Quando o usuário responder:
- Se informar apenas o caminho do arquivo → ler o arquivo com a ferramenta Read.
- Se colar o conteúdo diretamente → usar o conteúdo colado.
- Se o usuário disser "crie um placeholder para mim" → gerar um FAQ placeholder genérico e marcar com
// TODO: preencher pelo usuáriopara que ele saiba que precisa atualizar. - Se não houver nome da marca → usar padrão "Assistente AI" e tratamento amigável.
Passo 4 — Gerar os arquivos no projeto
Ler os templates em templates/ desta skill e adaptá-los ao projeto. Os templates:
templates/chatbot-knowledge.ts— Módulo que exporta a base de conhecimento + systemPrompt. Injetar FAQ, informações do produto, nome da marca e tom. Já inclui bloco de FORMATAÇÃO DE RESPOSTA (regras de markdown) + bloco de COLETA ATIVA DE LEAD (ensina o LLM a solicitar nome/telefone/e-mail quando houver sinal de compra, agradecer e confirmar quando o usuário fornecer, NÃO mencionar "salvo no banco de dados").templates/Chatbot.tsx— Componente do widget, priorizando Tailwind. Já importareact-markdown+remark-gfm, renderiza a mensagem do assistente com<ReactMarkdown remarkPlugins={[remarkGfm]}>(apenas assistente — mensagens do usuário continuam comwhitespace-pre-wrap). Se o projeto NÃO tiver Tailwind → fallback paratemplates/Chatbot-noTailwind.tsx+templates/chatbot.module.css.templates/chat-route-app.ts— Rota da API para App Router (app/api/chat/route.ts). Já inclui o hookpersistLeadIfReadyexecutado de forma assíncrona após o fechamento do stream — não bloqueia a resposta.templates/chat-route-pages.ts— Rota da API para Pages Router (pages/api/chat.ts).templates/chat-lead.ts— CRIADO apenas se o projeto tiver KV/Upstash — extrai telefone VN, e-mail e nome (heurística: padrões de introdução "nome X" / "me chamo X" / "nome: X"),saveChatLeadcom deduplicação por telefone, TTL de 90 dias, namespace de chavechat-lead:{telefone}.templates/chatbot-markdown-styles.css— Trecho CSS para a classe.chatbot-md. DEVE ser anexado ao final deapp/globals.css(ousrc/app/globals.css/styles/globals.css). Alterar a cor de destaque (#fde68a/#f59e0b) de acordo com a paleta da marca do projeto antes de anexar.templates/env-instructions.md— Trecho de instruções para obter a chave OpenRouter, usado na etapa final.
Regras ao adaptar templates:
-
TS vs JS: se o projeto tiver apenas JS, alterar a extensão
.ts/.tsx→.js/.jsxe remover anotações de tipo (não apenas renomear o arquivo). Ler o arquivo de exemplo, fazer o parse, remover tipos e escrever. -
Alias de caminho: se o
tsconfigmapear@/*→./src/*, os imports no template devem usar@/lib/chatbot-knowledgee o arquivo deve ser colocado emsrc/lib/. Se não houver alias, usar caminho relativo. -
Modelo: substituir placeholder
__MODEL_ID__pelo modelo escolhido pelo usuário (google/gemini-3-flash-previewouanthropic/claude-sonnet-4.6). -
Marca: substituir
__BRAND_NAME__,__BRAND_TONE__. -
Conhecimento: construir
systemPrompta partir do FAQ + informações do produto de forma estruturada e clara (ver template). Manter o bloco de FORMATAÇÃO DE RESPOSTA no systemPrompt — é ele que ensina o LLM a gerar markdown adequado para um balão de chat (negrito em vez de título, marcadores curtos de uma linha). -
Instalar pacotes de renderização de markdown (OBRIGATÓRIO — se pular, o chatbot exibirá
**negrito**bruto em vez de texto em negrito no balão):# detectar arquivo de lock → escolher o gerenciador de pacotes correto npm install react-markdown remark-gfm # ou: pnpm add react-markdown remark-gfm # ou: yarn add react-markdown remark-gfm -
Anexar estilos markdown: ler
templates/chatbot-markdown-styles.css, trocar a cor de destaque pela paleta da marca do projeto (verificarglobals.cssem busca de--color-primaryou equivalente) e anexar ao final deapp/globals.css(ousrc/app/globals.css/styles/globals.css). -
Montar widget:
- App Router: editar
app/layout.tsx(ousrc/app/layout.tsx), adicionarimport Chatbot from '@/components/Chatbot'e<Chatbot />imediatamente antes de</body>. Ler o layout.tsx atual antes de editar para manter metadados, fontes, providers. - Pages Router: editar
pages/_app.tsx, encapsular o retorno:<><Component {...pageProps} /><Chatbot /></>. Ler_appantes, manter providers existentes.
- App Router: editar
-
Conexão da captura automática de leads (fazer apenas se o KV foi detectado no Passo 2):
- Copiar
templates/chat-lead.tsparalib/chat-lead.ts(ousrc/lib/chat-lead.ts). - Se o projeto AINDA NÃO tiver
lib/kv.ts→ criar:import { Redis } from "@upstash/redis"; export const kv = Redis.fromEnv(); - O handler da rota deve importar:
import { extractLeadFromMessages, saveChatLead } from "@/lib/chat-lead". - No loop do stream: rastrear
assistantText(acumular delta); quando o stream fechar → chamarpersistLeadIfReady(history, assistantText)(fire-and-forget, NÃO aguardar no caminho da resposta). - System prompt: garantir que o bloco de COLETA ATIVA DE LEAD já esteja em
chatbot-knowledge.ts(o template já o inclui). - Confirmar com o usuário: "Ativei a captura automática de leads — quando um visitante fornecer nome/telefone/e-mail no chat, o sistema salvará automaticamente no KV sob o namespace
chat-lead:{telefone}. Você pode visualizar os leads em/admin(se já instalou/biz-admin-leads-dashboard)."
- Copiar
Passo 5 — Configurar .env.local + .gitignore
-
Verificar se
.env.localjá existe:- Não: criar com:
# Chave da API OpenRouter — Obter em https://openrouter.ai/keys OPENROUTER_API_KEY= # Opcional: URL do site para OpenRouter rastrear o referenciador (ajuda com rate limit) NEXT_PUBLIC_SITE_URL=http://localhost:3000 - Sim: anexar as 2 variáveis acima se não existirem, sem sobrescrever variáveis existentes.
- Não: criar com:
-
Atualizar
.env.example(criar se não existir):OPENROUTER_API_KEY=sk-or-v1-xxxxx NEXT_PUBLIC_SITE_URL=https://seu-dominio.com -
Verificar
.gitignore—.env.localjá está incluído? Se não → anexar.env.locale.env*.local.
Passo 6 — Relatório para o usuário
Exibir 1 mensagem de resumo clara com 4 partes:
✅ Chatbot instalado em [nome do projeto]
📁 Arquivos criados:
- components/Chatbot.tsx (renderiza markdown via react-markdown + remark-gfm)
- app/api/chat/route.ts
- lib/chatbot-knowledge.ts
- app/globals.css (estilos markdown .chatbot-md anexados)
- .env.local (placeholder)
📦 Pacotes instalados: react-markdown, remark-gfm
🔑 3 passos que você precisa fazer para o chatbot funcionar:
1. Obter a chave da API OpenRouter:
- Acesse https://openrouter.ai → Cadastre-se (pode entrar com Google)
- Vá para https://openrouter.ai/keys → Criar Chave
- Adicione créditos (https://openrouter.ai/credits) — Gemini 3 Flash é barato, $5 é suficiente para milhares de conversas
- Copie a chave no formato `sk-or-v1-xxxxx`
2. Cole no arquivo `.env.local`:
OPENROUTER_API_KEY=sk-or-v1-xxxxx-cole-aqui
3. Teste:
[npm/pnpm/yarn] run dev
Abra http://localhost:3000 → clique no balão no canto inferior direito
🔄 Para alternar entre Gemini ↔ Sonnet:
Abra `app/api/chat/route.ts` e altere a variável `model:` no início do arquivo.
- `google/gemini-3-flash-preview` (padrão, $0.075/1M tokens de entrada, rápido)
- `anthropic/claude-sonnet-4.6` (avançado, ~$3/1M tokens de entrada, melhor qualidade)
📚 Para atualizar a base de conhecimento posteriormente:
Edite `lib/chatbot-knowledge.ts` — adicione/altere FAQ e productInfo, salve, recarregue.
Design responsivo mobile-first
O widget deve atender a 3 breakpoints:
| Breakpoint | Comportamento |
|---|---|
| ≤ 640px (mobile) | Clicar no balão → abre em tela cheia (z-index 9999), cabeçalho com botão X para fechar. Input fixado na parte inferior com safe-area-inset para não ser coberto pelo teclado. |
| 641–1023px (tablet) | Painel de 380px × 70vh, ancorado no canto inferior direito com margem de 16px. |
| ≥ 1024px (desktop) | Painel de 400px × 600px, ancorado no canto inferior direito com margem de 24px. Balão redondo de 60px. |