Ahora la IA puede generar los criterios de evaluación #47

Merged
Guillermo.Arrieta merged 1 commits from issue/46-homologar-campo-de-criterios-de-evaluacin-y-sistem into main 2026-03-05 17:36:43 +00:00
8 changed files with 167 additions and 20 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"allowScripts": [
"npm:deno@2.6.4",
"npm:supabase-js@1.0.4",
"npm:supabase@2.72.6"
"npm:supabase@2.75.0"
],
"imports": {
"@openai/openai": "jsr:@openai/openai@^6.16.0",
Generated
+8 -7
View File
@@ -28,7 +28,7 @@
"npm:openai@6.16.0": "6.16.0_zod@3.25.76",
"npm:openai@^4.52.5": "4.104.0_zod@3.25.76",
"npm:openai@^6.16.0": "6.16.0_zod@3.25.76",
"npm:supabase@^2.72.6": "2.72.6",
"npm:supabase@2.75.0": "2.75.0",
"npm:zod@3": "3.25.76"
},
"jsr": {
@@ -508,8 +508,8 @@
"signal-exit@4.1.0": {
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
},
"supabase@2.72.6": {
"integrity": "sha512-axO1MkZgwMIxj78vKiGosnuXwzOaQq0Kz0I8jheNMwJH9dKGf3q/arivYT44z8u3t5FjGUxQWOuQoJetzcmm/A==",
"supabase@2.75.0": {
"integrity": "sha512-Xaai8Wp7F03OMkOWSyS1OMMdk5DxkauJxcMMesj4mO6jDGEZpWBwgo/gIUb4hsckexmr/RXYdpDpTbUIMXahbw==",
"dependencies": [
"bin-links",
"https-proxy-agent",
@@ -519,15 +519,16 @@
"scripts": true,
"bin": true
},
"tar@7.5.2": {
"integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==",
"tar@7.5.7": {
"integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
"dependencies": [
"@isaacs/fs-minipass",
"chownr",
"minipass",
"minizlib",
"yallist"
]
],
"deprecated": true
},
"tr46@0.0.3": {
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
@@ -603,7 +604,7 @@
"npm:deno@^2.6.4",
"npm:jwt-decode@4",
"npm:openai@^6.16.0",
"npm:supabase@^2.72.6"
"npm:supabase@2.75.0"
]
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
"deno": "^2.6.4",
"jwt-decode": "^4.0.0",
"openai": "^6.16.0",
"supabase": "^2.72.6"
"supabase": "2.75.0"
},
"name": "genesis-2",
"module": "index.ts",
+2
View File
@@ -1,3 +1,5 @@
[db]
major_version = 15
[functions.ai-generate-plan]
enabled = true
@@ -141,6 +141,7 @@ export type Database = {
creado_en: string
creado_por: string | null
creditos: number
criterios_de_evaluacion: Json
datos: Json
estado: Database["public"]["Enums"]["estado_asignatura"]
estructura_id: string | null
@@ -165,6 +166,7 @@ export type Database = {
creado_en?: string
creado_por?: string | null
creditos: number
criterios_de_evaluacion?: Json
datos?: Json
estado?: Database["public"]["Enums"]["estado_asignatura"]
estructura_id?: string | null
@@ -189,6 +191,7 @@ export type Database = {
creado_en?: string
creado_por?: string | null
creditos?: number
criterios_de_evaluacion?: Json
datos?: Json
estado?: Database["public"]["Enums"]["estado_asignatura"]
estructura_id?: string | null
@@ -414,10 +414,9 @@ Deno.serve(async (req: Request): Promise<Response> => {
estructura_id: resolved.estructura_id as string,
nombre: resolved.nombre as string,
codigo: resolved.codigo ?? null,
tipo:
(resolved.tipo ?? undefined) as Database["public"]["Tables"][
"asignaturas"
]["Insert"]["tipo"],
tipo: (resolved.tipo ?? undefined) as Database["public"]["Tables"][
"asignaturas"
]["Insert"]["tipo"],
creditos: resolved.creditos as number,
horas_academicas: resolved.horas_academicas ?? null,
horas_independientes: resolved.horas_independientes ?? null,
@@ -458,7 +457,7 @@ Deno.serve(async (req: Request): Promise<Response> => {
const { data: estructura, error: estructuraError } = await supabaseService
.from("estructuras_asignatura")
.select("id,nombre,definicion,version")
.select("id,nombre,definicion")
.eq("id", resolved.estructura_id)
.single();
if (estructuraError) {
@@ -509,10 +508,11 @@ Deno.serve(async (req: Request): Promise<Response> => {
iaConfig.instruccionesAdicionalesIA ?? "(ninguna)"
}` +
archivosAdjuntosTexto +
`\n\nREGLA ESTRICTA MATEMÁTICA:\n` +
`Si generas el 'contenido_tematico', la suma total de las 'horasEstimadas' de todos los temas en todas las unidades DEBE coincidir exactamente con el total de Horas académicas indicadas arriba (${
`\n\nREGLAS ESTRICTAS MATEMÁTICAS:\n` +
`- Si generas el 'contenido_tematico', la suma total de las 'horasEstimadas' de todos los temas en todas las unidades DEBE coincidir exactamente con el total de Horas académicas indicadas arriba (${
resolved.horas_academicas ?? 0
}). No te pases ni te falten horas.`;
}). No te pases ni te falten horas.\n` +
`- Si generas los 'criterios_de_evaluacion', la suma total de los 'porcentajes' de todos los criterios DEBE ser exactamente 100%. No te pases ni te falten porcentajes.`;
const schemaDef: Record<string, unknown> =
typeof estructura?.definicion === "object" &&
@@ -658,4 +658,39 @@ const definicionesDeEstructurasDeColumnas = {
],
"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,
},
};
@@ -0,0 +1 @@
alter table "public"."asignaturas" add column "criterios_de_evaluacion" jsonb not null default '[]'::jsonb;
+108 -3
View File
@@ -108,6 +108,16 @@ CREATE TYPE "public"."estado_conversacion" AS ENUM (
ALTER TYPE "public"."estado_conversacion" OWNER TO "postgres";
CREATE TYPE "public"."estado_mensaje_ia" AS ENUM (
'PROCESANDO',
'COMPLETADO',
'ERROR'
);
ALTER TYPE "public"."estado_mensaje_ia" OWNER TO "postgres";
CREATE TYPE "public"."estado_tarea_revision" AS ENUM (
'PENDIENTE',
'COMPLETADA',
@@ -523,6 +533,24 @@ CREATE TABLE IF NOT EXISTS "public"."archivos" (
ALTER TABLE "public"."archivos" OWNER TO "postgres";
CREATE TABLE IF NOT EXISTS "public"."asignatura_mensajes_ia" (
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
"enviado_por" "uuid" DEFAULT "auth"."uid"() NOT NULL,
"mensaje" "text" NOT NULL,
"campos" "text"[] DEFAULT '{}'::"text"[] NOT NULL,
"respuesta" "text",
"is_refusal" boolean DEFAULT false NOT NULL,
"propuesta" "jsonb",
"estado" "public"."estado_mensaje_ia" DEFAULT 'PROCESANDO'::"public"."estado_mensaje_ia" NOT NULL,
"fecha_creacion" timestamp without time zone DEFAULT "now"() NOT NULL,
"fecha_actualizacion" timestamp without time zone DEFAULT "now"() NOT NULL,
"conversacion_asignatura_id" "uuid" NOT NULL
);
ALTER TABLE "public"."asignatura_mensajes_ia" OWNER TO "postgres";
CREATE TABLE IF NOT EXISTS "public"."asignaturas" (
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
"plan_estudio_id" "uuid" NOT NULL,
@@ -546,6 +574,7 @@ CREATE TABLE IF NOT EXISTS "public"."asignaturas" (
"horas_academicas" integer,
"horas_independientes" integer,
"estado" "public"."estado_asignatura" DEFAULT 'borrador'::"public"."estado_asignatura" NOT NULL,
"criterios_de_evaluacion" "jsonb" DEFAULT '[]'::"jsonb" NOT NULL,
CONSTRAINT "asignaturas_ciclo_chk" CHECK ((("numero_ciclo" IS NULL) OR ("numero_ciclo" > 0))),
CONSTRAINT "asignaturas_creditos_check" CHECK (("creditos" >= (0)::numeric)),
CONSTRAINT "asignaturas_horas_academicas_check" CHECK ((("horas_academicas" IS NULL) OR ("horas_academicas" >= 0))),
@@ -675,10 +704,11 @@ ALTER TABLE "public"."estados_plan" OWNER TO "postgres";
CREATE TABLE IF NOT EXISTS "public"."estructuras_asignatura" (
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
"nombre" "text" NOT NULL,
"version" "text",
"definicion" "jsonb" DEFAULT '{}'::"jsonb" NOT NULL,
"creado_en" timestamp with time zone DEFAULT "now"() NOT NULL,
"actualizado_en" timestamp with time zone DEFAULT "now"() NOT NULL
"actualizado_en" timestamp with time zone DEFAULT "now"() NOT NULL,
"template_id" "text",
"tipo" "public"."tipo_estructura_plan"
);
@@ -763,6 +793,24 @@ CREATE TABLE IF NOT EXISTS "public"."notificaciones" (
ALTER TABLE "public"."notificaciones" OWNER TO "postgres";
CREATE TABLE IF NOT EXISTS "public"."plan_mensajes_ia" (
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
"enviado_por" "uuid" DEFAULT "auth"."uid"() NOT NULL,
"mensaje" "text" NOT NULL,
"campos" "text"[] DEFAULT '{}'::"text"[] NOT NULL,
"respuesta" "text",
"is_refusal" boolean DEFAULT false NOT NULL,
"propuesta" "jsonb",
"estado" "public"."estado_mensaje_ia" DEFAULT 'PROCESANDO'::"public"."estado_mensaje_ia" NOT NULL,
"fecha_creacion" timestamp without time zone DEFAULT "now"() NOT NULL,
"fecha_actualizacion" timestamp without time zone DEFAULT "now"() NOT NULL,
"conversacion_plan_id" "uuid" NOT NULL
);
ALTER TABLE "public"."plan_mensajes_ia" OWNER TO "postgres";
CREATE TABLE IF NOT EXISTS "public"."planes_estudio" (
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
"carrera_id" "uuid" NOT NULL,
@@ -789,7 +837,18 @@ CREATE TABLE IF NOT EXISTS "public"."planes_estudio" (
ALTER TABLE "public"."planes_estudio" OWNER TO "postgres";
CREATE OR REPLACE VIEW "public"."plantilla_plan" AS
CREATE OR REPLACE VIEW "public"."plantilla_asignatura" AS
SELECT "asignaturas"."id" AS "asignatura_id",
"struct"."id" AS "estructura_id",
"struct"."template_id"
FROM ("public"."asignaturas"
JOIN "public"."estructuras_asignatura" "struct" ON (("asignaturas"."estructura_id" = "struct"."id")));
ALTER TABLE "public"."plantilla_asignatura" OWNER TO "postgres";
CREATE OR REPLACE VIEW "public"."plantilla_plan" WITH ("security_invoker"='on') AS
SELECT "plan"."id" AS "plan_estudio_id",
"struct"."id" AS "estructura_id",
"struct"."template_id"
@@ -896,6 +955,11 @@ ALTER TABLE ONLY "public"."archivos"
ALTER TABLE ONLY "public"."asignatura_mensajes_ia"
ADD CONSTRAINT "asignatura_mensajes_ia_pkey" PRIMARY KEY ("id");
ALTER TABLE ONLY "public"."asignaturas"
ADD CONSTRAINT "asignaturas_pkey" PRIMARY KEY ("id");
@@ -991,6 +1055,11 @@ ALTER TABLE ONLY "public"."notificaciones"
ALTER TABLE ONLY "public"."plan_mensajes_ia"
ADD CONSTRAINT "plan_mensajes_ia_pkey" PRIMARY KEY ("id");
ALTER TABLE ONLY "public"."planes_estudio"
ADD CONSTRAINT "planes_estudio_pkey" PRIMARY KEY ("id");
@@ -1136,6 +1205,11 @@ ALTER TABLE ONLY "public"."archivos"
ALTER TABLE ONLY "public"."asignatura_mensajes_ia"
ADD CONSTRAINT "asignatura_mensajes_ia_conversacion_asignatura_id_fkey" FOREIGN KEY ("conversacion_asignatura_id") REFERENCES "public"."conversaciones_asignatura"("id") ON DELETE CASCADE;
ALTER TABLE ONLY "public"."asignaturas"
ADD CONSTRAINT "asignaturas_actualizado_por_fkey" FOREIGN KEY ("actualizado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL;
@@ -1246,6 +1320,11 @@ ALTER TABLE ONLY "public"."notificaciones"
ALTER TABLE ONLY "public"."plan_mensajes_ia"
ADD CONSTRAINT "plan_mensajes_ia_conversacion_plan_id_fkey" FOREIGN KEY ("conversacion_plan_id") REFERENCES "public"."conversaciones_plan"("id") ON DELETE CASCADE;
ALTER TABLE ONLY "public"."planes_estudio"
ADD CONSTRAINT "planes_estudio_actualizado_por_fkey" FOREIGN KEY ("actualizado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL;
@@ -1350,6 +1429,14 @@ ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres";
ALTER PUBLICATION "supabase_realtime" ADD TABLE ONLY "public"."asignaturas";
ALTER PUBLICATION "supabase_realtime" ADD TABLE ONLY "public"."planes_estudio";
@@ -1688,6 +1775,12 @@ GRANT ALL ON TABLE "public"."archivos" TO "service_role";
GRANT ALL ON TABLE "public"."asignatura_mensajes_ia" TO "anon";
GRANT ALL ON TABLE "public"."asignatura_mensajes_ia" TO "authenticated";
GRANT ALL ON TABLE "public"."asignatura_mensajes_ia" TO "service_role";
GRANT ALL ON TABLE "public"."asignaturas" TO "anon";
GRANT ALL ON TABLE "public"."asignaturas" TO "authenticated";
GRANT ALL ON TABLE "public"."asignaturas" TO "service_role";
@@ -1772,12 +1865,24 @@ GRANT ALL ON TABLE "public"."notificaciones" TO "service_role";
GRANT ALL ON TABLE "public"."plan_mensajes_ia" TO "anon";
GRANT ALL ON TABLE "public"."plan_mensajes_ia" TO "authenticated";
GRANT ALL ON TABLE "public"."plan_mensajes_ia" TO "service_role";
GRANT ALL ON TABLE "public"."planes_estudio" TO "anon";
GRANT ALL ON TABLE "public"."planes_estudio" TO "authenticated";
GRANT ALL ON TABLE "public"."planes_estudio" TO "service_role";
GRANT ALL ON TABLE "public"."plantilla_asignatura" TO "anon";
GRANT ALL ON TABLE "public"."plantilla_asignatura" TO "authenticated";
GRANT ALL ON TABLE "public"."plantilla_asignatura" TO "service_role";
GRANT ALL ON TABLE "public"."plantilla_plan" TO "anon";
GRANT ALL ON TABLE "public"."plantilla_plan" TO "authenticated";
GRANT ALL ON TABLE "public"."plantilla_plan" TO "service_role";