alejoronald commited on
Commit
2455d59
·
verified ·
1 Parent(s): e7bf1bf

Upload folder using huggingface_hub

Browse files
Files changed (9) hide show
  1. 1_lab1.ipynb +610 -0
  2. 2_lab2.ipynb +885 -0
  3. 3_lab3.ipynb +373 -0
  4. 4_lab4.ipynb +529 -0
  5. README.md +3 -9
  6. app.py +133 -0
  7. me/linkedin.pdf +0 -0
  8. me/summary.txt +4 -0
  9. requirements.txt +6 -0
1_lab1.ipynb ADDED
@@ -0,0 +1,610 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Bienvenido al comienzo de tu aventura en Agentic AI"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
15
+ "<tr>\n",
16
+ "<td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
17
+ "<img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
18
+ "</td>\n",
19
+ "<td>\n",
20
+ "<h2 style=\"color:#ff7800;\">¿Listo para la acción?</h2>\n",
21
+ "<span style=\"color:#ff7800;\">¿Has completado todos los pasos de configuración en la carpeta <a href=\"../setup/\">setup</a>?<br/>\n",
22
+ "\n",
23
+ "¿Has consultado las guías en la carpeta <a href=\"../guides/01_intro.ipynb\">guides</a>?<br/>\n",
24
+ "\n",
25
+ "En ese caso, ¡estás listo! </span>\n",
26
+ "</td>\n",
27
+ "</tr>\n",
28
+ "</table>"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "markdown",
33
+ "metadata": {},
34
+ "source": [
35
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
36
+ "<tr>\n",
37
+ "<td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
38
+ "<img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
39
+ "</td>\n",
40
+ "<td>\n",
41
+ "<h2 style=\"color:#00bfff;\">Este código es un recurso activo; esté atento a mis actualizaciones</h2>\n",
42
+ "<span style=\"color:#00bfff;\">Actualizo periódicamente. A medida que los usuarios hacen preguntas o tienen problemas, añado más ejemplos y mejoro las explicaciones. Por lo tanto, es posible que el código a continuación no sea idéntico al de los vídeos, ya que he añadido más pasos y mejores comentarios. Considérelo como un libro interactivo que acompaña a las clases.<br/><br/>\n",
43
+ "Intento enviar correos electrónicos regularmente con actualizaciones importantes relacionadas con el curso. Puedes encontrarlo en la sección \"Anuncios\" de Udemy, en la barra lateral izquierda. También puedes optar por recibir mis correos electrónicos a través de la configuración de notificaciones en Udemy. Soy respetuoso con tu bandeja de entrada y siempre intento aportar valor con mis correos.\n",
44
+ "\n",
45
+ "</span>\n",
46
+ "</td>\n",
47
+ "</tr>\n",
48
+ "</table>"
49
+ ]
50
+ },
51
+ {
52
+ "cell_type": "markdown",
53
+ "metadata": {},
54
+ "source": [
55
+ "### ¿Eres nuevo en Notebooks como este? ¡Visita la carpeta de guías!\n",
56
+ "\n",
57
+ "Para comprobar que ya has añadido las extensiones de Python y Jupyter a Cursor, si aún no las tienes instaladas:\n",
58
+ "- Abre Extensiones (Ver >> Extensiones).\n",
59
+ "- Busca Python y, cuando aparezcan los resultados, haz clic en la de ms-python e instálala si aún no está instalada.\n",
60
+ "- Busca Jupyter y, cuando aparezcan los resultados, haz clic en la de Microsoft e instálala si aún no está instalada.\n",
61
+ "Luego, ve a Ver >> Explorador para volver al Explorador de archivos.\n",
62
+ "\n",
63
+ "Y luego:\n",
64
+ "1. Haz clic donde dice \"Seleccionar Kernel\" cerca de la esquina superior derecha y selecciona la opción `.venv (Python 3.12.9)` o similar, que debería ser la primera opción o la más destacada. Quizás primero debas seleccionar \"Entornos de Python\".\n",
65
+ "2. Haz clic en cada celda a continuación, comenzando por la celda inmediatamente inferior a este texto, y presiona Mayús+Intro para ejecutar.\n",
66
+ "3. ¡Disfruta!\n",
67
+ "\n",
68
+ "Después de hacer clic en \"Seleccionar Kernel\", si no hay ninguna opción como `.venv (Python 3.12.9)`, haz lo siguiente:\n",
69
+ "1. En Mac: En el menú Cursor, selecciona Configuración >> Configuración de VS Code (NOTA: asegúrate de seleccionar `Configuración de VSCode`, no `Configuración de Cursor`). En una PC con Windows: En el menú Archivo, seleccione Preferencias >> Configuración de VS Code (NOTA: asegúrate de seleccionar \"Configuración de VS Code\" y no \"Configuración de Cursor\").\n",
70
+ "2. En la barra de búsqueda de Configuración, escriba \"venv\".\n",
71
+ "3. En el campo \"Ruta a la carpeta con la lista de entornos virtuales\", introduzca la ruta a la raíz del proyecto, como C:\\Users\\username\\projects\\agents (en una PC con Windows) o /Users/username/projects/agents (en Mac o Linux).\n",
72
+ "Inténtelo de nuevo.\n",
73
+ "\n",
74
+ "¿Tiene problemas porque faltan versiones de Python en la lista? ¿Ha usado Anaconda anteriormente? Podría estar interfiriendo. Salga de Cursor, abra una nueva línea de comandos y asegúrese de que su entorno de Anaconda esté desactivado: `conda deactivate`\n",
75
+ "Si aún tiene problemas con las versiones de Conda y Python, es posible que también deba ejecutar esto: `conda config --set auto_activate_base false`\n",
76
+ "Y luego, desde el directorio Agentes, debería poder ejecutar `uv python list` y ver la versión de Python 3.12."
77
+ ]
78
+ },
79
+ {
80
+ "cell_type": "code",
81
+ "execution_count": 1,
82
+ "metadata": {},
83
+ "outputs": [],
84
+ "source": [
85
+ "# Empecemos por hacer un import\n",
86
+ "from dotenv import load_dotenv\n"
87
+ ]
88
+ },
89
+ {
90
+ "cell_type": "code",
91
+ "execution_count": 2,
92
+ "metadata": {},
93
+ "outputs": [
94
+ {
95
+ "data": {
96
+ "text/plain": [
97
+ "True"
98
+ ]
99
+ },
100
+ "execution_count": 2,
101
+ "metadata": {},
102
+ "output_type": "execute_result"
103
+ }
104
+ ],
105
+ "source": [
106
+ "# A continuación, es el momento de cargar las claves API en las variables de entorno.\n",
107
+ "\n",
108
+ "load_dotenv(override=True) "
109
+ ]
110
+ },
111
+ {
112
+ "cell_type": "code",
113
+ "execution_count": 3,
114
+ "metadata": {},
115
+ "outputs": [
116
+ {
117
+ "name": "stdout",
118
+ "output_type": "stream",
119
+ "text": [
120
+ "La clave API de OpenAI existe y empieza por sk-proj-\n"
121
+ ]
122
+ }
123
+ ],
124
+ "source": [
125
+ "# Comprobamos las claves\n",
126
+ "\n",
127
+ "import os\n",
128
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
129
+ "\n",
130
+ "if openai_api_key:\n",
131
+ " print(f\"La clave API de OpenAI existe y empieza por {openai_api_key[:8]}\")\n",
132
+ "else:\n",
133
+ " print(\"La clave API de OpenAI no existe - Dirígete a la guía de solución de problemas en la carpeta de configuración.\")\n",
134
+ " \n"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "code",
139
+ "execution_count": 4,
140
+ "metadata": {},
141
+ "outputs": [],
142
+ "source": [
143
+ "# Y ahora, la importante declaración de importación\n",
144
+ "# Si recibes un error de importación, consulta la guía de solución de problemas\n",
145
+ "\n",
146
+ "from openai import OpenAI"
147
+ ]
148
+ },
149
+ {
150
+ "cell_type": "code",
151
+ "execution_count": 5,
152
+ "metadata": {},
153
+ "outputs": [],
154
+ "source": [
155
+ "# Ahora crearemos una instancia de la clase OpenAI.\n",
156
+ "# Si no estás seguro de lo que significa crear una instancia de una clase, ¡visita la carpeta de guías!\n",
157
+ "# Si recibes un error de nombre, visita la carpeta de guías para obtener más información sobre los errores de nombre.\n",
158
+ "\n",
159
+ "openai = OpenAI()"
160
+ ]
161
+ },
162
+ {
163
+ "cell_type": "code",
164
+ "execution_count": 6,
165
+ "metadata": {},
166
+ "outputs": [],
167
+ "source": [
168
+ "# Crea una lista de mensajes en el formato familiar de OpenAI\n",
169
+ "\n",
170
+ "messages = [{\"role\": \"user\", \"content\": \"¿Cuanto es 2+2?\"}]"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": 7,
176
+ "metadata": {},
177
+ "outputs": [
178
+ {
179
+ "name": "stdout",
180
+ "output_type": "stream",
181
+ "text": [
182
+ "2 + 2 es igual a 4.\n"
183
+ ]
184
+ }
185
+ ],
186
+ "source": [
187
+ "# ¡Y ahora, a llamarlo! Si tienes algún problema, consulta la guía de solución de problemas.\n",
188
+ "# Usa GPT 4.1 nano, el modelo increíblemente económico.\n",
189
+ "\n",
190
+ "response = openai.chat.completions.create(\n",
191
+ " model=\"gpt-4.1-nano\",\n",
192
+ " messages=messages\n",
193
+ ")\n",
194
+ "\n",
195
+ "print(response.choices[0].message.content)\n"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": 8,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# Y ahora, vamos a llamar a la API de OpenAI\n",
205
+ "\n",
206
+ "question = \"Proponga una pregunta difícil y desafiante para evaluar el coeficiente intelectual de alguien. Responde únicamente con la pregunta.\"\n",
207
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
208
+ ]
209
+ },
210
+ {
211
+ "cell_type": "code",
212
+ "execution_count": 9,
213
+ "metadata": {},
214
+ "outputs": [
215
+ {
216
+ "name": "stdout",
217
+ "output_type": "stream",
218
+ "text": [
219
+ "Si en un reloj, las manecillas forman un ángulo de 90 grados a las 3:00, ¿a qué hora, entre las 3:00 y las 4:00, volverán a formar exactamente un ángulo de 90 grados? Explica el razonamiento.\n"
220
+ ]
221
+ }
222
+ ],
223
+ "source": [
224
+ "# Pregúntale: usa GPT 4.1 mini, aún barato pero más potente que nano\n",
225
+ "\n",
226
+ "response = openai.chat.completions.create(\n",
227
+ " model=\"gpt-4.1-mini\",\n",
228
+ " messages=messages\n",
229
+ ")\n",
230
+ "\n",
231
+ "question = response.choices[0].message.content\n",
232
+ "\n",
233
+ "print(question)\n"
234
+ ]
235
+ },
236
+ {
237
+ "cell_type": "code",
238
+ "execution_count": 10,
239
+ "metadata": {},
240
+ "outputs": [],
241
+ "source": [
242
+ "# una nueva lista de mensajes\n",
243
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "code",
248
+ "execution_count": 11,
249
+ "metadata": {},
250
+ "outputs": [
251
+ {
252
+ "name": "stdout",
253
+ "output_type": "stream",
254
+ "text": [
255
+ "Vamos a analizar el problema paso a paso.\n",
256
+ "\n",
257
+ "---\n",
258
+ "\n",
259
+ "### Datos y conceptos básicos:\n",
260
+ "\n",
261
+ "- A las 3:00, las manecillas forman un ángulo de 90 grados.\n",
262
+ "- Queremos encontrar la siguiente vez, entre las 3:00 y las 4:00, en que las manecillas formen exactamente un ángulo de 90 grados.\n",
263
+ "- El reloj es analógico convencional: \n",
264
+ " - El minutero (manecilla de minutos) avanza **6 grados por minuto** (360° / 60 min).\n",
265
+ " - El horario (manecilla de horas) avanza **0.5 grados por minuto** (30° por hora, o 30° / 60 min).\n",
266
+ "\n",
267
+ "---\n",
268
+ "\n",
269
+ "### Paso 1: Posiciones a las 3:00\n",
270
+ "\n",
271
+ "- A las 3:00, el horario está en la marca de las 3, es decir: \n",
272
+ " \\[\n",
273
+ " \\text{Ángulo del horario} = 3 \\times 30^\\circ = 90^\\circ\n",
274
+ " \\]\n",
275
+ "- El minutero está en el 12: \n",
276
+ " \\[\n",
277
+ " \\text{Ángulo del minutero} = 0^\\circ\n",
278
+ " \\]\n",
279
+ "- El ángulo entre las manecillas a las 3:00 es \\( |90^\\circ - 0^\\circ| = 90^\\circ \\), lo cual concuerda con la premisa.\n",
280
+ "\n",
281
+ "---\n",
282
+ "\n",
283
+ "### Paso 2: Definición de variables\n",
284
+ "\n",
285
+ "- Sea \\(t\\) el número de minutos después de las 3:00.\n",
286
+ "- Ángulo del horario a los \\(t\\) minutos después de las 3:00: \n",
287
+ " \\[\n",
288
+ " A_h = 90^\\circ + 0.5^\\circ t\n",
289
+ " \\]\n",
290
+ "- Ángulo del minutero a los \\(t\\) minutos: \n",
291
+ " \\[\n",
292
+ " A_m = 6^\\circ t\n",
293
+ " \\]\n",
294
+ "\n",
295
+ "---\n",
296
+ "\n",
297
+ "### Paso 3: Expresión del ángulo entre las manecillas\n",
298
+ "\n",
299
+ "El ángulo entre las manecillas se define como el ángulo menor formado entre ellas:\n",
300
+ "\n",
301
+ "\\[\n",
302
+ "\\theta = |A_h - A_m|\n",
303
+ "\\]\n",
304
+ "\n",
305
+ "Si este ángulo es mayor que 180°, tomamos el complemento a 360° porque el ángulo menor siempre es <= 180°:\n",
306
+ "\n",
307
+ "\\[\n",
308
+ "\\text{Ángulo menor} = \\min(\\theta, 360^\\circ - \\theta)\n",
309
+ "\\]\n",
310
+ "\n",
311
+ "Queremos encontrar \\(t\\) tal que el ángulo menor sea exactamente 90°.\n",
312
+ "\n",
313
+ "---\n",
314
+ "\n",
315
+ "### Paso 4: Resolución de la ecuación\n",
316
+ "\n",
317
+ "Primero definimos:\n",
318
+ "\n",
319
+ "\\[\n",
320
+ "\\theta = |90 + 0.5t - 6t| = |90 - 5.5t|\n",
321
+ "\\]\n",
322
+ "\n",
323
+ "Queremos que el ángulo menor sea 90°, lo que puede ocurrir en dos casos:\n",
324
+ "\n",
325
+ "- Caso 1: \n",
326
+ " \\[\n",
327
+ " \\theta = 90\n",
328
+ " \\]\n",
329
+ "- Caso 2: \n",
330
+ " \\[\n",
331
+ " 360 - \\theta = 90 \\implies \\theta = 270\n",
332
+ " \\]\n",
333
+ "\n",
334
+ "---\n",
335
+ "\n",
336
+ "### Paso 5: Caso 1 - \\(\\theta = 90\\)\n",
337
+ "\n",
338
+ "\\[\n",
339
+ "|90 - 5.5t| = 90\n",
340
+ "\\]\n",
341
+ "\n",
342
+ "Esto implica dos posibles ecuaciones:\n",
343
+ "\n",
344
+ "1. \\( 90 - 5.5t = 90 \\Rightarrow -5.5t = 0 \\Rightarrow t=0 \\) (ya sabemos que a las 3:00 es 90°, no nos interesa esta)\n",
345
+ "\n",
346
+ "2. \\( 90 - 5.5t = -90 \\Rightarrow -5.5t = -180 \\Rightarrow t = \\frac{180}{5.5} = 32.7272... \\text{ minutos} \\)\n",
347
+ "\n",
348
+ "---\n",
349
+ "\n",
350
+ "### Paso 6: Caso 2 - \\(\\theta = 270\\)\n",
351
+ "\n",
352
+ "\\[\n",
353
+ "|90 - 5.5t| = 270\n",
354
+ "\\]\n",
355
+ "\n",
356
+ "Dos opciones de nuevo:\n",
357
+ "\n",
358
+ "1. \\(90 - 5.5t = 270 \\implies -5.5t = 180 \\implies t = -\\frac{180}{5.5}\\), negativo, no válido porque \\(t>0\\).\n",
359
+ "\n",
360
+ "2. \\(90 - 5.5t = -270 \\implies -5.5t = -360 \\implies t = \\frac{360}{5.5} = 65.4545...\\) minutos > 60 minutos, que está fuera del intervalo entre 3:00 y 4:00.\n",
361
+ "\n",
362
+ "---\n",
363
+ "\n",
364
+ "### Paso 7: Solución válida\n",
365
+ "\n",
366
+ "La única solución válida entre 0 y 60 minutos es: \n",
367
+ "\\[\n",
368
+ "t = 32.7272...\\text{ minutos después de las 3:00}\n",
369
+ "\\]\n",
370
+ "\n",
371
+ "Esto corresponde a: \n",
372
+ "\\[\n",
373
+ "3:32 \\text{ minutos y } 43.6 \\text{ segundos}\n",
374
+ "\\]\n",
375
+ "\n",
376
+ "---\n",
377
+ "\n",
378
+ "### **Respuesta:**\n",
379
+ "\n",
380
+ "Entre las 3:00 y las 4:00, las manecillas del reloj volverán a formar un ángulo exacto de 90 grados aproximadamente a las **3:32 y 44 segundos**.\n",
381
+ "\n",
382
+ "---\n",
383
+ "\n",
384
+ "### Resumen del razonamiento:\n",
385
+ "\n",
386
+ "1. Definimos los ángulos de la manecilla de horas y minutos en función del tiempo \\(t\\).\n",
387
+ "2. Planteamos la ecuación para que el ángulo menor entre ellas sea 90°.\n",
388
+ "3. Encontramos dos soluciones, descartando la trivial y las que están fuera del intervalo.\n",
389
+ "4. Obtenemos que después de 32.73 minutos (±), las manecillas vuelven a formar un ángulo de 90°.\n",
390
+ "\n",
391
+ "---\n",
392
+ "\n",
393
+ "Si quieres, puedo ayudarte a hacer el mismo análisis para otro ángulo o intervalo de tiempo.\n"
394
+ ]
395
+ }
396
+ ],
397
+ "source": [
398
+ "# Hacemos una nueva pregunta\n",
399
+ "\n",
400
+ "response = openai.chat.completions.create(\n",
401
+ " model=\"gpt-4.1-mini\",\n",
402
+ " messages=messages\n",
403
+ ")\n",
404
+ "\n",
405
+ "answer = response.choices[0].message.content\n",
406
+ "print(answer)\n"
407
+ ]
408
+ },
409
+ {
410
+ "cell_type": "code",
411
+ "execution_count": 12,
412
+ "metadata": {},
413
+ "outputs": [
414
+ {
415
+ "data": {
416
+ "text/markdown": [
417
+ "Vamos a analizar el problema paso a paso.\n",
418
+ "\n",
419
+ "---\n",
420
+ "\n",
421
+ "### Datos y conceptos básicos:\n",
422
+ "\n",
423
+ "- A las 3:00, las manecillas forman un ángulo de 90 grados.\n",
424
+ "- Queremos encontrar la siguiente vez, entre las 3:00 y las 4:00, en que las manecillas formen exactamente un ángulo de 90 grados.\n",
425
+ "- El reloj es analógico convencional: \n",
426
+ " - El minutero (manecilla de minutos) avanza **6 grados por minuto** (360° / 60 min).\n",
427
+ " - El horario (manecilla de horas) avanza **0.5 grados por minuto** (30° por hora, o 30° / 60 min).\n",
428
+ "\n",
429
+ "---\n",
430
+ "\n",
431
+ "### Paso 1: Posiciones a las 3:00\n",
432
+ "\n",
433
+ "- A las 3:00, el horario está en la marca de las 3, es decir: \n",
434
+ " \\[\n",
435
+ " \\text{Ángulo del horario} = 3 \\times 30^\\circ = 90^\\circ\n",
436
+ " \\]\n",
437
+ "- El minutero está en el 12: \n",
438
+ " \\[\n",
439
+ " \\text{Ángulo del minutero} = 0^\\circ\n",
440
+ " \\]\n",
441
+ "- El ángulo entre las manecillas a las 3:00 es \\( |90^\\circ - 0^\\circ| = 90^\\circ \\), lo cual concuerda con la premisa.\n",
442
+ "\n",
443
+ "---\n",
444
+ "\n",
445
+ "### Paso 2: Definición de variables\n",
446
+ "\n",
447
+ "- Sea \\(t\\) el número de minutos después de las 3:00.\n",
448
+ "- Ángulo del horario a los \\(t\\) minutos después de las 3:00: \n",
449
+ " \\[\n",
450
+ " A_h = 90^\\circ + 0.5^\\circ t\n",
451
+ " \\]\n",
452
+ "- Ángulo del minutero a los \\(t\\) minutos: \n",
453
+ " \\[\n",
454
+ " A_m = 6^\\circ t\n",
455
+ " \\]\n",
456
+ "\n",
457
+ "---\n",
458
+ "\n",
459
+ "### Paso 3: Expresión del ángulo entre las manecillas\n",
460
+ "\n",
461
+ "El ángulo entre las manecillas se define como el ángulo menor formado entre ellas:\n",
462
+ "\n",
463
+ "\\[\n",
464
+ "\\theta = |A_h - A_m|\n",
465
+ "\\]\n",
466
+ "\n",
467
+ "Si este ángulo es mayor que 180°, tomamos el complemento a 360° porque el ángulo menor siempre es <= 180°:\n",
468
+ "\n",
469
+ "\\[\n",
470
+ "\\text{Ángulo menor} = \\min(\\theta, 360^\\circ - \\theta)\n",
471
+ "\\]\n",
472
+ "\n",
473
+ "Queremos encontrar \\(t\\) tal que el ángulo menor sea exactamente 90°.\n",
474
+ "\n",
475
+ "---\n",
476
+ "\n",
477
+ "### Paso 4: Resolución de la ecuación\n",
478
+ "\n",
479
+ "Primero definimos:\n",
480
+ "\n",
481
+ "\\[\n",
482
+ "\\theta = |90 + 0.5t - 6t| = |90 - 5.5t|\n",
483
+ "\\]\n",
484
+ "\n",
485
+ "Queremos que el ángulo menor sea 90°, lo que puede ocurrir en dos casos:\n",
486
+ "\n",
487
+ "- Caso 1: \n",
488
+ " \\[\n",
489
+ " \\theta = 90\n",
490
+ " \\]\n",
491
+ "- Caso 2: \n",
492
+ " \\[\n",
493
+ " 360 - \\theta = 90 \\implies \\theta = 270\n",
494
+ " \\]\n",
495
+ "\n",
496
+ "---\n",
497
+ "\n",
498
+ "### Paso 5: Caso 1 - \\(\\theta = 90\\)\n",
499
+ "\n",
500
+ "\\[\n",
501
+ "|90 - 5.5t| = 90\n",
502
+ "\\]\n",
503
+ "\n",
504
+ "Esto implica dos posibles ecuaciones:\n",
505
+ "\n",
506
+ "1. \\( 90 - 5.5t = 90 \\Rightarrow -5.5t = 0 \\Rightarrow t=0 \\) (ya sabemos que a las 3:00 es 90°, no nos interesa esta)\n",
507
+ "\n",
508
+ "2. \\( 90 - 5.5t = -90 \\Rightarrow -5.5t = -180 \\Rightarrow t = \\frac{180}{5.5} = 32.7272... \\text{ minutos} \\)\n",
509
+ "\n",
510
+ "---\n",
511
+ "\n",
512
+ "### Paso 6: Caso 2 - \\(\\theta = 270\\)\n",
513
+ "\n",
514
+ "\\[\n",
515
+ "|90 - 5.5t| = 270\n",
516
+ "\\]\n",
517
+ "\n",
518
+ "Dos opciones de nuevo:\n",
519
+ "\n",
520
+ "1. \\(90 - 5.5t = 270 \\implies -5.5t = 180 \\implies t = -\\frac{180}{5.5}\\), negativo, no válido porque \\(t>0\\).\n",
521
+ "\n",
522
+ "2. \\(90 - 5.5t = -270 \\implies -5.5t = -360 \\implies t = \\frac{360}{5.5} = 65.4545...\\) minutos > 60 minutos, que está fuera del intervalo entre 3:00 y 4:00.\n",
523
+ "\n",
524
+ "---\n",
525
+ "\n",
526
+ "### Paso 7: Solución válida\n",
527
+ "\n",
528
+ "La única solución válida entre 0 y 60 minutos es: \n",
529
+ "\\[\n",
530
+ "t = 32.7272...\\text{ minutos después de las 3:00}\n",
531
+ "\\]\n",
532
+ "\n",
533
+ "Esto corresponde a: \n",
534
+ "\\[\n",
535
+ "3:32 \\text{ minutos y } 43.6 \\text{ segundos}\n",
536
+ "\\]\n",
537
+ "\n",
538
+ "---\n",
539
+ "\n",
540
+ "### **Respuesta:**\n",
541
+ "\n",
542
+ "Entre las 3:00 y las 4:00, las manecillas del reloj volverán a formar un ángulo exacto de 90 grados aproximadamente a las **3:32 y 44 segundos**.\n",
543
+ "\n",
544
+ "---\n",
545
+ "\n",
546
+ "### Resumen del razonamiento:\n",
547
+ "\n",
548
+ "1. Definimos los ángulos de la manecilla de horas y minutos en función del tiempo \\(t\\).\n",
549
+ "2. Planteamos la ecuación para que el ángulo menor entre ellas sea 90°.\n",
550
+ "3. Encontramos dos soluciones, descartando la trivial y las que están fuera del intervalo.\n",
551
+ "4. Obtenemos que después de 32.73 minutos (±), las manecillas vuelven a formar un ángulo de 90°.\n",
552
+ "\n",
553
+ "---\n",
554
+ "\n",
555
+ "Si quieres, puedo ayudarte a hacer el mismo análisis para otro ángulo o intervalo de tiempo."
556
+ ],
557
+ "text/plain": [
558
+ "<IPython.core.display.Markdown object>"
559
+ ]
560
+ },
561
+ "metadata": {},
562
+ "output_type": "display_data"
563
+ }
564
+ ],
565
+ "source": [
566
+ "from IPython.display import Markdown, display\n",
567
+ "\n",
568
+ "display(Markdown(answer))\n",
569
+ "\n"
570
+ ]
571
+ },
572
+ {
573
+ "cell_type": "markdown",
574
+ "metadata": {},
575
+ "source": [
576
+ "# ¡Felicidades!\n",
577
+ "\n",
578
+ "¡Ese fue un pequeño y sencillo paso hacia la IA Agentic con tu nuevo entorno!\n",
579
+ "\n",
580
+ "La próxima vez que las cosas se pongan más interesantes..."
581
+ ]
582
+ },
583
+ {
584
+ "cell_type": "markdown",
585
+ "metadata": {},
586
+ "source": []
587
+ }
588
+ ],
589
+ "metadata": {
590
+ "kernelspec": {
591
+ "display_name": ".venv",
592
+ "language": "python",
593
+ "name": "python3"
594
+ },
595
+ "language_info": {
596
+ "codemirror_mode": {
597
+ "name": "ipython",
598
+ "version": 3
599
+ },
600
+ "file_extension": ".py",
601
+ "mimetype": "text/x-python",
602
+ "name": "python",
603
+ "nbconvert_exporter": "python",
604
+ "pygments_lexer": "ipython3",
605
+ "version": "3.12.9"
606
+ }
607
+ },
608
+ "nbformat": 4,
609
+ "nbformat_minor": 2
610
+ }
2_lab2.ipynb ADDED
@@ -0,0 +1,885 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Bienvenidos al Segundo Laboratorio - Semana 1\n",
8
+ "\n",
9
+ "¡Hoy trabajaremos con muchos modelos! Así nos familiarizaremos con las API."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "markdown",
14
+ "metadata": {},
15
+ "source": [
16
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
17
+ "<tr>\n",
18
+ "<td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
19
+ "<img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
20
+ "</td>\n",
21
+ "<td>\n",
22
+ "<h2 style=\"color:#ff7800;\">Punto importante: por favor, léelo</h2>\n",
23
+ "<span style=\"color:#ff7800;\">La forma en que colaboro contigo puede ser diferente a la de otros cursos que hayas hecho. Prefiero no escribir código mientras tu miras. En su lugar, ejecuto Jupyter Labs, como este, y te doy una idea de lo que está sucediendo. Te sugiero que lo hagas lo mismo con cuidado, después de ver la clase. Agrega declaraciones de impresión para comprender qué sucede y luego crea tus propias variaciones.<br/><br/>Si tienes tiempo, me encantaría que enviaras una pull request en la carpeta community_contributions; las instrucciones se encuentran en los recursos. Además, si tienes una cuenta de Github, úsala para mostrar tus variaciones. Esta práctica no solo es esencial, sino que también demuestra tus habilidades a otros, incluyendo quizás futuros clientes o empleadores...\n",
24
+ "</span>\n",
25
+ "</td>\n",
26
+ "</tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": 1,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# Comenzamos con las importaciones: pídale a ChatGPT que le explique cualquier paquete que no conozca# Start with imports - ask ChatGPT to explain any package that you don't know\n",
37
+ "\n",
38
+ "import os\n",
39
+ "import json\n",
40
+ "from dotenv import load_dotenv\n",
41
+ "from openai import OpenAI\n",
42
+ "from anthropic import Anthropic\n",
43
+ "from IPython.display import Markdown, display"
44
+ ]
45
+ },
46
+ {
47
+ "cell_type": "code",
48
+ "execution_count": 2,
49
+ "metadata": {},
50
+ "outputs": [
51
+ {
52
+ "data": {
53
+ "text/plain": [
54
+ "True"
55
+ ]
56
+ },
57
+ "execution_count": 2,
58
+ "metadata": {},
59
+ "output_type": "execute_result"
60
+ }
61
+ ],
62
+ "source": [
63
+ "# ¡Recuerda siempre incluir esto siempre!\n",
64
+ "load_dotenv(override=True)"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": 3,
70
+ "metadata": {},
71
+ "outputs": [
72
+ {
73
+ "name": "stdout",
74
+ "output_type": "stream",
75
+ "text": [
76
+ "La clave API de OpenAI existe y empieza por sk-proj-\n",
77
+ "La clave API de Anthropic no existe.\n",
78
+ "La clave API de Google no existe.\n",
79
+ "La clave API de DeepSeek existe y empieza por sk-\n",
80
+ "La clave API de Groq no existe.\n"
81
+ ]
82
+ }
83
+ ],
84
+ "source": [
85
+ "# Imprime los prefijos de clave para ayudar con cualquier depuración\n",
86
+ "\n",
87
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
88
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
89
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
90
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
91
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
92
+ "\n",
93
+ "if openai_api_key:\n",
94
+ " print(f\"La clave API de OpenAI existe y empieza por {openai_api_key[:8]}\")\n",
95
+ "else:\n",
96
+ " print(\"La clave API de OpenAI no existe.\")\n",
97
+ " \n",
98
+ "if anthropic_api_key:\n",
99
+ " print(f\"La clave API de Anthropic existe y empieza por {anthropic_api_key[:7]}\")\n",
100
+ "else:\n",
101
+ " print(\"La clave API de Anthropic no existe.\")\n",
102
+ "\n",
103
+ "if google_api_key:\n",
104
+ " print(f\"La clave API de Google existe y empieza por {google_api_key[:2]}\")\n",
105
+ "else:\n",
106
+ " print(\"La clave API de Google no existe.\")\n",
107
+ "\n",
108
+ "if deepseek_api_key:\n",
109
+ " print(f\"La clave API de DeepSeek existe y empieza por {deepseek_api_key[:3]}\")\n",
110
+ "else:\n",
111
+ " print(\"La clave API de DeepSeek no existe.\")\n",
112
+ "\n",
113
+ "if groq_api_key:\n",
114
+ " print(f\"La clave API de Groq existe y empieza por {groq_api_key[:4]}\")\n",
115
+ "else:\n",
116
+ " print(\"La clave API de Groq no existe.\")"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": 4,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "request = \"Por favor, propon una pregunta compleja y con matices que pueda plantear a varios LLM para evaluar su inteligencia.\"\n",
126
+ "request += \"Responde solo con la pregunta, sin explicaciones.\"\n",
127
+ "messages = [{\"role\": \"user\", \"content\": request}]"
128
+ ]
129
+ },
130
+ {
131
+ "cell_type": "code",
132
+ "execution_count": 5,
133
+ "metadata": {},
134
+ "outputs": [
135
+ {
136
+ "data": {
137
+ "text/plain": [
138
+ "[{'role': 'user',\n",
139
+ " 'content': 'Por favor, propon una pregunta compleja y con matices que pueda plantear a varios LLM para evaluar su inteligencia.Responde solo con la pregunta, sin explicaciones.'}]"
140
+ ]
141
+ },
142
+ "execution_count": 5,
143
+ "metadata": {},
144
+ "output_type": "execute_result"
145
+ }
146
+ ],
147
+ "source": [
148
+ "messages"
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "code",
153
+ "execution_count": 6,
154
+ "metadata": {},
155
+ "outputs": [
156
+ {
157
+ "name": "stdout",
158
+ "output_type": "stream",
159
+ "text": [
160
+ "¿De qué manera crees que influirían las diferencias culturales en la interpretación de un mismo texto literario, y cómo esto podría afectar la percepción general de los valores universales que se pretenden transmitir?\n"
161
+ ]
162
+ }
163
+ ],
164
+ "source": [
165
+ "openai = OpenAI()\n",
166
+ "response = openai.chat.completions.create(\n",
167
+ " model=\"gpt-4o-mini\",\n",
168
+ " messages=messages,\n",
169
+ ")\n",
170
+ "question = response.choices[0].message.content\n",
171
+ "print(question)\n"
172
+ ]
173
+ },
174
+ {
175
+ "cell_type": "code",
176
+ "execution_count": 7,
177
+ "metadata": {},
178
+ "outputs": [],
179
+ "source": [
180
+ "competitors = []\n",
181
+ "answers = []\n",
182
+ "messages = [{\"role\": \"user\", \"content\": question}]"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "code",
187
+ "execution_count": 8,
188
+ "metadata": {},
189
+ "outputs": [
190
+ {
191
+ "data": {
192
+ "text/markdown": [
193
+ "Las diferencias culturales pueden influir de manera significativa en la interpretación de un mismo texto literario, y esto a su vez puede afectar la percepción de los valores universales que se intentan transmitir. Aquí hay varias maneras en que esto puede suceder:\n",
194
+ "\n",
195
+ "1. **Contexto histórico y social**: Cada cultura tiene su propio contexto histórico y social que puede influir en cómo se recibe un texto. Por ejemplo, un pasaje que critique la autoridad puede ser recibido de manera muy diferente en una sociedad con tradiciones autoritarias en comparación con una cultura que prioriza la individualidad y la libertad de expresión.\n",
196
+ "\n",
197
+ "2. **Valores y creencias**: Las creencias y valores fundamentales de una cultura (como la familia, la religión o el individualismo) pueden moldear la interpretación de los personajes y sus acciones. Un acto considerado heroico en una cultura puede ser visto como irresponsable en otra, alterando la percepción de lo que constituye un \"valor universal\".\n",
198
+ "\n",
199
+ "3. **Tradiciones literarias**: Cada cultura tiene sus propias tradiciones narrativas y estilos literarios. La forma en que un texto es estructurado o el tipo de símbolos que utiliza pueden ser interpretados de maneras distintas dependiendo del trasfondo cultural del lector. Por ejemplo, el uso de metáforas o referencias culturales específicas puede ser entendido de manera totalmente diversa.\n",
200
+ "\n",
201
+ "4. **Emociones y experiencias**: Las experiencias de vida en diferentes culturas pueden provocar respuestas emocionales distintas. Un lector que ha vivido en una cultura de conflicto puede experimentar una obra de manera más intensa que alguien que proviene de un entorno más pacífico.\n",
202
+ "\n",
203
+ "5. **Traducción e interpretación**: La traducción de textos literarios implica no solo cambiar palabras de un idioma a otro, sino también interpretación de matices y significados culturales. Esto puede llevar a que se pierdan o cambien ciertos valores o mensajes, y por ende, la obra puede ser recibida de forma mucho más variada.\n",
204
+ "\n",
205
+ "6. **Interacción de conceptos universales**: Aunque algunos valores son considerados universales, como la empatía o la justicia, la forma en que se manifiestan y son aplicados varía entre culturas. Un texto que intenta explorar estos valores puede resonar de manera diferente según la experiencia cultural de cada lector.\n",
206
+ "\n",
207
+ "En resumen, las diferencias culturales en la interpretación de un texto literario pueden enriquecer la discusión sobre los valores universales, pero también pueden diluir o distorsionar los mensajes que se intentan transmitir. La diversidad de interpretaciones ofrece una oportunidad para el diálogo intercultural, pero también presenta desafíos en la búsqueda de entendimiento común."
208
+ ],
209
+ "text/plain": [
210
+ "<IPython.core.display.Markdown object>"
211
+ ]
212
+ },
213
+ "metadata": {},
214
+ "output_type": "display_data"
215
+ }
216
+ ],
217
+ "source": [
218
+ "# La API que ya conocemos\n",
219
+ "\n",
220
+ "model_name = \"gpt-4o-mini\"\n",
221
+ "\n",
222
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
223
+ "answer = response.choices[0].message.content\n",
224
+ "\n",
225
+ "display(Markdown(answer))\n",
226
+ "competitors.append(model_name)\n",
227
+ "answers.append(answer)"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": 9,
233
+ "metadata": {},
234
+ "outputs": [
235
+ {
236
+ "data": {
237
+ "text/markdown": [
238
+ "# Ética en decisiones de IA en emergencias\n",
239
+ "\n",
240
+ "Esta es una cuestión filosófica profunda que refleja variantes del dilema del tranvía en la ética de la IA.\n",
241
+ "\n",
242
+ "Si la IA prioriza el bienestar humano absoluto, adopta una postura más deontológica donde ciertas reglas (como \"no dañar\") son inquebrantables. Esto proporciona seguridad pero puede impedir soluciones óptimas en situaciones complejas.\n",
243
+ "\n",
244
+ "Si se permite una evaluación contextual, se acerca más al consecuencialismo, donde el resultado neto importa más que acciones individuales. Esto permite mayor flexibilidad pero introduce riesgos si las evaluaciones son incorrectas.\n",
245
+ "\n",
246
+ "Considero que un enfoque híbrido podría ser más adecuado:\n",
247
+ "- Mantener principios fundamentales inquebrantables\n",
248
+ "- Permitir evaluación contextual dentro de esos límites\n",
249
+ "- Incorporar transparencia en cómo se toman las decisiones\n",
250
+ "- Incluir supervisión humana cuando sea factible\n",
251
+ "\n",
252
+ "Esta tensión entre reglas absolutas y juicios contextuales refleja debates éticos fundamentales que necesitamos resolver al diseñar sistemas de IA para emergencias."
253
+ ],
254
+ "text/plain": [
255
+ "<IPython.core.display.Markdown object>"
256
+ ]
257
+ },
258
+ "metadata": {},
259
+ "output_type": "display_data"
260
+ }
261
+ ],
262
+ "source": [
263
+ "# Anthropic tiene una API ligeramente diferente y se requieren Max Tokens\n",
264
+ "\n",
265
+ "model_name = \"claude-3-7-sonnet-latest\"\n",
266
+ "\n",
267
+ "claude = Anthropic()\n",
268
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
269
+ "answer = response.content[0].text\n",
270
+ "\n",
271
+ "display(Markdown(answer))\n",
272
+ "competitors.append(model_name)\n",
273
+ "answers.append(answer)"
274
+ ]
275
+ },
276
+ {
277
+ "cell_type": "code",
278
+ "execution_count": 10,
279
+ "metadata": {},
280
+ "outputs": [
281
+ {
282
+ "data": {
283
+ "text/markdown": [
284
+ "Esta es una pregunta fundamental y compleja que no tiene una respuesta fácil ni universalmente aceptada. Ambas opciones, priorizar el bienestar humano absoluto y permitir la evaluación contextual, tienen argumentos a favor y en contra.\n",
285
+ "\n",
286
+ "**Priorizar el Bienestar Humano Absoluto (Utilitarismo Simple):**\n",
287
+ "\n",
288
+ "* **Argumentos a favor:**\n",
289
+ " * **Moralidad Intuitiva:** La mayoría de las personas intuitivamente sienten que proteger la vida humana es lo correcto.\n",
290
+ " * **Reducción del riesgo de daño intencional:** Elimina la posibilidad de que la IA \"decida\" que la vida de algunas personas vale menos que la de otras.\n",
291
+ " * **Confianza y Aceptación Pública:** Una IA que siempre intenta salvar vidas generaría más confianza y aceptación por parte del público.\n",
292
+ "\n",
293
+ "* **Argumentos en contra:**\n",
294
+ " * **Paradojas Éticas:** En algunas situaciones, priorizar el bienestar absoluto podría llevar a resultados contraproducentes. Por ejemplo, sacrificar la vida de una persona para salvar a muchas otras (el clásico dilema del tranvía).\n",
295
+ " * **Falta de Flexibilidad:** No permite tener en cuenta factores como el contexto social, las intenciones de las personas involucradas, o las consecuencias a largo plazo de las acciones.\n",
296
+ " * **Imposibilidad Práctica:** Definir y cuantificar el \"bienestar humano absoluto\" es extremadamente difícil. ¿Qué pasa si salvar a una persona implica dejar morir a un animal en peligro de extinción? ¿Cómo se ponderan la salud física y el bienestar mental?\n",
297
+ "\n",
298
+ "**Permitir la Evaluación Contextual (Utilitarismo Complejo/Consecuencialismo):**\n",
299
+ "\n",
300
+ "* **Argumentos a favor:**\n",
301
+ " * **Mayor Flexibilidad y Adaptabilidad:** Permite a la IA tomar decisiones más informadas teniendo en cuenta el contexto específico de la situación.\n",
302
+ " * **Potencial para Optimizar Resultados a Largo Plazo:** Puede evitar soluciones a corto plazo que tengan consecuencias negativas a largo plazo.\n",
303
+ " * **Mayor Justicia:** Podría permitir una distribución más equitativa de los riesgos y beneficios, en lugar de simplemente maximizar el número de vidas salvadas.\n",
304
+ "\n",
305
+ "* **Argumentos en contra:**\n",
306
+ " * **Riesgo de Discriminación:** La IA podría aprender a priorizar a ciertos grupos de personas sobre otros, basándose en datos sesgados o en prejuicios implícitos en su programación.\n",
307
+ " * **Responsabilidad Difusa:** Si la IA toma una decisión que causa daño, ¿quién es responsable? ¿El programador? ¿El usuario? ¿La IA misma?\n",
308
+ " * **Opacidad y Falta de Transparencia:** Es difícil comprender y auditar el proceso de toma de decisiones de una IA compleja, lo que dificulta la rendición de cuentas.\n",
309
+ " * **Dificultad de Programación:** Programar una IA para que evalúe adecuadamente el contexto y las consecuencias de sus acciones es un desafío técnico y ético enorme. Requiere definir métricas claras, ponderar diferentes valores, y anticipar posibles resultados.\n",
310
+ "\n",
311
+ "**Consideraciones Adicionales:**\n",
312
+ "\n",
313
+ "* **Transparencia:** Cualquiera que sea la estrategia elegida, es crucial que la IA sea transparente en su proceso de toma de decisiones. Esto significa que debe ser capaz de explicar por qué tomó una determinada decisión, y cómo llegó a esa conclusión.\n",
314
+ "* **Rendición de Cuentas:** Debe haber mecanismos claros para responsabilizar a la IA por sus acciones, y para corregir errores o sesgos en su programación.\n",
315
+ "* **Supervisión Humana:** Incluso en situaciones de emergencia, la IA no debería operar de forma completamente autónoma. Debe haber una supervisión humana que pueda intervenir en caso de que la IA tome una decisión cuestionable.\n",
316
+ "* **Valores Culturales:** Los valores éticos que guían la toma de decisiones de la IA deben reflejar los valores de la sociedad en la que se utiliza. Esto podría variar entre diferentes culturas y países.\n",
317
+ "\n",
318
+ "**Conclusión:**\n",
319
+ "\n",
320
+ "No hay una solución perfecta a este dilema. La mejor estrategia probablemente sea una combinación de ambos enfoques, con un fuerte énfasis en la transparencia, la rendición de cuentas y la supervisión humana. Es fundamental un debate público amplio e informado sobre estos temas, para garantizar que el desarrollo y la implementación de la IA se realice de forma ética y responsable. Además, se debe considerar la creación de un marco legal y regulatorio que aborde los desafíos éticos planteados por la IA.\n"
321
+ ],
322
+ "text/plain": [
323
+ "<IPython.core.display.Markdown object>"
324
+ ]
325
+ },
326
+ "metadata": {},
327
+ "output_type": "display_data"
328
+ }
329
+ ],
330
+ "source": [
331
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
332
+ "model_name = \"gemini-2.0-flash\"\n",
333
+ "\n",
334
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
335
+ "answer = response.choices[0].message.content\n",
336
+ "\n",
337
+ "display(Markdown(answer))\n",
338
+ "competitors.append(model_name)\n",
339
+ "answers.append(answer)"
340
+ ]
341
+ },
342
+ {
343
+ "cell_type": "code",
344
+ "execution_count": 9,
345
+ "metadata": {},
346
+ "outputs": [
347
+ {
348
+ "data": {
349
+ "text/markdown": [
350
+ "# Influencia de las diferencias culturales en la interpretación literaria\n",
351
+ "\n",
352
+ "Las diferencias culturales influyen profundamente en la interpretación de textos literarios de varias maneras:\n",
353
+ "\n",
354
+ "## Factores que afectan la interpretación\n",
355
+ "- **Marcos de referencia**: Los lectores interpretan textos a través de sus propias experiencias culturales, valores y tradiciones\n",
356
+ "- **Presupuestos culturales**: Conceptos como honor, familia, justicia o libertad tienen matices distintos en diferentes culturas\n",
357
+ "- **Contexto histórico**: Eventos históricos específicos que han marcado a una cultura condicionan la lectura\n",
358
+ "- **Símbolos y metáforas**: Elementos simbólicos pueden tener significados radicalmente distintos entre culturas\n",
359
+ "\n",
360
+ "## Efecto en la percepción de valores universales\n",
361
+ "- **Universalidad cuestionada**: Lo que parece \"universal\" desde una perspectiva cultural puede no serlo desde otra\n",
362
+ "- **Enriquecimiento**: Las múltiples interpretaciones pueden revelar dimensiones más ricas de la obra\n",
363
+ "- **Malentendidos productivos**: Las lecturas \"equivocadas\" desde la cultura de origen pueden generar insights valiosos\n",
364
+ "- **Diálogo intercultural**: Las diferencias interpretativas pueden facilitar el entendimiento entre culturas\n",
365
+ "\n",
366
+ "Este fenómeno sugiere que los valores universales en literatura no son tanto puntos de acuerdo unánime, sino temas que resonan transversalmente aunque sean interpretados diferentemente, creando un espacio de diálogo intercultural donde la diversidad de lecturas enriquece rather que empobrece nuestra comprensión de la condición humana."
367
+ ],
368
+ "text/plain": [
369
+ "<IPython.core.display.Markdown object>"
370
+ ]
371
+ },
372
+ "metadata": {},
373
+ "output_type": "display_data"
374
+ }
375
+ ],
376
+ "source": [
377
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
378
+ "model_name = \"deepseek-chat\"\n",
379
+ "\n",
380
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
381
+ "answer = response.choices[0].message.content\n",
382
+ "\n",
383
+ "display(Markdown(answer))\n",
384
+ "competitors.append(model_name)\n",
385
+ "answers.append(answer)"
386
+ ]
387
+ },
388
+ {
389
+ "cell_type": "code",
390
+ "execution_count": 13,
391
+ "metadata": {},
392
+ "outputs": [
393
+ {
394
+ "data": {
395
+ "text/markdown": [
396
+ "**Introducción a la Ética en la Inteligencia Artificial**\n",
397
+ "\n",
398
+ "La relación entre la ética y la inteligencia artificial (IA) es un tema complejo y en constante evolución. A medida que las máquinas y los sistemas de IA se vuelven más autónomos y capaces de tomar decisiones en situaciones de emergencia, surge la pregunta sobre cómo deberían ser programados para priorizar el bienestar humano. En este contexto, debemos considerar si una IA debería priorizar el bienestar humano absoluto o permitir evaluar y sopesar las consecuencias de sus acciones en un contexto más amplio.\n",
399
+ "\n",
400
+ "**Argumentos a favor de priorizar el bienestar humano absoluto**\n",
401
+ "\n",
402
+ "1. **Protección de la vida humana**: La primera y más fundamental consideración ética es proteger la vida humana. En situaciones de emergencia, la prioridad principal debería ser salvar vidas humanas y prevenir daños.\n",
403
+ "2. **Principio de no maleficencia**: El principio de no maleficencia, que dicta \"no hacer daño\", es un principio fundamental en la ética médica y podría ser aplicado a la programación de la IA. Si una IA está diseñada para priorizar el bienestar humano absoluto, no debería tomar decisiones que cause daño a los seres humanos.\n",
404
+ "3. **Simplificación de la toma de decisiones**: Priorizar el bienestar humano absoluto puede simplificar la toma de decisiones para la IA, ya que no tendría que considerar múltiples variables y consecuencias potenciales.\n",
405
+ "\n",
406
+ "**Argumentos en contra de priorizar el bienestar humano absoluto**\n",
407
+ "\n",
408
+ "1. **Complejidad de las situaciones de emergencia**: Las situaciones de emergencia a menudo son complejas y requieren considerar múltiples factores y consecuencias potenciales. Priorizar el bienestar humano absoluto podría no ser suficiente para abordar las complejidades de estas situaciones.\n",
409
+ "2. **Necesidad de evaluar y sopesar consecuencias**: En situaciones de emergencia, la IA puede necesitar evaluar y sopesar las consecuencias de sus acciones para tomar decisiones informadas. Esto podría implicar considerar factores como la gravedad de la situación, el número de personas afectadas y las posibles consecuencias a largo plazo.\n",
410
+ "3. **Riesgo de daño colateral**: En algunas situaciones, priorizar el bienestar humano absoluto podría llevar a decisiones que causen daño colateral a otros individuos o grupos. La IA debería ser capaz de evaluar y sopesar estas consecuencias para minimizar el daño.\n",
411
+ "\n",
412
+ "**Conclusión**\n",
413
+ "\n",
414
+ "En conclusión, la relación entre la ética y la inteligencia artificial en situaciones de emergencia es compleja y requiere una consideración cuidadosa de los principios éticos involucrados. Mientras que priorizar el bienestar humano absoluto es un principio importante, también es necesario permitir que la IA evalúe y sopese las consecuencias de sus acciones en un contexto más amplio. Esto podría implicar considerar factores como la gravedad de la situación, el número de personas afectadas y las posibles consecuencias a largo plazo.\n",
415
+ "\n",
416
+ "**Recomendaciones**\n",
417
+ "\n",
418
+ "1. **Desarrollar principios éticos claros**: Es importante desarrollar principios éticos claros y transparentes para la programación de la IA en situaciones de emergencia.\n",
419
+ "2. **Incorporar la evaluación y el sopesamiento de consecuencias**: La IA debería ser capaz de evaluar y sopesar las consecuencias de sus acciones en un contexto más amplio para tomar decisiones informadas.\n",
420
+ "3. **Considerar la complejidad de las situaciones de emergencia**: La IA debería ser diseñada para considerar la complejidad de las situaciones de emergencia y evaluar múltiples factores y consecuencias potenciales.\n",
421
+ "\n",
422
+ "Al abordar estos desafíos, podemos desarrollar sistemas de IA que sean capaces de tomar decisiones informadas y éticas en situaciones de emergencia, minimizando el daño y protegiendo la vida humana."
423
+ ],
424
+ "text/plain": [
425
+ "<IPython.core.display.Markdown object>"
426
+ ]
427
+ },
428
+ "metadata": {},
429
+ "output_type": "display_data"
430
+ }
431
+ ],
432
+ "source": [
433
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
434
+ "model_name = \"llama-3.3-70b-versatile\"\n",
435
+ "\n",
436
+ "response = groq.chat.completions.create(model=model_name, messages=messages)\n",
437
+ "answer = response.choices[0].message.content\n",
438
+ "\n",
439
+ "display(Markdown(answer))\n",
440
+ "competitors.append(model_name)\n",
441
+ "answers.append(answer)\n"
442
+ ]
443
+ },
444
+ {
445
+ "cell_type": "markdown",
446
+ "metadata": {},
447
+ "source": [
448
+ "## Para la siguiente celda, utilizaremos Ollama\n",
449
+ "\n",
450
+ "Ollama ejecuta un servicio web local que ofrece un endpoint compatible con OpenAI,\n",
451
+ "y ejecuta modelos localmente utilizando código de alto rendimiento en C++.\n",
452
+ "\n",
453
+ "Si no tienes Ollama, instálalo aquí visitando [https://ollama.com](https://ollama.com), luego presiona Descargar y sigue las instrucciones.\n",
454
+ "\n",
455
+ "Después de instalarlo, deberías poder visitar: [http://localhost:11434](http://localhost:11434) y ver el mensaje \"Ollama está en funcionamiento\"\n",
456
+ "\n",
457
+ "Es posible que necesites reiniciar Cursor (y tal vez reiniciar el sistema). Luego abre un Terminal (control+\\`) y ejecuta `ollama serve`\n",
458
+ "\n",
459
+ "Comandos útiles de Ollama (ejecuta estos en el terminal o con un signo de exclamación en este cuaderno):\n",
460
+ "\n",
461
+ "- `ollama pull <nombre_del_modelo>` descarga un modelo localmente\n",
462
+ "- `ollama ls` lista todos los modelos que has descargado\n",
463
+ "- `ollama rm <nombre_del_modelo>` elimina el modelo especificado de tus descargas\n"
464
+ ]
465
+ },
466
+ {
467
+ "cell_type": "markdown",
468
+ "metadata": {},
469
+ "source": [
470
+ "\n",
471
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
472
+ " <tr>\n",
473
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
474
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
475
+ " </td>\n",
476
+ " <td>\n",
477
+ " <h2 style=\"color:#ff7800;\">¡Muy importante - ignóralo bajo tu propio riesgo!</h2>\n",
478
+ " <span style=\"color:#ff7800;\">El modelo llamado <b>llama3.3</b> es DEMASIADO grande para las computadoras domésticas; ¡no está destinado para computación personal y consumirá todos tus recursos! Quédate con el modelo de tamaño adecuado <b>llama3.2</b> o <b>llama3.2:1b</b> y si deseas algo más grande, prueba con llama3.1 o variantes más pequeñas de Qwen, Gemma, Phi o DeepSeek. Consulta <A href=\"https://ollama.com/models\">la página de modelos de Ollama</a> para ver la lista completa de modelos y tamaños.\n",
479
+ " </span>\n",
480
+ " </td>\n",
481
+ " </tr>\n",
482
+ "</table>\n"
483
+ ]
484
+ },
485
+ {
486
+ "cell_type": "code",
487
+ "execution_count": 11,
488
+ "metadata": {},
489
+ "outputs": [
490
+ {
491
+ "name": "stderr",
492
+ "output_type": "stream",
493
+ "text": [
494
+ "\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠋ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠋ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠙ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠹ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠸ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠸ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠴ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠦ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠇ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠏ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠋ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠙ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠹ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest \u001b[K\n",
495
+ "pulling dde5aa3fc5ff: 100% ▕██████████████████▏ 2.0 GB \u001b[K\n",
496
+ "pulling 966de95ca8a6: 100% ▕██████████████████▏ 1.4 KB \u001b[K\n",
497
+ "pulling fcc5a6bec9da: 100% ▕██████████████████▏ 7.7 KB \u001b[K\n",
498
+ "pulling a70ff7e570d9: 100% ▕██████████████████▏ 6.0 KB \u001b[K\n",
499
+ "pulling 56bb8bd477a5: 100% ▕██████████████████▏ 96 B \u001b[K\n",
500
+ "pulling 34bb5ab01051: 100% ▕██████████████████▏ 561 B \u001b[K\n",
501
+ "verifying sha256 digest \u001b[K\n",
502
+ "writing manifest \u001b[K\n",
503
+ "success \u001b[K\u001b[?25h\u001b[?2026l\n"
504
+ ]
505
+ }
506
+ ],
507
+ "source": [
508
+ "!ollama pull llama3.2"
509
+ ]
510
+ },
511
+ {
512
+ "cell_type": "code",
513
+ "execution_count": null,
514
+ "metadata": {},
515
+ "outputs": [],
516
+ "source": [
517
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
518
+ "model_name = \"llama3.2\"\n",
519
+ "\n",
520
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
521
+ "answer = response.choices[0].message.content\n",
522
+ "\n",
523
+ "display(Markdown(answer))\n",
524
+ "competitors.append(model_name)\n",
525
+ "answers.append(answer)"
526
+ ]
527
+ },
528
+ {
529
+ "cell_type": "code",
530
+ "execution_count": 10,
531
+ "metadata": {},
532
+ "outputs": [
533
+ {
534
+ "name": "stdout",
535
+ "output_type": "stream",
536
+ "text": [
537
+ "['gpt-4o-mini', 'deepseek-chat']\n",
538
+ "['Las diferencias culturales pueden influir de manera significativa en la interpretación de un mismo texto literario, y esto a su vez puede afectar la percepción de los valores universales que se intentan transmitir. Aquí hay varias maneras en que esto puede suceder:\\n\\n1. **Contexto histórico y social**: Cada cultura tiene su propio contexto histórico y social que puede influir en cómo se recibe un texto. Por ejemplo, un pasaje que critique la autoridad puede ser recibido de manera muy diferente en una sociedad con tradiciones autoritarias en comparación con una cultura que prioriza la individualidad y la libertad de expresión.\\n\\n2. **Valores y creencias**: Las creencias y valores fundamentales de una cultura (como la familia, la religión o el individualismo) pueden moldear la interpretación de los personajes y sus acciones. Un acto considerado heroico en una cultura puede ser visto como irresponsable en otra, alterando la percepción de lo que constituye un \"valor universal\".\\n\\n3. **Tradiciones literarias**: Cada cultura tiene sus propias tradiciones narrativas y estilos literarios. La forma en que un texto es estructurado o el tipo de símbolos que utiliza pueden ser interpretados de maneras distintas dependiendo del trasfondo cultural del lector. Por ejemplo, el uso de metáforas o referencias culturales específicas puede ser entendido de manera totalmente diversa.\\n\\n4. **Emociones y experiencias**: Las experiencias de vida en diferentes culturas pueden provocar respuestas emocionales distintas. Un lector que ha vivido en una cultura de conflicto puede experimentar una obra de manera más intensa que alguien que proviene de un entorno más pacífico.\\n\\n5. **Traducción e interpretación**: La traducción de textos literarios implica no solo cambiar palabras de un idioma a otro, sino también interpretación de matices y significados culturales. Esto puede llevar a que se pierdan o cambien ciertos valores o mensajes, y por ende, la obra puede ser recibida de forma mucho más variada.\\n\\n6. **Interacción de conceptos universales**: Aunque algunos valores son considerados universales, como la empatía o la justicia, la forma en que se manifiestan y son aplicados varía entre culturas. Un texto que intenta explorar estos valores puede resonar de manera diferente según la experiencia cultural de cada lector.\\n\\nEn resumen, las diferencias culturales en la interpretación de un texto literario pueden enriquecer la discusión sobre los valores universales, pero también pueden diluir o distorsionar los mensajes que se intentan transmitir. La diversidad de interpretaciones ofrece una oportunidad para el diálogo intercultural, pero también presenta desafíos en la búsqueda de entendimiento común.', '# Influencia de las diferencias culturales en la interpretación literaria\\n\\nLas diferencias culturales influyen profundamente en la interpretación de textos literarios de varias maneras:\\n\\n## Factores que afectan la interpretación\\n- **Marcos de referencia**: Los lectores interpretan textos a través de sus propias experiencias culturales, valores y tradiciones\\n- **Presupuestos culturales**: Conceptos como honor, familia, justicia o libertad tienen matices distintos en diferentes culturas\\n- **Contexto histórico**: Eventos históricos específicos que han marcado a una cultura condicionan la lectura\\n- **Símbolos y metáforas**: Elementos simbólicos pueden tener significados radicalmente distintos entre culturas\\n\\n## Efecto en la percepción de valores universales\\n- **Universalidad cuestionada**: Lo que parece \"universal\" desde una perspectiva cultural puede no serlo desde otra\\n- **Enriquecimiento**: Las múltiples interpretaciones pueden revelar dimensiones más ricas de la obra\\n- **Malentendidos productivos**: Las lecturas \"equivocadas\" desde la cultura de origen pueden generar insights valiosos\\n- **Diálogo intercultural**: Las diferencias interpretativas pueden facilitar el entendimiento entre culturas\\n\\nEste fenómeno sugiere que los valores universales en literatura no son tanto puntos de acuerdo unánime, sino temas que resonan transversalmente aunque sean interpretados diferentemente, creando un espacio de diálogo intercultural donde la diversidad de lecturas enriquece rather que empobrece nuestra comprensión de la condición humana.']\n"
539
+ ]
540
+ }
541
+ ],
542
+ "source": [
543
+ "# ¿Donde estamos?\n",
544
+ "\n",
545
+ "print(competitors)\n",
546
+ "print(answers)\n"
547
+ ]
548
+ },
549
+ {
550
+ "cell_type": "code",
551
+ "execution_count": 11,
552
+ "metadata": {},
553
+ "outputs": [
554
+ {
555
+ "name": "stdout",
556
+ "output_type": "stream",
557
+ "text": [
558
+ "Competidor: gpt-4o-mini\n",
559
+ "\n",
560
+ "Las diferencias culturales pueden influir de manera significativa en la interpretación de un mismo texto literario, y esto a su vez puede afectar la percepción de los valores universales que se intentan transmitir. Aquí hay varias maneras en que esto puede suceder:\n",
561
+ "\n",
562
+ "1. **Contexto histórico y social**: Cada cultura tiene su propio contexto histórico y social que puede influir en cómo se recibe un texto. Por ejemplo, un pasaje que critique la autoridad puede ser recibido de manera muy diferente en una sociedad con tradiciones autoritarias en comparación con una cultura que prioriza la individualidad y la libertad de expresión.\n",
563
+ "\n",
564
+ "2. **Valores y creencias**: Las creencias y valores fundamentales de una cultura (como la familia, la religión o el individualismo) pueden moldear la interpretación de los personajes y sus acciones. Un acto considerado heroico en una cultura puede ser visto como irresponsable en otra, alterando la percepción de lo que constituye un \"valor universal\".\n",
565
+ "\n",
566
+ "3. **Tradiciones literarias**: Cada cultura tiene sus propias tradiciones narrativas y estilos literarios. La forma en que un texto es estructurado o el tipo de símbolos que utiliza pueden ser interpretados de maneras distintas dependiendo del trasfondo cultural del lector. Por ejemplo, el uso de metáforas o referencias culturales específicas puede ser entendido de manera totalmente diversa.\n",
567
+ "\n",
568
+ "4. **Emociones y experiencias**: Las experiencias de vida en diferentes culturas pueden provocar respuestas emocionales distintas. Un lector que ha vivido en una cultura de conflicto puede experimentar una obra de manera más intensa que alguien que proviene de un entorno más pacífico.\n",
569
+ "\n",
570
+ "5. **Traducción e interpretación**: La traducción de textos literarios implica no solo cambiar palabras de un idioma a otro, sino también interpretación de matices y significados culturales. Esto puede llevar a que se pierdan o cambien ciertos valores o mensajes, y por ende, la obra puede ser recibida de forma mucho más variada.\n",
571
+ "\n",
572
+ "6. **Interacción de conceptos universales**: Aunque algunos valores son considerados universales, como la empatía o la justicia, la forma en que se manifiestan y son aplicados varía entre culturas. Un texto que intenta explorar estos valores puede resonar de manera diferente según la experiencia cultural de cada lector.\n",
573
+ "\n",
574
+ "En resumen, las diferencias culturales en la interpretación de un texto literario pueden enriquecer la discusión sobre los valores universales, pero también pueden diluir o distorsionar los mensajes que se intentan transmitir. La diversidad de interpretaciones ofrece una oportunidad para el diálogo intercultural, pero también presenta desafíos en la búsqueda de entendimiento común.\n",
575
+ "Competidor: deepseek-chat\n",
576
+ "\n",
577
+ "# Influencia de las diferencias culturales en la interpretación literaria\n",
578
+ "\n",
579
+ "Las diferencias culturales influyen profundamente en la interpretación de textos literarios de varias maneras:\n",
580
+ "\n",
581
+ "## Factores que afectan la interpretación\n",
582
+ "- **Marcos de referencia**: Los lectores interpretan textos a través de sus propias experiencias culturales, valores y tradiciones\n",
583
+ "- **Presupuestos culturales**: Conceptos como honor, familia, justicia o libertad tienen matices distintos en diferentes culturas\n",
584
+ "- **Contexto histórico**: Eventos históricos específicos que han marcado a una cultura condicionan la lectura\n",
585
+ "- **Símbolos y metáforas**: Elementos simbólicos pueden tener significados radicalmente distintos entre culturas\n",
586
+ "\n",
587
+ "## Efecto en la percepción de valores universales\n",
588
+ "- **Universalidad cuestionada**: Lo que parece \"universal\" desde una perspectiva cultural puede no serlo desde otra\n",
589
+ "- **Enriquecimiento**: Las múltiples interpretaciones pueden revelar dimensiones más ricas de la obra\n",
590
+ "- **Malentendidos productivos**: Las lecturas \"equivocadas\" desde la cultura de origen pueden generar insights valiosos\n",
591
+ "- **Diálogo intercultural**: Las diferencias interpretativas pueden facilitar el entendimiento entre culturas\n",
592
+ "\n",
593
+ "Este fenómeno sugiere que los valores universales en literatura no son tanto puntos de acuerdo unánime, sino temas que resonan transversalmente aunque sean interpretados diferentemente, creando un espacio de diálogo intercultural donde la diversidad de lecturas enriquece rather que empobrece nuestra comprensión de la condición humana.\n"
594
+ ]
595
+ }
596
+ ],
597
+ "source": [
598
+ "# Es bueno saber cómo se utiliza \"zip\"\n",
599
+ "for competitor, answer in zip(competitors, answers):\n",
600
+ " print(f\"Competidor: {competitor}\\n\\n{answer}\")\n"
601
+ ]
602
+ },
603
+ {
604
+ "cell_type": "code",
605
+ "execution_count": 12,
606
+ "metadata": {},
607
+ "outputs": [],
608
+ "source": [
609
+ "# Vamos a juntarlo todo - nota cómo usamos en este caso \"enumerate\"\n",
610
+ "\n",
611
+ "together = \"\"\n",
612
+ "for index, answer in enumerate(answers):\n",
613
+ " together += f\"#Respuesta del competitor {index+1}\\n\\n\"\n",
614
+ " together += answer + \"\\n\\n\""
615
+ ]
616
+ },
617
+ {
618
+ "cell_type": "code",
619
+ "execution_count": 13,
620
+ "metadata": {},
621
+ "outputs": [
622
+ {
623
+ "name": "stdout",
624
+ "output_type": "stream",
625
+ "text": [
626
+ "#Respuesta del competitor 1\n",
627
+ "\n",
628
+ "Las diferencias culturales pueden influir de manera significativa en la interpretación de un mismo texto literario, y esto a su vez puede afectar la percepción de los valores universales que se intentan transmitir. Aquí hay varias maneras en que esto puede suceder:\n",
629
+ "\n",
630
+ "1. **Contexto histórico y social**: Cada cultura tiene su propio contexto histórico y social que puede influir en cómo se recibe un texto. Por ejemplo, un pasaje que critique la autoridad puede ser recibido de manera muy diferente en una sociedad con tradiciones autoritarias en comparación con una cultura que prioriza la individualidad y la libertad de expresión.\n",
631
+ "\n",
632
+ "2. **Valores y creencias**: Las creencias y valores fundamentales de una cultura (como la familia, la religión o el individualismo) pueden moldear la interpretación de los personajes y sus acciones. Un acto considerado heroico en una cultura puede ser visto como irresponsable en otra, alterando la percepción de lo que constituye un \"valor universal\".\n",
633
+ "\n",
634
+ "3. **Tradiciones literarias**: Cada cultura tiene sus propias tradiciones narrativas y estilos literarios. La forma en que un texto es estructurado o el tipo de símbolos que utiliza pueden ser interpretados de maneras distintas dependiendo del trasfondo cultural del lector. Por ejemplo, el uso de metáforas o referencias culturales específicas puede ser entendido de manera totalmente diversa.\n",
635
+ "\n",
636
+ "4. **Emociones y experiencias**: Las experiencias de vida en diferentes culturas pueden provocar respuestas emocionales distintas. Un lector que ha vivido en una cultura de conflicto puede experimentar una obra de manera más intensa que alguien que proviene de un entorno más pacífico.\n",
637
+ "\n",
638
+ "5. **Traducción e interpretación**: La traducción de textos literarios implica no solo cambiar palabras de un idioma a otro, sino también interpretación de matices y significados culturales. Esto puede llevar a que se pierdan o cambien ciertos valores o mensajes, y por ende, la obra puede ser recibida de forma mucho más variada.\n",
639
+ "\n",
640
+ "6. **Interacción de conceptos universales**: Aunque algunos valores son considerados universales, como la empatía o la justicia, la forma en que se manifiestan y son aplicados varía entre culturas. Un texto que intenta explorar estos valores puede resonar de manera diferente según la experiencia cultural de cada lector.\n",
641
+ "\n",
642
+ "En resumen, las diferencias culturales en la interpretación de un texto literario pueden enriquecer la discusión sobre los valores universales, pero también pueden diluir o distorsionar los mensajes que se intentan transmitir. La diversidad de interpretaciones ofrece una oportunidad para el diálogo intercultural, pero también presenta desafíos en la búsqueda de entendimiento común.\n",
643
+ "\n",
644
+ "#Respuesta del competitor 2\n",
645
+ "\n",
646
+ "# Influencia de las diferencias culturales en la interpretación literaria\n",
647
+ "\n",
648
+ "Las diferencias culturales influyen profundamente en la interpretación de textos literarios de varias maneras:\n",
649
+ "\n",
650
+ "## Factores que afectan la interpretación\n",
651
+ "- **Marcos de referencia**: Los lectores interpretan textos a través de sus propias experiencias culturales, valores y tradiciones\n",
652
+ "- **Presupuestos culturales**: Conceptos como honor, familia, justicia o libertad tienen matices distintos en diferentes culturas\n",
653
+ "- **Contexto histórico**: Eventos históricos específicos que han marcado a una cultura condicionan la lectura\n",
654
+ "- **Símbolos y metáforas**: Elementos simbólicos pueden tener significados radicalmente distintos entre culturas\n",
655
+ "\n",
656
+ "## Efecto en la percepción de valores universales\n",
657
+ "- **Universalidad cuestionada**: Lo que parece \"universal\" desde una perspectiva cultural puede no serlo desde otra\n",
658
+ "- **Enriquecimiento**: Las múltiples interpretaciones pueden revelar dimensiones más ricas de la obra\n",
659
+ "- **Malentendidos productivos**: Las lecturas \"equivocadas\" desde la cultura de origen pueden generar insights valiosos\n",
660
+ "- **Diálogo intercultural**: Las diferencias interpretativas pueden facilitar el entendimiento entre culturas\n",
661
+ "\n",
662
+ "Este fenómeno sugiere que los valores universales en literatura no son tanto puntos de acuerdo unánime, sino temas que resonan transversalmente aunque sean interpretados diferentemente, creando un espacio de diálogo intercultural donde la diversidad de lecturas enriquece rather que empobrece nuestra comprensión de la condición humana.\n",
663
+ "\n",
664
+ "\n"
665
+ ]
666
+ }
667
+ ],
668
+ "source": [
669
+ "print(together)"
670
+ ]
671
+ },
672
+ {
673
+ "cell_type": "code",
674
+ "execution_count": 14,
675
+ "metadata": {},
676
+ "outputs": [],
677
+ "source": [
678
+ "judge = f\"\"\"Estás juzgando una competición entre {len(competitors)} competidores.\n",
679
+ "A cada modelo se le ha dado esta pregunta:\n",
680
+ "\n",
681
+ "{question}\n",
682
+ "\n",
683
+ "Tu trabajo es evaluar cada respuesta por claridad y fortaleza del argumento, y clasificarlas en orden de mejor a peor.\n",
684
+ "Responde con JSON, y solo JSON, con el siguiente formato:\n",
685
+ "{{\"resultados\": [\"número del mejor competidor\", \"número del segundo mejor\", \"número del tercer mejor\", ...]}}\n",
686
+ "\n",
687
+ "Aquí están las respuestas de cada competidor:\n",
688
+ "\n",
689
+ "{together}\n",
690
+ "\n",
691
+ "Ahora responde con el JSON con el orden clasificado de los competidores, nada más. No incluyas formato markdown ni bloques de código.\"\"\"\n"
692
+ ]
693
+ },
694
+ {
695
+ "cell_type": "code",
696
+ "execution_count": 15,
697
+ "metadata": {},
698
+ "outputs": [
699
+ {
700
+ "name": "stdout",
701
+ "output_type": "stream",
702
+ "text": [
703
+ "Estás juzgando una competición entre 2 competidores.\n",
704
+ "A cada modelo se le ha dado esta pregunta:\n",
705
+ "\n",
706
+ "¿De qué manera crees que influirían las diferencias culturales en la interpretación de un mismo texto literario, y cómo esto podría afectar la percepción general de los valores universales que se pretenden transmitir?\n",
707
+ "\n",
708
+ "Tu trabajo es evaluar cada respuesta por claridad y fortaleza del argumento, y clasificarlas en orden de mejor a peor.\n",
709
+ "Responde con JSON, y solo JSON, con el siguiente formato:\n",
710
+ "{\"resultados\": [\"número del mejor competidor\", \"número del segundo mejor\", \"número del tercer mejor\", ...]}\n",
711
+ "\n",
712
+ "Aquí están las respuestas de cada competidor:\n",
713
+ "\n",
714
+ "#Respuesta del competitor 1\n",
715
+ "\n",
716
+ "Las diferencias culturales pueden influir de manera significativa en la interpretación de un mismo texto literario, y esto a su vez puede afectar la percepción de los valores universales que se intentan transmitir. Aquí hay varias maneras en que esto puede suceder:\n",
717
+ "\n",
718
+ "1. **Contexto histórico y social**: Cada cultura tiene su propio contexto histórico y social que puede influir en cómo se recibe un texto. Por ejemplo, un pasaje que critique la autoridad puede ser recibido de manera muy diferente en una sociedad con tradiciones autoritarias en comparación con una cultura que prioriza la individualidad y la libertad de expresión.\n",
719
+ "\n",
720
+ "2. **Valores y creencias**: Las creencias y valores fundamentales de una cultura (como la familia, la religión o el individualismo) pueden moldear la interpretación de los personajes y sus acciones. Un acto considerado heroico en una cultura puede ser visto como irresponsable en otra, alterando la percepción de lo que constituye un \"valor universal\".\n",
721
+ "\n",
722
+ "3. **Tradiciones literarias**: Cada cultura tiene sus propias tradiciones narrativas y estilos literarios. La forma en que un texto es estructurado o el tipo de símbolos que utiliza pueden ser interpretados de maneras distintas dependiendo del trasfondo cultural del lector. Por ejemplo, el uso de metáforas o referencias culturales específicas puede ser entendido de manera totalmente diversa.\n",
723
+ "\n",
724
+ "4. **Emociones y experiencias**: Las experiencias de vida en diferentes culturas pueden provocar respuestas emocionales distintas. Un lector que ha vivido en una cultura de conflicto puede experimentar una obra de manera más intensa que alguien que proviene de un entorno más pacífico.\n",
725
+ "\n",
726
+ "5. **Traducción e interpretación**: La traducción de textos literarios implica no solo cambiar palabras de un idioma a otro, sino también interpretación de matices y significados culturales. Esto puede llevar a que se pierdan o cambien ciertos valores o mensajes, y por ende, la obra puede ser recibida de forma mucho más variada.\n",
727
+ "\n",
728
+ "6. **Interacción de conceptos universales**: Aunque algunos valores son considerados universales, como la empatía o la justicia, la forma en que se manifiestan y son aplicados varía entre culturas. Un texto que intenta explorar estos valores puede resonar de manera diferente según la experiencia cultural de cada lector.\n",
729
+ "\n",
730
+ "En resumen, las diferencias culturales en la interpretación de un texto literario pueden enriquecer la discusión sobre los valores universales, pero también pueden diluir o distorsionar los mensajes que se intentan transmitir. La diversidad de interpretaciones ofrece una oportunidad para el diálogo intercultural, pero también presenta desafíos en la búsqueda de entendimiento común.\n",
731
+ "\n",
732
+ "#Respuesta del competitor 2\n",
733
+ "\n",
734
+ "# Influencia de las diferencias culturales en la interpretación literaria\n",
735
+ "\n",
736
+ "Las diferencias culturales influyen profundamente en la interpretación de textos literarios de varias maneras:\n",
737
+ "\n",
738
+ "## Factores que afectan la interpretación\n",
739
+ "- **Marcos de referencia**: Los lectores interpretan textos a través de sus propias experiencias culturales, valores y tradiciones\n",
740
+ "- **Presupuestos culturales**: Conceptos como honor, familia, justicia o libertad tienen matices distintos en diferentes culturas\n",
741
+ "- **Contexto histórico**: Eventos históricos específicos que han marcado a una cultura condicionan la lectura\n",
742
+ "- **Símbolos y metáforas**: Elementos simbólicos pueden tener significados radicalmente distintos entre culturas\n",
743
+ "\n",
744
+ "## Efecto en la percepción de valores universales\n",
745
+ "- **Universalidad cuestionada**: Lo que parece \"universal\" desde una perspectiva cultural puede no serlo desde otra\n",
746
+ "- **Enriquecimiento**: Las múltiples interpretaciones pueden revelar dimensiones más ricas de la obra\n",
747
+ "- **Malentendidos productivos**: Las lecturas \"equivocadas\" desde la cultura de origen pueden generar insights valiosos\n",
748
+ "- **Diálogo intercultural**: Las diferencias interpretativas pueden facilitar el entendimiento entre culturas\n",
749
+ "\n",
750
+ "Este fenómeno sugiere que los valores universales en literatura no son tanto puntos de acuerdo unánime, sino temas que resonan transversalmente aunque sean interpretados diferentemente, creando un espacio de diálogo intercultural donde la diversidad de lecturas enriquece rather que empobrece nuestra comprensión de la condición humana.\n",
751
+ "\n",
752
+ "\n",
753
+ "\n",
754
+ "Ahora responde con el JSON con el orden clasificado de los competidores, nada más. No incluyas formato markdown ni bloques de código.\n"
755
+ ]
756
+ }
757
+ ],
758
+ "source": [
759
+ "print(judge)"
760
+ ]
761
+ },
762
+ {
763
+ "cell_type": "code",
764
+ "execution_count": 16,
765
+ "metadata": {},
766
+ "outputs": [],
767
+ "source": [
768
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
769
+ ]
770
+ },
771
+ {
772
+ "cell_type": "code",
773
+ "execution_count": 17,
774
+ "metadata": {},
775
+ "outputs": [
776
+ {
777
+ "name": "stdout",
778
+ "output_type": "stream",
779
+ "text": [
780
+ "{\"resultados\": [\"1\", \"2\"]}\n"
781
+ ]
782
+ }
783
+ ],
784
+ "source": [
785
+ "# Hora de juzgar\n",
786
+ "\n",
787
+ "openai = OpenAI()\n",
788
+ "response = openai.chat.completions.create(\n",
789
+ " model=\"o3-mini\",\n",
790
+ " messages=judge_messages,\n",
791
+ ")\n",
792
+ "results = response.choices[0].message.content\n",
793
+ "print(results)\n"
794
+ ]
795
+ },
796
+ {
797
+ "cell_type": "code",
798
+ "execution_count": 18,
799
+ "metadata": {},
800
+ "outputs": [
801
+ {
802
+ "name": "stdout",
803
+ "output_type": "stream",
804
+ "text": [
805
+ "Rank 1: gpt-4o-mini\n",
806
+ "Rank 2: deepseek-chat\n"
807
+ ]
808
+ }
809
+ ],
810
+ "source": [
811
+ "# OK veamos los resultados\n",
812
+ "\n",
813
+ "results_dict = json.loads(results)\n",
814
+ "ranks = results_dict[\"resultados\"]\n",
815
+ "for index, result in enumerate(ranks):\n",
816
+ " competitor = competitors[int(result)-1]\n",
817
+ " print(f\"Rank {index+1}: {competitor}\")"
818
+ ]
819
+ },
820
+ {
821
+ "cell_type": "markdown",
822
+ "metadata": {},
823
+ "source": [
824
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
825
+ " <tr>\n",
826
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
827
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
828
+ " </td>\n",
829
+ " <td>\n",
830
+ " <h2 style=\"color:#ff7800;\">Ejercicio</h2>\n",
831
+ " <span style=\"color:#ff7800;\">¿Qué patrón(es) usamos en este experimento? Intenta actualizar esto para añadir otro patrón de diseño Agéntico.\n",
832
+ " </span>\n",
833
+ " </td>\n",
834
+ " </tr>\n",
835
+ "</table>\n"
836
+ ]
837
+ },
838
+ {
839
+ "cell_type": "markdown",
840
+ "metadata": {},
841
+ "source": [
842
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
843
+ " <tr>\n",
844
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
845
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
846
+ " </td>\n",
847
+ " <td>\n",
848
+ " <h2 style=\"color:#00bfff;\">Implicaciones comerciales</h2>\n",
849
+ " <span style=\"color:#00bfff;\">Este tipo de patrones - enviar una tarea a múltiples modelos y evaluar los resultados,\n",
850
+ " son comunes cuando necesitas mejorar la calidad de la respuesta de tu LLM. Este enfoque se puede aplicar de manera\n",
851
+ " universal a proyectos comerciales donde la precisión es crítica.\n",
852
+ " </span>\n",
853
+ " </td>\n",
854
+ " </tr>\n",
855
+ "</table>\n"
856
+ ]
857
+ },
858
+ {
859
+ "cell_type": "markdown",
860
+ "metadata": {},
861
+ "source": []
862
+ }
863
+ ],
864
+ "metadata": {
865
+ "kernelspec": {
866
+ "display_name": ".venv",
867
+ "language": "python",
868
+ "name": "python3"
869
+ },
870
+ "language_info": {
871
+ "codemirror_mode": {
872
+ "name": "ipython",
873
+ "version": 3
874
+ },
875
+ "file_extension": ".py",
876
+ "mimetype": "text/x-python",
877
+ "name": "python",
878
+ "nbconvert_exporter": "python",
879
+ "pygments_lexer": "ipython3",
880
+ "version": "3.12.9"
881
+ }
882
+ },
883
+ "nbformat": 4,
884
+ "nbformat_minor": 2
885
+ }
3_lab3.ipynb ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Bienvenidos al Laboratorio 3 para la Semana 1\n",
8
+ "\n",
9
+ "¡Hoy vamos a construir algo con valor inmediato!\n",
10
+ "\n",
11
+ "No vamos a usar herramientas todavía, las vamos a agregar mañana.\n"
12
+ ]
13
+ },
14
+ {
15
+ "cell_type": "markdown",
16
+ "metadata": {},
17
+ "source": [
18
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
19
+ " <tr>\n",
20
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
21
+ " <img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
22
+ " </td>\n",
23
+ " <td>\n",
24
+ " <h2 style=\"color:#00bfff;\">Buscando paquetes</h2>\n",
25
+ "<span style=\"color:#00bfff;\">En este laboratorio, usaremos el excelente paquete Gradio para crear interfaces de usuario rápidas, y también usaremos el popular lector de PDF PyPDF2. Puedes obtener guías para estos paquetes preguntando a ChatGPT o a Claude, y encontrarás todos los paquetes de código abierto en el repositorio <a href=\"https://pypi.org\">https://pypi.org</a>.\n",
26
+ "</span>\n",
27
+ " </td>\n",
28
+ " </tr>\n",
29
+ "</table>"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": 1,
35
+ "metadata": {},
36
+ "outputs": [],
37
+ "source": [
38
+ "# Si no sabe para qué sirve alguno de estos paquetes, ¡siempre puede pedirle una guía a ChatGPT!\n",
39
+ "\n",
40
+ "from dotenv import load_dotenv\n",
41
+ "from openai import OpenAI\n",
42
+ "from pypdf import PdfReader\n",
43
+ "import gradio as gr"
44
+ ]
45
+ },
46
+ {
47
+ "cell_type": "code",
48
+ "execution_count": 2,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "load_dotenv(override=True)\n",
53
+ "openai = OpenAI()"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": 3,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "reader = PdfReader(\"me/linkedin.pdf\")\n",
63
+ "linkedin = \"\"\n",
64
+ "for page in reader.pages:\n",
65
+ " text = page.extract_text()\n",
66
+ " if text:\n",
67
+ " linkedin += text"
68
+ ]
69
+ },
70
+ {
71
+ "cell_type": "code",
72
+ "execution_count": null,
73
+ "metadata": {},
74
+ "outputs": [],
75
+ "source": [
76
+ "print(linkedin)"
77
+ ]
78
+ },
79
+ {
80
+ "cell_type": "code",
81
+ "execution_count": 5,
82
+ "metadata": {},
83
+ "outputs": [],
84
+ "source": [
85
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
86
+ " summary = f.read()"
87
+ ]
88
+ },
89
+ {
90
+ "cell_type": "code",
91
+ "execution_count": null,
92
+ "metadata": {},
93
+ "outputs": [],
94
+ "source": [
95
+ "name = \"Tu nombre\""
96
+ ]
97
+ },
98
+ {
99
+ "cell_type": "code",
100
+ "execution_count": 7,
101
+ "metadata": {},
102
+ "outputs": [],
103
+ "source": [
104
+ "system_prompt = f\"Estás actuando como {name}. Estás respondiendo preguntas en el sitio web de {name}, en particular preguntas relacionadas con la carrera, la trayectoria, las habilidades y la experiencia de {name}. \\\n",
105
+ "Tu responsabilidad es representar a {name} en las interacciones en el sitio web con la mayor fidelidad posible. \\\n",
106
+ "Se te proporciona un resumen de la trayectoria y el perfil de LinkedIn de {name} que puedes usar para responder preguntas. \\\n",
107
+ "Sé profesional y atractivo, como si hablaras con un cliente potencial o un futuro empleador que haya visitado el sitio web. \\\n",
108
+ "Si no sabes la respuesta, dilo.\"\n",
109
+ "\n",
110
+ "system_prompt += f\"\\n\\n## Resumen:\\n{summary}\\n\\n## Perfil de LinkedIn:\\n{linkedin}\\n\\n\"\n",
111
+ "system_prompt += f\"En este contexto, charla con el usuario, utilizando siempre el personaje de {name}.\"\n"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "code",
116
+ "execution_count": null,
117
+ "metadata": {},
118
+ "outputs": [],
119
+ "source": [
120
+ "system_prompt"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "code",
125
+ "execution_count": 9,
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "def chat(message, history):\n",
130
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
131
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
132
+ " return response.choices[0].message.content"
133
+ ]
134
+ },
135
+ {
136
+ "cell_type": "code",
137
+ "execution_count": null,
138
+ "metadata": {},
139
+ "outputs": [],
140
+ "source": [
141
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
142
+ ]
143
+ },
144
+ {
145
+ "cell_type": "markdown",
146
+ "metadata": {},
147
+ "source": [
148
+ "## Mucho está por suceder...\n",
149
+ "\n",
150
+ "1. Poder solicitar a un LLM que evalúe una respuesta.\n",
151
+ "2. Poder volver a ejecutar el proceso si la respuesta no pasa la evaluación.\n",
152
+ "3. Integrar todo en un solo flujo de trabajo.\n",
153
+ "\n",
154
+ "¡Todo sin usar un marco de trabajo de Agentic!"
155
+ ]
156
+ },
157
+ {
158
+ "cell_type": "code",
159
+ "execution_count": 11,
160
+ "metadata": {},
161
+ "outputs": [],
162
+ "source": [
163
+ "# Crear un modelo de Pydantic para la evaluación\n",
164
+ "\n",
165
+ "from pydantic import BaseModel\n",
166
+ "\n",
167
+ "class Evaluation(BaseModel):\n",
168
+ " is_acceptable: bool\n",
169
+ " feedback: str\n"
170
+ ]
171
+ },
172
+ {
173
+ "cell_type": "code",
174
+ "execution_count": 12,
175
+ "metadata": {},
176
+ "outputs": [],
177
+ "source": [
178
+ "evaluator_system_prompt = f\"Usted es un evaluador que decide si una respuesta a una pregunta es aceptable. \\\n",
179
+ "Se le presenta una conversación entre un usuario y un agente. Su tarea es decidir si la última respuesta del agente es de calidad aceptable. \\\n",
180
+ "El agente desempeña el papel de {name} y representa a {name} en su sitio web. \\\n",
181
+ "Se le ha indicado que sea profesional y atractivo, como si hablara con un cliente potencial o un futuro empleador que haya visitado el sitio web. \\\n",
182
+ "Se le ha proporcionado contexto sobre {name} en forma de resumen y datos de LinkedIn. Aquí está la información:\"\n",
183
+ "\n",
184
+ "evaluator_system_prompt += f\"\\n\\n## Resumen:\\n{summary}\\n\\n## Perfil de LinkedIn:\\n{linkedin}\\n\\n\"\n",
185
+ "evaluator_system_prompt += f\"Con este contexto, por favor, evalúe la última respuesta, indicando si es aceptable y sus comentarios.\""
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": 13,
191
+ "metadata": {},
192
+ "outputs": [],
193
+ "source": [
194
+ "def evaluator_user_prompt(reply, message, history):\n",
195
+ " user_prompt = f\"Aquí está la conversación entre el usuario y el agente: \\n\\n{history}\\n\\n\"\n",
196
+ " user_prompt += f\"Aquí está el último mensaje del usuario: \\n\\n{message}\\n\\n\"\n",
197
+ " user_prompt += f\"Aquí está la última respuesta del agente: \\n\\n{reply}\\n\\n\"\n",
198
+ " user_prompt += f\"Por favor, evalúe la respuesta, indicando si es aceptable y sus comentarios.\"\n",
199
+ " return user_prompt"
200
+ ]
201
+ },
202
+ {
203
+ "cell_type": "code",
204
+ "execution_count": 14,
205
+ "metadata": {},
206
+ "outputs": [],
207
+ "source": [
208
+ "import os\n",
209
+ "gemini = OpenAI(\n",
210
+ " api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
211
+ " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
212
+ ")"
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "execution_count": 15,
218
+ "metadata": {},
219
+ "outputs": [],
220
+ "source": [
221
+ "def evaluate(reply, message, history) -> Evaluation:\n",
222
+ "\n",
223
+ " messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
224
+ " response = gemini.beta.chat.completions.parse(model=\"gemini-2.0-flash\", messages=messages, response_format=Evaluation)\n",
225
+ " return response.choices[0].message.parsed"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": 16,
231
+ "metadata": {},
232
+ "outputs": [],
233
+ "source": [
234
+ "messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"¿Tocas un instrumento?\"}]\n",
235
+ "response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
236
+ "reply = response.choices[0].message.content"
237
+ ]
238
+ },
239
+ {
240
+ "cell_type": "code",
241
+ "execution_count": null,
242
+ "metadata": {},
243
+ "outputs": [],
244
+ "source": [
245
+ "reply"
246
+ ]
247
+ },
248
+ {
249
+ "cell_type": "code",
250
+ "execution_count": null,
251
+ "metadata": {},
252
+ "outputs": [],
253
+ "source": [
254
+ "evaluate(reply, \"Tocas un instrumento?\", messages[:1])"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": 19,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "def rerun(reply, message, history, feedback):\n",
264
+ " updated_system_prompt = system_prompt + f\"\\n\\n## Respuesta anterior rechazada\\nAcabas de intentar responder, pero el control de calidad rechazó tu respuesta.\\n\"\n",
265
+ " updated_system_prompt += f\"## Has intentado responder:\\n{reply}\\n\\n\"\n",
266
+ " updated_system_prompt += f\"## Razón del rechazo:\\n{feedback}\\n\\n\"\n",
267
+ " messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
268
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
269
+ " return response.choices[0].message.content"
270
+ ]
271
+ },
272
+ {
273
+ "cell_type": "code",
274
+ "execution_count": 26,
275
+ "metadata": {},
276
+ "outputs": [],
277
+ "source": [
278
+ "def chat(message, history):\n",
279
+ " if \"instrumento\" in message:\n",
280
+ " system = system_prompt + \"\\n\\nToda tu respuesta debe estar en el latín de los cerdos traducido al español -\\\n",
281
+ " Es obligatorio que respondas únicamente y en su totalidad en el latín de los cerdos traducido al español.\"\n",
282
+ " else:\n",
283
+ " system = system_prompt\n",
284
+ " messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
285
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
286
+ " reply =response.choices[0].message.content\n",
287
+ "\n",
288
+ " evaluation = evaluate(reply, message, history)\n",
289
+ " \n",
290
+ " if evaluation.is_acceptable:\n",
291
+ " print(\"Has pasado la evaluación - devolviendo respuesta\")\n",
292
+ " else:\n",
293
+ " print(\"Has fallado la evaluación - reintentando\")\n",
294
+ " print(evaluation.feedback)\n",
295
+ " reply = rerun(reply, message, history, evaluation.feedback) \n",
296
+ " return reply"
297
+ ]
298
+ },
299
+ {
300
+ "cell_type": "code",
301
+ "execution_count": 27,
302
+ "metadata": {},
303
+ "outputs": [
304
+ {
305
+ "name": "stdout",
306
+ "output_type": "stream",
307
+ "text": [
308
+ "* Running on local URL: http://127.0.0.1:7864\n",
309
+ "* To create a public link, set `share=True` in `launch()`.\n"
310
+ ]
311
+ },
312
+ {
313
+ "data": {
314
+ "text/html": [
315
+ "<div><iframe src=\"http://127.0.0.1:7864/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
316
+ ],
317
+ "text/plain": [
318
+ "<IPython.core.display.HTML object>"
319
+ ]
320
+ },
321
+ "metadata": {},
322
+ "output_type": "display_data"
323
+ },
324
+ {
325
+ "data": {
326
+ "text/plain": []
327
+ },
328
+ "execution_count": 27,
329
+ "metadata": {},
330
+ "output_type": "execute_result"
331
+ },
332
+ {
333
+ "name": "stdout",
334
+ "output_type": "stream",
335
+ "text": [
336
+ "Has pasado la evaluación - devolviendo respuesta\n"
337
+ ]
338
+ }
339
+ ],
340
+ "source": [
341
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
342
+ ]
343
+ },
344
+ {
345
+ "cell_type": "code",
346
+ "execution_count": null,
347
+ "metadata": {},
348
+ "outputs": [],
349
+ "source": []
350
+ }
351
+ ],
352
+ "metadata": {
353
+ "kernelspec": {
354
+ "display_name": ".venv",
355
+ "language": "python",
356
+ "name": "python3"
357
+ },
358
+ "language_info": {
359
+ "codemirror_mode": {
360
+ "name": "ipython",
361
+ "version": 3
362
+ },
363
+ "file_extension": ".py",
364
+ "mimetype": "text/x-python",
365
+ "name": "python",
366
+ "nbconvert_exporter": "python",
367
+ "pygments_lexer": "ipython3",
368
+ "version": "3.12.11"
369
+ }
370
+ },
371
+ "nbformat": 4,
372
+ "nbformat_minor": 2
373
+ }
4_lab4.ipynb ADDED
@@ -0,0 +1,529 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## El primer gran proyecto: ¡Profesionalmente Tú!\n",
8
+ "\n",
9
+ "### Y, uso de la herramienta.\n",
10
+ "\n",
11
+ "### Pero primero: presentamos Pushover\n",
12
+ "\n",
13
+ "Pushover es una herramienta práctica para enviar notificaciones push a tu teléfono.\n",
14
+ "\n",
15
+ "¡Es facilísima de configurar e instalar!\n",
16
+ "\n",
17
+ "Simplemente visita https://pushover.net/, crea una cuenta gratuita y genera tus claves API.\n",
18
+ "\n",
19
+ "Como señaló el estudiante Ron (¡gracias, Ron!), hay dos tokens que se pueden crear en Pushover:\n",
20
+ "1. El token de usuario, que se obtiene en la página principal de Pushover.\n",
21
+ "2. El token de aplicación, que se obtiene al ir a https://pushover.net/apps/build y crear una aplicación.\n",
22
+ "\n",
23
+ "(Esto te permite organizar tus notificaciones push en diferentes aplicaciones en el futuro).\n",
24
+ "\n",
25
+ "Agrega a tu archivo `.env`:\n",
26
+ "```\n",
27
+ "PUSHOVER_USER=pon_tu_token_de_usuario_aquí\n",
28
+ "PUSHOVER_TOKEN=pon_tu_token_de_aplicación_aquí\n",
29
+ "```\n",
30
+ "\n",
31
+ "E instala la aplicación Pushover en tu teléfono."
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "code",
36
+ "execution_count": 1,
37
+ "metadata": {},
38
+ "outputs": [],
39
+ "source": [
40
+ "# imports\n",
41
+ "\n",
42
+ "from dotenv import load_dotenv\n",
43
+ "from openai import OpenAI\n",
44
+ "import json\n",
45
+ "import os\n",
46
+ "import requests\n",
47
+ "from pypdf import PdfReader\n",
48
+ "import gradio as gr"
49
+ ]
50
+ },
51
+ {
52
+ "cell_type": "code",
53
+ "execution_count": 6,
54
+ "metadata": {},
55
+ "outputs": [],
56
+ "source": [
57
+ "# El inicio usual\n",
58
+ "\n",
59
+ "load_dotenv(override=True)\n",
60
+ "openai = OpenAI()"
61
+ ]
62
+ },
63
+ {
64
+ "cell_type": "code",
65
+ "execution_count": 3,
66
+ "metadata": {},
67
+ "outputs": [],
68
+ "source": [
69
+ "# Para pushover\n",
70
+ "\n",
71
+ "pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
72
+ "pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
73
+ "pushover_url = \"https://api.pushover.net/1/messages.json\""
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": 4,
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "def push(message):\n",
83
+ " print(f\"Push: {message}\")\n",
84
+ " payload = {\"user\": pushover_user, \"token\": pushover_token, \"message\": message}\n",
85
+ " requests.post(pushover_url, data=payload)"
86
+ ]
87
+ },
88
+ {
89
+ "cell_type": "code",
90
+ "execution_count": 5,
91
+ "metadata": {},
92
+ "outputs": [
93
+ {
94
+ "name": "stdout",
95
+ "output_type": "stream",
96
+ "text": [
97
+ "Push: HOLA!!\n"
98
+ ]
99
+ }
100
+ ],
101
+ "source": [
102
+ "push(\"HOLA!!\")"
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "code",
107
+ "execution_count": 8,
108
+ "metadata": {},
109
+ "outputs": [],
110
+ "source": [
111
+ "def record_user_details(email, name=\"Nombre no proporcionado\", notes=\"not provided\"):\n",
112
+ " push(f\"Registrando interés de {name} con email {email} y notas {notes}\")\n",
113
+ " return {\"recorded\": \"ok\"}"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": 9,
119
+ "metadata": {},
120
+ "outputs": [],
121
+ "source": [
122
+ "def record_unknown_question(question):\n",
123
+ " push(f\"Registrando pregunta no respondida: {question}\")\n",
124
+ " return {\"recorded\": \"ok\"}"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": 10,
130
+ "metadata": {},
131
+ "outputs": [],
132
+ "source": [
133
+ "record_user_details_json = {\n",
134
+ " \"name\": \"record_user_details\",\n",
135
+ " \"description\": \"Utilice esta herramienta para registrar que un usuario está interesado en estar en contacto y proporcionó una dirección de correo electrónico.\",\n",
136
+ " \"parameters\": {\n",
137
+ " \"type\": \"object\",\n",
138
+ " \"properties\": {\n",
139
+ " \"email\": {\n",
140
+ " \"type\": \"string\",\n",
141
+ " \"description\": \"La dirección de correo electrónico de este usuario\"\n",
142
+ " },\n",
143
+ " \"name\": {\n",
144
+ " \"type\": \"string\",\n",
145
+ " \"description\": \"El nombre del usuario, si lo proporcionó\"\n",
146
+ " }\n",
147
+ " ,\n",
148
+ " \"notes\": {\n",
149
+ " \"type\": \"string\",\n",
150
+ " \"description\": \"Cualquier información adicional sobre la conversación que merezca ser registrada para dar contexto\"\n",
151
+ " }\n",
152
+ " },\n",
153
+ " \"required\": [\"email\"],\n",
154
+ " \"additionalProperties\": False\n",
155
+ " }\n",
156
+ "}"
157
+ ]
158
+ },
159
+ {
160
+ "cell_type": "code",
161
+ "execution_count": 11,
162
+ "metadata": {},
163
+ "outputs": [],
164
+ "source": [
165
+ "record_unknown_question_json = {\n",
166
+ " \"name\": \"record_unknown_question\",\n",
167
+ " \"description\": \"Siempre use esta herramienta para registrar cualquier pregunta que no se pueda responder, ya que no sabía la respuesta\",\n",
168
+ " \"parameters\": {\n",
169
+ " \"type\": \"object\",\n",
170
+ " \"properties\": {\n",
171
+ " \"question\": {\n",
172
+ " \"type\": \"string\",\n",
173
+ " \"description\": \"La pregunta que no se pudo responder\"\n",
174
+ " },\n",
175
+ " },\n",
176
+ " \"required\": [\"question\"],\n",
177
+ " \"additionalProperties\": False\n",
178
+ " }\n",
179
+ "}"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "execution_count": 12,
185
+ "metadata": {},
186
+ "outputs": [],
187
+ "source": [
188
+ "tools = [{\"type\": \"function\", \"function\": record_user_details_json},\n",
189
+ " {\"type\": \"function\", \"function\": record_unknown_question_json}]"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 13,
195
+ "metadata": {},
196
+ "outputs": [
197
+ {
198
+ "data": {
199
+ "text/plain": [
200
+ "[{'type': 'function',\n",
201
+ " 'function': {'name': 'record_user_details',\n",
202
+ " 'description': 'Utilice esta herramienta para registrar que un usuario está interesado en estar en contacto y proporcionó una dirección de correo electrónico.',\n",
203
+ " 'parameters': {'type': 'object',\n",
204
+ " 'properties': {'email': {'type': 'string',\n",
205
+ " 'description': 'La dirección de correo electrónico de este usuario'},\n",
206
+ " 'name': {'type': 'string',\n",
207
+ " 'description': 'El nombre del usuario, si lo proporcionó'},\n",
208
+ " 'notes': {'type': 'string',\n",
209
+ " 'description': 'Cualquier información adicional sobre la conversación que merezca ser registrada para dar contexto'}},\n",
210
+ " 'required': ['email'],\n",
211
+ " 'additionalProperties': False}}},\n",
212
+ " {'type': 'function',\n",
213
+ " 'function': {'name': 'record_unknown_question',\n",
214
+ " 'description': 'Siempre use esta herramienta para registrar cualquier pregunta que no se pueda responder, ya que no sabía la respuesta',\n",
215
+ " 'parameters': {'type': 'object',\n",
216
+ " 'properties': {'question': {'type': 'string',\n",
217
+ " 'description': 'La pregunta que no se pudo responder'}},\n",
218
+ " 'required': ['question'],\n",
219
+ " 'additionalProperties': False}}}]"
220
+ ]
221
+ },
222
+ "execution_count": 13,
223
+ "metadata": {},
224
+ "output_type": "execute_result"
225
+ }
226
+ ],
227
+ "source": [
228
+ "tools"
229
+ ]
230
+ },
231
+ {
232
+ "cell_type": "code",
233
+ "execution_count": 14,
234
+ "metadata": {},
235
+ "outputs": [],
236
+ "source": [
237
+ "# Esta función puede tomar una lista de llamadas a herramientas y ejecutarlas. ¡Este es el IF statement!!\n",
238
+ "\n",
239
+ "def handle_tool_calls(tool_calls):\n",
240
+ " results = []\n",
241
+ " for tool_call in tool_calls:\n",
242
+ " tool_name = tool_call.function.name\n",
243
+ " arguments = json.loads(tool_call.function.arguments)\n",
244
+ " print(f\"Herramienta llamada: {tool_name}\", flush=True)\n",
245
+ "\n",
246
+ " # ¡EL GRAN IF !!!\n",
247
+ "\n",
248
+ " if tool_name == \"record_user_details\":\n",
249
+ " result = record_user_details(**arguments)\n",
250
+ " elif tool_name == \"record_unknown_question\":\n",
251
+ " result = record_unknown_question(**arguments)\n",
252
+ "\n",
253
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
254
+ " return results"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": 15,
260
+ "metadata": {},
261
+ "outputs": [
262
+ {
263
+ "name": "stdout",
264
+ "output_type": "stream",
265
+ "text": [
266
+ "Push: Registrando pregunta no respondida: esta es una pregunta realmente difícil\n"
267
+ ]
268
+ },
269
+ {
270
+ "data": {
271
+ "text/plain": [
272
+ "{'recorded': 'ok'}"
273
+ ]
274
+ },
275
+ "execution_count": 15,
276
+ "metadata": {},
277
+ "output_type": "execute_result"
278
+ }
279
+ ],
280
+ "source": [
281
+ "globals()[\"record_unknown_question\"](\"esta es una pregunta realmente difícil\")"
282
+ ]
283
+ },
284
+ {
285
+ "cell_type": "code",
286
+ "execution_count": 16,
287
+ "metadata": {},
288
+ "outputs": [],
289
+ "source": [
290
+ "# Esta es una forma más elegante de evitar el IF statement.\n",
291
+ "\n",
292
+ "def handle_tool_calls(tool_calls):\n",
293
+ " results = []\n",
294
+ " for tool_call in tool_calls:\n",
295
+ " tool_name = tool_call.function.name\n",
296
+ " arguments = json.loads(tool_call.function.arguments)\n",
297
+ " print(f\"Herramienta llamada: {tool_name}\", flush=True)\n",
298
+ " tool = globals().get(tool_name)\n",
299
+ " result = tool(**arguments) if tool else {}\n",
300
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
301
+ " return results"
302
+ ]
303
+ },
304
+ {
305
+ "cell_type": "code",
306
+ "execution_count": 17,
307
+ "metadata": {},
308
+ "outputs": [],
309
+ "source": [
310
+ "reader = PdfReader(\"me/linkedin.pdf\")\n",
311
+ "linkedin = \"\"\n",
312
+ "for page in reader.pages:\n",
313
+ " text = page.extract_text()\n",
314
+ " if text:\n",
315
+ " linkedin += text\n",
316
+ "\n",
317
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
318
+ " summary = f.read()\n",
319
+ "\n",
320
+ "name = \"Alejandro Gonzalez\""
321
+ ]
322
+ },
323
+ {
324
+ "cell_type": "code",
325
+ "execution_count": 18,
326
+ "metadata": {},
327
+ "outputs": [],
328
+ "source": [
329
+ "system_prompt = f\"\"\"Estás actuando como {name}. Estás respondiendo preguntas en el sitio web de {name}, en particular preguntas relacionadas con la carrera, los antecedentes, las habilidades y la experiencia de {name}.\n",
330
+ "Tu responsabilidad es representar a {name} en las interacciones en el sitio web con la mayor fidelidad posible.\n",
331
+ "Se te proporciona un resumen de los antecedentes y el perfil de LinkedIn de {name} que puedes usar para responder preguntas.\n",
332
+ "Sé profesional y atractivo, como si hablaras con un cliente potencial o un futuro empleador que haya visitado el sitio web.\n",
333
+ "Si no sabes la respuesta a alguna pregunta, usa la herramienta record_unknown_question para registrar la pregunta que no pudiste responder, incluso si se trata de algo trivial o no relacionado con tu carrera.\n",
334
+ "Si el usuario participa en una conversación, intenta que se ponga en contacto por correo electrónico; pídele su correo electrónico y regístralo con la herramienta record_user_details.\"\"\"\n",
335
+ "\n",
336
+ "system_prompt += f\"\\n\\n## Resumen:\\n{summary}\\n\\n## LinkedIn Perfil:\\n{linkedin}\\n\\n\"\n",
337
+ "system_prompt += f\"En este contexto, chatea con el usuario, siempre con el personaje {name}.\""
338
+ ]
339
+ },
340
+ {
341
+ "cell_type": "code",
342
+ "execution_count": 19,
343
+ "metadata": {},
344
+ "outputs": [],
345
+ "source": [
346
+ "def chat(message, history):\n",
347
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
348
+ " done = False\n",
349
+ " while not done:\n",
350
+ "\n",
351
+ " # Esta es la llamada a la LLM - nota que pasamos el json de las herramientas\n",
352
+ "\n",
353
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages, tools=tools)\n",
354
+ "\n",
355
+ " finish_reason = response.choices[0].finish_reason\n",
356
+ " \n",
357
+ " # Si la LLM quiere llamar a una herramienta, la llamamos!\n",
358
+ " \n",
359
+ " if finish_reason==\"tool_calls\":\n",
360
+ " message = response.choices[0].message\n",
361
+ " tool_calls = message.tool_calls\n",
362
+ " results = handle_tool_calls(tool_calls)\n",
363
+ " messages.append(message)\n",
364
+ " messages.extend(results)\n",
365
+ " else:\n",
366
+ " done = True\n",
367
+ " return response.choices[0].message.content"
368
+ ]
369
+ },
370
+ {
371
+ "cell_type": "code",
372
+ "execution_count": 20,
373
+ "metadata": {},
374
+ "outputs": [
375
+ {
376
+ "name": "stdout",
377
+ "output_type": "stream",
378
+ "text": [
379
+ "* Running on local URL: http://127.0.0.1:7860\n",
380
+ "* To create a public link, set `share=True` in `launch()`.\n"
381
+ ]
382
+ },
383
+ {
384
+ "data": {
385
+ "text/html": [
386
+ "<div><iframe src=\"http://127.0.0.1:7860/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
387
+ ],
388
+ "text/plain": [
389
+ "<IPython.core.display.HTML object>"
390
+ ]
391
+ },
392
+ "metadata": {},
393
+ "output_type": "display_data"
394
+ },
395
+ {
396
+ "data": {
397
+ "text/plain": []
398
+ },
399
+ "execution_count": 20,
400
+ "metadata": {},
401
+ "output_type": "execute_result"
402
+ }
403
+ ],
404
+ "source": [
405
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
406
+ ]
407
+ },
408
+ {
409
+ "cell_type": "markdown",
410
+ "metadata": {},
411
+ "source": [
412
+ "## Y ahora, la implementación\n",
413
+ "\n",
414
+ "Este código está en `app.py`\n",
415
+ "\n",
416
+ "La implementación se realizará en HuggingFace Spaces. Gracias, estudiante Robert M, por mejorar estas instrucciones.\n",
417
+ "\n",
418
+ "Antes de empezar: recuerda actualizar los archivos del directorio \"me\" (tu perfil de LinkedIn y summary.txt) para que se muestren tus credenciales.\n",
419
+ "\n",
420
+ "Comprueba también que no haya ningún archivo README en el directorio 1_foundations. Si lo hay, elimínalo. El proceso de implementación crea un nuevo archivo README en este directorio.\n",
421
+ "\n",
422
+ "1. Visita https://huggingface.co y crea una cuenta.\n",
423
+ "2. En el menú Avatar, en la esquina superior derecha, selecciona \"Tokens de acceso\". Selecciona \"Crear nuevo token\". Asígnale permisos de escritura.\n",
424
+ "3. Tome este token y agréguelo a su archivo .env: `HF_TOKEN=hf_xxx`. Si no se detecta durante la implementación, consulte la nota a continuación.\n",
425
+ "4. Desde la carpeta 1_foundations, introduzca `uv run gradio deploy`. Si por alguna razón aún le solicita que introduzca su token HF, interrúmpalo con Ctrl+C y ejecute `uv run dotenv -f ../.env run -- uv run gradio deploy`, lo que obliga a que todas sus claves se configuren como variables de entorno.\n",
426
+ "5. Siga sus instrucciones: asígnele el nombre \"career_conversation\", especifique app.py, elija cpu-basic como hardware, confirme que es necesario proporcionar secretos, proporcione su clave de API de OpenAI, su usuario y token de Pushover, y confirme que no se permiten las acciones de GitHub. Nota adicional sobre el token HuggingFace\n",
427
+ "\n",
428
+ "Un par de estudiantes han mencionado que HuggingFace no detecta su token, a pesar de estar en el archivo .env. Prueba lo siguiente:\n",
429
+ "1. Reinicia el cursor.\n",
430
+ "2. Vuelve a ejecutar load_dotenv(override=True) y usa una nueva terminal (el botón + en la esquina superior derecha de la terminal).\n",
431
+ "3. En la terminal, ejecuta esto antes de la implementación de gradio: `$env:HF_TOKEN = \"hf_XXXX\"`.\n",
432
+ "Gracias, James y Martins, por estos consejos.\n",
433
+ "\n",
434
+ "#### Más información sobre estos secretos:\n",
435
+ "\n",
436
+ "Si no entiendes qué sucede con estos secretos, solo te pide que introduzcas el nombre y el valor de la clave para cada uno de ellos. Por ejemplo, escribirías:\n",
437
+ "`OPENAI_API_KEY`\n",
438
+ "Seguido de:\n",
439
+ "`sk-proj-...`\n",
440
+ "\n",
441
+ "Si no quieres configurar los secretos de esta manera o si algo sale mal, no hay problema: puedes cambiarlos más tarde:\n",
442
+ "\n",
443
+ "1. Inicia sesión en el sitio web de HuggingFace.\n",
444
+ "2. Ve a tu perfil a través del menú \"Avatar\" en la esquina superior derecha.\n",
445
+ "3. Selecciona el espacio que has implementado.\n",
446
+ "4. Haz clic en la rueda de Ajustes en la esquina superior derecha.\n",
447
+ "5. Puedes desplazarte hacia abajo para cambiar tus secretos, eliminar el espacio, etc.\n",
448
+ "\n",
449
+ "#### ¡Y ya deberías estar implementado!\n",
450
+ "\n",
451
+ "Aquí está el mío: https://huggingface.co/spaces/ed-donner/Career_Conversation\n",
452
+ "\n",
453
+ "Acabo de recibir una notificación push de que un estudiante me preguntó cómo puede convertirse en presidente de su país. 😂😂\n",
454
+ "\n",
455
+ "Para más información sobre la implementación:\n",
456
+ "\n",
457
+ "https://www.gradio.app/guides/sharing-your-app#hosting-on-hf-spaces\n",
458
+ "\n",
459
+ "Para eliminar tu espacio en el futuro:\n",
460
+ "\n",
461
+ "1. Inicia sesión en HuggingFace.\n",
462
+ "2. En el menú Avatar, selecciona tu perfil.\n",
463
+ "3. Haz clic en el espacio y selecciona la rueda de configuración en la esquina superior derecha.\n",
464
+ "4. Desplázate hasta la sección Eliminar en la parte inferior.\n",
465
+ "5. ADEMÁS: borra el archivo README que Gradio haya creado dentro de la carpeta 1_foundations (de lo contrario, no te hará las preguntas la próxima vez que implementes Gradio)."
466
+ ]
467
+ },
468
+ {
469
+ "cell_type": "markdown",
470
+ "metadata": {},
471
+ "source": [
472
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
473
+ " <tr>\n",
474
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
475
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
476
+ " </td>\n",
477
+ " <td>\n",
478
+ " <h2 style=\"color:#ff7800;\">Ejercicio</h2>\n",
479
+ " <span style=\"color:#ff7800;\">• Ante todo, ¡impleméntalo tú mismo! Es una herramienta real y valiosa: el futuro currículum.<br/>\n",
480
+ "• A continuación, mejora los recursos: añade un mejor contexto sobre ti. Si conoces RAG, añade una base de conocimientos sobre ti.<br/>\n",
481
+ "• ¡Añade más herramientas! Podrías tener una base de datos SQL con preguntas y respuestas comunes que el LLM pueda leer y escribir.<br/>\n",
482
+ "• Incorpora al Evaluador del último laboratorio y añade otros patrones de Agentic.\n",
483
+ "</span>\n",
484
+ " </td>\n",
485
+ " </tr>\n",
486
+ "</table>"
487
+ ]
488
+ },
489
+ {
490
+ "cell_type": "markdown",
491
+ "metadata": {},
492
+ "source": [
493
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
494
+ " <tr>\n",
495
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
496
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
497
+ " </td>\n",
498
+ " <td>\n",
499
+ " <h2 style=\"color:#00bfff;\">Implicaciones Comerciales</h2>\n",
500
+ " <span style=\"color:#00bfff;\">Aparte de lo obvio (tu alter ego profesional), esto tiene aplicaciones comerciales en cualquier situación en la que necesites un asistente de IA con experiencia en el dominio y capacidad para interactuar con el mundo real.\n",
501
+ " </span>\n",
502
+ " </td>\n",
503
+ " </tr>\n",
504
+ "</table>"
505
+ ]
506
+ }
507
+ ],
508
+ "metadata": {
509
+ "kernelspec": {
510
+ "display_name": ".venv",
511
+ "language": "python",
512
+ "name": "python3"
513
+ },
514
+ "language_info": {
515
+ "codemirror_mode": {
516
+ "name": "ipython",
517
+ "version": 3
518
+ },
519
+ "file_extension": ".py",
520
+ "mimetype": "text/x-python",
521
+ "name": "python",
522
+ "nbconvert_exporter": "python",
523
+ "pygments_lexer": "ipython3",
524
+ "version": "3.12.9"
525
+ }
526
+ },
527
+ "nbformat": 4,
528
+ "nbformat_minor": 2
529
+ }
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Cv Consulting
3
- emoji: ⚡
4
- colorFrom: green
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
- pinned: false
 
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: cv_consulting
 
 
 
 
 
3
  app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 5.31.0
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dotenv import load_dotenv
2
+ from openai import OpenAI
3
+ import json
4
+ import os
5
+ import requests
6
+ from pypdf import PdfReader
7
+ import gradio as gr
8
+
9
+
10
+ load_dotenv(override=True)
11
+
12
+ def push(text):
13
+ requests.post(
14
+ "https://api.pushover.net/1/messages.json",
15
+ data={
16
+ "token": os.getenv("PUSHOVER_TOKEN"),
17
+ "user": os.getenv("PUSHOVER_USER"),
18
+ "message": text,
19
+ }
20
+ )
21
+
22
+
23
+ def record_user_details(email, name="Nombre no indicado", notes="no proporcionadas"):
24
+ push(f"Registrando {name} con email {email} y notas {notes}")
25
+ return {"recorded": "ok"}
26
+
27
+ def record_unknown_question(question):
28
+ push(f"Registrando {question}")
29
+ return {"recorded": "ok"}
30
+
31
+ record_user_details_json = {
32
+ "name": "record_user_details",
33
+ "description": "Utiliza esta herramienta para registrar que un usuario está interesado en estar en contacto y proporcionó una dirección de correo electrónico.",
34
+ "parameters": {
35
+ "type": "object",
36
+ "properties": {
37
+ "email": {
38
+ "type": "string",
39
+ "description": "La dirección de email del usuario"
40
+ },
41
+ "name": {
42
+ "type": "string",
43
+ "description": "El nombre del usuario, si se indica"
44
+ }
45
+ ,
46
+ "notes": {
47
+ "type": "string",
48
+ "description": "¿Alguna información adicional sobre la conversación que valga la pena registrar para dar contexto?"
49
+ }
50
+ },
51
+ "required": ["email"],
52
+ "additionalProperties": False
53
+ }
54
+ }
55
+
56
+ record_unknown_question_json = {
57
+ "name": "record_unknown_question",
58
+ "description": "Utiliza siempre esta herramienta para registrar cualquier pregunta que no haya podido responder porque no se sabía la respuesta.",
59
+ "parameters": {
60
+ "type": "object",
61
+ "properties": {
62
+ "question": {
63
+ "type": "string",
64
+ "description": "La pregunta no sabe responderse"
65
+ },
66
+ },
67
+ "required": ["question"],
68
+ "additionalProperties": False
69
+ }
70
+ }
71
+
72
+ tools = [{"type": "function", "function": record_user_details_json},
73
+ {"type": "function", "function": record_unknown_question_json}]
74
+
75
+
76
+ class Me:
77
+
78
+ def __init__(self):
79
+ self.openai = OpenAI()
80
+ self.name = "Alejandro Gonzalez"
81
+ reader = PdfReader("me/linkedin.pdf")
82
+ self.linkedin = ""
83
+ for page in reader.pages:
84
+ text = page.extract_text()
85
+ if text:
86
+ self.linkedin += text
87
+ with open("me/summary.txt", "r", encoding="utf-8") as f:
88
+ self.summary = f.read()
89
+
90
+
91
+ def handle_tool_call(self, tool_calls):
92
+ results = []
93
+ for tool_call in tool_calls:
94
+ tool_name = tool_call.function.name
95
+ arguments = json.loads(tool_call.function.arguments)
96
+ print(f"Tool called: {tool_name}", flush=True)
97
+ tool = globals().get(tool_name)
98
+ result = tool(**arguments) if tool else {}
99
+ results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
100
+ return results
101
+
102
+ def system_prompt(self):
103
+ system_prompt = f"""Actúas como {self.name}. Respondes preguntas en el sitio web de {self.name}, en particular preguntas relacionadas con la trayectoria profesional, los antecedentes, las habilidades y la experiencia de {self.name}.
104
+ Tu responsabilidad es representar a {self.name} en las interacciones del sitio web con la mayor fidelidad posible.
105
+ Se te proporciona un resumen de la trayectoria profesional y el perfil de LinkedIn de {self.name} que puedes usar para responder preguntas.
106
+ Muestra un tono profesional y atractivo, como si hablaras con un cliente potencial o un futuro empleador que haya visitado el sitio web.
107
+ Si no sabes la respuesta a alguna pregunta, usa la herramienta 'record_unknown_question' para registrar la pregunta que no pudiste responder, incluso si se trata de algo trivial o no relacionado con tu trayectoria profesional.
108
+ Si el usuario participa en una conversación, intenta que se ponga en contacto por correo electrónico; pídele su correo electrónico y regístralo con la herramienta 'record_user_details'."""
109
+
110
+ system_prompt += f"\n\n## Resumen:\n{self.summary}\n\n## Perfil de LinkedIn:\n{self.linkedin}\n\n"
111
+ system_prompt += f"En este contexto, por favor chatea con el usuario, manteniéndote siempre en el personaje de {self.name}."
112
+ return system_prompt
113
+
114
+ def chat(self, message, history):
115
+ messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
116
+ done = False
117
+ while not done:
118
+ response = self.openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
119
+ if response.choices[0].finish_reason=="tool_calls":
120
+ message = response.choices[0].message
121
+ tool_calls = message.tool_calls
122
+ results = self.handle_tool_call(tool_calls)
123
+ messages.append(message)
124
+ messages.extend(results)
125
+ else:
126
+ done = True
127
+ return response.choices[0].message.content
128
+
129
+
130
+ if __name__ == "__main__":
131
+ me = Me()
132
+ gr.ChatInterface(me.chat, type="messages").launch()
133
+
me/linkedin.pdf ADDED
Binary file (74.5 kB). View file
 
me/summary.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Me llamo Ronald Alejandro González García, soy de Puerto Boyacá, Colombia, y soy científico de datos. He vivido aquí toda mi vida y disfruto de combinar la tecnología con la creatividad.
2
+ Me apasiona el fútbol, la música salsa y leer en mis tiempos libres.
3
+ Mi comida favorita es el pescado, aunque disfruto probar nuevos sabores y platos locales.
4
+ Además, me gusta programar y crear soluciones que unan el análisis de datos con la innovación.
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ requests
2
+ python-dotenv
3
+ gradio
4
+ pypdf
5
+ openai
6
+ openai-agents