diff --git a/rest/controllers/api/ia_v2_controller.go b/rest/controllers/api/ia_v2_controller.go new file mode 100644 index 0000000..ee6ec53 --- /dev/null +++ b/rest/controllers/api/ia_v2_controller.go @@ -0,0 +1,39 @@ +package controllers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/sujit-baniya/fiber-boilerplate/pkg/services" +) + +// GenerarTextoIA corre una generación con la configuración de IA que el staff +// eligió en /app/ai-config para el módulo "ia" (el que la pantalla llama +// "IA / vCard"). +// +// La clave del proveedor no sale de acá: la integración manda su prompt con su +// propia API key de /api/v2 y recibe el texto. Es la diferencia con devolverle +// la configuración —incluida la clave de OpenAI o Anthropic— a otra aplicación. +// +// POST /api/v2/vcard/ia {"prompt": "...", "sistema": "..."} +func GenerarTextoIA(c *fiber.Ctx) error { + var body struct { + Prompt string `json:"prompt"` + Sistema string `json:"sistema"` + } + if err := c.BodyParser(&body); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) + } + if body.Prompt == "" { + return c.Status(400).JSON(fiber.Map{"error": "prompt requerido"}) + } + if body.Sistema == "" { + body.Sistema = "Respondé de forma clara y breve." + } + + // El módulo va fijo: si lo eligiera quien llama, una llave con scope vcard + // podría usar la configuración del agente o la del Landing Generator. + texto, err := services.CompletarTextoIA("ia", body.Sistema, body.Prompt) + if err != nil { + return c.Status(502).JSON(fiber.Map{"error": err.Error()}) + } + return c.JSON(fiber.Map{"texto": texto}) +} diff --git a/rest/controllers/hermes_spec_controller.go b/rest/controllers/hermes_spec_controller.go index 65fa887..766260a 100644 --- a/rest/controllers/hermes_spec_controller.go +++ b/rest/controllers/hermes_spec_controller.go @@ -441,6 +441,7 @@ func AdminApiSpec(c *fiber.Ctx) error { {"method": "POST", "path": "/api/v2/vcard/qr", "desc": "QR de contacto — devuelve imagen image/webp, NO JSON"}, {"method": "POST", "path": "/api/v2/vcard/qr-url", "desc": "QR de una URL → {\"url\": \"...\"}"}, {"method": "POST", "path": "/api/v2/vcard/vcf", "desc": "Generar archivo .vcf → {\"success\": true, \"url\": \"...\"}"}, + {"method": "POST", "path": "/api/v2/vcard/ia", "desc": "Generar texto con la IA configurada en /app/ai-config (módulo 'ia') → {\"texto\": \"...\"}"}, {"method": "POST", "path": "/api/v2/vcard/dlocal/planes", "desc": "Crear plan de suscripción"}, {"method": "GET", "path": "/api/v2/vcard/dlocal/planes", "desc": "Listar planes"}, {"method": "GET", "path": "/api/v2/vcard/dlocal/planes/:planID", "desc": "Ver un plan"}, diff --git a/rest/routes/hermes.go b/rest/routes/hermes.go index 9a384ea..b5a1b28 100644 --- a/rest/routes/hermes.go +++ b/rest/routes/hermes.go @@ -394,6 +394,10 @@ func AdminApiRoutes(api fiber.Router) { vcard.Post("/qr-url", apiControllers.CreateUrlQr) vcard.Post("/vcf", apiControllers.CreateVcf) + // Generación de texto con la configuración de IA del panel. La integración + // manda el prompt y recibe el texto: la clave del proveedor no sale de acá. + vcard.Post("/ia", apiControllers.GenerarTextoIA) + // dLocal y Rapyd bajo el mismo scope: son las operaciones de cobro que // acompañan a la VCard, y quien integra una necesita la otra. vcard.Post("/dlocal/planes", apiControllers.CreatePlan) diff --git a/rest/routes/hermes_vcard_test.go b/rest/routes/hermes_vcard_test.go index e813539..945cfcb 100644 --- a/rest/routes/hermes_vcard_test.go +++ b/rest/routes/hermes_vcard_test.go @@ -26,6 +26,7 @@ func TestRutasVcardRegistradas(t *testing.T) { "POST /v2/vcard/qr", "POST /v2/vcard/qr-url", "POST /v2/vcard/vcf", + "POST /v2/vcard/ia", "POST /v2/vcard/dlocal/planes", "GET /v2/vcard/dlocal/planes", "GET /v2/vcard/dlocal/planes/:planID",