Versión funcional de creación de plan de estudios con IA

This commit is contained in:
2026-01-20 17:03:13 -06:00
parent 4a6ef4b09d
commit 63d6fefa96
7 changed files with 1763 additions and 269 deletions
+65 -49
View File
@@ -25,7 +25,9 @@ function mustEnv() {
if (!SUPABASE_ANON_KEY) throw new Error("SUPABASE_ANON_KEY is required");
}
async function getAuthedClient(): Promise<{ client: SupabaseClient; accessToken: string }> {
async function getAuthedClient(): Promise<
{ client: SupabaseClient; accessToken: string }
> {
mustEnv();
const client = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, options);
@@ -36,69 +38,83 @@ async function getAuthedClient(): Promise<{ client: SupabaseClient; accessToken:
if (error) throw new Error("Sign-in failed: " + error.message);
const accessToken = data.session?.access_token;
if (!accessToken) throw new Error("No access_token returned from signInWithPassword");
if (!accessToken) {
throw new Error("No access_token returned from signInWithPassword");
}
return { client, accessToken };
}
Deno.test("ai-structured (JSON body)", async () => {
const { client, accessToken } = await getAuthedClient();
Deno.test(
{ name: "ai-structured (JSON body) [DEPRECATED]", ignore: true },
async () => {
const { client, accessToken } = await getAuthedClient();
const { data, error } = await client.functions.invoke("ai-structured", {
headers: {
Authorization: `Bearer ${accessToken}`, // 👈 clave para que tu función pase el authHeader check
},
body: {
response: {
model: "gpt-5",
input: [
{ role: "system", content: "Responde SIEMPRE en JSON válido." },
{ role: "user", content: "Dame 3 ideas de proyecto de IA para educación." },
],
const { data, error } = await client.functions.invoke("ai-structured", {
headers: {
Authorization: `Bearer ${accessToken}`, // 👈 clave para que tu función pase el authHeader check
},
structured: {
type: "json_schema",
name: "ideas",
strict: true,
schema: {
type: "object",
properties: {
ideas: {
type: "array",
items: {
type: "object",
properties: {
titulo: { type: "string" },
descripcion: { type: "string" },
body: {
response: {
model: "gpt-5",
input: [
{ role: "system", content: "Responde SIEMPRE en JSON válido." },
{
role: "user",
content: "Dame 3 ideas de proyecto de IA para educación.",
},
],
},
structured: {
type: "json_schema",
name: "ideas",
strict: true,
schema: {
type: "object",
properties: {
ideas: {
type: "array",
items: {
type: "object",
properties: {
titulo: { type: "string" },
descripcion: { type: "string" },
},
required: ["titulo", "descripcion"],
additionalProperties: false,
},
required: ["titulo", "descripcion"],
additionalProperties: false,
},
},
required: ["ideas"],
additionalProperties: false,
},
required: ["ideas"],
additionalProperties: false,
},
references: {},
usarMCP: false,
},
references: {},
usarMCP: false,
},
});
});
if (error) throw new Error("Invoke failed: " + error.message);
assert(data, "Expected data from function");
if (error) throw new Error("Invoke failed: " + error.message);
assert(data, "Expected data from function");
// tu función responde { ok, output, outputText, ... }
assertEquals(data.ok, true);
assert(Array.isArray(data.output?.ideas), "output.ideas should be an array");
assertEquals(data.output.ideas.length, 3);
for (const it of data.output.ideas) {
assert(typeof it.titulo === "string");
assert(typeof it.descripcion === "string");
}
});
// tu función responde { ok, output, outputText, ... }
assertEquals(data.ok, true);
assert(
Array.isArray(data.output?.ideas),
"output.ideas should be an array",
);
assertEquals(data.output.ideas.length, 3);
for (const it of data.output.ideas) {
assert(typeof it.titulo === "string");
assert(typeof it.descripcion === "string");
}
},
);
Deno.test("ai-structured (multipart + file)", async () => {
Deno.test({
name: "ai-structured (multipart + file) [DEPRECATED]",
ignore: true,
}, async () => {
const { client, accessToken } = await getAuthedClient();
// Lee un PDF local (ajusta path)