284 lines
10 KiB
JavaScript
284 lines
10 KiB
JavaScript
/**
|
|
* 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,
|
|
};
|
|
}
|