Agregar contexto de la asignatura al chat y se agrega estructura de contenido tematico y de criterios de evaluación para la respuesta estructurada
fix #55
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
export const definicionesDeEstructurasDeColumnas = {
|
||||||
|
contenido_tematico: {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"x-column": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"contenido_tematico",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"x-definicion": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"unidad": {
|
||||||
|
"type": "integer",
|
||||||
|
},
|
||||||
|
"titulo": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"temas": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"nombre": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"horasEstimadas": {
|
||||||
|
"type": "integer",
|
||||||
|
"description":
|
||||||
|
"Horas del tema. La suma de todas las horasEstimadas debe ser igual a las horas académicas del prompt.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"nombre",
|
||||||
|
"horasEstimadas",
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"unidad",
|
||||||
|
"titulo",
|
||||||
|
"temas",
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"x-column",
|
||||||
|
"x-definicion",
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
},
|
||||||
|
criterios_de_evaluacion: {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"x-column": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"criterios_de_evaluacion",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"x-definicion": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"criterio": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"porcentaje": {
|
||||||
|
"type": "integer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"criterio",
|
||||||
|
"porcentaje",
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"x-column",
|
||||||
|
"x-definicion",
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { definicionesDeEstructurasDeColumnas } from "../../_shared/estructuras.ts";
|
||||||
import { HttpError } from "./errors.ts";
|
import { HttpError } from "./errors.ts";
|
||||||
|
|
||||||
export function pickSchemaFields(
|
export function pickSchemaFields(
|
||||||
definicion: any,
|
definicion: any,
|
||||||
campos: string[],
|
campos: string[],
|
||||||
@@ -45,17 +45,15 @@ export function pickSchemaFields(
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pickSchemaAsignaturaFields(
|
export function pickSchemaAsignaturaFields(
|
||||||
definicion: any,
|
definicion: any,
|
||||||
campos: string[],
|
campos: string[],
|
||||||
) {
|
) {
|
||||||
console.log(campos);
|
|
||||||
console.log(definicion);
|
|
||||||
if (!definicion || definicion.type !== "object" || !definicion.properties) {
|
if (!definicion || definicion.type !== "object" || !definicion.properties) {
|
||||||
return definicion;
|
return definicion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Campos extra de control
|
|
||||||
const extra = {
|
const extra = {
|
||||||
properties: {
|
properties: {
|
||||||
"ai-message": {
|
"ai-message": {
|
||||||
@@ -70,33 +68,36 @@ export function pickSchemaAsignaturaFields(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const out = structuredClone(definicion);
|
const out = structuredClone(definicion);
|
||||||
|
const finalProperties: Record<string, any> = {};
|
||||||
|
const finalRequired: string[] = [];
|
||||||
|
|
||||||
// FILTRADO: Si el usuario pidió campos específicos, filtramos.
|
campos.forEach((key) => {
|
||||||
// Si campos está vacío, la lógica de Planes devolvería todo,
|
|
||||||
// pero aquí asumimos que siempre vienen campos si isStructured es true.
|
// REVISIÓN DE ESTRUCTURA ESPECIAL
|
||||||
const entries = Object.entries(out.properties).filter(([k]) =>
|
if (key in definicionesDeEstructurasDeColumnas) {
|
||||||
campos.includes(k)
|
// Extraemos solo el esquema del array que vive en 'x-definicion'
|
||||||
);
|
// Esto hace que la IA reciba el esquema del array directamente
|
||||||
|
const especial = (definicionesDeEstructurasDeColumnas as any)[key];
|
||||||
out.properties = Object.fromEntries(entries);
|
|
||||||
|
finalProperties[key] = especial.properties["x-definicion"];
|
||||||
if (Array.isArray(out.required)) {
|
finalRequired.push(key);
|
||||||
out.required = out.required.filter((k: string) => campos.includes(k));
|
}
|
||||||
}
|
// CAMPOS NORMALES (los que están en 'datos')
|
||||||
|
else if (out.properties[key]) {
|
||||||
|
finalProperties[key] = out.properties[key];
|
||||||
|
if (out.required?.includes(key)) {
|
||||||
|
finalRequired.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// SIEMPRE agregamos los campos de control (ai-message, is_refusal)
|
out.properties = { ...finalProperties, ...extra.properties };
|
||||||
out.properties = { ...out.properties, ...extra.properties };
|
out.required = [...new Set([...finalRequired, ...Object.keys(extra.properties)])];
|
||||||
|
|
||||||
// Reconstruimos los requeridos para que OpenAI sepa que DEBE llenar los campos solicitados
|
|
||||||
out.required = Array.isArray(out.required)
|
|
||||||
? [...new Set([...out.required, ...Object.keys(extra.properties)])]
|
|
||||||
: Object.keys(extra.properties);
|
|
||||||
|
|
||||||
// Forzamos que no invente campos
|
|
||||||
out.additionalProperties = false;
|
out.additionalProperties = false;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function safePlanForPrompt(plan: any) {
|
export function safePlanForPrompt(plan: any) {
|
||||||
const copy = structuredClone(plan);
|
const copy = structuredClone(plan);
|
||||||
if (copy?.estructuras_plan) delete copy.estructuras_plan;
|
if (copy?.estructuras_plan) delete copy.estructuras_plan;
|
||||||
|
|||||||
Reference in New Issue
Block a user