From d029fa23e7395b95b80de8aaaf641d4b95e2a92a Mon Sep 17 00:00:00 2001 From: Alejandro Rosales Date: Fri, 20 Feb 2026 11:53:50 -0600 Subject: [PATCH] =?UTF-8?q?Agregar=20notebook=20para=20integraci=C3=B3n=20?= =?UTF-8?q?con=20OpenAI=20y=20Supabase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notebooks/background-openai.ipynb | 398 ++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 notebooks/background-openai.ipynb diff --git a/notebooks/background-openai.ipynb b/notebooks/background-openai.ipynb new file mode 100644 index 0000000..83ded53 --- /dev/null +++ b/notebooks/background-openai.ipynb @@ -0,0 +1,398 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "bb61ec88", + "metadata": {}, + "outputs": [], + "source": [ + "import { load } from \"jsr:@std/dotenv\";\n", + "import OpenAI from \"jsr:@openai/openai\";\n", + "\n", + "const env = await load({\n", + " export: true,\n", + "});\n", + "\n", + "const openai = new OpenAI();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8baca5f2", + "metadata": {}, + "outputs": [], + "source": [ + "import { createClient } from \"@supabase/supabase-js\";\n", + "const supabaseUrl = Deno.env.get(\"SUPABASE_URL\") || env.SUPABASE_URL;\n", + "const supabaseKey = Deno.env.get(\"SUPABASE_ANON_KEY\") || env.SUPABASE_ANON_KEY;\n", + "const supabase = createClient(supabaseUrl, supabaseKey);" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "26b3bb36", + "metadata": {}, + "outputs": [], + "source": [ + "// plan Crear un plan en la base (sin datos) estado generando\n", + "const { data: plan, error } = await supabase.from(\"planes_estudio\").insert({\n", + " \"carrera_id\": \"8208da08-d549-4359-8865-9d806bc54f19\",\n", + " \"estructura_id\": \"69fb2b77-5a95-47e0-bf1f-389d384200e4\",\n", + " \"estado_actual_id\": \"18f49b67-8077-4371-be6e-2019a3be3562\",\n", + " \"nombre\": \"Ingeniearía en Cifbernética y Ciberseguridad (2025)\",\n", + " \"nivel\": \"Doctorado\",\n", + " \"tipo_ciclo\": \"Semestre\",\n", + " \"numero_ciclos\": 8,\n", + " \"activo\": true,\n", + " \"tipo_origen\": \"IA\",\n", + " \"creado_por\": \"11111111-1111-1111-1111-111111111111\",\n", + " \"actualizado_por\": \"11111111-1111-1111-1111-111111111111\",\n", + "}).select(\"*\").single();\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "8abb080e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[32m\"e39952c1-a53b-43bf-8033-feda493a0651\"\u001b[39m" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plan.id" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "a382bdc6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{\n", + " id: \u001b[32m\"resp_0f1906be7e83879e00699895d7f1cc8193a960e6ccdab1d377\"\u001b[39m,\n", + " object: \u001b[32m\"response\"\u001b[39m,\n", + " created_at: \u001b[33m1771607511\u001b[39m,\n", + " status: \u001b[32m\"queued\"\u001b[39m,\n", + " background: \u001b[33mtrue\u001b[39m,\n", + " completed_at: \u001b[1mnull\u001b[22m,\n", + " error: \u001b[1mnull\u001b[22m,\n", + " frequency_penalty: \u001b[33m0\u001b[39m,\n", + " incomplete_details: \u001b[1mnull\u001b[22m,\n", + " instructions: \u001b[1mnull\u001b[22m,\n", + " max_output_tokens: \u001b[1mnull\u001b[22m,\n", + " max_tool_calls: \u001b[1mnull\u001b[22m,\n", + " model: \u001b[32m\"gpt-5-mini-2025-08-07\"\u001b[39m,\n", + " output: [],\n", + " parallel_tool_calls: \u001b[33mtrue\u001b[39m,\n", + " presence_penalty: \u001b[33m0\u001b[39m,\n", + " previous_response_id: \u001b[1mnull\u001b[22m,\n", + " prompt_cache_key: \u001b[1mnull\u001b[22m,\n", + " prompt_cache_retention: \u001b[1mnull\u001b[22m,\n", + " reasoning: { effort: \u001b[32m\"medium\"\u001b[39m, summary: \u001b[1mnull\u001b[22m },\n", + " safety_identifier: \u001b[1mnull\u001b[22m,\n", + " service_tier: \u001b[32m\"auto\"\u001b[39m,\n", + " store: \u001b[33mtrue\u001b[39m,\n", + " temperature: \u001b[33m1\u001b[39m,\n", + " text: {\n", + " format: {\n", + " type: \u001b[32m\"json_schema\"\u001b[39m,\n", + " description: \u001b[1mnull\u001b[22m,\n", + " name: \u001b[32m\"response_schema\"\u001b[39m,\n", + " schema: {\n", + " type: \u001b[32m\"object\"\u001b[39m,\n", + " properties: { \u001b[32m\"ai-message\"\u001b[39m: \u001b[36m[Object]\u001b[39m, \u001b[32m\"suggested-topic\"\u001b[39m: \u001b[36m[Object]\u001b[39m },\n", + " required: [ \u001b[32m\"ai-message\"\u001b[39m, \u001b[32m\"suggested-topic\"\u001b[39m ],\n", + " additionalProperties: \u001b[33mfalse\u001b[39m\n", + " },\n", + " strict: \u001b[33mtrue\u001b[39m\n", + " },\n", + " verbosity: \u001b[32m\"medium\"\u001b[39m\n", + " },\n", + " tool_choice: \u001b[32m\"auto\"\u001b[39m,\n", + " tools: [],\n", + " top_logprobs: \u001b[33m0\u001b[39m,\n", + " top_p: \u001b[33m1\u001b[39m,\n", + " truncation: \u001b[32m\"disabled\"\u001b[39m,\n", + " usage: \u001b[1mnull\u001b[22m,\n", + " user: \u001b[1mnull\u001b[22m,\n", + " metadata: {\n", + " tabla: \u001b[32m\"planes_estudio\"\u001b[39m,\n", + " id: \u001b[32m\"e39952c1-a53b-43bf-8033-feda493a0651\"\u001b[39m\n", + " },\n", + " output_text: \u001b[32m\"\"\u001b[39m\n", + "}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "let response = await openai.responses.create({\n", + " model: \"gpt-5-mini\",\n", + " input: \"Hola mundo\",\n", + " metadata: {\n", + " tabla: \"planes_estudio\",\n", + " id: plan.id,\n", + " },\n", + " text: {\n", + " format: {\n", + " type: \"json_schema\",\n", + " name: \"response_schema\",\n", + " schema: {\n", + " type: \"object\",\n", + " properties: {\n", + " \"ai-message\": {\n", + " type: \"string\",\n", + " description:\n", + " \"Un mensaje de texto que la IA generará para el usuario final. Este mensaje debe ser claro y directo, proporcionando la información solicitada por el usuario o indicando que no se puede procesar la solicitud si no está relacionada con planes de estudio o asignaturas.\",\n", + " },\n", + " \"suggested-topic\": {\n", + " type: \"string\",\n", + " description:\n", + " \"Un tema de investigación sugerido por la IA que sea relevante para el plan de estudio o asignatura mencionada en la solicitud del usuario. Este tema debe ser específico y relacionado con el área de estudio correspondiente.\",\n", + " },\n", + " },\n", + " required: [\"ai-message\", \"suggested-topic\"],\n", + " additionalProperties: false,\n", + " },\n", + " },\n", + " },\n", + " background: true,\n", + "});\n", + "\n", + "response;\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "6b2470ed", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current status: queued\n", + "Current status: in_progress\n", + "Current status: in_progress\n" + ] + }, + { + "data": { + "text/plain": [ + "{\n", + " id: \u001b[32m\"resp_0f1906be7e83879e00699895d7f1cc8193a960e6ccdab1d377\"\u001b[39m,\n", + " object: \u001b[32m\"response\"\u001b[39m,\n", + " created_at: \u001b[33m1771607511\u001b[39m,\n", + " status: \u001b[32m\"completed\"\u001b[39m,\n", + " background: \u001b[33mtrue\u001b[39m,\n", + " billing: { payer: \u001b[32m\"developer\"\u001b[39m },\n", + " completed_at: \u001b[33m1771607519\u001b[39m,\n", + " error: \u001b[1mnull\u001b[22m,\n", + " frequency_penalty: \u001b[33m0\u001b[39m,\n", + " incomplete_details: \u001b[1mnull\u001b[22m,\n", + " instructions: \u001b[1mnull\u001b[22m,\n", + " max_output_tokens: \u001b[1mnull\u001b[22m,\n", + " max_tool_calls: \u001b[1mnull\u001b[22m,\n", + " model: \u001b[32m\"gpt-5-mini-2025-08-07\"\u001b[39m,\n", + " output: [\n", + " {\n", + " id: \u001b[32m\"rs_0f1906be7e83879e00699895d976548193ad40e9aae0b1b4f2\"\u001b[39m,\n", + " type: \u001b[32m\"reasoning\"\u001b[39m,\n", + " summary: []\n", + " },\n", + " {\n", + " id: \u001b[32m\"msg_0f1906be7e83879e00699895ddf62881938811097ba62e8724\"\u001b[39m,\n", + " type: \u001b[32m\"message\"\u001b[39m,\n", + " status: \u001b[32m\"completed\"\u001b[39m,\n", + " content: [\n", + " {\n", + " type: \u001b[32m\"output_text\"\u001b[39m,\n", + " annotations: [],\n", + " logprobs: [],\n", + " text: \u001b[32m'{\"ai-message\":\"¡Hola! ¿Cómo puedo ayudarte hoy? Si te refieres al clásico “Hola mundo” en programación, puedo mostrarte ejemplos en varios lenguajes, explicar su historia o ayudarte a crear tu primer programa. ¿Qué prefieres?\",\"suggested-topic\":\"El uso del programa “Hola mundo” como herramienta pedagógica en la enseñanza de la programación: impacto en la comprensión inicial, variaciones por lenguaje y mejores prácticas didácticas.\"}'\u001b[39m\n", + " }\n", + " ],\n", + " role: \u001b[32m\"assistant\"\u001b[39m\n", + " }\n", + " ],\n", + " parallel_tool_calls: \u001b[33mtrue\u001b[39m,\n", + " presence_penalty: \u001b[33m0\u001b[39m,\n", + " previous_response_id: \u001b[1mnull\u001b[22m,\n", + " prompt_cache_key: \u001b[1mnull\u001b[22m,\n", + " prompt_cache_retention: \u001b[1mnull\u001b[22m,\n", + " reasoning: { effort: \u001b[32m\"medium\"\u001b[39m, summary: \u001b[1mnull\u001b[22m },\n", + " safety_identifier: \u001b[1mnull\u001b[22m,\n", + " service_tier: \u001b[32m\"default\"\u001b[39m,\n", + " store: \u001b[33mtrue\u001b[39m,\n", + " temperature: \u001b[33m1\u001b[39m,\n", + " text: {\n", + " format: {\n", + " type: \u001b[32m\"json_schema\"\u001b[39m,\n", + " description: \u001b[1mnull\u001b[22m,\n", + " name: \u001b[32m\"response_schema\"\u001b[39m,\n", + " schema: {\n", + " type: \u001b[32m\"object\"\u001b[39m,\n", + " properties: { \u001b[32m\"ai-message\"\u001b[39m: \u001b[36m[Object]\u001b[39m, \u001b[32m\"suggested-topic\"\u001b[39m: \u001b[36m[Object]\u001b[39m },\n", + " required: [ \u001b[32m\"ai-message\"\u001b[39m, \u001b[32m\"suggested-topic\"\u001b[39m ],\n", + " additionalProperties: \u001b[33mfalse\u001b[39m\n", + " },\n", + " strict: \u001b[33mtrue\u001b[39m\n", + " },\n", + " verbosity: \u001b[32m\"medium\"\u001b[39m\n", + " },\n", + " tool_choice: \u001b[32m\"auto\"\u001b[39m,\n", + " tools: [],\n", + " top_logprobs: \u001b[33m0\u001b[39m,\n", + " top_p: \u001b[33m1\u001b[39m,\n", + " truncation: \u001b[32m\"disabled\"\u001b[39m,\n", + " usage: {\n", + " input_tokens: \u001b[33m167\u001b[39m,\n", + " input_tokens_details: { cached_tokens: \u001b[33m0\u001b[39m },\n", + " output_tokens: \u001b[33m437\u001b[39m,\n", + " output_tokens_details: { reasoning_tokens: \u001b[33m320\u001b[39m },\n", + " total_tokens: \u001b[33m604\u001b[39m\n", + " },\n", + " user: \u001b[1mnull\u001b[22m,\n", + " metadata: {\n", + " tabla: \u001b[32m\"planes_estudio\"\u001b[39m,\n", + " id: \u001b[32m\"e39952c1-a53b-43bf-8033-feda493a0651\"\u001b[39m\n", + " },\n", + " output_text: \u001b[32m'{\"ai-message\":\"¡Hola! ¿Cómo puedo ayudarte hoy? Si te refieres al clásico “Hola mundo” en programación, puedo mostrarte ejemplos en varios lenguajes, explicar su historia o ayudarte a crear tu primer programa. ¿Qué prefieres?\",\"suggested-topic\":\"El uso del programa “Hola mundo” como herramienta pedagógica en la enseñanza de la programación: impacto en la comprensión inicial, variaciones por lenguaje y mejores prácticas didácticas.\"}'\u001b[39m\n", + "}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "while (response.status === \"queued\" || response.status === \"in_progress\") {\n", + " console.log(\"Current status: \" + response.status);\n", + " await new Promise((resolve) => setTimeout(resolve, 2000)); // wait 2 seconds\n", + " response = await openai.responses.retrieve(response.id);\n", + "}\n", + "\n", + "response;" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "ebb67bd8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{ tabla: \u001b[32m\"planes_estudio\"\u001b[39m, id: \u001b[32m\"e39952c1-a53b-43bf-8033-feda493a0651\"\u001b[39m }" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "response.metadata" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "cd18fc2d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{\n", + " error: \u001b[1mnull\u001b[22m,\n", + " data: {\n", + " id: \u001b[32m\"e39952c1-a53b-43bf-8033-feda493a0651\"\u001b[39m,\n", + " carrera_id: \u001b[32m\"8208da08-d549-4359-8865-9d806bc54f19\"\u001b[39m,\n", + " estructura_id: \u001b[32m\"69fb2b77-5a95-47e0-bf1f-389d384200e4\"\u001b[39m,\n", + " nombre: \u001b[32m\"Ingeniearía en Cifbernética y Ciberseguridad (2025)\"\u001b[39m,\n", + " nivel: \u001b[32m\"Doctorado\"\u001b[39m,\n", + " tipo_ciclo: \u001b[32m\"Semestre\"\u001b[39m,\n", + " numero_ciclos: \u001b[33m8\u001b[39m,\n", + " datos: {\n", + " \u001b[32m\"ai-message\"\u001b[39m: \u001b[32m\"¡Hola! ¿Cómo puedo ayudarte hoy? Si te refieres al clásico “Hola mundo” en programación, puedo mostrarte ejemplos en varios lenguajes, explicar su historia o ayudarte a crear tu primer programa. ¿Qué prefieres?\"\u001b[39m,\n", + " \u001b[32m\"suggested-topic\"\u001b[39m: \u001b[32m\"El uso del programa “Hola mundo” como herramienta pedagógica en la enseñanza de la programación: impacto en la comprensión inicial, variaciones por lenguaje y mejores prácticas didácticas.\"\u001b[39m\n", + " },\n", + " estado_actual_id: \u001b[32m\"18f49b67-8077-4371-be6e-2019a3be3562\"\u001b[39m,\n", + " activo: \u001b[33mtrue\u001b[39m,\n", + " tipo_origen: \u001b[32m\"IA\"\u001b[39m,\n", + " meta_origen: {},\n", + " creado_por: \u001b[32m\"11111111-1111-1111-1111-111111111111\"\u001b[39m,\n", + " actualizado_por: \u001b[32m\"11111111-1111-1111-1111-111111111111\"\u001b[39m,\n", + " creado_en: \u001b[32m\"2026-02-20T17:11:28.995222+00:00\"\u001b[39m,\n", + " actualizado_en: \u001b[32m\"2026-02-20T17:12:40.170995+00:00\"\u001b[39m,\n", + " nombre_search: \u001b[32m\"ingeniearia en cifbernetica y ciberseguridad (2025)\"\u001b[39m,\n", + " plan_hash: \u001b[32m\"70d28457bbddfe4f5cde0574\"\u001b[39m\n", + " },\n", + " count: \u001b[1mnull\u001b[22m,\n", + " status: \u001b[33m200\u001b[39m,\n", + " statusText: \u001b[32m\"OK\"\u001b[39m\n", + "}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "await supabase.from(response.metadata.tabla).update({\n", + " datos: JSON.parse(response.output_text),\n", + "}).eq(\"id\", response.metadata.id).select(\"*\").single();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbbfd8c0", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Deno", + "language": "typescript", + "name": "deno" + }, + "language_info": { + "codemirror_mode": "typescript", + "file_extension": ".ts", + "mimetype": "text/x.typescript", + "name": "typescript", + "nbconvert_exporter": "script", + "pygments_lexer": "typescript", + "version": "5.9.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}