ajustes
This commit is contained in:
296
main.go
296
main.go
@@ -845,6 +845,206 @@ func formatChargeabilityForLLM(result []ProfissionalChargeability, args Chargeab
|
|||||||
return b.String()
|
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 {
|
func filterEmpty(ss []string) []string {
|
||||||
var out []string
|
var out []string
|
||||||
for _, s := range ss {
|
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:
|
default:
|
||||||
sendResponse(w, id, map[string]interface{}{
|
sendResponse(w, id, map[string]interface{}{
|
||||||
"content": []map[string]interface{}{
|
"content": []map[string]interface{}{
|
||||||
|
|||||||
BIN
mcp-qualitor
BIN
mcp-qualitor
Binary file not shown.
Reference in New Issue
Block a user