up
This commit is contained in:
@@ -320,6 +320,77 @@ func quoteIdent(name, driver string) string {
|
||||
return "`" + strings.ReplaceAll(name, "`", "``") + "`"
|
||||
}
|
||||
|
||||
// NL2SQLHandler convierte lenguaje natural a SQL usando IA.
|
||||
// POST /app/query-runner/nl2sql
|
||||
// Body: { conx_db_id, database, text, schema }
|
||||
// schema es un array de { table, columns: [{name, type}] } para dar contexto a la IA.
|
||||
func NL2SQLHandler(c *fiber.Ctx) error {
|
||||
var body struct {
|
||||
ConxDbID uint `json:"conx_db_id"`
|
||||
Database string `json:"database"`
|
||||
Text string `json:"text"`
|
||||
Schema []struct {
|
||||
Table string `json:"table"`
|
||||
Columns []struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
} `json:"columns"`
|
||||
} `json:"schema"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cuerpo inválido"})
|
||||
}
|
||||
if strings.TrimSpace(body.Text) == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "El texto está vacío"})
|
||||
}
|
||||
|
||||
// Construir representación del esquema para el prompt
|
||||
var schemaLines []string
|
||||
for _, t := range body.Schema {
|
||||
var cols []string
|
||||
for _, col := range t.Columns {
|
||||
cols = append(cols, col.Name+" ("+col.Type+")")
|
||||
}
|
||||
if len(cols) > 0 {
|
||||
schemaLines = append(schemaLines, fmt.Sprintf(" %s: %s", t.Table, strings.Join(cols, ", ")))
|
||||
} else {
|
||||
schemaLines = append(schemaLines, " "+t.Table)
|
||||
}
|
||||
}
|
||||
schemaStr := ""
|
||||
if len(schemaLines) > 0 {
|
||||
schemaStr = "Esquema disponible:\n" + strings.Join(schemaLines, "\n")
|
||||
}
|
||||
|
||||
aiConfig, err := models.GetAiConfigForService("query_runner")
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No hay configuración de IA activa. Configura una en /app/ai-config",
|
||||
})
|
||||
}
|
||||
|
||||
prompt := fmt.Sprintf(`Eres un experto en SQL. Convierte la siguiente descripción en lenguaje natural a una consulta SQL válida.
|
||||
|
||||
%s
|
||||
|
||||
Descripción: %s
|
||||
|
||||
Reglas:
|
||||
- Devuelve SOLO el SQL, sin explicaciones ni bloques de código markdown.
|
||||
- Usa los nombres de tablas y columnas exactamente como aparecen en el esquema.
|
||||
- Si la base de datos es PostgreSQL, usa comillas dobles para identificadores.
|
||||
- Termina siempre con punto y coma.
|
||||
- Si no hay suficiente información para generar el SQL, devuelve el SQL más razonable posible.
|
||||
|
||||
SQL:`, schemaStr, body.Text)
|
||||
|
||||
result := callAISQLSuggestion(aiConfig, prompt, "nl2sql", body.ConxDbID, body.Database)
|
||||
if result == nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "La IA no pudo generar el SQL"})
|
||||
}
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
// CorrectQueryHandler usa IA o heurística para corregir/sugerir queries.
|
||||
// POST /app/query-runner/suggest
|
||||
// Body: { conx_db_id, database, sql, action: "correct"|"complete"|"optimize" }
|
||||
@@ -340,8 +411,8 @@ func CorrectQueryHandler(c *fiber.Ctx) error {
|
||||
body.Action = "correct"
|
||||
}
|
||||
|
||||
// 1. Si hay una configuración de IA activa, usarla
|
||||
aiConfig, aiErr := models.GetActiveAiConfig("")
|
||||
// 1. Si hay una configuración de IA activa para este servicio, usarla
|
||||
aiConfig, aiErr := models.GetAiConfigForService("query_runner")
|
||||
if aiErr == nil && aiConfig != nil {
|
||||
aiResult := callAISQLSuggestion(aiConfig, body.SQL, body.Action, body.ConxDbID, body.Database)
|
||||
if aiResult != nil {
|
||||
|
||||
Reference in New Issue
Block a user