3. Campos de Configuración de API
3.1. Campos Obligatorios
enabled
Type: boolean | OBLIGATORIO
Descripción: Activa o desactiva la API.
Valores: true | false
Ejemplo:
"enabled": true
base_url
Type: string | OBLIGATORIO
Descripción: URL base del servidor API.
Formato: https://dominio.com (sin trailing slash)
Ejemplo:
"base_url": "https://api.miempresa.com"
endpoint
Type: string | OBLIGATORIO
Descripción: Endpoint específico de la API.
Formato: Ruta relativa con placeholders opcionales {id}, {resource_id}, etc.
Ejemplos:
"endpoint": "/api/v1/quotations"
"endpoint": "/api/v1/quotations/{id}"
"endpoint": "/api/v1/customers/{customer_id}/orders/{id}"
method
Type: string | OBLIGATORIO
Descripción: Método HTTP de la petición.
Valores: GET | POST | PUT | PATCH | DELETE
Ejemplo:
"method": "POST"
token
Type: string | OBLIGATORIO
Descripción: Token de autenticación para la API (Bearer token).
Formato: String del token (será enviado como Authorization: Bearer {token})
Ejemplo:
"token": "9|shIrISTPHEbvmpPPnGgH0ZtBxqTICxLYaw7MHpmq35b3d381"
fields
Type: object | OBLIGATORIO
Descripción: Schema completo de todos los campos que la API acepta.
Formato: Objeto con campos como keys. Ver sección Configuración de Campos.
3.2. Campos Opcionales
operation
Type: string | OPCIONAL
Descripción: Tipo de operación CRUD que realiza la API.
Valores: create | read | update | delete
Uso: Ayuda al sistema a clasificar la intención del usuario.
Ejemplo:
"operation": "create"
description
Type: string | OPCIONAL
Descripción: Descripción legible de lo que hace la API.
Uso: Para logging y debugging.
Ejemplo:
"description": "Crear nueva cotización con productos"
timeout
Type: integer | OPCIONAL (default: 30)
Descripción: Timeout de la petición HTTP en segundos.
Ejemplo:
"timeout": 10
response_mapping
Type: object | OPCIONAL
Descripción: Mapeo de la estructura de respuesta de la API.
Subopciones:
- id_field: Ruta al ID del recurso (ej: "data.id")
- data_field: Ruta a los datos del recurso (para GET)
- message_field: Ruta al mensaje de respuesta
- success_field: Ruta al campo que indica éxito/fallo
- exclude_from_merge: Array de campos a excluir al mergear datos
Ejemplo:
"response_mapping": {
"id_field": "data.id",
"data_field": "data",
"message_field": "message",
"success_field": "success",
"exclude_from_merge": ["id", "created_at", "updated_at"]
}
3.3. Campos Nuevos (Sistema Genérico) NUEVO
resource_type
Type: string | NUEVO | OPCIONAL
Descripción: Tipo de recurso que maneja la API (para sistema genérico).
Valores sugeridos: quotation, reservation, order, appointment, ticket, booking, lead, customer
Uso: El sistema usa este valor para:
- Guardar estado genérico (last_resource_id, last_resource_type)
- Permitir referencias futuras ("modificar la última reserva")
- Mensajes contextuales
Ejemplos por Dominio:
"resource_type": "quotation" // E-commerce
"resource_type": "reservation" // Hotel
"resource_type": "appointment" // Consultorio médico
"resource_type": "ticket" // Soporte técnico
resource_name_es
Type: string | NUEVO | OPCIONAL
Descripción: Nombre del recurso en español, usado en los mensajes de confirmacion del chatbot.
Uso: El chatbot reemplaza el texto generico "registro" con este nombre en sus respuestas de exito. Si se omite, usa el valor de resource_name como fallback; si tampoco existe, usa "registro".
Ejemplos por Dominio:
"resource_name_es": "paciente" // Clinica / consultorio
"resource_name_es": "cotizacion" // E-commerce
"resource_name_es": "reserva" // Hotel
"resource_name_es": "cita" // Agenda / calendario
"resource_name_es": "ticket" // Soporte tecnico
resource_name_en
Type: string | NUEVO | OPCIONAL
Descripción: Nombre del recurso en ingles, usado cuando el chatbot detecta que la conversacion es en ese idioma.
Uso: Si se omite, el chatbot usa el valor de resource_name_es como fallback.
Ejemplos por Dominio:
"resource_name_en": "patient" // Clinic / medical office
"resource_name_en": "quote" // E-commerce
"resource_name_en": "reservation" // Hotel
"resource_name_en": "appointment" // Scheduling
"resource_name_en": "ticket" // Support
Configuracion completa para una clinica:
"resource_name_es": "paciente",
"resource_name_en": "patient"
Mensaje generado (ES):
El paciente ha sido registrado correctamente. Numero de referencia: #123. Necesitas algo mas?
Mensaje generado (EN):
The patient has been registered successfully. Reference number: #123. Anything else?
calculation_rules
Type: object | NUEVO | OPCIONAL
Descripción: Reglas personalizadas para auto-generación de campos calculados.
Uso: Define lógica de negocio específica del dominio sin hardcodear en código Python.
Subopciones:
- auto_fields_prompt (string): Instrucciones para OpenAI sobre cómo calcular campos auto_generated
Ejemplo - Cotizaciones:
"calculation_rules": {
"auto_fields_prompt": "Para campos auto_generated: 1) Si el campo es 'subtotal' y hay un array 'details' con 'quantity' y 'unit_price', calcula la suma de (quantity * unit_price) para todos los items. 2) Si el campo es 'tax' y hay 'subtotal', calcula el 7% del subtotal. 3) Si el campo es 'total', calcula subtotal + tax - discount."
}
Ejemplo - Reservas de Hotel:
"calculation_rules": {
"auto_fields_prompt": "Para campos auto_generated: 1) Si el campo es 'total_nights' y hay 'check_in_date' y 'check_out_date', calcula la diferencia en días. 2) Si el campo es 'total_cost' y hay 'total_nights' y 'room_rate', multiplica ambos."
}
4. Configuración de Campos (fields)
Cada campo en el objeto fields define un dato que la API espera recibir.
4.1. Campos Básicos
| Campo |
Tipo |
¿Requerido? |
Descripción |
| type |
string |
SÍ |
Tipo de dato: string, number, integer, boolean, date, datetime, array, object |
| required |
boolean |
SÍ |
Indica si el campo es obligatorio (true | false) |
| description |
string |
SÍ |
Descripción del campo para que OpenAI entienda su propósito (CRÍTICO para captura correcta) |
Descripción CRÍTICA: OpenAI usa la descripción para entender qué dato capturar, validar que sea apropiado, y generar preguntas de captura. ¡Debe ser clara y específica!
4.2. Campos de Validación
| Campo |
Tipo |
Descripción |
Ejemplo |
| pattern |
string |
Regex para validar formato |
"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" |
| min |
number |
Valor mínimo (números) |
"min": 0.01 |
| max |
number |
Valor máximo (números) |
"max": 10000 |
| max_length |
integer |
Longitud máxima (strings) |
"max_length": 500 |
4.3. Campos de UI/Captura
| Campo |
Tipo |
Descripción |
display_label_es display_label_en |
string |
Etiqueta amigable para mostrar al usuario en español/inglés. El chatbot usa esto en mensajes de captura. |
| capture_order |
integer |
Orden en que se capturan los campos (menor = primero). Define la secuencia de preguntas del chatbot. |
4.4. Auto-Generación NUEVO
Campos Auto-Generados: El sistema NO pregunta por estos campos al usuario, los calcula automáticamente usando OpenAI basándose en la descripción, fórmula y datos disponibles.
auto_generated
Type: boolean | NUEVO
Descripción: Indica que el campo se genera automáticamente.
Valores: true | false
Ejemplo:
"quotation_date": {
"type": "date",
"auto_generated": true,
"default": "today"
}
default
Type: any | NUEVO
Descripción: Valor por defecto si no se puede calcular.
Valores especiales:
- "today": Fecha actual (para type: date)
- "now": Timestamp actual (para type: datetime)
- 0: Cero numérico
- "": String vacío
Ejemplo:
"discount": {
"type": "number",
"auto_generated": true,
"default": 0,
"description": "Descuento (0 si no se especifica)"
}
formula
Type: string | NUEVO
Descripción: Fórmula Python para calcular el campo.
Uso: OpenAI genera código basado en esta fórmula + datos disponibles.
Formato: Expresión Python válida. Variables disponibles: Todos los campos capturados.
Ejemplos:
// Suma de items en array
"formula": "sum(item['quantity'] * item['unit_price'] for item in details)"
// Porcentaje
"formula": "subtotal * 0.07"
// Operación matemática
"formula": "subtotal + tax - discount"
// Diferencia de fechas
"formula": "(check_out_date - check_in_date).days"
calculated_from
Type: array | NUEVO
Descripción: Lista de campos de los que depende este cálculo.
Uso: El sistema sabe qué datos necesita antes de calcular.
Formato: Array de strings con nombres de campos. Notación dot para arrays: "details.quantity"
Ejemplo:
"total": {
"type": "number",
"auto_generated": true,
"formula": "subtotal + tax - discount",
"calculated_from": ["subtotal", "tax", "discount"],
"description": "Total final (subtotal + impuesto - descuento)"
}
4.5. Campos de Tipo Array
Para campos tipo array, usa la estructura especial con items:
"details": {
"type": "array",
"required": true,
"description": "Lista de productos a cotizar",
"display_label_es": "productos",
"display_label_en": "products",
"items": {
"product_name": {
"type": "string",
"required": true,
"description": "Nombre del producto"
},
"quantity": {
"type": "number",
"min": 0.01,
"required": true,
"description": "Cantidad"
},
"unit_price": {
"type": "number",
"min": 0,
"required": true,
"description": "Precio unitario en USD"
}
}
}
4.6. Mapeo Automático de Campos Array (Fuzzy Matching) ⭐ NUEVO
Problema Resuelto: Cuando el chatbot extrae datos de conversaciones, los nombres de campos pueden no coincidir exactamente con los esperados por la API.
Solución: El sistema incluye fuzzy matching automático que mapea nombres internos a nombres de API sin necesidad de configuración explícita.
¿Cómo funciona?
// El chatbot extrae:
{
"product_name": "Windows 11 Pro",
"quantity": 1,
"unit_price": 15.9
}
// La API espera:
{
"Description": "Windows 11 Pro",
"Quantity": 1,
"Unit_Price": 15.9
}
// Sistema mapea automáticamente:
[AUTO-MAP] product_name → Description (similitud: 0.85)
[AUTO-MAP] quantity → Quantity (similitud: 0.95)
[AUTO-MAP] unit_price → Unit_Price (similitud: 0.95)
Características del Algoritmo
| Característica |
Descripción |
| Normalization |
Convierte CamelCase ↔ snake_case automáticamente |
| Keyword Detection |
Detecta palabras clave: description, quantity, price, unitprice, etc. |
| Fuzzy Matching |
Usa difflib.SequenceMatcher para similitud flexible (umbral: 60%) |
| Language Agnostic |
Funciona con español, inglés y otros idiomas |
| Zero Configuration |
No requiere mapeos hardcodeados en apis_config.json |
| Deterministic |
Los mismos nombres siempre se mapean igual forma |
Estrategia de Detección (3 Niveles)
1. Similitud de String Normalizado
- Normaliza ambos nombres a snake_case
- Calcula similitud con SequenceMatcher
- Si similitud > 60%, es candidato
2. Detección de Palabras Clave
Si esperado = "Description" y entrada contiene "name" o "product"
→ Score = 0.90 (muy probable)
Si esperado = "Quantity" y entrada contiene "qty" o "cantidad"
→ Score = 0.95 (casi seguro)
Si esperado = "Unit_Price" y entrada contiene "price" o "unitprice"
→ Score = 0.95 (casi seguro)
3. Mejor Coincidencia
- Selecciona el campo con score más alto
- Evita asignaciones múltiples al mismo campo
- Valida que el campo sea requerido
Beneficios - Inteligencia Dual (Fuzzy + OpenAI Fallback)
✅ Fuzzy Primero
Cero quota OpenAI para campos claros
✅ Fallback Inteligente
OpenAI mini si fuzzy falla
✅ Cobertura Total
Garantiza mapeo correcto siempre
✅ Logs Diferenciados
[AUTO-MAP] vs [AUTO-MAP-AI]
Flujo de Decisión
Item ingresa: {product_name, qty, unitprice}
↓
¿Hay coincidencias fuzzy matching > 60%?
/ \
SÍ NO
↓ ↓
Usar fuzzy matching Usar OpenAI mini
[AUTO-MAP] [AUTO-MAP-AI]
CERO quota OpenAI Mínima quota (JSON)
Logs de Ejemplo
Caso exitoso (sin OpenAI):
[AUTO-MAP] product_name → Description (similitud: 0.85)
[AUTO-MAP] quantity → Quantity (similitud: 0.95)
[AUTO-MAP] unit_price → Unit_Price (similitud: 0.95)
Caso fallback (con OpenAI mini):
[AUTO-MAP] No se encontraron coincidencias con fuzzy matching. Usando OpenAI mini...
[AUTO-MAP-AI] Mapeo con OpenAI mini: {"prod": "Description", "cant": "Quantity"}
Cuándo se activa cada estrategia
| Escenario |
Estrategia |
Quota OpenAI |
Ejemplo |
| Nombres claros |
Fuzzy matching |
❌ NO |
product_name, quantity |
| Abreviaciones |
Fuzzy matching |
❌ NO |
prod, qty, price |
| Multiidioma |
Fuzzy matching |
❌ NO |
cantidad, precio_unitario |
| Nombres crípticos |
OpenAI fallback |
✅ MINI |
x, y, z |
| Variaciones impredecibles |
OpenAI fallback |
✅ MINI |
custom_field_123 |
Ejemplos de Mapeos Automáticos
Entrada del Chatbot → Esperado por API → Similitud → Mapeo
─────────────────────────────────────────────────────────────────────
product_name → Description → 85% → ✅
qty → Quantity → 95%* (keyword) → ✅
unit_price → Unit_Price → 95%* (keyword) → ✅
precio_unitario → Unit_Price → 75% → ✅
nombre_producto → Description → 65% → ✅
desc → Description → 55% → ❌ (< 60%)
unknown_field → (sin mapeo) → - → ❌
Configuración Avanzada (Opcional)
Aunque el fuzzy matching es automático, puedes proporcionar un mapeo explícito si necesitas control total:
{
"apis": {
"API Especial": {
"fields": {
"Items": {
"type": "array",
"items": {
"Description": {"type": "string", "required": true},
"Quantity": {"type": "number", "required": true},
"Unit_Price": {"type": "number", "required": true}
},
"field_mapping": {
"product_name": "Description",
"qty": "Quantity",
"price": "Unit_Price"
}
}
}
}
}
}
5. Ejemplos Completos por Dominio
E-commerce: Cotizaciones
{
"Creacion de Cotizacion": {
"enabled": true,
"base_url": "https://api.miempresa.com",
"endpoint": "/api/v1/quotations",
"method": "POST",
"operation": "create",
"token": "tu-token-aqui",
"resource_type": "quotation",
"calculation_rules": {
"auto_fields_prompt": "Para 'subtotal': suma quantity*unit_price de items en 'details'. Para 'tax': calcula 7% del subtotal. Para 'total': suma subtotal + tax - discount."
},
"fields": {
"customer_name": {
"type": "string",
"required": true,
"description": "Nombre completo del cliente",
"display_label_es": "nombre completo",
"capture_order": 1
},
"details": {
"type": "array",
"required": true,
"description": "Lista de productos a cotizar",
"items": {
"product_name": {"type": "string", "required": true},
"quantity": {"type": "number", "required": true},
"unit_price": {"type": "number", "required": true}
}
},
"subtotal": {
"type": "number",
"auto_generated": true,
"formula": "sum(item['quantity'] * item['unit_price'] for item in details)",
"calculated_from": ["details.quantity", "details.unit_price"]
},
"tax": {
"type": "number",
"auto_generated": true,
"formula": "subtotal * 0.07",
"calculated_from": ["subtotal"]
},
"total": {
"type": "number",
"auto_generated": true,
"formula": "subtotal + tax - discount",
"calculated_from": ["subtotal", "tax", "discount"]
}
}
}
}
Hotelería: Reservas
{
"Crear Reserva": {
"enabled": true,
"base_url": "https://api.mihotel.com",
"endpoint": "/api/v1/reservations",
"method": "POST",
"resource_type": "reservation",
"calculation_rules": {
"auto_fields_prompt": "Para 'total_nights': calcula días entre check_in_date y check_out_date. Para 'total_cost': multiplica total_nights * room_rate."
},
"fields": {
"guest_name": {
"type": "string",
"required": true,
"description": "Nombre completo del huésped"
},
"check_in_date": {
"type": "date",
"required": true,
"description": "Fecha de entrada (YYYY-MM-DD)"
},
"check_out_date": {
"type": "date",
"required": true,
"description": "Fecha de salida (YYYY-MM-DD)"
},
"total_nights": {
"type": "integer",
"auto_generated": true,
"formula": "(check_out_date - check_in_date).days",
"calculated_from": ["check_in_date", "check_out_date"]
},
"total_cost": {
"type": "number",
"auto_generated": true,
"formula": "total_nights * room_rate",
"calculated_from": ["total_nights", "room_rate"]
}
}
}
}