/** * Schemas JSON para validación de respuestas NLU */ import Ajv from "ajv"; const ajv = new Ajv({ allErrors: true, strict: true }); // ───────────────────────────────────────────────────────────── // Schema: Router // ───────────────────────────────────────────────────────────── export const RouterSchema = { $id: "Router", type: "object", additionalProperties: false, required: ["domain"], properties: { domain: { type: "string", enum: ["greeting", "orders", "shipping", "payment", "browse", "other"], }, }, }; export const validateRouter = ajv.compile(RouterSchema); // ───────────────────────────────────────────────────────────── // Schema: Greeting // ───────────────────────────────────────────────────────────── export const GreetingSchema = { $id: "Greeting", type: "object", additionalProperties: false, required: ["intent", "reply"], properties: { intent: { type: "string", enum: ["greeting"] }, reply: { type: "string", minLength: 1 }, }, }; export const validateGreeting = ajv.compile(GreetingSchema); // ───────────────────────────────────────────────────────────── // Schema: Orders // ───────────────────────────────────────────────────────────── export const OrdersSchema = { $id: "Orders", type: "object", additionalProperties: false, required: ["intent", "confidence"], properties: { intent: { type: "string", enum: ["add_to_cart", "remove_from_cart", "view_cart", "confirm_order"], }, confidence: { type: "number", minimum: 0, maximum: 1 }, items: { anyOf: [ { type: "null" }, { type: "array", items: { type: "object", additionalProperties: false, required: ["product_query"], properties: { product_query: { type: "string", minLength: 1 }, quantity: { anyOf: [{ type: "number" }, { type: "null" }] }, unit: { anyOf: [{ type: "string", enum: ["kg", "g", "unidad"] }, { type: "null" }] }, }, }, }, ], }, product_query: { anyOf: [{ type: "string" }, { type: "null" }] }, quantity: { anyOf: [{ type: "number" }, { type: "null" }] }, unit: { anyOf: [{ type: "string", enum: ["kg", "g", "unidad"] }, { type: "null" }] }, }, }; export const validateOrders = ajv.compile(OrdersSchema); // ───────────────────────────────────────────────────────────── // Schema: Shipping // ───────────────────────────────────────────────────────────── export const ShippingSchema = { $id: "Shipping", type: "object", additionalProperties: false, required: ["intent"], properties: { intent: { type: "string", enum: ["select_shipping", "provide_address"], }, shipping_method: { anyOf: [{ type: "string", enum: ["delivery", "pickup"] }, { type: "null" }], }, address: { anyOf: [{ type: "string" }, { type: "null" }] }, }, }; export const validateShipping = ajv.compile(ShippingSchema); // ───────────────────────────────────────────────────────────── // Schema: Payment // ───────────────────────────────────────────────────────────── export const PaymentSchema = { $id: "Payment", type: "object", additionalProperties: false, required: ["intent"], properties: { intent: { type: "string", enum: ["select_payment"], }, payment_method: { anyOf: [{ type: "string", enum: ["cash", "link"] }, { type: "null" }], }, }, }; export const validatePayment = ajv.compile(PaymentSchema); // ───────────────────────────────────────────────────────────── // Schema: Browse // ───────────────────────────────────────────────────────────── export const BrowseSchema = { $id: "Browse", type: "object", additionalProperties: false, required: ["intent"], properties: { intent: { type: "string", enum: ["price_query", "browse", "recommend"], }, product_query: { anyOf: [{ type: "string" }, { type: "null" }] }, people_count: { anyOf: [{ type: "number" }, { type: "null" }] }, event_type: { anyOf: [{ type: "string" }, { type: "null" }] }, }, }; export const validateBrowse = ajv.compile(BrowseSchema); // ───────────────────────────────────────────────────────────── // Schema: NLU Unificado (output final) // ───────────────────────────────────────────────────────────── export const UnifiedNluSchema = { $id: "UnifiedNlu", type: "object", additionalProperties: false, required: ["intent", "confidence", "language", "entities", "needs"], properties: { intent: { type: "string", enum: [ "price_query", "browse", "add_to_cart", "remove_from_cart", "checkout", "confirm_order", "select_payment", "select_shipping", "provide_address", "greeting", "recommend", "view_cart", "other" ], }, confidence: { type: "number", minimum: 0, maximum: 1 }, language: { type: "string" }, entities: { type: "object", additionalProperties: false, required: ["product_query", "quantity", "unit", "selection", "attributes", "preparation", "items"], properties: { product_query: { anyOf: [{ type: "string" }, { type: "null" }] }, quantity: { anyOf: [{ type: "number" }, { type: "null" }] }, unit: { anyOf: [{ type: "string", enum: ["kg", "g", "unidad"] }, { type: "null" }] }, selection: { anyOf: [ { type: "null" }, { type: "object", additionalProperties: false, required: ["type", "value"], properties: { type: { type: "string", enum: ["index", "text", "sku"] }, value: { type: "string", minLength: 1 }, }, }, ], }, attributes: { type: "array", items: { type: "string" } }, preparation: { type: "array", items: { type: "string" } }, payment_method: { anyOf: [{ type: "string", enum: ["cash", "link"] }, { type: "null" }] }, shipping_method: { anyOf: [{ type: "string", enum: ["delivery", "pickup"] }, { type: "null" }] }, address: { anyOf: [{ type: "string" }, { type: "null" }] }, items: { anyOf: [ { type: "null" }, { type: "array", items: { type: "object", additionalProperties: false, required: ["product_query"], properties: { product_query: { type: "string", minLength: 1 }, quantity: { anyOf: [{ type: "number" }, { type: "null" }] }, unit: { anyOf: [{ type: "string", enum: ["kg", "g", "unidad"] }, { type: "null" }] }, }, }, }, ], }, // Browse-specific people_count: { anyOf: [{ type: "number" }, { type: "null" }] }, event_type: { anyOf: [{ type: "string" }, { type: "null" }] }, }, }, needs: { type: "object", additionalProperties: false, required: ["catalog_lookup", "knowledge_lookup"], properties: { catalog_lookup: { type: "boolean" }, knowledge_lookup: { type: "boolean" }, }, }, // Greeting-specific: reply del LLM reply: { anyOf: [{ type: "string" }, { type: "null" }] }, }, }; export const validateUnifiedNlu = ajv.compile(UnifiedNluSchema); // ───────────────────────────────────────────────────────────── // Helpers // ───────────────────────────────────────────────────────────── /** * Obtiene errores de validación formateados */ export function getValidationErrors(validate) { const errors = validate.errors || []; return errors.map((e) => ({ path: e.instancePath, message: e.message, params: e.params, })); } /** * Crea un NLU unificado vacío (fallback) */ export function createEmptyNlu() { return { intent: "other", confidence: 0, language: "es-AR", entities: { product_query: null, quantity: null, unit: null, selection: null, attributes: [], preparation: [], payment_method: null, shipping_method: null, address: null, items: null, people_count: null, event_type: null, }, needs: { catalog_lookup: false, knowledge_lookup: false, }, reply: null, }; }