package services import ( "fmt" "strings" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" ) // RedactarBorradorTicket propone una respuesta para un ticket, apoyándose en la // base de conocimiento del agente de uMind que se haya elegido en la // configuración de soporte. // // Devuelve un borrador, no una respuesta: no se manda a nadie. Contestarle solo // a un cliente con lo que dijo un modelo es la forma más rápida de perderlo; // acá lo lee una persona, lo corrige y aprieta enviar. func RedactarBorradorTicket(ticket *models.ProyectoTicket) (string, error) { if ticket == nil { return "", fmt.Errorf("ticket no encontrado") } cfg, _ := models.GetSoporteWebhookActivo() var conversacion strings.Builder fmt.Fprintf(&conversacion, "Asunto: %s\n\n%s: %s\n", ticket.Titulo, ticket.AutorNombre, ticket.Descripcion) for _, m := range ticket.Mensajes { quien := ticket.AutorNombre if m.EsAdmin { quien = "Soporte" } fmt.Fprintf(&conversacion, "\n%s: %s\n", quien, m.Contenido) } sistema := `Redactás borradores de respuesta para un equipo de soporte. Los lee una persona antes de enviarlos. - Escribí en el mismo idioma que usó el cliente. - Respondé lo que preguntó, directo, sin relleno ni frases de manual. - Usá SOLO lo que esté en la documentación de referencia y en la conversación. Si falta información para resolverlo, decilo y proponé qué preguntarle. - Nunca inventes precios, plazos, funciones ni pasos que no estén escritos. - Sin asunto, sin firma: solo el cuerpo del mensaje.` if cfg != nil && strings.TrimSpace(cfg.ContextoNegocio) != "" { sistema += "\n\nContexto del negocio:\n" + strings.TrimSpace(cfg.ContextoNegocio) } usuario := conversacion.String() if doc := documentacionRelevante(cfg, ticket); doc != "" { usuario = "Documentación de referencia:\n---\n" + doc + "\n---\n\nConversación:\n" + usuario } borrador, err := CompletarTextoIA("ia", sistema, usuario) if err != nil { return "", err } return strings.TrimSpace(borrador), nil } // documentacionRelevante busca en la base de conocimiento del agente elegido. // Sin agente configurado devuelve vacío y el borrador se arma solo con la // conversación — peor, pero mejor que un error. func documentacionRelevante(cfg *models.SoporteWebhookConfig, ticket *models.ProyectoTicket) string { if cfg == nil || cfg.AgenteBorradorID == nil || *cfg.AgenteBorradorID == 0 { return "" } consulta := ticket.Titulo + "\n" + ticket.Descripcion chunks, err := BuscarConocimiento(*cfg.AgenteBorradorID, consulta, 4) if err != nil || len(chunks) == 0 { return "" } var b strings.Builder for _, ch := range chunks { b.WriteString(strings.TrimSpace(ch.Contenido)) b.WriteString("\n\n") } return strings.TrimSpace(b.String()) }