Merge branch 'main' into issue/42-chats-de-la-ia-en-segundo-plano
This commit is contained in:
@@ -1 +1 @@
|
||||
postgresql://postgres.bxkskdxwppdlplrkidcz@aws-1-us-east-2.pooler.supabase.com:5432/postgres
|
||||
postgresql://postgres.exdkssurzmjnnhgtiama@aws-0-us-west-1.pooler.supabase.com:5432/postgres
|
||||
@@ -1 +1 @@
|
||||
17.6.1.063
|
||||
15.8.1.085
|
||||
@@ -1 +1 @@
|
||||
bxkskdxwppdlplrkidcz
|
||||
exdkssurzmjnnhgtiama
|
||||
@@ -1 +1 @@
|
||||
v14.1
|
||||
v12.2.3
|
||||
@@ -1,3 +1,5 @@
|
||||
[db]
|
||||
major_version = 15
|
||||
|
||||
[functions.ai-generate-plan]
|
||||
enabled = true
|
||||
@@ -63,3 +65,14 @@ entrypoint = "./functions/openai-webhook-responses/index.ts"
|
||||
# Specifies static files to be bundled with the function. Supports glob patterns.
|
||||
# For example, if you want to serve static HTML pages in your function:
|
||||
# static_files = [ "./functions/openai-webhook-responses/*.html" ]
|
||||
|
||||
[functions.buscar-bibliografia]
|
||||
enabled = true
|
||||
verify_jwt = true
|
||||
import_map = "./functions/buscar-bibliografia/deno.json"
|
||||
# Uncomment to specify a custom file path to the entrypoint.
|
||||
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
|
||||
entrypoint = "./functions/buscar-bibliografia/index.ts"
|
||||
# Specifies static files to be bundled with the function. Supports glob patterns.
|
||||
# For example, if you want to serve static HTML pages in your function:
|
||||
# static_files = [ "./functions/buscar-bibliografia/*.html" ]
|
||||
|
||||
@@ -81,6 +81,56 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
asignatura_mensajes_ia: {
|
||||
Row: {
|
||||
campos: string[]
|
||||
conversacion_asignatura_id: string
|
||||
enviado_por: string
|
||||
estado: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion: string
|
||||
fecha_creacion: string
|
||||
id: string
|
||||
is_refusal: boolean
|
||||
mensaje: string
|
||||
propuesta: Json | null
|
||||
respuesta: string | null
|
||||
}
|
||||
Insert: {
|
||||
campos?: string[]
|
||||
conversacion_asignatura_id: string
|
||||
enviado_por?: string
|
||||
estado?: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion?: string
|
||||
fecha_creacion?: string
|
||||
id?: string
|
||||
is_refusal?: boolean
|
||||
mensaje: string
|
||||
propuesta?: Json | null
|
||||
respuesta?: string | null
|
||||
}
|
||||
Update: {
|
||||
campos?: string[]
|
||||
conversacion_asignatura_id?: string
|
||||
enviado_por?: string
|
||||
estado?: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion?: string
|
||||
fecha_creacion?: string
|
||||
id?: string
|
||||
is_refusal?: boolean
|
||||
mensaje?: string
|
||||
propuesta?: Json | null
|
||||
respuesta?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "asignatura_mensajes_ia_conversacion_asignatura_id_fkey"
|
||||
columns: ["conversacion_asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "conversaciones_asignatura"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
asignaturas: {
|
||||
Row: {
|
||||
actualizado_en: string
|
||||
@@ -91,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
|
||||
@@ -115,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
|
||||
@@ -139,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
|
||||
@@ -176,6 +229,13 @@ export type Database = {
|
||||
referencedRelation: "estructuras_asignatura"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "asignaturas_estructura_id_fkey"
|
||||
columns: ["estructura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["estructura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "asignaturas_linea_plan_fk_compuesta"
|
||||
columns: ["linea_plan_id", "plan_estudio_id"]
|
||||
@@ -241,6 +301,13 @@ export type Database = {
|
||||
referencedRelation: "asignaturas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "bibliografia_asignatura_asignatura_id_fkey"
|
||||
columns: ["asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["asignatura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "bibliografia_asignatura_creado_por_fkey"
|
||||
columns: ["creado_por"]
|
||||
@@ -295,6 +362,13 @@ export type Database = {
|
||||
referencedRelation: "asignaturas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "cambios_asignatura_asignatura_id_fkey"
|
||||
columns: ["asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["asignatura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "cambios_asignatura_cambiado_por_fkey"
|
||||
columns: ["cambiado_por"]
|
||||
@@ -441,6 +515,13 @@ export type Database = {
|
||||
referencedRelation: "asignaturas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "conversaciones_asignatura_asignatura_id_fkey"
|
||||
columns: ["asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["asignatura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "conversaciones_asignatura_creado_por_fkey"
|
||||
columns: ["creado_por"]
|
||||
@@ -552,7 +633,8 @@ export type Database = {
|
||||
definicion: Json
|
||||
id: string
|
||||
nombre: string
|
||||
version: string | null
|
||||
template_id: string | null
|
||||
tipo: Database["public"]["Enums"]["tipo_estructura_plan"] | null
|
||||
}
|
||||
Insert: {
|
||||
actualizado_en?: string
|
||||
@@ -560,7 +642,8 @@ export type Database = {
|
||||
definicion?: Json
|
||||
id?: string
|
||||
nombre: string
|
||||
version?: string | null
|
||||
template_id?: string | null
|
||||
tipo?: Database["public"]["Enums"]["tipo_estructura_plan"] | null
|
||||
}
|
||||
Update: {
|
||||
actualizado_en?: string
|
||||
@@ -568,7 +651,8 @@ export type Database = {
|
||||
definicion?: Json
|
||||
id?: string
|
||||
nombre?: string
|
||||
version?: string | null
|
||||
template_id?: string | null
|
||||
tipo?: Database["public"]["Enums"]["tipo_estructura_plan"] | null
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
@@ -692,6 +776,13 @@ export type Database = {
|
||||
referencedRelation: "asignaturas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "interacciones_ia_asignatura_id_fkey"
|
||||
columns: ["asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["asignatura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "interacciones_ia_plan_estudio_id_fkey"
|
||||
columns: ["plan_estudio_id"]
|
||||
@@ -798,6 +889,56 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
plan_mensajes_ia: {
|
||||
Row: {
|
||||
campos: string[]
|
||||
conversacion_plan_id: string
|
||||
enviado_por: string
|
||||
estado: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion: string
|
||||
fecha_creacion: string
|
||||
id: string
|
||||
is_refusal: boolean
|
||||
mensaje: string
|
||||
propuesta: Json | null
|
||||
respuesta: string | null
|
||||
}
|
||||
Insert: {
|
||||
campos?: string[]
|
||||
conversacion_plan_id: string
|
||||
enviado_por?: string
|
||||
estado?: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion?: string
|
||||
fecha_creacion?: string
|
||||
id?: string
|
||||
is_refusal?: boolean
|
||||
mensaje: string
|
||||
propuesta?: Json | null
|
||||
respuesta?: string | null
|
||||
}
|
||||
Update: {
|
||||
campos?: string[]
|
||||
conversacion_plan_id?: string
|
||||
enviado_por?: string
|
||||
estado?: Database["public"]["Enums"]["estado_mensaje_ia"]
|
||||
fecha_actualizacion?: string
|
||||
fecha_creacion?: string
|
||||
id?: string
|
||||
is_refusal?: boolean
|
||||
mensaje?: string
|
||||
propuesta?: Json | null
|
||||
respuesta?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "plan_mensajes_ia_conversacion_plan_id_fkey"
|
||||
columns: ["conversacion_plan_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "conversaciones_plan"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
planes_estudio: {
|
||||
Row: {
|
||||
activo: boolean
|
||||
@@ -934,6 +1075,13 @@ export type Database = {
|
||||
referencedRelation: "asignaturas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "responsables_asignatura_asignatura_id_fkey"
|
||||
columns: ["asignatura_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "plantilla_asignatura"
|
||||
referencedColumns: ["asignatura_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "responsables_asignatura_usuario_id_fkey"
|
||||
columns: ["usuario_id"]
|
||||
@@ -1199,6 +1347,14 @@ export type Database = {
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
plantilla_asignatura: {
|
||||
Row: {
|
||||
asignatura_id: string | null
|
||||
estructura_id: string | null
|
||||
template_id: string | null
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
plantilla_plan: {
|
||||
Row: {
|
||||
estructura_id: string | null
|
||||
@@ -1221,13 +1377,9 @@ export type Database = {
|
||||
unaccent_immutable: { Args: { "": string }; Returns: string }
|
||||
}
|
||||
Enums: {
|
||||
estado_asignatura:
|
||||
| "borrador"
|
||||
| "revisada"
|
||||
| "aprobada"
|
||||
| "generando"
|
||||
| "fallida"
|
||||
estado_asignatura: "borrador" | "revisada" | "aprobada" | "generando"
|
||||
estado_conversacion: "ACTIVA" | "ARCHIVANDO" | "ARCHIVADA" | "ERROR"
|
||||
estado_mensaje_ia: "PROCESANDO" | "COMPLETADO" | "ERROR"
|
||||
estado_tarea_revision: "PENDIENTE" | "COMPLETADA" | "OMITIDA"
|
||||
fuente_cambio: "HUMANO" | "IA"
|
||||
nivel_plan_estudio:
|
||||
@@ -1400,14 +1552,9 @@ export const Constants = {
|
||||
},
|
||||
public: {
|
||||
Enums: {
|
||||
estado_asignatura: [
|
||||
"borrador",
|
||||
"revisada",
|
||||
"aprobada",
|
||||
"generando",
|
||||
"fallida",
|
||||
],
|
||||
estado_asignatura: ["borrador", "revisada", "aprobada", "generando"],
|
||||
estado_conversacion: ["ACTIVA", "ARCHIVANDO", "ARCHIVADA", "ERROR"],
|
||||
estado_mensaje_ia: ["PROCESANDO", "COMPLETADO", "ERROR"],
|
||||
estado_tarea_revision: ["PENDIENTE", "COMPLETADA", "OMITIDA"],
|
||||
fuente_cambio: ["HUMANO", "IA"],
|
||||
nivel_plan_estudio: [
|
||||
|
||||
@@ -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,
|
||||
@@ -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,3 @@
|
||||
# Configuration for private npm package dependencies
|
||||
# For more information on using private registries with Edge Functions, see:
|
||||
# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"imports": {
|
||||
"zod": "https://deno.land/x/zod@v3.22.4/mod.ts",
|
||||
"@supabase/functions-js": "jsr:@supabase/functions-js@^2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
import "@supabase/functions-js/edge-runtime.d.ts";
|
||||
import { z } from "zod";
|
||||
import { corsHeaders } from "../_shared/cors.ts";
|
||||
import { HttpError, sendError, sendSuccess } from "../_shared/utils.ts";
|
||||
|
||||
console.log("Starting buscar-bibliografia function");
|
||||
|
||||
type GoogleBooksVolume = Record<string, unknown>;
|
||||
|
||||
interface GoogleBooksVolumesListResponse {
|
||||
kind?: string;
|
||||
totalItems?: number;
|
||||
items?: GoogleBooksVolume[];
|
||||
}
|
||||
|
||||
const SearchTermsSchema = z
|
||||
.object({
|
||||
q: z.string().min(1, "q es requerido"),
|
||||
maxResults: z.number().int().min(0).max(40),
|
||||
orderBy: z.enum(["newest", "relevance"]).optional(),
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
const BodySchema = z
|
||||
.object({
|
||||
searchTerms: SearchTermsSchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
type BuscarBibliografiaRequest = z.infer<typeof BodySchema>;
|
||||
|
||||
function formatZodIssues(issues: z.ZodIssue[]): string {
|
||||
return issues
|
||||
.map((issue, i) => {
|
||||
const path = issue.path.length ? issue.path.join(".") : "(root)";
|
||||
return `${i + 1}. ${path}: ${issue.message}`;
|
||||
})
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function buildUrlWithSearchTerms(
|
||||
baseUrl: string,
|
||||
searchTerms: Record<string, unknown>,
|
||||
): string {
|
||||
const url = new URL(baseUrl);
|
||||
for (const [key, value] of Object.entries(searchTerms)) {
|
||||
if (value === undefined || value === null) continue;
|
||||
if (Array.isArray(value)) {
|
||||
for (const v of value) {
|
||||
if (v === undefined || v === null) continue;
|
||||
url.searchParams.append(key, String(v));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
url.searchParams.set(key, String(value));
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
Deno.serve(async (req: Request): Promise<Response> => {
|
||||
const url = new URL(req.url);
|
||||
const functionName = url.pathname.split("/").pop();
|
||||
console.log(
|
||||
`[${new Date().toISOString()}][${functionName}]: Request received`,
|
||||
);
|
||||
|
||||
if (req.method === "OPTIONS") {
|
||||
return new Response(null, { status: 204, headers: corsHeaders });
|
||||
}
|
||||
|
||||
try {
|
||||
if (req.method !== "POST") {
|
||||
throw new HttpError(405, "Método no permitido.", "METHOD_NOT_ALLOWED", {
|
||||
method: req.method,
|
||||
});
|
||||
}
|
||||
|
||||
const contentType = (req.headers.get("content-type") || "").toLowerCase();
|
||||
if (!contentType.includes("application/json")) {
|
||||
throw new HttpError(
|
||||
415,
|
||||
"Content-Type no soportado.",
|
||||
"UNSUPPORTED_MEDIA_TYPE",
|
||||
{ contentType, expected: "application/json" },
|
||||
);
|
||||
}
|
||||
|
||||
let rawBody: unknown;
|
||||
try {
|
||||
rawBody = await req.json();
|
||||
} catch (e) {
|
||||
throw new HttpError(400, "Body JSON inválido.", "INVALID_JSON", {
|
||||
cause: e,
|
||||
});
|
||||
}
|
||||
|
||||
const parsed = BodySchema.safeParse(rawBody);
|
||||
if (!parsed.success) {
|
||||
throw new HttpError(
|
||||
422,
|
||||
formatZodIssues(parsed.error.issues),
|
||||
"VALIDATION_ERROR",
|
||||
parsed.error,
|
||||
);
|
||||
}
|
||||
|
||||
const body: BuscarBibliografiaRequest = parsed.data;
|
||||
|
||||
const GOOGLE_API_KEY = Deno.env.get("GOOGLE_API_KEY");
|
||||
if (!GOOGLE_API_KEY) {
|
||||
throw new HttpError(
|
||||
500,
|
||||
"Configuración del servidor incompleta.",
|
||||
"MISSING_ENV",
|
||||
{ missing: ["GOOGLE_API_KEY"] },
|
||||
);
|
||||
}
|
||||
|
||||
const baseUrl = "https://www.googleapis.com/books/v1/volumes";
|
||||
const requestUrl = buildUrlWithSearchTerms(baseUrl, {
|
||||
...body.searchTerms,
|
||||
key: GOOGLE_API_KEY,
|
||||
});
|
||||
|
||||
const googleResp = await fetch(requestUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!googleResp.ok) {
|
||||
const text = await googleResp.text().catch(() => "");
|
||||
throw new HttpError(
|
||||
502,
|
||||
"Error al consultar Google Books.",
|
||||
"GOOGLE_BOOKS_REQUEST_FAILED",
|
||||
{
|
||||
status: googleResp.status,
|
||||
statusText: googleResp.statusText,
|
||||
body: text || null,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const data = (await googleResp.json()) as GoogleBooksVolumesListResponse;
|
||||
const items = Array.isArray(data?.items) ? data.items : [];
|
||||
|
||||
return sendSuccess(items);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
console.error(
|
||||
`[${new Date().toISOString()}][${functionName}] ⚠️ Handled Error:`,
|
||||
{
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
internalDetails: error.internalDetails || "N/A",
|
||||
},
|
||||
);
|
||||
return sendError(error.status, error.message, error.code);
|
||||
}
|
||||
|
||||
const unexpectedError = error instanceof Error
|
||||
? error
|
||||
: new Error(String(error));
|
||||
|
||||
console.error(
|
||||
`[${
|
||||
new Date().toISOString()
|
||||
}][${functionName}] 💥 CRITICAL UNHANDLED ERROR:`,
|
||||
unexpectedError.stack || unexpectedError.message,
|
||||
);
|
||||
|
||||
return sendError(
|
||||
500,
|
||||
"Ocurrió un error inesperado en el servidor.",
|
||||
"INTERNAL_SERVER_ERROR",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/* To invoke locally:
|
||||
|
||||
1. Run `supabase start` (see: https://supabase.com/docs/reference/cli/supabase-start)
|
||||
2. Make an HTTP request:
|
||||
|
||||
curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/buscar-bibliografia' \
|
||||
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{"name":"Functions"}'
|
||||
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."asignaturas" add column "criterios_de_evaluacion" jsonb not null default '[]'::jsonb;
|
||||
+108
-3
@@ -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";
|
||||
|
||||
+217
-26
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user