This commit is contained in:
Junior
2026-04-02 06:17:38 -03:00
parent 5a702b419e
commit 1ae68ccfe7
2 changed files with 296 additions and 0 deletions

296
main.go
View File

@@ -845,6 +845,206 @@ func formatChargeabilityForLLM(result []ProfissionalChargeability, args Chargeab
return b.String()
}
// ── Tool: pesquisar_usuarios / get_usuario ──
type UsuarioResumo struct {
Nome string `json:"nome"`
Email string `json:"email"`
Cargo string `json:"cargo"`
Ativo string `json:"ativo"`
Disponivel string `json:"disponivel"`
}
func pesquisarUsuarios(busca string) ([]UsuarioResumo, error) {
token, cookie, err := qualitorLogin()
if err != nil {
return nil, err
}
safe := safeSQLString(busca)
like := "%" + safe + "%"
sql := `SELECT u.nmusuario, u.dsemail, u.idativo, u.iddisponivel, c.nmcargo
FROM QUALITOR.dbo.ad_usuario u
LEFT JOIN QUALITOR.dbo.ad_cargo c ON c.cdcargo = u.cdcargo
WHERE (u.nmusuario LIKE '` + like + `' OR u.dsemail LIKE '` + like + `' OR u.nmusuariorede LIKE '` + like + `')
AND u.idativo = 'Y'
ORDER BY u.nmusuario`
xmlResult, err := qualitorQuery(token, cookie, sql)
if err != nil {
return nil, err
}
decoded := extractResult(xmlResult)
items := extractDataItems(decoded)
var usuarios []UsuarioResumo
for _, block := range items {
f := extractAllFields(block)
usuarios = append(usuarios, UsuarioResumo{
Nome: f["nmusuario"],
Email: f["dsemail"],
Cargo: f["nmcargo"],
Ativo: f["idativo"],
Disponivel: f["iddisponivel"],
})
}
return usuarios, nil
}
type UsuarioDetalhado struct {
Nome string `json:"nome"`
Email string `json:"email"`
Login string `json:"login"`
Cargo string `json:"cargo"`
Superior string `json:"superior"`
Ativo string `json:"ativo"`
Disponivel string `json:"disponivel"`
Bloqueado string `json:"bloqueado"`
Equipes []string `json:"equipes"`
Total30d string `json:"total_chamados_30d"`
Terminados string `json:"terminados_30d"`
Abertos string `json:"abertos_30d"`
}
func getUsuario(nome string) (*UsuarioDetalhado, error) {
token, cookie, err := qualitorLogin()
if err != nil {
return nil, err
}
safe := safeSQLString(nome)
// Dados do usuario
sqlUser := `SELECT u.nmusuario, u.dsemail, u.nmusuariorede, u.idativo, u.iddisponivel, u.idbloqueado,
c.nmcargo, s.nmusuario AS superior
FROM QUALITOR.dbo.ad_usuario u
LEFT JOIN QUALITOR.dbo.ad_cargo c ON c.cdcargo = u.cdcargo
LEFT JOIN QUALITOR.dbo.ad_usuario s ON s.cdusuario = u.cdusuariosuperior
WHERE u.nmusuario = '` + safe + `'`
// Equipes
sqlEquipes := `SELECT e.nmequipe
FROM QUALITOR.dbo.hd_equipe e
JOIN QUALITOR.dbo.hd_equipeusuario eu ON eu.cdequipe = e.cdequipe
JOIN QUALITOR.dbo.ad_usuario u ON u.cdusuario = eu.cdusuario
WHERE u.nmusuario = '` + safe + `'
ORDER BY e.nmequipe`
// Stats 30 dias
sqlStats := `SELECT
COUNT(*) AS total,
SUM(CASE WHEN STATUS = 'TERMINADO' THEN 1 ELSE 0 END) AS terminados,
SUM(CASE WHEN STATUS NOT IN ('TERMINADO','Cancelado') THEN 1 ELSE 0 END) AS abertos
FROM lgit_chamados
WHERE ATENDENTE = '` + safe + `' AND DATA_ABERTURA >= DATEADD(DAY, -30, GETDATE())`
xmlUser, err := qualitorQuery(token, cookie, sqlUser)
if err != nil {
return nil, err
}
xmlEquipes, err := qualitorQuery(token, cookie, sqlEquipes)
if err != nil {
return nil, err
}
xmlStats, err := qualitorQuery(token, cookie, sqlStats)
if err != nil {
return nil, err
}
// Parse user
decoded := extractResult(xmlUser)
items := extractDataItems(decoded)
if len(items) == 0 {
return nil, fmt.Errorf("usuário '%s' não encontrado", nome)
}
f := extractAllFields(items[0])
result := &UsuarioDetalhado{
Nome: f["nmusuario"],
Email: f["dsemail"],
Login: f["nmusuariorede"],
Cargo: f["nmcargo"],
Superior: f["superior"],
Ativo: f["idativo"],
Disponivel: f["iddisponivel"],
Bloqueado: f["idbloqueado"],
}
// Parse equipes
decodedEq := extractResult(xmlEquipes)
eqItems := extractDataItems(decodedEq)
for _, block := range eqItems {
eq := extractField(block, "nmequipe")
if eq != "" {
result.Equipes = append(result.Equipes, eq)
}
}
// Parse stats
decodedSt := extractResult(xmlStats)
stItems := extractDataItems(decodedSt)
if len(stItems) > 0 {
sf := extractAllFields(stItems[0])
result.Total30d = sf["total"]
result.Terminados = sf["terminados"]
result.Abertos = sf["abertos"]
}
return result, nil
}
func formatUsuarioForLLM(u *UsuarioDetalhado) string {
var b strings.Builder
b.WriteString(fmt.Sprintf("# Usuário: %s\n\n", u.Nome))
b.WriteString(fmt.Sprintf("**E-mail:** %s\n", u.Email))
b.WriteString(fmt.Sprintf("**Login:** %s\n", u.Login))
b.WriteString(fmt.Sprintf("**Cargo:** %s\n", u.Cargo))
b.WriteString(fmt.Sprintf("**Superior:** %s\n", u.Superior))
status := "Ativo"
if u.Ativo != "Y" {
status = "Inativo"
}
if u.Bloqueado == "S" {
status += " (Bloqueado)"
}
b.WriteString(fmt.Sprintf("**Status:** %s | **Disponível:** %s\n", status, u.Disponivel))
if len(u.Equipes) > 0 {
b.WriteString(fmt.Sprintf("**Equipes:** %s\n", strings.Join(u.Equipes, ", ")))
}
b.WriteString(fmt.Sprintf("\n## Chamados (últimos 30 dias)\n"))
b.WriteString(fmt.Sprintf("- Total: %s\n", u.Total30d))
b.WriteString(fmt.Sprintf("- Terminados: %s\n", u.Terminados))
b.WriteString(fmt.Sprintf("- Em aberto: %s\n", u.Abertos))
return b.String()
}
func formatPesquisaUsuariosForLLM(usuarios []UsuarioResumo, busca string) string {
var b strings.Builder
b.WriteString(fmt.Sprintf("# Pesquisa de Usuários (%d resultados)\n\n", len(usuarios)))
b.WriteString(fmt.Sprintf("**Busca:** \"%s\"\n\n", busca))
if len(usuarios) == 0 {
b.WriteString("Nenhum usuário encontrado.\n")
return b.String()
}
b.WriteString("| Nome | E-mail | Cargo | Disponível |\n")
b.WriteString("|------|--------|-------|------------|\n")
for _, u := range usuarios {
disp := "Sim"
if u.Disponivel != "Y" {
disp = "Não"
}
b.WriteString(fmt.Sprintf("| %s | %s | %s | %s |\n", u.Nome, u.Email, u.Cargo, disp))
}
return b.String()
}
func filterEmpty(ss []string) []string {
var out []string
for _, s := range ss {
@@ -990,6 +1190,34 @@ func handleToolsList(id json.RawMessage, w io.Writer) {
},
},
},
{
"name": "pesquisar_usuarios",
"description": "Pesquisa usuários ativos no Qualitor por nome, e-mail ou login de rede. Retorna nome, e-mail, cargo e disponibilidade.",
"inputSchema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"busca": map[string]interface{}{
"type": "string",
"description": "Texto para buscar no nome, e-mail ou login do usuário (ex: 'Odilon', 'odilon.silva', 'grupothink')",
},
},
"required": []string{"busca"},
},
},
{
"name": "get_usuario",
"description": "Busca informações detalhadas de um usuário no Qualitor pelo nome completo. Retorna dados pessoais (e-mail, login, cargo, superior hierárquico), equipes que participa, status (ativo/bloqueado/disponível) e estatísticas de chamados dos últimos 30 dias.",
"inputSchema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"nome": map[string]interface{}{
"type": "string",
"description": "Nome completo do usuário no Qualitor (ex: 'Odilon Pascoal Mendes Silva')",
},
},
"required": []string{"nome"},
},
},
},
})
}
@@ -1081,6 +1309,74 @@ func handleToolCall(id json.RawMessage, params json.RawMessage, w io.Writer) {
},
})
case "pesquisar_usuarios":
var args struct {
Busca string `json:"busca"`
}
json.Unmarshal(p.Arguments, &args)
if args.Busca == "" {
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": "Erro: campo 'busca' é obrigatório"},
},
"isError": true,
})
return
}
usuarios, err := pesquisarUsuarios(args.Busca)
if err != nil {
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": fmt.Sprintf("Erro: %s", err.Error())},
},
"isError": true,
})
return
}
text := formatPesquisaUsuariosForLLM(usuarios, args.Busca)
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": text},
},
})
case "get_usuario":
var args struct {
Nome string `json:"nome"`
}
json.Unmarshal(p.Arguments, &args)
if args.Nome == "" {
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": "Erro: campo 'nome' é obrigatório"},
},
"isError": true,
})
return
}
usuario, err := getUsuario(args.Nome)
if err != nil {
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": fmt.Sprintf("Erro: %s", err.Error())},
},
"isError": true,
})
return
}
text := formatUsuarioForLLM(usuario)
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": text},
},
})
default:
sendResponse(w, id, map[string]interface{}{
"content": []map[string]interface{}{

Binary file not shown.