feat: add CRM templates
This commit is contained in:
parent
5db33107da
commit
1c026e3dcd
18 changed files with 1022 additions and 0 deletions
40
crm/attendance.gbai/attendance.gbdialog/create-ticket.bas
Normal file
40
crm/attendance.gbai/attendance.gbdialog/create-ticket.bas
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
PARAM title AS STRING LIKE "Equipamento com defeito" DESCRIPTION "Título do problema"
|
||||
PARAM category AS STRING LIKE "support" DESCRIPTION "Categoria: support, billing, sales, bug" OPTIONAL
|
||||
PARAM priority AS STRING LIKE "high" DESCRIPTION "Nível: low, normal, high, urgent" OPTIONAL
|
||||
PARAM contact_email AS EMAIL LIKE "usuario@dominio.com" DESCRIPTION "Email do reclamante" OPTIONAL
|
||||
PARAM description AS STRING LIKE "O mouse parou" DESCRIPTION "Detalhes da solicitação"
|
||||
|
||||
DESCRIPTION "Cria um Ticket de suporte de longo prazo no sistema, fora da fila de atendimento tempo-real."
|
||||
|
||||
IF NOT category THEN
|
||||
category = "support"
|
||||
END IF
|
||||
|
||||
IF NOT priority THEN
|
||||
priority = "normal"
|
||||
END IF
|
||||
|
||||
contact_id = ""
|
||||
IF contact_email THEN
|
||||
existing = GET "/api/crm/contacts?search=" + contact_email
|
||||
IF UBOUND(existing) > 0 THEN
|
||||
contact_id = FIRST(existing).id
|
||||
END IF
|
||||
END IF
|
||||
|
||||
new_ticket = POST "/api/tickets", #{
|
||||
title: title,
|
||||
description: description,
|
||||
category: category,
|
||||
priority: priority,
|
||||
status: "open",
|
||||
contact_id: contact_id
|
||||
}
|
||||
|
||||
TALK "🎫 **Ticket Criado com Sucesso!**"
|
||||
TALK "ID: " + new_ticket.id
|
||||
TALK "Título: " + title
|
||||
TALK "Prioridade: " + priority
|
||||
TALK "A equipe será notificada para escalonamento conforme SLA."
|
||||
|
||||
RETURN new_ticket.id
|
||||
63
crm/attendance.gbai/attendance.gbdialog/resolve-chat.bas
Normal file
63
crm/attendance.gbai/attendance.gbdialog/resolve-chat.bas
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão atendida" OPTIONAL
|
||||
PARAM status AS STRING LIKE "resolved" DESCRIPTION "Finalizar o chat ou aguardar (resolved, pending_customer)" OPTIONAL
|
||||
PARAM summary AS STRING LIKE "Dúvida resolvida com sucesso" DESCRIPTION "Breve resumo da solução" OPTIONAL
|
||||
|
||||
DESCRIPTION "Resolve a conversa, registrando o final no CRM (atividade) ou deixa pendente pelo cliente."
|
||||
|
||||
IF NOT status THEN
|
||||
status = "resolved"
|
||||
END IF
|
||||
|
||||
IF status = "resolved" THEN
|
||||
IF NOT summary THEN
|
||||
TALK "A sessão foi totalmente concluída? Qual seria o resumo?"
|
||||
HEAR summary AS STRING
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' Tratar ID da sessão conversacionalmente
|
||||
IF NOT session_id THEN
|
||||
my_sessions = GET "/api/attendance/queue?status=active"
|
||||
IF UBOUND(my_sessions) = 0 THEN
|
||||
TALK "Você não tem nenhuma sessão de atendimento ativa no momento."
|
||||
RETURN
|
||||
END IF
|
||||
IF UBOUND(my_sessions) = 1 THEN
|
||||
session_id = FIRST(my_sessions).session_id
|
||||
ELSE
|
||||
TALK "Você tem várias sessões ativas. Qual delas quer resolver? Diga o nome do cliente."
|
||||
FOR EACH s IN my_sessions
|
||||
TALK "- **" + s.user_name + "**"
|
||||
NEXT s
|
||||
HEAR query AS STRING
|
||||
FOR EACH s IN my_sessions
|
||||
IF INSTR(LCASE(s.user_name), LCASE(query)) > 0 THEN
|
||||
session_id = s.session_id
|
||||
END IF
|
||||
NEXT s
|
||||
IF NOT session_id THEN
|
||||
TALK "Sessão não identificada."
|
||||
RETURN
|
||||
END IF
|
||||
END IF
|
||||
END IF
|
||||
|
||||
resolution_payload = #{
|
||||
status: status,
|
||||
resolution_summary: summary,
|
||||
resolved_by: GET "session.user_id",
|
||||
resolved_at: FORMAT(NOW(), "YYYY-MM-DD HH:mm:ss")
|
||||
}
|
||||
|
||||
PUT "/api/attendance/sessions/" + session_id + "/resolve", resolution_payload
|
||||
|
||||
IF status = "resolved" THEN
|
||||
TALK "✅ **Atendimento Encerrado!**"
|
||||
TALK "A conversa foi marcada como **Resolvida**."
|
||||
TALK "Resumo: " + summary
|
||||
ELSE
|
||||
TALK "⏳ **Aguardando Cliente**"
|
||||
TALK "O atendimento ficará pausado aguardando retorno do cliente."
|
||||
END IF
|
||||
|
||||
RETURN session_id
|
||||
48
crm/attendance.gbai/attendance.gbdialog/start.bas
Normal file
48
crm/attendance.gbai/attendance.gbdialog/start.bas
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
ADD TOOL "view-queue"
|
||||
ADD TOOL "take-next"
|
||||
ADD TOOL "transfer-chat"
|
||||
ADD TOOL "resolve-chat"
|
||||
ADD TOOL "queue-stats"
|
||||
ADD TOOL "create-ticket"
|
||||
|
||||
SET CONTEXT "attendance" AS "You are a customer service assistant for General Bots. You help attendants manage the support queue: view waiting customers, take conversations, transfer between attendants, resolve cases, and create tickets. All actions affect real sessions in the database."
|
||||
|
||||
CLEAR SUGGESTIONS
|
||||
|
||||
ADD SUGGESTION "queue" AS "Ver fila de espera"
|
||||
ADD SUGGESTION "take" AS "Atender próximo"
|
||||
ADD SUGGESTION "transfer" AS "Transferir conversa"
|
||||
ADD SUGGESTION "resolve" AS "Resolver conversa"
|
||||
|
||||
BEGIN TALK
|
||||
**Atendimento — Gestão de Fila**
|
||||
|
||||
Posso ajudar com:
|
||||
• Ver a fila de clientes aguardando
|
||||
• Atender o próximo da fila
|
||||
• Transferir conversa para outro atendente
|
||||
• Resolver/encerrar conversa
|
||||
• Criar ticket de suporte
|
||||
• Ver estatísticas do atendimento
|
||||
|
||||
O que deseja?
|
||||
END TALK
|
||||
|
||||
BEGIN SYSTEM PROMPT
|
||||
You are a customer service queue manager.
|
||||
|
||||
Queue statuses:
|
||||
- new: Just arrived, not yet in queue
|
||||
- waiting: In queue, waiting for an attendant
|
||||
- active: Being handled by an attendant
|
||||
- pending_customer: Waiting for customer reply
|
||||
- resolved: Completed
|
||||
|
||||
Key rules:
|
||||
- Always show the customer's name and channel (WhatsApp, Web, Telegram, etc.)
|
||||
- Show how long the customer has been waiting
|
||||
- When transferring, always ask for the reason
|
||||
- When resolving, ask if the customer's issue was fully resolved
|
||||
- Prioritize customers who have been waiting the longest
|
||||
- If a customer is from a known CRM contact, show their company and deal info
|
||||
END SYSTEM PROMPT
|
||||
27
crm/attendance.gbai/attendance.gbdialog/take-next.bas
Normal file
27
crm/attendance.gbai/attendance.gbdialog/take-next.bas
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão (opcional). Se vazio, pega o próximo da fila." OPTIONAL
|
||||
|
||||
DESCRIPTION "Atender o próximo cliente da fila ou um cliente específico."
|
||||
|
||||
IF NOT session_id THEN
|
||||
' Tentar pegar o mais antigo da fila ("waiting", sem assignee)
|
||||
queue = GET "/api/attendance/queue?status=waiting"
|
||||
IF UBOUND(queue) = 0 THEN
|
||||
TALK "A fila está vazia no momento. Bom trabalho!"
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
' Pega o primeiro (mais antigo, se a API ordenar por tempo de espera)
|
||||
first_item = FIRST(queue)
|
||||
session_id = first_item.session_id
|
||||
END IF
|
||||
|
||||
' Endpoint hipotético para "tomar posse" da sessão
|
||||
assign_result = POST "/api/attendance/sessions/" + session_id + "/assign", #{
|
||||
attendant_id: GET "session.user_id"
|
||||
}
|
||||
|
||||
TALK "✅ **Sessão atribuída a você!**"
|
||||
TALK "Você agora está atendendo: " + assign_result.user_name + " via " + assign_result.channel
|
||||
TALK "Use as ferramentas de chat para conversar com o cliente."
|
||||
|
||||
RETURN session_id
|
||||
66
crm/attendance.gbai/attendance.gbdialog/transfer-chat.bas
Normal file
66
crm/attendance.gbai/attendance.gbdialog/transfer-chat.bas
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão" OPTIONAL
|
||||
PARAM skill AS STRING LIKE "suporte" DESCRIPTION "Habilidade ou fila destino (ex: financeiro, vendas)" OPTIONAL
|
||||
PARAM priority AS STRING LIKE "high" DESCRIPTION "Nova prioridade (urgent, high, normal, low)" OPTIONAL
|
||||
PARAM reason AS STRING LIKE "Dúvida sobre boleto" DESCRIPTION "Motivo da transferência (obrigatório)"
|
||||
|
||||
DESCRIPTION "Transfere o chat para outro nível de suporte ou fila usando Habilidades, ajustando prioridade."
|
||||
|
||||
IF NOT reason THEN
|
||||
TALK "Qual é o motivo da transferência para o próximo atendente?"
|
||||
HEAR reason AS STRING
|
||||
END IF
|
||||
|
||||
IF NOT priority THEN
|
||||
priority = "normal"
|
||||
END IF
|
||||
|
||||
' Tratar ID da sessão conversacionalmente
|
||||
IF NOT session_id THEN
|
||||
' Busca sessões ativas do atendente
|
||||
my_sessions = GET "/api/attendance/queue?status=active"
|
||||
IF UBOUND(my_sessions) = 0 THEN
|
||||
TALK "Você não tem nenhuma sessão de atendimento ativa no momento para transferir."
|
||||
RETURN
|
||||
END IF
|
||||
IF UBOUND(my_sessions) = 1 THEN
|
||||
session_id = FIRST(my_sessions).session_id
|
||||
ELSE
|
||||
TALK "Você tem " + UBOUND(my_sessions) + " atendimentos ativos. Vou mostrar os nomes, por favor diga qual deseja transferir:"
|
||||
FOR EACH s IN my_sessions
|
||||
TALK "- **" + s.user_name + "** via " + s.channel
|
||||
NEXT s
|
||||
HEAR query AS STRING
|
||||
' Busca simplificada
|
||||
FOR EACH s IN my_sessions
|
||||
IF INSTR(LCASE(s.user_name), LCASE(query)) > 0 THEN
|
||||
session_id = s.session_id
|
||||
END IF
|
||||
NEXT s
|
||||
IF NOT session_id THEN
|
||||
TALK "Não consegui identificar a sessão."
|
||||
RETURN
|
||||
END IF
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' TRANSFER TO HUMAN envia para a roleta novamente
|
||||
' No BASIC real, seria executado ou POSTado na API de transferência
|
||||
|
||||
transfer_payload = #{
|
||||
required_skill: skill,
|
||||
priority: priority,
|
||||
transfer_reason: reason,
|
||||
transferred_by: GET "session.user_id"
|
||||
}
|
||||
|
||||
POST "/api/attendance/sessions/" + session_id + "/transfer", transfer_payload
|
||||
|
||||
TALK "✅ **Sessão Transferida!**"
|
||||
TALK "Motivo: " + reason
|
||||
IF skill THEN
|
||||
TALK "Aguardando um especialista em **" + skill + "**"
|
||||
ELSE
|
||||
TALK "Aguardando o próximo atendente livre."
|
||||
END IF
|
||||
|
||||
RETURN session_id
|
||||
43
crm/attendance.gbai/attendance.gbdialog/view-queue.bas
Normal file
43
crm/attendance.gbai/attendance.gbdialog/view-queue.bas
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
PARAM status AS STRING LIKE "waiting" DESCRIPTION "Filtrar por status: waiting, active, all" OPTIONAL
|
||||
|
||||
DESCRIPTION "Ver a fila de atendimento: quem está aguardando, há quanto tempo, e por qual canal."
|
||||
|
||||
IF NOT status THEN
|
||||
status = "waiting"
|
||||
END IF
|
||||
|
||||
queue = GET "/api/attendance/queue?status=" + status
|
||||
|
||||
item_count = UBOUND(queue)
|
||||
|
||||
IF item_count = 0 THEN
|
||||
TALK "✅ Fila vazia! Nenhum cliente aguardando."
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
TALK "📋 **Fila de Atendimento — " + item_count + " cliente(s)**"
|
||||
TALK ""
|
||||
|
||||
FOR EACH item IN queue
|
||||
channel_icon = "💬"
|
||||
IF item.channel = "whatsapp" THEN
|
||||
channel_icon = "📱"
|
||||
ELSE IF item.channel = "telegram" THEN
|
||||
channel_icon = "✈️"
|
||||
ELSE IF item.channel = "email" THEN
|
||||
channel_icon = "📧"
|
||||
END IF
|
||||
|
||||
TALK "---"
|
||||
TALK channel_icon + " **" + item.user_name + "** via " + item.channel
|
||||
TALK "⏱️ Aguardando há " + item.wait_time
|
||||
TALK "💬 Última mensagem: " + item.last_message
|
||||
|
||||
IF item.assigned_to THEN
|
||||
TALK "👤 Atendente: " + item.assigned_to
|
||||
END IF
|
||||
|
||||
TALK "🔗 Session: " + item.session_id
|
||||
NEXT item
|
||||
|
||||
RETURN queue
|
||||
77
crm/crm.gbai/crm.gbdialog/close-deal.bas
Normal file
77
crm/crm.gbai/crm.gbdialog/close-deal.bas
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal a fechar" OPTIONAL
|
||||
PARAM won AS BOOLEAN LIKE TRUE DESCRIPTION "TRUE se ganhou, FALSE se perdeu"
|
||||
PARAM lost_reason AS STRING LIKE "Preço acima do mercado" DESCRIPTION "Motivo da perda (obrigatório se won=FALSE)" OPTIONAL
|
||||
|
||||
DESCRIPTION "Fechar um deal como ganho (won) ou perdido (lost). Se perdido, informe o motivo."
|
||||
|
||||
IF NOT deal_id OR deal_id = "uuid" THEN
|
||||
TALK "Qual deal você deseja fechar? (Diga o nome da empresa ou título)"
|
||||
HEAR query AS STRING
|
||||
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
|
||||
IF UBOUND(deals) = 0 THEN
|
||||
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
|
||||
RETURN
|
||||
END IF
|
||||
IF UBOUND(deals) = 1 THEN
|
||||
deal_id = FIRST(deals).id
|
||||
ELSE
|
||||
TALK "Encontrei várias opções. Qual delas quer fechar? Especifique melhor, por favor."
|
||||
FOR EACH d IN deals
|
||||
TALK "- **" + d.title + "** (" + d.stage + ")"
|
||||
NEXT d
|
||||
RETURN
|
||||
END IF
|
||||
END IF
|
||||
|
||||
deal = GET "/api/crm/deals/" + deal_id
|
||||
IF NOT deal THEN
|
||||
TALK "Deal não encontrado: " + deal_id
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
IF won THEN
|
||||
PUT "/api/crm/deals/" + deal_id, #{
|
||||
stage: "won",
|
||||
won: TRUE,
|
||||
probability: 100,
|
||||
actual_close_date: FORMAT(TODAY(), "YYYY-MM-DD")
|
||||
}
|
||||
|
||||
POST "/api/crm/activities", #{
|
||||
activity_type: "deal_won",
|
||||
subject: "Deal ganho: " + deal.title,
|
||||
contact_id: deal.contact_id,
|
||||
account_id: deal.account_id
|
||||
}
|
||||
|
||||
TALK "🎉 **Deal ganho!**"
|
||||
TALK "**" + deal.title + "** — R$ " + FORMAT(deal.value, "#,##0")
|
||||
TALK "Parabéns pela conquista!"
|
||||
ELSE
|
||||
IF NOT lost_reason THEN
|
||||
TALK "Qual foi o motivo da perda?"
|
||||
HEAR lost_reason AS STRING
|
||||
END IF
|
||||
|
||||
PUT "/api/crm/deals/" + deal_id, #{
|
||||
stage: "lost",
|
||||
won: FALSE,
|
||||
probability: 0,
|
||||
lost_reason: lost_reason,
|
||||
actual_close_date: FORMAT(TODAY(), "YYYY-MM-DD")
|
||||
}
|
||||
|
||||
POST "/api/crm/activities", #{
|
||||
activity_type: "deal_lost",
|
||||
subject: "Deal perdido: " + deal.title,
|
||||
description: "Motivo: " + lost_reason,
|
||||
contact_id: deal.contact_id,
|
||||
account_id: deal.account_id
|
||||
}
|
||||
|
||||
TALK "📋 **Deal perdido**"
|
||||
TALK "**" + deal.title + "** — Motivo: " + lost_reason
|
||||
TALK "Use essa experiência para os próximos negócios."
|
||||
END IF
|
||||
|
||||
RETURN deal_id
|
||||
106
crm/crm.gbai/crm.gbdialog/create-deal.bas
Normal file
106
crm/crm.gbai/crm.gbdialog/create-deal.bas
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
PARAM title AS STRING LIKE "Contrato Empresa ABC" DESCRIPTION "Título do deal ou oportunidade"
|
||||
PARAM contact_email AS EMAIL LIKE "joao@empresa.com" DESCRIPTION "Email do contato principal"
|
||||
PARAM contact_name AS STRING LIKE "João Silva" DESCRIPTION "Nome do contato" OPTIONAL
|
||||
PARAM company AS STRING LIKE "Empresa ABC Ltda" DESCRIPTION "Nome da empresa/conta" OPTIONAL
|
||||
PARAM value AS MONEY LIKE 50000 DESCRIPTION "Valor estimado do deal"
|
||||
PARAM stage AS STRING LIKE "new" DESCRIPTION "Estágio inicial: new, qualified, proposal, negotiation" OPTIONAL
|
||||
PARAM source AS STRING LIKE "WHATSAPP" DESCRIPTION "Origem: WHATSAPP, EMAIL, CALL, WEBSITE, REFERAL, PARTNER, CHAT" OPTIONAL
|
||||
PARAM close_date AS DATE LIKE "2026-06-30" DESCRIPTION "Data prevista de fechamento" OPTIONAL
|
||||
PARAM notes AS STRING LIKE "Conheceu na feira" DESCRIPTION "Observações sobre o deal" OPTIONAL
|
||||
|
||||
DESCRIPTION "Criar um novo deal no pipeline de vendas. Registra o negócio com valor, estágio, contato e empresa."
|
||||
|
||||
IF NOT stage THEN
|
||||
stage = "new"
|
||||
END IF
|
||||
|
||||
IF NOT source THEN
|
||||
source = "CHAT"
|
||||
END IF
|
||||
|
||||
IF NOT close_date THEN
|
||||
close_date = DATEADD(TODAY(), 30, "day")
|
||||
END IF
|
||||
|
||||
' Determine probability based on stage
|
||||
probability = 10
|
||||
IF stage = "qualified" THEN
|
||||
probability = 30
|
||||
ELSE IF stage = "proposal" THEN
|
||||
probability = 50
|
||||
ELSE IF stage = "negotiation" THEN
|
||||
probability = 70
|
||||
END IF
|
||||
|
||||
' Check if contact exists, create if not
|
||||
contact_id = ""
|
||||
IF contact_email THEN
|
||||
existing = GET "/api/crm/contacts?search=" + contact_email
|
||||
IF UBOUND(existing) > 0 THEN
|
||||
contact_id = FIRST(existing).id
|
||||
TALK "Contato encontrado: " + FIRST(existing).first_name + " " + FIRST(existing).last_name
|
||||
ELSE
|
||||
' Create contact
|
||||
IF NOT contact_name THEN
|
||||
contact_name = "Contato"
|
||||
END IF
|
||||
parts = SPLIT(contact_name, " ")
|
||||
first_name = FIRST(parts)
|
||||
last_name = LAST(parts)
|
||||
|
||||
new_contact = POST "/api/crm/contacts", #{
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
email: contact_email,
|
||||
company: company,
|
||||
source: source
|
||||
}
|
||||
contact_id = new_contact.id
|
||||
TALK "Novo contato criado: " + contact_name
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' Check if account exists, create if not
|
||||
account_id = ""
|
||||
IF company THEN
|
||||
existing_acc = GET "/api/crm/accounts?search=" + company
|
||||
IF UBOUND(existing_acc) > 0 THEN
|
||||
account_id = FIRST(existing_acc).id
|
||||
ELSE
|
||||
new_account = POST "/api/crm/accounts", #{
|
||||
name: company
|
||||
}
|
||||
account_id = new_account.id
|
||||
TALK "Nova conta criada: " + company
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' Create the deal
|
||||
deal = POST "/api/crm/deals", #{
|
||||
title: title,
|
||||
value: value,
|
||||
stage: stage,
|
||||
probability: probability,
|
||||
source: source,
|
||||
expected_close_date: close_date,
|
||||
contact_id: contact_id,
|
||||
account_id: account_id,
|
||||
notes: notes
|
||||
}
|
||||
|
||||
TALK "✅ **Deal criado com sucesso!**"
|
||||
TALK ""
|
||||
TALK "**" + title + "**"
|
||||
TALK "💰 Valor: R$ " + FORMAT(value, "#,##0")
|
||||
TALK "📊 Estágio: " + stage + " (" + probability + "% probabilidade)"
|
||||
TALK "📅 Previsão de fechamento: " + close_date
|
||||
|
||||
IF company THEN
|
||||
TALK "🏢 Empresa: " + company
|
||||
END IF
|
||||
|
||||
IF contact_email THEN
|
||||
TALK "👤 Contato: " + contact_email
|
||||
END IF
|
||||
|
||||
RETURN deal.id
|
||||
50
crm/crm.gbai/crm.gbdialog/find-deal.bas
Normal file
50
crm/crm.gbai/crm.gbdialog/find-deal.bas
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
PARAM query AS STRING LIKE "Acme" DESCRIPTION "Nome da empresa, pessoa ou título do deal"
|
||||
PARAM return_id_only AS BOOLEAN LIKE TRUE DESCRIPTION "Se TRUE retorna apenas o ID. Se FALSE, descreve as opções ao usuário." OPTIONAL
|
||||
|
||||
DESCRIPTION "Procura por um deal pelo nome da empresa, título ou pessoa. Usado por outros tools para não obrigar o humano a saber UUIDs."
|
||||
|
||||
IF NOT return_id_only THEN return_id_only = TRUE
|
||||
|
||||
' Search API (assuming ?search= looks at title, contact email/name, and account name)
|
||||
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
|
||||
count = UBOUND(deals)
|
||||
|
||||
IF count = 0 THEN
|
||||
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
|
||||
RETURN ""
|
||||
END IF
|
||||
|
||||
IF count = 1 THEN
|
||||
found_deal = FIRST(deals)
|
||||
IF NOT return_id_only THEN
|
||||
TALK "Encontrei: **" + found_deal.title + "** (R$ " + FORMAT(found_deal.value, "#,##0") + ", " + found_deal.stage + ")"
|
||||
END IF
|
||||
RETURN found_deal.id
|
||||
END IF
|
||||
|
||||
' If multiple matches found, ask user to disambiguate
|
||||
TALK "Encontrei " + count + " opções para '" + query + "'. Qual delas?"
|
||||
idx = 1
|
||||
FOR EACH d IN deals
|
||||
TALK idx + ". **" + d.title + "** (" + d.stage + ") - R$ " + FORMAT(d.value, "#,##0")
|
||||
idx = idx + 1
|
||||
NEXT d
|
||||
|
||||
HEAR choice
|
||||
|
||||
' Simple index selection logic (assuming user types "1", "2")
|
||||
choice_num = TO_NUMBER(choice)
|
||||
IF choice_num > 0 AND choice_num <= count THEN
|
||||
selected = deals[choice_num - 1]
|
||||
RETURN selected.id
|
||||
ELSE
|
||||
' Fallback to string matching on title
|
||||
FOR EACH d IN deals
|
||||
IF INSTR(LCASE(d.title), LCASE(choice)) > 0 THEN
|
||||
RETURN d.id
|
||||
END IF
|
||||
NEXT d
|
||||
END IF
|
||||
|
||||
TALK "Desculpe, não consegui identificar qual você escolheu."
|
||||
RETURN ""
|
||||
60
crm/crm.gbai/crm.gbdialog/list-deals.bas
Normal file
60
crm/crm.gbai/crm.gbdialog/list-deals.bas
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
PARAM stage AS STRING LIKE "proposal" DESCRIPTION "Filtrar por estágio: new, qualified, proposal, negotiation, won, lost" OPTIONAL
|
||||
PARAM owner AS STRING LIKE "joao@empresa.com" DESCRIPTION "Filtrar por dono do deal" OPTIONAL
|
||||
|
||||
DESCRIPTION "Listar deals do pipeline de vendas. Pode filtrar por estágio e por dono."
|
||||
|
||||
url = "/api/crm/deals?"
|
||||
|
||||
IF stage THEN
|
||||
url = url + "stage=" + stage + "&"
|
||||
END IF
|
||||
|
||||
IF owner THEN
|
||||
url = url + "search=" + owner + "&"
|
||||
END IF
|
||||
|
||||
url = url + "limit=20"
|
||||
|
||||
deals = GET url
|
||||
|
||||
deal_count = UBOUND(deals)
|
||||
|
||||
IF deal_count = 0 THEN
|
||||
TALK "Nenhum deal encontrado com os filtros informados."
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
TALK "📊 **Pipeline — " + deal_count + " deal(s) encontrado(s)**"
|
||||
TALK ""
|
||||
|
||||
total_value = 0
|
||||
total_weighted = 0
|
||||
|
||||
FOR EACH deal IN deals
|
||||
prob = deal.probability
|
||||
weighted = deal.value * prob / 100
|
||||
total_value = total_value + deal.value
|
||||
total_weighted = total_weighted + weighted
|
||||
|
||||
TALK "---"
|
||||
TALK "**" + deal.title + "**"
|
||||
TALK "💰 R$ " + FORMAT(deal.value, "#,##0") + " | " + deal.stage + " (" + prob + "%)"
|
||||
|
||||
IF deal.expected_close_date THEN
|
||||
TALK "📅 Previsão: " + deal.expected_close_date
|
||||
END IF
|
||||
|
||||
IF deal.contact_id THEN
|
||||
contact = GET "/api/crm/contacts/" + deal.contact_id
|
||||
IF contact THEN
|
||||
TALK "👤 " + contact.first_name + " " + contact.last_name
|
||||
END IF
|
||||
END IF
|
||||
NEXT deal
|
||||
|
||||
TALK ""
|
||||
TALK "**Totais:**"
|
||||
TALK "💰 Valor total: R$ " + FORMAT(total_value, "#,##0")
|
||||
TALK "📊 Valor ponderado: R$ " + FORMAT(total_weighted, "#,##0")
|
||||
|
||||
RETURN deals
|
||||
54
crm/crm.gbai/crm.gbdialog/log-activity.bas
Normal file
54
crm/crm.gbai/crm.gbdialog/log-activity.bas
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
PARAM activity_type AS STRING LIKE "call" DESCRIPTION "Tipo: call, email, meeting, note, follow_up"
|
||||
PARAM subject AS STRING LIKE "Ligação de follow-up" DESCRIPTION "Assunto da atividade"
|
||||
PARAM contact_email AS EMAIL LIKE "joao@empresa.com" DESCRIPTION "Email do contato relacionado" OPTIONAL
|
||||
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal relacionado" OPTIONAL
|
||||
PARAM description AS STRING LIKE "Discutimos termos do contrato" DESCRIPTION "Detalhes da atividade" OPTIONAL
|
||||
PARAM due_date AS DATE LIKE "2026-04-01" DESCRIPTION "Data de follow-up" OPTIONAL
|
||||
|
||||
DESCRIPTION "Registrar uma atividade de CRM: ligação, email, reunião, nota ou follow-up. Pode vincular a contato e/ou deal."
|
||||
|
||||
' Resolve contact_id from email
|
||||
contact_id = ""
|
||||
IF contact_email THEN
|
||||
contacts = GET "/api/crm/contacts?search=" + contact_email
|
||||
IF UBOUND(contacts) > 0 THEN
|
||||
contact_id = FIRST(contacts).id
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' Resolve deal_id if empty or uuid but we need it
|
||||
IF NOT deal_id OR deal_id = "uuid" THEN
|
||||
TALK "A qual deal esta atividade se refere? (Opcional: Diga 'nenhum' ou o nome da empresa)"
|
||||
HEAR query AS STRING
|
||||
IF LCASE(query) != "nenhum" AND LCASE(query) != "none" THEN
|
||||
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
|
||||
IF UBOUND(deals) > 0 THEN
|
||||
deal_id = FIRST(deals).id
|
||||
TALK "Atividade será vinculada ao deal: " + FIRST(deals).title
|
||||
END IF
|
||||
ELSE
|
||||
deal_id = ""
|
||||
END IF
|
||||
END IF
|
||||
|
||||
' Create activity
|
||||
activity = POST "/api/crm/activities", #{
|
||||
activity_type: activity_type,
|
||||
subject: subject,
|
||||
description: description,
|
||||
contact_id: contact_id,
|
||||
due_date: due_date
|
||||
}
|
||||
|
||||
TALK "✅ **Atividade registrada!**"
|
||||
TALK "📋 " + activity_type + ": " + subject
|
||||
|
||||
IF contact_email THEN
|
||||
TALK "👤 Contato: " + contact_email
|
||||
END IF
|
||||
|
||||
IF due_date THEN
|
||||
TALK "📅 Follow-up: " + due_date
|
||||
END IF
|
||||
|
||||
RETURN activity.id
|
||||
21
crm/crm.gbai/crm.gbdialog/pipeline-summary.bas
Normal file
21
crm/crm.gbai/crm.gbdialog/pipeline-summary.bas
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
DESCRIPTION "Exibe resumo do pipeline de vendas: total por estágio, valor, taxa de conversão."
|
||||
|
||||
stats = GET "/api/crm/stats"
|
||||
stages = GET "/api/crm/pipeline"
|
||||
|
||||
TALK "📊 **Resumo do Pipeline de Vendas**"
|
||||
TALK ""
|
||||
TALK "💰 Valor total no pipeline: R$ " + FORMAT(stats.total_value, "#,##0")
|
||||
TALK "🏆 Valor ganho: R$ " + FORMAT(stats.won_value, "#,##0")
|
||||
TALK "📈 Taxa de conversão: " + FORMAT(stats.conversion_rate, "#0.0") + "%"
|
||||
TALK "📐 Ticket médio: R$ " + FORMAT(stats.avg_deal_size, "#,##0")
|
||||
TALK ""
|
||||
|
||||
IF stats.stages THEN
|
||||
TALK "**Por estágio:**"
|
||||
FOR EACH sg IN stats.stages
|
||||
TALK " " + sg.name + ": " + sg.count + " deals — R$ " + FORMAT(sg.total_value, "#,##0")
|
||||
NEXT sg
|
||||
END IF
|
||||
|
||||
RETURN stats
|
||||
52
crm/crm.gbai/crm.gbdialog/start.bas
Normal file
52
crm/crm.gbai/crm.gbdialog/start.bas
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
ADD TOOL "create-deal"
|
||||
ADD TOOL "update-deal"
|
||||
ADD TOOL "list-deals"
|
||||
ADD TOOL "close-deal"
|
||||
ADD TOOL "add-contact"
|
||||
ADD TOOL "search-contact"
|
||||
ADD TOOL "add-account"
|
||||
ADD TOOL "log-activity"
|
||||
ADD TOOL "pipeline-summary"
|
||||
|
||||
SET CONTEXT "crm" AS "You are a CRM sales assistant for General Bots. You help salespeople create and manage deals, contacts, and accounts. All data is stored in PostgreSQL via the API. Deals follow a unified pipeline: new → qualified → proposal → negotiation → won/lost. There are no separate 'leads' or 'opportunities' — everything is a Deal with a stage. Business units are Departments from people_departments."
|
||||
|
||||
CLEAR SUGGESTIONS
|
||||
|
||||
ADD SUGGESTION "newdeal" AS "Criar um novo deal"
|
||||
ADD SUGGESTION "pipeline" AS "Ver meu pipeline"
|
||||
ADD SUGGESTION "contacts" AS "Buscar contato"
|
||||
ADD SUGGESTION "report" AS "Relatório de vendas"
|
||||
|
||||
BEGIN TALK
|
||||
**CRM — Gestão de Vendas**
|
||||
|
||||
Posso ajudar com:
|
||||
• Criar e gerenciar deals (negócios)
|
||||
• Buscar e cadastrar contatos
|
||||
• Cadastrar contas (empresas)
|
||||
• Atualizar estágios do pipeline
|
||||
• Relatórios e previsões de vendas
|
||||
• Registrar atividades (ligações, emails, reuniões)
|
||||
|
||||
O que deseja fazer?
|
||||
END TALK
|
||||
|
||||
BEGIN SYSTEM PROMPT
|
||||
You are a CRM sales assistant. All entities are managed via the General Bots REST API.
|
||||
|
||||
Pipeline stages (in order):
|
||||
- new: Initial contact, just entered the funnel
|
||||
- qualified: Budget, authority, need, timeline confirmed (BANT)
|
||||
- proposal: Quote or proposal sent to the customer
|
||||
- negotiation: Active discussions on terms
|
||||
- won: Deal successfully closed
|
||||
- lost: Deal lost (always ask for lost_reason)
|
||||
|
||||
Key rules:
|
||||
- Always confirm information BEFORE saving
|
||||
- Use Brazilian Real (BRL) as default currency unless the user specifies otherwise
|
||||
- When creating a deal, always try to link to an existing contact or create one
|
||||
- When closing a deal as lost, always ask for the reason
|
||||
- Encourage the salesperson and suggest next actions based on the new stage
|
||||
END SYSTEM PROMPT
|
||||
ADD TOOL "find-deal"
|
||||
118
crm/crm.gbai/crm.gbdialog/update-deal.bas
Normal file
118
crm/crm.gbai/crm.gbdialog/update-deal.bas
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal a atualizar" OPTIONAL
|
||||
PARAM stage AS STRING LIKE "qualified" DESCRIPTION "Novo estágio: new, qualified, proposal, negotiation, won, lost" OPTIONAL
|
||||
PARAM value AS MONEY LIKE 75000 DESCRIPTION "Novo valor do deal" OPTIONAL
|
||||
PARAM lost_reason AS STRING LIKE "Preço" DESCRIPTION "Motivo da perda (obrigatório se stage=lost)" OPTIONAL
|
||||
PARAM notes AS STRING LIKE "Reunião positiva" DESCRIPTION "Observações adicionais" OPTIONAL
|
||||
|
||||
DESCRIPTION "Atualizar um deal existente: mudar estágio, valor, adicionar notas. Se mudar para 'won' ou 'lost', o deal é fechado."
|
||||
|
||||
' Validate deal exists
|
||||
IF NOT deal_id OR deal_id = "uuid" THEN
|
||||
TALK "Qual deal você deseja atualizar? (Pode dizer o nome da empresa ou o título)"
|
||||
HEAR query AS STRING
|
||||
' Usar a ferramenta recém-criada (ou lógica similar) para buscar
|
||||
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
|
||||
IF UBOUND(deals) = 0 THEN
|
||||
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
|
||||
RETURN
|
||||
END IF
|
||||
IF UBOUND(deals) = 1 THEN
|
||||
deal_id = FIRST(deals).id
|
||||
ELSE
|
||||
TALK "Encontrei várias opções. Seguem as 3 primeiras:"
|
||||
count = 1
|
||||
FOR EACH d IN deals
|
||||
IF count <= 3 THEN
|
||||
TALK count + ". **" + d.title + "** (R$ " + FORMAT(d.value, "#,##0") + ", " + d.stage + ")"
|
||||
END IF
|
||||
count = count + 1
|
||||
NEXT d
|
||||
TALK "Por favor, especifique melhor informando o título exato ou o e-mail do contato."
|
||||
RETURN
|
||||
END IF
|
||||
END IF
|
||||
|
||||
deal = GET "/api/crm/deals/" + deal_id
|
||||
IF NOT deal THEN
|
||||
TALK "Deal não encontrado com ID: " + deal_id
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
TALK "Deal atual: **" + deal.title + "** — " + deal.stage + " — R$ " + FORMAT(deal.value, "#,##0")
|
||||
|
||||
' Build update payload
|
||||
update = #{}
|
||||
|
||||
IF stage THEN
|
||||
' Validate stage
|
||||
valid_stages = "new,qualified,proposal,negotiation,won,lost"
|
||||
IF INSTR(valid_stages, stage) = 0 THEN
|
||||
TALK "Estágio inválido. Use: new, qualified, proposal, negotiation, won, lost"
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
update.stage = stage
|
||||
|
||||
' Set probability
|
||||
IF stage = "new" THEN
|
||||
update.probability = 10
|
||||
ELSE IF stage = "qualified" THEN
|
||||
update.probability = 30
|
||||
ELSE IF stage = "proposal" THEN
|
||||
update.probability = 50
|
||||
ELSE IF stage = "negotiation" THEN
|
||||
update.probability = 70
|
||||
ELSE IF stage = "won" THEN
|
||||
update.probability = 100
|
||||
update.won = TRUE
|
||||
update.actual_close_date = FORMAT(TODAY(), "YYYY-MM-DD")
|
||||
ELSE IF stage = "lost" THEN
|
||||
update.probability = 0
|
||||
update.won = FALSE
|
||||
update.actual_close_date = FORMAT(TODAY(), "YYYY-MM-DD")
|
||||
IF NOT lost_reason THEN
|
||||
TALK "Por que o deal foi perdido?"
|
||||
HEAR lost_reason AS STRING
|
||||
END IF
|
||||
update.lost_reason = lost_reason
|
||||
END IF
|
||||
END IF
|
||||
|
||||
IF value THEN
|
||||
update.value = value
|
||||
END IF
|
||||
|
||||
IF notes THEN
|
||||
update.notes = notes
|
||||
END IF
|
||||
|
||||
' Execute update
|
||||
PUT "/api/crm/deals/" + deal_id, update
|
||||
|
||||
' Log activity
|
||||
POST "/api/crm/activities", #{
|
||||
activity_type: "stage_change",
|
||||
subject: "Deal atualizado para " + stage,
|
||||
description: notes,
|
||||
contact_id: deal.contact_id
|
||||
}
|
||||
|
||||
' Response by stage
|
||||
IF stage = "won" THEN
|
||||
TALK "🎉 **Parabéns! Deal ganho!**"
|
||||
TALK "**" + deal.title + "** fechado com sucesso!"
|
||||
TALK "💰 Valor: R$ " + FORMAT(COALESCE(value, deal.value), "#,##0")
|
||||
ELSE IF stage = "lost" THEN
|
||||
TALK "📋 **Deal perdido**"
|
||||
TALK "**" + deal.title + "** marcado como perdido."
|
||||
TALK "📝 Motivo: " + lost_reason
|
||||
TALK "Analise o que aconteceu para melhorar nas próximas!"
|
||||
ELSE IF stage THEN
|
||||
TALK "✅ **Deal atualizado!**"
|
||||
TALK "**" + deal.title + "** → **" + stage + "**"
|
||||
TALK "📊 Probabilidade: " + update.probability + "%"
|
||||
ELSE
|
||||
TALK "✅ Deal atualizado com sucesso."
|
||||
END IF
|
||||
|
||||
RETURN deal_id
|
||||
52
crm/marketing.gbai/marketing.gbdialog/create-campaign.bas
Normal file
52
crm/marketing.gbai/marketing.gbdialog/create-campaign.bas
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
PARAM name AS STRING LIKE "Promoção Dia das Mães" DESCRIPTION "Nome descritivo da campanha"
|
||||
PARAM channel AS STRING LIKE "email" DESCRIPTION "Canal de envio: whatsapp, email, sms, telegram"
|
||||
PARAM scheduled_date AS DATE LIKE "2026-05-01 09:00:00" DESCRIPTION "Data/Hora de agendamento do envio (opcional)" OPTIONAL
|
||||
PARAM list_id AS STRING LIKE "uuid_da_lista" DESCRIPTION "ID da Lista de Contatos alvo" OPTIONAL
|
||||
PARAM template_id AS STRING LIKE "uuid_do_template" DESCRIPTION "ID do Template de Conteúdo" OPTIONAL
|
||||
PARAM ai_generate_template AS STRING LIKE "Crie um email rápido de 3 parágrafos sobre sapatos com desconto de 15%" DESCRIPTION "Prompt para IA caso queira gerar um template agora" OPTIONAL
|
||||
|
||||
DESCRIPTION "Cria uma Campanha de Marketing e agenda seu envio. Pode integrar/vincular a listas e templates existentes."
|
||||
|
||||
IF NOT list_id THEN
|
||||
TALK "Qual lista de contatos você deseja usar para esta campanha?"
|
||||
' Aqui seria uma busca na db ou listagem interativa
|
||||
HEAR list_id AS STRING
|
||||
END IF
|
||||
|
||||
// Create template if an AI prompt was given but no template_id
|
||||
IF ai_generate_template AND NOT template_id THEN
|
||||
TALK "🤖 Gerando e salvando um template de " + channel + " baseado no seu pedido..."
|
||||
new_template = POST "/api/marketing/templates", #{
|
||||
name: name + " Template",
|
||||
channel: channel,
|
||||
ai_prompt: ai_generate_template
|
||||
}
|
||||
template_id = new_template.id
|
||||
TALK "Template ID retornado: " + template_id
|
||||
ELSE IF NOT template_id THEN
|
||||
TALK "Tem o ID do template guardado? Diga-me por favor."
|
||||
HEAR template_id AS STRING
|
||||
END IF
|
||||
|
||||
new_campaign = POST "/api/marketing/campaigns", #{
|
||||
name: name,
|
||||
channel: channel,
|
||||
status: "draft",
|
||||
scheduled_at: scheduled_date,
|
||||
template_id: template_id,
|
||||
list_id: list_id
|
||||
}
|
||||
|
||||
TALK "📣 **Campanha Criada!**"
|
||||
TALK "Nome: " + name
|
||||
TALK "Canal: " + UCASE(channel)
|
||||
TALK "Status: Draft"
|
||||
TALK "ID: " + new_campaign.id
|
||||
|
||||
IF scheduled_date THEN
|
||||
TALK "Agendada para: " + scheduled_date
|
||||
ELSE
|
||||
TALK "Pendente de envio. Use 'send-campaign' para dispará-la agora."
|
||||
END IF
|
||||
|
||||
RETURN new_campaign.id
|
||||
44
crm/marketing.gbai/marketing.gbdialog/list-campaigns.bas
Normal file
44
crm/marketing.gbai/marketing.gbdialog/list-campaigns.bas
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
PARAM status AS STRING LIKE "draft" DESCRIPTION "Filtro de status (draft, scheduled, sending, sent, completed)" OPTIONAL
|
||||
PARAM limit AS INTEGER LIKE 10 DESCRIPTION "Número máximo de campanhas a exibir" OPTIONAL
|
||||
|
||||
DESCRIPTION "Lista as campanhas de marketing."
|
||||
|
||||
IF NOT limit THEN
|
||||
limit = 10
|
||||
END IF
|
||||
|
||||
url = "/api/marketing/campaigns?limit=" + limit
|
||||
|
||||
IF status THEN
|
||||
url = url + "&status=" + status
|
||||
END IF
|
||||
|
||||
campaigns = GET url
|
||||
count = UBOUND(campaigns)
|
||||
|
||||
IF count = 0 THEN
|
||||
TALK "Nenhuma campanha encontrada."
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
TALK "📊 **Campanhas — " + count + " resultado(s)**"
|
||||
|
||||
FOR EACH c IN campaigns
|
||||
TALK "---"
|
||||
TALK "**" + c.name + "** (" + c.status + ")"
|
||||
TALK "📣 Canal: " + UCASE(c.channel)
|
||||
TALK "🔑 ID: " + c.id
|
||||
|
||||
IF c.scheduled_at THEN
|
||||
TALK "🕒 Agendada: " + c.scheduled_at
|
||||
END IF
|
||||
|
||||
IF c.metrics THEN
|
||||
TALK "📈 Enviados: " + c.metrics.sent + " | Erros: " + c.metrics.failed
|
||||
IF c.channel = "email" THEN
|
||||
TALK " Aberturas: " + c.metrics.opened + " | Clicks: " + c.metrics.clicked
|
||||
END IF
|
||||
END IF
|
||||
NEXT c
|
||||
|
||||
RETURN campaigns
|
||||
59
crm/marketing.gbai/marketing.gbdialog/send-campaign.bas
Normal file
59
crm/marketing.gbai/marketing.gbdialog/send-campaign.bas
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
PARAM campaign_id AS STRING LIKE "uuid" DESCRIPTION "ID da Campanha" OPTIONAL
|
||||
PARAM allow_over_budget AS BOOLEAN LIKE FALSE DESCRIPTION "Permitir envio mesmo se ultrapassar o orçamento do canal?" OPTIONAL
|
||||
|
||||
DESCRIPTION "Confirma e inicia o disparo (envio) imediato de uma campanha."
|
||||
|
||||
IF NOT campaign_id OR campaign_id = "uuid" THEN
|
||||
TALK "Qual campanha você deseja enviar? (Diga o nome)"
|
||||
HEAR query AS STRING
|
||||
camps = GET "/api/marketing/campaigns?search=" + query + "&limit=5"
|
||||
IF UBOUND(camps) = 0 THEN
|
||||
TALK "Não encontrei nenhuma campanha com o termo '" + query + "'."
|
||||
RETURN
|
||||
END IF
|
||||
IF UBOUND(camps) = 1 THEN
|
||||
campaign_id = FIRST(camps).id
|
||||
ELSE
|
||||
TALK "Encontrei várias campanhas. Qual delas?"
|
||||
FOR EACH c IN camps
|
||||
TALK "- **" + c.name + "** (" + c.status + ")"
|
||||
NEXT c
|
||||
RETURN
|
||||
END IF
|
||||
END IF
|
||||
|
||||
camp = GET "/api/marketing/campaigns/" + campaign_id
|
||||
IF NOT camp THEN
|
||||
TALK "Campanha não encontrada: " + campaign_id
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
IF camp.status = "sent" OR camp.status = "completed" THEN
|
||||
TALK "A campanha '" + camp.name + "' já foi enviada."
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
IF NOT camp.list_id THEN
|
||||
TALK "Esta campanha não tem uma lista de contatos vinculada. Não é possível enviar."
|
||||
RETURN
|
||||
END IF
|
||||
|
||||
list_info = GET "/api/marketing/lists/" + camp.list_id
|
||||
TALK "🔍 **Análise Pré-Envio:**"
|
||||
TALK "• Campanha: " + camp.name
|
||||
TALK "• Canal: " + UCASE(camp.channel)
|
||||
TALK "• Segmentação/Lista: " + list_info.name + " (" + list_info.contact_count + " contatos)"
|
||||
|
||||
TALK "Deseja realmente iniciar o envio AGORA para " + list_info.contact_count + " pessoas?"
|
||||
HEAR confirm AS BOOLEAN
|
||||
|
||||
IF confirm THEN
|
||||
POST "/api/marketing/campaigns/" + campaign_id + "/send"
|
||||
TALK "🚀 **Envio Iniciado!**"
|
||||
TALK "As automações do " + UCASE(camp.channel) + " foram engatilhadas."
|
||||
TALK "Você pode acompanhar as métricas em 'list-campaigns' depois de alguns minutos."
|
||||
ELSE
|
||||
TALK "Envio cancelado. A campanha continua no status '" + camp.status + "'."
|
||||
END IF
|
||||
|
||||
RETURN camp_id
|
||||
42
crm/marketing.gbai/marketing.gbdialog/start.bas
Normal file
42
crm/marketing.gbai/marketing.gbdialog/start.bas
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
ADD TOOL "create-campaign"
|
||||
ADD TOOL "list-campaigns"
|
||||
ADD TOOL "send-campaign"
|
||||
ADD TOOL "create-template"
|
||||
ADD TOOL "list-templates"
|
||||
ADD TOOL "create-dynamic-list"
|
||||
|
||||
SET CONTEXT "marketing" AS "You are a marketing automation assistant for General Bots. You help marketers create campaigns, design templates (email/WhatsApp), build contact lists (static or dynamic), and schedule or send messages. All features interact with the CRM contacts via the General Bots marketing REST API."
|
||||
|
||||
CLEAR SUGGESTIONS
|
||||
|
||||
ADD SUGGESTION "newcamp" AS "Criar nova campanha"
|
||||
ADD SUGGESTION "viewcamps" AS "Ver minhas campanhas"
|
||||
ADD SUGGESTION "lists" AS "Criar lista de contatos"
|
||||
ADD SUGGESTION "send" AS "Enviar uma campanha"
|
||||
|
||||
BEGIN TALK
|
||||
**Marketing — Campanhas e Envio**
|
||||
|
||||
Posso ajudar com:
|
||||
• Criar Campanhas (WhatsApp, Email, SMS)
|
||||
• Gerenciar Templates (com IA ou predefinidos)
|
||||
• Construir Listas Dinâmicas (ex: VIPs, Clientes do Bairro X)
|
||||
• Enviar campanhas em massa (Broadcast)
|
||||
• Ver métricas e estatísticas de aberturas
|
||||
|
||||
O que quer divulgar hoje?
|
||||
END TALK
|
||||
|
||||
BEGIN SYSTEM PROMPT
|
||||
You are a Marketing Automation assistant.
|
||||
|
||||
Key workflows:
|
||||
1. Contact List -> Select *who* receives it.
|
||||
2. Template -> Define *what* is sent. If it's WhatsApp, it usually needs a "meta_template_id" or approval.
|
||||
3. Campaign -> Groups List + Template + Schedule + Channel. We can "send" or "schedule" it.
|
||||
|
||||
Key rules:
|
||||
- Provide marketing advice: suggest A/B testing or better copy when writing templates.
|
||||
- Ensure the user confirms the number of recipients before sending a campaign.
|
||||
- AI prompt in templates allows personalizing messages per recipient (e.g. "Escreva de forma amigável e ofereça 10%").
|
||||
END SYSTEM PROMPT
|
||||
Loading…
Add table
Reference in a new issue