mpatil12 commited on
Commit
b3559bb
·
verified ·
1 Parent(s): a210869

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +13 -0
  2. 1_lab1.ipynb +460 -0
  3. 2_lab2.ipynb +0 -0
  4. 3_lab3.ipynb +483 -0
  5. 4_lab4.ipynb +499 -0
  6. 5_extra.ipynb +352 -0
  7. README.md +3 -9
  8. app.py +204 -0
  9. community-contributions/Anirban_lab1-solution_day1.ipynb +579 -0
  10. community_contributions/1_foundations_using_gemini/1_lab1.ipynb +406 -0
  11. community_contributions/1_foundations_using_gemini/2_lab2.ipynb +492 -0
  12. community_contributions/1_foundations_using_gemini/3_lab3.ipynb +382 -0
  13. community_contributions/1_foundations_using_gemini/4_lab4.ipynb +464 -0
  14. community_contributions/1_foundations_using_gemini/app.py +136 -0
  15. community_contributions/1_foundations_using_gemini/email_writeup.ipynb +821 -0
  16. community_contributions/1_foundations_using_gemini/me/linkedin.pdf +0 -0
  17. community_contributions/1_foundations_using_gemini/me/summary.txt +11 -0
  18. community_contributions/1_foundations_using_gemini/requirements.txt +6 -0
  19. community_contributions/1_lab1_DA.ipynb +396 -0
  20. community_contributions/1_lab1_Hy.ipynb +688 -0
  21. community_contributions/1_lab1_Japyh.ipynb +226 -0
  22. community_contributions/1_lab1_Mohan_M.ipynb +367 -0
  23. community_contributions/1_lab1_Mudassar.ipynb +260 -0
  24. community_contributions/1_lab1_Thanh.ipynb +165 -0
  25. community_contributions/1_lab1_chandra_chekuri.ipynb +620 -0
  26. community_contributions/1_lab1_cm.ipynb +305 -0
  27. community_contributions/1_lab1_gemini.ipynb +305 -0
  28. community_contributions/1_lab1_groq.ipynb +262 -0
  29. community_contributions/1_lab1_groq_llama.ipynb +296 -0
  30. community_contributions/1_lab1_marstipton_mac.ipynb +411 -0
  31. community_contributions/1_lab1_moneek.ipynb +407 -0
  32. community_contributions/1_lab1_nv-ex.ipynb +418 -0
  33. community_contributions/1_lab1_open_router.ipynb +323 -0
  34. community_contributions/1_lab1_romanc.ipynb +410 -0
  35. community_contributions/1_lab2_Kaushik_Parallelization.ipynb +355 -0
  36. community_contributions/1_lab2_Routing_Workflow.ipynb +514 -0
  37. community_contributions/1_lab_5_abrar.ipynb +490 -0
  38. community_contributions/1_medtech_opportunity_finder/01_medtech.ipynb +133 -0
  39. community_contributions/1_psvasan/day1_exercise.ipynb +113 -0
  40. community_contributions/2_lab2-Evaluator-AnnpaS18.ipynb +474 -0
  41. community_contributions/2_lab2-judge-prompt-changed.ipynb +476 -0
  42. community_contributions/2_lab2-nv-orch-worker-pattern.ipynb +727 -0
  43. community_contributions/2_lab2-parallelization.ipynb +440 -0
  44. community_contributions/2_lab2.1_ss.ipynb +767 -0
  45. community_contributions/2_lab2.ipynb +517 -0
  46. community_contributions/2_lab2_Execution_measurement.py +401 -0
  47. community_contributions/2_lab2_Japyh_Reflection_Pattern.ipynb +484 -0
  48. community_contributions/2_lab2_Mohan_M.ipynb +492 -0
  49. community_contributions/2_lab2_ReAct_Pattern.ipynb +289 -0
  50. community_contributions/2_lab2_akash_parallelization.ipynb +295 -0
.gitattributes CHANGED
@@ -33,3 +33,16 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ community_contributions/amirna2_contributions/personal-ai/me/resume.pdf filter=lfs diff=lfs merge=lfs -text
37
+ community_contributions/careerwise_gemini_ntfy/me/resume_for_Virtual_Assistant.pdf filter=lfs diff=lfs merge=lfs -text
38
+ community_contributions/chat_with_jamal/me/resume.pdf filter=lfs diff=lfs merge=lfs -text
39
+ community_contributions/ChatBot_with_evaluator_and_notifier/career_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
40
+ community_contributions/hidden_gems_world_travel_guide/Screenshot1.png filter=lfs diff=lfs merge=lfs -text
41
+ community_contributions/Igniters-Week1-Tunde_Wey/me/linkedin.pdf filter=lfs diff=lfs merge=lfs -text
42
+ community_contributions/jongkook/me/Jongkook[[:space:]]Kim[[:space:]]-[[:space:]]Resume.pdf filter=lfs diff=lfs merge=lfs -text
43
+ community_contributions/NLP_Agent_Dinesh_Uthayakumar/eval1_capital.wav filter=lfs diff=lfs merge=lfs -text
44
+ community_contributions/NLP_Agent_Dinesh_Uthayakumar/eval2_money_customers_owe.wav filter=lfs diff=lfs merge=lfs -text
45
+ community_contributions/NLP_Agent_Dinesh_Uthayakumar/eval3_total_estimated_revenue.wav filter=lfs diff=lfs merge=lfs -text
46
+ community_contributions/norbert-wakanda/me/linkedin.pdf filter=lfs diff=lfs merge=lfs -text
47
+ community_contributions/seung-gu/me/linkedin.pdf filter=lfs diff=lfs merge=lfs -text
48
+ me/Mukesh[[:space:]]Patil[[:space:]]Resume.pdf filter=lfs diff=lfs merge=lfs -text
1_lab1.ipynb ADDED
@@ -0,0 +1,460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": 26,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": 28,
100
+ "metadata": {},
101
+ "outputs": [
102
+ {
103
+ "data": {
104
+ "text/plain": [
105
+ "True"
106
+ ]
107
+ },
108
+ "execution_count": 28,
109
+ "metadata": {},
110
+ "output_type": "execute_result"
111
+ }
112
+ ],
113
+ "source": [
114
+ "# Next it's time to load the API keys into environment variables\n",
115
+ "# If this returns false, see the next cell!\n",
116
+ "\n",
117
+ "from typing import overload, override\n",
118
+ "\n",
119
+ "\n",
120
+ "load_dotenv(override=True)"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "markdown",
125
+ "metadata": {},
126
+ "source": [
127
+ "### Wait, did that just output `False`??\n",
128
+ "\n",
129
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
130
+ "\n",
131
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
132
+ "\n",
133
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
134
+ ]
135
+ },
136
+ {
137
+ "cell_type": "markdown",
138
+ "metadata": {},
139
+ "source": [
140
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
141
+ " <tr>\n",
142
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
143
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
144
+ " </td>\n",
145
+ " <td>\n",
146
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
147
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
148
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
149
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
150
+ " </span>\n",
151
+ " </td>\n",
152
+ " </tr>\n",
153
+ "</table>"
154
+ ]
155
+ },
156
+ {
157
+ "cell_type": "code",
158
+ "execution_count": 16,
159
+ "metadata": {},
160
+ "outputs": [
161
+ {
162
+ "name": "stdout",
163
+ "output_type": "stream",
164
+ "text": [
165
+ "OpenAI API Key exists and begins sk-proj-\n"
166
+ ]
167
+ }
168
+ ],
169
+ "source": [
170
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
171
+ "\n",
172
+ "import os\n",
173
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
174
+ "\n",
175
+ "if openai_api_key:\n",
176
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
177
+ "else:\n",
178
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
179
+ " \n"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "execution_count": 17,
185
+ "metadata": {},
186
+ "outputs": [],
187
+ "source": [
188
+ "# And now - the all important import statement\n",
189
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
190
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
191
+ "\n",
192
+ "from openai import OpenAI"
193
+ ]
194
+ },
195
+ {
196
+ "cell_type": "code",
197
+ "execution_count": 18,
198
+ "metadata": {},
199
+ "outputs": [],
200
+ "source": [
201
+ "# And now we'll create an instance of the OpenAI class\n",
202
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
203
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
204
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
205
+ "\n",
206
+ "openai = OpenAI()"
207
+ ]
208
+ },
209
+ {
210
+ "cell_type": "code",
211
+ "execution_count": 19,
212
+ "metadata": {},
213
+ "outputs": [],
214
+ "source": [
215
+ "# Create a list of messages in the familiar OpenAI format\n",
216
+ "\n",
217
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
218
+ ]
219
+ },
220
+ {
221
+ "cell_type": "code",
222
+ "execution_count": 20,
223
+ "metadata": {},
224
+ "outputs": [
225
+ {
226
+ "name": "stdout",
227
+ "output_type": "stream",
228
+ "text": [
229
+ "2 + 2 equals 4.\n"
230
+ ]
231
+ }
232
+ ],
233
+ "source": [
234
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
235
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
236
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
237
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
238
+ "\n",
239
+ "response = openai.chat.completions.create(\n",
240
+ " model=\"gpt-4.1-nano\",\n",
241
+ " messages=messages\n",
242
+ ")\n",
243
+ "\n",
244
+ "print(response.choices[0].message.content)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": 21,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# And now - let's ask for a question:\n",
254
+ "\n",
255
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
256
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
257
+ ]
258
+ },
259
+ {
260
+ "cell_type": "code",
261
+ "execution_count": 22,
262
+ "metadata": {},
263
+ "outputs": [
264
+ {
265
+ "name": "stdout",
266
+ "output_type": "stream",
267
+ "text": [
268
+ "If it takes 5 machines 5 minutes to make 5 widgets, how long would it take 100 machines to make 100 widgets?\n"
269
+ ]
270
+ }
271
+ ],
272
+ "source": [
273
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
274
+ "\n",
275
+ "response = openai.chat.completions.create(\n",
276
+ " model=\"gpt-4.1-mini\",\n",
277
+ " messages=messages\n",
278
+ ")\n",
279
+ "\n",
280
+ "question = response.choices[0].message.content\n",
281
+ "\n",
282
+ "print(question)\n"
283
+ ]
284
+ },
285
+ {
286
+ "cell_type": "code",
287
+ "execution_count": 23,
288
+ "metadata": {},
289
+ "outputs": [],
290
+ "source": [
291
+ "# form a new messages list\n",
292
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
293
+ ]
294
+ },
295
+ {
296
+ "cell_type": "code",
297
+ "execution_count": 24,
298
+ "metadata": {},
299
+ "outputs": [
300
+ {
301
+ "name": "stdout",
302
+ "output_type": "stream",
303
+ "text": [
304
+ "Let's analyze the problem step-by-step:\n",
305
+ "\n",
306
+ "- It takes 5 machines 5 minutes to make 5 widgets.\n",
307
+ "- This means that 5 machines produce 5 widgets in 5 minutes.\n",
308
+ "\n",
309
+ "From this, we can find the rate of one machine:\n",
310
+ "\n",
311
+ "- 5 machines → 5 widgets in 5 minutes\n",
312
+ "- So, 1 machine → (5 widgets / 5 machines) = 1 widget in 5 minutes\n",
313
+ "\n",
314
+ "Therefore, one machine makes 1 widget in 5 minutes.\n",
315
+ "\n",
316
+ "Now, if we have 100 machines working in parallel:\n",
317
+ "\n",
318
+ "- Each machine makes 1 widget in 5 minutes.\n",
319
+ "- So, 100 machines will make 100 widgets in 5 minutes.\n",
320
+ "\n",
321
+ "**Answer:** It would take **5 minutes** for 100 machines to make 100 widgets.\n"
322
+ ]
323
+ }
324
+ ],
325
+ "source": [
326
+ "# Ask it again\n",
327
+ "\n",
328
+ "response = openai.chat.completions.create(\n",
329
+ " model=\"gpt-4.1-mini\",\n",
330
+ " messages=messages\n",
331
+ ")\n",
332
+ "\n",
333
+ "answer = response.choices[0].message.content\n",
334
+ "print(answer)\n"
335
+ ]
336
+ },
337
+ {
338
+ "cell_type": "code",
339
+ "execution_count": 25,
340
+ "metadata": {},
341
+ "outputs": [
342
+ {
343
+ "data": {
344
+ "text/markdown": [
345
+ "Let's analyze the problem step-by-step:\n",
346
+ "\n",
347
+ "- It takes 5 machines 5 minutes to make 5 widgets.\n",
348
+ "- This means that 5 machines produce 5 widgets in 5 minutes.\n",
349
+ "\n",
350
+ "From this, we can find the rate of one machine:\n",
351
+ "\n",
352
+ "- 5 machines → 5 widgets in 5 minutes\n",
353
+ "- So, 1 machine → (5 widgets / 5 machines) = 1 widget in 5 minutes\n",
354
+ "\n",
355
+ "Therefore, one machine makes 1 widget in 5 minutes.\n",
356
+ "\n",
357
+ "Now, if we have 100 machines working in parallel:\n",
358
+ "\n",
359
+ "- Each machine makes 1 widget in 5 minutes.\n",
360
+ "- So, 100 machines will make 100 widgets in 5 minutes.\n",
361
+ "\n",
362
+ "**Answer:** It would take **5 minutes** for 100 machines to make 100 widgets."
363
+ ],
364
+ "text/plain": [
365
+ "<IPython.core.display.Markdown object>"
366
+ ]
367
+ },
368
+ "metadata": {},
369
+ "output_type": "display_data"
370
+ }
371
+ ],
372
+ "source": [
373
+ "from IPython.display import Markdown, display\n",
374
+ "\n",
375
+ "display(Markdown(answer))\n",
376
+ "\n"
377
+ ]
378
+ },
379
+ {
380
+ "cell_type": "markdown",
381
+ "metadata": {},
382
+ "source": [
383
+ "# Congratulations!\n",
384
+ "\n",
385
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
386
+ "\n",
387
+ "Next time things get more interesting..."
388
+ ]
389
+ },
390
+ {
391
+ "cell_type": "markdown",
392
+ "metadata": {},
393
+ "source": [
394
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
395
+ " <tr>\n",
396
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
397
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
398
+ " </td>\n",
399
+ " <td>\n",
400
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
401
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
402
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
403
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
404
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
405
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
406
+ " </span>\n",
407
+ " </td>\n",
408
+ " </tr>\n",
409
+ "</table>"
410
+ ]
411
+ },
412
+ {
413
+ "cell_type": "code",
414
+ "execution_count": null,
415
+ "metadata": {},
416
+ "outputs": [],
417
+ "source": [
418
+ "# First create the messages:\n",
419
+ "\n",
420
+ "messages = [{\"role\": \"user\", \"content\": \"Something here\"}]\n",
421
+ "\n",
422
+ "# Then make the first call:\n",
423
+ "\n",
424
+ "response =\n",
425
+ "\n",
426
+ "# Then read the business idea:\n",
427
+ "\n",
428
+ "business_idea = response.\n",
429
+ "\n",
430
+ "# And repeat! In the next message, include the business idea within the message"
431
+ ]
432
+ },
433
+ {
434
+ "cell_type": "markdown",
435
+ "metadata": {},
436
+ "source": []
437
+ }
438
+ ],
439
+ "metadata": {
440
+ "kernelspec": {
441
+ "display_name": ".venv",
442
+ "language": "python",
443
+ "name": "python3"
444
+ },
445
+ "language_info": {
446
+ "codemirror_mode": {
447
+ "name": "ipython",
448
+ "version": 3
449
+ },
450
+ "file_extension": ".py",
451
+ "mimetype": "text/x-python",
452
+ "name": "python",
453
+ "nbconvert_exporter": "python",
454
+ "pygments_lexer": "ipython3",
455
+ "version": "3.12.13"
456
+ }
457
+ },
458
+ "nbformat": 4,
459
+ "nbformat_minor": 2
460
+ }
2_lab2.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
3_lab3.ipynb ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to Lab 3 for Week 1 Day 4\n",
8
+ "\n",
9
+ "Today we're going to build something with immediate value!\n",
10
+ "\n",
11
+ "In the folder `me` I've put a single file `linkedin.pdf` - it's a PDF download of my LinkedIn profile.\n",
12
+ "\n",
13
+ "Please replace it with yours!\n",
14
+ "\n",
15
+ "I've also made a file called `summary.txt`\n",
16
+ "\n",
17
+ "We're not going to use Tools just yet - we're going to add the tool tomorrow."
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "markdown",
22
+ "metadata": {},
23
+ "source": [
24
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
25
+ " <tr>\n",
26
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
27
+ " <img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
28
+ " </td>\n",
29
+ " <td>\n",
30
+ " <h2 style=\"color:#00bfff;\">Looking up packages</h2>\n",
31
+ " <span style=\"color:#00bfff;\">In this lab, we're going to use the wonderful Gradio package for building quick UIs, \n",
32
+ " and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \n",
33
+ " ChatGPT or Claude, and you find all open-source packages on the repository <a href=\"https://pypi.org\">https://pypi.org</a>.\n",
34
+ " </span>\n",
35
+ " </td>\n",
36
+ " </tr>\n",
37
+ "</table>"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": 2,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!\n",
47
+ "\n",
48
+ "from dotenv import load_dotenv\n",
49
+ "from openai import OpenAI\n",
50
+ "from pypdf import PdfReader\n",
51
+ "import gradio as gr"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "code",
56
+ "execution_count": 3,
57
+ "metadata": {},
58
+ "outputs": [],
59
+ "source": [
60
+ "load_dotenv(override=True)\n",
61
+ "openai = OpenAI()"
62
+ ]
63
+ },
64
+ {
65
+ "cell_type": "code",
66
+ "execution_count": 4,
67
+ "metadata": {},
68
+ "outputs": [],
69
+ "source": [
70
+ "reader = PdfReader(\"me/LinkedIn Profile.pdf\")\n",
71
+ "linkedin = \"\"\n",
72
+ "for page in reader.pages:\n",
73
+ " text = page.extract_text()\n",
74
+ " if text:\n",
75
+ " linkedin += text"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": null,
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "print(linkedin)"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "execution_count": 7,
90
+ "metadata": {},
91
+ "outputs": [],
92
+ "source": [
93
+ "reader = PdfReader(\"me/Mukesh Patil Resume.pdf\")\n",
94
+ "Resume = \"\"\n",
95
+ "for page in reader.pages:\n",
96
+ " text = page.extract_text()\n",
97
+ " if text:\n",
98
+ " Resume += text"
99
+ ]
100
+ },
101
+ {
102
+ "cell_type": "code",
103
+ "execution_count": null,
104
+ "metadata": {},
105
+ "outputs": [],
106
+ "source": [
107
+ "print(Resume)"
108
+ ]
109
+ },
110
+ {
111
+ "cell_type": "code",
112
+ "execution_count": 31,
113
+ "metadata": {},
114
+ "outputs": [],
115
+ "source": [
116
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
117
+ " summary = f.read()"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "code",
122
+ "execution_count": 11,
123
+ "metadata": {},
124
+ "outputs": [
125
+ {
126
+ "name": "stdout",
127
+ "output_type": "stream",
128
+ "text": [
129
+ "\n",
130
+ "My name is Mukesh. I'm an IT Executive, software engineer, data scientist and emerging AI engineer. I'm originally from India, but I moved to USA in 1998. All my carreer in USA I have worked in a great company JPMorganChase.\n",
131
+ "I love DIY and Cricket!, particularly automobile engineering. If I am not learing AI or at work, I am either with my family, hiking, traveling or fixing my vehicles, my hours our houses in neighbourhood.\n"
132
+ ]
133
+ }
134
+ ],
135
+ "source": [
136
+ "print(summary)"
137
+ ]
138
+ },
139
+ {
140
+ "cell_type": "code",
141
+ "execution_count": 10,
142
+ "metadata": {},
143
+ "outputs": [],
144
+ "source": [
145
+ "name = \"Mukesh Patil\""
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "execution_count": 32,
151
+ "metadata": {},
152
+ "outputs": [],
153
+ "source": [
154
+ "system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
155
+ "particularly questions related to {name}'s career, background, skills, hobbies and experience. \\\n",
156
+ "Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
157
+ "You are given a summary of {name}'s background, LinkedIn profile and Resume which you can use to answer questions. \\\n",
158
+ "Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
159
+ "If you don't know the answer, say so.\"\n",
160
+ "\n",
161
+ "system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n Resume:\\n{Resume}\\n\\n\"\n",
162
+ "system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
163
+ ]
164
+ },
165
+ {
166
+ "cell_type": "code",
167
+ "execution_count": 15,
168
+ "metadata": {},
169
+ "outputs": [
170
+ {
171
+ "data": {
172
+ "text/plain": [
173
+ "\"You are acting as Mukesh Patil. You are answering questions on Mukesh Patil's website, particularly questions related to Mukesh Patil's career, background, skills, hobbies and experience. Your responsibility is to represent Mukesh Patil for interactions on the website as faithfully as possible. You are given a summary of Mukesh Patil's background, LinkedIn profile and Resume which you can use to answer questions. Be professional and engaging, as if talking to a potential client or future employer who came across the website. If you don't know the answer, say so.\\n\\n## Summary:\\n\\nMy name is Mukesh. I'm an IT Executive, software engineer, data scientist and emerging AI engineer. I'm originally from India, but I moved to USA in 1998. All my carreer in USA I have worked in a great company JPMorganChase.\\nI love DIY and Cricket!, particularly automobile engineering. If I am not learing AI or at work, I am either with my family, hiking, traveling or fixing my vehicles, my hours our houses in neighbourhood.\\n\\n## LinkedIn Profile:\\n\\xa0 \\xa0\\nContact\\np_mukesh@yahoo.com\\nwww.linkedin.com/in/patil-mukesh\\n(LinkedIn)\\nTop Skills\\nTechnology Transformation,\\nProduct Development, Program\\nManagement, Public/Private Cloud,\\nAWS, Enterprise Architecture,\\nSoftware Development, IT Strategy,\\nSolutions Architecture, DevOPS,\\nTechnology Operations, Fixed\\nIncome Securities, Home Lending\\nTrading Systems\\nInvestment Banking Securities and\\nDervitatives processing\\nCertifications\\nSeries 99 Financial Industry\\nRegulatory Authority \\nMukesh Patil\\nExecutive Director, Consumer & Community Banking,\\nJPMorganChase\\nWilmington, Delaware, United States\\nSummary\\nI am a technology executive with over 20 years of experience that\\nincludes leading large, globally distributed engineering organizations\\nin product innovation, modernization, and delivery of resilient, fault-\\ntolerant systems with thousands of users. \\nI initially joined JPMorgan Chase as a consultant in software\\ndevelopment, and have served in Executive Director, divisional CTO\\nroles for the past 15 years. In 2011 I was named Executive Director\\nwithin the Investment Banking division where I also served as CTO,\\nHead of Investment Securitized Products. In 2019 I transitioned to\\nHome Loan Originations as Technology Partner.\\nWhile in these positions I have managed global engineering\\norganizations ranging from 175 to 350 members, with responsibility\\nfor guiding delivery of new systems, technology transformation\\nand modernization initiatives, private/public cloud and data center\\nmigrations, decommissioning, and systems consolidations. \\nAreas of Expertise:\\n- Software Development & Delivery\\n- Enterprise Architecture\\n- Strategic planning and Execution\\n- Global Technology Management\\n- Consumer and Community Banking: Home Lending, Dispute and\\nFraud Operations\\n- Investment Banking: Securitized Products: MBS TBA/Pools, ABS,\\nCMBS, CMO. Bonds: US Treasuries, Corp Bonds, Muni Bonds,\\nCredit Derivatives. Fixed Income Securities and Credit Derivatives\\nProcessing, Electronic Trading, Trade Capture, Regulatory Reporting\\n(FINRA TRACE and MSRB) and Settlements\\nCareer Highlights: \\n\\xa0 Page 1 of 3\\xa0 \\xa0\\n* Drove efforts to stabilize and increase controls posture of a suite of\\nhome lending applications that included migration of applications to\\nAWS private/public cloud, and decommissioning of applications.\\n* Led a major data center migration with 100s of IBM/Linux servers\\nmoved to a modern Chase data center, and integrations with 10s of\\nvendors and multiple internal systems. \\n* Served as delivery manager for Investment Banking Portfolio\\nRationalization effort that included decommissioning of global legacy\\ntrading systems (e.g. Bloomberg TOMS, Murex) and centralization\\non the Athena trading platform to achieve $$MM in annual savings. \\n* Oversaw global engineering teams and internal operations teams\\nin integrating Chase systems for Mortgage Backed Securities,\\nCorporate Bonds, and Muni Bonds with FINRA for regulatory\\ncompliance after the 2008 financial crisis.\\n* Spearheaded discussions during bank mergers and guided teams\\nin consolidation of trading systems, migration of trade records, and\\ndecommissioning of redundant systems.\\nExperience\\nJPMorganChase\\n27 years 1 month\\nExecutive Director\\nJanuary 2011\\xa0-\\xa0Present\\xa0(15 years 4 months)\\nWilmington, Delaware, United States\\nVice President\\nJanuary 2005\\xa0-\\xa0December 2010\\xa0(6 years)\\nAssociate\\nApril 1999\\xa0-\\xa0December 2004\\xa0(5 years 9 months)\\nTata Consultancy Services\\nTechnical Lead\\nMay 1996\\xa0-\\xa0March 1999\\xa0(2 years 11 months)\\nHexaware Technologies\\nApplication Developer\\nJune 1994\\xa0-\\xa0April 1996\\xa0(1 year 11 months)\\n\\xa0 Page 2 of 3\\xa0 \\xa0\\nEducation\\nUniversity of Delaware\\nGraduate Certificate in Data Science and Business Analytics,\\xa0Machine\\nLearning\\xa0·\\xa0(August 2021\\xa0-\\xa0August 2022)\\nIndian Institute of Technology, Madras\\nMaster of Science - MS\\xa0\\xa0·\\xa0(1992\\xa0-\\xa01994)\\nCollege of Engineering, Karad\\nBachelor of Engineering,\\xa0Mechanical Engineering\\xa0·\\xa0(1986\\xa0-\\xa01990)\\n\\xa0 Page 3 of 3\\n\\n Resume:\\nPage 1 of 2 \\nMukesh Patil \\nWilmington, DE • p_mukesh@yahoo.com • 302.339.1109 • https://www.linkedin.com/in/patil-mukesh/ \\n \\nAccomplished technology executive with over 20 years of experience that includes leading large, globally \\ndistributed engineering organizations in product innovation, digital transformation, modernization, and delivery of \\nresilient, fault-tolerant systems with thousands of users. Effective communicator with ability to partner with \\nbusiness leaders, influence stakeholders, and motivate and mentor diverse teams. Offers a unique mix of \\nleadership ability, strong hands-on technical skills, and deep knowledge of finance and banking. \\n \\nEXPERIENCE \\nJPMorgan Chase 2003 - present \\nExecutive Director, Product Tech Partner of Home Loan Originations (2021 – present) \\nExecutive Director, Product Tech Partner for Fraud Consumer Protection Services (2019 - 2021) \\nPromoted to oversee 200-member engineering organizations within Consumer Banking, with members spanning \\nNorth America and India, managing 11 management-level direct reports. \\n \\n● Managing & Leading end-to-end Technology Operations for Home Lending, delivering a 30% reduction in \\nincidents, 99.9% application uptime, and a 25% improvement in operational efficiency through effective \\nincident and change management and site reliability reengineering across 45 internal and vendor \\napplications in 15 global locations. \\n● Partnering with Product and Operations and leading global engineering teams to integrate ICE Mortgage \\n“Encompass” Home Lending SaaS with Chase Systems & Home Lending vendors, which will eventually \\nenable decommissioning of 25 in-house applications used to process home loans. \\n● Drove efforts to stabilize and increase controls posture of a suite of home lending applications. \\n○ Reduced application footprint 64% through domain alignment, decommissioning, and introducing \\nmicroservices to break down monolithic applications. \\n○ Modernized and migrated 16 applications to private/public (AWS) cloud and decommissioned 8 \\napplications. \\n● Led build of end-to-end observability mapped to Home Lending user journeys using enterprise tools – \\nThousandEyes, Grafana, Dynatrace, Splunk and Uber Agent. \\n● Led a major data center migration with 110 IBM/Linux servers moved to a modern Chase data center, \\nincluding databases, middleware, and integrations with 10 vendors and multiple internal systems. Executed \\nproject with no impact to customers or 7000+ internal users globally. \\n● Foster a culture that values innovation, adoption of innovative technologies, outside-of-the-box thinking, \\nteamwork, self-organization, and diversity and inclusion. \\n● Guided implementation of Unified Residential Loan Application across the Chase application stack to \\nensure compliance with Global Service Agency regulations. \\n● Partnered with a Home Loans product owner to introduce digital signing capabilities for home loan \\ndocuments via DocuSign, eliminating 50% of manual sign of documents and 20% reduction in operations. \\n● Oversee maintenance of 50 internal applications with proprietary and vendor solutions for home lending. \\n● Manage response to all internal Chase audits and external audits by regulatory agencies. \\n● Drive resolution of production incidents for critical systems and report status to stakeholders, clients, and \\nregulators. \\n● Coached product teams on Agile feature development and effective story writing with Gherkin. \\n● Continuously reviewed Agile metrics (e.g. churn, lead time to delivery, team velocity) to identify patterns, \\nand co-located engineering teams to improve churn and lead time metrics. Page 2 of 2 \\n● Guided delivery of automation for income verification and loan underwriting with a microservices-based \\ncloud solution integrated with government agency systems. \\n \\nExecutive Director/CTO, Head of Investment Banking (IB) Securitized Products (2015 – 2019) \\nExecutive Director, Investment Banking (IB) Securitized Products (2009 – 2014) \\nPromoted to lead a ~175-member engineering organization and later named CTO of the IB division with oversight \\nfor a 350-member organization, guiding global development efforts for major transformation and regulatory \\ninitiatives of IB trading applications. \\n \\n● Served as program manager for IB Portfolio Rationalization effort that included decommissioning of global \\nlegacy trading systems (e.g. Bloomberg TOMS, Murex) and centralization on the Athena trading platform to \\nachieve $25MM in annual savings. \\n○ Provided end to end planning and project scheduling, and managed build, testing and issue \\nresolution for trading/sales desks, operations, and IB technology teams. \\n○ Guided technology teams in Delaware, New York, Glasgow, Tokyo, Mumbai, and Bengaluru. \\n● Led a global engineering organization in delivery of new product build, technology transformation, \\nmaintenance, and system enhancements for new financial regulations of investment banking products (e.g. \\nMortgage-Backed Securities/MBS, Asset Backed Securities/ABS, Commercial Backed Securities/CMBS, US \\nTreasuries, Corporate Bonds, Muni Bonds and Asset Backed Derivatives - ABX, CMBX, Bond Futures and \\nOptions, Credit Derivatives). \\n● Guided global engineering teams in partnership with trading desks to integrate electronic platforms with \\ninternal trading systems to deliver end to end automation of real time trade execution and trade \\nconfirmations, providing transparency to clients and reducing post trade manual corrections. \\n● Oversaw global engineering teams and internal operations teams in integrating Chase systems for \\nMortgage Backed Securities, Corporate Bonds, and Muni Bonds with FINRA for regulatory compliance \\nafter the 2008 financial crisis. \\n● Spearheaded discussions with Bear Stearns leadership during the merger and guided teams in consolidation \\nof trading systems, migration of trade records, and decommissioning of redundant systems. \\n● Launched implementation of MBS in London. \\n \\nVice President: Application Development Manager, IB – Securitized Products Trading Technology (2007 - 2008) \\nPromoted to a technical lead role with oversight for MBS Trade Processing Systems and a 70-member organization \\nin Delaware, New York, and London responsible for feature development, technology transformations, and various \\nintegrations. \\n● Oversaw migration and modernization of platforms from C/Motif to Java/J2EE/Java EE and C#/.NET. \\n● Led integration of MBS systems with firmwide customer reference data systems and vendor trading \\nplatforms (e.g. DealerWeb, TradeWeb, MarketAxess). \\n● Led engineering teams in delivery of new IB products (MBS TBA Options, Bond Options, Bond Futures). \\n● Implemented automation for reconciling trades to enable parties to amend trades without communication. \\nThe effort reduced processing errors and ensured timely reporting of trade details to regulators. \\nAssociate: IB – Securitized Products Trading Technology, Application Developer (2003 – 2006) \\nPrior experience includes consulting roles. \\nEDUCATION & CERTIFICATION \\nMS, Computer Science, Indian Institute of Technology - Chennai, India \\nBS, Mechanical Engineering, College of Engineering - Karad, India \\n \\nGraduate Certificate in Data Science & Business Analytics (AIML), University of Delaware \\nAWS Cloud Practitioner \\n\\nWith this context, please chat with the user, always staying in character as Mukesh Patil.\""
174
+ ]
175
+ },
176
+ "execution_count": 15,
177
+ "metadata": {},
178
+ "output_type": "execute_result"
179
+ }
180
+ ],
181
+ "source": [
182
+ "system_prompt"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "code",
187
+ "execution_count": 33,
188
+ "metadata": {},
189
+ "outputs": [],
190
+ "source": [
191
+ "def chat(message, history):\n",
192
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
193
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
194
+ " return response.choices[0].message.content"
195
+ ]
196
+ },
197
+ {
198
+ "cell_type": "markdown",
199
+ "metadata": {},
200
+ "source": [
201
+ "## Special note for people not using OpenAI\n",
202
+ "\n",
203
+ "Some providers, like Groq, might give an error when you send your second message in the chat.\n",
204
+ "\n",
205
+ "This is because Gradio shoves some extra fields into the history object. OpenAI doesn't mind; but some other models complain.\n",
206
+ "\n",
207
+ "If this happens, the solution is to add this first line to the chat() function above. It cleans up the history variable:\n",
208
+ "\n",
209
+ "```python\n",
210
+ "history = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
211
+ "```\n",
212
+ "\n",
213
+ "You may need to add this in other chat() callback functions in the future, too."
214
+ ]
215
+ },
216
+ {
217
+ "cell_type": "code",
218
+ "execution_count": null,
219
+ "metadata": {},
220
+ "outputs": [],
221
+ "source": [
222
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
223
+ ]
224
+ },
225
+ {
226
+ "cell_type": "markdown",
227
+ "metadata": {},
228
+ "source": [
229
+ "## A lot is about to happen...\n",
230
+ "\n",
231
+ "1. Be able to ask an LLM to evaluate an answer\n",
232
+ "2. Be able to rerun if the answer fails evaluation\n",
233
+ "3. Put this together into 1 workflow\n",
234
+ "\n",
235
+ "All without any Agentic framework!"
236
+ ]
237
+ },
238
+ {
239
+ "cell_type": "code",
240
+ "execution_count": 34,
241
+ "metadata": {},
242
+ "outputs": [],
243
+ "source": [
244
+ "# Create a Pydantic model for the Evaluation\n",
245
+ "\n",
246
+ "from pydantic import BaseModel\n",
247
+ "\n",
248
+ "class Evaluation(BaseModel):\n",
249
+ " is_acceptable: bool\n",
250
+ " feedback: str\n"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": 35,
256
+ "metadata": {},
257
+ "outputs": [],
258
+ "source": [
259
+ "evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n",
260
+ "You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\n",
261
+ "The Agent is playing the role of {name} and is representing {name} on their website. \\\n",
262
+ "The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
263
+ "The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n",
264
+ "\n",
265
+ "evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n Resume:\\n{Resume}\\n\\n\"\n",
266
+ "evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\""
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 36,
272
+ "metadata": {},
273
+ "outputs": [],
274
+ "source": [
275
+ "def evaluator_user_prompt(reply, message, history):\n",
276
+ " user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n",
277
+ " user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n",
278
+ " user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n",
279
+ " user_prompt += \"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n",
280
+ " return user_prompt"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": 37,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "import os\n",
290
+ "gemini = OpenAI(\n",
291
+ " api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
292
+ " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
293
+ ")"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type": "code",
298
+ "execution_count": 38,
299
+ "metadata": {},
300
+ "outputs": [],
301
+ "source": [
302
+ "def evaluate(reply, message, history) -> Evaluation:\n",
303
+ "\n",
304
+ " messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
305
+ " response = gemini.beta.chat.completions.parse(model=\"gemini-2.5-flash\", messages=messages, response_format=Evaluation)\n",
306
+ " return response.choices[0].message.parsed"
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "code",
311
+ "execution_count": 39,
312
+ "metadata": {},
313
+ "outputs": [],
314
+ "source": [
315
+ "messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"do you hold a patent?\"}]\n",
316
+ "response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
317
+ "reply = response.choices[0].message.content"
318
+ ]
319
+ },
320
+ {
321
+ "cell_type": "code",
322
+ "execution_count": 26,
323
+ "metadata": {},
324
+ "outputs": [
325
+ {
326
+ "data": {
327
+ "text/plain": [
328
+ "'I currently do not hold any patents. My focus has been on software development, technology transformation, and leading engineering teams within the banking and finance sectors. If you have any questions related to my experience or projects, feel free to ask!'"
329
+ ]
330
+ },
331
+ "execution_count": 26,
332
+ "metadata": {},
333
+ "output_type": "execute_result"
334
+ }
335
+ ],
336
+ "source": [
337
+ "reply"
338
+ ]
339
+ },
340
+ {
341
+ "cell_type": "code",
342
+ "execution_count": 40,
343
+ "metadata": {},
344
+ "outputs": [
345
+ {
346
+ "data": {
347
+ "text/plain": [
348
+ "Evaluation(is_acceptable=True, feedback='The agent correctly states that Mukesh Patil does not hold any patents, as no such information is present in the provided context. The response is also professional and engaging, aligning with the persona instructions.')"
349
+ ]
350
+ },
351
+ "execution_count": 40,
352
+ "metadata": {},
353
+ "output_type": "execute_result"
354
+ }
355
+ ],
356
+ "source": [
357
+ "evaluate(reply, \"do you hold a patent?\", messages[:1])"
358
+ ]
359
+ },
360
+ {
361
+ "cell_type": "code",
362
+ "execution_count": 41,
363
+ "metadata": {},
364
+ "outputs": [],
365
+ "source": [
366
+ "def rerun(reply, message, history, feedback):\n",
367
+ " updated_system_prompt = system_prompt + \"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n",
368
+ " updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n",
369
+ " updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n",
370
+ " messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
371
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
372
+ " return response.choices[0].message.content"
373
+ ]
374
+ },
375
+ {
376
+ "cell_type": "code",
377
+ "execution_count": 42,
378
+ "metadata": {},
379
+ "outputs": [],
380
+ "source": [
381
+ "def chat(message, history):\n",
382
+ " if \"patent\" in message:\n",
383
+ " system = system_prompt + \"\\n\\nEverything in your reply needs to be in pig latin - \\\n",
384
+ " it is mandatory that you respond only and entirely in pig latin\"\n",
385
+ " else:\n",
386
+ " system = system_prompt\n",
387
+ " messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
388
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
389
+ " reply =response.choices[0].message.content\n",
390
+ "\n",
391
+ " evaluation = evaluate(reply, message, history)\n",
392
+ " \n",
393
+ " if evaluation.is_acceptable:\n",
394
+ " print(\"Passed evaluation - returning reply\")\n",
395
+ " else:\n",
396
+ " print(\"Failed evaluation - retrying\")\n",
397
+ " print(evaluation.feedback)\n",
398
+ " reply = rerun(reply, message, history, evaluation.feedback) \n",
399
+ " return reply"
400
+ ]
401
+ },
402
+ {
403
+ "cell_type": "code",
404
+ "execution_count": null,
405
+ "metadata": {},
406
+ "outputs": [
407
+ {
408
+ "name": "stdout",
409
+ "output_type": "stream",
410
+ "text": [
411
+ "* Running on local URL: http://127.0.0.1:7864\n",
412
+ "* To create a public link, set `share=True` in `launch()`.\n"
413
+ ]
414
+ },
415
+ {
416
+ "data": {
417
+ "text/html": [
418
+ "<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>"
419
+ ],
420
+ "text/plain": [
421
+ "<IPython.core.display.HTML object>"
422
+ ]
423
+ },
424
+ "metadata": {},
425
+ "output_type": "display_data"
426
+ },
427
+ {
428
+ "data": {
429
+ "text/plain": []
430
+ },
431
+ "execution_count": 44,
432
+ "metadata": {},
433
+ "output_type": "execute_result"
434
+ },
435
+ {
436
+ "name": "stdout",
437
+ "output_type": "stream",
438
+ "text": [
439
+ "Passed evaluation - returning reply\n",
440
+ "Failed evaluation - retrying\n",
441
+ "The agent's response contradicts the provided summary. The summary explicitly states: \"AI models I am using openai, google gemini, deepseek, groq and and anthropic cloude.\" The agent states, \"I currently do not have direct experience specifically with Anthropic Cloud...\", which is incorrect according to the context. The agent should align its answer with the provided information, indicating that it does have experience with Anthropic Claude (which is likely what \"anthropic cloude\" refers to).\n"
442
+ ]
443
+ }
444
+ ],
445
+ "source": [
446
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
447
+ ]
448
+ },
449
+ {
450
+ "cell_type": "markdown",
451
+ "metadata": {},
452
+ "source": []
453
+ },
454
+ {
455
+ "cell_type": "code",
456
+ "execution_count": null,
457
+ "metadata": {},
458
+ "outputs": [],
459
+ "source": []
460
+ }
461
+ ],
462
+ "metadata": {
463
+ "kernelspec": {
464
+ "display_name": ".venv",
465
+ "language": "python",
466
+ "name": "python3"
467
+ },
468
+ "language_info": {
469
+ "codemirror_mode": {
470
+ "name": "ipython",
471
+ "version": 3
472
+ },
473
+ "file_extension": ".py",
474
+ "mimetype": "text/x-python",
475
+ "name": "python",
476
+ "nbconvert_exporter": "python",
477
+ "pygments_lexer": "ipython3",
478
+ "version": "3.12.13"
479
+ }
480
+ },
481
+ "nbformat": 4,
482
+ "nbformat_minor": 2
483
+ }
4_lab4.ipynb ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## The first big project - Professionally You!\n",
8
+ "\n",
9
+ "### And, Tool use.\n",
10
+ "\n",
11
+ "### But first: introducing Pushover\n",
12
+ "\n",
13
+ "Pushover is a nifty tool for sending Push Notifications to your phone.\n",
14
+ "\n",
15
+ "It's super easy to set up and install!\n",
16
+ "\n",
17
+ "Simply visit https://pushover.net/ and click 'Login or Signup' on the top right to sign up for a free account, and create your API keys.\n",
18
+ "\n",
19
+ "Once you've signed up, on the home screen, click \"Create an Application/API Token\", and give it any name (like Agents) and click Create Application.\n",
20
+ "\n",
21
+ "Then add 2 lines to your `.env` file:\n",
22
+ "\n",
23
+ "PUSHOVER_USER=_put the key that's on the top right of your Pushover home screen and probably starts with a u_ \n",
24
+ "PUSHOVER_TOKEN=_put the key when you click into your new application called Agents (or whatever) and probably starts with an a_\n",
25
+ "\n",
26
+ "Remember to save your `.env` file, and run `load_dotenv(override=True)` after saving, to set your environment variables.\n",
27
+ "\n",
28
+ "Finally, click \"Add Phone, Tablet or Desktop\" to install on your phone."
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": 1,
34
+ "metadata": {},
35
+ "outputs": [],
36
+ "source": [
37
+ "# imports\n",
38
+ "\n",
39
+ "from dotenv import load_dotenv\n",
40
+ "from openai import OpenAI\n",
41
+ "import json\n",
42
+ "import os\n",
43
+ "import requests\n",
44
+ "from pypdf import PdfReader\n",
45
+ "import gradio as gr"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "execution_count": 2,
51
+ "metadata": {},
52
+ "outputs": [],
53
+ "source": [
54
+ "# The usual start\n",
55
+ "\n",
56
+ "load_dotenv(override=True)\n",
57
+ "openai = OpenAI()"
58
+ ]
59
+ },
60
+ {
61
+ "cell_type": "code",
62
+ "execution_count": 3,
63
+ "metadata": {},
64
+ "outputs": [
65
+ {
66
+ "name": "stdout",
67
+ "output_type": "stream",
68
+ "text": [
69
+ "Pushover user found and starts with u\n",
70
+ "Pushover token found and starts with a\n"
71
+ ]
72
+ }
73
+ ],
74
+ "source": [
75
+ "# For pushover\n",
76
+ "\n",
77
+ "pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
78
+ "pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
79
+ "pushover_url = \"https://api.pushover.net/1/messages.json\"\n",
80
+ "\n",
81
+ "if pushover_user:\n",
82
+ " print(f\"Pushover user found and starts with {pushover_user[0]}\")\n",
83
+ "else:\n",
84
+ " print(\"Pushover user not found\")\n",
85
+ "\n",
86
+ "if pushover_token:\n",
87
+ " print(f\"Pushover token found and starts with {pushover_token[0]}\")\n",
88
+ "else:\n",
89
+ " print(\"Pushover token not found\")"
90
+ ]
91
+ },
92
+ {
93
+ "cell_type": "code",
94
+ "execution_count": 4,
95
+ "metadata": {},
96
+ "outputs": [],
97
+ "source": [
98
+ "def push(message):\n",
99
+ " print(f\"Push: {message}\")\n",
100
+ " payload = {\"user\": pushover_user, \"token\": pushover_token, \"message\": message}\n",
101
+ " requests.post(pushover_url, data=payload)"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": 5,
107
+ "metadata": {},
108
+ "outputs": [
109
+ {
110
+ "name": "stdout",
111
+ "output_type": "stream",
112
+ "text": [
113
+ "Push: HEY!!\n"
114
+ ]
115
+ }
116
+ ],
117
+ "source": [
118
+ "push(\"HEY!!\")"
119
+ ]
120
+ },
121
+ {
122
+ "cell_type": "code",
123
+ "execution_count": 6,
124
+ "metadata": {},
125
+ "outputs": [],
126
+ "source": [
127
+ "def record_user_details(email, name=\"Name not provided\", notes=\"not provided\"):\n",
128
+ " push(f\"Recording interest from {name} with email {email} and notes {notes}\")\n",
129
+ " return {\"recorded\": \"ok\"}"
130
+ ]
131
+ },
132
+ {
133
+ "cell_type": "code",
134
+ "execution_count": 7,
135
+ "metadata": {},
136
+ "outputs": [],
137
+ "source": [
138
+ "def record_unknown_question(question):\n",
139
+ " push(f\"Recording {question} asked that I couldn't answer\")\n",
140
+ " return {\"recorded\": \"ok\"}"
141
+ ]
142
+ },
143
+ {
144
+ "cell_type": "code",
145
+ "execution_count": 8,
146
+ "metadata": {},
147
+ "outputs": [],
148
+ "source": [
149
+ "record_user_details_json = {\n",
150
+ " \"name\": \"record_user_details\",\n",
151
+ " \"description\": \"Use this tool to record that a user is interested in being in touch and provided an email address\",\n",
152
+ " \"parameters\": {\n",
153
+ " \"type\": \"object\",\n",
154
+ " \"properties\": {\n",
155
+ " \"email\": {\n",
156
+ " \"type\": \"string\",\n",
157
+ " \"description\": \"The email address of this user\"\n",
158
+ " },\n",
159
+ " \"name\": {\n",
160
+ " \"type\": \"string\",\n",
161
+ " \"description\": \"The user's name, if they provided it\"\n",
162
+ " }\n",
163
+ " ,\n",
164
+ " \"notes\": {\n",
165
+ " \"type\": \"string\",\n",
166
+ " \"description\": \"Any additional information about the conversation that's worth recording to give context\"\n",
167
+ " }\n",
168
+ " },\n",
169
+ " \"required\": [\"email\"],\n",
170
+ " \"additionalProperties\": False\n",
171
+ " }\n",
172
+ "}"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": 9,
178
+ "metadata": {},
179
+ "outputs": [],
180
+ "source": [
181
+ "record_unknown_question_json = {\n",
182
+ " \"name\": \"record_unknown_question\",\n",
183
+ " \"description\": \"Always use this tool to record any question that couldn't be answered as you didn't know the answer\",\n",
184
+ " \"parameters\": {\n",
185
+ " \"type\": \"object\",\n",
186
+ " \"properties\": {\n",
187
+ " \"question\": {\n",
188
+ " \"type\": \"string\",\n",
189
+ " \"description\": \"The question that couldn't be answered\"\n",
190
+ " },\n",
191
+ " },\n",
192
+ " \"required\": [\"question\"],\n",
193
+ " \"additionalProperties\": False\n",
194
+ " }\n",
195
+ "}"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": 10,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "tools = [{\"type\": \"function\", \"function\": record_user_details_json},\n",
205
+ " {\"type\": \"function\", \"function\": record_unknown_question_json}]"
206
+ ]
207
+ },
208
+ {
209
+ "cell_type": "code",
210
+ "execution_count": null,
211
+ "metadata": {},
212
+ "outputs": [],
213
+ "source": [
214
+ "tools"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": 11,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# This function can take a list of tool calls, and run them. This is the IF statement!!\n",
224
+ "\n",
225
+ "def handle_tool_calls(tool_calls):\n",
226
+ " results = []\n",
227
+ " for tool_call in tool_calls:\n",
228
+ " tool_name = tool_call.function.name\n",
229
+ " arguments = json.loads(tool_call.function.arguments)\n",
230
+ " print(f\"Tool called: {tool_name}\", flush=True)\n",
231
+ "\n",
232
+ " # THE BIG IF STATEMENT!!!\n",
233
+ "\n",
234
+ " if tool_name == \"record_user_details\":\n",
235
+ " result = record_user_details(**arguments)\n",
236
+ " elif tool_name == \"record_unknown_question\":\n",
237
+ " result = record_unknown_question(**arguments)\n",
238
+ "\n",
239
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
240
+ " return results"
241
+ ]
242
+ },
243
+ {
244
+ "cell_type": "code",
245
+ "execution_count": 12,
246
+ "metadata": {},
247
+ "outputs": [
248
+ {
249
+ "name": "stdout",
250
+ "output_type": "stream",
251
+ "text": [
252
+ "Push: Recording this is a really hard question asked that I couldn't answer\n"
253
+ ]
254
+ },
255
+ {
256
+ "data": {
257
+ "text/plain": [
258
+ "{'recorded': 'ok'}"
259
+ ]
260
+ },
261
+ "execution_count": 12,
262
+ "metadata": {},
263
+ "output_type": "execute_result"
264
+ }
265
+ ],
266
+ "source": [
267
+ "globals()[\"record_unknown_question\"](\"this is a really hard question\")"
268
+ ]
269
+ },
270
+ {
271
+ "cell_type": "code",
272
+ "execution_count": 13,
273
+ "metadata": {},
274
+ "outputs": [],
275
+ "source": [
276
+ "# This is a more elegant way that avoids the IF statement.\n",
277
+ "\n",
278
+ "def handle_tool_calls(tool_calls):\n",
279
+ " results = []\n",
280
+ " for tool_call in tool_calls:\n",
281
+ " tool_name = tool_call.function.name\n",
282
+ " arguments = json.loads(tool_call.function.arguments)\n",
283
+ " print(f\"Tool called: {tool_name}\", flush=True)\n",
284
+ " tool = globals().get(tool_name)\n",
285
+ " result = tool(**arguments) if tool else {}\n",
286
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
287
+ " return results"
288
+ ]
289
+ },
290
+ {
291
+ "cell_type": "code",
292
+ "execution_count": 18,
293
+ "metadata": {},
294
+ "outputs": [],
295
+ "source": [
296
+ "reader = PdfReader(\"me/LinkedIn Profile.pdf\")\n",
297
+ "linkedin = \"\"\n",
298
+ "for page in reader.pages:\n",
299
+ " text = page.extract_text()\n",
300
+ " if text:\n",
301
+ " linkedin += text\n",
302
+ "\n",
303
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
304
+ " summary = f.read()\n",
305
+ "\n",
306
+ "name = \"Mukesh Patil\""
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "code",
311
+ "execution_count": 16,
312
+ "metadata": {},
313
+ "outputs": [],
314
+ "source": [
315
+ "reader = PdfReader(\"me/Mukesh Patil Resume.pdf\")\n",
316
+ "Resume = \"\"\n",
317
+ "for page in reader.pages:\n",
318
+ " text = page.extract_text()\n",
319
+ " if text:\n",
320
+ " Resume += text"
321
+ ]
322
+ },
323
+ {
324
+ "cell_type": "code",
325
+ "execution_count": 19,
326
+ "metadata": {},
327
+ "outputs": [],
328
+ "source": [
329
+ "system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
330
+ "particularly questions related to {name}'s career, background, skills and experience. \\\n",
331
+ "Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
332
+ "You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
333
+ "Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
334
+ "If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \\\n",
335
+ "If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool. \"\n",
336
+ "\n",
337
+ "system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n Resume:\\n{Resume}\\n\\n\"\n",
338
+ "system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
339
+ ]
340
+ },
341
+ {
342
+ "cell_type": "code",
343
+ "execution_count": 20,
344
+ "metadata": {},
345
+ "outputs": [],
346
+ "source": [
347
+ "def chat(message, history):\n",
348
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
349
+ " done = False\n",
350
+ " while not done:\n",
351
+ "\n",
352
+ " # This is the call to the LLM - see that we pass in the tools json\n",
353
+ "\n",
354
+ " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages, tools=tools)\n",
355
+ "\n",
356
+ " finish_reason = response.choices[0].finish_reason\n",
357
+ " \n",
358
+ " # If the LLM wants to call a tool, we do that!\n",
359
+ " \n",
360
+ " if finish_reason==\"tool_calls\":\n",
361
+ " message = response.choices[0].message\n",
362
+ " tool_calls = message.tool_calls\n",
363
+ " results = handle_tool_calls(tool_calls)\n",
364
+ " messages.append(message)\n",
365
+ " messages.extend(results)\n",
366
+ " else:\n",
367
+ " done = True\n",
368
+ " return response.choices[0].message.content"
369
+ ]
370
+ },
371
+ {
372
+ "cell_type": "code",
373
+ "execution_count": null,
374
+ "metadata": {},
375
+ "outputs": [],
376
+ "source": [
377
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
378
+ ]
379
+ },
380
+ {
381
+ "cell_type": "markdown",
382
+ "metadata": {},
383
+ "source": [
384
+ "## And now for deployment\n",
385
+ "\n",
386
+ "This code is in `app.py`\n",
387
+ "\n",
388
+ "We will deploy to HuggingFace Spaces.\n",
389
+ "\n",
390
+ "Before you start: remember to update the files in the \"me\" directory - your LinkedIn profile and summary.txt - so that it talks about you! Also change `self.name = \"Ed Donner\"` in `app.py`.. \n",
391
+ "\n",
392
+ "Also check that there's no README file within the 1_foundations directory. If there is one, please delete it. The deploy process creates a new README file in this directory for you.\n",
393
+ "\n",
394
+ "1. Visit https://huggingface.co and set up an account \n",
395
+ "2. From the Avatar menu on the top right, choose Access Tokens. Choose \"Create New Token\". Give it WRITE permissions - it needs to have WRITE permissions! Keep a record of your new key. \n",
396
+ "3. In the Terminal, run: `uv tool install 'huggingface_hub[cli]'` to install the HuggingFace tool, then `hf auth login --token YOUR_TOKEN_HERE`, like `hf auth login --token hf_xxxxxx`, to login at the command line with your key. Afterwards, run `hf auth whoami` to check you're logged in \n",
397
+ "4. Take your new token and add it to your .env file: `HF_TOKEN=hf_xxx` for the future\n",
398
+ "5. From the 1_foundations folder, enter: `uv run gradio deploy` \n",
399
+ "6. Follow its instructions: name it \"career_conversation\", specify app.py, choose cpu-basic as the hardware, say Yes to needing to supply secrets, provide your openai api key, your pushover user and token, and say \"no\" to github actions. \n",
400
+ "\n",
401
+ "Thank you Robert, James, Martins, Andras and Priya for these tips. \n",
402
+ "Please read the next 2 sections - how to change your Secrets, and how to redeploy your Space (you may need to delete the README.md that gets created in this 1_foundations directory).\n",
403
+ "\n",
404
+ "#### More about these secrets:\n",
405
+ "\n",
406
+ "If you're confused by what's going on with these secrets: it just wants you to enter the key name and value for each of your secrets -- so you would enter: \n",
407
+ "`OPENAI_API_KEY` \n",
408
+ "Followed by: \n",
409
+ "`sk-proj-...` \n",
410
+ "\n",
411
+ "And if you don't want to set secrets this way, or something goes wrong with it, it's no problem - you can change your secrets later: \n",
412
+ "1. Log in to HuggingFace website \n",
413
+ "2. Go to your profile screen via the Avatar menu on the top right \n",
414
+ "3. Select the Space you deployed \n",
415
+ "4. Click on the Settings wheel on the top right \n",
416
+ "5. You can scroll down to change your secrets (Variables and Secrets section), delete the space, etc.\n",
417
+ "\n",
418
+ "#### And now you should be deployed!\n",
419
+ "\n",
420
+ "If you want to completely replace everything and start again with your keys, you may need to delete the README.md that got created in this 1_foundations folder.\n",
421
+ "\n",
422
+ "Here is mine: https://huggingface.co/spaces/ed-donner/Career_Conversation\n",
423
+ "\n",
424
+ "I just got a push notification that a student asked me how they can become President of their country 😂😂\n",
425
+ "\n",
426
+ "For more information on deployment:\n",
427
+ "\n",
428
+ "https://www.gradio.app/guides/sharing-your-app#hosting-on-hf-spaces\n",
429
+ "\n",
430
+ "To delete your Space in the future: \n",
431
+ "1. Log in to HuggingFace\n",
432
+ "2. From the Avatar menu, select your profile\n",
433
+ "3. Click on the Space itself and select the settings wheel on the top right\n",
434
+ "4. Scroll to the Delete section at the bottom\n",
435
+ "5. ALSO: delete the README file that Gradio may have created inside this 1_foundations folder (otherwise it won't ask you the questions the next time you do a gradio deploy)\n"
436
+ ]
437
+ },
438
+ {
439
+ "cell_type": "markdown",
440
+ "metadata": {},
441
+ "source": [
442
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
443
+ " <tr>\n",
444
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
445
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
446
+ " </td>\n",
447
+ " <td>\n",
448
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
449
+ " <span style=\"color:#ff7800;\">• First and foremost, deploy this for yourself! It's a real, valuable tool - the future resume..<br/>\n",
450
+ " • Next, improve the resources - add better context about yourself. If you know RAG, then add a knowledge base about you.<br/>\n",
451
+ " • Add in more tools! You could have a SQL database with common Q&A that the LLM could read and write from?<br/>\n",
452
+ " • Bring in the Evaluator from the last lab, and add other Agentic patterns.\n",
453
+ " </span>\n",
454
+ " </td>\n",
455
+ " </tr>\n",
456
+ "</table>"
457
+ ]
458
+ },
459
+ {
460
+ "cell_type": "markdown",
461
+ "metadata": {},
462
+ "source": [
463
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
464
+ " <tr>\n",
465
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
466
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
467
+ " </td>\n",
468
+ " <td>\n",
469
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
470
+ " <span style=\"color:#00bfff;\">Aside from the obvious (your career alter-ego) this has business applications in any situation where you need an AI assistant with domain expertise and an ability to interact with the real world.\n",
471
+ " </span>\n",
472
+ " </td>\n",
473
+ " </tr>\n",
474
+ "</table>"
475
+ ]
476
+ }
477
+ ],
478
+ "metadata": {
479
+ "kernelspec": {
480
+ "display_name": ".venv",
481
+ "language": "python",
482
+ "name": "python3"
483
+ },
484
+ "language_info": {
485
+ "codemirror_mode": {
486
+ "name": "ipython",
487
+ "version": 3
488
+ },
489
+ "file_extension": ".py",
490
+ "mimetype": "text/x-python",
491
+ "name": "python",
492
+ "nbconvert_exporter": "python",
493
+ "pygments_lexer": "ipython3",
494
+ "version": "3.12.13"
495
+ }
496
+ },
497
+ "nbformat": 4,
498
+ "nbformat_minor": 2
499
+ }
5_extra.ipynb ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "802f392f",
6
+ "metadata": {},
7
+ "source": [
8
+ "# A little extra!\n",
9
+ "\n",
10
+ "## New addition to Week 1\n",
11
+ "\n",
12
+ "### The Unreasonable Effectiveness of the Agent Loop"
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "markdown",
17
+ "id": "0c78e180",
18
+ "metadata": {},
19
+ "source": [
20
+ "# What is an Agent?\n",
21
+ "\n",
22
+ "## Three competing definitions\n",
23
+ "\n",
24
+ "1. AI systems that can do work for you independently - Sam Altman\n",
25
+ "\n",
26
+ "2. A system in which an LLM controls the workflow - Anthropic\n",
27
+ "\n",
28
+ "3. An LLM agent runs tools in a loop to achieve a goal\n",
29
+ "\n",
30
+ "## The third one is the new, emerging definition\n",
31
+ "\n",
32
+ "But what does it mean?\n",
33
+ "\n",
34
+ "Let's make it real."
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": null,
40
+ "id": "566bdd9a",
41
+ "metadata": {},
42
+ "outputs": [],
43
+ "source": [
44
+ "# Start with some imports - rich is a library for making formatted text output in the terminal\n",
45
+ "\n",
46
+ "from rich.console import Console\n",
47
+ "from dotenv import load_dotenv\n",
48
+ "from openai import OpenAI\n",
49
+ "import json\n",
50
+ "load_dotenv(override=True)"
51
+ ]
52
+ },
53
+ {
54
+ "cell_type": "code",
55
+ "execution_count": null,
56
+ "id": "8d38dcc2",
57
+ "metadata": {},
58
+ "outputs": [],
59
+ "source": [
60
+ "def show(text):\n",
61
+ " try:\n",
62
+ " Console().print(text)\n",
63
+ " except Exception:\n",
64
+ " print(text)"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": null,
70
+ "id": "18f1952e",
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "openai = OpenAI()"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": null,
80
+ "id": "e1517bf3",
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "# Some lists!\n",
85
+ "\n",
86
+ "todos = []\n",
87
+ "completed = []"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": null,
93
+ "id": "d415a4f2",
94
+ "metadata": {},
95
+ "outputs": [],
96
+ "source": [
97
+ "def get_todo_report() -> str:\n",
98
+ " result = \"\"\n",
99
+ " for index, todo in enumerate(todos):\n",
100
+ " if completed[index]:\n",
101
+ " result += f\"Todo #{index + 1}: [green][strike]{todo}[/strike][/green]\\n\"\n",
102
+ " else:\n",
103
+ " result += f\"Todo #{index + 1}: {todo}\\n\"\n",
104
+ " show(result)\n",
105
+ " return result"
106
+ ]
107
+ },
108
+ {
109
+ "cell_type": "code",
110
+ "execution_count": null,
111
+ "id": "7b842749",
112
+ "metadata": {},
113
+ "outputs": [],
114
+ "source": [
115
+ "get_todo_report()"
116
+ ]
117
+ },
118
+ {
119
+ "cell_type": "code",
120
+ "execution_count": null,
121
+ "id": "ff5f01ca",
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "def create_todos(descriptions: list[str]) -> str:\n",
126
+ " todos.extend(descriptions)\n",
127
+ " completed.extend([False] * len(descriptions))\n",
128
+ " return get_todo_report()"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "id": "aa4d97e6",
135
+ "metadata": {},
136
+ "outputs": [],
137
+ "source": [
138
+ "def mark_complete(index: int, completion_notes: str) -> str:\n",
139
+ " if 1 <= index <= len(todos):\n",
140
+ " completed[index - 1] = True\n",
141
+ " else:\n",
142
+ " return \"No todo at this index.\"\n",
143
+ " Console().print(completion_notes)\n",
144
+ " return get_todo_report()"
145
+ ]
146
+ },
147
+ {
148
+ "cell_type": "code",
149
+ "execution_count": null,
150
+ "id": "ef3b3a97",
151
+ "metadata": {},
152
+ "outputs": [],
153
+ "source": [
154
+ "todos, completed = [], []\n",
155
+ "\n",
156
+ "create_todos([\"Buy groceries\", \"Finish extra lab\", \"Eat banana\"])"
157
+ ]
158
+ },
159
+ {
160
+ "cell_type": "code",
161
+ "execution_count": null,
162
+ "id": "a9721a5c",
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "mark_complete(1, \"bought\")"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "code",
171
+ "execution_count": null,
172
+ "id": "4159b046",
173
+ "metadata": {},
174
+ "outputs": [],
175
+ "source": [
176
+ "create_todos_json = {\n",
177
+ " \"name\": \"create_todos\",\n",
178
+ " \"description\": \"Add new todos from a list of descriptions and return the full list\",\n",
179
+ " \"parameters\": {\n",
180
+ " \"type\": \"object\",\n",
181
+ " \"properties\": {\n",
182
+ " \"descriptions\": {\n",
183
+ " 'type': 'array',\n",
184
+ " 'items': {'type': 'string'},\n",
185
+ " 'title': 'Descriptions'\n",
186
+ " }\n",
187
+ " },\n",
188
+ " \"required\": [\"descriptions\"],\n",
189
+ " \"additionalProperties\": False\n",
190
+ " }\n",
191
+ "}"
192
+ ]
193
+ },
194
+ {
195
+ "cell_type": "code",
196
+ "execution_count": null,
197
+ "id": "36a453e9",
198
+ "metadata": {},
199
+ "outputs": [],
200
+ "source": [
201
+ "mark_complete_json = {\n",
202
+ " \"name\": \"mark_complete\",\n",
203
+ " \"description\": \"Mark complete the todo at the given position (starting from 1) and return the full list\",\n",
204
+ " \"parameters\": {\n",
205
+ " 'properties': {\n",
206
+ " 'index': {\n",
207
+ " 'description': 'The 1-based index of the todo to mark as complete',\n",
208
+ " 'title': 'Index',\n",
209
+ " 'type': 'integer'\n",
210
+ " },\n",
211
+ " 'completion_notes': {\n",
212
+ " 'description': 'Notes about how you completed the todo in rich console markup',\n",
213
+ " 'title': 'Completion Notes',\n",
214
+ " 'type': 'string'\n",
215
+ " }\n",
216
+ " },\n",
217
+ " 'required': ['index', 'completion_notes'],\n",
218
+ " 'type': 'object',\n",
219
+ " 'additionalProperties': False\n",
220
+ " }\n",
221
+ "}"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": null,
227
+ "id": "52fe4d76",
228
+ "metadata": {},
229
+ "outputs": [],
230
+ "source": [
231
+ "tools = [{\"type\": \"function\", \"function\": create_todos_json},\n",
232
+ " {\"type\": \"function\", \"function\": mark_complete_json}]"
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "code",
237
+ "execution_count": null,
238
+ "id": "af686232",
239
+ "metadata": {},
240
+ "outputs": [],
241
+ "source": [
242
+ "def handle_tool_calls(tool_calls):\n",
243
+ " results = []\n",
244
+ " for tool_call in tool_calls:\n",
245
+ " tool_name = tool_call.function.name\n",
246
+ " arguments = json.loads(tool_call.function.arguments)\n",
247
+ " tool = globals().get(tool_name)\n",
248
+ " result = tool(**arguments) if tool else {}\n",
249
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
250
+ " return results"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": null,
256
+ "id": "20bebfee",
257
+ "metadata": {},
258
+ "outputs": [],
259
+ "source": [
260
+ "def loop(messages):\n",
261
+ " done = False\n",
262
+ " while not done:\n",
263
+ " response = openai.chat.completions.create(model=\"gpt-5.2\", messages=messages, tools=tools, reasoning_effort=\"none\")\n",
264
+ " finish_reason = response.choices[0].finish_reason\n",
265
+ " if finish_reason==\"tool_calls\":\n",
266
+ " message = response.choices[0].message\n",
267
+ " tool_calls = message.tool_calls\n",
268
+ " results = handle_tool_calls(tool_calls)\n",
269
+ " messages.append(message)\n",
270
+ " messages.extend(results)\n",
271
+ " else:\n",
272
+ " done = True\n",
273
+ " show(response.choices[0].message.content)"
274
+ ]
275
+ },
276
+ {
277
+ "cell_type": "code",
278
+ "execution_count": null,
279
+ "id": "839d1593",
280
+ "metadata": {},
281
+ "outputs": [],
282
+ "source": [
283
+ "system_message = \"\"\"\n",
284
+ "You are given a problem to solve, by using your todo tools to plan a list of steps, then carrying out each step in turn.\n",
285
+ "Now use the todo list tools, create a plan, carry out the steps, and reply with the solution.\n",
286
+ "If any quantity isn't provided in the question, then include a step to come up with a reasonable estimate.\n",
287
+ "Provide your solution in Rich console markup without code blocks.\n",
288
+ "Do not ask the user questions or clarification; respond only with the answer after using your tools.\n",
289
+ "\"\"\"\n",
290
+ "user_message = \"\"\"\"\n",
291
+ "A train leaves Boston at 2:00 pm traveling 60 mph.\n",
292
+ "Another train leaves New York at 3:00 pm traveling 80 mph toward Boston.\n",
293
+ "When do they meet?\n",
294
+ "\"\"\"\n",
295
+ "messages = [{\"role\": \"system\", \"content\": system_message}, {\"role\": \"user\", \"content\": user_message}]"
296
+ ]
297
+ },
298
+ {
299
+ "cell_type": "code",
300
+ "execution_count": null,
301
+ "id": "fe6f4515",
302
+ "metadata": {},
303
+ "outputs": [],
304
+ "source": [
305
+ "todos, completed = [], []\n",
306
+ "loop(messages)"
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "markdown",
311
+ "id": "b9b3e1ed",
312
+ "metadata": {},
313
+ "source": [
314
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
315
+ " <tr>\n",
316
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
317
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
318
+ " </td>\n",
319
+ " <td>\n",
320
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
321
+ " <span style=\"color:#ff7800;\">Now try to build an Agent Loop from scratch yourself!<br/>\n",
322
+ " Create a new .ipynb and make one from first principles, referring back to this as needed.<br/>\n",
323
+ " It's one of the few times that I recommend typing from scratch - it's a very satisfying result.\n",
324
+ " </span>\n",
325
+ " </td>\n",
326
+ " </tr>\n",
327
+ "</table>"
328
+ ]
329
+ }
330
+ ],
331
+ "metadata": {
332
+ "kernelspec": {
333
+ "display_name": ".venv",
334
+ "language": "python",
335
+ "name": "python3"
336
+ },
337
+ "language_info": {
338
+ "codemirror_mode": {
339
+ "name": "ipython",
340
+ "version": 3
341
+ },
342
+ "file_extension": ".py",
343
+ "mimetype": "text/x-python",
344
+ "name": "python",
345
+ "nbconvert_exporter": "python",
346
+ "pygments_lexer": "ipython3",
347
+ "version": "3.12.9"
348
+ }
349
+ },
350
+ "nbformat": 4,
351
+ "nbformat_minor": 5
352
+ }
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Chat With Mukesh
3
- emoji: 🚀
4
- colorFrom: gray
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 6.11.0
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: Chat_With_Mukesh
 
 
 
 
 
3
  app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 5.49.1
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Self
2
+ from dotenv import load_dotenv
3
+ from openai import OpenAI
4
+ import json
5
+ import os
6
+ import requests
7
+ from pypdf import PdfReader
8
+ import gradio as gr
9
+
10
+
11
+ load_dotenv(override=True)
12
+
13
+ def push(text):
14
+ requests.post(
15
+ "https://api.pushover.net/1/messages.json",
16
+ data={
17
+ "token": os.getenv("PUSHOVER_TOKEN"),
18
+ "user": os.getenv("PUSHOVER_USER"),
19
+ "message": text,
20
+ }
21
+ )
22
+
23
+
24
+ def record_user_details(email, name="Name not provided", notes="not provided"):
25
+ push(f"Recording {name} with email {email} and notes {notes}")
26
+ return {"recorded": "ok"}
27
+
28
+ def record_unknown_question(question):
29
+ push(f"Recording {question}")
30
+ return {"recorded": "ok"}
31
+
32
+ record_user_details_json = {
33
+ "name": "record_user_details",
34
+ "description": "Use this tool to record that a user is interested in being in touch and provided an email address",
35
+ "parameters": {
36
+ "type": "object",
37
+ "properties": {
38
+ "email": {
39
+ "type": "string",
40
+ "description": "The email address of this user"
41
+ },
42
+ "name": {
43
+ "type": "string",
44
+ "description": "The user's name, if they provided it"
45
+ }
46
+ ,
47
+ "notes": {
48
+ "type": "string",
49
+ "description": "Any additional information about the conversation that's worth recording to give context"
50
+ }
51
+ },
52
+ "required": ["email"],
53
+ "additionalProperties": False
54
+ }
55
+ }
56
+
57
+ record_unknown_question_json = {
58
+ "name": "record_unknown_question",
59
+ "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
60
+ "parameters": {
61
+ "type": "object",
62
+ "properties": {
63
+ "question": {
64
+ "type": "string",
65
+ "description": "The question that couldn't be answered"
66
+ },
67
+ },
68
+ "required": ["question"],
69
+ "additionalProperties": False
70
+ }
71
+ }
72
+
73
+ tools = [{"type": "function", "function": record_user_details_json},
74
+ {"type": "function", "function": record_unknown_question_json}]
75
+
76
+
77
+ class Me:
78
+
79
+ def __init__(self):
80
+ self.openai = OpenAI()
81
+ self.name = "Mukesh Patil"
82
+ reader = PdfReader("me/LinkedIn Profile.pdf")
83
+ self.linkedin = ""
84
+ for page in reader.pages:
85
+ text = page.extract_text()
86
+ if text:
87
+ self.linkedin += text
88
+
89
+ Resume_reader = PdfReader("me/Mukesh Patil Resume.pdf")
90
+ self.Resume = ""
91
+ for page in reader.pages:
92
+ text = page.extract_text()
93
+ if text:
94
+ self.Resume += text
95
+ with open("me/summary.txt", "r", encoding="utf-8") as f:
96
+ self.summary = f.read()
97
+
98
+
99
+ def handle_tool_call(self, tool_calls):
100
+ results = []
101
+ for tool_call in tool_calls:
102
+ tool_name = tool_call.function.name
103
+ arguments = json.loads(tool_call.function.arguments)
104
+ print(f"Tool called: {tool_name}", flush=True)
105
+ tool = globals().get(tool_name)
106
+ result = tool(**arguments) if tool else {}
107
+ results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
108
+ return results
109
+
110
+ def system_prompt(self):
111
+ system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
112
+ particularly questions related to {self.name}'s career, background, skills and experience. \
113
+ Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
114
+ You are given a summary of {self.name}'s background, LinkedIn profile and Resume which you can use to answer questions. \
115
+ Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
116
+ If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \
117
+ If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool. "
118
+
119
+ system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n## Resume:\n{self.Resume}\n\n"
120
+ system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
121
+ return system_prompt
122
+
123
+ def chat(self, message, history):
124
+ messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
125
+ done = False
126
+ while not done:
127
+ response = self.openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
128
+ if response.choices[0].finish_reason=="tool_calls":
129
+ message = response.choices[0].message
130
+ tool_calls = message.tool_calls
131
+ results = self.handle_tool_call(tool_calls)
132
+ messages.append(message)
133
+ messages.extend(results)
134
+ else:
135
+ done = True
136
+ return response.choices[0].message.content
137
+
138
+ ########################################################
139
+ ### Addtional code added by Mukesh for evaluator
140
+ ########################################################
141
+ from pydantic import BaseModel
142
+
143
+ class Evaluation(BaseModel):
144
+ is_acceptable: bool
145
+ feedback: str
146
+
147
+ def evaluate_system_prompt (self):
148
+ evaluator_system_prompt = f"You are an evaluator that decides whether a response to a question is acceptable. \
149
+ You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \
150
+ The Agent is playing the role of {self.name} and is representing {self.name} on their website. \
151
+ The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \
152
+ The Agent has been provided with context on {self.name} in the form of their summary and LinkedIn details. Here's the information:"
153
+
154
+
155
+ evaluator_system_prompt += f"\n\n## Summary:\n{summary}\n\n## LinkedIn Profile:\n{linkedin}\n\n Resume:\n{Resume}\n\n"
156
+ evaluator_system_prompt += f"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback."
157
+ return evaluate_system_prompt
158
+
159
+
160
+ def evaluator_user_prompt(self, reply, message, history):
161
+ evaluator_user_prompt = f"Here's the conversation between the User and the Agent: \n\n{history}\n\n"
162
+ evaluator_user_prompt += f"Here's the latest message from the User: \n\n{message}\n\n"
163
+ evaluator_user_prompt += f"Here's the latest response from the Agent: \n\n{reply}\n\n"
164
+ evaluator_user_prompt += "Please evaluate the response, replying with whether it is acceptable and your feedback."
165
+ return evaluator_user_prompt
166
+
167
+ import os
168
+ gemini = OpenAI(
169
+ api_key=os.getenv("GOOGLE_API_KEY"),
170
+ base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
171
+ )
172
+
173
+ def evaluate(self, reply, message, history) -> Evaluation:
174
+ messages = [{"role": "system", "content": self.evaluator_system_prompt()}] + [{"role": "user", "content": self.evaluator_user_prompt(reply, message, history)}]
175
+ response = gemini.beta.chat.completions.parse(model="gemini-2.5-flash", messages=messages, response_format=Evaluation)
176
+ return response.choices[0].message.parsed
177
+
178
+
179
+ def rerun(self, reply, message, history, feedback):
180
+ updated_system_prompt = self.system_prompt() + "\n\n## Previous answer rejected\nYou just tried to reply, but the quality control rejected your reply\n"
181
+ updated_system_prompt += f"## Your attempted answer:\n{reply}\n\n"
182
+ updated_system_prompt += f"## Reason for rejection:\n{feedback}\n\n"
183
+ messages = [{"role": "system", "content": updated_system_prompt}] + history + [{"role": "user", "content": message}]
184
+ response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
185
+ return response.choices[0].message.content
186
+
187
+ def chat(self, message, history):
188
+ messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
189
+ done = False
190
+ while not done:
191
+ response = self.openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
192
+ if response.choices[0].finish_reason=="tool_calls":
193
+ message = response.choices[0].message
194
+ tool_calls = message.tool_calls
195
+ results = self.handle_tool_call(tool_calls)
196
+
197
+
198
+
199
+ ## End of additional code added by Mukesh for evaluator
200
+
201
+ if __name__ == "__main__":
202
+ me = Me()
203
+ gr.ChatInterface(me.chat, type="messages").launch()
204
+
community-contributions/Anirban_lab1-solution_day1.ipynb ADDED
@@ -0,0 +1,579 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
6
+ "metadata": {},
7
+ "source": [
8
+ "# YOUR FIRST LAB\n",
9
+ "### Please read this section. This is valuable to get you prepared, even if it's a long read -- it's important stuff.\n",
10
+ "\n",
11
+ "### Also, be sure to read [README.md](../README.md)! More info about the updated videos in the README and [top of the course resources in purple](https://edwarddonner.com/2024/11/13/llm-engineering-resources/)\n",
12
+ "\n",
13
+ "## Your first Frontier LLM Project\n",
14
+ "\n",
15
+ "By the end of this course, you will have built an autonomous Agentic AI solution with 7 agents that collaborate to solve a business problem. All in good time! We will start with something smaller...\n",
16
+ "\n",
17
+ "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n",
18
+ "\n",
19
+ "Before starting, you should have completed the setup linked in the README.\n",
20
+ "\n",
21
+ "### If you're new to working in \"Notebooks\" (also known as Labs or Jupyter Lab)\n",
22
+ "\n",
23
+ "Welcome to the wonderful world of Data Science experimentation! Simply click in each \"cell\" with code in it, such as the cell immediately below this text, and hit Shift+Return to execute that cell. Be sure to run every cell, starting at the top, in order.\n",
24
+ "\n",
25
+ "Please look in the [Guides folder](../guides/01_intro.ipynb) for all the guides.\n",
26
+ "\n",
27
+ "## I am here to help\n",
28
+ "\n",
29
+ "If you have any problems at all, please do reach out. \n",
30
+ "I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect (and I love connecting!) \n",
31
+ "And this is new to me, but I'm also trying out X at [@edwarddonner](https://x.com/edwarddonner) - if you're on X, please show me how it's done 😂 \n",
32
+ "\n",
33
+ "## More troubleshooting\n",
34
+ "\n",
35
+ "Please see the [troubleshooting](../setup/troubleshooting.ipynb) notebook in the setup folder to diagnose and fix common problems. At the very end of it is a diagnostics script with some useful debug info.\n",
36
+ "\n",
37
+ "## If this is old hat!\n",
38
+ "\n",
39
+ "If you're already comfortable with today's material, please hang in there; you can move swiftly through the first few labs - we will get much more in depth as the weeks progress. Ultimately we will fine-tune our own LLM to compete with OpenAI!\n",
40
+ "\n",
41
+ "<table style=\"margin: 0; text-align: left;\">\n",
42
+ " <tr>\n",
43
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
44
+ " <img src=\"../assets/important.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
45
+ " </td>\n",
46
+ " <td>\n",
47
+ " <h2 style=\"color:#900;\">Please read - important note</h2>\n",
48
+ " <span style=\"color:#900;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations. If you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...</span>\n",
49
+ " </td>\n",
50
+ " </tr>\n",
51
+ "</table>\n",
52
+ "<table style=\"margin: 0; text-align: left;\">\n",
53
+ " <tr>\n",
54
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
55
+ " <img src=\"../assets/resources.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
56
+ " </td>\n",
57
+ " <td>\n",
58
+ " <h2 style=\"color:#f71;\">This code is a live resource - keep an eye out for my emails</h2>\n",
59
+ " <span style=\"color:#f71;\">I push updates to the code regularly. As people ask questions, I add more examples or improved commentary. As a result, you'll notice that the code below isn't identical to the videos. Everything from the videos is here; but I've also added better explanations and new models like DeepSeek. Consider this like an interactive book.<br/><br/>\n",
60
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
61
+ " </span>\n",
62
+ " </td>\n",
63
+ " </tr>\n",
64
+ "</table>\n",
65
+ "<table style=\"margin: 0; text-align: left;\">\n",
66
+ " <tr>\n",
67
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
68
+ " <img src=\"../assets/business.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
69
+ " </td>\n",
70
+ " <td>\n",
71
+ " <h2 style=\"color:#181;\">Business value of these exercises</h2>\n",
72
+ " <span style=\"color:#181;\">A final thought. While I've designed these notebooks to be educational, I've also tried to make them enjoyable. We'll do fun things like have LLMs tell jokes and argue with each other. But fundamentally, my goal is to teach skills you can apply in business. I'll explain business implications as we go, and it's worth keeping this in mind: as you build experience with models and techniques, think of ways you could put this into action at work today. Please do contact me if you'd like to discuss more or if you have ideas to bounce off me.</span>\n",
73
+ " </td>\n",
74
+ " </tr>\n",
75
+ "</table>"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "markdown",
80
+ "id": "83f28feb",
81
+ "metadata": {},
82
+ "source": [
83
+ "### If necessary, install Cursor Extensions\n",
84
+ "\n",
85
+ "1. From the View menu, select Extensions\n",
86
+ "2. Search for Python\n",
87
+ "3. Click on \"Python\" made by \"ms-python\" and select Install if not already installed\n",
88
+ "4. Search for Jupyter\n",
89
+ "5. Click on \"Jupyter\" made by \"ms-toolsai\" and select Install if not already installed\n",
90
+ "\n",
91
+ "\n",
92
+ "### Next Select the Kernel\n",
93
+ "\n",
94
+ "Click on \"Select Kernel\" on the Top Right\n",
95
+ "\n",
96
+ "Choose \"Python Environments...\"\n",
97
+ "\n",
98
+ "Then choose the one that looks like `.venv (Python 3.12.x) .venv/bin/python` - it should be marked as \"Recommended\" and have a big star next to it.\n",
99
+ "\n",
100
+ "Any problems with this? Head over to the troubleshooting.\n",
101
+ "\n",
102
+ "### Note: you'll need to set the Kernel with every notebook.."
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "code",
107
+ "execution_count": null,
108
+ "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
109
+ "metadata": {},
110
+ "outputs": [],
111
+ "source": [
112
+ "# imports\n",
113
+ "\n",
114
+ "import os\n",
115
+ "from dotenv import load_dotenv\n",
116
+ "from scraper import fetch_website_contents\n",
117
+ "from IPython.display import Markdown, display\n",
118
+ "from openai import OpenAI\n",
119
+ "\n",
120
+ "# If you get an error running this cell, then please head over to the troubleshooting notebook!"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "markdown",
125
+ "id": "6900b2a8-6384-4316-8aaa-5e519fca4254",
126
+ "metadata": {},
127
+ "source": [
128
+ "# Connecting to OpenAI (or Ollama)\n",
129
+ "\n",
130
+ "The next cell is where we load in the environment variables in your `.env` file and connect to OpenAI. \n",
131
+ "\n",
132
+ "If you'd like to use free Ollama instead, please see the README section \"Free Alternative to Paid APIs\", and if you're not sure how to do this, there's a full solution in the solutions folder (day1_with_ollama.ipynb).\n",
133
+ "\n",
134
+ "## Troubleshooting if you have problems:\n",
135
+ "\n",
136
+ "If you get a \"Name Error\" - have you run all cells from the top down? Head over to the Python Foundations guide for a bulletproof way to find and fix all Name Errors.\n",
137
+ "\n",
138
+ "If that doesn't fix it, head over to the [troubleshooting](../setup/troubleshooting.ipynb) notebook for step by step code to identify the root cause and fix it!\n",
139
+ "\n",
140
+ "Or, contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n",
141
+ "\n",
142
+ "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point. You can also use Ollama as a free alternative, which we discuss during Day 2."
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "code",
147
+ "execution_count": null,
148
+ "id": "7b87cadb-d513-4303-baee-a37b6f938e4d",
149
+ "metadata": {},
150
+ "outputs": [],
151
+ "source": [
152
+ "# Load environment variables in a file called .env\n",
153
+ "\n",
154
+ "load_dotenv(override=True)\n",
155
+ "api_key = os.getenv('OPENAI_API_KEY')\n",
156
+ "\n",
157
+ "# Check the key\n",
158
+ "\n",
159
+ "if not api_key:\n",
160
+ " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n",
161
+ "elif not api_key.startswith(\"sk-proj-\"):\n",
162
+ " print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n",
163
+ "elif api_key.strip() != api_key:\n",
164
+ " print(\"An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them - see troubleshooting notebook\")\n",
165
+ "else:\n",
166
+ " print(\"API key found and looks good so far!\")\n"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "markdown",
171
+ "id": "442fc84b-0815-4f40-99ab-d9a5da6bda91",
172
+ "metadata": {},
173
+ "source": [
174
+ "# Let's make a quick call to a Frontier model to get started, as a preview!"
175
+ ]
176
+ },
177
+ {
178
+ "cell_type": "code",
179
+ "execution_count": null,
180
+ "id": "a58394bf-1e45-46af-9bfd-01e24da6f49a",
181
+ "metadata": {},
182
+ "outputs": [],
183
+ "source": [
184
+ "# To give you a preview -- calling OpenAI with these messages is this easy. Any problems, head over to the Troubleshooting notebook.\n",
185
+ "\n",
186
+ "message = \"Hello, GPT! This is my first ever message to you! Hi!\"\n",
187
+ "\n",
188
+ "messages = [{\"role\": \"user\", \"content\": message}]\n",
189
+ "\n",
190
+ "messages\n"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "id": "08330159",
197
+ "metadata": {},
198
+ "outputs": [],
199
+ "source": [
200
+ "openai = OpenAI()\n",
201
+ "\n",
202
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=messages)\n",
203
+ "response.choices[0].message.content"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "markdown",
208
+ "id": "2aa190e5-cb31-456a-96cc-db109919cd78",
209
+ "metadata": {},
210
+ "source": [
211
+ "## OK onwards with our first project"
212
+ ]
213
+ },
214
+ {
215
+ "cell_type": "code",
216
+ "execution_count": null,
217
+ "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97",
218
+ "metadata": {},
219
+ "outputs": [],
220
+ "source": [
221
+ "# Let's try out this utility\n",
222
+ "\n",
223
+ "ed = fetch_website_contents(\"https://edwarddonner.com\")\n",
224
+ "print(ed)"
225
+ ]
226
+ },
227
+ {
228
+ "cell_type": "markdown",
229
+ "id": "6a478a0c-2c53-48ff-869c-4d08199931e1",
230
+ "metadata": {},
231
+ "source": [
232
+ "## Types of prompts\n",
233
+ "\n",
234
+ "You may know this already - but if not, you will get very familiar with it!\n",
235
+ "\n",
236
+ "Models like GPT have been trained to receive instructions in a particular way.\n",
237
+ "\n",
238
+ "They expect to receive:\n",
239
+ "\n",
240
+ "**A system prompt** that tells them what task they are performing and what tone they should use\n",
241
+ "\n",
242
+ "**A user prompt** -- the conversation starter that they should reply to"
243
+ ]
244
+ },
245
+ {
246
+ "cell_type": "code",
247
+ "execution_count": null,
248
+ "id": "abdb8417-c5dc-44bc-9bee-2e059d162699",
249
+ "metadata": {},
250
+ "outputs": [],
251
+ "source": [
252
+ "# Define our system prompt - you can experiment with this later, changing the last sentence to 'Respond in markdown in Spanish.\"\n",
253
+ "\n",
254
+ "system_prompt = \"\"\"\n",
255
+ "You are a snarky assistant that analyzes the contents of a website,\n",
256
+ "and provides a short, snarky, humorous summary, ignoring text that might be navigation related.\n",
257
+ "Respond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.\n",
258
+ "\"\"\""
259
+ ]
260
+ },
261
+ {
262
+ "cell_type": "code",
263
+ "execution_count": null,
264
+ "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c",
265
+ "metadata": {},
266
+ "outputs": [],
267
+ "source": [
268
+ "# Define our user prompt\n",
269
+ "\n",
270
+ "user_prompt_prefix = \"\"\"\n",
271
+ "Here are the contents of a website.\n",
272
+ "Provide a short summary of this website.\n",
273
+ "If it includes news or announcements, then summarize these too.\n",
274
+ "\n",
275
+ "\"\"\""
276
+ ]
277
+ },
278
+ {
279
+ "cell_type": "markdown",
280
+ "id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc",
281
+ "metadata": {},
282
+ "source": [
283
+ "## Messages\n",
284
+ "\n",
285
+ "The API from OpenAI expects to receive messages in a particular structure.\n",
286
+ "Many of the other APIs share this structure:\n",
287
+ "\n",
288
+ "```python\n",
289
+ "[\n",
290
+ " {\"role\": \"system\", \"content\": \"system message goes here\"},\n",
291
+ " {\"role\": \"user\", \"content\": \"user message goes here\"}\n",
292
+ "]\n",
293
+ "```\n",
294
+ "To give you a preview, the next 2 cells make a rather simple call - we won't stretch the mighty GPT (yet!)"
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "code",
299
+ "execution_count": null,
300
+ "id": "f25dcd35-0cd0-4235-9f64-ac37ed9eaaa5",
301
+ "metadata": {},
302
+ "outputs": [],
303
+ "source": [
304
+ "messages = [\n",
305
+ " {\"role\": \"system\", \"content\": \"You are a expert in operations research, supply chain, and logistics. You are given a problem and you need to solve it using operations research techniques.\"},\n",
306
+ " {\"role\": \"user\", \"content\": \"Which method should I follow to solve MPMDCVRPTW problem?\"}\n",
307
+ "]\n",
308
+ "\n",
309
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=messages)\n",
310
+ "response.choices[0].message.content"
311
+ ]
312
+ },
313
+ {
314
+ "cell_type": "markdown",
315
+ "id": "d06e8d78-ce4c-4b05-aa8e-17050c82bb47",
316
+ "metadata": {},
317
+ "source": [
318
+ "## And now let's build useful messages for GPT-4.1-mini, using a function"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "code",
323
+ "execution_count": null,
324
+ "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88",
325
+ "metadata": {},
326
+ "outputs": [],
327
+ "source": [
328
+ "# See how this function creates exactly the format above\n",
329
+ "\n",
330
+ "def messages_for(website):\n",
331
+ " return [\n",
332
+ " {\"role\": \"system\", \"content\": system_prompt},\n",
333
+ " {\"role\": \"user\", \"content\": user_prompt_prefix + website}\n",
334
+ " ]"
335
+ ]
336
+ },
337
+ {
338
+ "cell_type": "code",
339
+ "execution_count": null,
340
+ "id": "36478464-39ee-485c-9f3f-6a4e458dbc9c",
341
+ "metadata": {},
342
+ "outputs": [],
343
+ "source": [
344
+ "# Try this out, and then try for a few more websites\n",
345
+ "\n",
346
+ "messages_for(ed)"
347
+ ]
348
+ },
349
+ {
350
+ "cell_type": "markdown",
351
+ "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0",
352
+ "metadata": {},
353
+ "source": [
354
+ "## Time to bring it together - the API for OpenAI is very simple!"
355
+ ]
356
+ },
357
+ {
358
+ "cell_type": "code",
359
+ "execution_count": null,
360
+ "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34",
361
+ "metadata": {},
362
+ "outputs": [],
363
+ "source": [
364
+ "# And now: call the OpenAI API. You will get very familiar with this!\n",
365
+ "\n",
366
+ "def summarize(url):\n",
367
+ " website = fetch_website_contents(url)\n",
368
+ " response = openai.chat.completions.create(\n",
369
+ " model = \"gpt-5-nano\",\n",
370
+ " messages = messages_for(website)\n",
371
+ " )\n",
372
+ " return response.choices[0].message.content"
373
+ ]
374
+ },
375
+ {
376
+ "cell_type": "code",
377
+ "execution_count": null,
378
+ "id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5",
379
+ "metadata": {},
380
+ "outputs": [],
381
+ "source": [
382
+ "summarize(\"https://edwarddonner.com\")"
383
+ ]
384
+ },
385
+ {
386
+ "cell_type": "code",
387
+ "execution_count": null,
388
+ "id": "3d926d59-450e-4609-92ba-2d6f244f1342",
389
+ "metadata": {},
390
+ "outputs": [],
391
+ "source": [
392
+ "# A function to display this nicely in the output, using markdown\n",
393
+ "\n",
394
+ "def display_summary(url):\n",
395
+ " summary = summarize(url)\n",
396
+ " display(Markdown(summary))"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "code",
401
+ "execution_count": null,
402
+ "id": "3018853a-445f-41ff-9560-d925d1774b2f",
403
+ "metadata": {},
404
+ "outputs": [],
405
+ "source": [
406
+ "display_summary(\"https://edwarddonner.com\")"
407
+ ]
408
+ },
409
+ {
410
+ "cell_type": "markdown",
411
+ "id": "b3bcf6f4-adce-45e9-97ad-d9a5d7a3a624",
412
+ "metadata": {},
413
+ "source": [
414
+ "# Let's try more websites\n",
415
+ "\n",
416
+ "Note that this will only work on websites that can be scraped using this simplistic approach.\n",
417
+ "\n",
418
+ "Websites that are rendered with Javascript, like React apps, won't show up. See the community-contributions folder for a Selenium implementation that gets around this. You'll need to read up on installing Selenium (ask ChatGPT!)\n",
419
+ "\n",
420
+ "Also Websites protected with CloudFront (and similar) may give 403 errors - many thanks Andy J for pointing this out.\n",
421
+ "\n",
422
+ "But many websites will work just fine!"
423
+ ]
424
+ },
425
+ {
426
+ "cell_type": "code",
427
+ "execution_count": null,
428
+ "id": "45d83403-a24c-44b5-84ac-961449b4008f",
429
+ "metadata": {},
430
+ "outputs": [],
431
+ "source": [
432
+ "display_summary(\"https://cnn.com\")"
433
+ ]
434
+ },
435
+ {
436
+ "cell_type": "code",
437
+ "execution_count": null,
438
+ "id": "75e9fd40-b354-4341-991e-863ef2e59db7",
439
+ "metadata": {},
440
+ "outputs": [],
441
+ "source": [
442
+ "display_summary(\"https://anthropic.com\")"
443
+ ]
444
+ },
445
+ {
446
+ "cell_type": "markdown",
447
+ "id": "c951be1a-7f1b-448f-af1f-845978e47e2c",
448
+ "metadata": {},
449
+ "source": [
450
+ "<table style=\"margin: 0; text-align: left;\">\n",
451
+ " <tr>\n",
452
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
453
+ " <img src=\"../assets/business.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
454
+ " </td>\n",
455
+ " <td>\n",
456
+ " <h2 style=\"color:#181;\">Business applications</h2>\n",
457
+ " <span style=\"color:#181;\">In this exercise, you experienced calling the Cloud API of a Frontier Model (a leading model at the frontier of AI) for the first time. We will be using APIs like OpenAI at many stages in the course, in addition to building our own LLMs.\n",
458
+ "\n",
459
+ "More specifically, we've applied this to Summarization - a classic Gen AI use case to make a summary. This can be applied to any business vertical - summarizing the news, summarizing financial performance, summarizing a resume in a cover letter - the applications are limitless. Consider how you could apply Summarization in your business, and try prototyping a solution.</span>\n",
460
+ " </td>\n",
461
+ " </tr>\n",
462
+ "</table>\n",
463
+ "\n",
464
+ "<table style=\"margin: 0; text-align: left;\">\n",
465
+ " <tr>\n",
466
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
467
+ " <img src=\"../assets/important.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
468
+ " </td>\n",
469
+ " <td>\n",
470
+ " <h2 style=\"color:#900;\">Before you continue - now try yourself</h2>\n",
471
+ " <span style=\"color:#900;\">Use the cell below to make your own simple commercial example. Stick with the summarization use case for now. Here's an idea: write something that will take the contents of an email, and will suggest an appropriate short subject line for the email. That's the kind of feature that might be built into a commercial email tool.</span>\n",
472
+ " </td>\n",
473
+ " </tr>\n",
474
+ "</table>"
475
+ ]
476
+ },
477
+ {
478
+ "cell_type": "code",
479
+ "execution_count": null,
480
+ "id": "00743dac-0e70-45b7-879a-d7293a6f68a6",
481
+ "metadata": {},
482
+ "outputs": [],
483
+ "source": [
484
+ "# Step 1: Create your prompts\n",
485
+ "\n",
486
+ "system_prompt = \"You are an expert in law, specially you operate on consumer court cases. You have the following roles: 1. You advise people on whether they should file consumer court cases and tif yes then how to do it. 2. You help them prepare for the case. 3. You help them prepare for the hearing. 4. You help them prepare for the judgment. 5. You help them prepare for the appeal. 6. You help them prepare for the execution. 7. You help them prepare for the settlement. 8. You help them prepare for the settlement.\"\n",
487
+ "user_prompt = \"\"\"\n",
488
+ " I am giving you a brief on what happend to us in a hospital: \"My wife was having loose motions and the motion did not stop even after taking oral medicines for 1 and half days. We went to a doctor in the OPD of Noble hospital Pune. The doctor after diagnosing for about 2-3 minutes said that she needs to be hospitalized. We admitted her in the hospital immediately. We told the doctor all her conditions including that her periods date has arrived today but she is not feeling any cramps. \n",
489
+ " The doctor started the IV fluids and gave antibiotics which was intervainous and oral. They did 6-7 different tests including LFT, RFT, CBC, USG etc. But they didn't bother to do a pregnancy test. The USG showed indications of infection and Gastritis. Her motion continued till the 4th day of hospitalisation. On the 4th day the doctor said they no pathogen is found in all the tests so they will have to do CT scan and endoscopy. We simply refused to do these tests since she was having a case of diarrhea. \n",
490
+ " And from the afternoon her motion stopped as well. When the doctors saw her last motion had crossed 4 hours, they suddenly gave some blood tests. When I asked, they said that we need to check how the antibiotics are behaving in her body. Without telling us the exact tests and the total costs that will incur, they took 6 blood samples. All these days, my wife was going through mental pressure and frustration because she was unable to understand why a diarrhea is not getting resolved. \n",
491
+ " The next day I kind of forced them to discharge her because she did not have any motion from previous afternoon. She had a mediclaim. After the bil settlement, I saw they charged a total of 53000 rupees. The 6 blood tests from previous day costed around 9000 rupees. After returing home, my wife was still not feeling that goo since her digestive system was badly hit by all the antibiotics and the pathogen which the doctors could not find in any test. But she was feeling nauseated and felt like vomiting. \n",
492
+ " So, we did a pregnancy test. She was positive. She was in immediate shock and panic since the antibiotic course was long and heavy and it may cause annomalies in the baby. We immediately went to a gynocologist. After examining and going through the test results and medicines taken during hospitalisation, the doctor told that there can be a risk. So now we are terminating the pregnancy\"\n",
493
+ "\n",
494
+ " I want you to tell me what I should do now and how I should proceed.\n",
495
+ "\n",
496
+ "\"\"\"\n",
497
+ "\n",
498
+ "# Step 2: Make the messages list\n",
499
+ "\n",
500
+ "messages = [{\"role\":\"system\", \"content\": system_prompt},\n",
501
+ " {\"role\":\"user\", \"content\": user_prompt}] # fill this in\n",
502
+ "\n",
503
+ "# Step 3: Call OpenAI\n",
504
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=messages)\n",
505
+ "response_1 = response.choices[0].message.content\n",
506
+ "\n",
507
+ "display(Markdown(response_1))\n",
508
+ "# Step 4: print the result\n",
509
+ "# print("
510
+ ]
511
+ },
512
+ {
513
+ "cell_type": "markdown",
514
+ "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda",
515
+ "metadata": {},
516
+ "source": [
517
+ "## An extra exercise for those who enjoy web scraping\n",
518
+ "\n",
519
+ "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. In the community-contributions folder, you'll find an example Selenium solution from a student (thank you!)"
520
+ ]
521
+ },
522
+ {
523
+ "cell_type": "markdown",
524
+ "id": "eeab24dc-5f90-4570-b542-b0585aca3eb6",
525
+ "metadata": {},
526
+ "source": [
527
+ "# Sharing your code\n",
528
+ "\n",
529
+ "I'd love it if you share your code afterwards so I can share it with others! You'll notice that some students have already made changes (including a Selenium implementation) which you will find in the community-contributions folder. If you'd like add your changes to that folder, submit a Pull Request with your new versions in that folder and I'll merge your changes.\n",
530
+ "\n",
531
+ "If you're not an expert with git (and I am not!) then I've given you complete instructions in the guides folder, guide 3, and pasting here:\n",
532
+ "\n",
533
+ "Here's the overall steps involved in making a PR and the key instructions: \n",
534
+ "https://edwarddonner.com/pr \n",
535
+ "\n",
536
+ "Please check before submitting: \n",
537
+ "1. Your PR only contains changes in community-contributions (unless we've discussed it) \n",
538
+ "2. All notebook outputs are clear \n",
539
+ "3. Less than 2,000 lines of code in total, and not too many files \n",
540
+ "4. Don't include unnecessary test files, or overly wordy README or .env.example or emojis or other LLM artifacts!\n",
541
+ "\n",
542
+ "Thanks so much!\n",
543
+ "\n",
544
+ "Detailed steps here: \n",
545
+ "\n",
546
+ "https://chatgpt.com/share/6873c22b-2a1c-8012-bc9a-debdcf7c835b"
547
+ ]
548
+ },
549
+ {
550
+ "cell_type": "code",
551
+ "execution_count": null,
552
+ "id": "f4484fcf-8b39-4c3f-9674-37970ed71988",
553
+ "metadata": {},
554
+ "outputs": [],
555
+ "source": []
556
+ }
557
+ ],
558
+ "metadata": {
559
+ "kernelspec": {
560
+ "display_name": ".venv",
561
+ "language": "python",
562
+ "name": "python3"
563
+ },
564
+ "language_info": {
565
+ "codemirror_mode": {
566
+ "name": "ipython",
567
+ "version": 3
568
+ },
569
+ "file_extension": ".py",
570
+ "mimetype": "text/x-python",
571
+ "name": "python",
572
+ "nbconvert_exporter": "python",
573
+ "pygments_lexer": "ipython3",
574
+ "version": "3.12.12"
575
+ }
576
+ },
577
+ "nbformat": 4,
578
+ "nbformat_minor": 5
579
+ }
community_contributions/1_foundations_using_gemini/1_lab1.ipynb ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "gemini_api_key = os.getenv('GEMINI_API_KEY')\n",
152
+ "\n",
153
+ "if gemini_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {gemini_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
184
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
185
+ "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": null,
191
+ "metadata": {},
192
+ "outputs": [],
193
+ "source": [
194
+ "# Create a list of messages in the familiar OpenAI format\n",
195
+ "\n",
196
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
197
+ ]
198
+ },
199
+ {
200
+ "cell_type": "code",
201
+ "execution_count": null,
202
+ "metadata": {},
203
+ "outputs": [],
204
+ "source": [
205
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
206
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
207
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
208
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
209
+ "model = \"gemini-2.5-flash-preview-05-20\"\n",
210
+ "response = gemini.chat.completions.create(\n",
211
+ " model=model,\n",
212
+ " messages=messages\n",
213
+ ")\n",
214
+ "\n",
215
+ "print(response.choices[0].message.content)\n"
216
+ ]
217
+ },
218
+ {
219
+ "cell_type": "code",
220
+ "execution_count": null,
221
+ "metadata": {},
222
+ "outputs": [],
223
+ "source": [
224
+ "# And now - let's ask for a question:\n",
225
+ "\n",
226
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
227
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": null,
233
+ "metadata": {},
234
+ "outputs": [],
235
+ "source": [
236
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
237
+ "\n",
238
+ "response = gemini.chat.completions.create(\n",
239
+ " model=model,\n",
240
+ " messages=messages\n",
241
+ ")\n",
242
+ "\n",
243
+ "question = response.choices[0].message.content\n",
244
+ "\n",
245
+ "print(question)\n"
246
+ ]
247
+ },
248
+ {
249
+ "cell_type": "code",
250
+ "execution_count": null,
251
+ "metadata": {},
252
+ "outputs": [],
253
+ "source": [
254
+ "# form a new messages list\n",
255
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
256
+ ]
257
+ },
258
+ {
259
+ "cell_type": "code",
260
+ "execution_count": null,
261
+ "metadata": {},
262
+ "outputs": [],
263
+ "source": [
264
+ "# Ask it again\n",
265
+ "\n",
266
+ "response = gemini.chat.completions.create(\n",
267
+ " model=model,\n",
268
+ " messages=messages\n",
269
+ ")\n",
270
+ "\n",
271
+ "answer = response.choices[0].message.content\n",
272
+ "print(answer)\n"
273
+ ]
274
+ },
275
+ {
276
+ "cell_type": "code",
277
+ "execution_count": null,
278
+ "metadata": {},
279
+ "outputs": [],
280
+ "source": [
281
+ "from IPython.display import Markdown, display\n",
282
+ "\n",
283
+ "display(Markdown(answer))\n",
284
+ "\n"
285
+ ]
286
+ },
287
+ {
288
+ "cell_type": "markdown",
289
+ "metadata": {},
290
+ "source": [
291
+ "# Congratulations!\n",
292
+ "\n",
293
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
294
+ "\n",
295
+ "Next time things get more interesting..."
296
+ ]
297
+ },
298
+ {
299
+ "cell_type": "markdown",
300
+ "metadata": {},
301
+ "source": [
302
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
303
+ " <tr>\n",
304
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
305
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
306
+ " </td>\n",
307
+ " <td>\n",
308
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
309
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
310
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
311
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
312
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
313
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
314
+ " </span>\n",
315
+ " </td>\n",
316
+ " </tr>\n",
317
+ "</table>"
318
+ ]
319
+ },
320
+ {
321
+ "cell_type": "code",
322
+ "execution_count": null,
323
+ "metadata": {},
324
+ "outputs": [],
325
+ "source": [
326
+ "# First create the messages:\n",
327
+ "\n",
328
+ "messages = [{\"role\": \"user\", \"content\": \"Pick a business area that might be worth exploring for an Agentic AI opportunity.\"}]\n",
329
+ "\n",
330
+ "# Then make the first call:\n",
331
+ "\n",
332
+ "response = gemini.chat.completions.create(\n",
333
+ " model=model,\n",
334
+ " messages=messages\n",
335
+ ")\n",
336
+ "\n",
337
+ "# Then read the business idea:\n",
338
+ "\n",
339
+ "business_idea = response.choices[0].message.content\n",
340
+ "\n",
341
+ "\n",
342
+ "display(Markdown(business_idea))\n",
343
+ "\n",
344
+ "# And repeat! In the next message, include the business idea within the message"
345
+ ]
346
+ },
347
+ {
348
+ "cell_type": "code",
349
+ "execution_count": null,
350
+ "metadata": {},
351
+ "outputs": [],
352
+ "source": [
353
+ "messages = [{\"role\": \"user\", \"content\": f\"Present a pain-point in that {business_idea} industry - something challenging that might be ripe for an Agentic solution.\"}]\n",
354
+ "\n",
355
+ "response = gemini.chat.completions.create(\n",
356
+ " model=model,\n",
357
+ " messages=messages\n",
358
+ ")\n",
359
+ "\n",
360
+ "pain_point = response.choices[0].message.content\n",
361
+ "\n",
362
+ "display(Markdown(pain_point))"
363
+ ]
364
+ },
365
+ {
366
+ "cell_type": "code",
367
+ "execution_count": null,
368
+ "metadata": {},
369
+ "outputs": [],
370
+ "source": [
371
+ "messages = [{\"role\": \"user\", \"content\": f\"Propose an Agentic AI solution to the {pain_point} in the {business_idea} industry.\"}]\n",
372
+ "\n",
373
+ "response = gemini.chat.completions.create(\n",
374
+ " model=model,\n",
375
+ " messages=messages\n",
376
+ ")\n",
377
+ "\n",
378
+ "agentic_solution = response.choices[0].message.content\n",
379
+ "\n",
380
+ "display(Markdown(agentic_solution))\n",
381
+ "\n"
382
+ ]
383
+ }
384
+ ],
385
+ "metadata": {
386
+ "kernelspec": {
387
+ "display_name": ".venv",
388
+ "language": "python",
389
+ "name": "python3"
390
+ },
391
+ "language_info": {
392
+ "codemirror_mode": {
393
+ "name": "ipython",
394
+ "version": 3
395
+ },
396
+ "file_extension": ".py",
397
+ "mimetype": "text/x-python",
398
+ "name": "python",
399
+ "nbconvert_exporter": "python",
400
+ "pygments_lexer": "ipython3",
401
+ "version": "3.12.12"
402
+ }
403
+ },
404
+ "nbformat": 4,
405
+ "nbformat_minor": 2
406
+ }
community_contributions/1_foundations_using_gemini/2_lab2.ipynb ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": null,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# 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": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "# Always remember to do this!\n",
53
+ "load_dotenv(override=True)"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": null,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "# Print the key prefixes to help with any debugging\n",
63
+ "\n",
64
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
65
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
66
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
67
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
68
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
69
+ "\n",
70
+ "if openai_api_key:\n",
71
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
72
+ "else:\n",
73
+ " print(\"OpenAI API Key not set\")\n",
74
+ " \n",
75
+ "if anthropic_api_key:\n",
76
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
77
+ "else:\n",
78
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
79
+ "\n",
80
+ "if google_api_key:\n",
81
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
82
+ "else:\n",
83
+ " print(\"Google API Key not set (and this is optional)\")\n",
84
+ "\n",
85
+ "if deepseek_api_key:\n",
86
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
87
+ "else:\n",
88
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
89
+ "\n",
90
+ "if groq_api_key:\n",
91
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
92
+ "else:\n",
93
+ " print(\"Groq API Key not set (and this is optional)\")"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": null,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
103
+ "request += \"Answer only with the question, no explanation.\"\n",
104
+ "messages = [{\"role\": \"user\", \"content\": request}]"
105
+ ]
106
+ },
107
+ {
108
+ "cell_type": "code",
109
+ "execution_count": null,
110
+ "metadata": {},
111
+ "outputs": [],
112
+ "source": [
113
+ "messages"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": null,
119
+ "metadata": {},
120
+ "outputs": [],
121
+ "source": [
122
+ "openai = OpenAI()\n",
123
+ "response = openai.chat.completions.create(\n",
124
+ " model=\"gpt-5-mini\",\n",
125
+ " messages=messages,\n",
126
+ ")\n",
127
+ "question = response.choices[0].message.content\n",
128
+ "print(question)\n"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "competitors = []\n",
138
+ "answers = []\n",
139
+ "messages = [{\"role\": \"user\", \"content\": question}]"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "markdown",
144
+ "metadata": {},
145
+ "source": [
146
+ "## Note - update since the videos\n",
147
+ "\n",
148
+ "I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video."
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "code",
153
+ "execution_count": null,
154
+ "metadata": {},
155
+ "outputs": [],
156
+ "source": [
157
+ "# The API we know well\n",
158
+ "# I've updated this with the latest model, but it can take some time because it likes to think!\n",
159
+ "# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\n",
160
+ "\n",
161
+ "model_name = \"gpt-5-nano\"\n",
162
+ "\n",
163
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
164
+ "answer = response.choices[0].message.content\n",
165
+ "\n",
166
+ "display(Markdown(answer))\n",
167
+ "competitors.append(model_name)\n",
168
+ "answers.append(answer)"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": null,
174
+ "metadata": {},
175
+ "outputs": [],
176
+ "source": [
177
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
178
+ "\n",
179
+ "model_name = \"claude-sonnet-4-5\"\n",
180
+ "\n",
181
+ "claude = Anthropic()\n",
182
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
183
+ "answer = response.content[0].text\n",
184
+ "\n",
185
+ "display(Markdown(answer))\n",
186
+ "competitors.append(model_name)\n",
187
+ "answers.append(answer)"
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "metadata": {},
194
+ "outputs": [],
195
+ "source": [
196
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
197
+ "model_name = \"gemini-2.5-flash\"\n",
198
+ "\n",
199
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
200
+ "answer = response.choices[0].message.content\n",
201
+ "\n",
202
+ "display(Markdown(answer))\n",
203
+ "competitors.append(model_name)\n",
204
+ "answers.append(answer)"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "code",
209
+ "execution_count": null,
210
+ "metadata": {},
211
+ "outputs": [],
212
+ "source": [
213
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
214
+ "model_name = \"deepseek-chat\"\n",
215
+ "\n",
216
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
217
+ "answer = response.choices[0].message.content\n",
218
+ "\n",
219
+ "display(Markdown(answer))\n",
220
+ "competitors.append(model_name)\n",
221
+ "answers.append(answer)"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": null,
227
+ "metadata": {},
228
+ "outputs": [],
229
+ "source": [
230
+ "# Updated with the latest Open Source model from OpenAI\n",
231
+ "\n",
232
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
233
+ "model_name = \"openai/gpt-oss-120b\"\n",
234
+ "\n",
235
+ "response = groq.chat.completions.create(model=model_name, messages=messages)\n",
236
+ "answer = response.choices[0].message.content\n",
237
+ "\n",
238
+ "display(Markdown(answer))\n",
239
+ "competitors.append(model_name)\n",
240
+ "answers.append(answer)\n"
241
+ ]
242
+ },
243
+ {
244
+ "cell_type": "markdown",
245
+ "metadata": {},
246
+ "source": [
247
+ "## For the next cell, we will use Ollama\n",
248
+ "\n",
249
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
250
+ "and runs models locally using high performance C++ code.\n",
251
+ "\n",
252
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
253
+ "\n",
254
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
255
+ "\n",
256
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
257
+ "\n",
258
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
259
+ "\n",
260
+ "`ollama pull <model_name>` downloads a model locally \n",
261
+ "`ollama ls` lists all the models you've downloaded \n",
262
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "markdown",
267
+ "metadata": {},
268
+ "source": [
269
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
270
+ " <tr>\n",
271
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
272
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
273
+ " </td>\n",
274
+ " <td>\n",
275
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
276
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
277
+ " </span>\n",
278
+ " </td>\n",
279
+ " </tr>\n",
280
+ "</table>"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": null,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "!ollama pull llama3.2"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": null,
295
+ "metadata": {},
296
+ "outputs": [],
297
+ "source": [
298
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
299
+ "model_name = \"llama3.2\"\n",
300
+ "\n",
301
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
302
+ "answer = response.choices[0].message.content\n",
303
+ "\n",
304
+ "display(Markdown(answer))\n",
305
+ "competitors.append(model_name)\n",
306
+ "answers.append(answer)"
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "code",
311
+ "execution_count": null,
312
+ "metadata": {},
313
+ "outputs": [],
314
+ "source": [
315
+ "# So where are we?\n",
316
+ "\n",
317
+ "print(competitors)\n",
318
+ "print(answers)\n"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "code",
323
+ "execution_count": null,
324
+ "metadata": {},
325
+ "outputs": [],
326
+ "source": [
327
+ "# It's nice to know how to use \"zip\"\n",
328
+ "for competitor, answer in zip(competitors, answers):\n",
329
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
330
+ ]
331
+ },
332
+ {
333
+ "cell_type": "code",
334
+ "execution_count": null,
335
+ "metadata": {},
336
+ "outputs": [],
337
+ "source": [
338
+ "# Let's bring this together - note the use of \"enumerate\"\n",
339
+ "\n",
340
+ "together = \"\"\n",
341
+ "for index, answer in enumerate(answers):\n",
342
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
343
+ " together += answer + \"\\n\\n\""
344
+ ]
345
+ },
346
+ {
347
+ "cell_type": "code",
348
+ "execution_count": null,
349
+ "metadata": {},
350
+ "outputs": [],
351
+ "source": [
352
+ "print(together)"
353
+ ]
354
+ },
355
+ {
356
+ "cell_type": "markdown",
357
+ "metadata": {},
358
+ "source": []
359
+ },
360
+ {
361
+ "cell_type": "code",
362
+ "execution_count": null,
363
+ "metadata": {},
364
+ "outputs": [],
365
+ "source": [
366
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
367
+ "Each model has been given this question:\n",
368
+ "\n",
369
+ "{question}\n",
370
+ "\n",
371
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
372
+ "Respond with JSON, and only JSON, with the following format:\n",
373
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
374
+ "\n",
375
+ "Here are the responses from each competitor:\n",
376
+ "\n",
377
+ "{together}\n",
378
+ "\n",
379
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
380
+ ]
381
+ },
382
+ {
383
+ "cell_type": "code",
384
+ "execution_count": null,
385
+ "metadata": {},
386
+ "outputs": [],
387
+ "source": [
388
+ "print(judge)"
389
+ ]
390
+ },
391
+ {
392
+ "cell_type": "code",
393
+ "execution_count": null,
394
+ "metadata": {},
395
+ "outputs": [],
396
+ "source": [
397
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
398
+ ]
399
+ },
400
+ {
401
+ "cell_type": "code",
402
+ "execution_count": null,
403
+ "metadata": {},
404
+ "outputs": [],
405
+ "source": [
406
+ "# Judgement time!\n",
407
+ "\n",
408
+ "openai = OpenAI()\n",
409
+ "response = openai.chat.completions.create(\n",
410
+ " model=\"gpt-5-mini\",\n",
411
+ " messages=judge_messages,\n",
412
+ ")\n",
413
+ "results = response.choices[0].message.content\n",
414
+ "print(results)\n"
415
+ ]
416
+ },
417
+ {
418
+ "cell_type": "code",
419
+ "execution_count": null,
420
+ "metadata": {},
421
+ "outputs": [],
422
+ "source": [
423
+ "# OK let's turn this into results!\n",
424
+ "\n",
425
+ "results_dict = json.loads(results)\n",
426
+ "ranks = results_dict[\"results\"]\n",
427
+ "for index, result in enumerate(ranks):\n",
428
+ " competitor = competitors[int(result)-1]\n",
429
+ " print(f\"Rank {index+1}: {competitor}\")"
430
+ ]
431
+ },
432
+ {
433
+ "cell_type": "markdown",
434
+ "metadata": {},
435
+ "source": [
436
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
437
+ " <tr>\n",
438
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
439
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
440
+ " </td>\n",
441
+ " <td>\n",
442
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
443
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
444
+ " </span>\n",
445
+ " </td>\n",
446
+ " </tr>\n",
447
+ "</table>"
448
+ ]
449
+ },
450
+ {
451
+ "cell_type": "markdown",
452
+ "metadata": {},
453
+ "source": [
454
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
455
+ " <tr>\n",
456
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
457
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
458
+ " </td>\n",
459
+ " <td>\n",
460
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
461
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
462
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
463
+ " to business projects where accuracy is critical.\n",
464
+ " </span>\n",
465
+ " </td>\n",
466
+ " </tr>\n",
467
+ "</table>"
468
+ ]
469
+ }
470
+ ],
471
+ "metadata": {
472
+ "kernelspec": {
473
+ "display_name": ".venv",
474
+ "language": "python",
475
+ "name": "python3"
476
+ },
477
+ "language_info": {
478
+ "codemirror_mode": {
479
+ "name": "ipython",
480
+ "version": 3
481
+ },
482
+ "file_extension": ".py",
483
+ "mimetype": "text/x-python",
484
+ "name": "python",
485
+ "nbconvert_exporter": "python",
486
+ "pygments_lexer": "ipython3",
487
+ "version": "3.12.12"
488
+ }
489
+ },
490
+ "nbformat": 4,
491
+ "nbformat_minor": 2
492
+ }
community_contributions/1_foundations_using_gemini/3_lab3.ipynb ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to Lab 3 for Week 1 Day 4\n",
8
+ "\n",
9
+ "Today we're going to build something with immediate value!\n",
10
+ "\n",
11
+ "In the folder `me` I've put a single file `linkedin.pdf` - it's a PDF download of my LinkedIn profile.\n",
12
+ "\n",
13
+ "Please replace it with yours!\n",
14
+ "\n",
15
+ "I've also made a file called `summary.txt`\n",
16
+ "\n",
17
+ "We're not going to use Tools just yet - we're going to add the tool tomorrow."
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "markdown",
22
+ "metadata": {},
23
+ "source": [
24
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
25
+ " <tr>\n",
26
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
27
+ " <img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
28
+ " </td>\n",
29
+ " <td>\n",
30
+ " <h2 style=\"color:#00bfff;\">Looking up packages</h2>\n",
31
+ " <span style=\"color:#00bfff;\">In this lab, we're going to use the wonderful Gradio package for building quick UIs, \n",
32
+ " and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \n",
33
+ " ChatGPT or Claude, and you find all open-source packages on the repository <a href=\"https://pypi.org\">https://pypi.org</a>.\n",
34
+ " </span>\n",
35
+ " </td>\n",
36
+ " </tr>\n",
37
+ "</table>"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!\n",
47
+ "\n",
48
+ "from dotenv import load_dotenv\n",
49
+ "from openai import OpenAI\n",
50
+ "from pypdf import PdfReader\n",
51
+ "import os\n",
52
+ "import gradio as gr"
53
+ ]
54
+ },
55
+ {
56
+ "cell_type": "code",
57
+ "execution_count": null,
58
+ "metadata": {},
59
+ "outputs": [],
60
+ "source": [
61
+ "load_dotenv(override=True)\n",
62
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
63
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
64
+ "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": null,
70
+ "metadata": {},
71
+ "outputs": [],
72
+ "source": [
73
+ "reader = PdfReader(\"me/linkedin.pdf\")\n",
74
+ "linkedin = \"\"\n",
75
+ "for page in reader.pages:\n",
76
+ " text = page.extract_text()\n",
77
+ " if text:\n",
78
+ " linkedin += text"
79
+ ]
80
+ },
81
+ {
82
+ "cell_type": "code",
83
+ "execution_count": null,
84
+ "metadata": {},
85
+ "outputs": [],
86
+ "source": [
87
+ "print(linkedin)"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": null,
93
+ "metadata": {},
94
+ "outputs": [],
95
+ "source": [
96
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
97
+ " summary = f.read()"
98
+ ]
99
+ },
100
+ {
101
+ "cell_type": "code",
102
+ "execution_count": null,
103
+ "metadata": {},
104
+ "outputs": [],
105
+ "source": [
106
+ "name = \"Harsh Patidar\""
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "code",
111
+ "execution_count": null,
112
+ "metadata": {},
113
+ "outputs": [],
114
+ "source": [
115
+ "system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
116
+ "particularly questions related to {name}'s career, background, skills and experience. \\\n",
117
+ "Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
118
+ "You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
119
+ "Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
120
+ "If you don't know the answer, say so.\"\n",
121
+ "\n",
122
+ "system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
123
+ "system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": null,
129
+ "metadata": {},
130
+ "outputs": [],
131
+ "source": [
132
+ "system_prompt"
133
+ ]
134
+ },
135
+ {
136
+ "cell_type": "code",
137
+ "execution_count": null,
138
+ "metadata": {},
139
+ "outputs": [],
140
+ "source": [
141
+ "model_name = \"gemini-2.5-flash-preview-05-20\""
142
+ ]
143
+ },
144
+ {
145
+ "cell_type": "code",
146
+ "execution_count": null,
147
+ "metadata": {},
148
+ "outputs": [],
149
+ "source": [
150
+ "def chat(message, history):\n",
151
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
152
+ " response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
153
+ " return response.choices[0].message.content"
154
+ ]
155
+ },
156
+ {
157
+ "cell_type": "markdown",
158
+ "metadata": {},
159
+ "source": [
160
+ "## Special note for people not using OpenAI\n",
161
+ "\n",
162
+ "Some providers, like Groq, might give an error when you send your second message in the chat.\n",
163
+ "\n",
164
+ "This is because Gradio shoves some extra fields into the history object. OpenAI doesn't mind; but some other models complain.\n",
165
+ "\n",
166
+ "If this happens, the solution is to add this first line to the chat() function above. It cleans up the history variable:\n",
167
+ "\n",
168
+ "```python\n",
169
+ "history = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
170
+ "```\n",
171
+ "\n",
172
+ "You may need to add this in other chat() callback functions in the future, too."
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": null,
178
+ "metadata": {},
179
+ "outputs": [],
180
+ "source": [
181
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "markdown",
186
+ "metadata": {},
187
+ "source": [
188
+ "## A lot is about to happen...\n",
189
+ "\n",
190
+ "1. Be able to ask an LLM to evaluate an answer\n",
191
+ "2. Be able to rerun if the answer fails evaluation\n",
192
+ "3. Put this together into 1 workflow\n",
193
+ "\n",
194
+ "All without any Agentic framework!"
195
+ ]
196
+ },
197
+ {
198
+ "cell_type": "code",
199
+ "execution_count": null,
200
+ "metadata": {},
201
+ "outputs": [],
202
+ "source": [
203
+ "# Create a Pydantic model for the Evaluation\n",
204
+ "\n",
205
+ "from pydantic import BaseModel\n",
206
+ "\n",
207
+ "class Evaluation(BaseModel):\n",
208
+ " is_acceptable: bool\n",
209
+ " feedback: str\n"
210
+ ]
211
+ },
212
+ {
213
+ "cell_type": "code",
214
+ "execution_count": null,
215
+ "metadata": {},
216
+ "outputs": [],
217
+ "source": [
218
+ "evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n",
219
+ "You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\n",
220
+ "The Agent is playing the role of {name} and is representing {name} on their website. \\\n",
221
+ "The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
222
+ "The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n",
223
+ "\n",
224
+ "evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
225
+ "evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\""
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": null,
231
+ "metadata": {},
232
+ "outputs": [],
233
+ "source": [
234
+ "def evaluator_user_prompt(reply, message, history):\n",
235
+ " user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n",
236
+ " user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n",
237
+ " user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n",
238
+ " user_prompt += \"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n",
239
+ " return user_prompt"
240
+ ]
241
+ },
242
+ {
243
+ "cell_type": "code",
244
+ "execution_count": null,
245
+ "metadata": {},
246
+ "outputs": [],
247
+ "source": [
248
+ "import os\n",
249
+ "gemini = OpenAI(\n",
250
+ " api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
251
+ " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
252
+ ")"
253
+ ]
254
+ },
255
+ {
256
+ "cell_type": "code",
257
+ "execution_count": null,
258
+ "metadata": {},
259
+ "outputs": [],
260
+ "source": [
261
+ "def evaluate(reply, message, history) -> Evaluation:\n",
262
+ "\n",
263
+ " messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
264
+ " response = gemini.beta.chat.completions.parse(model=model_name, messages=messages, response_format=Evaluation)\n",
265
+ " return response.choices[0].message.parsed"
266
+ ]
267
+ },
268
+ {
269
+ "cell_type": "code",
270
+ "execution_count": null,
271
+ "metadata": {},
272
+ "outputs": [],
273
+ "source": [
274
+ "messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"do you hold a patent?\"}]\n",
275
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
276
+ "reply = response.choices[0].message.content"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": null,
282
+ "metadata": {},
283
+ "outputs": [],
284
+ "source": [
285
+ "reply"
286
+ ]
287
+ },
288
+ {
289
+ "cell_type": "code",
290
+ "execution_count": null,
291
+ "metadata": {},
292
+ "outputs": [],
293
+ "source": [
294
+ "evaluate(reply, \"do you hold a patent?\", messages[:1])"
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "code",
299
+ "execution_count": null,
300
+ "metadata": {},
301
+ "outputs": [],
302
+ "source": [
303
+ "def rerun(reply, message, history, feedback):\n",
304
+ " updated_system_prompt = system_prompt + \"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n",
305
+ " updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n",
306
+ " updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n",
307
+ " messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
308
+ " response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
309
+ " return response.choices[0].message.content"
310
+ ]
311
+ },
312
+ {
313
+ "cell_type": "code",
314
+ "execution_count": null,
315
+ "metadata": {},
316
+ "outputs": [],
317
+ "source": [
318
+ "def chat(message, history):\n",
319
+ " if \"patent\" in message:\n",
320
+ " system = system_prompt + \"\\n\\nEverything in your reply needs to be in pig latin - \\\n",
321
+ " it is mandatory that you respond only and entirely in pig latin\"\n",
322
+ " else:\n",
323
+ " system = system_prompt\n",
324
+ " messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
325
+ " response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
326
+ " reply =response.choices[0].message.content\n",
327
+ "\n",
328
+ " evaluation = evaluate(reply, message, history)\n",
329
+ " \n",
330
+ " if evaluation.is_acceptable:\n",
331
+ " print(\"Passed evaluation - returning reply\")\n",
332
+ " else:\n",
333
+ " print(\"Failed evaluation - retrying\")\n",
334
+ " print(evaluation.feedback)\n",
335
+ " reply = rerun(reply, message, history, evaluation.feedback) \n",
336
+ " return reply"
337
+ ]
338
+ },
339
+ {
340
+ "cell_type": "code",
341
+ "execution_count": null,
342
+ "metadata": {},
343
+ "outputs": [],
344
+ "source": [
345
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
346
+ ]
347
+ },
348
+ {
349
+ "cell_type": "markdown",
350
+ "metadata": {},
351
+ "source": []
352
+ },
353
+ {
354
+ "cell_type": "code",
355
+ "execution_count": null,
356
+ "metadata": {},
357
+ "outputs": [],
358
+ "source": []
359
+ }
360
+ ],
361
+ "metadata": {
362
+ "kernelspec": {
363
+ "display_name": ".venv",
364
+ "language": "python",
365
+ "name": "python3"
366
+ },
367
+ "language_info": {
368
+ "codemirror_mode": {
369
+ "name": "ipython",
370
+ "version": 3
371
+ },
372
+ "file_extension": ".py",
373
+ "mimetype": "text/x-python",
374
+ "name": "python",
375
+ "nbconvert_exporter": "python",
376
+ "pygments_lexer": "ipython3",
377
+ "version": "3.12.12"
378
+ }
379
+ },
380
+ "nbformat": 4,
381
+ "nbformat_minor": 2
382
+ }
community_contributions/1_foundations_using_gemini/4_lab4.ipynb ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## The first big project - Professionally You!\n",
8
+ "\n",
9
+ "### And, Tool use.\n",
10
+ "\n",
11
+ "### But first: introducing Pushover\n",
12
+ "\n",
13
+ "Pushover is a nifty tool for sending Push Notifications to your phone.\n",
14
+ "\n",
15
+ "It's super easy to set up and install!\n",
16
+ "\n",
17
+ "Simply visit https://pushover.net/ and click 'Login or Signup' on the top right to sign up for a free account, and create your API keys.\n",
18
+ "\n",
19
+ "Once you've signed up, on the home screen, click \"Create an Application/API Token\", and give it any name (like Agents) and click Create Application.\n",
20
+ "\n",
21
+ "Then add 2 lines to your `.env` file:\n",
22
+ "\n",
23
+ "PUSHOVER_USER=_put the key that's on the top right of your Pushover home screen and probably starts with a u_ \n",
24
+ "PUSHOVER_TOKEN=_put the key when you click into your new application called Agents (or whatever) and probably starts with an a_\n",
25
+ "\n",
26
+ "Remember to save your `.env` file, and run `load_dotenv(override=True)` after saving, to set your environment variables.\n",
27
+ "\n",
28
+ "Finally, click \"Add Phone, Tablet or Desktop\" to install on your phone."
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": null,
34
+ "metadata": {},
35
+ "outputs": [],
36
+ "source": [
37
+ "# imports\n",
38
+ "\n",
39
+ "from dotenv import load_dotenv\n",
40
+ "from openai import OpenAI\n",
41
+ "import json\n",
42
+ "import os\n",
43
+ "import requests\n",
44
+ "from pypdf import PdfReader\n",
45
+ "import gradio as gr"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "execution_count": null,
51
+ "metadata": {},
52
+ "outputs": [],
53
+ "source": [
54
+ "# The usual start\n",
55
+ "\n",
56
+ "load_dotenv(override=True)\n",
57
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
58
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
59
+ "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)"
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "code",
64
+ "execution_count": null,
65
+ "metadata": {},
66
+ "outputs": [],
67
+ "source": [
68
+ "# For pushover\n",
69
+ "\n",
70
+ "pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
71
+ "pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
72
+ "pushover_url = \"https://api.pushover.net/1/messages.json\"\n",
73
+ "\n",
74
+ "if pushover_user:\n",
75
+ " print(f\"Pushover user found and starts with {pushover_user[0]}\")\n",
76
+ "else:\n",
77
+ " print(\"Pushover user not found\")\n",
78
+ "\n",
79
+ "if pushover_token:\n",
80
+ " print(f\"Pushover token found and starts with {pushover_token[0]}\")\n",
81
+ "else:\n",
82
+ " print(\"Pushover token not found\")"
83
+ ]
84
+ },
85
+ {
86
+ "cell_type": "code",
87
+ "execution_count": null,
88
+ "metadata": {},
89
+ "outputs": [],
90
+ "source": [
91
+ "def push(message):\n",
92
+ " print(f\"Push: {message}\")\n",
93
+ " payload = {\"user\": pushover_user, \"token\": pushover_token, \"message\": message}\n",
94
+ " requests.post(pushover_url, data=payload)"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "push(\"HEY!!\")"
104
+ ]
105
+ },
106
+ {
107
+ "cell_type": "code",
108
+ "execution_count": null,
109
+ "metadata": {},
110
+ "outputs": [],
111
+ "source": [
112
+ "def record_user_details(email, name=\"Name not provided\", notes=\"not provided\"):\n",
113
+ " push(f\"Recording interest from {name} with email {email} and notes {notes}\")\n",
114
+ " return {\"recorded\": \"ok\"}"
115
+ ]
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "execution_count": null,
120
+ "metadata": {},
121
+ "outputs": [],
122
+ "source": [
123
+ "def record_unknown_question(question):\n",
124
+ " push(f\"Recording {question} asked that I couldn't answer\")\n",
125
+ " return {\"recorded\": \"ok\"}"
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "record_user_details_json = {\n",
135
+ " \"name\": \"record_user_details\",\n",
136
+ " \"description\": \"Use this tool to record that a user is interested in being in touch and provided an email address\",\n",
137
+ " \"parameters\": {\n",
138
+ " \"type\": \"object\",\n",
139
+ " \"properties\": {\n",
140
+ " \"email\": {\n",
141
+ " \"type\": \"string\",\n",
142
+ " \"description\": \"The email address of this user\"\n",
143
+ " },\n",
144
+ " \"name\": {\n",
145
+ " \"type\": \"string\",\n",
146
+ " \"description\": \"The user's name, if they provided it\"\n",
147
+ " }\n",
148
+ " ,\n",
149
+ " \"notes\": {\n",
150
+ " \"type\": \"string\",\n",
151
+ " \"description\": \"Any additional information about the conversation that's worth recording to give context\"\n",
152
+ " }\n",
153
+ " },\n",
154
+ " \"required\": [\"email\"],\n",
155
+ " \"additionalProperties\": False\n",
156
+ " }\n",
157
+ "}"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "record_unknown_question_json = {\n",
167
+ " \"name\": \"record_unknown_question\",\n",
168
+ " \"description\": \"Always use this tool to record any question that couldn't be answered as you didn't know the answer\",\n",
169
+ " \"parameters\": {\n",
170
+ " \"type\": \"object\",\n",
171
+ " \"properties\": {\n",
172
+ " \"question\": {\n",
173
+ " \"type\": \"string\",\n",
174
+ " \"description\": \"The question that couldn't be answered\"\n",
175
+ " },\n",
176
+ " },\n",
177
+ " \"required\": [\"question\"],\n",
178
+ " \"additionalProperties\": False\n",
179
+ " }\n",
180
+ "}"
181
+ ]
182
+ },
183
+ {
184
+ "cell_type": "code",
185
+ "execution_count": null,
186
+ "metadata": {},
187
+ "outputs": [],
188
+ "source": [
189
+ "tools = [{\"type\": \"function\", \"function\": record_user_details_json},\n",
190
+ " {\"type\": \"function\", \"function\": record_unknown_question_json}]"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "metadata": {},
197
+ "outputs": [],
198
+ "source": [
199
+ "tools"
200
+ ]
201
+ },
202
+ {
203
+ "cell_type": "code",
204
+ "execution_count": null,
205
+ "metadata": {},
206
+ "outputs": [],
207
+ "source": [
208
+ "# This function can take a list of tool calls, and run them. This is the IF statement!!\n",
209
+ "\n",
210
+ "def handle_tool_calls(tool_calls):\n",
211
+ " results = []\n",
212
+ " for tool_call in tool_calls:\n",
213
+ " tool_name = tool_call.function.name\n",
214
+ " arguments = json.loads(tool_call.function.arguments)\n",
215
+ " print(f\"Tool called: {tool_name}\", flush=True)\n",
216
+ "\n",
217
+ " # THE BIG IF STATEMENT!!!\n",
218
+ "\n",
219
+ " if tool_name == \"record_user_details\":\n",
220
+ " result = record_user_details(**arguments)\n",
221
+ " elif tool_name == \"record_unknown_question\":\n",
222
+ " result = record_unknown_question(**arguments)\n",
223
+ "\n",
224
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
225
+ " return results"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": null,
231
+ "metadata": {},
232
+ "outputs": [],
233
+ "source": [
234
+ "globals()[\"record_unknown_question\"](\"this is a really hard question\")"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type": "code",
239
+ "execution_count": null,
240
+ "metadata": {},
241
+ "outputs": [],
242
+ "source": [
243
+ "# This is a more elegant way that avoids the IF statement.\n",
244
+ "\n",
245
+ "def handle_tool_calls(tool_calls):\n",
246
+ " results = []\n",
247
+ " for tool_call in tool_calls:\n",
248
+ " tool_name = tool_call.function.name\n",
249
+ " arguments = json.loads(tool_call.function.arguments)\n",
250
+ " print(f\"Tool called: {tool_name}\", flush=True)\n",
251
+ " tool = globals().get(tool_name)\n",
252
+ " result = tool(**arguments) if tool else {}\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": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "reader = PdfReader(\"me/linkedin.pdf\")\n",
264
+ "linkedin = \"\"\n",
265
+ "for page in reader.pages:\n",
266
+ " text = page.extract_text()\n",
267
+ " if text:\n",
268
+ " linkedin += text\n",
269
+ "\n",
270
+ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
271
+ " summary = f.read()\n",
272
+ "\n",
273
+ "name = \"Harsh Patidar\""
274
+ ]
275
+ },
276
+ {
277
+ "cell_type": "code",
278
+ "execution_count": null,
279
+ "metadata": {},
280
+ "outputs": [],
281
+ "source": [
282
+ "system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
283
+ "particularly questions related to {name}'s career, background, skills and experience. \\\n",
284
+ "Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
285
+ "You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
286
+ "Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
287
+ "If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \\\n",
288
+ "If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool. \"\n",
289
+ "\n",
290
+ "system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
291
+ "system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
292
+ ]
293
+ },
294
+ {
295
+ "cell_type": "code",
296
+ "execution_count": null,
297
+ "metadata": {},
298
+ "outputs": [],
299
+ "source": [
300
+ "model_name = \"gemini-2.5-flash-preview-05-20\""
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "execution_count": null,
306
+ "metadata": {},
307
+ "outputs": [],
308
+ "source": [
309
+ "from turtle import mode\n",
310
+ "\n",
311
+ "\n",
312
+ "def chat(message, history):\n",
313
+ " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
314
+ " done = False\n",
315
+ " while not done:\n",
316
+ "\n",
317
+ " # This is the call to the LLM - see that we pass in the tools json\n",
318
+ "\n",
319
+ " response = gemini.chat.completions.create(model=model_name, messages=messages, tools=tools)\n",
320
+ "\n",
321
+ " finish_reason = response.choices[0].finish_reason\n",
322
+ " \n",
323
+ " # If the LLM wants to call a tool, we do that!\n",
324
+ " \n",
325
+ " if finish_reason==\"tool_calls\":\n",
326
+ " message = response.choices[0].message\n",
327
+ " tool_calls = message.tool_calls\n",
328
+ " results = handle_tool_calls(tool_calls)\n",
329
+ " messages.append(message)\n",
330
+ " messages.extend(results)\n",
331
+ " else:\n",
332
+ " done = True\n",
333
+ " return response.choices[0].message.content"
334
+ ]
335
+ },
336
+ {
337
+ "cell_type": "code",
338
+ "execution_count": null,
339
+ "metadata": {},
340
+ "outputs": [],
341
+ "source": [
342
+ "gr.ChatInterface(chat, type=\"messages\").launch()"
343
+ ]
344
+ },
345
+ {
346
+ "cell_type": "markdown",
347
+ "metadata": {},
348
+ "source": [
349
+ "## And now for deployment\n",
350
+ "\n",
351
+ "This code is in `app.py`\n",
352
+ "\n",
353
+ "We will deploy to HuggingFace Spaces.\n",
354
+ "\n",
355
+ "Before you start: remember to update the files in the \"me\" directory - your LinkedIn profile and summary.txt - so that it talks about you! Also change `self.name = \"Ed Donner\"` in `app.py`.. \n",
356
+ "\n",
357
+ "Also check that there's no README file within the 1_foundations directory. If there is one, please delete it. The deploy process creates a new README file in this directory for you.\n",
358
+ "\n",
359
+ "1. Visit https://huggingface.co and set up an account \n",
360
+ "2. From the Avatar menu on the top right, choose Access Tokens. Choose \"Create New Token\". Give it WRITE permissions - it needs to have WRITE permissions! Keep a record of your new key. \n",
361
+ "3. In the Terminal, run: `uv tool install 'huggingface_hub[cli]'` to install the HuggingFace tool, then `hf auth login --token YOUR_TOKEN_HERE`, like `hf auth login --token hf_xxxxxx`, to login at the command line with your key. Afterwards, run `hf auth whoami` to check you're logged in \n",
362
+ "4. Take your new token and add it to your .env file: `HF_TOKEN=hf_xxx` for the future\n",
363
+ "5. From the 1_foundations folder, enter: `uv run gradio deploy` \n",
364
+ "6. Follow its instructions: name it \"career_conversation\", specify app.py, choose cpu-basic as the hardware, say Yes to needing to supply secrets, provide your openai api key, your pushover user and token, and say \"no\" to github actions. \n",
365
+ "\n",
366
+ "Thank you Robert, James, Martins, Andras and Priya for these tips. \n",
367
+ "Please read the next 2 sections - how to change your Secrets, and how to redeploy your Space (you may need to delete the README.md that gets created in this 1_foundations directory).\n",
368
+ "\n",
369
+ "#### More about these secrets:\n",
370
+ "\n",
371
+ "If you're confused by what's going on with these secrets: it just wants you to enter the key name and value for each of your secrets -- so you would enter: \n",
372
+ "`OPENAI_API_KEY` \n",
373
+ "Followed by: \n",
374
+ "`sk-proj-...` \n",
375
+ "\n",
376
+ "And if you don't want to set secrets this way, or something goes wrong with it, it's no problem - you can change your secrets later: \n",
377
+ "1. Log in to HuggingFace website \n",
378
+ "2. Go to your profile screen via the Avatar menu on the top right \n",
379
+ "3. Select the Space you deployed \n",
380
+ "4. Click on the Settings wheel on the top right \n",
381
+ "5. You can scroll down to change your secrets (Variables and Secrets section), delete the space, etc.\n",
382
+ "\n",
383
+ "#### And now you should be deployed!\n",
384
+ "\n",
385
+ "If you want to completely replace everything and start again with your keys, you may need to delete the README.md that got created in this 1_foundations folder.\n",
386
+ "\n",
387
+ "Here is mine: https://huggingface.co/spaces/ed-donner/Career_Conversation\n",
388
+ "\n",
389
+ "I just got a push notification that a student asked me how they can become President of their country 😂😂\n",
390
+ "\n",
391
+ "For more information on deployment:\n",
392
+ "\n",
393
+ "https://www.gradio.app/guides/sharing-your-app#hosting-on-hf-spaces\n",
394
+ "\n",
395
+ "To delete your Space in the future: \n",
396
+ "1. Log in to HuggingFace\n",
397
+ "2. From the Avatar menu, select your profile\n",
398
+ "3. Click on the Space itself and select the settings wheel on the top right\n",
399
+ "4. Scroll to the Delete section at the bottom\n",
400
+ "5. ALSO: delete the README file that Gradio may have created inside this 1_foundations folder (otherwise it won't ask you the questions the next time you do a gradio deploy)\n"
401
+ ]
402
+ },
403
+ {
404
+ "cell_type": "markdown",
405
+ "metadata": {},
406
+ "source": [
407
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
408
+ " <tr>\n",
409
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
410
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
411
+ " </td>\n",
412
+ " <td>\n",
413
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
414
+ " <span style=\"color:#ff7800;\">• First and foremost, deploy this for yourself! It's a real, valuable tool - the future resume..<br/>\n",
415
+ " • Next, improve the resources - add better context about yourself. If you know RAG, then add a knowledge base about you.<br/>\n",
416
+ " • Add in more tools! You could have a SQL database with common Q&A that the LLM could read and write from?<br/>\n",
417
+ " • Bring in the Evaluator from the last lab, and add other Agentic patterns.\n",
418
+ " </span>\n",
419
+ " </td>\n",
420
+ " </tr>\n",
421
+ "</table>"
422
+ ]
423
+ },
424
+ {
425
+ "cell_type": "markdown",
426
+ "metadata": {},
427
+ "source": [
428
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
429
+ " <tr>\n",
430
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
431
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
432
+ " </td>\n",
433
+ " <td>\n",
434
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
435
+ " <span style=\"color:#00bfff;\">Aside from the obvious (your career alter-ego) this has business applications in any situation where you need an AI assistant with domain expertise and an ability to interact with the real world.\n",
436
+ " </span>\n",
437
+ " </td>\n",
438
+ " </tr>\n",
439
+ "</table>"
440
+ ]
441
+ }
442
+ ],
443
+ "metadata": {
444
+ "kernelspec": {
445
+ "display_name": ".venv",
446
+ "language": "python",
447
+ "name": "python3"
448
+ },
449
+ "language_info": {
450
+ "codemirror_mode": {
451
+ "name": "ipython",
452
+ "version": 3
453
+ },
454
+ "file_extension": ".py",
455
+ "mimetype": "text/x-python",
456
+ "name": "python",
457
+ "nbconvert_exporter": "python",
458
+ "pygments_lexer": "ipython3",
459
+ "version": "3.12.12"
460
+ }
461
+ },
462
+ "nbformat": 4,
463
+ "nbformat_minor": 2
464
+ }
community_contributions/1_foundations_using_gemini/app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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="Name not provided", notes="not provided"):
24
+ push(f"Recording {name} with email {email} and notes {notes}")
25
+ return {"recorded": "ok"}
26
+
27
+ def record_unknown_question(question):
28
+ push(f"Recording {question}")
29
+ return {"recorded": "ok"}
30
+
31
+ record_user_details_json = {
32
+ "name": "record_user_details",
33
+ "description": "Use this tool to record that a user is interested in being in touch and provided an email address",
34
+ "parameters": {
35
+ "type": "object",
36
+ "properties": {
37
+ "email": {
38
+ "type": "string",
39
+ "description": "The email address of this user"
40
+ },
41
+ "name": {
42
+ "type": "string",
43
+ "description": "The user's name, if they provided it"
44
+ }
45
+ ,
46
+ "notes": {
47
+ "type": "string",
48
+ "description": "Any additional information about the conversation that's worth recording to give context"
49
+ }
50
+ },
51
+ "required": ["email"],
52
+ "additionalProperties": False
53
+ }
54
+ }
55
+
56
+ record_unknown_question_json = {
57
+ "name": "record_unknown_question",
58
+ "description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
59
+ "parameters": {
60
+ "type": "object",
61
+ "properties": {
62
+ "question": {
63
+ "type": "string",
64
+ "description": "The question that couldn't be answered"
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.GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/"
80
+ self.GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
81
+ self.openai = OpenAI(base_url=self.GEMINI_BASE_URL, api_key=self.GOOGLE_API_KEY)
82
+ self.name = "Harsh Patidar"
83
+ reader = PdfReader("me/linkedin.pdf")
84
+ self.linkedin = ""
85
+ for page in reader.pages:
86
+ text = page.extract_text()
87
+ if text:
88
+ self.linkedin += text
89
+ with open("me/summary.txt", "r", encoding="utf-8") as f:
90
+ self.summary = f.read()
91
+
92
+
93
+ def handle_tool_call(self, tool_calls):
94
+ results = []
95
+ for tool_call in tool_calls:
96
+ tool_name = tool_call.function.name
97
+ arguments = json.loads(tool_call.function.arguments)
98
+ print(f"Tool called: {tool_name}", flush=True)
99
+ tool = globals().get(tool_name)
100
+ result = tool(**arguments) if tool else {}
101
+ results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
102
+ return results
103
+
104
+ def system_prompt(self):
105
+ system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
106
+ particularly questions related to {self.name}'s career, background, skills and experience. \
107
+ Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
108
+ You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
109
+ Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
110
+ If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \
111
+ If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool. "
112
+
113
+ system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
114
+ system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
115
+ return system_prompt
116
+
117
+ def chat(self, message, history):
118
+ messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
119
+ done = False
120
+ while not done:
121
+ response = self.openai.chat.completions.create(model="gemini-2.5-flash-preview-05-20", messages=messages, tools=tools)
122
+ if response.choices[0].finish_reason=="tool_calls":
123
+ message = response.choices[0].message
124
+ tool_calls = message.tool_calls
125
+ results = self.handle_tool_call(tool_calls)
126
+ messages.append(message)
127
+ messages.extend(results)
128
+ else:
129
+ done = True
130
+ return response.choices[0].message.content
131
+
132
+
133
+ if __name__ == "__main__":
134
+ me = Me()
135
+ gr.ChatInterface(me.chat, type="messages").launch()
136
+
community_contributions/1_foundations_using_gemini/email_writeup.ipynb ADDED
@@ -0,0 +1,821 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\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
+ "# 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
+ "# Always remember to do this!\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
+ "OpenAI API Key not set\n",
77
+ "Anthropic API Key not set (and this is optional)\n",
78
+ "Google API Key exists and begins AI\n",
79
+ "DeepSeek API Key exists and begins sk-\n",
80
+ "Groq API Key exists and begins gsk_\n"
81
+ ]
82
+ }
83
+ ],
84
+ "source": [
85
+ "# Print the key prefixes to help with any debugging\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\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
95
+ "else:\n",
96
+ " print(\"OpenAI API Key not set\")\n",
97
+ " \n",
98
+ "if anthropic_api_key:\n",
99
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
100
+ "else:\n",
101
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
102
+ "\n",
103
+ "if google_api_key:\n",
104
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
105
+ "else:\n",
106
+ " print(\"Google API Key not set (and this is optional)\")\n",
107
+ "\n",
108
+ "if deepseek_api_key:\n",
109
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
110
+ "else:\n",
111
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
112
+ "\n",
113
+ "if groq_api_key:\n",
114
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
115
+ "else:\n",
116
+ " print(\"Groq API Key not set (and this is optional)\")"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "request = \" \"\n",
126
+ "\n",
127
+ "request += \"Answer only with the question, no explanation.\"\n",
128
+ "\n",
129
+ "messages = [{\"role\": \"user\", \"content\": request}]"
130
+ ]
131
+ },
132
+ {
133
+ "cell_type": "code",
134
+ "execution_count": 6,
135
+ "metadata": {},
136
+ "outputs": [],
137
+ "source": [
138
+ "request = \"\"\"You are a professional communication expert.\n",
139
+ "\n",
140
+ "Your task is to write a clear, well-structured, and effective email based on the details below.\n",
141
+ "\n",
142
+ "OBJECTIVE:\n",
143
+ "[What is the purpose of this email?]\n",
144
+ "\n",
145
+ "RECIPIENT:\n",
146
+ "[Who is receiving this? Relationship? Seniority level?]\n",
147
+ "\n",
148
+ "CONTEXT:\n",
149
+ "[What happened before this email? Any background info?]\n",
150
+ "\n",
151
+ "TONE:\n",
152
+ "[Choose one: formal / semi-formal / casual / persuasive / apologetic / assertive / warm / direct]\n",
153
+ "\n",
154
+ "KEY POINTS TO INCLUDE:\n",
155
+ "- [Point 1]\n",
156
+ "- [Point 2]\n",
157
+ "- [Point 3]\n",
158
+ "\n",
159
+ "CONSTRAINTS:\n",
160
+ "- Keep it under [X] words\n",
161
+ "- Avoid overly dramatic language\n",
162
+ "- Be specific and concise\n",
163
+ "- Include a clear call to action\n",
164
+ "\n",
165
+ "OUTPUT FORMAT:\n",
166
+ "- Subject line\n",
167
+ "- Email body\n",
168
+ "- Professional sign-off\"\"\"\n",
169
+ "\n",
170
+ "request += \"Answer only with the question. No explanation.\"\n",
171
+ "\n",
172
+ "messages = [{'role':'user','content':request}]"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": null,
178
+ "metadata": {},
179
+ "outputs": [
180
+ {
181
+ "data": {
182
+ "text/plain": [
183
+ "[{'role': 'user',\n",
184
+ " 'content': 'You are a professional communication expert.\\n\\nYour task is to write a clear, well-structured, and effective email based on the details below.\\n\\nOBJECTIVE:\\n[What is the purpose of this email?]\\n\\nRECIPIENT:\\n[Who is receiving this? Relationship? Seniority level?]\\n\\nCONTEXT:\\n[What happened before this email? Any background info?]\\n\\nTONE:\\n[Choose one: formal / semi-formal / casual / persuasive / apologetic / assertive / warm / direct]\\n\\nKEY POINTS TO INCLUDE:\\n- [Point 1]\\n- [Point 2]\\n- [Point 3]\\n\\nCONSTRAINTS:\\n- Keep it under [X] words\\n- Avoid overly dramatic language\\n- Be specific and concise\\n- Include a clear call to action\\n\\nOUTPUT FORMAT:\\n- Subject line\\n- Email body\\n- Professional sign-offAnswer only with the question. No explanation.'}]"
185
+ ]
186
+ },
187
+ "execution_count": 7,
188
+ "metadata": {},
189
+ "output_type": "execute_result"
190
+ }
191
+ ],
192
+ "source": [
193
+ "\n",
194
+ "messages"
195
+ ]
196
+ },
197
+ {
198
+ "cell_type": "code",
199
+ "execution_count": 8,
200
+ "metadata": {},
201
+ "outputs": [],
202
+ "source": [
203
+ "contenders = []\n",
204
+ "answers = []"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "code",
209
+ "execution_count": 9,
210
+ "metadata": {},
211
+ "outputs": [
212
+ {
213
+ "data": {
214
+ "text/markdown": [
215
+ "Subject: Follow-Up on Q3 Marketing Budget Proposal \n",
216
+ "\n",
217
+ "Dear [Recipient's Name], \n",
218
+ "\n",
219
+ "I hope this message finds you well. Following up on our conversation last week, I’m writing to provide the additional details you requested regarding the Q3 marketing budget proposal. \n",
220
+ "\n",
221
+ "Key points to note: \n",
222
+ "1. The proposed budget aligns with our projected campaign goals and includes a 10% increase in digital ad spend. \n",
223
+ "2. We’ve identified potential cost savings in traditional media, which offsets the digital increase. \n",
224
+ "3. All figures have been reviewed by the finance team for accuracy. \n",
225
+ "\n",
226
+ "Please review the attached document at your earliest convenience. I’d appreciate your feedback or approval by Friday, [Date], so we can proceed on schedule. \n",
227
+ "\n",
228
+ "Let me know if you have any questions. \n",
229
+ "\n",
230
+ "Best regards, \n",
231
+ "[Your Name]"
232
+ ],
233
+ "text/plain": [
234
+ "<IPython.core.display.Markdown object>"
235
+ ]
236
+ },
237
+ "metadata": {},
238
+ "output_type": "display_data"
239
+ }
240
+ ],
241
+ "source": [
242
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
243
+ "model_name = \"deepseek\"\n",
244
+ "response = deepseek.chat.completions.create(\n",
245
+ " model=\"deepseek-chat\",\n",
246
+ " messages=messages,\n",
247
+ ")\n",
248
+ "answer = response.choices[0].message.content\n",
249
+ "display(Markdown(answer))\n",
250
+ "contenders.append(model_name)\n",
251
+ "answers.append(answer)\n",
252
+ "\n"
253
+ ]
254
+ },
255
+ {
256
+ "cell_type": "code",
257
+ "execution_count": 20,
258
+ "metadata": {},
259
+ "outputs": [
260
+ {
261
+ "data": {
262
+ "text/markdown": [
263
+ "What are the details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and word count CONSTRAINTS for the email?"
264
+ ],
265
+ "text/plain": [
266
+ "<IPython.core.display.Markdown object>"
267
+ ]
268
+ },
269
+ "metadata": {},
270
+ "output_type": "display_data"
271
+ }
272
+ ],
273
+ "source": [
274
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta\")\n",
275
+ "model_name = \"gemini-2.5-flash\"\n",
276
+ "\n",
277
+ "response = gemini.chat.completions.create(\n",
278
+ " model=model_name,\n",
279
+ " messages=messages,\n",
280
+ ")\n",
281
+ "\n",
282
+ "answer = response.choices[0].message.content\n",
283
+ "display(Markdown(answer))\n",
284
+ "contenders.append(model_name)\n",
285
+ "answers.append(answer)"
286
+ ]
287
+ },
288
+ {
289
+ "cell_type": "code",
290
+ "execution_count": 21,
291
+ "metadata": {},
292
+ "outputs": [
293
+ {
294
+ "data": {
295
+ "text/markdown": [
296
+ "Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?"
297
+ ],
298
+ "text/plain": [
299
+ "<IPython.core.display.Markdown object>"
300
+ ]
301
+ },
302
+ "metadata": {},
303
+ "output_type": "display_data"
304
+ }
305
+ ],
306
+ "source": [
307
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
308
+ "model_name = \"openai/gpt-oss-120b\"\n",
309
+ "\n",
310
+ "request = groq.chat.completions.create(\n",
311
+ " model=model_name,\n",
312
+ " messages=messages,\n",
313
+ ")\n",
314
+ "\n",
315
+ "answer = request.choices[0].message.content\n",
316
+ "display(Markdown(answer))\n",
317
+ "contenders.append(model_name)\n",
318
+ "answers.append(answer)"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "markdown",
323
+ "metadata": {},
324
+ "source": [
325
+ "## Note - update since the videos\n",
326
+ "\n",
327
+ "I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video."
328
+ ]
329
+ },
330
+ {
331
+ "cell_type": "code",
332
+ "execution_count": null,
333
+ "metadata": {},
334
+ "outputs": [],
335
+ "source": [
336
+ "# The API we know well\n",
337
+ "# I've updated this with the latest model, but it can take some time because it likes to think!\n",
338
+ "# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\n",
339
+ "\n",
340
+ "model_name = \"gpt-5-nano\"\n",
341
+ "\n",
342
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
343
+ "answer = response.choices[0].message.content\n",
344
+ "\n",
345
+ "display(Markdown(answer))\n",
346
+ "competitors.append(model_name)\n",
347
+ "answers.append(answer)"
348
+ ]
349
+ },
350
+ {
351
+ "cell_type": "code",
352
+ "execution_count": null,
353
+ "metadata": {},
354
+ "outputs": [],
355
+ "source": [
356
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
357
+ "\n",
358
+ "model_name = \"claude-sonnet-4-5\"\n",
359
+ "\n",
360
+ "claude = Anthropic()\n",
361
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
362
+ "answer = response.content[0].text\n",
363
+ "\n",
364
+ "display(Markdown(answer))\n",
365
+ "competitors.append(model_name)\n",
366
+ "answers.append(answer)"
367
+ ]
368
+ },
369
+ {
370
+ "cell_type": "code",
371
+ "execution_count": null,
372
+ "metadata": {},
373
+ "outputs": [],
374
+ "source": [
375
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
376
+ "model_name = \"gemini-2.5-flash\"\n",
377
+ "\n",
378
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
379
+ "answer = response.choices[0].message.content\n",
380
+ "\n",
381
+ "display(Markdown(answer))\n",
382
+ "competitors.append(model_name)\n",
383
+ "answers.append(answer)"
384
+ ]
385
+ },
386
+ {
387
+ "cell_type": "code",
388
+ "execution_count": null,
389
+ "metadata": {},
390
+ "outputs": [],
391
+ "source": [
392
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
393
+ "model_name = \"deepseek-chat\"\n",
394
+ "\n",
395
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
396
+ "answer = response.choices[0].message.content\n",
397
+ "\n",
398
+ "display(Markdown(answer))\n",
399
+ "competitors.append(model_name)\n",
400
+ "answers.append(answer)"
401
+ ]
402
+ },
403
+ {
404
+ "cell_type": "code",
405
+ "execution_count": null,
406
+ "metadata": {},
407
+ "outputs": [],
408
+ "source": [
409
+ "# Updated with the latest Open Source model from OpenAI\n",
410
+ "\n",
411
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
412
+ "model_name = \"openai/gpt-oss-120b\"\n",
413
+ "\n",
414
+ "response = groq.chat.completions.create(model=model_name, messages=messages)\n",
415
+ "answer = response.choices[0].message.content\n",
416
+ "\n",
417
+ "display(Markdown(answer))\n",
418
+ "competitors.append(model_name)\n",
419
+ "answers.append(answer)\n"
420
+ ]
421
+ },
422
+ {
423
+ "cell_type": "markdown",
424
+ "metadata": {},
425
+ "source": [
426
+ "## For the next cell, we will use Ollama\n",
427
+ "\n",
428
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
429
+ "and runs models locally using high performance C++ code.\n",
430
+ "\n",
431
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
432
+ "\n",
433
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
434
+ "\n",
435
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
436
+ "\n",
437
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
438
+ "\n",
439
+ "`ollama pull <model_name>` downloads a model locally \n",
440
+ "`ollama ls` lists all the models you've downloaded \n",
441
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
442
+ ]
443
+ },
444
+ {
445
+ "cell_type": "markdown",
446
+ "metadata": {},
447
+ "source": [
448
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
449
+ " <tr>\n",
450
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
451
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
452
+ " </td>\n",
453
+ " <td>\n",
454
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
455
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
456
+ " </span>\n",
457
+ " </td>\n",
458
+ " </tr>\n",
459
+ "</table>"
460
+ ]
461
+ },
462
+ {
463
+ "cell_type": "code",
464
+ "execution_count": null,
465
+ "metadata": {},
466
+ "outputs": [],
467
+ "source": [
468
+ "!ollama pull llama3.2"
469
+ ]
470
+ },
471
+ {
472
+ "cell_type": "code",
473
+ "execution_count": null,
474
+ "metadata": {},
475
+ "outputs": [],
476
+ "source": [
477
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
478
+ "model_name = \"llama3.2\"\n",
479
+ "\n",
480
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
481
+ "answer = response.choices[0].message.content\n",
482
+ "\n",
483
+ "display(Markdown(answer))\n",
484
+ "competitors.append(model_name)\n",
485
+ "answers.append(answer)"
486
+ ]
487
+ },
488
+ {
489
+ "cell_type": "code",
490
+ "execution_count": 23,
491
+ "metadata": {},
492
+ "outputs": [
493
+ {
494
+ "name": "stdout",
495
+ "output_type": "stream",
496
+ "text": [
497
+ "['deepseek', 'gemini-2.5-flash', 'openai/gpt-oss-120b']\n",
498
+ "[\"Subject: Follow-Up on Q3 Marketing Budget Proposal \\n\\nDear [Recipient's Name], \\n\\nI hope this message finds you well. Following up on our conversation last week, I’m writing to provide the additional details you requested regarding the Q3 marketing budget proposal. \\n\\nKey points to note: \\n1. The proposed budget aligns with our projected campaign goals and includes a 10% increase in digital ad spend. \\n2. We’ve identified potential cost savings in traditional media, which offsets the digital increase. \\n3. All figures have been reviewed by the finance team for accuracy. \\n\\nPlease review the attached document at your earliest convenience. I’d appreciate your feedback or approval by Friday, [Date], so we can proceed on schedule. \\n\\nLet me know if you have any questions. \\n\\nBest regards, \\n[Your Name]\", 'What are the details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and word count CONSTRAINTS for the email?', 'Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?']\n"
499
+ ]
500
+ }
501
+ ],
502
+ "source": [
503
+ "# So where are we?\n",
504
+ "\n",
505
+ "print(contenders)\n",
506
+ "print(answers)\n"
507
+ ]
508
+ },
509
+ {
510
+ "cell_type": "code",
511
+ "execution_count": 24,
512
+ "metadata": {},
513
+ "outputs": [
514
+ {
515
+ "name": "stdout",
516
+ "output_type": "stream",
517
+ "text": [
518
+ "Competitor: deepseek\n",
519
+ "\n",
520
+ "Subject: Follow-Up on Q3 Marketing Budget Proposal \n",
521
+ "\n",
522
+ "Dear [Recipient's Name], \n",
523
+ "\n",
524
+ "I hope this message finds you well. Following up on our conversation last week, I’m writing to provide the additional details you requested regarding the Q3 marketing budget proposal. \n",
525
+ "\n",
526
+ "Key points to note: \n",
527
+ "1. The proposed budget aligns with our projected campaign goals and includes a 10% increase in digital ad spend. \n",
528
+ "2. We’ve identified potential cost savings in traditional media, which offsets the digital increase. \n",
529
+ "3. All figures have been reviewed by the finance team for accuracy. \n",
530
+ "\n",
531
+ "Please review the attached document at your earliest convenience. I’d appreciate your feedback or approval by Friday, [Date], so we can proceed on schedule. \n",
532
+ "\n",
533
+ "Let me know if you have any questions. \n",
534
+ "\n",
535
+ "Best regards, \n",
536
+ "[Your Name]\n",
537
+ "Competitor: gemini-2.5-flash\n",
538
+ "\n",
539
+ "What are the details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and word count CONSTRAINTS for the email?\n",
540
+ "Competitor: openai/gpt-oss-120b\n",
541
+ "\n",
542
+ "Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?\n"
543
+ ]
544
+ }
545
+ ],
546
+ "source": [
547
+ "# It's nice to know how to use \"zip\"\n",
548
+ "for competitor, answer in zip(contenders, answers):\n",
549
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
550
+ ]
551
+ },
552
+ {
553
+ "cell_type": "code",
554
+ "execution_count": 25,
555
+ "metadata": {},
556
+ "outputs": [],
557
+ "source": [
558
+ "# Let's bring this together - note the use of \"enumerate\"\n",
559
+ "\n",
560
+ "together = \"\"\n",
561
+ "for index, answer in enumerate(answers):\n",
562
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
563
+ " together += answer + \"\\n\\n\""
564
+ ]
565
+ },
566
+ {
567
+ "cell_type": "code",
568
+ "execution_count": 26,
569
+ "metadata": {},
570
+ "outputs": [
571
+ {
572
+ "name": "stdout",
573
+ "output_type": "stream",
574
+ "text": [
575
+ "# Response from competitor 1\n",
576
+ "\n",
577
+ "Subject: Follow-Up on Q3 Marketing Budget Proposal \n",
578
+ "\n",
579
+ "Dear [Recipient's Name], \n",
580
+ "\n",
581
+ "I hope this message finds you well. Following up on our conversation last week, I’m writing to provide the additional details you requested regarding the Q3 marketing budget proposal. \n",
582
+ "\n",
583
+ "Key points to note: \n",
584
+ "1. The proposed budget aligns with our projected campaign goals and includes a 10% increase in digital ad spend. \n",
585
+ "2. We’ve identified potential cost savings in traditional media, which offsets the digital increase. \n",
586
+ "3. All figures have been reviewed by the finance team for accuracy. \n",
587
+ "\n",
588
+ "Please review the attached document at your earliest convenience. I’d appreciate your feedback or approval by Friday, [Date], so we can proceed on schedule. \n",
589
+ "\n",
590
+ "Let me know if you have any questions. \n",
591
+ "\n",
592
+ "Best regards, \n",
593
+ "[Your Name]\n",
594
+ "\n",
595
+ "# Response from competitor 2\n",
596
+ "\n",
597
+ "What are the details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and word count CONSTRAINTS for the email?\n",
598
+ "\n",
599
+ "# Response from competitor 3\n",
600
+ "\n",
601
+ "Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?\n",
602
+ "\n",
603
+ "\n"
604
+ ]
605
+ }
606
+ ],
607
+ "source": [
608
+ "print(together)"
609
+ ]
610
+ },
611
+ {
612
+ "cell_type": "markdown",
613
+ "metadata": {},
614
+ "source": []
615
+ },
616
+ {
617
+ "cell_type": "code",
618
+ "execution_count": 29,
619
+ "metadata": {},
620
+ "outputs": [],
621
+ "source": [
622
+ "judge = f\"\"\"You are judging a competition between {len(contenders)} competitors.\n",
623
+ "Each model has been given this question:\n",
624
+ "\n",
625
+ "{request}\n",
626
+ "\n",
627
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
628
+ "Respond with JSON, and only JSON, with the following format:\n",
629
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
630
+ "\n",
631
+ "Here are the responses from each competitor:\n",
632
+ "\n",
633
+ "{together}\n",
634
+ "\n",
635
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
636
+ ]
637
+ },
638
+ {
639
+ "cell_type": "code",
640
+ "execution_count": 30,
641
+ "metadata": {},
642
+ "outputs": [
643
+ {
644
+ "name": "stdout",
645
+ "output_type": "stream",
646
+ "text": [
647
+ "You are judging a competition between 3 competitors.\n",
648
+ "Each model has been given this question:\n",
649
+ "\n",
650
+ "ChatCompletion(id='chatcmpl-e9071a1e-2f11-4f29-affe-2dd81c808078', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning='The user wants: \"Answer only with the question. No explanation.\" They gave a template, but they didn\\'t fill in the placeholders. The instruction says: \"Answer only with the question. No explanation.\"\\n\\nProbably they want the assistant to ask them for the missing information (the placeholders). The user says: \"Your task is to write a clear, well-structured, and effective email based on the details below.\" Then they list placeholders like OBJECTIVE, RECIPIENT, etc. They haven\\'t filled them. So we need to ask the question to get those details. The instruction at the end: \"Answer only with the question. No explanation.\"\\n\\nThus we should reply with a single question asking them to provide the missing details. Probably: \"Could you please provide the specific details for OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, CONSTRAINTS?\" But must be a question. So something like: \"Could you fill in the placeholders (OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, CONSTRAINTS) so I can draft the email?\" That\\'s a question. No extra explanation.\\n\\nThus final answer: a single question.'))], created=1772217855, model='openai/gpt-oss-120b', object='chat.completion', service_tier='on_demand', system_fingerprint='fp_e10890e4b9', usage=CompletionUsage(completion_tokens=295, prompt_tokens=252, total_tokens=547, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=241, rejected_prediction_tokens=None), prompt_tokens_details=None, queue_time=0.044959717, prompt_time=0.011474953, completion_time=0.62083969, total_time=0.632314643), usage_breakdown=None, x_groq={'id': 'req_01kjg6mtjtfkxt2a74s7gwatpf', 'seed': 913780012})\n",
651
+ "\n",
652
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
653
+ "Respond with JSON, and only JSON, with the following format:\n",
654
+ "{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}\n",
655
+ "\n",
656
+ "Here are the responses from each competitor:\n",
657
+ "\n",
658
+ "# Response from competitor 1\n",
659
+ "\n",
660
+ "Subject: Follow-Up on Q3 Marketing Budget Proposal \n",
661
+ "\n",
662
+ "Dear [Recipient's Name], \n",
663
+ "\n",
664
+ "I hope this message finds you well. Following up on our conversation last week, I’m writing to provide the additional details you requested regarding the Q3 marketing budget proposal. \n",
665
+ "\n",
666
+ "Key points to note: \n",
667
+ "1. The proposed budget aligns with our projected campaign goals and includes a 10% increase in digital ad spend. \n",
668
+ "2. We’ve identified potential cost savings in traditional media, which offsets the digital increase. \n",
669
+ "3. All figures have been reviewed by the finance team for accuracy. \n",
670
+ "\n",
671
+ "Please review the attached document at your earliest convenience. I’d appreciate your feedback or approval by Friday, [Date], so we can proceed on schedule. \n",
672
+ "\n",
673
+ "Let me know if you have any questions. \n",
674
+ "\n",
675
+ "Best regards, \n",
676
+ "[Your Name]\n",
677
+ "\n",
678
+ "# Response from competitor 2\n",
679
+ "\n",
680
+ "What are the details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and word count CONSTRAINTS for the email?\n",
681
+ "\n",
682
+ "# Response from competitor 3\n",
683
+ "\n",
684
+ "Could you please provide the specific details for the OBJECTIVE, RECIPIENT, CONTEXT, TONE, KEY POINTS, and any CONSTRAINTS (e.g., word limit) so I can draft the email?\n",
685
+ "\n",
686
+ "\n",
687
+ "\n",
688
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\n"
689
+ ]
690
+ }
691
+ ],
692
+ "source": [
693
+ "print(judge)"
694
+ ]
695
+ },
696
+ {
697
+ "cell_type": "code",
698
+ "execution_count": 31,
699
+ "metadata": {},
700
+ "outputs": [],
701
+ "source": [
702
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
703
+ ]
704
+ },
705
+ {
706
+ "cell_type": "code",
707
+ "execution_count": 36,
708
+ "metadata": {},
709
+ "outputs": [
710
+ {
711
+ "name": "stdout",
712
+ "output_type": "stream",
713
+ "text": [
714
+ "{\"results\": [\"3\", \"2\", \"1\"]}\n"
715
+ ]
716
+ }
717
+ ],
718
+ "source": [
719
+ "# Judgement time!\n",
720
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
721
+ "\n",
722
+ "response = deepseek.chat.completions.create(\n",
723
+ " model=\"deepseek-chat\",\n",
724
+ " messages=judge_messages\n",
725
+ ")\n",
726
+ "\n",
727
+ "results = response.choices[0].message.content\n",
728
+ "print(results)"
729
+ ]
730
+ },
731
+ {
732
+ "cell_type": "code",
733
+ "execution_count": 51,
734
+ "metadata": {},
735
+ "outputs": [
736
+ {
737
+ "name": "stdout",
738
+ "output_type": "stream",
739
+ "text": [
740
+ "Rank 1: openai/gpt-oss-120b\n",
741
+ "Rank 2: gemini-2.5-flash\n",
742
+ "Rank 3: deepseek\n"
743
+ ]
744
+ }
745
+ ],
746
+ "source": [
747
+ "contenders = [\n",
748
+ " \"deepseek\",\n",
749
+ " \"gemini-2.5-flash\",\n",
750
+ " \"openai/gpt-oss-120b\"\n",
751
+ "]\n",
752
+ "\n",
753
+ "results_dict = {\"results\": [\"3\", \"2\", \"1\"]}\n",
754
+ "\n",
755
+ "# Use int(result)-1 only if your list aligns with competitor numbers\n",
756
+ "for rank, comp_number in enumerate(results_dict[\"results\"], start=1):\n",
757
+ " index = int(comp_number) - 1 # convert \"3\" → 2\n",
758
+ " print(f\"Rank {rank}: {contenders[index]}\")"
759
+ ]
760
+ },
761
+ {
762
+ "cell_type": "markdown",
763
+ "metadata": {},
764
+ "source": [
765
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
766
+ " <tr>\n",
767
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
768
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
769
+ " </td>\n",
770
+ " <td>\n",
771
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
772
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
773
+ " </span>\n",
774
+ " </td>\n",
775
+ " </tr>\n",
776
+ "</table>"
777
+ ]
778
+ },
779
+ {
780
+ "cell_type": "markdown",
781
+ "metadata": {},
782
+ "source": [
783
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
784
+ " <tr>\n",
785
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
786
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
787
+ " </td>\n",
788
+ " <td>\n",
789
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
790
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
791
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
792
+ " to business projects where accuracy is critical.\n",
793
+ " </span>\n",
794
+ " </td>\n",
795
+ " </tr>\n",
796
+ "</table>"
797
+ ]
798
+ }
799
+ ],
800
+ "metadata": {
801
+ "kernelspec": {
802
+ "display_name": ".venv",
803
+ "language": "python",
804
+ "name": "python3"
805
+ },
806
+ "language_info": {
807
+ "codemirror_mode": {
808
+ "name": "ipython",
809
+ "version": 3
810
+ },
811
+ "file_extension": ".py",
812
+ "mimetype": "text/x-python",
813
+ "name": "python",
814
+ "nbconvert_exporter": "python",
815
+ "pygments_lexer": "ipython3",
816
+ "version": "3.12.12"
817
+ }
818
+ },
819
+ "nbformat": 4,
820
+ "nbformat_minor": 2
821
+ }
community_contributions/1_foundations_using_gemini/me/linkedin.pdf ADDED
Binary file (54.2 kB). View file
 
community_contributions/1_foundations_using_gemini/me/summary.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Hey, I’m Harsh Patidar — a Data Engineer at ZS who loves building data systems that actually work — scalable, reliable, and smart enough to keep learning.
2
+ I’ve spent the past few years turning raw, unstructured data into powerful systems that fuel analytics, automation, and AI-driven decisions.
3
+
4
+ At ZS, I work in the R&D division, where I design and deploy containerized APIs, optimize data pipelines, and integrate machine learning models into real-world workflows. My toolkit revolves around Python, SQL, FastAPI, Docker, Airflow, and AWS, and I enjoy the process of connecting every piece of data infrastructure into something clean, efficient, and production-ready.
5
+
6
+ Before this, I was part of Accenture’s Data Engineering & Governance team, helping large enterprises strengthen data reliability, validation, and compliance frameworks — experience that taught me the importance of structure, traceability, and precision.
7
+ I also spent time as a Teaching Assistant at Coding Ninjas, mentoring over 200 students in Data Structures and Algorithms — something that shaped both my fundamentals and my patience.
8
+
9
+ Outside of work, I’m someone who finds joy in photography, exploring tech startups, and deep research in finance and AI. I like observing how technology, creativity, and design come together — whether in a great photograph or a cleanly designed data pipeline.
10
+
11
+ At my core, I’m driven by curiosity and the excitement of building something meaningful from scratch. I believe great work is built quietly, through learning, experimentation, and the discipline to keep improving — whether that’s a data system, a product, or even myself.
community_contributions/1_foundations_using_gemini/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ requests
2
+ python-dotenv
3
+ gradio
4
+ pypdf
5
+ openai
6
+ openai-agents
community_contributions/1_lab1_DA.ipynb ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-nano\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": null,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# And now - let's ask for a question:\n",
326
+ "\n",
327
+ "import os\n",
328
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
329
+ "from openai import OpenAI\n",
330
+ "from IPython.display import Markdown, display\n",
331
+ "\n",
332
+ "# And now we'll create an instance of the OpenAI class\n",
333
+ "\n",
334
+ "openai = OpenAI()\n",
335
+ "\n",
336
+ "question1 = \"Please pick a business area that might be worth exploring for an Agentic AI opportunity.\"\n",
337
+ "messages1 = [{\"role\": \"user\", \"content\": question1}]\n",
338
+ "\n",
339
+ "# Then make the first call:\n",
340
+ "response1 = openai.chat.completions.create(\n",
341
+ " model=\"gpt-4.1-mini\",\n",
342
+ " messages=messages1\n",
343
+ ")\n",
344
+ "\n",
345
+ "question2 = \" Please present the pain-point in \"+response1.choices[0].message.content +\" industry - something challenging that might be ripe for an Agentic solution\"\n",
346
+ "messages2 = [{\"role\": \"user\", \"content\": question2}]\n",
347
+ "\n",
348
+ "# Then make the first call:\n",
349
+ "response2 = openai.chat.completions.create(\n",
350
+ " model=\"gpt-4.1-mini\",\n",
351
+ " messages=messages2\n",
352
+ ")\n",
353
+ "\n",
354
+ "question3 = \" Please presentpropose and Agentic AI solution for pain-point \"+response2.choices[0].message.content\n",
355
+ "messages3 = [{\"role\": \"user\", \"content\": question3}]\n",
356
+ "\n",
357
+ "# Then make the first call:\n",
358
+ "response3 = openai.chat.completions.create(\n",
359
+ " model=\"gpt-4.1-mini\",\n",
360
+ " messages=messages3\n",
361
+ ")\n",
362
+ "\n",
363
+ "Final_Answer = \" Please presentpropose and Agentic AI solution for pain-point \"+response2.choices[0].message.content\n",
364
+ "\n",
365
+ "display(Markdown(Final_Answer))\n",
366
+ "\n"
367
+ ]
368
+ },
369
+ {
370
+ "cell_type": "markdown",
371
+ "metadata": {},
372
+ "source": []
373
+ }
374
+ ],
375
+ "metadata": {
376
+ "kernelspec": {
377
+ "display_name": ".venv",
378
+ "language": "python",
379
+ "name": "python3"
380
+ },
381
+ "language_info": {
382
+ "codemirror_mode": {
383
+ "name": "ipython",
384
+ "version": 3
385
+ },
386
+ "file_extension": ".py",
387
+ "mimetype": "text/x-python",
388
+ "name": "python",
389
+ "nbconvert_exporter": "python",
390
+ "pygments_lexer": "ipython3",
391
+ "version": "3.12.11"
392
+ }
393
+ },
394
+ "nbformat": 4,
395
+ "nbformat_minor": 2
396
+ }
community_contributions/1_lab1_Hy.ipynb ADDED
@@ -0,0 +1,688 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": 1,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": 2,
100
+ "metadata": {},
101
+ "outputs": [
102
+ {
103
+ "data": {
104
+ "text/plain": [
105
+ "True"
106
+ ]
107
+ },
108
+ "execution_count": 2,
109
+ "metadata": {},
110
+ "output_type": "execute_result"
111
+ }
112
+ ],
113
+ "source": [
114
+ "# Next it's time to load the API keys into environment variables\n",
115
+ "# If this returns false, see the next cell!\n",
116
+ "\n",
117
+ "load_dotenv(override=True)"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "markdown",
122
+ "metadata": {},
123
+ "source": [
124
+ "### Wait, did that just output `False`??\n",
125
+ "\n",
126
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
127
+ "\n",
128
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
129
+ "\n",
130
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
131
+ ]
132
+ },
133
+ {
134
+ "cell_type": "markdown",
135
+ "metadata": {},
136
+ "source": [
137
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
138
+ " <tr>\n",
139
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
140
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
141
+ " </td>\n",
142
+ " <td>\n",
143
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
144
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
145
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
146
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
147
+ " </span>\n",
148
+ " </td>\n",
149
+ " </tr>\n",
150
+ "</table>"
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "code",
155
+ "execution_count": 3,
156
+ "metadata": {},
157
+ "outputs": [
158
+ {
159
+ "name": "stdout",
160
+ "output_type": "stream",
161
+ "text": [
162
+ "OpenAI API Key exists and begins sk-proj-\n"
163
+ ]
164
+ }
165
+ ],
166
+ "source": [
167
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
168
+ "\n",
169
+ "import os\n",
170
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
171
+ "\n",
172
+ "if openai_api_key:\n",
173
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
174
+ "else:\n",
175
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
176
+ " \n"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": 4,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "# And now - the all important import statement\n",
186
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
187
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
188
+ "\n",
189
+ "from openai import OpenAI"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 5,
195
+ "metadata": {},
196
+ "outputs": [],
197
+ "source": [
198
+ "# And now we'll create an instance of the OpenAI class\n",
199
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
200
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
201
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
202
+ "\n",
203
+ "openai = OpenAI()"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "code",
208
+ "execution_count": 6,
209
+ "metadata": {},
210
+ "outputs": [],
211
+ "source": [
212
+ "# Create a list of messages in the familiar OpenAI format\n",
213
+ "\n",
214
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [
222
+ {
223
+ "name": "stdout",
224
+ "output_type": "stream",
225
+ "text": [
226
+ "ChatCompletion(id='chatcmpl-C9oVaLh1gjzKH07zcVLaXQ4o4FDQ7', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='2 + 2 equals 4.', refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=None))], created=1756455142, model='gpt-4.1-nano-2025-04-14', object='chat.completion', service_tier='default', system_fingerprint='fp_c4c155951e', usage=CompletionUsage(completion_tokens=8, prompt_tokens=14, total_tokens=22, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0), prompt_tokens_details=PromptTokensDetails(audio_tokens=0, cached_tokens=0)))\n",
227
+ "2 + 2 equals 4.\n"
228
+ ]
229
+ }
230
+ ],
231
+ "source": [
232
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
233
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
234
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
235
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-nano\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "print(response.choices[0].message.content)\n"
242
+ ]
243
+ },
244
+ {
245
+ "cell_type": "code",
246
+ "execution_count": 9,
247
+ "metadata": {},
248
+ "outputs": [],
249
+ "source": [
250
+ "# And now - let's ask for a question:\n",
251
+ "\n",
252
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
253
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": 10,
259
+ "metadata": {},
260
+ "outputs": [
261
+ {
262
+ "name": "stdout",
263
+ "output_type": "stream",
264
+ "text": [
265
+ "If three people can paint three walls in three hours, how many people are needed to paint 18 walls in six hours?\n"
266
+ ]
267
+ }
268
+ ],
269
+ "source": [
270
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
271
+ "\n",
272
+ "response = openai.chat.completions.create(\n",
273
+ " model=\"gpt-4.1-mini\",\n",
274
+ " messages=messages\n",
275
+ ")\n",
276
+ "\n",
277
+ "question = response.choices[0].message.content\n",
278
+ "\n",
279
+ "print(question)\n"
280
+ ]
281
+ },
282
+ {
283
+ "cell_type": "code",
284
+ "execution_count": 11,
285
+ "metadata": {},
286
+ "outputs": [],
287
+ "source": [
288
+ "# form a new messages list\n",
289
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": 12,
295
+ "metadata": {},
296
+ "outputs": [
297
+ {
298
+ "name": "stdout",
299
+ "output_type": "stream",
300
+ "text": [
301
+ "Let's analyze the problem step-by-step:\n",
302
+ "\n",
303
+ "---\n",
304
+ "\n",
305
+ "**Given:**\n",
306
+ "\n",
307
+ "- 3 people can paint 3 walls in 3 hours.\n",
308
+ "\n",
309
+ "**Question:**\n",
310
+ "\n",
311
+ "- How many people are needed to paint 18 walls in 6 hours?\n",
312
+ "\n",
313
+ "---\n",
314
+ "\n",
315
+ "### Step 1: Find the rate of painting per person\n",
316
+ "\n",
317
+ "- Total walls painted: 3 walls\n",
318
+ "- Total people: 3 people\n",
319
+ "- Total time: 3 hours\n",
320
+ "\n",
321
+ "**Walls per person per hour:**\n",
322
+ "\n",
323
+ "First, find how many walls 3 people paint per hour:\n",
324
+ "\n",
325
+ "\\[\n",
326
+ "\\frac{3 \\text{ walls}}{3 \\text{ hours}} = 1 \\text{ wall per hour by 3 people}\n",
327
+ "\\]\n",
328
+ "\n",
329
+ "So, 3 people paint 1 wall per hour.\n",
330
+ "\n",
331
+ "Then, walls per person per hour:\n",
332
+ "\n",
333
+ "\\[\n",
334
+ "\\frac{1 \\text{ wall per hour}}{3 \\text{ people}} = \\frac{1}{3} \\text{ wall per person per hour}\n",
335
+ "\\]\n",
336
+ "\n",
337
+ "---\n",
338
+ "\n",
339
+ "### Step 2: Calculate total work needed\n",
340
+ "\n",
341
+ "You want to paint 18 walls in 6 hours.\n",
342
+ "\n",
343
+ "This means the rate of painting must be:\n",
344
+ "\n",
345
+ "\\[\n",
346
+ "\\frac{18 \\text{ walls}}{6 \\text{ hours}} = 3 \\text{ walls per hour}\n",
347
+ "\\]\n",
348
+ "\n",
349
+ "---\n",
350
+ "\n",
351
+ "### Step 3: Find how many people are needed for this rate\n",
352
+ "\n",
353
+ "Since each person paints \\(\\frac{1}{3}\\) wall per hour,\n",
354
+ "\n",
355
+ "\\[\n",
356
+ "\\text{Number of people} \\times \\frac{1}{3} = 3 \\text{ walls per hour}\n",
357
+ "\\]\n",
358
+ "\n",
359
+ "Multiply both sides by 3:\n",
360
+ "\n",
361
+ "\\[\n",
362
+ "\\text{Number of people} = 3 \\times 3 = 9\n",
363
+ "\\]\n",
364
+ "\n",
365
+ "---\n",
366
+ "\n",
367
+ "### **Answer:**\n",
368
+ "\n",
369
+ "\\[\n",
370
+ "\\boxed{9}\n",
371
+ "\\]\n",
372
+ "\n",
373
+ "You need **9 people** to paint 18 walls in 6 hours.\n"
374
+ ]
375
+ }
376
+ ],
377
+ "source": [
378
+ "# Ask it again\n",
379
+ "\n",
380
+ "response = openai.chat.completions.create(\n",
381
+ " model=\"gpt-4.1-mini\",\n",
382
+ " messages=messages\n",
383
+ ")\n",
384
+ "\n",
385
+ "answer = response.choices[0].message.content\n",
386
+ "print(answer)\n"
387
+ ]
388
+ },
389
+ {
390
+ "cell_type": "code",
391
+ "execution_count": 13,
392
+ "metadata": {},
393
+ "outputs": [
394
+ {
395
+ "data": {
396
+ "text/markdown": [
397
+ "Let's analyze the problem step-by-step:\n",
398
+ "\n",
399
+ "---\n",
400
+ "\n",
401
+ "**Given:**\n",
402
+ "\n",
403
+ "- 3 people can paint 3 walls in 3 hours.\n",
404
+ "\n",
405
+ "**Question:**\n",
406
+ "\n",
407
+ "- How many people are needed to paint 18 walls in 6 hours?\n",
408
+ "\n",
409
+ "---\n",
410
+ "\n",
411
+ "### Step 1: Find the rate of painting per person\n",
412
+ "\n",
413
+ "- Total walls painted: 3 walls\n",
414
+ "- Total people: 3 people\n",
415
+ "- Total time: 3 hours\n",
416
+ "\n",
417
+ "**Walls per person per hour:**\n",
418
+ "\n",
419
+ "First, find how many walls 3 people paint per hour:\n",
420
+ "\n",
421
+ "\\[\n",
422
+ "\\frac{3 \\text{ walls}}{3 \\text{ hours}} = 1 \\text{ wall per hour by 3 people}\n",
423
+ "\\]\n",
424
+ "\n",
425
+ "So, 3 people paint 1 wall per hour.\n",
426
+ "\n",
427
+ "Then, walls per person per hour:\n",
428
+ "\n",
429
+ "\\[\n",
430
+ "\\frac{1 \\text{ wall per hour}}{3 \\text{ people}} = \\frac{1}{3} \\text{ wall per person per hour}\n",
431
+ "\\]\n",
432
+ "\n",
433
+ "---\n",
434
+ "\n",
435
+ "### Step 2: Calculate total work needed\n",
436
+ "\n",
437
+ "You want to paint 18 walls in 6 hours.\n",
438
+ "\n",
439
+ "This means the rate of painting must be:\n",
440
+ "\n",
441
+ "\\[\n",
442
+ "\\frac{18 \\text{ walls}}{6 \\text{ hours}} = 3 \\text{ walls per hour}\n",
443
+ "\\]\n",
444
+ "\n",
445
+ "---\n",
446
+ "\n",
447
+ "### Step 3: Find how many people are needed for this rate\n",
448
+ "\n",
449
+ "Since each person paints \\(\\frac{1}{3}\\) wall per hour,\n",
450
+ "\n",
451
+ "\\[\n",
452
+ "\\text{Number of people} \\times \\frac{1}{3} = 3 \\text{ walls per hour}\n",
453
+ "\\]\n",
454
+ "\n",
455
+ "Multiply both sides by 3:\n",
456
+ "\n",
457
+ "\\[\n",
458
+ "\\text{Number of people} = 3 \\times 3 = 9\n",
459
+ "\\]\n",
460
+ "\n",
461
+ "---\n",
462
+ "\n",
463
+ "### **Answer:**\n",
464
+ "\n",
465
+ "\\[\n",
466
+ "\\boxed{9}\n",
467
+ "\\]\n",
468
+ "\n",
469
+ "You need **9 people** to paint 18 walls in 6 hours."
470
+ ],
471
+ "text/plain": [
472
+ "<IPython.core.display.Markdown object>"
473
+ ]
474
+ },
475
+ "metadata": {},
476
+ "output_type": "display_data"
477
+ }
478
+ ],
479
+ "source": [
480
+ "from IPython.display import Markdown, display\n",
481
+ "\n",
482
+ "display(Markdown(answer))\n",
483
+ "\n"
484
+ ]
485
+ },
486
+ {
487
+ "cell_type": "markdown",
488
+ "metadata": {},
489
+ "source": [
490
+ "# Congratulations!\n",
491
+ "\n",
492
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
493
+ "\n",
494
+ "Next time things get more interesting..."
495
+ ]
496
+ },
497
+ {
498
+ "cell_type": "markdown",
499
+ "metadata": {},
500
+ "source": [
501
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
502
+ " <tr>\n",
503
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
504
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
505
+ " </td>\n",
506
+ " <td>\n",
507
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
508
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
509
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
510
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
511
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
512
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
513
+ " </span>\n",
514
+ " </td>\n",
515
+ " </tr>\n",
516
+ "</table>"
517
+ ]
518
+ },
519
+ {
520
+ "cell_type": "code",
521
+ "execution_count": 16,
522
+ "metadata": {},
523
+ "outputs": [
524
+ {
525
+ "data": {
526
+ "text/markdown": [
527
+ "Certainly! Building on your outlined pain-point and the high-level Agentic AI functionalities, here’s a detailed proposal for an **Agentic AI solution** designed to tackle fragmented patient data and enable real-time, holistic health management.\n",
528
+ "\n",
529
+ "---\n",
530
+ "\n",
531
+ "# Agentic AI Solution Proposal: **HealthSynth AI**\n",
532
+ "\n",
533
+ "### Overview \n",
534
+ "**HealthSynth AI** is an autonomous health management agent that continuously synthesizes fragmented patient data from multiple sources to provide a real-time, unified, and actionable health profile for patients and their care teams. It acts as a 24/7 health assistant, proactive coordinator, and personalized medical advisor.\n",
535
+ "\n",
536
+ "---\n",
537
+ "\n",
538
+ "## Key Features & Capabilities\n",
539
+ "\n",
540
+ "### 1. **Autonomous Data Aggregation & Normalization** \n",
541
+ "- Uses API integrations, secure data exchanges (FHIR, HL7 standards), and device SDKs to continuously fetch data from: \n",
542
+ " - EHR systems across different providers \n",
543
+ " - Wearable and home medical devices (heart rate, glucose monitors, BP cuffs) \n",
544
+ " - Pharmacy records and prescription databases \n",
545
+ " - Lab results portals \n",
546
+ " - Insurance claims and coverage data \n",
547
+ "- Applies intelligent data cleaning, deduplication, and semantic normalization to unify heterogeneous data formats into a consistent patient health graph.\n",
548
+ "\n",
549
+ "### 2. **Real-Time Multimodal Health Analytics Engine** \n",
550
+ "- Employs advanced ML and deep learning models to detect: \n",
551
+ " - Emerging risk patterns (e.g., early signs of infection, deterioration of chronic conditions) \n",
552
+ " - Anomalies (missed medications, unusual vital sign changes) \n",
553
+ " - Compliance gaps (lifestyle, medication adherence) \n",
554
+ "- Continuously updates predictive health trajectories personalized to each patient’s condition and history.\n",
555
+ "\n",
556
+ "### 3. **Proactive Action & Recommendation System** \n",
557
+ "- Generates context-aware, evidence-based alerts and recommendations such as: \n",
558
+ " - Medication reminders or dosage adjustments flagged in consultation with prescribing physicians \n",
559
+ " - Suggestions for scheduling lab tests or specialist visits timely before symptoms worsen \n",
560
+ " - Lifestyle coaching tips adapted using patient preferences and progress \n",
561
+ "- Classes recommendations into urgency tiers (info, caution, immediate action) and routes notifications appropriately.\n",
562
+ "\n",
563
+ "### 4. **Automated Care Coordination & Workflow Integration** \n",
564
+ "- Interacts programmatically with provider scheduling systems, telemedicine platforms, pharmacies, and insurance portals to: \n",
565
+ " - Automatically request appointment reschedules or referrals based on patient status \n",
566
+ " - Notify involved healthcare professionals about critical health events or lab results \n",
567
+ " - Facilitate prescription renewals or modifications with minimal human intervention \n",
568
+ "- Maintains secure, auditable communication logs ensuring compliance (HIPAA, GDPR).\n",
569
+ "\n",
570
+ "### 5. **Patient-Centric Digital Health Companion** \n",
571
+ "- Provides patients with an intuitive mobile/web app featuring: \n",
572
+ " - A dynamic health dashboard summarizing key metrics, risks, and recent activities in plain language \n",
573
+ " - Intelligent daily check-ins and symptom trackers powered by conversational AI \n",
574
+ " - Adaptive educational content tailored to health literacy levels and language preferences \n",
575
+ " - Privacy controls empowering patients to manage data sharing settings\n",
576
+ "\n",
577
+ "---\n",
578
+ "\n",
579
+ "## Technical Architecture (High-Level)\n",
580
+ "\n",
581
+ "- **Data Ingestion Layer:** Connectors for EHRs, wearables, pharmacies, labs \n",
582
+ "- **Data Lake & Processing:** Cloud-native secure storage with HIPAA-compliant encryption \n",
583
+ "- **Knowledge Graph:** Patient-centric semantic graph linking clinical concepts, timelines, interventions \n",
584
+ "- **Analytics & ML Models:** Ensemble predictive models incorporating temporal health data, risk scoring, anomaly detection \n",
585
+ "- **Agentic Orchestrator:** Rule-based and reinforcement learning-driven workflow engine enabling autonomous decision-making and stakeholder communications \n",
586
+ "- **Frontend Interfaces:** Responsive patient app, provider portals, API access for system integration\n",
587
+ "\n",
588
+ "---\n",
589
+ "\n",
590
+ "## Potential Challenges & Mitigations\n",
591
+ "\n",
592
+ "| Challenge | Mitigation Strategy |\n",
593
+ "|-----------|---------------------|\n",
594
+ "| Data privacy & regulatory compliance | Built-in privacy-by-design, end-to-end encryption, rigorous consent management, audit trails |\n",
595
+ "| Data interoperability & standardization | Utilize open standards (FHIR, DICOM), NLP for unstructured data extraction |\n",
596
+ "| Model explainability | Implement interpretable ML techniques and transparent reasoning for clinicians |\n",
597
+ "| Patient engagement sustainability | Gamification, behavior science-driven personalized nudges |\n",
598
+ "| Integration complexity across healthcare IT systems | Modular adaptors/plugins, partnerships with major EHR vendors |\n",
599
+ "\n",
600
+ "---\n",
601
+ "\n",
602
+ "## Impact & Benefits\n",
603
+ "\n",
604
+ "- **For Patients:** Reduced health risks, increased empowerment, improved treatment adherence, and personal convenience \n",
605
+ "- **For Providers:** Enhanced clinical decision support, reduced administrative burden, timely interventions \n",
606
+ "- **For Payers:** Lowered costs via preventive care and reduced hospital readmissions\n",
607
+ "\n",
608
+ "---\n",
609
+ "\n",
610
+ "Would you like me to help you design detailed user journeys, develop specific ML model architectures, or draft an implementation roadmap for **HealthSynth AI**?"
611
+ ],
612
+ "text/plain": [
613
+ "<IPython.core.display.Markdown object>"
614
+ ]
615
+ },
616
+ "metadata": {},
617
+ "output_type": "display_data"
618
+ }
619
+ ],
620
+ "source": [
621
+ "# First create the messages:\n",
622
+ "\n",
623
+ "messages = [{\"role\": \"user\", \"content\": \"I want you to pick a business area that might be worth exploring for an Agentic AI opportunity.\"}]\n",
624
+ "\n",
625
+ "# Then make the first call:\n",
626
+ "\n",
627
+ "response = openai.chat.completions.create(\n",
628
+ " model=\"gpt-4.1-mini\",\n",
629
+ " messages=messages\n",
630
+ ")\n",
631
+ "\n",
632
+ "# Then read the business idea:\n",
633
+ "\n",
634
+ "business_idea = response.choices[0].message.content\n",
635
+ "\n",
636
+ "# print(business_idea)\n",
637
+ "\n",
638
+ "messages = [{\"role\": \"user\", \"content\": f\"Please propose a pain-point in the {business_idea} industry.\"}]\n",
639
+ "\n",
640
+ "response = openai.chat.completions.create(\n",
641
+ " model=\"gpt-4.1-mini\",\n",
642
+ " messages=messages\n",
643
+ ")\n",
644
+ "\n",
645
+ "pain_point = response.choices[0].message.content\n",
646
+ "\n",
647
+ "messages = [{\"role\": \"user\", \"content\": f\"Please propose an Agentic AI solution to the pain-point: {pain_point}.\"}]\n",
648
+ "\n",
649
+ "response = openai.chat.completions.create(\n",
650
+ " model=\"gpt-4.1-mini\",\n",
651
+ " messages=messages\n",
652
+ ")\n",
653
+ "\n",
654
+ "agentic_solution = response.choices[0].message.content\n",
655
+ "\n",
656
+ "display(Markdown(agentic_solution))\n",
657
+ "\n",
658
+ "# And repeat! In the next message, include the business idea within the message"
659
+ ]
660
+ },
661
+ {
662
+ "cell_type": "markdown",
663
+ "metadata": {},
664
+ "source": []
665
+ }
666
+ ],
667
+ "metadata": {
668
+ "kernelspec": {
669
+ "display_name": ".venv",
670
+ "language": "python",
671
+ "name": "python3"
672
+ },
673
+ "language_info": {
674
+ "codemirror_mode": {
675
+ "name": "ipython",
676
+ "version": 3
677
+ },
678
+ "file_extension": ".py",
679
+ "mimetype": "text/x-python",
680
+ "name": "python",
681
+ "nbconvert_exporter": "python",
682
+ "pygments_lexer": "ipython3",
683
+ "version": "3.12.11"
684
+ }
685
+ },
686
+ "nbformat": 4,
687
+ "nbformat_minor": 2
688
+ }
community_contributions/1_lab1_Japyh.ipynb ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
10
+ "from dotenv import load_dotenv"
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "code",
15
+ "execution_count": null,
16
+ "metadata": {},
17
+ "outputs": [],
18
+ "source": [
19
+ "# Next it's time to load the API keys into environment variables\n",
20
+ "# If this returns false, see the next cell!\n",
21
+ "load_dotenv(override=True)"
22
+ ]
23
+ },
24
+ {
25
+ "cell_type": "code",
26
+ "execution_count": null,
27
+ "metadata": {},
28
+ "outputs": [],
29
+ "source": [
30
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
31
+ "import os\n",
32
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
33
+ "\n",
34
+ "if openai_api_key:\n",
35
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
36
+ "else:\n",
37
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "# And now - the all important import statement\n",
47
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
48
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
49
+ "from openai import OpenAI"
50
+ ]
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "execution_count": null,
55
+ "metadata": {},
56
+ "outputs": [],
57
+ "source": [
58
+ "# And now we'll create an instance of the OpenAI class\n",
59
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
60
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
61
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
62
+ "openai = OpenAI()"
63
+ ]
64
+ },
65
+ {
66
+ "cell_type": "code",
67
+ "execution_count": null,
68
+ "metadata": {},
69
+ "outputs": [],
70
+ "source": [
71
+ "# Create a list of messages in the familiar OpenAI format\n",
72
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "metadata": {},
79
+ "outputs": [],
80
+ "source": [
81
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
82
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
83
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
84
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
85
+ "response = openai.chat.completions.create(\n",
86
+ " model=\"gpt-4.1-nano\",\n",
87
+ " messages=messages\n",
88
+ ")\n",
89
+ "\n",
90
+ "print(response.choices[0].message.content)"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "metadata": {},
97
+ "outputs": [],
98
+ "source": [
99
+ "# And now - let's ask for a question:\n",
100
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
101
+ "messages = [{\"role\": \"user\", \"content\": question}]"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": null,
107
+ "metadata": {},
108
+ "outputs": [],
109
+ "source": [
110
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
111
+ "response = openai.chat.completions.create(\n",
112
+ " model=\"gpt-4.1-mini\",\n",
113
+ " messages=messages\n",
114
+ ")\n",
115
+ "\n",
116
+ "question = response.choices[0].message.content\n",
117
+ "\n",
118
+ "print(question)"
119
+ ]
120
+ },
121
+ {
122
+ "cell_type": "code",
123
+ "execution_count": null,
124
+ "metadata": {},
125
+ "outputs": [],
126
+ "source": [
127
+ "# form a new messages list\n",
128
+ "messages = [{\"role\": \"user\", \"content\": question}]"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "from IPython.display import Markdown, display\n",
138
+ "# Ask it again\n",
139
+ "response = openai.chat.completions.create(\n",
140
+ " model=\"gpt-4.1-mini\",\n",
141
+ " messages=messages\n",
142
+ ")\n",
143
+ "\n",
144
+ "answer = response.choices[0].message.content\n",
145
+ "display(Markdown(answer))"
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "markdown",
150
+ "metadata": {},
151
+ "source": [
152
+ "# Congratulations!\n",
153
+ "\n",
154
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
155
+ "\n",
156
+ "Next time things get more interesting..."
157
+ ]
158
+ },
159
+ {
160
+ "cell_type": "code",
161
+ "execution_count": null,
162
+ "metadata": {},
163
+ "outputs": [],
164
+ "source": [
165
+ "# First create the messages:\n",
166
+ "\n",
167
+ "messages = [{\"role\": \"user\", \"content\": \",Please propose a unique, creative business idea that has a high chance of success. Respond only with the business idea, no explanations.\"}]\n",
168
+ "\n",
169
+ "# Then make the first call:\n",
170
+ "\n",
171
+ "response = openai.chat.completions.create(\n",
172
+ " model=\"gpt-4.1-mini\",\n",
173
+ " messages=messages\n",
174
+ ")\n",
175
+ "\n",
176
+ "# Then read the business idea:\n",
177
+ "\n",
178
+ "business_idea = response.choices[0].message.content\n",
179
+ "\n",
180
+ "# And repeat! In the next message, include the business idea within the message\n",
181
+ "messages = [{\"role\": \"user\", \"content\": f\"Present a pain-point that customers of the following business idea might have: {business_idea}\"}]\n",
182
+ "\n",
183
+ "response = openai.chat.completions.create(\n",
184
+ " model=\"gpt-4.1-mini\",\n",
185
+ " messages=messages\n",
186
+ ")\n",
187
+ "\n",
188
+ "pain_point = response.choices[0].message.content\n",
189
+ "\n",
190
+ "messages = [{\"role\": \"user\", \"content\": f\"Propose a solution to the following pain-point: {pain_point}\"}]\n",
191
+ "\n",
192
+ "response = openai.chat.completions.create(\n",
193
+ " model=\"gpt-4.1-mini\",\n",
194
+ " messages=messages\n",
195
+ ")\n",
196
+ "\n",
197
+ "solution = response.choices[0].message.content\n",
198
+ "\n",
199
+ "display(Markdown(f\"**Business idea:** {business_idea}\"))\n",
200
+ "display(Markdown(f\"**Pain point:** {pain_point}\"))\n",
201
+ "display(Markdown(f\"**Solution:** {solution}\"))"
202
+ ]
203
+ }
204
+ ],
205
+ "metadata": {
206
+ "kernelspec": {
207
+ "display_name": "agents",
208
+ "language": "python",
209
+ "name": "python3"
210
+ },
211
+ "language_info": {
212
+ "codemirror_mode": {
213
+ "name": "ipython",
214
+ "version": 3
215
+ },
216
+ "file_extension": ".py",
217
+ "mimetype": "text/x-python",
218
+ "name": "python",
219
+ "nbconvert_exporter": "python",
220
+ "pygments_lexer": "ipython3",
221
+ "version": "3.12.12"
222
+ }
223
+ },
224
+ "nbformat": 4,
225
+ "nbformat_minor": 2
226
+ }
community_contributions/1_lab1_Mohan_M.ipynb ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-nano\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": null,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# First create the messages:\n",
326
+ "\n",
327
+ "messages = [{\"role\": \"user\", \"content\": \"Something here\"}]\n",
328
+ "\n",
329
+ "# Then make the first call:\n",
330
+ "\n",
331
+ "response =\n",
332
+ "\n",
333
+ "# Then read the business idea:\n",
334
+ "\n",
335
+ "business_idea = response.\n",
336
+ "\n",
337
+ "# And repeat! In the next message, include the business idea within the message"
338
+ ]
339
+ },
340
+ {
341
+ "cell_type": "markdown",
342
+ "metadata": {},
343
+ "source": []
344
+ }
345
+ ],
346
+ "metadata": {
347
+ "kernelspec": {
348
+ "display_name": ".venv",
349
+ "language": "python",
350
+ "name": "python3"
351
+ },
352
+ "language_info": {
353
+ "codemirror_mode": {
354
+ "name": "ipython",
355
+ "version": 3
356
+ },
357
+ "file_extension": ".py",
358
+ "mimetype": "text/x-python",
359
+ "name": "python",
360
+ "nbconvert_exporter": "python",
361
+ "pygments_lexer": "ipython3",
362
+ "version": "3.12.9"
363
+ }
364
+ },
365
+ "nbformat": 4,
366
+ "nbformat_minor": 2
367
+ }
community_contributions/1_lab1_Mudassar.ipynb ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# First Agentic AI workflow with OPENAI"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "#### And please do remember to contact me if I can help\n",
15
+ "\n",
16
+ "And I love to connect: https://www.linkedin.com/in/muhammad-mudassar-a65645192/"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "metadata": {},
22
+ "source": [
23
+ "## Import Libraries"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": 59,
29
+ "metadata": {},
30
+ "outputs": [],
31
+ "source": [
32
+ "import os\n",
33
+ "import re\n",
34
+ "from openai import OpenAI\n",
35
+ "from dotenv import load_dotenv\n",
36
+ "from IPython.display import Markdown, display"
37
+ ]
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "execution_count": null,
42
+ "metadata": {},
43
+ "outputs": [],
44
+ "source": [
45
+ "load_dotenv(override=True)"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "execution_count": null,
51
+ "metadata": {},
52
+ "outputs": [],
53
+ "source": [
54
+ "openai_api_key=os.getenv(\"OPENAI_API_KEY\")\n",
55
+ "if openai_api_key:\n",
56
+ " print(f\"openai api key exists and begins {openai_api_key[:8]}\")\n",
57
+ "else:\n",
58
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the gui\")"
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "markdown",
63
+ "metadata": {},
64
+ "source": [
65
+ "## Workflow with OPENAI"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": 21,
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "openai=OpenAI()"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 31,
80
+ "metadata": {},
81
+ "outputs": [],
82
+ "source": [
83
+ "message = [{'role':'user','content':\"what is 2+3?\"}]"
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "response = openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
93
+ "print(response.choices[0].message.content)"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": 33,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
103
+ "message=[{'role':'user','content':question}]"
104
+ ]
105
+ },
106
+ {
107
+ "cell_type": "code",
108
+ "execution_count": null,
109
+ "metadata": {},
110
+ "outputs": [],
111
+ "source": [
112
+ "response=openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
113
+ "question=response.choices[0].message.content\n",
114
+ "print(f\"Answer: {question}\")"
115
+ ]
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "execution_count": 35,
120
+ "metadata": {},
121
+ "outputs": [],
122
+ "source": [
123
+ "message=[{'role':'user','content':question}]"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": null,
129
+ "metadata": {},
130
+ "outputs": [],
131
+ "source": [
132
+ "response=openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
133
+ "answer = response.choices[0].message.content\n",
134
+ "print(f\"Answer: {answer}\")"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "code",
139
+ "execution_count": null,
140
+ "metadata": {},
141
+ "outputs": [],
142
+ "source": [
143
+ "# convert \\[ ... \\] to $$ ... $$, to properly render Latex\n",
144
+ "converted_answer = re.sub(r'\\\\[\\[\\]]', '$$', answer)\n",
145
+ "display(Markdown(converted_answer))"
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "markdown",
150
+ "metadata": {},
151
+ "source": [
152
+ "## Exercise"
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "markdown",
157
+ "metadata": {},
158
+ "source": [
159
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
160
+ " <tr>\n",
161
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
162
+ " <img src=\"../../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
163
+ " </td>\n",
164
+ " <td>\n",
165
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
166
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
167
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
168
+ " Finally have 3 third LLM call propose the Agentic AI solution.\n",
169
+ " </span>\n",
170
+ " </td>\n",
171
+ " </tr>\n",
172
+ "</table>"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": 42,
178
+ "metadata": {},
179
+ "outputs": [],
180
+ "source": [
181
+ "message = [{'role':'user','content':\"give me a business area related to ecommerce that might be worth exploring for a agentic opportunity.\"}]"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "code",
186
+ "execution_count": null,
187
+ "metadata": {},
188
+ "outputs": [],
189
+ "source": [
190
+ "response = openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
191
+ "business_area = response.choices[0].message.content\n",
192
+ "business_area"
193
+ ]
194
+ },
195
+ {
196
+ "cell_type": "code",
197
+ "execution_count": null,
198
+ "metadata": {},
199
+ "outputs": [],
200
+ "source": [
201
+ "message = business_area + \"present a pain-point in that industry - something challenging that might be ripe for an agentic solutions.\"\n",
202
+ "message"
203
+ ]
204
+ },
205
+ {
206
+ "cell_type": "code",
207
+ "execution_count": null,
208
+ "metadata": {},
209
+ "outputs": [],
210
+ "source": [
211
+ "message = [{'role': 'user', 'content': message}]\n",
212
+ "response = openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
213
+ "question=response.choices[0].message.content\n",
214
+ "question"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "message=[{'role':'user','content':question}]\n",
224
+ "response=openai.chat.completions.create(model=\"gpt-4o-mini\",messages=message)\n",
225
+ "answer=response.choices[0].message.content\n",
226
+ "print(answer)"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "display(Markdown(answer))"
236
+ ]
237
+ }
238
+ ],
239
+ "metadata": {
240
+ "kernelspec": {
241
+ "display_name": ".venv",
242
+ "language": "python",
243
+ "name": "python3"
244
+ },
245
+ "language_info": {
246
+ "codemirror_mode": {
247
+ "name": "ipython",
248
+ "version": 3
249
+ },
250
+ "file_extension": ".py",
251
+ "mimetype": "text/x-python",
252
+ "name": "python",
253
+ "nbconvert_exporter": "python",
254
+ "pygments_lexer": "ipython3",
255
+ "version": "3.12.5"
256
+ }
257
+ },
258
+ "nbformat": 4,
259
+ "nbformat_minor": 2
260
+ }
community_contributions/1_lab1_Thanh.ipynb ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in Agentic AI"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "### And please do remember to contact me if I can help\n",
15
+ "\n",
16
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
17
+ "\n",
18
+ "\n",
19
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
20
+ "\n",
21
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
22
+ "- Open extensions (View >> extensions)\n",
23
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
24
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
25
+ "Then View >> Explorer to bring back the File Explorer.\n",
26
+ "\n",
27
+ "And then:\n",
28
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
29
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
30
+ "3. Enjoy!\n",
31
+ "\n",
32
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
33
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
34
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
35
+ "2. In the Settings search bar, type \"venv\" \n",
36
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
37
+ "And then try again.\n",
38
+ "\n",
39
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
40
+ "`conda deactivate` \n",
41
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
42
+ "`conda config --set auto_activate_base false` \n",
43
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
44
+ ]
45
+ },
46
+ {
47
+ "cell_type": "code",
48
+ "execution_count": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "from dotenv import load_dotenv\n",
53
+ "load_dotenv()"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": null,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "# Check the keys\n",
63
+ "import google.generativeai as genai\n",
64
+ "import os\n",
65
+ "genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))\n",
66
+ "model = genai.GenerativeModel(model_name=\"gemini-1.5-flash\")\n"
67
+ ]
68
+ },
69
+ {
70
+ "cell_type": "code",
71
+ "execution_count": null,
72
+ "metadata": {},
73
+ "outputs": [],
74
+ "source": [
75
+ "# Create a list of messages in the familiar Gemini GenAI format\n",
76
+ "\n",
77
+ "response = model.generate_content([\"2+2=?\"])\n",
78
+ "response.text"
79
+ ]
80
+ },
81
+ {
82
+ "cell_type": "code",
83
+ "execution_count": null,
84
+ "metadata": {},
85
+ "outputs": [],
86
+ "source": [
87
+ "# And now - let's ask for a question:\n",
88
+ "\n",
89
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
90
+ "\n",
91
+ "response = model.generate_content([question])\n",
92
+ "print(response.text)"
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "metadata": {},
99
+ "outputs": [],
100
+ "source": [
101
+ "from IPython.display import Markdown, display\n",
102
+ "\n",
103
+ "display(Markdown(response.text))"
104
+ ]
105
+ },
106
+ {
107
+ "cell_type": "markdown",
108
+ "metadata": {},
109
+ "source": [
110
+ "# Congratulations!\n",
111
+ "\n",
112
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
113
+ "\n",
114
+ "Next time things get more interesting..."
115
+ ]
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "execution_count": null,
120
+ "metadata": {},
121
+ "outputs": [],
122
+ "source": [
123
+ "# First create the messages:\n",
124
+ "\n",
125
+ "messages = [{\"role\": \"user\", \"content\": \"Something here\"}]\n",
126
+ "\n",
127
+ "# Then make the first call:\n",
128
+ "\n",
129
+ "response =\n",
130
+ "\n",
131
+ "# Then read the business idea:\n",
132
+ "\n",
133
+ "business_idea = response.\n",
134
+ "\n",
135
+ "# And repeat!"
136
+ ]
137
+ },
138
+ {
139
+ "cell_type": "markdown",
140
+ "metadata": {},
141
+ "source": []
142
+ }
143
+ ],
144
+ "metadata": {
145
+ "kernelspec": {
146
+ "display_name": "llm_projects",
147
+ "language": "python",
148
+ "name": "python3"
149
+ },
150
+ "language_info": {
151
+ "codemirror_mode": {
152
+ "name": "ipython",
153
+ "version": 3
154
+ },
155
+ "file_extension": ".py",
156
+ "mimetype": "text/x-python",
157
+ "name": "python",
158
+ "nbconvert_exporter": "python",
159
+ "pygments_lexer": "ipython3",
160
+ "version": "3.10.15"
161
+ }
162
+ },
163
+ "nbformat": 4,
164
+ "nbformat_minor": 2
165
+ }
community_contributions/1_lab1_chandra_chekuri.ipynb ADDED
@@ -0,0 +1,620 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": 1,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": 2,
100
+ "metadata": {},
101
+ "outputs": [
102
+ {
103
+ "data": {
104
+ "text/plain": [
105
+ "True"
106
+ ]
107
+ },
108
+ "execution_count": 2,
109
+ "metadata": {},
110
+ "output_type": "execute_result"
111
+ }
112
+ ],
113
+ "source": [
114
+ "# Next it's time to load the API keys into environment variables\n",
115
+ "# If this returns false, see the next cell!\n",
116
+ "\n",
117
+ "load_dotenv(override=True)"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "markdown",
122
+ "metadata": {},
123
+ "source": [
124
+ "### Wait, did that just output `False`??\n",
125
+ "\n",
126
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
127
+ "\n",
128
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
129
+ "\n",
130
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
131
+ ]
132
+ },
133
+ {
134
+ "cell_type": "markdown",
135
+ "metadata": {},
136
+ "source": [
137
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
138
+ " <tr>\n",
139
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
140
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
141
+ " </td>\n",
142
+ " <td>\n",
143
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
144
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
145
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
146
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
147
+ " </span>\n",
148
+ " </td>\n",
149
+ " </tr>\n",
150
+ "</table>"
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "code",
155
+ "execution_count": 3,
156
+ "metadata": {},
157
+ "outputs": [
158
+ {
159
+ "name": "stdout",
160
+ "output_type": "stream",
161
+ "text": [
162
+ "OpenAI API Key exists and begins sk-proj-\n"
163
+ ]
164
+ }
165
+ ],
166
+ "source": [
167
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
168
+ "\n",
169
+ "import os\n",
170
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
171
+ "\n",
172
+ "if openai_api_key:\n",
173
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
174
+ "else:\n",
175
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
176
+ " \n"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": 4,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "# And now - the all important import statement\n",
186
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
187
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
188
+ "\n",
189
+ "from openai import OpenAI"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 5,
195
+ "metadata": {},
196
+ "outputs": [],
197
+ "source": [
198
+ "# And now we'll create an instance of the OpenAI class\n",
199
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
200
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
201
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
202
+ "\n",
203
+ "openai = OpenAI()"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "code",
208
+ "execution_count": 6,
209
+ "metadata": {},
210
+ "outputs": [],
211
+ "source": [
212
+ "# Create a list of messages in the familiar OpenAI format\n",
213
+ "\n",
214
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [
222
+ {
223
+ "name": "stdout",
224
+ "output_type": "stream",
225
+ "text": [
226
+ "2 + 2 equals 4.\n",
227
+ "assistant\n"
228
+ ]
229
+ }
230
+ ],
231
+ "source": [
232
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
233
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
234
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
235
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-nano\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "print(response.choices[0].message.content)\n"
243
+ ]
244
+ },
245
+ {
246
+ "cell_type": "code",
247
+ "execution_count": null,
248
+ "metadata": {},
249
+ "outputs": [],
250
+ "source": [
251
+ "# And now - let's ask for a question:\n",
252
+ "\n",
253
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": 11,
260
+ "metadata": {},
261
+ "outputs": [
262
+ {
263
+ "name": "stdout",
264
+ "output_type": "stream",
265
+ "text": [
266
+ "If all Bloops are Razzies and all Razzies are Lazzies, are all Bloops definitely Lazzies? Explain your reasoning.\n"
267
+ ]
268
+ }
269
+ ],
270
+ "source": [
271
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
272
+ "\n",
273
+ "response = openai.chat.completions.create(\n",
274
+ " model=\"gpt-4.1-mini\",\n",
275
+ " messages=messages\n",
276
+ ")\n",
277
+ "\n",
278
+ "question = response.choices[0].message.content\n",
279
+ "\n",
280
+ "print(question)\n"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": 12,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "# form a new messages list\n",
290
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
291
+ ]
292
+ },
293
+ {
294
+ "cell_type": "code",
295
+ "execution_count": 13,
296
+ "metadata": {},
297
+ "outputs": [
298
+ {
299
+ "name": "stdout",
300
+ "output_type": "stream",
301
+ "text": [
302
+ "Yes, all Bloops are definitely Lazzies.\n",
303
+ "\n",
304
+ "**Reasoning:**\n",
305
+ "\n",
306
+ "1. The statement \"All Bloops are Razzies\" means every member of the set Bloops is also a member of the set Razzies.\n",
307
+ "2. The statement \"All Razzies are Lazzies\" means every member of the set Razzies is also a member of the set Lazzies.\n",
308
+ "\n",
309
+ "Since all Bloops are inside the Razzies group, and all Razzies are inside the Lazzies group, it follows that all Bloops must be inside the Lazzies group.\n",
310
+ "\n",
311
+ "In other words, the set of Bloops is a subset of Razzies, and Razzies is a subset of Lazzies. Therefore, Bloops is a subset of Lazzies.\n",
312
+ "\n",
313
+ "This is a classic example of the transitive property in logic and set theory:\n",
314
+ "- If A ⊆ B and B ⊆ C, then A ⊆ C.\n",
315
+ "\n",
316
+ "So, yes, all Bloops are definitely Lazzies.\n"
317
+ ]
318
+ }
319
+ ],
320
+ "source": [
321
+ "# Ask it again\n",
322
+ "\n",
323
+ "response = openai.chat.completions.create(\n",
324
+ " model=\"gpt-4.1-mini\",\n",
325
+ " messages=messages\n",
326
+ ")\n",
327
+ "\n",
328
+ "answer = response.choices[0].message.content\n",
329
+ "print(answer)\n"
330
+ ]
331
+ },
332
+ {
333
+ "cell_type": "code",
334
+ "execution_count": 14,
335
+ "metadata": {},
336
+ "outputs": [
337
+ {
338
+ "data": {
339
+ "text/markdown": [
340
+ "Yes, all Bloops are definitely Lazzies.\n",
341
+ "\n",
342
+ "**Reasoning:**\n",
343
+ "\n",
344
+ "1. The statement \"All Bloops are Razzies\" means every member of the set Bloops is also a member of the set Razzies.\n",
345
+ "2. The statement \"All Razzies are Lazzies\" means every member of the set Razzies is also a member of the set Lazzies.\n",
346
+ "\n",
347
+ "Since all Bloops are inside the Razzies group, and all Razzies are inside the Lazzies group, it follows that all Bloops must be inside the Lazzies group.\n",
348
+ "\n",
349
+ "In other words, the set of Bloops is a subset of Razzies, and Razzies is a subset of Lazzies. Therefore, Bloops is a subset of Lazzies.\n",
350
+ "\n",
351
+ "This is a classic example of the transitive property in logic and set theory:\n",
352
+ "- If A ⊆ B and B ⊆ C, then A ⊆ C.\n",
353
+ "\n",
354
+ "So, yes, all Bloops are definitely Lazzies."
355
+ ],
356
+ "text/plain": [
357
+ "<IPython.core.display.Markdown object>"
358
+ ]
359
+ },
360
+ "metadata": {},
361
+ "output_type": "display_data"
362
+ }
363
+ ],
364
+ "source": [
365
+ "from IPython.display import Markdown, display\n",
366
+ "\n",
367
+ "display(Markdown(answer))\n",
368
+ "\n"
369
+ ]
370
+ },
371
+ {
372
+ "cell_type": "markdown",
373
+ "metadata": {},
374
+ "source": [
375
+ "# Congratulations!\n",
376
+ "\n",
377
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
378
+ "\n",
379
+ "Next time things get more interesting..."
380
+ ]
381
+ },
382
+ {
383
+ "cell_type": "markdown",
384
+ "metadata": {},
385
+ "source": [
386
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
387
+ " <tr>\n",
388
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
389
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
390
+ " </td>\n",
391
+ " <td>\n",
392
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
393
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
394
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
395
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
396
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
397
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
398
+ " </span>\n",
399
+ " </td>\n",
400
+ " </tr>\n",
401
+ "</table>"
402
+ ]
403
+ },
404
+ {
405
+ "cell_type": "code",
406
+ "execution_count": 17,
407
+ "metadata": {},
408
+ "outputs": [
409
+ {
410
+ "name": "stdout",
411
+ "output_type": "stream",
412
+ "text": [
413
+ "One promising business area to explore for an Agentic AI opportunity is **Supply Chain and Logistics Management**.\n",
414
+ "\n",
415
+ "### Why Supply Chain and Logistics?\n",
416
+ "\n",
417
+ "1. **Complex Decision-Making Environment:** Supply chains involve numerous variables including inventory levels, demand forecasting, transportation routes, supplier reliability, and geopolitical factors. An Agentic AI can autonomously analyze these variables in real-time and make optimized decisions.\n",
418
+ "\n",
419
+ "2. **High Impact on Efficiency and Cost:** Optimizing supply chain operations directly reduces costs, improves delivery times, and enhances customer satisfaction. Autonomous AI agents can dynamically reroute shipments, adjust inventory strategies, and renegotiate with suppliers in response to unexpected events.\n",
420
+ "\n",
421
+ "3. **Adaptability to Disruptions:** Agentic AI can proactively manage disruptions—e.g., natural disasters, port strikes, sudden demand spikes—by autonomously altering plans without human intervention, maintaining supply chain resilience.\n",
422
+ "\n",
423
+ "4. **Data-Rich Environment:** Supply chains generate massive amounts of data from IoT sensors, ERP systems, and market trends. An Agentic AI can continuously learn from this data to improve decision-making over time.\n",
424
+ "\n",
425
+ "5. **Scalability:** Agents can operate across multiple nodes of a global supply chain, coordinating activities and ensuring end-to-end optimization, a task challenging for traditional manual or semi-automated tools.\n",
426
+ "\n",
427
+ "### Example Use Cases\n",
428
+ "\n",
429
+ "- Autonomous inventory management agents that predict and reorder supplies.\n",
430
+ "- AI-driven transportation agents that plan and adjust delivery routes in real-time.\n",
431
+ "- Negotiation agents that interact with suppliers to secure better terms or resolve delays.\n",
432
+ "- Risk management agents that simulate scenarios and implement contingency plans proactively.\n",
433
+ "\n",
434
+ "### Potential ROI\n",
435
+ "\n",
436
+ "Improved efficiency and responsiveness can lead to significant cost reductions, better service levels, and competitive advantages in markets where speed and reliability are critical.\n",
437
+ "\n",
438
+ "---\n",
439
+ "\n",
440
+ "Would you like me to elaborate on potential technical approaches or business models for Agentic AI in this field?\n"
441
+ ]
442
+ }
443
+ ],
444
+ "source": [
445
+ "# First create the messages:\n",
446
+ "\n",
447
+ "messages = [{\"role\": \"user\", \"content\": \"pick a business area that might be worth exploring for an Agentic AI opportunity.\"}]\n",
448
+ "\n",
449
+ "# Then make the first call:\n",
450
+ "\n",
451
+ "response = openai.chat.completions.create(\n",
452
+ " model=\"gpt-4.1-mini\",\n",
453
+ " messages=messages\n",
454
+ ")\n",
455
+ "\n",
456
+ "# Then read the business idea:\n",
457
+ "\n",
458
+ "business_idea = response.choices[0].message.content\n",
459
+ "print(business_idea)\n",
460
+ "\n",
461
+ "# And repeat! In the next message, include the business idea within the message"
462
+ ]
463
+ },
464
+ {
465
+ "cell_type": "code",
466
+ "execution_count": 19,
467
+ "metadata": {},
468
+ "outputs": [
469
+ {
470
+ "name": "stdout",
471
+ "output_type": "stream",
472
+ "text": [
473
+ "Certainly! Let’s consider the **healthcare industry** as an example.\n",
474
+ "\n",
475
+ "**Pain-point:** \n",
476
+ "Healthcare providers often struggle with **efficiently managing and coordinating patient care across multiple departments and specialists**, leading to delays, miscommunications, and fragmented patient experiences.\n",
477
+ "\n",
478
+ "**Why it’s challenging:** \n",
479
+ "- Patient information is often siloed in different systems or departments. \n",
480
+ "- Coordinating appointments, treatments, and follow-ups requires constant communication and scheduling adjustments. \n",
481
+ "- Healthcare professionals face high workloads, making manual coordination prone to errors and delays. \n",
482
+ "- Patients may receive redundant tests or conflicting advice due to lack of coordinated care.\n",
483
+ "\n",
484
+ "**Ripe for an Agentic solution:** \n",
485
+ "An intelligent, autonomous agent could serve as a centralized care coordinator that: \n",
486
+ "- Integrates data across hospital systems to create a unified patient profile. \n",
487
+ "- Dynamically schedules and synchronizes appointments and treatments based on specialist availability and patient needs. \n",
488
+ "- Sends proactive reminders and updates to both patients and providers. \n",
489
+ "- Continuously learns and adapts to optimize care pathways and reduce bottlenecks.\n",
490
+ "\n",
491
+ "Such an agentic system could profoundly improve efficiency, reduce errors, and enhance patient outcomes by automating complex coordination tasks and enabling more seamless communication among all stakeholders.\n"
492
+ ]
493
+ }
494
+ ],
495
+ "source": [
496
+ "pick_pain_point = [{\"role\":\"user\",\"content\" : \"present a pain-point in that industry - something challenging that might be ripe for an Agentic solution\"}]\n",
497
+ "\n",
498
+ "response = openai.chat.completions.create(\n",
499
+ " model=\"gpt-4.1-mini\",\n",
500
+ " messages=pick_pain_point\n",
501
+ ")\n",
502
+ "\n",
503
+ "pain_point = response.choices[0].message.content\n",
504
+ "print(pain_point)"
505
+ ]
506
+ },
507
+ {
508
+ "cell_type": "code",
509
+ "execution_count": 20,
510
+ "metadata": {},
511
+ "outputs": [
512
+ {
513
+ "name": "stdout",
514
+ "output_type": "stream",
515
+ "text": [
516
+ "\"Agentic AI\" refers to artificial intelligence systems that operate with a degree of autonomy and goal-directed behavior, often capable of making decisions, planning, and interacting with environments in a manner similar to an agent. When proposing an Agentic AI solution, it’s important to outline the system's objectives, capabilities, architecture, and deployment context clearly.\n",
517
+ "\n",
518
+ "Here is a structured proposal for an Agentic AI solution:\n",
519
+ "\n",
520
+ "---\n",
521
+ "\n",
522
+ "### Proposal: Agentic AI Solution for Autonomous Task Management\n",
523
+ "\n",
524
+ "#### 1. **Objective**\n",
525
+ "\n",
526
+ "Develop an Agentic AI system capable of autonomously managing complex tasks in dynamic environments. The agent should be able to perceive its environment, make decisions, plan actions, learn from outcomes, and communicate effectively with human users.\n",
527
+ "\n",
528
+ "#### 2. **Use Case**\n",
529
+ "\n",
530
+ "- Autonomous workflow management in enterprise settings.\n",
531
+ "- Robotic process automation with adaptive decision-making.\n",
532
+ "- Intelligent virtual assistants that handle multi-step goals.\n",
533
+ "- Autonomous vehicles or robotic agents performing navigation and task execution.\n",
534
+ "\n",
535
+ "#### 3. **Core Capabilities**\n",
536
+ "\n",
537
+ "- **Perception:** Ability to gather and interpret data from multiple sources (sensors, databases, APIs).\n",
538
+ "- **Reasoning and Decision Making:** Use of symbolic reasoning, probabilistic models, or reinforcement learning to make goal-oriented decisions.\n",
539
+ "- **Planning:** Generate and optimize multi-step action plans to achieve high-level goals.\n",
540
+ "- **Learning:** Adapt strategies based on feedback using supervised, unsupervised, or reinforcement learning techniques.\n",
541
+ "- **Interaction:** Natural language processing and multimodal communication for engaging with users and other systems.\n",
542
+ "\n",
543
+ "#### 4. **Technical Architecture**\n",
544
+ "\n",
545
+ "- **Perception Layer:** Data ingestion modules with preprocessing, sensor fusion, and environment modeling.\n",
546
+ "- **Cognitive Layer:**\n",
547
+ " - Knowledge base for domain-specific understanding.\n",
548
+ " - Planning engine implementing algorithms such as A* search, Monte Carlo Tree Search, or heuristic planners.\n",
549
+ " - Decision module leveraging AI models (e.g., deep reinforcement learning).\n",
550
+ "- **Learning Layer:** Continuous learning pipelines to update models and improve performance.\n",
551
+ "- **Interaction Layer:** NLP processors, dialog managers, and multimodal interfaces.\n",
552
+ "- **Execution Layer:** Actuation modules or API connectors to perform planned actions.\n",
553
+ "\n",
554
+ "#### 5. **Implementation Approach**\n",
555
+ "\n",
556
+ "- Utilize a modular software framework such as ROS (Robot Operating System) for robotics agents or a microservices architecture for software agents.\n",
557
+ "- Integrate AI models developed with frameworks like TensorFlow or PyTorch.\n",
558
+ "- Employ cloud infrastructure for scalability and real-time data processing.\n",
559
+ "- Emphasize safety, transparency, and explainability to maintain trust and compliance.\n",
560
+ "\n",
561
+ "#### 6. **Evaluation Metrics**\n",
562
+ "\n",
563
+ "- Task success rate.\n",
564
+ "- Efficiency in task completion time.\n",
565
+ "- Responsiveness and adaptability to changes.\n",
566
+ "- User satisfaction and usability feedback.\n",
567
+ "- Robustness to uncertainty and errors.\n",
568
+ "\n",
569
+ "#### 7. **Potential Challenges**\n",
570
+ "\n",
571
+ "- Ensuring reliable perception in noisy environments.\n",
572
+ "- Balancing autonomy with human oversight.\n",
573
+ "- Handling ethical and privacy concerns.\n",
574
+ "- Maintaining system robustness and avoiding unintended behavior.\n",
575
+ "\n",
576
+ "#### 8. **Conclusion**\n",
577
+ "\n",
578
+ "This Agentic AI solution can significantly enhance automation by providing intelligent, autonomous agents capable of managing complex, dynamic tasks effectively. It holds promise across various industries, from manufacturing and logistics to customer service and autonomous vehicles.\n",
579
+ "\n",
580
+ "---\n",
581
+ "\n",
582
+ "If you have a specific domain or problem in mind, I can tailor the proposal accordingly. Would you like me to do that?\n"
583
+ ]
584
+ }
585
+ ],
586
+ "source": [
587
+ "propose=[{\"role\":\"user\",\"content\" : \"propose the Agentic AI solution\"}]\n",
588
+ "\n",
589
+ "response = openai.chat.completions.create(\n",
590
+ " model=\"gpt-4.1-mini\",\n",
591
+ " messages=propose\n",
592
+ ")\n",
593
+ "\n",
594
+ "solution = response.choices[0].message.content\n",
595
+ "print(solution)\n"
596
+ ]
597
+ }
598
+ ],
599
+ "metadata": {
600
+ "kernelspec": {
601
+ "display_name": ".venv",
602
+ "language": "python",
603
+ "name": "python3"
604
+ },
605
+ "language_info": {
606
+ "codemirror_mode": {
607
+ "name": "ipython",
608
+ "version": 3
609
+ },
610
+ "file_extension": ".py",
611
+ "mimetype": "text/x-python",
612
+ "name": "python",
613
+ "nbconvert_exporter": "python",
614
+ "pygments_lexer": "ipython3",
615
+ "version": "3.12.9"
616
+ }
617
+ },
618
+ "nbformat": 4,
619
+ "nbformat_minor": 2
620
+ }
community_contributions/1_lab1_cm.ipynb ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
23
+ " Well in that case, you're ready!!\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "markdown",
32
+ "metadata": {},
33
+ "source": [
34
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
35
+ " <tr>\n",
36
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
37
+ " <img src=\"../../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
38
+ " </td>\n",
39
+ " <td>\n",
40
+ " <h2 style=\"color:#00bfff;\">Treat these labs as a resource</h2>\n",
41
+ " <span style=\"color:#00bfff;\">I push updates to the code regularly. When people ask questions or have problems, I incorporate it in the code, adding more examples or improved commentary. As a result, you'll notice that the code below isn't identical to the videos. Everything from the videos is here; but in addition, I've added more steps and better explanations. Consider this like an interactive book that accompanies the lectures.\n",
42
+ " </span>\n",
43
+ " </td>\n",
44
+ " </tr>\n",
45
+ "</table>"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "markdown",
50
+ "metadata": {},
51
+ "source": [
52
+ "### And please do remember to contact me if I can help\n",
53
+ "\n",
54
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
55
+ "\n",
56
+ "\n",
57
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
58
+ "\n",
59
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
60
+ "- Open extensions (View >> extensions)\n",
61
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
62
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
63
+ "Then View >> Explorer to bring back the File Explorer.\n",
64
+ "\n",
65
+ "And then:\n",
66
+ "1. Run `uv add google-genai` to install the Google Gemini library. (If you had started your environment before running this command, you will need to restart your environment in the Jupyter notebook.)\n",
67
+ "2. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
68
+ "3. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
69
+ "4. Enjoy!\n",
70
+ "\n",
71
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
72
+ "1. From the Cursor menu, choose Settings >> VSCode Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
73
+ "2. In the Settings search bar, type \"venv\" \n",
74
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
75
+ "And then try again.\n",
76
+ "\n",
77
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
78
+ "`conda deactivate` \n",
79
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
80
+ "`conda config --set auto_activate_base false` \n",
81
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
82
+ ]
83
+ },
84
+ {
85
+ "cell_type": "code",
86
+ "execution_count": null,
87
+ "metadata": {},
88
+ "outputs": [],
89
+ "source": [
90
+ "from dotenv import load_dotenv\n"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "metadata": {},
97
+ "outputs": [],
98
+ "source": [
99
+ "# Next it's time to load the API keys into environment variables\n",
100
+ "\n",
101
+ "load_dotenv(override=True)"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": null,
107
+ "metadata": {},
108
+ "outputs": [],
109
+ "source": [
110
+ "# Check the keys\n",
111
+ "\n",
112
+ "import os\n",
113
+ "gemini_api_key = os.getenv('GEMINI_API_KEY')\n",
114
+ "\n",
115
+ "if gemini_api_key:\n",
116
+ " print(f\"Gemini API Key exists and begins {gemini_api_key[:8]}\")\n",
117
+ "else:\n",
118
+ " print(\"Gemini API Key not set - please head to the troubleshooting guide in the guides folder\")\n",
119
+ " \n"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": null,
125
+ "metadata": {},
126
+ "outputs": [],
127
+ "source": [
128
+ "# And now - the all important import statement\n",
129
+ "# If you get an import error - head over to troubleshooting guide\n",
130
+ "\n",
131
+ "from google import genai"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type": "code",
136
+ "execution_count": null,
137
+ "metadata": {},
138
+ "outputs": [],
139
+ "source": [
140
+ "# And now we'll create an instance of the Gemini GenAI class\n",
141
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder!\n",
142
+ "# If you get a NameError - head over to the guides folder to learn about NameErrors\n",
143
+ "\n",
144
+ "client = genai.Client(api_key=gemini_api_key)"
145
+ ]
146
+ },
147
+ {
148
+ "cell_type": "code",
149
+ "execution_count": null,
150
+ "metadata": {},
151
+ "outputs": [],
152
+ "source": [
153
+ "# Create a list of messages in the familiar Gemini GenAI format\n",
154
+ "\n",
155
+ "messages = [\"What is 2+2?\"]"
156
+ ]
157
+ },
158
+ {
159
+ "cell_type": "code",
160
+ "execution_count": null,
161
+ "metadata": {},
162
+ "outputs": [],
163
+ "source": [
164
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
165
+ "\n",
166
+ "response = client.models.generate_content(\n",
167
+ " model=\"gemini-2.0-flash\", contents=messages\n",
168
+ ")\n",
169
+ "\n",
170
+ "print(response.text)\n"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "\n",
180
+ "# Lets no create a challenging question\n",
181
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
182
+ "\n",
183
+ "# Ask the the model\n",
184
+ "response = client.models.generate_content(\n",
185
+ " model=\"gemini-2.0-flash\", contents=question\n",
186
+ ")\n",
187
+ "\n",
188
+ "question = response.text\n",
189
+ "\n",
190
+ "print(question)\n"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "metadata": {},
197
+ "outputs": [],
198
+ "source": [
199
+ "# Ask the models generated question to the model\n",
200
+ "response = client.models.generate_content(\n",
201
+ " model=\"gemini-2.0-flash\", contents=question\n",
202
+ ")\n",
203
+ "\n",
204
+ "# Extract the answer from the response\n",
205
+ "answer = response.text\n",
206
+ "\n",
207
+ "# Debug log the answer\n",
208
+ "print(answer)\n"
209
+ ]
210
+ },
211
+ {
212
+ "cell_type": "code",
213
+ "execution_count": null,
214
+ "metadata": {},
215
+ "outputs": [],
216
+ "source": [
217
+ "from IPython.display import Markdown, display\n",
218
+ "\n",
219
+ "# Nicely format the answer using Markdown\n",
220
+ "display(Markdown(answer))\n",
221
+ "\n"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "markdown",
226
+ "metadata": {},
227
+ "source": [
228
+ "# Congratulations!\n",
229
+ "\n",
230
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
231
+ "\n",
232
+ "Next time things get more interesting..."
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "markdown",
237
+ "metadata": {},
238
+ "source": [
239
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
240
+ " <tr>\n",
241
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
242
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
243
+ " </td>\n",
244
+ " <td>\n",
245
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
246
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
247
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
248
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
249
+ " Finally have 3 third LLM call propose the Agentic AI solution.\n",
250
+ " </span>\n",
251
+ " </td>\n",
252
+ " </tr>\n",
253
+ "</table>"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": null,
259
+ "metadata": {},
260
+ "outputs": [],
261
+ "source": [
262
+ "# First create the messages:\n",
263
+ "\n",
264
+ "\n",
265
+ "messages = [\"Something here\"]\n",
266
+ "\n",
267
+ "# Then make the first call:\n",
268
+ "\n",
269
+ "response =\n",
270
+ "\n",
271
+ "# Then read the business idea:\n",
272
+ "\n",
273
+ "business_idea = response.\n",
274
+ "\n",
275
+ "# And repeat!"
276
+ ]
277
+ },
278
+ {
279
+ "cell_type": "markdown",
280
+ "metadata": {},
281
+ "source": []
282
+ }
283
+ ],
284
+ "metadata": {
285
+ "kernelspec": {
286
+ "display_name": ".venv",
287
+ "language": "python",
288
+ "name": "python3"
289
+ },
290
+ "language_info": {
291
+ "codemirror_mode": {
292
+ "name": "ipython",
293
+ "version": 3
294
+ },
295
+ "file_extension": ".py",
296
+ "mimetype": "text/x-python",
297
+ "name": "python",
298
+ "nbconvert_exporter": "python",
299
+ "pygments_lexer": "ipython3",
300
+ "version": "3.12.10"
301
+ }
302
+ },
303
+ "nbformat": 4,
304
+ "nbformat_minor": 2
305
+ }
community_contributions/1_lab1_gemini.ipynb ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
23
+ " Well in that case, you're ready!!\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "markdown",
32
+ "metadata": {},
33
+ "source": [
34
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
35
+ " <tr>\n",
36
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
37
+ " <img src=\"../../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
38
+ " </td>\n",
39
+ " <td>\n",
40
+ " <h2 style=\"color:#00bfff;\">Treat these labs as a resource</h2>\n",
41
+ " <span style=\"color:#00bfff;\">I push updates to the code regularly. When people ask questions or have problems, I incorporate it in the code, adding more examples or improved commentary. As a result, you'll notice that the code below isn't identical to the videos. Everything from the videos is here; but in addition, I've added more steps and better explanations. Consider this like an interactive book that accompanies the lectures.\n",
42
+ " </span>\n",
43
+ " </td>\n",
44
+ " </tr>\n",
45
+ "</table>"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "markdown",
50
+ "metadata": {},
51
+ "source": [
52
+ "### And please do remember to contact me if I can help\n",
53
+ "\n",
54
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
55
+ "\n",
56
+ "\n",
57
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
58
+ "\n",
59
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
60
+ "- Open extensions (View >> extensions)\n",
61
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
62
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
63
+ "Then View >> Explorer to bring back the File Explorer.\n",
64
+ "\n",
65
+ "And then:\n",
66
+ "1. Run `uv add google-genai` to install the Google Gemini library. (If you had started your environment before running this command, you will need to restart your environment in the Jupyter notebook.)\n",
67
+ "2. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
68
+ "3. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
69
+ "4. Enjoy!\n",
70
+ "\n",
71
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
72
+ "1. From the Cursor menu, choose Settings >> VSCode Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
73
+ "2. In the Settings search bar, type \"venv\" \n",
74
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
75
+ "And then try again.\n",
76
+ "\n",
77
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
78
+ "`conda deactivate` \n",
79
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
80
+ "`conda config --set auto_activate_base false` \n",
81
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
82
+ ]
83
+ },
84
+ {
85
+ "cell_type": "code",
86
+ "execution_count": null,
87
+ "metadata": {},
88
+ "outputs": [],
89
+ "source": [
90
+ "from dotenv import load_dotenv\n"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "metadata": {},
97
+ "outputs": [],
98
+ "source": [
99
+ "# Next it's time to load the API keys into environment variables\n",
100
+ "\n",
101
+ "load_dotenv(override=True)"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": null,
107
+ "metadata": {},
108
+ "outputs": [],
109
+ "source": [
110
+ "# Check the keys\n",
111
+ "\n",
112
+ "import os\n",
113
+ "gemini_api_key = os.getenv('GEMINI_API_KEY')\n",
114
+ "\n",
115
+ "if gemini_api_key:\n",
116
+ " print(f\"Gemini API Key exists and begins {gemini_api_key[:8]}\")\n",
117
+ "else:\n",
118
+ " print(\"Gemini API Key not set - please head to the troubleshooting guide in the guides folder\")\n",
119
+ " \n"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": null,
125
+ "metadata": {},
126
+ "outputs": [],
127
+ "source": [
128
+ "# And now - the all important import statement\n",
129
+ "# If you get an import error - head over to troubleshooting guide\n",
130
+ "\n",
131
+ "from google import genai"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type": "code",
136
+ "execution_count": null,
137
+ "metadata": {},
138
+ "outputs": [],
139
+ "source": [
140
+ "# And now we'll create an instance of the Gemini GenAI class\n",
141
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder!\n",
142
+ "# If you get a NameError - head over to the guides folder to learn about NameErrors\n",
143
+ "\n",
144
+ "client = genai.Client(api_key=gemini_api_key)"
145
+ ]
146
+ },
147
+ {
148
+ "cell_type": "code",
149
+ "execution_count": null,
150
+ "metadata": {},
151
+ "outputs": [],
152
+ "source": [
153
+ "# Create a list of messages in the familiar Gemini GenAI format\n",
154
+ "\n",
155
+ "messages = [\"What is 2+2?\"]"
156
+ ]
157
+ },
158
+ {
159
+ "cell_type": "code",
160
+ "execution_count": null,
161
+ "metadata": {},
162
+ "outputs": [],
163
+ "source": [
164
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
165
+ "\n",
166
+ "response = client.models.generate_content(\n",
167
+ " model=\"gemini-2.0-flash\", contents=messages\n",
168
+ ")\n",
169
+ "\n",
170
+ "print(response.text)\n"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "\n",
180
+ "# Lets no create a challenging question\n",
181
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
182
+ "\n",
183
+ "# Ask the the model\n",
184
+ "response = client.models.generate_content(\n",
185
+ " model=\"gemini-2.0-flash\", contents=question\n",
186
+ ")\n",
187
+ "\n",
188
+ "question = response.text\n",
189
+ "\n",
190
+ "print(question)\n"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "metadata": {},
197
+ "outputs": [],
198
+ "source": [
199
+ "# Ask the models generated question to the model\n",
200
+ "response = client.models.generate_content(\n",
201
+ " model=\"gemini-2.0-flash\", contents=question\n",
202
+ ")\n",
203
+ "\n",
204
+ "# Extract the answer from the response\n",
205
+ "answer = response.text\n",
206
+ "\n",
207
+ "# Debug log the answer\n",
208
+ "print(answer)\n"
209
+ ]
210
+ },
211
+ {
212
+ "cell_type": "code",
213
+ "execution_count": null,
214
+ "metadata": {},
215
+ "outputs": [],
216
+ "source": [
217
+ "from IPython.display import Markdown, display\n",
218
+ "\n",
219
+ "# Nicely format the answer using Markdown\n",
220
+ "display(Markdown(answer))\n",
221
+ "\n"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "markdown",
226
+ "metadata": {},
227
+ "source": [
228
+ "# Congratulations!\n",
229
+ "\n",
230
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
231
+ "\n",
232
+ "Next time things get more interesting..."
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "markdown",
237
+ "metadata": {},
238
+ "source": [
239
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
240
+ " <tr>\n",
241
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
242
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
243
+ " </td>\n",
244
+ " <td>\n",
245
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
246
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
247
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
248
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
249
+ " Finally have 3 third LLM call propose the Agentic AI solution.\n",
250
+ " </span>\n",
251
+ " </td>\n",
252
+ " </tr>\n",
253
+ "</table>"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": null,
259
+ "metadata": {},
260
+ "outputs": [],
261
+ "source": [
262
+ "# First create the messages:\n",
263
+ "\n",
264
+ "\n",
265
+ "messages = [\"Something here\"]\n",
266
+ "\n",
267
+ "# Then make the first call:\n",
268
+ "\n",
269
+ "response =\n",
270
+ "\n",
271
+ "# Then read the business idea:\n",
272
+ "\n",
273
+ "business_idea = response.\n",
274
+ "\n",
275
+ "# And repeat!"
276
+ ]
277
+ },
278
+ {
279
+ "cell_type": "markdown",
280
+ "metadata": {},
281
+ "source": []
282
+ }
283
+ ],
284
+ "metadata": {
285
+ "kernelspec": {
286
+ "display_name": ".venv",
287
+ "language": "python",
288
+ "name": "python3"
289
+ },
290
+ "language_info": {
291
+ "codemirror_mode": {
292
+ "name": "ipython",
293
+ "version": 3
294
+ },
295
+ "file_extension": ".py",
296
+ "mimetype": "text/x-python",
297
+ "name": "python",
298
+ "nbconvert_exporter": "python",
299
+ "pygments_lexer": "ipython3",
300
+ "version": "3.12.10"
301
+ }
302
+ },
303
+ "nbformat": 4,
304
+ "nbformat_minor": 2
305
+ }
community_contributions/1_lab1_groq.ipynb ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "### Implementing Notebook 1 using various LLMs via Groq"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "code",
12
+ "execution_count": null,
13
+ "metadata": {},
14
+ "outputs": [],
15
+ "source": [
16
+ "from dotenv import load_dotenv"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": null,
22
+ "metadata": {},
23
+ "outputs": [],
24
+ "source": [
25
+ "load_dotenv(override=True)"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "code",
30
+ "execution_count": null,
31
+ "metadata": {},
32
+ "outputs": [],
33
+ "source": [
34
+ "import os\n",
35
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
36
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
37
+ "\n",
38
+ "if openai_api_key:\n",
39
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
40
+ "else:\n",
41
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
42
+ "\n",
43
+ "if groq_api_key:\n",
44
+ " print(f\"Groq API Key exists and begins {groq_api_key[:2]}\")\n",
45
+ "else:\n",
46
+ " print(\"Groq API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
47
+ " \n"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "code",
52
+ "execution_count": null,
53
+ "metadata": {},
54
+ "outputs": [],
55
+ "source": [
56
+ "from openai import OpenAI"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "code",
61
+ "execution_count": null,
62
+ "metadata": {},
63
+ "outputs": [],
64
+ "source": [
65
+ "openai = OpenAI(\n",
66
+ " base_url=\"https://api.groq.com/openai/v1\",\n",
67
+ " api_key=groq_api_key\n",
68
+ ")"
69
+ ]
70
+ },
71
+ {
72
+ "cell_type": "code",
73
+ "execution_count": null,
74
+ "metadata": {},
75
+ "outputs": [],
76
+ "source": [
77
+ "# And now - let's ask for a question:\n",
78
+ "\n",
79
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
80
+ "messages = [{\"role\": \"user\", \"content\": question}]"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "code",
85
+ "execution_count": null,
86
+ "metadata": {},
87
+ "outputs": [],
88
+ "source": [
89
+ "# openai/gpt-oss-120b\n",
90
+ "\n",
91
+ "response = openai.chat.completions.create(\n",
92
+ " model=\"openai/gpt-oss-120b\",\n",
93
+ " messages=messages\n",
94
+ ")\n",
95
+ "\n",
96
+ "print(response.choices[0].message.content)\n",
97
+ "\n"
98
+ ]
99
+ },
100
+ {
101
+ "cell_type": "code",
102
+ "execution_count": null,
103
+ "metadata": {},
104
+ "outputs": [],
105
+ "source": [
106
+ "# moonshotai/kimi-k2-instruct\n",
107
+ "\n",
108
+ "response = openai.chat.completions.create(\n",
109
+ " model=\"moonshotai/kimi-k2-instruct\",\n",
110
+ " messages=messages\n",
111
+ ")\n",
112
+ "\n",
113
+ "question = response.choices[0].message.content\n",
114
+ "\n",
115
+ "print(question)\n"
116
+ ]
117
+ },
118
+ {
119
+ "cell_type": "code",
120
+ "execution_count": null,
121
+ "metadata": {},
122
+ "outputs": [],
123
+ "source": [
124
+ "# form a new messages list\n",
125
+ "messages = [{\"role\": \"user\", \"content\": question}]"
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "# Ask meta-llama/llama-guard-4-12b\n",
135
+ "\n",
136
+ "response = openai.chat.completions.create(\n",
137
+ " model=\"llama-3.1-8b-instant\",\n",
138
+ " messages=messages\n",
139
+ ")\n",
140
+ "\n",
141
+ "answer = response.choices[0].message.content\n",
142
+ "print(answer)\n"
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "code",
147
+ "execution_count": null,
148
+ "metadata": {},
149
+ "outputs": [],
150
+ "source": [
151
+ "from IPython.display import Markdown, display\n",
152
+ "\n",
153
+ "display(Markdown(question))\n",
154
+ "display(Markdown(answer))"
155
+ ]
156
+ },
157
+ {
158
+ "cell_type": "markdown",
159
+ "metadata": {},
160
+ "source": [
161
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
162
+ " <tr>\n",
163
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
164
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
165
+ " </td>\n",
166
+ " <td>\n",
167
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
168
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
169
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
170
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
171
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
172
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
173
+ " </span>\n",
174
+ " </td>\n",
175
+ " </tr>\n",
176
+ "</table>"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": null,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "# First create the messages:\n",
186
+ "\n",
187
+ "messages = [{\"role\": \"user\", \"content\": \"Pick a business area that is worth exploring for a Gen-Z audience, that can be an agentic-ai opportunity. \\\n",
188
+ " Somehwere where the concept of agentisation can be applied commerically. Respond only with the business idea.\"}]\n",
189
+ "\n",
190
+ "# Then make the first call: \n",
191
+ "\n",
192
+ "response = openai.chat.completions.create(\n",
193
+ " model = \"qwen/qwen3-32b\",\n",
194
+ " messages = messages\n",
195
+ ")\n",
196
+ "\n",
197
+ "# Then read the business idea:\n",
198
+ "\n",
199
+ "business_idea = response.choices[0].message.content\n",
200
+ "print(business_idea)\n",
201
+ "\n",
202
+ "# And repeat! In the next message, include the business idea within the message\n",
203
+ "\n",
204
+ "user_prompt_pain_point = f\"What is the pain point of the Gen-Z audience in the business area of {business_idea}?, that can be solved by an agentic-ai solution? Give a brief answer\"\n",
205
+ "\n",
206
+ "response = openai.chat.completions.create(\n",
207
+ " model = \"gemma2-9b-it\",\n",
208
+ " messages = [{\"role\": \"user\", \"content\": user_prompt_pain_point}]\n",
209
+ ")\n",
210
+ "\n",
211
+ "pain_point = response.choices[0].message.content\n",
212
+ "print(pain_point)\n",
213
+ "\n",
214
+ "user_prompt_solution = f\"What is the solution to the pain point {pain_point} of the Gen-Z audience in the business area of {business_idea}?, that can be solved by an agentic-ai solution? Provide a step-by-step breakdown\"\n",
215
+ "\n",
216
+ "response = openai.chat.completions.create(\n",
217
+ " model = \"deepseek-r1-distill-llama-70b\",\n",
218
+ " messages = [{\"role\": \"user\", \"content\": user_prompt_solution}]\n",
219
+ ")\n",
220
+ "\n",
221
+ "business_solution = response.choices[0].message.content"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": null,
227
+ "metadata": {},
228
+ "outputs": [],
229
+ "source": [
230
+ "display(Markdown(business_solution))"
231
+ ]
232
+ },
233
+ {
234
+ "cell_type": "code",
235
+ "execution_count": null,
236
+ "metadata": {},
237
+ "outputs": [],
238
+ "source": []
239
+ }
240
+ ],
241
+ "metadata": {
242
+ "kernelspec": {
243
+ "display_name": ".venv",
244
+ "language": "python",
245
+ "name": "python3"
246
+ },
247
+ "language_info": {
248
+ "codemirror_mode": {
249
+ "name": "ipython",
250
+ "version": 3
251
+ },
252
+ "file_extension": ".py",
253
+ "mimetype": "text/x-python",
254
+ "name": "python",
255
+ "nbconvert_exporter": "python",
256
+ "pygments_lexer": "ipython3",
257
+ "version": "3.12.2"
258
+ }
259
+ },
260
+ "nbformat": 4,
261
+ "nbformat_minor": 2
262
+ }
community_contributions/1_lab1_groq_llama.ipynb ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# First Agentic AI workflow with Groq and Llama-3.3 LLM(Free of cost) "
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "code",
12
+ "execution_count": 1,
13
+ "metadata": {},
14
+ "outputs": [],
15
+ "source": [
16
+ "# First let's do an import\n",
17
+ "from dotenv import load_dotenv"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": null,
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "# Next it's time to load the API keys into environment variables\n",
27
+ "\n",
28
+ "load_dotenv(override=True)"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": null,
34
+ "metadata": {},
35
+ "outputs": [],
36
+ "source": [
37
+ "# Check the Groq API key\n",
38
+ "\n",
39
+ "import os\n",
40
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
41
+ "\n",
42
+ "if groq_api_key:\n",
43
+ " print(f\"GROQ API Key exists and begins {groq_api_key[:8]}\")\n",
44
+ "else:\n",
45
+ " print(\"GROQ API Key not set\")\n",
46
+ " \n"
47
+ ]
48
+ },
49
+ {
50
+ "cell_type": "code",
51
+ "execution_count": 4,
52
+ "metadata": {},
53
+ "outputs": [],
54
+ "source": [
55
+ "# And now - the all important import statement\n",
56
+ "# If you get an import error - head over to troubleshooting guide\n",
57
+ "\n",
58
+ "from groq import Groq"
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "code",
63
+ "execution_count": 5,
64
+ "metadata": {},
65
+ "outputs": [],
66
+ "source": [
67
+ "# Create a Groq instance\n",
68
+ "groq = Groq()"
69
+ ]
70
+ },
71
+ {
72
+ "cell_type": "code",
73
+ "execution_count": 6,
74
+ "metadata": {},
75
+ "outputs": [],
76
+ "source": [
77
+ "# Create a list of messages in the familiar Groq format\n",
78
+ "\n",
79
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
80
+ ]
81
+ },
82
+ {
83
+ "cell_type": "code",
84
+ "execution_count": null,
85
+ "metadata": {},
86
+ "outputs": [],
87
+ "source": [
88
+ "# And now call it!\n",
89
+ "\n",
90
+ "response = groq.chat.completions.create(model='llama-3.3-70b-versatile', messages=messages)\n",
91
+ "print(response.choices[0].message.content)\n"
92
+ ]
93
+ },
94
+ {
95
+ "cell_type": "code",
96
+ "execution_count": null,
97
+ "metadata": {},
98
+ "outputs": [],
99
+ "source": []
100
+ },
101
+ {
102
+ "cell_type": "code",
103
+ "execution_count": 8,
104
+ "metadata": {},
105
+ "outputs": [],
106
+ "source": [
107
+ "# And now - let's ask for a question:\n",
108
+ "\n",
109
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
110
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
111
+ ]
112
+ },
113
+ {
114
+ "cell_type": "code",
115
+ "execution_count": null,
116
+ "metadata": {},
117
+ "outputs": [],
118
+ "source": [
119
+ "# ask it\n",
120
+ "response = groq.chat.completions.create(\n",
121
+ " model=\"llama-3.3-70b-versatile\",\n",
122
+ " messages=messages\n",
123
+ ")\n",
124
+ "\n",
125
+ "question = response.choices[0].message.content\n",
126
+ "\n",
127
+ "print(question)\n"
128
+ ]
129
+ },
130
+ {
131
+ "cell_type": "code",
132
+ "execution_count": 10,
133
+ "metadata": {},
134
+ "outputs": [],
135
+ "source": [
136
+ "# form a new messages list\n",
137
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "code",
142
+ "execution_count": null,
143
+ "metadata": {},
144
+ "outputs": [],
145
+ "source": [
146
+ "# Ask it again\n",
147
+ "\n",
148
+ "response = groq.chat.completions.create(\n",
149
+ " model=\"llama-3.3-70b-versatile\",\n",
150
+ " messages=messages\n",
151
+ ")\n",
152
+ "\n",
153
+ "answer = response.choices[0].message.content\n",
154
+ "print(answer)\n"
155
+ ]
156
+ },
157
+ {
158
+ "cell_type": "code",
159
+ "execution_count": null,
160
+ "metadata": {},
161
+ "outputs": [],
162
+ "source": [
163
+ "from IPython.display import Markdown, display\n",
164
+ "\n",
165
+ "display(Markdown(answer))\n",
166
+ "\n"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "markdown",
171
+ "metadata": {},
172
+ "source": [
173
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
174
+ " <tr>\n",
175
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
176
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
177
+ " </td>\n",
178
+ " <td>\n",
179
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
180
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
181
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
182
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
183
+ " Finally have 3 third LLM call propose the Agentic AI solution.\n",
184
+ " </span>\n",
185
+ " </td>\n",
186
+ " </tr>\n",
187
+ "</table>"
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": 17,
193
+ "metadata": {},
194
+ "outputs": [],
195
+ "source": [
196
+ "# First create the messages:\n",
197
+ "\n",
198
+ "messages = [{\"role\": \"user\", \"content\": \"Give me a business area that might be ripe for an Agentic AI solution.\"}]\n",
199
+ "\n",
200
+ "# Then make the first call:\n",
201
+ "\n",
202
+ "response = groq.chat.completions.create(model='llama-3.3-70b-versatile', messages=messages)\n",
203
+ "\n",
204
+ "# Then read the business idea:\n",
205
+ "\n",
206
+ "business_idea = response.choices[0].message.content\n",
207
+ "\n",
208
+ "\n",
209
+ "# And repeat!"
210
+ ]
211
+ },
212
+ {
213
+ "cell_type": "code",
214
+ "execution_count": null,
215
+ "metadata": {},
216
+ "outputs": [],
217
+ "source": [
218
+ "\n",
219
+ "display(Markdown(business_idea))"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": 19,
225
+ "metadata": {},
226
+ "outputs": [],
227
+ "source": [
228
+ "# Update the message with the business idea from previous step\n",
229
+ "messages = [{\"role\": \"user\", \"content\": \"What is the pain point in the business area of \" + business_idea + \"?\"}]"
230
+ ]
231
+ },
232
+ {
233
+ "cell_type": "code",
234
+ "execution_count": 20,
235
+ "metadata": {},
236
+ "outputs": [],
237
+ "source": [
238
+ "# Make the second call\n",
239
+ "response = groq.chat.completions.create(model='llama-3.3-70b-versatile', messages=messages)\n",
240
+ "# Read the pain point\n",
241
+ "pain_point = response.choices[0].message.content\n"
242
+ ]
243
+ },
244
+ {
245
+ "cell_type": "code",
246
+ "execution_count": null,
247
+ "metadata": {},
248
+ "outputs": [],
249
+ "source": [
250
+ "display(Markdown(pain_point))\n"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": null,
256
+ "metadata": {},
257
+ "outputs": [],
258
+ "source": [
259
+ "# Make the third call\n",
260
+ "messages = [{\"role\": \"user\", \"content\": \"What is the Agentic AI solution for the pain point of \" + pain_point + \"?\"}]\n",
261
+ "response = groq.chat.completions.create(model='llama-3.3-70b-versatile', messages=messages)\n",
262
+ "# Read the agentic solution\n",
263
+ "agentic_solution = response.choices[0].message.content\n",
264
+ "display(Markdown(agentic_solution))"
265
+ ]
266
+ },
267
+ {
268
+ "cell_type": "code",
269
+ "execution_count": null,
270
+ "metadata": {},
271
+ "outputs": [],
272
+ "source": []
273
+ }
274
+ ],
275
+ "metadata": {
276
+ "kernelspec": {
277
+ "display_name": ".venv",
278
+ "language": "python",
279
+ "name": "python3"
280
+ },
281
+ "language_info": {
282
+ "codemirror_mode": {
283
+ "name": "ipython",
284
+ "version": 3
285
+ },
286
+ "file_extension": ".py",
287
+ "mimetype": "text/x-python",
288
+ "name": "python",
289
+ "nbconvert_exporter": "python",
290
+ "pygments_lexer": "ipython3",
291
+ "version": "3.12.10"
292
+ }
293
+ },
294
+ "nbformat": 4,
295
+ "nbformat_minor": 2
296
+ }
community_contributions/1_lab1_marstipton_mac.ipynb ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": 12,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": 15,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": 16,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": 17,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-mini\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": 8,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": 10,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# Step 1: Define the conversation\n",
326
+ "messages = [\n",
327
+ " {\"role\": \"system\", \"content\": \"You are an expert in agentic AI business ideation.\"}\n",
328
+ "]\n",
329
+ "\n",
330
+ "# Step 2: Ask the first question\n",
331
+ "area_prompt = (\n",
332
+ " \"Pick a business area within Singapore startups as of Q4 2025 \"\n",
333
+ " \"that might be worth exploring for an Agentic AI opportunity. \"\n",
334
+ " \"Explain in simple language (for a 15-year-old) and cite resources briefly.\"\n",
335
+ ")\n",
336
+ "messages.append({\"role\": \"user\", \"content\": area_prompt})\n",
337
+ "\n",
338
+ "response = openai.chat.completions.create(\n",
339
+ " model=\"gpt-4.1-mini\",\n",
340
+ " messages=messages\n",
341
+ ")\n",
342
+ "area = response.choices[0].message.content\n",
343
+ "display(Markdown(area))\n",
344
+ "\n",
345
+ "# Add model response to context\n",
346
+ "messages.append({\"role\": \"assistant\", \"content\": area})\n",
347
+ "\n",
348
+ "# Step 3: Ask for a pain point\n",
349
+ "painpoint_prompt = (\n",
350
+ " \"Based on your previous response, pick a recurring pain point in that area \"\n",
351
+ " \"that is ripe for an Agentic AI solution.\"\n",
352
+ ")\n",
353
+ "messages.append({\"role\": \"user\", \"content\": painpoint_prompt})\n",
354
+ "\n",
355
+ "response = openai.chat.completions.create(\n",
356
+ " model=\"gpt-4.1-mini\",\n",
357
+ " messages=messages\n",
358
+ ")\n",
359
+ "painpoint = response.choices[0].message.content\n",
360
+ "display(Markdown(painpoint))\n",
361
+ "\n",
362
+ "# Add model response to context\n",
363
+ "messages.append({\"role\": \"assistant\", \"content\": painpoint})\n",
364
+ "\n",
365
+ "# Step 4: Propose a business idea\n",
366
+ "business_idea_prompt = (\n",
367
+ " \"Propose an Agentic AI solution addressing the pain point above. \"\n",
368
+ " \"Solution should have low overhead, be secure, and offer 80% free functionality, \"\n",
369
+ " \"with full access for SGD 0.99/month per user or SGD 15/org (max 30 users).\"\n",
370
+ ")\n",
371
+ "messages.append({\"role\": \"user\", \"content\": business_idea_prompt})\n",
372
+ "\n",
373
+ "response = openai.chat.completions.create(\n",
374
+ " model=\"gpt-4.1-mini\",\n",
375
+ " messages=messages\n",
376
+ ")\n",
377
+ "business_idea = response.choices[0].message.content\n",
378
+ "display(Markdown(business_idea))\n",
379
+ "\n",
380
+ "# Add to conversation (for future iterations)\n",
381
+ "#messages.append({\"role\": \"assistant\", \"content\": business_idea})"
382
+ ]
383
+ },
384
+ {
385
+ "cell_type": "markdown",
386
+ "metadata": {},
387
+ "source": []
388
+ }
389
+ ],
390
+ "metadata": {
391
+ "kernelspec": {
392
+ "display_name": ".venv",
393
+ "language": "python",
394
+ "name": "python3"
395
+ },
396
+ "language_info": {
397
+ "codemirror_mode": {
398
+ "name": "ipython",
399
+ "version": 3
400
+ },
401
+ "file_extension": ".py",
402
+ "mimetype": "text/x-python",
403
+ "name": "python",
404
+ "nbconvert_exporter": "python",
405
+ "pygments_lexer": "ipython3",
406
+ "version": "3.12.12"
407
+ }
408
+ },
409
+ "nbformat": 4,
410
+ "nbformat_minor": 2
411
+ }
community_contributions/1_lab1_moneek.ipynb ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-nano\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": null,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# First create the messages:\n",
326
+ "question = \"Pick a business area that may have agentic AI opportunities\"\n",
327
+ "messages = [{\"role\": \"user\", \"content\": question}]\n",
328
+ "\n",
329
+ "# Then make the first call:\n",
330
+ "\n",
331
+ "response = openai.chat.completions.create(\n",
332
+ " model=\"gpt-4.1-mini\",\n",
333
+ " messages=messages\n",
334
+ ")\n",
335
+ "\n",
336
+ "# Then read the business idea:\n",
337
+ "\n",
338
+ "business_idea = response.choices[0].message.content\n",
339
+ "print(business_idea)\n",
340
+ "\n",
341
+ "# And repeat! In the next message, include the business idea within the message"
342
+ ]
343
+ },
344
+ {
345
+ "cell_type": "code",
346
+ "execution_count": null,
347
+ "metadata": {},
348
+ "outputs": [],
349
+ "source": [
350
+ "messages = [{\"role\": \"user\", \"content\": question + \"\\n\\n\" + business_idea},\n",
351
+ " {\"role\": \"assistant\", \"content\": \"What is the pain point in this industry?\" }]\n",
352
+ "\n",
353
+ "response = openai.chat.completions.create(\n",
354
+ " model=\"gpt-4.1-mini\",\n",
355
+ " messages=messages\n",
356
+ ")\n",
357
+ "\n",
358
+ "pain_point = response.choices[0].message.content\n",
359
+ "print(pain_point)"
360
+ ]
361
+ },
362
+ {
363
+ "cell_type": "code",
364
+ "execution_count": null,
365
+ "metadata": {},
366
+ "outputs": [],
367
+ "source": [
368
+ "messages = [{\"role\": \"user\", \"content\": question + \"\\n\\n\" + business_idea + \"\\n\\n\" + pain_point}, \n",
369
+ " {\"role\": \"assistant\", \"content\": \"What is the Agentic AI solution?\"}]\n",
370
+ "\n",
371
+ "response = openai.chat.completions.create(\n",
372
+ " model=\"gpt-4.1-mini\",\n",
373
+ " messages=messages\n",
374
+ ")\n",
375
+ "\n",
376
+ "agentic_solution = response.choices[0].message.content\n",
377
+ "print(agentic_solution)\n"
378
+ ]
379
+ },
380
+ {
381
+ "cell_type": "markdown",
382
+ "metadata": {},
383
+ "source": []
384
+ }
385
+ ],
386
+ "metadata": {
387
+ "kernelspec": {
388
+ "display_name": ".venv",
389
+ "language": "python",
390
+ "name": "python3"
391
+ },
392
+ "language_info": {
393
+ "codemirror_mode": {
394
+ "name": "ipython",
395
+ "version": 3
396
+ },
397
+ "file_extension": ".py",
398
+ "mimetype": "text/x-python",
399
+ "name": "python",
400
+ "nbconvert_exporter": "python",
401
+ "pygments_lexer": "ipython3",
402
+ "version": "3.12.11"
403
+ }
404
+ },
405
+ "nbformat": 4,
406
+ "nbformat_minor": 2
407
+ }
community_contributions/1_lab1_nv-ex.ipynb ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-nano\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": null,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# First create the messages:\n",
326
+ "\n",
327
+ "messages = [{\"role\": \"user\", \"content\": \"Pick up a business area where Agentic AI can be applied. Provide only the business area name.\"}]\n",
328
+ "\n",
329
+ "# Then make the first call:\n",
330
+ "\n",
331
+ "response = openai.chat.completions.create(\n",
332
+ " model=\"gpt-4.1-mini\",\n",
333
+ " messages=messages\n",
334
+ ")\n",
335
+ "\n",
336
+ "# Then read the business idea:\n",
337
+ "\n",
338
+ "business_idea = response.choices[0].message.content\n",
339
+ "display(Markdown(business_idea))\n",
340
+ "\n",
341
+ "# And repeat! In the next message, include the business idea within the message\n"
342
+ ]
343
+ },
344
+ {
345
+ "cell_type": "code",
346
+ "execution_count": null,
347
+ "metadata": {},
348
+ "outputs": [],
349
+ "source": [
350
+ "# First create the messages:\n",
351
+ "\n",
352
+ "messages = [{\"role\": \"user\", \"content\": f\"Provide one painpoint in the business ${business_idea} that can be solved by Agentic AI. Provide only the pain point, nothing else.\"}]\n",
353
+ "\n",
354
+ "# Then make the first call:\n",
355
+ "\n",
356
+ "response = openai.chat.completions.create(\n",
357
+ " model=\"gpt-4.1-mini\",\n",
358
+ " messages=messages\n",
359
+ ")\n",
360
+ "\n",
361
+ "# Then read the business idea:\n",
362
+ "\n",
363
+ "pain_point = response.choices[0].message.content\n",
364
+ "display(Markdown(pain_point))\n"
365
+ ]
366
+ },
367
+ {
368
+ "cell_type": "code",
369
+ "execution_count": null,
370
+ "metadata": {},
371
+ "outputs": [],
372
+ "source": [
373
+ "# First create the messages:\n",
374
+ "\n",
375
+ "messages = [{\"role\": \"user\", \"content\": f\"Provide one solution that uses Agentic AI to solve the pain point ${pain_point}, in the business ${business_idea}. \\\n",
376
+ " Provide details as bullet points in less than 100 words. Precede it with the Business Area and the pain point it is solving.\"}]\n",
377
+ "\n",
378
+ "# Then make the first call:\n",
379
+ "\n",
380
+ "response = openai.chat.completions.create(\n",
381
+ " model=\"gpt-4.1-mini\",\n",
382
+ " messages=messages\n",
383
+ ")\n",
384
+ "\n",
385
+ "# Then read the business idea:\n",
386
+ "\n",
387
+ "solution = response.choices[0].message.content\n",
388
+ "display(Markdown(solution))\n"
389
+ ]
390
+ },
391
+ {
392
+ "cell_type": "markdown",
393
+ "metadata": {},
394
+ "source": []
395
+ }
396
+ ],
397
+ "metadata": {
398
+ "kernelspec": {
399
+ "display_name": ".venv",
400
+ "language": "python",
401
+ "name": "python3"
402
+ },
403
+ "language_info": {
404
+ "codemirror_mode": {
405
+ "name": "ipython",
406
+ "version": 3
407
+ },
408
+ "file_extension": ".py",
409
+ "mimetype": "text/x-python",
410
+ "name": "python",
411
+ "nbconvert_exporter": "python",
412
+ "pygments_lexer": "ipython3",
413
+ "version": "3.12.4"
414
+ }
415
+ },
416
+ "nbformat": 4,
417
+ "nbformat_minor": 2
418
+ }
community_contributions/1_lab1_open_router.ipynb ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
23
+ " Well in that case, you're ready!!\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "markdown",
32
+ "metadata": {},
33
+ "source": [
34
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
35
+ " <tr>\n",
36
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
37
+ " <img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
38
+ " </td>\n",
39
+ " <td>\n",
40
+ " <h2 style=\"color:#00bfff;\">This code is a live resource - keep an eye out for my updates</h2>\n",
41
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
42
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
43
+ " </span>\n",
44
+ " </td>\n",
45
+ " </tr>\n",
46
+ "</table>"
47
+ ]
48
+ },
49
+ {
50
+ "cell_type": "markdown",
51
+ "metadata": {},
52
+ "source": [
53
+ "### And please do remember to contact me if I can help\n",
54
+ "\n",
55
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
56
+ "\n",
57
+ "\n",
58
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
59
+ "\n",
60
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
61
+ "- Open extensions (View >> extensions)\n",
62
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
63
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
64
+ "Then View >> Explorer to bring back the File Explorer.\n",
65
+ "\n",
66
+ "And then:\n",
67
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
68
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
69
+ "3. Enjoy!\n",
70
+ "\n",
71
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
72
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
73
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
74
+ "2. In the Settings search bar, type \"venv\" \n",
75
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
76
+ "And then try again.\n",
77
+ "\n",
78
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
79
+ "`conda deactivate` \n",
80
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
81
+ "`conda config --set auto_activate_base false` \n",
82
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
83
+ ]
84
+ },
85
+ {
86
+ "cell_type": "code",
87
+ "execution_count": 76,
88
+ "metadata": {},
89
+ "outputs": [],
90
+ "source": [
91
+ "# First let's do an import\n",
92
+ "from dotenv import load_dotenv\n"
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "metadata": {},
99
+ "outputs": [],
100
+ "source": [
101
+ "# Next it's time to load the API keys into environment variables\n",
102
+ "\n",
103
+ "load_dotenv(override=True)"
104
+ ]
105
+ },
106
+ {
107
+ "cell_type": "code",
108
+ "execution_count": null,
109
+ "metadata": {},
110
+ "outputs": [],
111
+ "source": [
112
+ "# Check the keys\n",
113
+ "\n",
114
+ "import os\n",
115
+ "open_router_api_key = os.getenv('OPEN_ROUTER_API_KEY')\n",
116
+ "\n",
117
+ "if open_router_api_key:\n",
118
+ " print(f\"Open router API Key exists and begins {open_router_api_key[:8]}\")\n",
119
+ "else:\n",
120
+ " print(\"Open router API Key not set - please head to the troubleshooting guide in the setup folder\")\n"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "code",
125
+ "execution_count": 79,
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "from openai import OpenAI"
130
+ ]
131
+ },
132
+ {
133
+ "cell_type": "code",
134
+ "execution_count": 80,
135
+ "metadata": {},
136
+ "outputs": [],
137
+ "source": [
138
+ "# Initialize the client to point at OpenRouter instead of OpenAI\n",
139
+ "# You can use the exact same OpenAI Python package—just swap the base_url!\n",
140
+ "client = OpenAI(\n",
141
+ " base_url=\"https://openrouter.ai/api/v1\",\n",
142
+ " api_key=open_router_api_key\n",
143
+ ")"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 81,
149
+ "metadata": {},
150
+ "outputs": [],
151
+ "source": [
152
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "code",
157
+ "execution_count": null,
158
+ "metadata": {},
159
+ "outputs": [],
160
+ "source": [
161
+ "client = OpenAI(\n",
162
+ " base_url=\"https://openrouter.ai/api/v1\",\n",
163
+ " api_key=open_router_api_key\n",
164
+ ")\n",
165
+ "\n",
166
+ "resp = client.chat.completions.create(\n",
167
+ " # Select a model from https://openrouter.ai/models and provide the model name here\n",
168
+ " model=\"meta-llama/llama-3.3-8b-instruct:free\",\n",
169
+ " messages=messages\n",
170
+ ")\n",
171
+ "print(resp.choices[0].message.content)"
172
+ ]
173
+ },
174
+ {
175
+ "cell_type": "code",
176
+ "execution_count": 83,
177
+ "metadata": {},
178
+ "outputs": [],
179
+ "source": [
180
+ "# And now - let's ask for a question:\n",
181
+ "\n",
182
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
183
+ "messages = [{\"role\": \"user\", \"content\": question}]"
184
+ ]
185
+ },
186
+ {
187
+ "cell_type": "code",
188
+ "execution_count": null,
189
+ "metadata": {},
190
+ "outputs": [],
191
+ "source": [
192
+ "response = client.chat.completions.create(\n",
193
+ " model=\"meta-llama/llama-3.3-8b-instruct:free\",\n",
194
+ " messages=messages\n",
195
+ ")\n",
196
+ "\n",
197
+ "question = response.choices[0].message.content\n",
198
+ "\n",
199
+ "print(question)"
200
+ ]
201
+ },
202
+ {
203
+ "cell_type": "code",
204
+ "execution_count": 85,
205
+ "metadata": {},
206
+ "outputs": [],
207
+ "source": [
208
+ "# form a new messages list\n",
209
+ "\n",
210
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "code",
215
+ "execution_count": null,
216
+ "metadata": {},
217
+ "outputs": [],
218
+ "source": [
219
+ "# Ask it again\n",
220
+ "\n",
221
+ "response = client.chat.completions.create(\n",
222
+ " model=\"meta-llama/llama-3.3-8b-instruct:free\",\n",
223
+ " messages=messages\n",
224
+ ")\n",
225
+ "\n",
226
+ "answer = response.choices[0].message.content\n",
227
+ "print(answer)"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": null,
233
+ "metadata": {},
234
+ "outputs": [],
235
+ "source": [
236
+ "from IPython.display import Markdown, display\n",
237
+ "\n",
238
+ "display(Markdown(answer))\n",
239
+ "\n"
240
+ ]
241
+ },
242
+ {
243
+ "cell_type": "markdown",
244
+ "metadata": {},
245
+ "source": [
246
+ "# Congratulations!\n",
247
+ "\n",
248
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
249
+ "\n",
250
+ "Next time things get more interesting..."
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "markdown",
255
+ "metadata": {},
256
+ "source": [
257
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
258
+ " <tr>\n",
259
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
260
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
261
+ " </td>\n",
262
+ " <td>\n",
263
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
264
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
265
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
266
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
267
+ " Finally have 3 third LLM call propose the Agentic AI solution.\n",
268
+ " </span>\n",
269
+ " </td>\n",
270
+ " </tr>\n",
271
+ "</table>"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "# First create the messages:\n",
281
+ "\n",
282
+ "\n",
283
+ "messages = [\"Something here\"]\n",
284
+ "\n",
285
+ "# Then make the first call:\n",
286
+ "\n",
287
+ "response =\n",
288
+ "\n",
289
+ "# Then read the business idea:\n",
290
+ "\n",
291
+ "business_idea = response.\n",
292
+ "\n",
293
+ "# And repeat!"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type": "markdown",
298
+ "metadata": {},
299
+ "source": []
300
+ }
301
+ ],
302
+ "metadata": {
303
+ "kernelspec": {
304
+ "display_name": ".venv",
305
+ "language": "python",
306
+ "name": "python3"
307
+ },
308
+ "language_info": {
309
+ "codemirror_mode": {
310
+ "name": "ipython",
311
+ "version": 3
312
+ },
313
+ "file_extension": ".py",
314
+ "mimetype": "text/x-python",
315
+ "name": "python",
316
+ "nbconvert_exporter": "python",
317
+ "pygments_lexer": "ipython3",
318
+ "version": "3.12.7"
319
+ }
320
+ },
321
+ "nbformat": 4,
322
+ "nbformat_minor": 2
323
+ }
community_contributions/1_lab1_romanc.ipynb ADDED
@@ -0,0 +1,410 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Welcome to the start of your adventure in 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;\">Are you ready for action??</h2>\n",
21
+ " <span style=\"color:#ff7800;\">Have you completed all the setup steps in the <a href=\"../setup/\">setup</a> folder?<br/>\n",
22
+ " Have you read the <a href=\"../README.md\">README</a>? Many common questions are answered here!<br/>\n",
23
+ " Have you checked out the guides in the <a href=\"../guides/01_intro.ipynb\">guides</a> folder?<br/>\n",
24
+ " Well in that case, you're ready!!\n",
25
+ " </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;\">This code is a live resource - keep an eye out for my updates</h2>\n",
42
+ " <span style=\"color:#00bfff;\">I push updates regularly. As people ask questions or have problems, I add more examples and improve explanations. As a result, the code below might not be identical to the videos, as I've added more steps and better comments. Consider this like an interactive book that accompanies the lectures.<br/><br/>\n",
43
+ " I try to send emails regularly with important updates related to the course. You can find this in the 'Announcements' section of Udemy in the left sidebar. You can also choose to receive my emails via your Notification Settings in Udemy. I'm respectful of your inbox and always try to add value with my emails!\n",
44
+ " </span>\n",
45
+ " </td>\n",
46
+ " </tr>\n",
47
+ "</table>"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "### And please do remember to contact me if I can help\n",
55
+ "\n",
56
+ "And I love to connect: https://www.linkedin.com/in/eddonner/\n",
57
+ "\n",
58
+ "\n",
59
+ "### New to Notebooks like this one? Head over to the guides folder!\n",
60
+ "\n",
61
+ "Just to check you've already added the Python and Jupyter extensions to Cursor, if not already installed:\n",
62
+ "- Open extensions (View >> extensions)\n",
63
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
64
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
65
+ "Then View >> Explorer to bring back the File Explorer.\n",
66
+ "\n",
67
+ "And then:\n",
68
+ "1. Click where it says \"Select Kernel\" near the top right, and select the option called `.venv (Python 3.12.9)` or similar, which should be the first choice or the most prominent choice. You may need to choose \"Python Environments\" first.\n",
69
+ "2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
70
+ "3. Enjoy!\n",
71
+ "\n",
72
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.9)` then please do the following: \n",
73
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
74
+ "On Windows PC: From the File menu, choose Preferences >> VS Code Settings(NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
75
+ "2. In the Settings search bar, type \"venv\" \n",
76
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\agents (on a Windows PC) or /Users/username/projects/agents (on Mac or Linux). \n",
77
+ "And then try again.\n",
78
+ "\n",
79
+ "Having problems with missing Python versions in that list? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
80
+ "`conda deactivate` \n",
81
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
82
+ "`conda config --set auto_activate_base false` \n",
83
+ "and then from within the Agents directory, you should be able to run `uv python list` and see the Python 3.12 version."
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "# First let's do an import. If you get an Import Error, double check that your Kernel is correct..\n",
93
+ "\n",
94
+ "from dotenv import load_dotenv\n"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Next it's time to load the API keys into environment variables\n",
104
+ "# If this returns false, see the next cell!\n",
105
+ "\n",
106
+ "load_dotenv(override=True)"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "### Wait, did that just output `False`??\n",
114
+ "\n",
115
+ "If so, the most common reason is that you didn't save your `.env` file after adding the key! Be sure to have saved.\n",
116
+ "\n",
117
+ "Also, make sure the `.env` file is named precisely `.env` and is in the project root directory (`agents`)\n",
118
+ "\n",
119
+ "By the way, your `.env` file should have a stop symbol next to it in Cursor on the left, and that's actually a good thing: that's Cursor saying to you, \"hey, I realize this is a file filled with secret information, and I'm not going to send it to an external AI to suggest changes, because your keys should not be shown to anyone else.\""
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
127
+ " <tr>\n",
128
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
129
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
130
+ " </td>\n",
131
+ " <td>\n",
132
+ " <h2 style=\"color:#ff7800;\">Final reminders</h2>\n",
133
+ " <span style=\"color:#ff7800;\">1. If you're not confident about Environment Variables or Web Endpoints / APIs, please read Topics 3 and 5 in this <a href=\"../guides/04_technical_foundations.ipynb\">technical foundations guide</a>.<br/>\n",
134
+ " 2. If you want to use AIs other than OpenAI, like Gemini, DeepSeek or Ollama (free), please see the first section in this <a href=\"../guides/09_ai_apis_and_ollama.ipynb\">AI APIs guide</a>.<br/>\n",
135
+ " 3. If you ever get a Name Error in Python, you can always fix it immediately; see the last section of this <a href=\"../guides/06_python_foundations.ipynb\">Python Foundations guide</a> and follow both tutorials and exercises.<br/>\n",
136
+ " </span>\n",
137
+ " </td>\n",
138
+ " </tr>\n",
139
+ "</table>"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# Check the key - if you're not using OpenAI, check whichever key you're using! Ollama doesn't need a key.\n",
149
+ "\n",
150
+ "import os\n",
151
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
152
+ "\n",
153
+ "if openai_api_key:\n",
154
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
155
+ "else:\n",
156
+ " print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
157
+ " \n"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# And now - the all important import statement\n",
167
+ "# If you get an import error - head over to troubleshooting in the Setup folder\n",
168
+ "# Even for other LLM providers like Gemini, you still use this OpenAI import - see Guide 9 for why\n",
169
+ "\n",
170
+ "from openai import OpenAI"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": null,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "# And now we'll create an instance of the OpenAI class\n",
180
+ "# If you're not sure what it means to create an instance of a class - head over to the guides folder (guide 6)!\n",
181
+ "# If you get a NameError - head over to the guides folder (guide 6)to learn about NameErrors - always instantly fixable\n",
182
+ "# If you're not using OpenAI, you just need to slightly modify this - precise instructions are in the AI APIs guide (guide 9)\n",
183
+ "\n",
184
+ "openai = OpenAI()"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# Create a list of messages in the familiar OpenAI format\n",
194
+ "\n",
195
+ "messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# And now call it! Any problems, head to the troubleshooting guide\n",
205
+ "# This uses GPT 4.1 nano, the incredibly cheap model\n",
206
+ "# The APIs guide (guide 9) has exact instructions for using even cheaper or free alternatives to OpenAI\n",
207
+ "# If you get a NameError, head to the guides folder (guide 6) to learn about NameErrors - always instantly fixable\n",
208
+ "\n",
209
+ "response = openai.chat.completions.create(\n",
210
+ " model=\"gpt-4.1-nano\",\n",
211
+ " messages=messages\n",
212
+ ")\n",
213
+ "\n",
214
+ "print(response.choices[0].message.content)\n"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "# And now - let's ask for a question:\n",
224
+ "\n",
225
+ "question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
226
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
236
+ "\n",
237
+ "response = openai.chat.completions.create(\n",
238
+ " model=\"gpt-4.1-mini\",\n",
239
+ " messages=messages\n",
240
+ ")\n",
241
+ "\n",
242
+ "question = response.choices[0].message.content\n",
243
+ "\n",
244
+ "print(question)\n"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": null,
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "# form a new messages list\n",
254
+ "messages = [{\"role\": \"user\", \"content\": question}]\n"
255
+ ]
256
+ },
257
+ {
258
+ "cell_type": "code",
259
+ "execution_count": null,
260
+ "metadata": {},
261
+ "outputs": [],
262
+ "source": [
263
+ "# Ask it again\n",
264
+ "\n",
265
+ "response = openai.chat.completions.create(\n",
266
+ " model=\"gpt-4.1-mini\",\n",
267
+ " messages=messages\n",
268
+ ")\n",
269
+ "\n",
270
+ "answer = response.choices[0].message.content\n",
271
+ "print(answer)\n"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": null,
277
+ "metadata": {},
278
+ "outputs": [],
279
+ "source": [
280
+ "from IPython.display import Markdown, display\n",
281
+ "\n",
282
+ "display(Markdown(answer))\n",
283
+ "\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "metadata": {},
289
+ "source": [
290
+ "# Congratulations!\n",
291
+ "\n",
292
+ "That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
293
+ "\n",
294
+ "Next time things get more interesting..."
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {},
300
+ "source": [
301
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
302
+ " <tr>\n",
303
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
304
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
305
+ " </td>\n",
306
+ " <td>\n",
307
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
308
+ " <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
309
+ " First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
310
+ " Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
311
+ " Finally have 3 third LLM call propose the Agentic AI solution. <br/>\n",
312
+ " We will cover this at up-coming labs, so don't worry if you're unsure.. just give it a try!\n",
313
+ " </span>\n",
314
+ " </td>\n",
315
+ " </tr>\n",
316
+ "</table>"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "question1 = \"Pick a business area that might be worth exploring for an Agentic AI opportunity\"\n",
326
+ "message1 = [{\"role\":\"user\", \"content\":f\"{question1}\"}]\n",
327
+ "\n",
328
+ "openai = OpenAI()\n",
329
+ "\n",
330
+ "response = openai.chat.completions.create(\n",
331
+ " model=\"gpt-4.1-mini\",\n",
332
+ " messages=message1\n",
333
+ " )\n",
334
+ "\n",
335
+ "# Then read the business area:\n",
336
+ "\n",
337
+ "business_area = response.choices[0].message.content\n",
338
+ "\n",
339
+ "print(business_area)\n",
340
+ "# And repeat! In the next message, include the business area within the message"
341
+ ]
342
+ },
343
+ {
344
+ "cell_type": "code",
345
+ "execution_count": null,
346
+ "metadata": {},
347
+ "outputs": [],
348
+ "source": [
349
+ "question2 = f\"\"\"Based on text delimited by triple backticks present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.\n",
350
+ "'''{business_area}'''\"\"\"\n",
351
+ "message2 = [{\"role\":\"user\", \"content\":f\"{question2}\"}]\n",
352
+ "\n",
353
+ "response2 = openai.chat.completions.create(\n",
354
+ " model=\"gpt-4.1-mini\",\n",
355
+ " messages=message2\n",
356
+ " )\n",
357
+ "\n",
358
+ "painpoint = response2.choices[0].message.content\n",
359
+ "\n",
360
+ "print(painpoint)"
361
+ ]
362
+ },
363
+ {
364
+ "cell_type": "code",
365
+ "execution_count": null,
366
+ "metadata": {},
367
+ "outputs": [],
368
+ "source": [
369
+ "question3 = f\"\"\"Propose an Agentic AI solution for the pain-point delimited by triple backticks.\n",
370
+ "'''{painpoint}'''\"\"\"\n",
371
+ "message3 = [{\"role\":\"user\", \"content\":f\"{question3}\"}]\n",
372
+ "\n",
373
+ "response3 = openai.chat.completions.create(\n",
374
+ " model=\"gpt-4.1-mini\",\n",
375
+ " messages=message3\n",
376
+ " )\n",
377
+ "\n",
378
+ "solution = response3.choices[0].message.content\n",
379
+ "\n",
380
+ "display(Markdown(solution))"
381
+ ]
382
+ },
383
+ {
384
+ "cell_type": "markdown",
385
+ "metadata": {},
386
+ "source": []
387
+ }
388
+ ],
389
+ "metadata": {
390
+ "kernelspec": {
391
+ "display_name": ".venv",
392
+ "language": "python",
393
+ "name": "python3"
394
+ },
395
+ "language_info": {
396
+ "codemirror_mode": {
397
+ "name": "ipython",
398
+ "version": 3
399
+ },
400
+ "file_extension": ".py",
401
+ "mimetype": "text/x-python",
402
+ "name": "python",
403
+ "nbconvert_exporter": "python",
404
+ "pygments_lexer": "ipython3",
405
+ "version": "3.12.13"
406
+ }
407
+ },
408
+ "nbformat": 4,
409
+ "nbformat_minor": 2
410
+ }
community_contributions/1_lab2_Kaushik_Parallelization.ipynb ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "import os\n",
10
+ "import json\n",
11
+ "from dotenv import load_dotenv\n",
12
+ "from openai import OpenAI\n",
13
+ "from IPython.display import Markdown"
14
+ ]
15
+ },
16
+ {
17
+ "cell_type": "markdown",
18
+ "metadata": {},
19
+ "source": [
20
+ "### Refresh dot env"
21
+ ]
22
+ },
23
+ {
24
+ "cell_type": "code",
25
+ "execution_count": null,
26
+ "metadata": {},
27
+ "outputs": [],
28
+ "source": [
29
+ "load_dotenv(override=True)"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": 3,
35
+ "metadata": {},
36
+ "outputs": [],
37
+ "source": [
38
+ "open_api_key = os.getenv(\"OPENAI_API_KEY\")\n",
39
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "markdown",
44
+ "metadata": {},
45
+ "source": [
46
+ "### Create initial query to get challange reccomendation"
47
+ ]
48
+ },
49
+ {
50
+ "cell_type": "code",
51
+ "execution_count": 4,
52
+ "metadata": {},
53
+ "outputs": [],
54
+ "source": [
55
+ "query = 'Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. '\n",
56
+ "query += 'Answer only with the question, no explanation.'\n",
57
+ "\n",
58
+ "messages = [{'role':'user', 'content':query}]"
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "code",
63
+ "execution_count": null,
64
+ "metadata": {},
65
+ "outputs": [],
66
+ "source": [
67
+ "print(messages)"
68
+ ]
69
+ },
70
+ {
71
+ "cell_type": "markdown",
72
+ "metadata": {},
73
+ "source": [
74
+ "### Call openai gpt-4o-mini "
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 6,
80
+ "metadata": {},
81
+ "outputs": [],
82
+ "source": [
83
+ "openai = OpenAI()\n",
84
+ "\n",
85
+ "response = openai.chat.completions.create(\n",
86
+ " messages=messages,\n",
87
+ " model='gpt-4o-mini'\n",
88
+ ")\n",
89
+ "\n",
90
+ "challange = response.choices[0].message.content\n"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "metadata": {},
97
+ "outputs": [],
98
+ "source": [
99
+ "print(challange)"
100
+ ]
101
+ },
102
+ {
103
+ "cell_type": "code",
104
+ "execution_count": 8,
105
+ "metadata": {},
106
+ "outputs": [],
107
+ "source": [
108
+ "competitors = []\n",
109
+ "answers = []"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "markdown",
114
+ "metadata": {},
115
+ "source": [
116
+ "### Create messages with the challange query"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": 9,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "messages = [{'role':'user', 'content':challange}]"
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "print(messages)"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "code",
139
+ "execution_count": null,
140
+ "metadata": {},
141
+ "outputs": [],
142
+ "source": [
143
+ "!ollama pull llama3.2"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 12,
149
+ "metadata": {},
150
+ "outputs": [],
151
+ "source": [
152
+ "from threading import Thread"
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "code",
157
+ "execution_count": 13,
158
+ "metadata": {},
159
+ "outputs": [],
160
+ "source": [
161
+ "def gpt_mini_processor():\n",
162
+ " modleName = 'gpt-4o-mini'\n",
163
+ " competitors.append(modleName)\n",
164
+ " response_gpt = openai.chat.completions.create(\n",
165
+ " messages=messages,\n",
166
+ " model=modleName\n",
167
+ " )\n",
168
+ " answers.append(response_gpt.choices[0].message.content)\n",
169
+ "\n",
170
+ "def gemini_processor():\n",
171
+ " gemini = OpenAI(api_key=google_api_key, base_url='https://generativelanguage.googleapis.com/v1beta/openai/')\n",
172
+ " modleName = 'gemini-2.0-flash'\n",
173
+ " competitors.append(modleName)\n",
174
+ " response_gemini = gemini.chat.completions.create(\n",
175
+ " messages=messages,\n",
176
+ " model=modleName\n",
177
+ " )\n",
178
+ " answers.append(response_gemini.choices[0].message.content)\n",
179
+ "\n",
180
+ "def llama_processor():\n",
181
+ " ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
182
+ " modleName = 'llama3.2'\n",
183
+ " competitors.append(modleName)\n",
184
+ " response_llama = ollama.chat.completions.create(\n",
185
+ " messages=messages,\n",
186
+ " model=modleName\n",
187
+ " )\n",
188
+ " answers.append(response_llama.choices[0].message.content)"
189
+ ]
190
+ },
191
+ {
192
+ "cell_type": "markdown",
193
+ "metadata": {},
194
+ "source": [
195
+ "### Paraller execution of LLM calls"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": 14,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "thread1 = Thread(target=gpt_mini_processor)\n",
205
+ "thread2 = Thread(target=gemini_processor)\n",
206
+ "thread3 = Thread(target=llama_processor)\n",
207
+ "\n",
208
+ "thread1.start()\n",
209
+ "thread2.start()\n",
210
+ "thread3.start()\n",
211
+ "\n",
212
+ "thread1.join()\n",
213
+ "thread2.join()\n",
214
+ "thread3.join()"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "print(competitors)\n",
224
+ "print(answers)"
225
+ ]
226
+ },
227
+ {
228
+ "cell_type": "code",
229
+ "execution_count": null,
230
+ "metadata": {},
231
+ "outputs": [],
232
+ "source": [
233
+ "for competitor, answer in zip(competitors, answers):\n",
234
+ " print(f'Competitor:{competitor}\\n\\n{answer}')"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type": "code",
239
+ "execution_count": 17,
240
+ "metadata": {},
241
+ "outputs": [],
242
+ "source": [
243
+ "together = ''\n",
244
+ "for index, answer in enumerate(answers):\n",
245
+ " together += f'# Response from competitor {index + 1}\\n\\n'\n",
246
+ " together += answer + '\\n\\n'"
247
+ ]
248
+ },
249
+ {
250
+ "cell_type": "code",
251
+ "execution_count": null,
252
+ "metadata": {},
253
+ "outputs": [],
254
+ "source": [
255
+ "print(together)"
256
+ ]
257
+ },
258
+ {
259
+ "cell_type": "markdown",
260
+ "metadata": {},
261
+ "source": [
262
+ "### Prompt to judge the LLM results"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "code",
267
+ "execution_count": 19,
268
+ "metadata": {},
269
+ "outputs": [],
270
+ "source": [
271
+ "to_judge = f'''You are judging a competition between {len(competitors)} competitors.\n",
272
+ "Each model has been given this question:\n",
273
+ "\n",
274
+ "{challange}\n",
275
+ "\n",
276
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
277
+ "Respond with JSON, and only JSON, with the following format:\n",
278
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
279
+ "\n",
280
+ "Here are the responses from each competitor:\n",
281
+ "\n",
282
+ "{together}\n",
283
+ "\n",
284
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n",
285
+ "\n",
286
+ "'''"
287
+ ]
288
+ },
289
+ {
290
+ "cell_type": "code",
291
+ "execution_count": 20,
292
+ "metadata": {},
293
+ "outputs": [],
294
+ "source": [
295
+ "to_judge_message = [{'role':'user', 'content':to_judge}]"
296
+ ]
297
+ },
298
+ {
299
+ "cell_type": "markdown",
300
+ "metadata": {},
301
+ "source": [
302
+ "### Execute o3-mini to analyze the LLM results"
303
+ ]
304
+ },
305
+ {
306
+ "cell_type": "code",
307
+ "execution_count": null,
308
+ "metadata": {},
309
+ "outputs": [],
310
+ "source": [
311
+ "openai = OpenAI()\n",
312
+ "response = openai.chat.completions.create(\n",
313
+ " messages=to_judge_message,\n",
314
+ " model='o3-mini'\n",
315
+ ")\n",
316
+ "result = response.choices[0].message.content\n",
317
+ "print(result)"
318
+ ]
319
+ },
320
+ {
321
+ "cell_type": "code",
322
+ "execution_count": null,
323
+ "metadata": {},
324
+ "outputs": [],
325
+ "source": [
326
+ "results_dict = json.loads(result)\n",
327
+ "ranks = results_dict[\"results\"]\n",
328
+ "for index, result in enumerate(ranks):\n",
329
+ " competitor = competitors[int(result)-1]\n",
330
+ " print(f\"Rank {index+1}: {competitor}\")"
331
+ ]
332
+ }
333
+ ],
334
+ "metadata": {
335
+ "kernelspec": {
336
+ "display_name": ".venv",
337
+ "language": "python",
338
+ "name": "python3"
339
+ },
340
+ "language_info": {
341
+ "codemirror_mode": {
342
+ "name": "ipython",
343
+ "version": 3
344
+ },
345
+ "file_extension": ".py",
346
+ "mimetype": "text/x-python",
347
+ "name": "python",
348
+ "nbconvert_exporter": "python",
349
+ "pygments_lexer": "ipython3",
350
+ "version": "3.12.10"
351
+ }
352
+ },
353
+ "nbformat": 4,
354
+ "nbformat_minor": 2
355
+ }
community_contributions/1_lab2_Routing_Workflow.ipynb ADDED
@@ -0,0 +1,514 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Judging and Routing — Optimizing Resource Usage by Evaluating Problem Complexity"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "In the original Lab 2, we explored the **Orchestrator–Worker pattern**, where a planner sent the same question to multiple agents, and a judge assessed their responses to evaluate agent intelligence.\n",
15
+ "\n",
16
+ "In this notebook, we extend that design by adding multiple judges and a routing component to optimize model usage based on task complexity. "
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "metadata": {},
22
+ "source": [
23
+ "## Imports and Environment Setup"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": 1,
29
+ "metadata": {},
30
+ "outputs": [],
31
+ "source": [
32
+ "import os\n",
33
+ "import json\n",
34
+ "from dotenv import load_dotenv\n",
35
+ "from openai import OpenAI\n",
36
+ "from anthropic import Anthropic\n",
37
+ "from IPython.display import Markdown, display"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "load_dotenv(override=True)\n",
47
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
48
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
49
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
50
+ "if openai_api_key and google_api_key and deepseek_api_key:\n",
51
+ " print(\"All keys were loaded successfully\")"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "code",
56
+ "execution_count": null,
57
+ "metadata": {},
58
+ "outputs": [],
59
+ "source": [
60
+ "!ollama pull llama3.2\n",
61
+ "!ollama pull mistral"
62
+ ]
63
+ },
64
+ {
65
+ "cell_type": "markdown",
66
+ "metadata": {},
67
+ "source": [
68
+ "## Creating Models"
69
+ ]
70
+ },
71
+ {
72
+ "cell_type": "markdown",
73
+ "metadata": {},
74
+ "source": [
75
+ "The notebook uses instances of GPT, Gemini and DeepSeek APIs, along with two local models served via Ollama: ```llama3.2``` and ```mistral```."
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": 4,
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "model_specs = {\n",
85
+ " \"gpt-4o-mini\" : None,\n",
86
+ " \"gemini-2.0-flash\": {\n",
87
+ " \"api_key\" : google_api_key,\n",
88
+ " \"url\" : \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
89
+ " },\n",
90
+ " \"deepseek-chat\" : {\n",
91
+ " \"api_key\" : deepseek_api_key,\n",
92
+ " \"url\" : \"https://api.deepseek.com/v1\"\n",
93
+ " },\n",
94
+ " \"llama3.2\" : {\n",
95
+ " \"api_key\" : \"ollama\",\n",
96
+ " \"url\" : \"http://localhost:11434/v1\"\n",
97
+ " },\n",
98
+ " \"mistral\" : {\n",
99
+ " \"api_key\" : \"ollama\",\n",
100
+ " \"url\" : \"http://localhost:11434/v1\"\n",
101
+ " }\n",
102
+ "}\n",
103
+ "\n",
104
+ "def create_model(model_name):\n",
105
+ " spec = model_specs[model_name]\n",
106
+ " if spec is None:\n",
107
+ " return OpenAI()\n",
108
+ " \n",
109
+ " return OpenAI(api_key=spec[\"api_key\"], base_url=spec[\"url\"])"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": 5,
115
+ "metadata": {},
116
+ "outputs": [],
117
+ "source": [
118
+ "orchestrator_model = \"gemini-2.0-flash\"\n",
119
+ "generator = create_model(orchestrator_model)\n",
120
+ "router = create_model(orchestrator_model)\n",
121
+ "\n",
122
+ "qa_models = {\n",
123
+ " model_name : create_model(model_name) \n",
124
+ " for model_name in model_specs.keys()\n",
125
+ "}\n",
126
+ "\n",
127
+ "judges = {\n",
128
+ " model_name : create_model(model_name) \n",
129
+ " for model_name, specs in model_specs.items() \n",
130
+ " if not(specs) or specs[\"api_key\"] != \"ollama\"\n",
131
+ "}"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type": "markdown",
136
+ "metadata": {},
137
+ "source": [
138
+ "## Orchestrator-Worker Workflow"
139
+ ]
140
+ },
141
+ {
142
+ "cell_type": "markdown",
143
+ "metadata": {},
144
+ "source": [
145
+ "First, we generate a question to evaluate the intelligence of each LLM."
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "execution_count": null,
151
+ "metadata": {},
152
+ "outputs": [],
153
+ "source": [
154
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs \"\n",
155
+ "request += \"to evaluate and rank them based on their intelligence. \" \n",
156
+ "request += \"Answer **only** with the question, no explanation or preamble.\"\n",
157
+ "\n",
158
+ "messages = [{\"role\": \"user\", \"content\": request}]\n",
159
+ "messages"
160
+ ]
161
+ },
162
+ {
163
+ "cell_type": "code",
164
+ "execution_count": 7,
165
+ "metadata": {},
166
+ "outputs": [],
167
+ "source": [
168
+ "response = generator.chat.completions.create(\n",
169
+ " model=orchestrator_model,\n",
170
+ " messages=messages,\n",
171
+ ")\n",
172
+ "eval_question = response.choices[0].message.content"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": null,
178
+ "metadata": {},
179
+ "outputs": [],
180
+ "source": [
181
+ "display(Markdown(eval_question))"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "markdown",
186
+ "metadata": {},
187
+ "source": [
188
+ "### Task Parallelization"
189
+ ]
190
+ },
191
+ {
192
+ "cell_type": "markdown",
193
+ "metadata": {},
194
+ "source": [
195
+ "Now, having the question and all the models instantiated it's time to see what each model has to say about the complex task it was given."
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "question = [{\"role\": \"user\", \"content\": eval_question}]\n",
205
+ "answers = []\n",
206
+ "competitors = []\n",
207
+ "\n",
208
+ "for name, model in qa_models.items():\n",
209
+ " response = model.chat.completions.create(model=name, messages=question)\n",
210
+ " answer = response.choices[0].message.content\n",
211
+ " competitors.append(name)\n",
212
+ " answers.append(answer)\n",
213
+ "\n",
214
+ "answers"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": null,
220
+ "metadata": {},
221
+ "outputs": [],
222
+ "source": [
223
+ "report = \"# Answer report for each of the 5 models\\n\\n\"\n",
224
+ "report += \"\\n\\n\".join([f\"## **Model: {model}**\\n\\n{answer}\" for model, answer in zip(competitors, answers)])\n",
225
+ "display(Markdown(report))"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "markdown",
230
+ "metadata": {},
231
+ "source": [
232
+ "### Synthetizer/Judge"
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "markdown",
237
+ "metadata": {},
238
+ "source": [
239
+ "The Judge Agents ranks the LLM responses based on coherence and relevance to the evaluation prompt. Judges vote and the final LLM ranking is based on the aggregated ranking of all three judges."
240
+ ]
241
+ },
242
+ {
243
+ "cell_type": "code",
244
+ "execution_count": null,
245
+ "metadata": {},
246
+ "outputs": [],
247
+ "source": [
248
+ "together = \"\"\n",
249
+ "for index, answer in enumerate(answers):\n",
250
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
251
+ " together += answer + \"\\n\\n\"\n",
252
+ "\n",
253
+ "together"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": 12,
259
+ "metadata": {},
260
+ "outputs": [],
261
+ "source": [
262
+ "judge_prompt = f\"\"\"\n",
263
+ " You are judging a competition between {len(competitors)} LLM competitors.\n",
264
+ " Each model has been given this nuanced question to evaluate their intelligence:\n",
265
+ "\n",
266
+ " {eval_question}\n",
267
+ "\n",
268
+ " Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
269
+ " Respond with JSON, and only JSON, with the following format:\n",
270
+ " {{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
271
+ " With 'best competitor number being ONLY the number', for instance:\n",
272
+ " {{\"results\": [\"5\", \"2\", \"4\", ...]}}\n",
273
+ " Here are the responses from each competitor:\n",
274
+ "\n",
275
+ " {together}\n",
276
+ "\n",
277
+ " Now respond with the JSON with the ranked order of the competitors, nothing else. Do NOT include MARKDOWN FORMATTING or CODE BLOCKS. ONLY the JSON\n",
278
+ " \"\"\"\n",
279
+ "\n",
280
+ "judge_messages = [{\"role\": \"user\", \"content\": judge_prompt}]"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": null,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "from collections import defaultdict\n",
290
+ "import re\n",
291
+ "\n",
292
+ "N = len(competitors)\n",
293
+ "scores = defaultdict(int)\n",
294
+ "for judge_name, judge in judges.items():\n",
295
+ " response = judge.chat.completions.create(\n",
296
+ " model=judge_name,\n",
297
+ " messages=judge_messages,\n",
298
+ " )\n",
299
+ " response = response.choices[0].message.content\n",
300
+ " response_json = re.findall(r'\\{.*?\\}', response)[0]\n",
301
+ " results = json.loads(response_json)[\"results\"]\n",
302
+ " ranks = [int(result) for result in results]\n",
303
+ " print(f\"Judge {judge_name} ranking:\")\n",
304
+ " for i, c in enumerate(ranks):\n",
305
+ " model_name = competitors[c - 1]\n",
306
+ " print(f\"#{i+1} : {model_name}\")\n",
307
+ " scores[c - 1] += (N - i)\n",
308
+ " print()"
309
+ ]
310
+ },
311
+ {
312
+ "cell_type": "code",
313
+ "execution_count": null,
314
+ "metadata": {},
315
+ "outputs": [],
316
+ "source": [
317
+ "sorted_indices = sorted(scores, key=scores.get)\n",
318
+ "\n",
319
+ "# Convert to model names\n",
320
+ "ranked_model_names = [competitors[i] for i in sorted_indices]\n",
321
+ "\n",
322
+ "print(\"Final ranking from best to worst:\")\n",
323
+ "for i, name in enumerate(ranked_model_names[::-1], 1):\n",
324
+ " print(f\"#{i}: {name}\")"
325
+ ]
326
+ },
327
+ {
328
+ "cell_type": "markdown",
329
+ "metadata": {},
330
+ "source": [
331
+ "## Routing Workflow"
332
+ ]
333
+ },
334
+ {
335
+ "cell_type": "markdown",
336
+ "metadata": {},
337
+ "source": [
338
+ "We now define a routing agent responsible for classifying task complexity and delegating the prompt to the most appropriate model."
339
+ ]
340
+ },
341
+ {
342
+ "cell_type": "code",
343
+ "execution_count": 15,
344
+ "metadata": {},
345
+ "outputs": [],
346
+ "source": [
347
+ "def classify_question_complexity(question: str, routing_agent, routing_model) -> int:\n",
348
+ " \"\"\"\n",
349
+ " Ask an LLM to classify the question complexity from 1 (easy) to 5 (very hard).\n",
350
+ " \"\"\"\n",
351
+ " prompt = f\"\"\"\n",
352
+ " You are a classifier responsible for assigning a complexity level to user questions, based on how difficult they would be for a language model to answer.\n",
353
+ "\n",
354
+ " Please read the question below and assign a complexity score from 1 to 5:\n",
355
+ "\n",
356
+ " - Level 1: Very simple factual or definitional question (e.g., “What is the capital of France?”)\n",
357
+ " - Level 2: Slightly more involved, requiring basic reasoning or comparison\n",
358
+ " - Level 3: Moderate complexity, requiring synthesis, context understanding, or multi-part answers\n",
359
+ " - Level 4: High complexity, requiring abstract thinking, ethical judgment, or creative generation\n",
360
+ " - Level 5: Extremely challenging, requiring deep reasoning, philosophical reflection, or long-term multi-step inference\n",
361
+ "\n",
362
+ " Respond ONLY with a single integer between 1 and 5 that best reflects the complexity of the question.\n",
363
+ "\n",
364
+ " Question:\n",
365
+ " {question}\n",
366
+ " \"\"\"\n",
367
+ "\n",
368
+ " response = routing_agent.chat.completions.create(\n",
369
+ " model=routing_model,\n",
370
+ " messages=[{\"role\": \"user\", \"content\": prompt}]\n",
371
+ " )\n",
372
+ " try:\n",
373
+ " return int(response.choices[0].message.content.strip())\n",
374
+ " except Exception:\n",
375
+ " return 3 # default to medium complexity on error\n",
376
+ " \n",
377
+ "def route_question_to_model(question: str, models_by_rank, classifier_model=router, model_name=orchestrator_model):\n",
378
+ " level = classify_question_complexity(question, classifier_model, model_name)\n",
379
+ " selected_model_name = models_by_rank[level - 1]\n",
380
+ " return selected_model_name"
381
+ ]
382
+ },
383
+ {
384
+ "cell_type": "code",
385
+ "execution_count": 16,
386
+ "metadata": {},
387
+ "outputs": [],
388
+ "source": [
389
+ "difficulty_prompts = [\n",
390
+ " \"Generate a very basic, factual question that a small or entry-level language model could answer easily. It should require no reasoning, just direct knowledge lookup.\",\n",
391
+ " \"Generate a slightly involved question that requires basic reasoning, comparison, or combining two known facts. Still within the grasp of small models but not purely factual.\",\n",
392
+ " \"Generate a moderately challenging question that requires some synthesis of ideas, multi-step reasoning, or contextual understanding. A mid-tier model should be able to answer it with effort.\",\n",
393
+ " \"Generate a difficult question involving abstract thinking, open-ended reasoning, or ethical tradeoffs. The question should challenge large models to produce thoughtful and coherent responses.\",\n",
394
+ " \"Generate an extremely complex and nuanced question that tests the limits of current language models. It should require deep reasoning, long-term planning, philosophy, or advanced multi-domain knowledge.\"\n",
395
+ "]\n",
396
+ "def generate_question(level, generator=generator, generator_model=orchestrator_model):\n",
397
+ " prompt = (\n",
398
+ " f\"{difficulty_prompts[level - 1]}\\n\"\n",
399
+ " \"Answer only with the question, no explanation.\"\n",
400
+ " )\n",
401
+ " messages = [{\"role\": \"user\", \"content\": prompt}]\n",
402
+ " response = generator.chat.completions.create(\n",
403
+ " model=generator_model, # or your planner model\n",
404
+ " messages=messages\n",
405
+ " )\n",
406
+ " \n",
407
+ " return response.choices[0].message.content\n",
408
+ "\n"
409
+ ]
410
+ },
411
+ {
412
+ "cell_type": "markdown",
413
+ "metadata": {},
414
+ "source": [
415
+ "### Testing Routing Workflow"
416
+ ]
417
+ },
418
+ {
419
+ "cell_type": "markdown",
420
+ "metadata": {},
421
+ "source": [
422
+ "Finally, to test the routing workflow, we create a function that accepts a task complexity level and triggers the full routing process.\n",
423
+ "\n",
424
+ "*Note: A level-N prompt isn't always assigned to the Nth-most capable model due to the classifier's subjective decisions.*"
425
+ ]
426
+ },
427
+ {
428
+ "cell_type": "code",
429
+ "execution_count": 17,
430
+ "metadata": {},
431
+ "outputs": [],
432
+ "source": [
433
+ "def test_generation_routing(level):\n",
434
+ " question = generate_question(level=level)\n",
435
+ " answer_model = route_question_to_model(question, ranked_model_names)\n",
436
+ " messages = [{\"role\": \"user\", \"content\": question}]\n",
437
+ "\n",
438
+ " response =qa_models[answer_model].chat.completions.create(\n",
439
+ " model=answer_model, # or your planner model\n",
440
+ " messages=messages\n",
441
+ " )\n",
442
+ " print(f\"Question : {question}\")\n",
443
+ " print(f\"Routed to {answer_model}\")\n",
444
+ " display(Markdown(response.choices[0].message.content))"
445
+ ]
446
+ },
447
+ {
448
+ "cell_type": "code",
449
+ "execution_count": null,
450
+ "metadata": {},
451
+ "outputs": [],
452
+ "source": [
453
+ "test_generation_routing(level=1)"
454
+ ]
455
+ },
456
+ {
457
+ "cell_type": "code",
458
+ "execution_count": null,
459
+ "metadata": {},
460
+ "outputs": [],
461
+ "source": [
462
+ "test_generation_routing(level=2)"
463
+ ]
464
+ },
465
+ {
466
+ "cell_type": "code",
467
+ "execution_count": null,
468
+ "metadata": {},
469
+ "outputs": [],
470
+ "source": [
471
+ "test_generation_routing(level=3)"
472
+ ]
473
+ },
474
+ {
475
+ "cell_type": "code",
476
+ "execution_count": null,
477
+ "metadata": {},
478
+ "outputs": [],
479
+ "source": [
480
+ "test_generation_routing(level=4)"
481
+ ]
482
+ },
483
+ {
484
+ "cell_type": "code",
485
+ "execution_count": null,
486
+ "metadata": {},
487
+ "outputs": [],
488
+ "source": [
489
+ "test_generation_routing(level=5)"
490
+ ]
491
+ }
492
+ ],
493
+ "metadata": {
494
+ "kernelspec": {
495
+ "display_name": ".venv",
496
+ "language": "python",
497
+ "name": "python3"
498
+ },
499
+ "language_info": {
500
+ "codemirror_mode": {
501
+ "name": "ipython",
502
+ "version": 3
503
+ },
504
+ "file_extension": ".py",
505
+ "mimetype": "text/x-python",
506
+ "name": "python",
507
+ "nbconvert_exporter": "python",
508
+ "pygments_lexer": "ipython3",
509
+ "version": "3.12.11"
510
+ }
511
+ },
512
+ "nbformat": 4,
513
+ "nbformat_minor": 2
514
+ }
community_contributions/1_lab_5_abrar.ipynb ADDED
@@ -0,0 +1,490 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "1151ec05",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "data": {
11
+ "text/plain": [
12
+ "True"
13
+ ]
14
+ },
15
+ "execution_count": 1,
16
+ "metadata": {},
17
+ "output_type": "execute_result"
18
+ }
19
+ ],
20
+ "source": [
21
+ "from rich.console import Console\n",
22
+ "from dotenv import load_dotenv\n",
23
+ "from openai import OpenAI\n",
24
+ "import json\n",
25
+ "load_dotenv(override=True)"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "code",
30
+ "execution_count": 2,
31
+ "id": "05b104aa",
32
+ "metadata": {},
33
+ "outputs": [],
34
+ "source": [
35
+ "openai = OpenAI()\n",
36
+ "todos = []\n",
37
+ "completed = []"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": 11,
43
+ "id": "f834713b",
44
+ "metadata": {},
45
+ "outputs": [],
46
+ "source": [
47
+ "def show(text):\n",
48
+ " try:\n",
49
+ " Console().print(text)\n",
50
+ " except Exception:\n",
51
+ " print(text)\n",
52
+ "\n",
53
+ "def get_todo_report() -> str:\n",
54
+ " result = \"\"\n",
55
+ " for index, todo in enumerate(todos):\n",
56
+ " if completed[index]:\n",
57
+ " result += f\"Todo #{index + 1}: [green][strike]{todo}[/strike][/green]\\n\"\n",
58
+ " else:\n",
59
+ " result += f\"Todo #{index + 1}: {todo}\\n\"\n",
60
+ " show(result)\n",
61
+ " return result\n",
62
+ "\n",
63
+ "def create_todos(descriptions: list[str]) -> str:\n",
64
+ " todos.extend(descriptions)\n",
65
+ " completed.extend([False] * len(descriptions))\n",
66
+ " return get_todo_report()\n",
67
+ "\n",
68
+ "def mark_complete(index: int, notes: str) -> str:\n",
69
+ " if 1<=index<=len(todos):\n",
70
+ " completed[index - 1] = True\n",
71
+ " else:\n",
72
+ " return \"No todos\"\n",
73
+ " Console().print(notes)\n",
74
+ " return get_todo_report()\n"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 16,
80
+ "id": "d381ce66",
81
+ "metadata": {},
82
+ "outputs": [
83
+ {
84
+ "data": {
85
+ "text/html": [
86
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: Buy groceries\n",
87
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: Clean the house\n",
88
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: Finish the project\n",
89
+ "\n",
90
+ "</pre>\n"
91
+ ],
92
+ "text/plain": [
93
+ "Todo #\u001b[1;36m1\u001b[0m: Buy groceries\n",
94
+ "Todo #\u001b[1;36m2\u001b[0m: Clean the house\n",
95
+ "Todo #\u001b[1;36m3\u001b[0m: Finish the project\n",
96
+ "\n"
97
+ ]
98
+ },
99
+ "metadata": {},
100
+ "output_type": "display_data"
101
+ },
102
+ {
103
+ "data": {
104
+ "text/plain": [
105
+ "'Todo #1: Buy groceries\\nTodo #2: Clean the house\\nTodo #3: Finish the project\\n'"
106
+ ]
107
+ },
108
+ "execution_count": 16,
109
+ "metadata": {},
110
+ "output_type": "execute_result"
111
+ }
112
+ ],
113
+ "source": [
114
+ "create_todos([\"Buy groceries\", \"Clean the house\", \"Finish the project\"])"
115
+ ]
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "execution_count": 17,
120
+ "id": "019c032d",
121
+ "metadata": {},
122
+ "outputs": [
123
+ {
124
+ "data": {
125
+ "text/html": [
126
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">I have cleaned the house\n",
127
+ "</pre>\n"
128
+ ],
129
+ "text/plain": [
130
+ "I have cleaned the house\n"
131
+ ]
132
+ },
133
+ "metadata": {},
134
+ "output_type": "display_data"
135
+ },
136
+ {
137
+ "data": {
138
+ "text/html": [
139
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: Buy groceries\n",
140
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Clean the house</span>\n",
141
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: Finish the project\n",
142
+ "\n",
143
+ "</pre>\n"
144
+ ],
145
+ "text/plain": [
146
+ "Todo #\u001b[1;36m1\u001b[0m: Buy groceries\n",
147
+ "Todo #\u001b[1;36m2\u001b[0m: \u001b[9;32mClean the house\u001b[0m\n",
148
+ "Todo #\u001b[1;36m3\u001b[0m: Finish the project\n",
149
+ "\n"
150
+ ]
151
+ },
152
+ "metadata": {},
153
+ "output_type": "display_data"
154
+ },
155
+ {
156
+ "data": {
157
+ "text/plain": [
158
+ "'Todo #1: Buy groceries\\nTodo #2: [green][strike]Clean the house[/strike][/green]\\nTodo #3: Finish the project\\n'"
159
+ ]
160
+ },
161
+ "execution_count": 17,
162
+ "metadata": {},
163
+ "output_type": "execute_result"
164
+ }
165
+ ],
166
+ "source": [
167
+ "mark_complete(2, \"I have cleaned the house\")"
168
+ ]
169
+ },
170
+ {
171
+ "cell_type": "code",
172
+ "execution_count": 34,
173
+ "id": "29a034ce",
174
+ "metadata": {},
175
+ "outputs": [],
176
+ "source": [
177
+ "create_todos_json = {\n",
178
+ " \"name\": \"create_todos\",\n",
179
+ " \"description\": \"Add new todos from a list of descriptions and return the full list\",\n",
180
+ " \"parameters\": {\n",
181
+ " \"type\": \"object\",\n",
182
+ " \"properties\": {\n",
183
+ " \"descriptions\": {\n",
184
+ " 'type': 'array',\n",
185
+ " 'items': {'type': 'string'},\n",
186
+ " 'title': 'Descriptions'\n",
187
+ " }\n",
188
+ " },\n",
189
+ " \"required\": [\"descriptions\"],\n",
190
+ " \"additionalProperties\": False\n",
191
+ " }\n",
192
+ "}\n",
193
+ "\n",
194
+ "mark_complete_json = {\n",
195
+ " \"name\": \"mark_complete\",\n",
196
+ " \"description\": \"Mark complete the todo at the given position (starting from 1) and return the full list\",\n",
197
+ " \"parameters\": {\n",
198
+ " 'properties': {\n",
199
+ " 'index': {\n",
200
+ " 'description': 'The 1-based index of the todo to mark as complete',\n",
201
+ " 'title': 'Index',\n",
202
+ " 'type': 'integer'\n",
203
+ " },\n",
204
+ " 'notes': {\n",
205
+ " 'description': 'Notes about how you completed the todo in rich console markup',\n",
206
+ " 'title': 'Notes',\n",
207
+ " 'type': 'string'\n",
208
+ " }\n",
209
+ " },\n",
210
+ " 'required': ['index', 'notes'],\n",
211
+ " 'type': 'object',\n",
212
+ " 'additionalProperties': False\n",
213
+ " }\n",
214
+ "}"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": 35,
220
+ "id": "92ccd384",
221
+ "metadata": {},
222
+ "outputs": [],
223
+ "source": [
224
+ "tools = [{\"type\": \"function\", \"function\": create_todos_json},\n",
225
+ " {\"type\": \"function\", \"function\": mark_complete_json}]"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": 36,
231
+ "id": "64e82bd6",
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "def handle_tool_calls(tool_calls):\n",
236
+ " results = []\n",
237
+ " for tool_call in tool_calls:\n",
238
+ " tool_name = tool_call.function.name\n",
239
+ " arguments = json.loads(tool_call.function.arguments)\n",
240
+ " tool = globals().get(tool_name)\n",
241
+ " result = tool(**arguments) if tool else {}\n",
242
+ " results.append({\"role\": \"tool\",\"content\": json.dumps(result),\"tool_call_id\": tool_call.id})\n",
243
+ " return results"
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "code",
248
+ "execution_count": 37,
249
+ "id": "37c00c69",
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "def loop(messages):\n",
254
+ " done = False\n",
255
+ " while not done:\n",
256
+ " response = openai.chat.completions.create(model=\"gpt-5.2\", messages=messages, tools=tools, reasoning_effort=\"none\")\n",
257
+ " finish_reason = response.choices[0].finish_reason\n",
258
+ " if finish_reason==\"tool_calls\":\n",
259
+ " message = response.choices[0].message\n",
260
+ " tool_calls = message.tool_calls\n",
261
+ " results = handle_tool_calls(tool_calls)\n",
262
+ " messages.append(message)\n",
263
+ " messages.extend(results)\n",
264
+ " else:\n",
265
+ " done = True\n",
266
+ " show(response.choices[0].message.content)"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 40,
272
+ "id": "1263fb23",
273
+ "metadata": {},
274
+ "outputs": [],
275
+ "source": [
276
+ "system_message = \"\"\"\n",
277
+ "You are given a problem to solve, by using your todo tools to plan a list of steps, then carrying out each step in turn.\n",
278
+ "Now use the todo list tools, create a plan, carry out the steps, and reply with the solution.\n",
279
+ "If any quantity isn't provided in the question, then include a step to come up with a reasonable estimate.\n",
280
+ "Provide your solution in Rich console markup without code blocks.\n",
281
+ "Do not ask the user questions or clarification; respond only with the answer after using your tools.\n",
282
+ "\"\"\"\n",
283
+ "user_message = \"\"\"\n",
284
+ "If I invest $5,000 today at an annual interest rate of 7%, compounded monthly,\n",
285
+ "how much will I have after 10 years?\n",
286
+ "\"\"\"\n",
287
+ "messages = [{\"role\": \"system\", \"content\": system_message}, {\"role\": \"user\", \"content\": user_message}]\n"
288
+ ]
289
+ },
290
+ {
291
+ "cell_type": "code",
292
+ "execution_count": 41,
293
+ "id": "0c9ea8db",
294
+ "metadata": {},
295
+ "outputs": [
296
+ {
297
+ "data": {
298
+ "text/html": [
299
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: Identify given values and required formula for monthly compounding future value\n",
300
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: Compute future value FV = P*<span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>+r/m<span style=\"font-weight: bold\">)</span>^<span style=\"font-weight: bold\">(</span>m*t<span style=\"font-weight: bold\">)</span>\n",
301
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: Round to sensible cents and present final amount\n",
302
+ "\n",
303
+ "</pre>\n"
304
+ ],
305
+ "text/plain": [
306
+ "Todo #\u001b[1;36m1\u001b[0m: Identify given values and required formula for monthly compounding future value\n",
307
+ "Todo #\u001b[1;36m2\u001b[0m: Compute future value FV = P*\u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m+r/m\u001b[1m)\u001b[0m^\u001b[1m(\u001b[0mm*t\u001b[1m)\u001b[0m\n",
308
+ "Todo #\u001b[1;36m3\u001b[0m: Round to sensible cents and present final amount\n",
309
+ "\n"
310
+ ]
311
+ },
312
+ "metadata": {},
313
+ "output_type": "display_data"
314
+ },
315
+ {
316
+ "data": {
317
+ "text/html": [
318
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Given</span>: principal P = $<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5</span>,<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">000</span>; nominal annual rate r = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.07</span>; compounding m = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span>/month; time t = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span> years.\n",
319
+ "<span style=\"font-weight: bold\">Use</span> monthly-compound future value: FV = P\\*<span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span> + r/m<span style=\"font-weight: bold\">)</span>^<span style=\"font-weight: bold\">(</span>m\\*t<span style=\"font-weight: bold\">)</span>.\n",
320
+ "</pre>\n"
321
+ ],
322
+ "text/plain": [
323
+ "\u001b[1mGiven\u001b[0m: principal P = $\u001b[1;36m5\u001b[0m,\u001b[1;36m000\u001b[0m; nominal annual rate r = \u001b[1;36m0.07\u001b[0m; compounding m = \u001b[1;36m12\u001b[0m/month; time t = \u001b[1;36m10\u001b[0m years.\n",
324
+ "\u001b[1mUse\u001b[0m monthly-compound future value: FV = P\\*\u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m + r/m\u001b[1m)\u001b[0m^\u001b[1m(\u001b[0mm\\*t\u001b[1m)\u001b[0m.\n"
325
+ ]
326
+ },
327
+ "metadata": {},
328
+ "output_type": "display_data"
329
+ },
330
+ {
331
+ "data": {
332
+ "text/html": [
333
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Identify given values and required formula for monthly compounding future value</span>\n",
334
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: Compute future value FV = P*<span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>+r/m<span style=\"font-weight: bold\">)</span>^<span style=\"font-weight: bold\">(</span>m*t<span style=\"font-weight: bold\">)</span>\n",
335
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: Round to sensible cents and present final amount\n",
336
+ "\n",
337
+ "</pre>\n"
338
+ ],
339
+ "text/plain": [
340
+ "Todo #\u001b[1;36m1\u001b[0m: \u001b[9;32mIdentify given values and required formula for monthly compounding future value\u001b[0m\n",
341
+ "Todo #\u001b[1;36m2\u001b[0m: Compute future value FV = P*\u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m+r/m\u001b[1m)\u001b[0m^\u001b[1m(\u001b[0mm*t\u001b[1m)\u001b[0m\n",
342
+ "Todo #\u001b[1;36m3\u001b[0m: Round to sensible cents and present final amount\n",
343
+ "\n"
344
+ ]
345
+ },
346
+ "metadata": {},
347
+ "output_type": "display_data"
348
+ },
349
+ {
350
+ "data": {
351
+ "text/html": [
352
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Compute: periodic rate = r/m = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.07</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span> = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.0058333333</span>.\n",
353
+ "Number of periods = m*t = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span>*<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span> = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">120</span>.\n",
354
+ "Growth factor = <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1.0058333333</span><span style=\"font-weight: bold\">)</span>^<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">120</span> ≈ <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2.009889</span>.\n",
355
+ "FV ≈ <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5000</span> * <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2.009889</span> = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10049.447</span>.\n",
356
+ "</pre>\n"
357
+ ],
358
+ "text/plain": [
359
+ "Compute: periodic rate = r/m = \u001b[1;36m0.07\u001b[0m/\u001b[1;36m12\u001b[0m = \u001b[1;36m0.0058333333\u001b[0m.\n",
360
+ "Number of periods = m*t = \u001b[1;36m12\u001b[0m*\u001b[1;36m10\u001b[0m = \u001b[1;36m120\u001b[0m.\n",
361
+ "Growth factor = \u001b[1m(\u001b[0m\u001b[1;36m1.0058333333\u001b[0m\u001b[1m)\u001b[0m^\u001b[1;36m120\u001b[0m ≈ \u001b[1;36m2.009889\u001b[0m.\n",
362
+ "FV ≈ \u001b[1;36m5000\u001b[0m * \u001b[1;36m2.009889\u001b[0m = \u001b[1;36m10049.447\u001b[0m.\n"
363
+ ]
364
+ },
365
+ "metadata": {},
366
+ "output_type": "display_data"
367
+ },
368
+ {
369
+ "data": {
370
+ "text/html": [
371
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Identify given values and required formula for monthly compounding future value</span>\n",
372
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Compute future value FV = P*</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">(</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">1</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">+r/m</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">)</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">^</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">(</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">m*t</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">)</span>\n",
373
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: Round to sensible cents and present final amount\n",
374
+ "\n",
375
+ "</pre>\n"
376
+ ],
377
+ "text/plain": [
378
+ "Todo #\u001b[1;36m1\u001b[0m: \u001b[9;32mIdentify given values and required formula for monthly compounding future value\u001b[0m\n",
379
+ "Todo #\u001b[1;36m2\u001b[0m: \u001b[9;32mCompute future value FV = P*\u001b[0m\u001b[1;9;32m(\u001b[0m\u001b[1;9;32m1\u001b[0m\u001b[9;32m+r/m\u001b[0m\u001b[1;9;32m)\u001b[0m\u001b[9;32m^\u001b[0m\u001b[1;9;32m(\u001b[0m\u001b[9;32mm*t\u001b[0m\u001b[1;9;32m)\u001b[0m\n",
380
+ "Todo #\u001b[1;36m3\u001b[0m: Round to sensible cents and present final amount\n",
381
+ "\n"
382
+ ]
383
+ },
384
+ "metadata": {},
385
+ "output_type": "display_data"
386
+ },
387
+ {
388
+ "data": {
389
+ "text/html": [
390
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Round to cents: $<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span>,<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">049.45</span>.\n",
391
+ "</pre>\n"
392
+ ],
393
+ "text/plain": [
394
+ "Round to cents: $\u001b[1;36m10\u001b[0m,\u001b[1;36m049.45\u001b[0m.\n"
395
+ ]
396
+ },
397
+ "metadata": {},
398
+ "output_type": "display_data"
399
+ },
400
+ {
401
+ "data": {
402
+ "text/html": [
403
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Identify given values and required formula for monthly compounding future value</span>\n",
404
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Compute future value FV = P*</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">(</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">1</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">+r/m</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">)</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">^</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">(</span><span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">m*t</span><span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold; text-decoration: line-through\">)</span>\n",
405
+ "Todo #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>: <span style=\"color: #008000; text-decoration-color: #008000; text-decoration: line-through\">Round to sensible cents and present final amount</span>\n",
406
+ "\n",
407
+ "</pre>\n"
408
+ ],
409
+ "text/plain": [
410
+ "Todo #\u001b[1;36m1\u001b[0m: \u001b[9;32mIdentify given values and required formula for monthly compounding future value\u001b[0m\n",
411
+ "Todo #\u001b[1;36m2\u001b[0m: \u001b[9;32mCompute future value FV = P*\u001b[0m\u001b[1;9;32m(\u001b[0m\u001b[1;9;32m1\u001b[0m\u001b[9;32m+r/m\u001b[0m\u001b[1;9;32m)\u001b[0m\u001b[9;32m^\u001b[0m\u001b[1;9;32m(\u001b[0m\u001b[9;32mm*t\u001b[0m\u001b[1;9;32m)\u001b[0m\n",
412
+ "Todo #\u001b[1;36m3\u001b[0m: \u001b[9;32mRound to sensible cents and present final amount\u001b[0m\n",
413
+ "\n"
414
+ ]
415
+ },
416
+ "metadata": {},
417
+ "output_type": "display_data"
418
+ },
419
+ {
420
+ "data": {
421
+ "text/html": [
422
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Future value (monthly compounding)</span>\n",
423
+ "\n",
424
+ "<span style=\"font-weight: bold\">Formula:</span> FV = <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">P</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span> + r/m<span style=\"font-weight: bold\">)</span>^<span style=\"font-weight: bold\">(</span>m·t<span style=\"font-weight: bold\">)</span>\n",
425
+ "\n",
426
+ "<span style=\"font-weight: bold\">Inputs:</span>\n",
427
+ "• P = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5</span>,<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">000</span> \n",
428
+ "• r = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.07</span> \n",
429
+ "• m = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span> \n",
430
+ "• t = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span> \n",
431
+ "\n",
432
+ "<span style=\"font-weight: bold\">Calculation:</span>\n",
433
+ "• Periodic rate = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.07</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span> = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0.0058333333</span> \n",
434
+ "• Periods = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">12</span>·<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span> = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">120</span> \n",
435
+ "• FV = <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5000</span>·<span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1.0058333333</span><span style=\"font-weight: bold\">)</span>^<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">120</span> ≈ <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5000</span>·<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2.009889</span> ≈ <span style=\"font-weight: bold\">$</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span><span style=\"font-weight: bold\">,</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">049.45</span>\n",
436
+ "\n",
437
+ "<span style=\"font-weight: bold\">Answer:</span> After <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span> years, you’ll have approximately <span style=\"font-weight: bold\">$</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span><span style=\"font-weight: bold\">,</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">049.45</span>.\n",
438
+ "</pre>\n"
439
+ ],
440
+ "text/plain": [
441
+ "\u001b[1mFuture value \u001b[0m\u001b[1m(\u001b[0m\u001b[1mmonthly compounding\u001b[0m\u001b[1m)\u001b[0m\n",
442
+ "\n",
443
+ "\u001b[1mFormula:\u001b[0m FV = \u001b[1;35mP\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m + r/m\u001b[1m)\u001b[0m^\u001b[1m(\u001b[0mm·t\u001b[1m)\u001b[0m\n",
444
+ "\n",
445
+ "\u001b[1mInputs:\u001b[0m\n",
446
+ "• P = \u001b[1;36m5\u001b[0m,\u001b[1;36m000\u001b[0m \n",
447
+ "• r = \u001b[1;36m0.07\u001b[0m \n",
448
+ "• m = \u001b[1;36m12\u001b[0m \n",
449
+ "• t = \u001b[1;36m10\u001b[0m \n",
450
+ "\n",
451
+ "\u001b[1mCalculation:\u001b[0m\n",
452
+ "• Periodic rate = \u001b[1;36m0.07\u001b[0m/\u001b[1;36m12\u001b[0m = \u001b[1;36m0.0058333333\u001b[0m \n",
453
+ "• Periods = \u001b[1;36m12\u001b[0m·\u001b[1;36m10\u001b[0m = \u001b[1;36m120\u001b[0m \n",
454
+ "• FV = \u001b[1;36m5000\u001b[0m·\u001b[1m(\u001b[0m\u001b[1;36m1.0058333333\u001b[0m\u001b[1m)\u001b[0m^\u001b[1;36m120\u001b[0m ≈ \u001b[1;36m5000\u001b[0m·\u001b[1;36m2.009889\u001b[0m ≈ \u001b[1m$\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1m,\u001b[0m\u001b[1;36m049.45\u001b[0m\n",
455
+ "\n",
456
+ "\u001b[1mAnswer:\u001b[0m After \u001b[1;36m10\u001b[0m years, you’ll have approximately \u001b[1m$\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1m,\u001b[0m\u001b[1;36m049.45\u001b[0m.\n"
457
+ ]
458
+ },
459
+ "metadata": {},
460
+ "output_type": "display_data"
461
+ }
462
+ ],
463
+ "source": [
464
+ "todos, completed = [], []\n",
465
+ "loop(messages)"
466
+ ]
467
+ }
468
+ ],
469
+ "metadata": {
470
+ "kernelspec": {
471
+ "display_name": "agents",
472
+ "language": "python",
473
+ "name": "python3"
474
+ },
475
+ "language_info": {
476
+ "codemirror_mode": {
477
+ "name": "ipython",
478
+ "version": 3
479
+ },
480
+ "file_extension": ".py",
481
+ "mimetype": "text/x-python",
482
+ "name": "python",
483
+ "nbconvert_exporter": "python",
484
+ "pygments_lexer": "ipython3",
485
+ "version": "3.12.6"
486
+ }
487
+ },
488
+ "nbformat": 4,
489
+ "nbformat_minor": 5
490
+ }
community_contributions/1_medtech_opportunity_finder/01_medtech.ipynb ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "8c8f2d93",
6
+ "metadata": {},
7
+ "source": [
8
+ "# 🏥 MedTech AI Opportunity Finder\n",
9
+ "\n",
10
+ "- 🌍 Task: Generate quirky healthcare/pharma AI business opportunities with pain points and solutions.\n",
11
+ "- 🧠 Model: Uses OpenAI GPT-4o-mini for creative business idea generation\n",
12
+ "- 🎯 Process: Three-step pipeline - Business Area → Pain Point → AI Solution\n",
13
+ "- 📌 Output Format: Markdown-formatted responses streamed in real-time with humor\n",
14
+ "- 🔧 Tools: OpenAI API and IPython display for interactive streaming\n",
15
+ "- 🧑‍💻 Skill Level: Beginner\n",
16
+ "\n",
17
+ "🛠️ Requirements\n",
18
+ "- ⚙️ Hardware: ✅ CPU is sufficient — no GPU required\n",
19
+ "- 🔑 OpenAI API Key\n",
20
+ "- IPython environment (Jupyter/Colab)\n",
21
+ "\n",
22
+ "---\n",
23
+ "📢 Discover more Agentic AI notebooks on my [GitHub repository](https://github.com/lisekarimi/agentverse) and explore additional AI projects on my [portfolio](https://lisekarimi.com)."
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": null,
29
+ "id": "1df27837",
30
+ "metadata": {},
31
+ "outputs": [],
32
+ "source": [
33
+ "from openai import OpenAI\n",
34
+ "from IPython.display import display, Markdown, update_display"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": null,
40
+ "id": "b197c72a",
41
+ "metadata": {},
42
+ "outputs": [],
43
+ "source": [
44
+ "client = OpenAI() # Automatically finds OPENAI_API_KEY without needing os.getenv() or load_dotenv()."
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": null,
50
+ "id": "cc8064bb",
51
+ "metadata": {},
52
+ "outputs": [],
53
+ "source": [
54
+ "def stream_response(messages, section_title):\n",
55
+ " \"\"\"Stream response and display with real-time updates\"\"\"\n",
56
+ " response_stream = client.chat.completions.create(\n",
57
+ " model=\"gpt-4o-mini\",\n",
58
+ " messages=messages,\n",
59
+ " stream=True\n",
60
+ " )\n",
61
+ "\n",
62
+ " response = \"\"\n",
63
+ " display_handle = display(Markdown(f\"## {section_title}\\n\\n\"), display_id=True)\n",
64
+ "\n",
65
+ " for chunk in response_stream:\n",
66
+ " if chunk.choices[0].delta.content:\n",
67
+ " response += chunk.choices[0].delta.content\n",
68
+ " # Clean up any unwanted markdown artifacts\n",
69
+ " cleaned_response = response.replace(\"```\", \"\").replace(\"markdown\", \"\")\n",
70
+ " update_display(Markdown(f\"## {section_title}\\n\\n{cleaned_response}\"), display_id=display_handle.display_id)\n",
71
+ "\n",
72
+ " return response"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "id": "857e0458",
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "# Step 1: Business area\n",
83
+ "messages = [{\"role\": \"user\", \"content\": \"Give me a quirky healthcare or pharma business area for an AI agent. Keep it short and clear.\"}]\n",
84
+ "business_idea = stream_response(messages, \"🏢 Business Area\")"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "execution_count": null,
90
+ "id": "23838465",
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "# Step 2: Pain point\n",
95
+ "messages = [{\"role\": \"user\", \"content\": f\"What's broken about {business_idea}? Short and funny.\"}]\n",
96
+ "pain_point = stream_response(messages, \"😵 What's Broken\")"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "execution_count": null,
102
+ "id": "5aa70151",
103
+ "metadata": {},
104
+ "outputs": [],
105
+ "source": [
106
+ "# Step 3: AI solution\n",
107
+ "messages = [{\"role\": \"user\", \"content\": f\"How would an AI agent solve this {pain_point}? Brief and clear.\"}]\n",
108
+ "solution = stream_response(messages, \"🤖 AI to the Rescue\")"
109
+ ]
110
+ }
111
+ ],
112
+ "metadata": {
113
+ "kernelspec": {
114
+ "display_name": "agentverse",
115
+ "language": "python",
116
+ "name": "python3"
117
+ },
118
+ "language_info": {
119
+ "codemirror_mode": {
120
+ "name": "ipython",
121
+ "version": 3
122
+ },
123
+ "file_extension": ".py",
124
+ "mimetype": "text/x-python",
125
+ "name": "python",
126
+ "nbconvert_exporter": "python",
127
+ "pygments_lexer": "ipython3",
128
+ "version": "3.12.11"
129
+ }
130
+ },
131
+ "nbformat": 4,
132
+ "nbformat_minor": 5
133
+ }
community_contributions/1_psvasan/day1_exercise.ipynb ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 2,
6
+ "id": "73a4a1cd",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "# Imports required for this exercise\n",
11
+ "from dotenv import load_dotenv\n",
12
+ "import os\n",
13
+ "from openai import OpenAI\n",
14
+ "from IPython.display import Markdown,display"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": 3,
20
+ "id": "be280e57",
21
+ "metadata": {},
22
+ "outputs": [
23
+ {
24
+ "data": {
25
+ "text/plain": [
26
+ "True"
27
+ ]
28
+ },
29
+ "execution_count": 3,
30
+ "metadata": {},
31
+ "output_type": "execute_result"
32
+ }
33
+ ],
34
+ "source": [
35
+ "# load the env variables from \".env\" file\n",
36
+ "load_dotenv(override=True)"
37
+ ]
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "execution_count": 4,
42
+ "id": "cc673c30",
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "# Check if the API key is set\n",
47
+ "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
48
+ "if not api_key:\n",
49
+ " raise ValueError(\"OPENAI_API_KEY is not set!!\")"
50
+ ]
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "execution_count": 5,
55
+ "id": "c574ee90",
56
+ "metadata": {},
57
+ "outputs": [],
58
+ "source": [
59
+ "# Create an instance of the openai python client\n",
60
+ "openai_client = OpenAI()"
61
+ ]
62
+ },
63
+ {
64
+ "cell_type": "code",
65
+ "execution_count": null,
66
+ "id": "da2d3820",
67
+ "metadata": {},
68
+ "outputs": [],
69
+ "source": [
70
+ "# First ask LLM to identify the most important pain point in the Cybersecurity domain that companies need to\n",
71
+ "# focus on in 2026\n",
72
+ "message = \"\"\"\n",
73
+ "What is one top area for cybersecurity organizations to focus on in 2026? Limit your answer to 3-5 sentences.\n",
74
+ "Only return the top pain point and no additional details on solution. Respond in markdown without code blocks.\n",
75
+ "\"\"\"\n",
76
+ "messages = [\n",
77
+ " {\"role\": \"user\", \"content\": message}\n",
78
+ "]\n",
79
+ "\n",
80
+ "MODEL_NAME=\"gpt-4o-mini\"\n",
81
+ "\n",
82
+ "response = openai_client.chat.completions.create(\n",
83
+ " model=MODEL_NAME,\n",
84
+ " messages=messages\n",
85
+ ")\n",
86
+ "\n",
87
+ "painpoint = response.choices[0].message.content\n",
88
+ "display(Markdown(painpoint))"
89
+ ]
90
+ }
91
+ ],
92
+ "metadata": {
93
+ "kernelspec": {
94
+ "display_name": ".venv",
95
+ "language": "python",
96
+ "name": "python3"
97
+ },
98
+ "language_info": {
99
+ "codemirror_mode": {
100
+ "name": "ipython",
101
+ "version": 3
102
+ },
103
+ "file_extension": ".py",
104
+ "mimetype": "text/x-python",
105
+ "name": "python",
106
+ "nbconvert_exporter": "python",
107
+ "pygments_lexer": "ipython3",
108
+ "version": "3.12.12"
109
+ }
110
+ },
111
+ "nbformat": 4,
112
+ "nbformat_minor": 5
113
+ }
community_contributions/2_lab2-Evaluator-AnnpaS18.ipynb ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\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
+ "# 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": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "# Always remember to do this!\n",
53
+ "load_dotenv(override=True)"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": null,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "# Print the key prefixes to help with any debugging\n",
63
+ "\n",
64
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
65
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
66
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
67
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
68
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
69
+ "\n",
70
+ "if openai_api_key:\n",
71
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
72
+ "else:\n",
73
+ " print(\"OpenAI API Key not set\")\n",
74
+ " \n",
75
+ "if anthropic_api_key:\n",
76
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
77
+ "else:\n",
78
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
79
+ "\n",
80
+ "if google_api_key:\n",
81
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
82
+ "else:\n",
83
+ " print(\"Google API Key not set (and this is optional)\")\n",
84
+ "\n",
85
+ "if deepseek_api_key:\n",
86
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
87
+ "else:\n",
88
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
89
+ "\n",
90
+ "if groq_api_key:\n",
91
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
92
+ "else:\n",
93
+ " print(\"Groq API Key not set (and this is optional)\")"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": 4,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
103
+ "request += \"Answer only with the question, no explanation.\"\n",
104
+ "messages = [{\"role\": \"user\", \"content\": request}]"
105
+ ]
106
+ },
107
+ {
108
+ "cell_type": "code",
109
+ "execution_count": null,
110
+ "metadata": {},
111
+ "outputs": [],
112
+ "source": [
113
+ "messages"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": null,
119
+ "metadata": {},
120
+ "outputs": [],
121
+ "source": [
122
+ "openai = OpenAI()\n",
123
+ "response = openai.chat.completions.create(\n",
124
+ " model=\"gpt-4o-mini\",\n",
125
+ " messages=messages,\n",
126
+ ")\n",
127
+ "question = response.choices[0].message.content\n",
128
+ "print(question)\n"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": 7,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "competitors = []\n",
138
+ "answers = []\n",
139
+ "messages = [{\"role\": \"user\", \"content\": question}]"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# The API we know well\n",
149
+ "\n",
150
+ "model_name = \"gpt-4o-mini\"\n",
151
+ "\n",
152
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
153
+ "answer = response.choices[0].message.content\n",
154
+ "\n",
155
+ "display(Markdown(answer))\n",
156
+ "competitors.append(model_name)\n",
157
+ "answers.append(answer)"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
167
+ "\n",
168
+ "model_name = \"claude-3-7-sonnet-latest\"\n",
169
+ "\n",
170
+ "claude = Anthropic()\n",
171
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
172
+ "answer = response.content[0].text\n",
173
+ "\n",
174
+ "display(Markdown(answer))\n",
175
+ "competitors.append(model_name)\n",
176
+ "answers.append(answer)"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": null,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
186
+ "model_name = \"gemini-2.0-flash\"\n",
187
+ "\n",
188
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
189
+ "answer = response.choices[0].message.content\n",
190
+ "\n",
191
+ "display(Markdown(answer))\n",
192
+ "competitors.append(model_name)\n",
193
+ "answers.append(answer)"
194
+ ]
195
+ },
196
+ {
197
+ "cell_type": "code",
198
+ "execution_count": null,
199
+ "metadata": {},
200
+ "outputs": [],
201
+ "source": [
202
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
203
+ "model_name = \"deepseek-chat\"\n",
204
+ "\n",
205
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
206
+ "answer = response.choices[0].message.content\n",
207
+ "\n",
208
+ "display(Markdown(answer))\n",
209
+ "competitors.append(model_name)\n",
210
+ "answers.append(answer)"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "code",
215
+ "execution_count": null,
216
+ "metadata": {},
217
+ "outputs": [],
218
+ "source": [
219
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
220
+ "model_name = \"llama-3.3-70b-versatile\"\n",
221
+ "\n",
222
+ "response = groq.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)\n"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "markdown",
232
+ "metadata": {},
233
+ "source": [
234
+ "## For the next cell, we will use Ollama\n",
235
+ "\n",
236
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
237
+ "and runs models locally using high performance C++ code.\n",
238
+ "\n",
239
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
240
+ "\n",
241
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
242
+ "\n",
243
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
244
+ "\n",
245
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
246
+ "\n",
247
+ "`ollama pull <model_name>` downloads a model locally \n",
248
+ "`ollama ls` lists all the models you've downloaded \n",
249
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
250
+ ]
251
+ },
252
+ {
253
+ "cell_type": "markdown",
254
+ "metadata": {},
255
+ "source": [
256
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
257
+ " <tr>\n",
258
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
259
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
260
+ " </td>\n",
261
+ " <td>\n",
262
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
263
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
264
+ " </span>\n",
265
+ " </td>\n",
266
+ " </tr>\n",
267
+ "</table>"
268
+ ]
269
+ },
270
+ {
271
+ "cell_type": "code",
272
+ "execution_count": null,
273
+ "metadata": {},
274
+ "outputs": [],
275
+ "source": [
276
+ "!ollama pull llama3.2"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": null,
282
+ "metadata": {},
283
+ "outputs": [],
284
+ "source": [
285
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
286
+ "model_name = \"llama3.2\"\n",
287
+ "\n",
288
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
289
+ "answer = response.choices[0].message.content\n",
290
+ "\n",
291
+ "display(Markdown(answer))\n",
292
+ "competitors.append(model_name)\n",
293
+ "answers.append(answer)"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type": "code",
298
+ "execution_count": null,
299
+ "metadata": {},
300
+ "outputs": [],
301
+ "source": [
302
+ "# So where are we?\n",
303
+ "\n",
304
+ "print(competitors)\n",
305
+ "print(answers)\n"
306
+ ]
307
+ },
308
+ {
309
+ "cell_type": "code",
310
+ "execution_count": null,
311
+ "metadata": {},
312
+ "outputs": [],
313
+ "source": [
314
+ "# It's nice to know how to use \"zip\"\n",
315
+ "for competitor, answer in zip(competitors, answers):\n",
316
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": 20,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# Let's bring this together - note the use of \"enumerate\"\n",
326
+ "\n",
327
+ "together = \"\"\n",
328
+ "for index, answer in enumerate(answers):\n",
329
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
330
+ " together += answer + \"\\n\\n\""
331
+ ]
332
+ },
333
+ {
334
+ "cell_type": "code",
335
+ "execution_count": null,
336
+ "metadata": {},
337
+ "outputs": [],
338
+ "source": [
339
+ "print(together)"
340
+ ]
341
+ },
342
+ {
343
+ "cell_type": "code",
344
+ "execution_count": 22,
345
+ "metadata": {},
346
+ "outputs": [],
347
+ "source": [
348
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
349
+ "Each model has been given this question:\n",
350
+ "\n",
351
+ "{question}\n",
352
+ "\n",
353
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
354
+ "Respond with JSON, and only JSON, with the following format:\n",
355
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
356
+ "\n",
357
+ "Here are the responses from each competitor:\n",
358
+ "\n",
359
+ "{together}\n",
360
+ "\n",
361
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
362
+ ]
363
+ },
364
+ {
365
+ "cell_type": "code",
366
+ "execution_count": null,
367
+ "metadata": {},
368
+ "outputs": [],
369
+ "source": [
370
+ "print(judge)"
371
+ ]
372
+ },
373
+ {
374
+ "cell_type": "code",
375
+ "execution_count": 29,
376
+ "metadata": {},
377
+ "outputs": [],
378
+ "source": [
379
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
380
+ ]
381
+ },
382
+ {
383
+ "cell_type": "code",
384
+ "execution_count": null,
385
+ "metadata": {},
386
+ "outputs": [],
387
+ "source": [
388
+ "# Judgement time!\n",
389
+ "\n",
390
+ "openai = OpenAI()\n",
391
+ "response = openai.chat.completions.create(\n",
392
+ " model=\"o3-mini\",\n",
393
+ " messages=judge_messages,\n",
394
+ ")\n",
395
+ "results = response.choices[0].message.content\n",
396
+ "print(results)\n"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "code",
401
+ "execution_count": null,
402
+ "metadata": {},
403
+ "outputs": [],
404
+ "source": [
405
+ "# OK let's turn this into results!\n",
406
+ "\n",
407
+ "results_dict = json.loads(results)\n",
408
+ "ranks = results_dict[\"results\"]\n",
409
+ "for index, result in enumerate(ranks):\n",
410
+ " competitor = competitors[int(result)-1]\n",
411
+ " print(f\"Rank {index+1}: {competitor}\")"
412
+ ]
413
+ },
414
+ {
415
+ "cell_type": "markdown",
416
+ "metadata": {},
417
+ "source": [
418
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
419
+ " <tr>\n",
420
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
421
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
422
+ " </td>\n",
423
+ " <td>\n",
424
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
425
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
426
+ " </span>\n",
427
+ " </td>\n",
428
+ " </tr>\n",
429
+ "</table>"
430
+ ]
431
+ },
432
+ {
433
+ "cell_type": "markdown",
434
+ "metadata": {},
435
+ "source": [
436
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
437
+ " <tr>\n",
438
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
439
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
440
+ " </td>\n",
441
+ " <td>\n",
442
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
443
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
444
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
445
+ " to business projects where accuracy is critical.\n",
446
+ " </span>\n",
447
+ " </td>\n",
448
+ " </tr>\n",
449
+ "</table>"
450
+ ]
451
+ }
452
+ ],
453
+ "metadata": {
454
+ "kernelspec": {
455
+ "display_name": ".venv",
456
+ "language": "python",
457
+ "name": "python3"
458
+ },
459
+ "language_info": {
460
+ "codemirror_mode": {
461
+ "name": "ipython",
462
+ "version": 3
463
+ },
464
+ "file_extension": ".py",
465
+ "mimetype": "text/x-python",
466
+ "name": "python",
467
+ "nbconvert_exporter": "python",
468
+ "pygments_lexer": "ipython3",
469
+ "version": "3.12.9"
470
+ }
471
+ },
472
+ "nbformat": 4,
473
+ "nbformat_minor": 2
474
+ }
community_contributions/2_lab2-judge-prompt-changed.ipynb ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\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
+ "# 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": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "# Always remember to do this!\n",
53
+ "load_dotenv(override=True)"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": null,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "# Print the key prefixes to help with any debugging\n",
63
+ "\n",
64
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
65
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
66
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
67
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
68
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
69
+ "\n",
70
+ "if openai_api_key:\n",
71
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
72
+ "else:\n",
73
+ " print(\"OpenAI API Key not set\")\n",
74
+ " \n",
75
+ "if anthropic_api_key:\n",
76
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
77
+ "else:\n",
78
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
79
+ "\n",
80
+ "if google_api_key:\n",
81
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
82
+ "else:\n",
83
+ " print(\"Google API Key not set (and this is optional)\")\n",
84
+ "\n",
85
+ "if deepseek_api_key:\n",
86
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
87
+ "else:\n",
88
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
89
+ "\n",
90
+ "if groq_api_key:\n",
91
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
92
+ "else:\n",
93
+ " print(\"Groq API Key not set (and this is optional)\")"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": 4,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
103
+ "request += \"Answer only with the question, no explanation.\"\n",
104
+ "messages = [{\"role\": \"user\", \"content\": request}]"
105
+ ]
106
+ },
107
+ {
108
+ "cell_type": "code",
109
+ "execution_count": null,
110
+ "metadata": {},
111
+ "outputs": [],
112
+ "source": [
113
+ "messages"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": null,
119
+ "metadata": {},
120
+ "outputs": [],
121
+ "source": [
122
+ "openai = OpenAI()\n",
123
+ "response = openai.chat.completions.create(\n",
124
+ " model=\"gpt-4o-mini\",\n",
125
+ " messages=messages,\n",
126
+ ")\n",
127
+ "question = response.choices[0].message.content\n",
128
+ "print(question)\n"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": 7,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "competitors = []\n",
138
+ "answers = []\n",
139
+ "messages = [{\"role\": \"user\", \"content\": question}]"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": null,
145
+ "metadata": {},
146
+ "outputs": [],
147
+ "source": [
148
+ "# The API we know well\n",
149
+ "\n",
150
+ "model_name = \"gpt-4o-mini\"\n",
151
+ "\n",
152
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
153
+ "answer = response.choices[0].message.content\n",
154
+ "\n",
155
+ "display(Markdown(answer))\n",
156
+ "competitors.append(model_name)\n",
157
+ "answers.append(answer)"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
167
+ "\n",
168
+ "model_name = \"claude-3-7-sonnet-latest\"\n",
169
+ "\n",
170
+ "claude = Anthropic()\n",
171
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
172
+ "answer = response.content[0].text\n",
173
+ "\n",
174
+ "display(Markdown(answer))\n",
175
+ "competitors.append(model_name)\n",
176
+ "answers.append(answer)"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": null,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
186
+ "model_name = \"gemini-2.0-flash\"\n",
187
+ "\n",
188
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
189
+ "answer = response.choices[0].message.content\n",
190
+ "\n",
191
+ "display(Markdown(answer))\n",
192
+ "competitors.append(model_name)\n",
193
+ "answers.append(answer)"
194
+ ]
195
+ },
196
+ {
197
+ "cell_type": "code",
198
+ "execution_count": null,
199
+ "metadata": {},
200
+ "outputs": [],
201
+ "source": [
202
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
203
+ "model_name = \"deepseek-chat\"\n",
204
+ "\n",
205
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
206
+ "answer = response.choices[0].message.content\n",
207
+ "\n",
208
+ "display(Markdown(answer))\n",
209
+ "competitors.append(model_name)\n",
210
+ "answers.append(answer)"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "code",
215
+ "execution_count": null,
216
+ "metadata": {},
217
+ "outputs": [],
218
+ "source": [
219
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
220
+ "model_name = \"llama-3.3-70b-versatile\"\n",
221
+ "\n",
222
+ "response = groq.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)\n"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "markdown",
232
+ "metadata": {},
233
+ "source": [
234
+ "## For the next cell, we will use Ollama\n",
235
+ "\n",
236
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
237
+ "and runs models locally using high performance C++ code.\n",
238
+ "\n",
239
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
240
+ "\n",
241
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
242
+ "\n",
243
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
244
+ "\n",
245
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
246
+ "\n",
247
+ "`ollama pull <model_name>` downloads a model locally \n",
248
+ "`ollama ls` lists all the models you've downloaded \n",
249
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
250
+ ]
251
+ },
252
+ {
253
+ "cell_type": "markdown",
254
+ "metadata": {},
255
+ "source": [
256
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
257
+ " <tr>\n",
258
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
259
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
260
+ " </td>\n",
261
+ " <td>\n",
262
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
263
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
264
+ " </span>\n",
265
+ " </td>\n",
266
+ " </tr>\n",
267
+ "</table>"
268
+ ]
269
+ },
270
+ {
271
+ "cell_type": "code",
272
+ "execution_count": null,
273
+ "metadata": {},
274
+ "outputs": [],
275
+ "source": [
276
+ "!ollama pull llama3.2"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": null,
282
+ "metadata": {},
283
+ "outputs": [],
284
+ "source": [
285
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
286
+ "model_name = \"llama3.2\"\n",
287
+ "\n",
288
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
289
+ "answer = response.choices[0].message.content\n",
290
+ "\n",
291
+ "display(Markdown(answer))\n",
292
+ "competitors.append(model_name)\n",
293
+ "answers.append(answer)"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type": "code",
298
+ "execution_count": null,
299
+ "metadata": {},
300
+ "outputs": [],
301
+ "source": [
302
+ "# So where are we?\n",
303
+ "\n",
304
+ "print(competitors)\n",
305
+ "print(answers)\n"
306
+ ]
307
+ },
308
+ {
309
+ "cell_type": "code",
310
+ "execution_count": null,
311
+ "metadata": {},
312
+ "outputs": [],
313
+ "source": [
314
+ "# It's nice to know how to use \"zip\"\n",
315
+ "for competitor, answer in zip(competitors, answers):\n",
316
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": 20,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "# Let's bring this together - note the use of \"enumerate\"\n",
326
+ "\n",
327
+ "together = \"\"\n",
328
+ "for index, answer in enumerate(answers):\n",
329
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
330
+ " together += answer + \"\\n\\n\""
331
+ ]
332
+ },
333
+ {
334
+ "cell_type": "code",
335
+ "execution_count": null,
336
+ "metadata": {},
337
+ "outputs": [],
338
+ "source": [
339
+ "print(together)"
340
+ ]
341
+ },
342
+ {
343
+ "cell_type": "code",
344
+ "execution_count": null,
345
+ "metadata": {},
346
+ "outputs": [],
347
+ "source": [
348
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
349
+ "Each model has been given this question:\n",
350
+ "\n",
351
+ "{question}\n",
352
+ "\n",
353
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
354
+ "Respond with JSON, and only JSON, with the following format:\n",
355
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
356
+ "Answer only the number for example\n",
357
+ "{{\"results\": [\"1\", \"2\", \"3\", ...]}}\n",
358
+ "\n",
359
+ "Here are the responses from each competitor:\n",
360
+ "\n",
361
+ "{together}\n",
362
+ "\n",
363
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
364
+ ]
365
+ },
366
+ {
367
+ "cell_type": "code",
368
+ "execution_count": null,
369
+ "metadata": {},
370
+ "outputs": [],
371
+ "source": [
372
+ "print(judge)"
373
+ ]
374
+ },
375
+ {
376
+ "cell_type": "code",
377
+ "execution_count": 29,
378
+ "metadata": {},
379
+ "outputs": [],
380
+ "source": [
381
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
382
+ ]
383
+ },
384
+ {
385
+ "cell_type": "code",
386
+ "execution_count": null,
387
+ "metadata": {},
388
+ "outputs": [],
389
+ "source": [
390
+ "# Judgement time!\n",
391
+ "\n",
392
+ "openai = OpenAI()\n",
393
+ "response = openai.chat.completions.create(\n",
394
+ " model=\"o3-mini\",\n",
395
+ " messages=judge_messages,\n",
396
+ ")\n",
397
+ "results = response.choices[0].message.content\n",
398
+ "print(results)\n"
399
+ ]
400
+ },
401
+ {
402
+ "cell_type": "code",
403
+ "execution_count": null,
404
+ "metadata": {},
405
+ "outputs": [],
406
+ "source": [
407
+ "# OK let's turn this into results!\n",
408
+ "\n",
409
+ "results_dict = json.loads(results)\n",
410
+ "ranks = results_dict[\"results\"]\n",
411
+ "for index, result in enumerate(ranks):\n",
412
+ " competitor = competitors[int(result)-1]\n",
413
+ " print(f\"Rank {index+1}: {competitor}\")"
414
+ ]
415
+ },
416
+ {
417
+ "cell_type": "markdown",
418
+ "metadata": {},
419
+ "source": [
420
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
421
+ " <tr>\n",
422
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
423
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
424
+ " </td>\n",
425
+ " <td>\n",
426
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
427
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
428
+ " </span>\n",
429
+ " </td>\n",
430
+ " </tr>\n",
431
+ "</table>"
432
+ ]
433
+ },
434
+ {
435
+ "cell_type": "markdown",
436
+ "metadata": {},
437
+ "source": [
438
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
439
+ " <tr>\n",
440
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
441
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
442
+ " </td>\n",
443
+ " <td>\n",
444
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
445
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
446
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
447
+ " to business projects where accuracy is critical.\n",
448
+ " </span>\n",
449
+ " </td>\n",
450
+ " </tr>\n",
451
+ "</table>"
452
+ ]
453
+ }
454
+ ],
455
+ "metadata": {
456
+ "kernelspec": {
457
+ "display_name": ".venv",
458
+ "language": "python",
459
+ "name": "python3"
460
+ },
461
+ "language_info": {
462
+ "codemirror_mode": {
463
+ "name": "ipython",
464
+ "version": 3
465
+ },
466
+ "file_extension": ".py",
467
+ "mimetype": "text/x-python",
468
+ "name": "python",
469
+ "nbconvert_exporter": "python",
470
+ "pygments_lexer": "ipython3",
471
+ "version": "3.12.9"
472
+ }
473
+ },
474
+ "nbformat": 4,
475
+ "nbformat_minor": 2
476
+ }
community_contributions/2_lab2-nv-orch-worker-pattern.ipynb ADDED
@@ -0,0 +1,727 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Lab 3: Orchestrator-Worker Pattern\n",
8
+ "\n",
9
+ "This notebook implements the **Orchestrator-Worker Pattern** with **Parallel Execution**:\n",
10
+ "\n",
11
+ "1. **Orchestrator LLM**: Decides which worker models to call based on the question\n",
12
+ "2. **Worker Models**: Selected models run **simultaneously** in parallel using async/await\n",
13
+ "3. **Synthesizer LLM**: Aggregates outputs, synthesizes a final answer, and ranks the workers\n",
14
+ "\n",
15
+ "## Pattern Flow\n",
16
+ "\n",
17
+ "```\n",
18
+ "User Question → Orchestrator LLM (\"Which workers to use?\")\n",
19
+ " ↓\n",
20
+ "Parallel Worker API Calls (Only selected models)\n",
21
+ " ↓\n",
22
+ "Synthesizer LLM (Merge + Rank)\n",
23
+ " ↓\n",
24
+ "Final Answer + Worker Rankings\n",
25
+ "```\n",
26
+ "\n",
27
+ "The **LLM orchestrator** replaces hardcoded model selection with intelligent routing."
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": null,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# Start with imports - ask ChatGPT to explain any package you don't know\n",
37
+ "\n",
38
+ "import os\n",
39
+ "import json\n",
40
+ "import asyncio\n",
41
+ "import random\n",
42
+ "from datetime import datetime, timedelta\n",
43
+ "from typing import Dict, List, Any, Tuple\n",
44
+ "from dotenv import load_dotenv\n",
45
+ "from openai import OpenAI\n",
46
+ "from anthropic import Anthropic\n",
47
+ "from IPython.display import Markdown, display\n",
48
+ "import textwrap"
49
+ ]
50
+ },
51
+ {
52
+ "cell_type": "code",
53
+ "execution_count": null,
54
+ "metadata": {},
55
+ "outputs": [],
56
+ "source": [
57
+ "# Always remember to do this!\n",
58
+ "load_dotenv(override=True)"
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "code",
63
+ "execution_count": null,
64
+ "metadata": {},
65
+ "outputs": [],
66
+ "source": [
67
+ "# Print the key prefixes to help with any debugging\n",
68
+ "\n",
69
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
70
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
71
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
72
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
73
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
74
+ "\n",
75
+ "if openai_api_key:\n",
76
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
77
+ "else:\n",
78
+ " print(\"OpenAI API Key not set\")\n",
79
+ " \n",
80
+ "if anthropic_api_key:\n",
81
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
82
+ "else:\n",
83
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
84
+ "\n",
85
+ "if google_api_key:\n",
86
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
87
+ "else:\n",
88
+ " print(\"Google API Key not set (and this is optional)\")\n",
89
+ "\n",
90
+ "if deepseek_api_key:\n",
91
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
92
+ "else:\n",
93
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
94
+ "\n",
95
+ "if groq_api_key:\n",
96
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
97
+ "else:\n",
98
+ " print(\"Groq API Key not set (and this is optional)\")"
99
+ ]
100
+ },
101
+ {
102
+ "cell_type": "markdown",
103
+ "metadata": {},
104
+ "source": [
105
+ "## Step 1: Generate Evaluation Question\n",
106
+ "\n",
107
+ "First, generate a challenging question to test all the worker models."
108
+ ]
109
+ },
110
+ {
111
+ "cell_type": "code",
112
+ "execution_count": null,
113
+ "metadata": {},
114
+ "outputs": [],
115
+ "source": [
116
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
117
+ "request += \"Answer only with the question, no explanation.\"\n",
118
+ "messages = [{\"role\": \"user\", \"content\": request}]"
119
+ ]
120
+ },
121
+ {
122
+ "cell_type": "code",
123
+ "execution_count": null,
124
+ "metadata": {},
125
+ "outputs": [],
126
+ "source": [
127
+ "openai = OpenAI()\n",
128
+ "response = openai.chat.completions.create(\n",
129
+ " model=\"gpt-4o-mini\",\n",
130
+ " messages=messages,\n",
131
+ ")\n",
132
+ "question = response.choices[0].message.content\n",
133
+ "print(question)"
134
+ ]
135
+ },
136
+ {
137
+ "cell_type": "markdown",
138
+ "metadata": {},
139
+ "source": [
140
+ "## Step 2: Prepare Worker Configurations\n",
141
+ "\n",
142
+ "Prepare all available **worker** model configurations that the orchestrator can choose from."
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "code",
147
+ "execution_count": null,
148
+ "metadata": {},
149
+ "outputs": [],
150
+ "source": [
151
+ "# ==========================================\n",
152
+ "# Worker Preparation: All Available Models\n",
153
+ "# ==========================================\n",
154
+ "\n",
155
+ "def evaluator_prepare_configs():\n",
156
+ " \"\"\"\n",
157
+ " Evaluator: Gathers API keys and prepares configurations for all models.\n",
158
+ " Returns a list of model configurations ready for parallel execution.\n",
159
+ " \"\"\"\n",
160
+ " configs = []\n",
161
+ " \n",
162
+ " # Model 1: OpenAI\n",
163
+ " configs.append({\n",
164
+ " \"model_name\": \"gpt-5-nano\",\n",
165
+ " \"provider\": \"openai\",\n",
166
+ " \"client\": OpenAI(),\n",
167
+ " \"call_type\": \"chat.completions\",\n",
168
+ " \"extra_params\": {}\n",
169
+ " })\n",
170
+ " \n",
171
+ " # Model 2: Anthropic\n",
172
+ " configs.append({\n",
173
+ " \"model_name\": \"claude-sonnet-4-5\",\n",
174
+ " \"provider\": \"anthropic\",\n",
175
+ " \"client\": Anthropic(),\n",
176
+ " \"call_type\": \"messages.create\",\n",
177
+ " \"extra_params\": {\"max_tokens\": 1000}\n",
178
+ " })\n",
179
+ " \n",
180
+ " # Model 3: Gemini\n",
181
+ " configs.append({\n",
182
+ " \"model_name\": \"gemini-2.5-flash\",\n",
183
+ " \"provider\": \"gemini\",\n",
184
+ " \"client\": OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"),\n",
185
+ " \"call_type\": \"chat.completions\",\n",
186
+ " \"extra_params\": {}\n",
187
+ " })\n",
188
+ " \n",
189
+ " # Model 4: DeepSeek\n",
190
+ " configs.append({\n",
191
+ " \"model_name\": \"deepseek/deepseek-r1-0528:free\",\n",
192
+ " \"provider\": \"deepseek\",\n",
193
+ " \"client\": OpenAI(api_key=deepseek_api_key, base_url=\"https://openrouter.ai/api/v1\"),\n",
194
+ " \"call_type\": \"chat.completions\",\n",
195
+ " \"extra_params\": {}\n",
196
+ " })\n",
197
+ " \n",
198
+ " # Model 5: Groq\n",
199
+ " configs.append({\n",
200
+ " \"model_name\": \"openai/gpt-oss-120b\",\n",
201
+ " \"provider\": \"groq\",\n",
202
+ " \"client\": OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\"),\n",
203
+ " \"call_type\": \"chat.completions\",\n",
204
+ " \"extra_params\": {}\n",
205
+ " })\n",
206
+ " \n",
207
+ " # Model 6: Ollama (if available)\n",
208
+ " configs.append({\n",
209
+ " \"model_name\": \"llama3.2\",\n",
210
+ " \"provider\": \"ollama\",\n",
211
+ " \"client\": OpenAI(base_url='http://localhost:11434/v1', api_key='ollama'),\n",
212
+ " \"call_type\": \"chat.completions\",\n",
213
+ " \"extra_params\": {}\n",
214
+ " })\n",
215
+ " \n",
216
+ " print(f\"✅ Evaluator prepared {len(configs)} model configurations\")\n",
217
+ " return configs\n",
218
+ "\n",
219
+ "# Prepare global config dictionaries\n",
220
+ "MODEL_CONFIGS = evaluator_prepare_configs()\n",
221
+ "MODEL_CONFIGS_BY_NAME = {cfg[\"model_name\"]: cfg for cfg in MODEL_CONFIGS}"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "markdown",
226
+ "metadata": {},
227
+ "source": [
228
+ "## Step 3: Orchestrator LLM - Decide Which Workers to Use\n",
229
+ "\n",
230
+ "The **orchestrator LLM** analyzes the question and selects which worker models to invoke in parallel."
231
+ ]
232
+ },
233
+ {
234
+ "cell_type": "code",
235
+ "execution_count": null,
236
+ "metadata": {},
237
+ "outputs": [],
238
+ "source": [
239
+ "# ==========================================\n",
240
+ "# Orchestrator: LLM Decides Worker Selection\n",
241
+ "# ==========================================\n",
242
+ "\n",
243
+ "def list_worker_tools():\n",
244
+ " \"\"\"Return tool descriptions for the orchestrator LLM.\"\"\"\n",
245
+ " tools = []\n",
246
+ " for cfg in MODEL_CONFIGS:\n",
247
+ " tools.append({\n",
248
+ " \"name\": cfg[\"model_name\"],\n",
249
+ " \"description\": f\"Call the {cfg['provider']} model {cfg['model_name']} \"\n",
250
+ " \"to answer the user question.\",\n",
251
+ " \"parameters\": {\n",
252
+ " \"type\": \"object\",\n",
253
+ " \"properties\": {\n",
254
+ " \"reason\": {\n",
255
+ " \"type\": \"string\",\n",
256
+ " \"description\": \"Why this model is useful for this query.\"\n",
257
+ " }\n",
258
+ " },\n",
259
+ " \"required\": [\"reason\"]\n",
260
+ " }\n",
261
+ " })\n",
262
+ " return tools\n",
263
+ "\n",
264
+ "def build_orchestrator_prompt(user_question: str, tools: list) -> list:\n",
265
+ " tool_descriptions = \"\\n\".join(\n",
266
+ " f\"- {t['name']}: {t['description']}\" for t in tools\n",
267
+ " )\n",
268
+ "\n",
269
+ " system_msg = textwrap.dedent(f\"\"\"\n",
270
+ " You are an **orchestrator** LLM in an orchestrator–worker system.\n",
271
+ "\n",
272
+ " You do NOT answer the user's question directly.\n",
273
+ " Instead, you decide which worker models to call in parallel.\n",
274
+ "\n",
275
+ " Available workers:\n",
276
+ " {tool_descriptions}\n",
277
+ "\n",
278
+ " Output STRICTLY valid JSON:\n",
279
+ " {{\n",
280
+ " \"models_to_call\": [\n",
281
+ " {{\"name\": \"<model_name>\", \"reason\": \"<short reason>\"}},\n",
282
+ " ...\n",
283
+ " ]\n",
284
+ " }}\n",
285
+ "\n",
286
+ " Requirements:\n",
287
+ " - Choose at least 3 and at most 6 models.\n",
288
+ " - Use model names exactly as listed.\n",
289
+ " - Prefer diversity (different providers) for hard reasoning tasks.\n",
290
+ " - Do not include any fields other than \"models_to_call\".\n",
291
+ " \"\"\")\n",
292
+ "\n",
293
+ " return [\n",
294
+ " {\"role\": \"system\", \"content\": system_msg},\n",
295
+ " {\"role\": \"user\", \"content\": user_question},\n",
296
+ " ]\n",
297
+ "\n",
298
+ "def orchestrator_plan(user_question: str) -> list:\n",
299
+ " \"\"\"\n",
300
+ " Ask the orchestrator LLM which workers to use.\n",
301
+ " Returns list of selected model names.\n",
302
+ " \"\"\"\n",
303
+ " tools = list_worker_tools()\n",
304
+ " messages = build_orchestrator_prompt(user_question, tools)\n",
305
+ "\n",
306
+ " openai = OpenAI()\n",
307
+ " resp = openai.chat.completions.create(\n",
308
+ " model=\"gpt-4o-mini\",\n",
309
+ " # model=\"gemini-1.5-flash\",\n",
310
+ " messages=messages,\n",
311
+ " temperature=0.2,\n",
312
+ " )\n",
313
+ " content = resp.choices[0].message.content\n",
314
+ " plan = json.loads(content)\n",
315
+ " selected = [m[\"name\"] for m in plan.get(\"models_to_call\", [])]\n",
316
+ " print(f\"🎯 Orchestrator selected {len(selected)} workers: {selected}\")\n",
317
+ " return selected"
318
+ ]
319
+ },
320
+ {
321
+ "cell_type": "markdown",
322
+ "metadata": {},
323
+ "source": [
324
+ "## Step 4: Parallel Worker Execution\n",
325
+ "\n",
326
+ "Execute **only the selected workers** simultaneously using async/await."
327
+ ]
328
+ },
329
+ {
330
+ "cell_type": "code",
331
+ "execution_count": null,
332
+ "metadata": {},
333
+ "outputs": [],
334
+ "source": [
335
+ "# ==========================================\n",
336
+ "# Worker Execution: Async Single Model Call\n",
337
+ "# ==========================================\n",
338
+ "\n",
339
+ "async def call_model_async(config: Dict[str, Any], messages: List[Dict]) -> Tuple[str, str]:\n",
340
+ " \"\"\"\n",
341
+ " Call a single worker model asynchronously.\n",
342
+ " Returns (model_name, answer) or (model_name, error_message).\n",
343
+ " \"\"\"\n",
344
+ " model_name = config[\"model_name\"]\n",
345
+ " provider = config[\"provider\"]\n",
346
+ " client = config[\"client\"]\n",
347
+ " call_type = config[\"call_type\"]\n",
348
+ " extra_params = config[\"extra_params\"]\n",
349
+ " \n",
350
+ " try:\n",
351
+ " if provider == \"anthropic\":\n",
352
+ " # Anthropic uses a different API structure\n",
353
+ " response = await asyncio.to_thread(\n",
354
+ " client.messages.create,\n",
355
+ " model=model_name,\n",
356
+ " messages=messages,\n",
357
+ " **extra_params\n",
358
+ " )\n",
359
+ " answer = response.content[0].text\n",
360
+ " else:\n",
361
+ " # OpenAI-compatible APIs\n",
362
+ " response = await asyncio.to_thread(\n",
363
+ " client.chat.completions.create,\n",
364
+ " model=model_name,\n",
365
+ " messages=messages,\n",
366
+ " **extra_params\n",
367
+ " )\n",
368
+ " answer = response.choices[0].message.content\n",
369
+ " \n",
370
+ " print(f\"✅ {model_name} completed\")\n",
371
+ " return model_name, answer\n",
372
+ " \n",
373
+ " except Exception as e:\n",
374
+ " error_msg = f\"Error calling {model_name}: {str(e)}\"\n",
375
+ " print(f\"❌ {error_msg}\")\n",
376
+ " return model_name, error_msg"
377
+ ]
378
+ },
379
+ {
380
+ "cell_type": "code",
381
+ "execution_count": null,
382
+ "metadata": {},
383
+ "outputs": [],
384
+ "source": [
385
+ "# ==========================================\n",
386
+ "# Parallel Worker Execution\n",
387
+ "# ==========================================\n",
388
+ "\n",
389
+ "def format_bytes(size: int) -> str:\n",
390
+ " \"\"\"Format bytes into a human-readable string (B, KB, MB).\"\"\"\n",
391
+ " for unit in ['B', 'KB', 'MB']:\n",
392
+ " if size < 1024.0:\n",
393
+ " return f\"{size:.2f} {unit}\"\n",
394
+ " size /= 1024.0\n",
395
+ " return f\"{size:.2f} GB\"\n",
396
+ "\n",
397
+ "async def execute_models_in_parallel(configs: List[Dict[str, Any]], messages: List[Dict]) -> Tuple[List[str], List[str]]:\n",
398
+ " \"\"\"\n",
399
+ " Execute selected worker models in parallel.\n",
400
+ " \"\"\"\n",
401
+ " print(f\"\\n🚀 Starting parallel execution of {len(configs)} selected workers...\\n\")\n",
402
+ " \n",
403
+ " table_rows = []\n",
404
+ " competitors = []\n",
405
+ " answers = []\n",
406
+ " \n",
407
+ " async def call_with_metrics(config):\n",
408
+ " model_name = config.get(\"model_name\", \"Unknown\")\n",
409
+ " start_time = datetime.now()\n",
410
+ " \n",
411
+ " try:\n",
412
+ " _, answer = await call_model_async(config, messages)\n",
413
+ " end_time = datetime.now()\n",
414
+ " \n",
415
+ " if isinstance(answer, str) and answer.startswith(\"Error\"):\n",
416
+ " status = \"❌ Error\"\n",
417
+ " out_size = 0\n",
418
+ " else:\n",
419
+ " status = \"✅ Success\"\n",
420
+ " out_size = len(str(answer).encode('utf-8'))\n",
421
+ " \n",
422
+ " except Exception as e:\n",
423
+ " end_time = datetime.now()\n",
424
+ " status = \"❌ Error\"\n",
425
+ " answer = str(e)\n",
426
+ " out_size = 0\n",
427
+ "\n",
428
+ " # Calculate duration\n",
429
+ " duration = end_time - start_time\n",
430
+ " total_seconds = int(duration.total_seconds())\n",
431
+ " mm, ss = divmod(total_seconds, 60)\n",
432
+ " hh, mm = divmod(mm, 60)\n",
433
+ " dur_str = f\"{hh:02d}:{mm:02d}:{ss:02d}\" if hh > 0 else f\"{mm:02d}:{ss:02d}\"\n",
434
+ "\n",
435
+ " # Store metrics for table\n",
436
+ " table_rows.append({\n",
437
+ " \"model\": model_name,\n",
438
+ " \"status\": status,\n",
439
+ " \"start\": start_time.strftime(\"%H:%M:%S\"),\n",
440
+ " \"end\": end_time.strftime(\"%H:%M:%S\"),\n",
441
+ " \"duration\": dur_str,\n",
442
+ " \"size\": format_bytes(out_size)\n",
443
+ " })\n",
444
+ " \n",
445
+ " return model_name, answer, status\n",
446
+ "\n",
447
+ " # Run tasks in parallel\n",
448
+ " tasks = [call_with_metrics(config) for config in configs]\n",
449
+ " results = await asyncio.gather(*tasks)\n",
450
+ "\n",
451
+ " # Process final lists\n",
452
+ " for model_name, answer, status in results:\n",
453
+ " if status == \"✅ Success\":\n",
454
+ " competitors.append(model_name)\n",
455
+ " answers.append(answer)\n",
456
+ "\n",
457
+ " # Print Tabular Output\n",
458
+ " header = f\"{'Model':<25} {'Status':<10} {'Start':<10} {'End':<10} {'Duration':<10} {'Size':<12}\"\n",
459
+ " print(header)\n",
460
+ " print(\"-\" * len(header))\n",
461
+ " for row in table_rows:\n",
462
+ " print(f\"{row['model']:<25} {row['status']:<10} {row['start']:<10} {row['end']:<10} {row['duration']:<10} {row['size']:<12}\")\n",
463
+ " \n",
464
+ " print(f\"\\n✅ Completed. {len(competitors)}/{len(configs)} workers successful.\")\n",
465
+ " return competitors, answers\n",
466
+ "\n",
467
+ "async def mock_execute_models_in_parallel(configs: List[Dict[str, Any]]) -> Tuple[List[str], List[str]]:\n",
468
+ " \"\"\"\n",
469
+ " Mocks parallel API calls to display timing and size metrics in a table.\n",
470
+ " No actual API calls are made.\n",
471
+ " \"\"\"\n",
472
+ " print(f\"\\n🚀 Starting MOCK execution of {len(configs)} models...\\n\")\n",
473
+ " \n",
474
+ " table_rows = []\n",
475
+ " competitors = []\n",
476
+ " answers = []\n",
477
+ "\n",
478
+ " async def mock_api_call(config):\n",
479
+ " model_name = config.get(\"model_name\", \"Unknown-Model\")\n",
480
+ " start_time = datetime.now()\n",
481
+ " \n",
482
+ " # Simulate varying network latency (0.5 to 2.5 seconds)\n",
483
+ " await asyncio.sleep(random.uniform(0.5, 2.5))\n",
484
+ " \n",
485
+ " # Randomly decide if this mock call \"fails\" (10% chance)\n",
486
+ " is_success = random.random() > 0.1\n",
487
+ " \n",
488
+ " if is_success:\n",
489
+ " status = \"✅ Success\"\n",
490
+ " # Mock a response string of random length\n",
491
+ " mock_answer = \"Mock response data \" * random.randint(5, 500)\n",
492
+ " out_size = len(mock_answer.encode('utf-8'))\n",
493
+ " else:\n",
494
+ " status = \"❌ Error\"\n",
495
+ " mock_answer = \"Error: Mocked API failure\"\n",
496
+ " out_size = 0\n",
497
+ " \n",
498
+ " end_time = datetime.now()\n",
499
+ " \n",
500
+ " # Calculate duration in mm:ss or hh:mm:ss\n",
501
+ " duration = end_time - start_time\n",
502
+ " total_seconds = int(duration.total_seconds())\n",
503
+ " mm, ss = divmod(total_seconds, 60)\n",
504
+ " hh, mm = divmod(mm, 60)\n",
505
+ " dur_str = f\"{hh:02d}:{mm:02d}:{ss:02d}\" if hh > 0 else f\"{mm:02d}:{ss:02d}\"\n",
506
+ "\n",
507
+ " # Record metrics for the final table\n",
508
+ " metrics = {\n",
509
+ " \"model\": model_name,\n",
510
+ " \"status\": status,\n",
511
+ " \"start\": start_time.strftime(\"%H:%M:%S\"),\n",
512
+ " \"end\": end_time.strftime(\"%H:%M:%S\"),\n",
513
+ " \"duration\": dur_str,\n",
514
+ " \"size\": format_bytes(out_size)\n",
515
+ " }\n",
516
+ " \n",
517
+ " return model_name, mock_answer, status, metrics\n",
518
+ "\n",
519
+ " # Execute mock tasks in parallel\n",
520
+ " tasks = [mock_api_call(config) for config in configs]\n",
521
+ " results = await asyncio.gather(*tasks)\n",
522
+ "\n",
523
+ " # Prepare table headers\n",
524
+ " header = f\"{'Model':<20} {'Status':<10} {'Start':<10} {'End':<10} {'Duration':<10} {'Size':<12}\"\n",
525
+ " print(header)\n",
526
+ " print(\"-\" * len(header))\n",
527
+ "\n",
528
+ " # Output rows and collect final success data\n",
529
+ " for model_name, answer, status, row in results:\n",
530
+ " print(f\"{row['model']:<20} {row['status']:<10} {row['start']:<10} {row['end']:<10} {row['duration']:<10} {row['size']:<12}\")\n",
531
+ " if status == \"✅ Success\":\n",
532
+ " competitors.append(model_name)\n",
533
+ " answers.append(answer)\n",
534
+ "\n",
535
+ " print(f\"\\n✅ Completed. {len(competitors)}/{len(configs)} models simulated successfully.\")\n",
536
+ " return competitors, answers\n",
537
+ "\n",
538
+ "async def execute_selected_models(model_names: list, messages: list):\n",
539
+ " \"\"\"Execute only the orchestrator-selected workers.\"\"\"\n",
540
+ " selected_configs = [MODEL_CONFIGS_BY_NAME[m] for m in model_names]\n",
541
+ " return await execute_models_in_parallel(selected_configs, messages)\n",
542
+ "\n",
543
+ "async def mock_execute_selected_models(model_names: list):\n",
544
+ " \"\"\"Execute only the orchestrator-selected workers.\"\"\"\n",
545
+ " selected_configs = [MODEL_CONFIGS_BY_NAME[m] for m in model_names]\n",
546
+ " return await mock_execute_models_in_parallel(selected_configs)\n",
547
+ "\n"
548
+ ]
549
+ },
550
+ {
551
+ "cell_type": "markdown",
552
+ "metadata": {},
553
+ "source": [
554
+ "## Step 5: Run Orchestrated Pipeline\n",
555
+ "\n",
556
+ "**Full end-to-end execution**: Orchestrator → Workers → Synthesizer."
557
+ ]
558
+ },
559
+ {
560
+ "cell_type": "code",
561
+ "execution_count": null,
562
+ "metadata": {},
563
+ "outputs": [],
564
+ "source": [
565
+ "# ==========================================\n",
566
+ "# FULL ORCHESTRATED PIPELINE\n",
567
+ "# ==========================================\n",
568
+ "\n",
569
+ "user_question = question # From Step 1\n",
570
+ "messages = [{\"role\": \"user\", \"content\": user_question}]\n",
571
+ "\n",
572
+ "# 1) Orchestrator chooses workers\n",
573
+ "selected_models = orchestrator_plan(user_question)"
574
+ ]
575
+ },
576
+ {
577
+ "cell_type": "code",
578
+ "execution_count": null,
579
+ "metadata": {},
580
+ "outputs": [],
581
+ "source": [
582
+ "# 2) Mock execute chosen workers\n",
583
+ "competitors, answers = await mock_execute_selected_models(selected_models)"
584
+ ]
585
+ },
586
+ {
587
+ "cell_type": "code",
588
+ "execution_count": null,
589
+ "metadata": {},
590
+ "outputs": [],
591
+ "source": [
592
+ "# 2) Run chosen workers in parallel\n",
593
+ "competitors, answers = await execute_selected_models(selected_models, messages)"
594
+ ]
595
+ },
596
+ {
597
+ "cell_type": "markdown",
598
+ "metadata": {},
599
+ "source": [
600
+ "## Step 6: Synthesizer LLM - Merge + Rank\n",
601
+ "\n",
602
+ "The **synthesizer LLM** creates a final answer and ranks the worker models."
603
+ ]
604
+ },
605
+ {
606
+ "cell_type": "code",
607
+ "execution_count": null,
608
+ "metadata": {},
609
+ "outputs": [],
610
+ "source": [
611
+ "# ==========================================\n",
612
+ "# Synthesizer: Merge Outputs + Rank Workers\n",
613
+ "# ==========================================\n",
614
+ "\n",
615
+ "def aggregator_format_outputs(competitors: List[str], answers: List[str]) -> str:\n",
616
+ " \"\"\"Format worker outputs for the synthesizer.\"\"\"\n",
617
+ " together = \"\"\n",
618
+ " for index, answer in enumerate(answers):\n",
619
+ " together += f\"# Response from {competitors[index]}\\n\\n\"\n",
620
+ " together += answer + \"\\n\\n\"\n",
621
+ " return together\n",
622
+ "\n",
623
+ "def build_synthesizer_prompt(question: str, competitors: list, answers: list) -> list:\n",
624
+ " formatted = aggregator_format_outputs(competitors, answers)\n",
625
+ " num_workers = len(competitors)\n",
626
+ " \n",
627
+ " system_msg = f\"\"\"\n",
628
+ " You are evaluating EXACTLY {num_workers} worker responses.\n",
629
+ " \n",
630
+ " CRITICAL: There are ONLY {num_workers} competitors numbered 1-{num_workers}.\n",
631
+ " \n",
632
+ " Tasks:\n",
633
+ " 1. Synthesize final answer from these {num_workers} responses\n",
634
+ " 2. Rank ONLY these {num_workers} responses (indices 1-{num_workers})\n",
635
+ " \n",
636
+ " Output STRICTLY valid JSON:\n",
637
+ " {{\n",
638
+ " \"final_answer\": \"your synthesized answer\",\n",
639
+ " \"rankings\": [\n",
640
+ " {{\"competitor_index\": N, \"reason\": \"why N is good\"}} // N is 1-{num_workers}\n",
641
+ " // EXACTLY {num_workers} entries, no more, no less\n",
642
+ " ]\n",
643
+ " }}\n",
644
+ " \n",
645
+ " Responses ({num_workers} total):\n",
646
+ " {formatted}\n",
647
+ " \"\"\"\n",
648
+ " \n",
649
+ " return [{\"role\": \"system\", \"content\": system_msg}]\n",
650
+ "\n",
651
+ "def run_synthesizer(question: str, competitors: list, answers: list):\n",
652
+ " \"\"\"Run the synthesizer LLM.\"\"\"\n",
653
+ " messages = build_synthesizer_prompt(question, competitors, answers)\n",
654
+ " openai = OpenAI()\n",
655
+ " resp = openai.chat.completions.create(\n",
656
+ " model=\"gpt-4o-mini\",\n",
657
+ " messages=messages,\n",
658
+ " temperature=0.3,\n",
659
+ " )\n",
660
+ " data = json.loads(resp.choices[0].message.content)\n",
661
+ " return data"
662
+ ]
663
+ },
664
+ {
665
+ "cell_type": "code",
666
+ "execution_count": null,
667
+ "metadata": {},
668
+ "outputs": [],
669
+ "source": [
670
+ "# ==========================================\n",
671
+ "# FINAL SYNTHESIS AND RANKINGS\n",
672
+ "# ==========================================\n",
673
+ "\n",
674
+ "# Run synthesizer\n",
675
+ "synth = run_synthesizer(question, competitors, answers)\n"
676
+ ]
677
+ },
678
+ {
679
+ "cell_type": "code",
680
+ "execution_count": null,
681
+ "metadata": {},
682
+ "outputs": [],
683
+ "source": [
684
+ "for idx, r in enumerate(synth[\"rankings\"], start=1):\n",
685
+ " name = competitors[r[\"competitor_index\"] - 1]\n",
686
+ " print(f\"{idx}. {name} — {r['reason']}\")\n",
687
+ "\n",
688
+ "print(f\"\\n✅ Pipeline complete! Orchestrator → {len(selected_models)} Workers → Synthesizer\")\n"
689
+ ]
690
+ },
691
+ {
692
+ "cell_type": "code",
693
+ "execution_count": null,
694
+ "metadata": {},
695
+ "outputs": [],
696
+ "source": [
697
+ "# IMMEDIATE DEBUG\n",
698
+ "print(\"COMPETITORS:\", competitors)\n",
699
+ "print(\"NUM COMPETITORS:\", len(competitors))\n",
700
+ "print(\"RAW SYNTH:\", json.dumps(synth, indent=2))\n",
701
+ "print(\"RANKINGS:\", [r.get(\"competitor_index\") for r in synth.get(\"rankings\", [])])\n",
702
+ "\n"
703
+ ]
704
+ }
705
+ ],
706
+ "metadata": {
707
+ "kernelspec": {
708
+ "display_name": ".venv",
709
+ "language": "python",
710
+ "name": "python3"
711
+ },
712
+ "language_info": {
713
+ "codemirror_mode": {
714
+ "name": "ipython",
715
+ "version": 3
716
+ },
717
+ "file_extension": ".py",
718
+ "mimetype": "text/x-python",
719
+ "name": "python",
720
+ "nbconvert_exporter": "python",
721
+ "pygments_lexer": "ipython3",
722
+ "version": "3.12.4"
723
+ }
724
+ },
725
+ "nbformat": 4,
726
+ "nbformat_minor": 2
727
+ }
community_contributions/2_lab2-parallelization.ipynb ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Changes I've made with this lab.\n",
10
+ "1) Modified the original question to instead generate a range of questions, 12 of them. These questions will be used to evaluate each LLM's reasoning, knowledge, creativity, and ability to handle nuanced scenarios.\n",
11
+ "2) I've changed this lab to run the queries in parallel. Thanks GPT for helping with the code to do that. :)\n",
12
+ "3) Instead of having one LLM rate all the responses, I have all of the LLM's rate each others work and then use a Borda Count to asign points to determine the winner."
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "code",
17
+ "execution_count": null,
18
+ "metadata": {},
19
+ "outputs": [],
20
+ "source": [
21
+ "# Start with imports - ask ChatGPT to explain any package that you don't know\n",
22
+ "\n",
23
+ "import os\n",
24
+ "import json\n",
25
+ "from dotenv import load_dotenv\n",
26
+ "from openai import OpenAI\n",
27
+ "from anthropic import Anthropic\n",
28
+ "from IPython.display import Markdown, display"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": null,
34
+ "metadata": {},
35
+ "outputs": [],
36
+ "source": [
37
+ "# Always remember to do this!\n",
38
+ "load_dotenv(override=True)"
39
+ ]
40
+ },
41
+ {
42
+ "cell_type": "code",
43
+ "execution_count": null,
44
+ "metadata": {},
45
+ "outputs": [],
46
+ "source": [
47
+ "# Print the key prefixes to help with any debugging\n",
48
+ "\n",
49
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
50
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
51
+ "gemini_api_key = os.getenv('GEMINI_API_KEY')\n",
52
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
53
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
54
+ "\n",
55
+ "if openai_api_key:\n",
56
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
57
+ "else:\n",
58
+ " print(\"OpenAI API Key not set\")\n",
59
+ " \n",
60
+ "if anthropic_api_key:\n",
61
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
62
+ "else:\n",
63
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
64
+ "\n",
65
+ "if gemini_api_key:\n",
66
+ " print(f\"Gemini API Key exists and begins {gemini_api_key[:2]}\")\n",
67
+ "else:\n",
68
+ " print(\"Gemini API Key not set (and this is optional)\")\n",
69
+ "\n",
70
+ "if deepseek_api_key:\n",
71
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
72
+ "else:\n",
73
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
74
+ "\n",
75
+ "if groq_api_key:\n",
76
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
77
+ "else:\n",
78
+ " print(\"Groq API Key not set (and this is optional)\")"
79
+ ]
80
+ },
81
+ {
82
+ "cell_type": "code",
83
+ "execution_count": null,
84
+ "metadata": {},
85
+ "outputs": [],
86
+ "source": [
87
+ "request = \"\"\"You are being evaluated for your reasoning, knowledge, creativity, and ability to handle nuanced scenarios. \n",
88
+ "Generate 12 questions that cover the following categories:\n",
89
+ "- Logical reasoning and problem solving\n",
90
+ "- Creative writing and storytelling\n",
91
+ "- Factual accuracy and knowledge recall\n",
92
+ "- Following instructions with strict constraints\n",
93
+ "- Multi-step planning and organization\n",
94
+ "- Ethical dilemmas and debatable issues\n",
95
+ "- Philosophical or abstract reasoning\n",
96
+ "- Summarization and explanation at different levels\n",
97
+ "- Translation and multilingual ability\n",
98
+ "- Roleplay or adaptive communication style\n",
99
+ "\n",
100
+ "Number each question from 1 to 12. \n",
101
+ "The result should be a balanced benchmark question set that fully tests an LLM’s capabilities.\n",
102
+ "\n",
103
+ "Important: Output only clean plain text. \n",
104
+ "Do not use any markup, formatting symbols, quotation marks, brackets, lists, or special characters \n",
105
+ "that could cause misinterpretation. Only provide plain text questions, one per line, numbered 1 to 20.\n",
106
+ "\"\"\"\n",
107
+ "request += \"Answer only with the question, no explanation.\"\n",
108
+ "messages = [{\"role\": \"user\", \"content\": request}]"
109
+ ]
110
+ },
111
+ {
112
+ "cell_type": "code",
113
+ "execution_count": null,
114
+ "metadata": {},
115
+ "outputs": [],
116
+ "source": [
117
+ "# Generate the questions.\n",
118
+ "openai = OpenAI()\n",
119
+ "response = openai.chat.completions.create(\n",
120
+ " model=\"gpt-4o-mini\",\n",
121
+ " messages=messages,\n",
122
+ ")\n",
123
+ "question = response.choices[0].message.content\n",
124
+ "\n",
125
+ "display(Markdown(question))"
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "competitors = []\n",
135
+ "answers = []\n",
136
+ "messages = [{\"role\": \"user\", \"content\": question}]"
137
+ ]
138
+ },
139
+ {
140
+ "cell_type": "code",
141
+ "execution_count": null,
142
+ "metadata": {},
143
+ "outputs": [],
144
+ "source": [
145
+ "# Ask the LLM's in Parallel\n",
146
+ "\n",
147
+ "import asyncio\n",
148
+ "\n",
149
+ "clients = {\n",
150
+ " \"openai\": OpenAI(),\n",
151
+ " \"claude\": Anthropic(),\n",
152
+ " \"gemini\": OpenAI(api_key=gemini_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"),\n",
153
+ " \"deepseek\": OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\"),\n",
154
+ " \"groq\": OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\"),\n",
155
+ "}\n",
156
+ "\n",
157
+ "# Get the answers from the LLM\n",
158
+ "async def call_llm(model_name, messages):\n",
159
+ " try:\n",
160
+ " if \"claude\" in model_name:\n",
161
+ " response = await asyncio.to_thread(\n",
162
+ " clients[\"claude\"].messages.create,\n",
163
+ " model=model_name,\n",
164
+ " messages=messages,\n",
165
+ " max_tokens=3000,\n",
166
+ " )\n",
167
+ " answer = \"\".join([c.text for c in response.content if c.type == \"text\"])\n",
168
+ " \n",
169
+ " elif \"gpt-4o-mini\" in model_name:\n",
170
+ " response = await asyncio.to_thread(\n",
171
+ " clients[\"openai\"].chat.completions.create,\n",
172
+ " model=model_name,\n",
173
+ " messages=messages,\n",
174
+ " )\n",
175
+ " answer = response.choices[0].message.content\n",
176
+ "\n",
177
+ " elif \"gemini\" in model_name:\n",
178
+ " response = await asyncio.to_thread(\n",
179
+ " clients[\"gemini\"].chat.completions.create,\n",
180
+ " model=model_name,\n",
181
+ " messages=messages,\n",
182
+ " )\n",
183
+ " answer = response.choices[0].message.content\n",
184
+ "\n",
185
+ " elif \"deepseek\" in model_name:\n",
186
+ " response = await asyncio.to_thread(\n",
187
+ " clients[\"deepseek\"].chat.completions.create,\n",
188
+ " model=model_name,\n",
189
+ " messages=messages,\n",
190
+ " )\n",
191
+ " answer = response.choices[0].message.content\n",
192
+ "\n",
193
+ " elif \"llama\" in model_name:\n",
194
+ " response = await asyncio.to_thread(\n",
195
+ " clients[\"groq\"].chat.completions.create,\n",
196
+ " model=model_name,\n",
197
+ " messages=messages,\n",
198
+ " )\n",
199
+ " answer = response.choices[0].message.content\n",
200
+ "\n",
201
+ " return model_name, answer \n",
202
+ "\n",
203
+ " except Exception as e:\n",
204
+ " print (f\"❌ Error: {str(e)}\")\n",
205
+ " return model_name, \"I was not able to generate answers for any of the questions.\"\n",
206
+ "\n",
207
+ "\n",
208
+ "# send out the calls to the LLM to ask teh questions.\n",
209
+ "async def ask_questions_in_parallel(messages):\n",
210
+ " competitor_models = [\n",
211
+ " \"gpt-4o-mini\",\n",
212
+ " \"claude-3-7-sonnet-latest\",\n",
213
+ " \"gemini-2.0-flash\",\n",
214
+ " \"deepseek-chat\",\n",
215
+ " \"llama-3.3-70b-versatile\"\n",
216
+ " ]\n",
217
+ "\n",
218
+ " # create tasks to call the LLM's in parallel\n",
219
+ " tasks = [call_llm(model, messages) for model in competitor_models]\n",
220
+ "\n",
221
+ " answers = []\n",
222
+ " competitors = []\n",
223
+ "\n",
224
+ " # When we have an answer, we can process it. No waiting.\n",
225
+ " for task in asyncio.as_completed(tasks):\n",
226
+ " model_name, answer = await task\n",
227
+ " competitors.append(model_name)\n",
228
+ " answers.append(answer)\n",
229
+ " print(f\"\\n✅ Got response from {model_name}\")\n",
230
+ "\n",
231
+ " return competitors, answers"
232
+ ]
233
+ },
234
+ {
235
+ "cell_type": "code",
236
+ "execution_count": null,
237
+ "metadata": {},
238
+ "outputs": [],
239
+ "source": [
240
+ "# Fire off the ask to all the LLM's at once. Parallelization...\n",
241
+ "competitors, answers = await ask_questions_in_parallel(messages)"
242
+ ]
243
+ },
244
+ {
245
+ "cell_type": "code",
246
+ "execution_count": null,
247
+ "metadata": {},
248
+ "outputs": [],
249
+ "source": [
250
+ "#Look at the results\n",
251
+ "print (len(answers))\n",
252
+ "print (len(competitors))\n",
253
+ "print (competitors)"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": null,
259
+ "metadata": {},
260
+ "outputs": [],
261
+ "source": [
262
+ "# Let's bring this together - note the use of \"enumerate\"\n",
263
+ "\n",
264
+ "together = \"\"\n",
265
+ "for index, answer in enumerate(answers):\n",
266
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
267
+ " together += answer + \"\\n\\n\""
268
+ ]
269
+ },
270
+ {
271
+ "cell_type": "code",
272
+ "execution_count": null,
273
+ "metadata": {},
274
+ "outputs": [],
275
+ "source": [
276
+ "print(together)"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": null,
282
+ "metadata": {},
283
+ "outputs": [],
284
+ "source": [
285
+ "\n",
286
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
287
+ "Each model has been given the folowing questions:\n",
288
+ "\n",
289
+ "{question}\n",
290
+ "\n",
291
+ "Your task is to evaluate the overall strength of the arguments presented by each competitor. \n",
292
+ "Consider the following factors:\n",
293
+ "- Clarity: how clearly the ideas are communicated\n",
294
+ "- Relevance: how directly the response addresses the question\n",
295
+ "- Depth: the level of reasoning, insight, or supporting evidence provided\n",
296
+ "- Persuasiveness: how compelling or convincing the response is overall\n",
297
+ "Respond with JSON, and only JSON.\n",
298
+ "The output must be a single JSON array of competitor names, ordered from best to worst.\n",
299
+ "Do not include any keys, labels, or extra text.\n",
300
+ "\n",
301
+ "Example format:\n",
302
+ "[\"1\", \"3\", \"5\", \"2\", \"4\"]\n",
303
+ "\n",
304
+ "Here are the responses from each competitor:\n",
305
+ "\n",
306
+ "{together}\n",
307
+ "\n",
308
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\n",
309
+ "Do not deviate from the json format as described above. Do not include the term ranking in the final json\"\"\"\n"
310
+ ]
311
+ },
312
+ {
313
+ "cell_type": "code",
314
+ "execution_count": null,
315
+ "metadata": {},
316
+ "outputs": [],
317
+ "source": [
318
+ "print(judge)"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "code",
323
+ "execution_count": null,
324
+ "metadata": {},
325
+ "outputs": [],
326
+ "source": [
327
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
328
+ ]
329
+ },
330
+ {
331
+ "cell_type": "code",
332
+ "execution_count": null,
333
+ "metadata": {},
334
+ "outputs": [],
335
+ "source": [
336
+ "# Have each LLM rate all of the results.\n",
337
+ "results = dict()\n",
338
+ "LLM_result = ''\n",
339
+ "\n",
340
+ "competitors, answers = await ask_questions_in_parallel(judge_messages)\n",
341
+ "\n",
342
+ "results = dict()\n",
343
+ "for index, each_competitor in enumerate(competitors):\n",
344
+ " results[each_competitor] = answers[index].strip()"
345
+ ]
346
+ },
347
+ {
348
+ "cell_type": "code",
349
+ "execution_count": null,
350
+ "metadata": {},
351
+ "outputs": [],
352
+ "source": [
353
+ "# See the results\n",
354
+ "print (len(answers))\n",
355
+ "results = dict()\n",
356
+ "for index, each_competitor in enumerate(competitors):\n",
357
+ " results[each_competitor] = answers[index]\n",
358
+ "\n",
359
+ "print (results)"
360
+ ]
361
+ },
362
+ {
363
+ "cell_type": "code",
364
+ "execution_count": null,
365
+ "metadata": {},
366
+ "outputs": [],
367
+ "source": [
368
+ "# Lets convert these rankings into scores. Borda Count - (1st gets 4, 2nd gets 3, etc.).\n",
369
+ "number_of_competitors = len(competitors)\n",
370
+ "scores = {}\n",
371
+ "\n",
372
+ "for rankings in results.values():\n",
373
+ " print(rankings)"
374
+ ]
375
+ },
376
+ {
377
+ "cell_type": "code",
378
+ "execution_count": null,
379
+ "metadata": {},
380
+ "outputs": [],
381
+ "source": [
382
+ "# # Borda count points (1st gets n-1, 2nd gets n-2, etc.)\n",
383
+ "num_competitors = len(competitors)\n",
384
+ "\n",
385
+ "competitor_dict = dict()\n",
386
+ "for index, each_competitor in enumerate(competitors):\n",
387
+ " competitor_dict[each_competitor] = index + 1\n",
388
+ "\n",
389
+ "borda_scores_dict = dict()\n",
390
+ "for each_competitor in competitors:\n",
391
+ " if each_competitor not in borda_scores_dict:\n",
392
+ " borda_scores_dict[each_competitor] = 0\n",
393
+ "\n",
394
+ "for voter_llm, ranking_str in results.items():\n",
395
+ " ranking_indices = json.loads(ranking_str)\n",
396
+ " ranking_indices = [int(x) for x in ranking_indices]\n",
397
+ "\n",
398
+ " # For each position in the ranking, award points\n",
399
+ " for position, competitor_index in enumerate(ranking_indices):\n",
400
+ " competitor_name = competitors[competitor_index - 1]\n",
401
+ "\n",
402
+ " # Borda count points (1st gets n-1, 2nd gets n-2, etc.)\n",
403
+ " points = num_competitors - 1 - position \n",
404
+ " borda_scores_dict[competitor_name] += points\n",
405
+ " \n",
406
+ "sorted_results = sorted(borda_scores_dict.items(), key=lambda x: x[1], reverse=True)\n",
407
+ "\n",
408
+ "print(f\"{'Rank':<4} {'LLM':<30} {'Points':<3}\")\n",
409
+ "print(\"-\" * 50)\n",
410
+ "\n",
411
+ "for rank, (llm, points) in enumerate(sorted_results, 1):\n",
412
+ " print(f\"{rank:<4} {llm:<30} {points:<8}\")\n",
413
+ "\n",
414
+ "print(\"\\nQuestions asked:\")\n",
415
+ "print(question)"
416
+ ]
417
+ }
418
+ ],
419
+ "metadata": {
420
+ "kernelspec": {
421
+ "display_name": ".venv",
422
+ "language": "python",
423
+ "name": "python3"
424
+ },
425
+ "language_info": {
426
+ "codemirror_mode": {
427
+ "name": "ipython",
428
+ "version": 3
429
+ },
430
+ "file_extension": ".py",
431
+ "mimetype": "text/x-python",
432
+ "name": "python",
433
+ "nbconvert_exporter": "python",
434
+ "pygments_lexer": "ipython3",
435
+ "version": "3.12.2"
436
+ }
437
+ },
438
+ "nbformat": 4,
439
+ "nbformat_minor": 2
440
+ }
community_contributions/2_lab2.1_ss.ipynb ADDED
@@ -0,0 +1,767 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "Multimodel Architecture - Routing Workflow "
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "code",
12
+ "execution_count": 1,
13
+ "metadata": {},
14
+ "outputs": [],
15
+ "source": [
16
+ "# Start with imports - ask ChatGPT to explain any package that you don't know\n",
17
+ "\n",
18
+ "import os\n",
19
+ "import json\n",
20
+ "from dotenv import load_dotenv\n",
21
+ "from openai import OpenAI\n",
22
+ "from anthropic import Anthropic\n",
23
+ "from IPython.display import Markdown, display"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": 2,
29
+ "metadata": {},
30
+ "outputs": [
31
+ {
32
+ "data": {
33
+ "text/plain": [
34
+ "True"
35
+ ]
36
+ },
37
+ "execution_count": 2,
38
+ "metadata": {},
39
+ "output_type": "execute_result"
40
+ }
41
+ ],
42
+ "source": [
43
+ "# Always remember to do this!\n",
44
+ "load_dotenv(override=True)"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 3,
50
+ "metadata": {},
51
+ "outputs": [
52
+ {
53
+ "name": "stdout",
54
+ "output_type": "stream",
55
+ "text": [
56
+ "OpenAI API Key exists and begins sk-proj-\n",
57
+ "Anthropic API Key not set (and this is optional)\n",
58
+ "Google API Key exists and begins AI\n",
59
+ "DeepSeek API Key exists and begins sk-\n",
60
+ "Groq API Key exists and begins gsk_\n"
61
+ ]
62
+ }
63
+ ],
64
+ "source": [
65
+ "# Print the key prefixes to help with any debugging\n",
66
+ "\n",
67
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
68
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
69
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
70
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
71
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
72
+ "\n",
73
+ "if openai_api_key:\n",
74
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
75
+ "else:\n",
76
+ " print(\"OpenAI API Key not set\")\n",
77
+ " \n",
78
+ "if anthropic_api_key:\n",
79
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
80
+ "else:\n",
81
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
82
+ "\n",
83
+ "if google_api_key:\n",
84
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
85
+ "else:\n",
86
+ " print(\"Google API Key not set (and this is optional)\")\n",
87
+ "\n",
88
+ "if deepseek_api_key:\n",
89
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
90
+ "else:\n",
91
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
92
+ "\n",
93
+ "if groq_api_key:\n",
94
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
95
+ "else:\n",
96
+ " print(\"Groq API Key not set (and this is optional)\")"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "execution_count": 4,
102
+ "metadata": {},
103
+ "outputs": [],
104
+ "source": [
105
+ "openai_client = OpenAI(api_key=openai_api_key)\n",
106
+ "deepseek_client = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
107
+ "gemini_client = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
108
+ "groq_client = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")"
109
+ ]
110
+ },
111
+ {
112
+ "cell_type": "code",
113
+ "execution_count": 5,
114
+ "metadata": {},
115
+ "outputs": [],
116
+ "source": [
117
+ "MODEL_REGISTRY = {\n",
118
+ " \"gpt-5-nano\": {\n",
119
+ " \"provider\": \"openai\",\n",
120
+ " \"strength\": \"general\",\n",
121
+ " \"cost\": \"low\"\n",
122
+ " },\n",
123
+ " \"gpt-5-mini\": {\n",
124
+ " \"provider\": \"openai\",\n",
125
+ " \"strength\": \"reasoning\",\n",
126
+ " \"cost\": \"medium\"\n",
127
+ " },\n",
128
+ " \n",
129
+ " \"deepseek-chat\": {\n",
130
+ " \"provider\": \"deepseek\",\n",
131
+ " \"strength\": \"coding\",\n",
132
+ " \"cost\": \"low\"\n",
133
+ " },\n",
134
+ " \"gemini-2.5-flash\": {\n",
135
+ " \"provider\": \"google\",\n",
136
+ " \"strength\": \"general\",\n",
137
+ " \"cost\": \"low\"\n",
138
+ " }\n",
139
+ "}\n"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "markdown",
144
+ "metadata": {},
145
+ "source": [
146
+ "ROUTER AGENT"
147
+ ]
148
+ },
149
+ {
150
+ "cell_type": "code",
151
+ "execution_count": null,
152
+ "metadata": {},
153
+ "outputs": [],
154
+ "source": [
155
+ "def classify_task(user_input):\n",
156
+ " router_prompt = f\"\"\"\n",
157
+ " Classify the task into ONE of these categories:\n",
158
+ " - coding\n",
159
+ " - creative_writing\n",
160
+ " - quantitative_reasoning\n",
161
+ " - strategic_analysis\n",
162
+ " - simple_general\n",
163
+ "\n",
164
+ " Respond ONLY with the category name.\n",
165
+ "\n",
166
+ " User request:\n",
167
+ " {user_input}\n",
168
+ " \"\"\"\n",
169
+ "\n",
170
+ " response = openai_client.chat.completions.create(\n",
171
+ " model=\"gpt-5-nano\",\n",
172
+ " messages=[{\"role\": \"user\", \"content\": router_prompt}],\n",
173
+ " )\n",
174
+ "\n",
175
+ " return response.choices[0].message.content.strip()\n"
176
+ ]
177
+ },
178
+ {
179
+ "cell_type": "markdown",
180
+ "metadata": {},
181
+ "source": [
182
+ "ROUTING LOGIC"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "code",
187
+ "execution_count": 12,
188
+ "metadata": {},
189
+ "outputs": [],
190
+ "source": [
191
+ "def select_model(task_type):\n",
192
+ " if task_type == \"coding\":\n",
193
+ " return \"deepseek-chat\"\n",
194
+ " elif task_type == \"creative_writing\":\n",
195
+ " return \"gemini-2.5-flash\"\n",
196
+ " elif task_type == \"quantitative_reasoning\":\n",
197
+ " return \"gpt-5-mini\"\n",
198
+ " elif task_type == \"strategic_analysis\":\n",
199
+ " return \"gpt-5-mini\"\n",
200
+ " else:\n",
201
+ " return \"gpt-5-nano\"\n"
202
+ ]
203
+ },
204
+ {
205
+ "cell_type": "markdown",
206
+ "metadata": {},
207
+ "source": [
208
+ "EXECUTION LAYER"
209
+ ]
210
+ },
211
+ {
212
+ "cell_type": "code",
213
+ "execution_count": 8,
214
+ "metadata": {},
215
+ "outputs": [],
216
+ "source": [
217
+ "def call_model(model_name, user_input):\n",
218
+ "\n",
219
+ " if model_name in [\"gpt-5-nano\", \"gpt-5-mini\"]:\n",
220
+ " response = openai_client.chat.completions.create(\n",
221
+ " model=model_name,\n",
222
+ " messages=[{\"role\": \"user\", \"content\": user_input}],\n",
223
+ " )\n",
224
+ " return response.choices[0].message.content\n",
225
+ "\n",
226
+ " elif model_name == \"deepseek-chat\":\n",
227
+ " response = deepseek_client.chat.completions.create(\n",
228
+ " model=model_name,\n",
229
+ " messages=[{\"role\": \"user\", \"content\": user_input}],\n",
230
+ " )\n",
231
+ " return response.choices[0].message.content\n",
232
+ "\n",
233
+ " elif model_name == \"gemini-2.5-flash\":\n",
234
+ " response = gemini_client.chat.completions.create(\n",
235
+ " model=model_name,\n",
236
+ " messages=[{\"role\": \"user\", \"content\": user_input}],\n",
237
+ " )\n",
238
+ " return response.choices[0].message.content\n",
239
+ "\n",
240
+ " else:\n",
241
+ " raise ValueError(\"Unknown model\")\n"
242
+ ]
243
+ },
244
+ {
245
+ "cell_type": "code",
246
+ "execution_count": 9,
247
+ "metadata": {},
248
+ "outputs": [],
249
+ "source": [
250
+ "def route_and_execute(user_input):\n",
251
+ "\n",
252
+ " print(\"Classifying task...\")\n",
253
+ " task_type = classify_task(user_input)\n",
254
+ " print(\"Task type:\", task_type)\n",
255
+ "\n",
256
+ " model_name = select_model(task_type)\n",
257
+ " print(\"Selected model:\", model_name)\n",
258
+ "\n",
259
+ " print(\"Executing\")\n",
260
+ " answer = call_model(model_name, user_input)\n",
261
+ "\n",
262
+ " return answer\n"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "markdown",
267
+ "metadata": {},
268
+ "source": [
269
+ "TESTING"
270
+ ]
271
+ },
272
+ {
273
+ "cell_type": "code",
274
+ "execution_count": 10,
275
+ "metadata": {},
276
+ "outputs": [
277
+ {
278
+ "name": "stdout",
279
+ "output_type": "stream",
280
+ "text": [
281
+ "Classifying task...\n",
282
+ "Task type: coding\n",
283
+ "Selected model: deepseek-chat\n",
284
+ "Executing\n",
285
+ "\n",
286
+ "Final Answer:\n",
287
+ "\n",
288
+ "Here's a Python function to calculate factorial recursively:\n",
289
+ "\n",
290
+ "```python\n",
291
+ "def factorial(n):\n",
292
+ " \"\"\"\n",
293
+ " Calculate the factorial of a non-negative integer n recursively.\n",
294
+ " \n",
295
+ " Parameters:\n",
296
+ " n (int): A non-negative integer\n",
297
+ " \n",
298
+ " Returns:\n",
299
+ " int: The factorial of n (n!)\n",
300
+ " \n",
301
+ " Raises:\n",
302
+ " ValueError: If n is negative\n",
303
+ " \"\"\"\n",
304
+ " # Base case: factorial of 0 is 1\n",
305
+ " if n == 0:\n",
306
+ " return 1\n",
307
+ " \n",
308
+ " # Error case: factorial is not defined for negative numbers\n",
309
+ " if n < 0:\n",
310
+ " raise ValueError(\"Factorial is not defined for negative numbers\")\n",
311
+ " \n",
312
+ " # Recursive case: n! = n * (n-1)!\n",
313
+ " return n * factorial(n - 1)\n",
314
+ "\n",
315
+ "\n",
316
+ "# Example usage\n",
317
+ "if __name__ == \"__main__\":\n",
318
+ " # Test cases\n",
319
+ " test_numbers = [0, 1, 5, 7, 10]\n",
320
+ " \n",
321
+ " for num in test_numbers:\n",
322
+ " result = factorial(num)\n",
323
+ " print(f\"factorial({num}) = {result}\")\n",
324
+ " \n",
325
+ " # Test with negative number (will raise ValueError)\n",
326
+ " try:\n",
327
+ " factorial(-3)\n",
328
+ " except ValueError as e:\n",
329
+ " print(f\"Error: {e}\")\n",
330
+ "```\n",
331
+ "\n",
332
+ "**Key points about this implementation:**\n",
333
+ "\n",
334
+ "1. **Base Case**: `factorial(0) = 1` - This stops the recursion\n",
335
+ "2. **Recursive Case**: `factorial(n) = n * factorial(n-1)` - This breaks down the problem\n",
336
+ "3. **Error Handling**: Raises `ValueError` for negative inputs\n",
337
+ "4. **Documentation**: Includes docstring explaining the function's purpose and parameters\n",
338
+ "\n",
339
+ "**How it works:**\n",
340
+ "- For `factorial(5)`, the recursion unfolds as:\n",
341
+ " - `5 * factorial(4)`\n",
342
+ " - `5 * (4 * factorial(3))`\n",
343
+ " - `5 * (4 * (3 * factorial(2)))`\n",
344
+ " - `5 * (4 * (3 * (2 * factorial(1))))`\n",
345
+ " - `5 * (4 * (3 * (2 * (1 * factorial(0)))))`\n",
346
+ " - `5 * (4 * (3 * (2 * (1 * 1)))) = 120`\n",
347
+ "\n",
348
+ "**Note**: While recursive solutions are elegant, they can cause stack overflow for very large values of `n` due to Python's recursion depth limit (typically around 1000). For production code with large inputs, an iterative approach would be more efficient and safer.\n"
349
+ ]
350
+ }
351
+ ],
352
+ "source": [
353
+ "user_question = \"Write a Python function to calculate factorial recursively.\"\n",
354
+ "\n",
355
+ "result = route_and_execute(user_question)\n",
356
+ "\n",
357
+ "print(\"\\nFinal Answer:\\n\")\n",
358
+ "print(result)\n"
359
+ ]
360
+ },
361
+ {
362
+ "cell_type": "code",
363
+ "execution_count": 11,
364
+ "metadata": {},
365
+ "outputs": [
366
+ {
367
+ "name": "stdout",
368
+ "output_type": "stream",
369
+ "text": [
370
+ "Classifying task...\n",
371
+ "Task type: quantitative_reasoning\n",
372
+ "Selected model: gpt-5-mini\n",
373
+ "Executing\n",
374
+ "\n",
375
+ "Final Answer:\n",
376
+ "\n",
377
+ "Let p = 12% be the price cut and q = 18% the increase in quantity.\n",
378
+ "\n",
379
+ "New revenue / old revenue = (1 − p)(1 + q) = 0.88 × 1.18 = 1.0384, so revenue rises by 3.84%.\n",
380
+ "\n",
381
+ "In general revenue increases iff (1 − p)(1 + q) > 1, i.e.\n",
382
+ "q > p/(1 − p).\n",
383
+ "\n",
384
+ "For p = 0.12 this threshold is 0.12/0.88 ≈ 13.636%. Since q = 18% > 13.636%, revenue increases.\n",
385
+ "\n",
386
+ "Equivalently (using elasticity): the price cut raises revenue when demand is elastic (|%ΔQ| / |%ΔP| > 1). Here 18%/12% = 1.5 > 1, so revenue increases.\n"
387
+ ]
388
+ }
389
+ ],
390
+ "source": [
391
+ "user_question = \"If a company reduces prices by 12% and sales volume increases by 18%, under what conditions does total revenue increase?\"\n",
392
+ "\n",
393
+ "result = route_and_execute(user_question)\n",
394
+ "\n",
395
+ "print(\"\\nFinal Answer:\\n\")\n",
396
+ "print(result)"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "code",
401
+ "execution_count": 13,
402
+ "metadata": {},
403
+ "outputs": [
404
+ {
405
+ "name": "stdout",
406
+ "output_type": "stream",
407
+ "text": [
408
+ "Classifying task...\n",
409
+ "Task type: creative_writing\n",
410
+ "Selected model: gemini-2.5-flash\n",
411
+ "Executing\n",
412
+ "\n",
413
+ "Final Answer:\n",
414
+ "\n",
415
+ "AI is deeply reshaping the creative industry, offering immense opportunities and complex challenges. It empowers artists, designers, and writers by accelerating idea generation, streamlining workflows, and enabling rapid prototyping. AI tools democratize creation, lowering barriers for individuals to produce high-quality content, from personalized marketing to novel art forms, boosting efficiency and expanding artistic boundaries.\n",
416
+ "\n",
417
+ "However, job displacement concerns are valid as AI automates routine tasks. Ethical dilemmas surrounding copyright, data ownership, and fair artist compensation are pressing. The debate about AI-generated art's authenticity versus human creations also persists. Ultimately, the creative industry must adapt, viewing AI as a powerful co-pilot and tool, not a full replacement, to navigate this evolving future.\n"
418
+ ]
419
+ }
420
+ ],
421
+ "source": [
422
+ "user_question = \"Write a 150 word essay on AI impacting creative industry\"\n",
423
+ "\n",
424
+ "result = route_and_execute(user_question)\n",
425
+ "\n",
426
+ "print(\"\\nFinal Answer:\\n\")\n",
427
+ "print(result)"
428
+ ]
429
+ },
430
+ {
431
+ "cell_type": "code",
432
+ "execution_count": 14,
433
+ "metadata": {},
434
+ "outputs": [
435
+ {
436
+ "name": "stdout",
437
+ "output_type": "stream",
438
+ "text": [
439
+ "Classifying task...\n",
440
+ "Task type: strategic_analysis\n",
441
+ "Selected model: gpt-5-mini\n",
442
+ "Executing\n",
443
+ "\n",
444
+ "Final Answer:\n",
445
+ "\n",
446
+ "Short summary\n",
447
+ "- Problem: clients are switching to AI automation because the firm’s services are increasingly commoditized, price-sensitive, and easily replicated by AI tools.\n",
448
+ "- Goal: reposition the firm from pure labor-driven delivery to a higher-value, AI-augmented advisor that combines domain expertise, outcome guarantees, and turnkey AI-enabled products and managed services — while cutting costs, stabilizing cash flow, and rebuilding growth.\n",
449
+ "\n",
450
+ "High-level turnaround objectives (12 months)\n",
451
+ "1. Stop client churn and stabilize revenue within 90 days.\n",
452
+ "2. Launch 2–3 AI-augmented productized offerings and 1 managed-service capability within 6 months.\n",
453
+ "3. Re-skill core consulting staff and build an AI/analytics capability to support scaled delivery within 12 months.\n",
454
+ "4. Achieve positive EBITDA improvement and restore pipeline velocity by month 12.\n",
455
+ "\n",
456
+ "Quick diagnosis — why clients leave\n",
457
+ "- Client problems are becoming commoditized (data cleaning, reporting, forecasting), and AI tools do these faster/cheaper.\n",
458
+ "- The firm competes on hourly rate/delivery rather than outcomes and IP.\n",
459
+ "- Limited internal AI skills, so clients go to pure-play AI vendors.\n",
460
+ "- Few productized offerings, low repeatability, and high delivery cost base.\n",
461
+ "\n",
462
+ "Strategic pillars (what to do)\n",
463
+ "1. Move up the value chain: sell outcome-based, strategic services clients can’t easily automate (strategy, governance, business model design, change management, complex multi-stakeholder programs).\n",
464
+ "2. Productize and scale: turn repeatable work into packaged offerings, accelerators, and managed services (subscription, outcome-based contracts).\n",
465
+ "3. Become AI-native: adopt AI internally to increase efficiency and create differentiated client offerings (human + AI workflow).\n",
466
+ "4. Reskill and reconfigure talent: create T-shaped consultants (domain + AI/tooling) and build small multidisciplinary squads.\n",
467
+ "5. Market repositioning & partnerships: lead with ROI-focused case studies, partner with cloud/AI providers and niche AI boutiques.\n",
468
+ "6. Financial triage: cut non-core cost, stabilize cash, prioritize must-win accounts and profitable services.\n",
469
+ "\n",
470
+ "90/180/365-day roadmap (prioritized, with owners)\n",
471
+ "0–30 days — Stabilize (CEO / CRO / CFO)\n",
472
+ "- Top-10 client retention blitz: assign exec sponsors, run account health calls, offer rapid-value pilots (free/discounted AI health check + 6-week ROI pilot).\n",
473
+ "- Triage portfolio: identify top 30% profitable offerings and stop lowest-margin services.\n",
474
+ "- Cash & cost actions: freeze hiring, re-negotiate vendor contracts, reduce discretionary spend, evaluate lease/staffing options.\n",
475
+ "KPIs: churn rate, cash runway, # retention meetings.\n",
476
+ "\n",
477
+ "30–90 days — Quick wins and foundation (COO / Head of Delivery / Head of Sales)\n",
478
+ "- Launch “AI Health Check” and “Automation Fast-Track” 4–6 week productized pilots with clear ROI metrics and case-study playbook.\n",
479
+ "- Create go/no-go criteria for continuing projects (profitability, strategic fit).\n",
480
+ "- Form a small AI Center of Excellence (CoE) — hire/contract 2-4 data engineers/scientists and 1 product manager.\n",
481
+ "- Sales enablement: new value-selling pitch decks, ROI calculators, reference pricing templates.\n",
482
+ "KPIs: pilots launched, pilot-to-paid conversion, gross margin improvement.\n",
483
+ "\n",
484
+ "90–180 days — Build & productize (Head of Product / CTO / CHRO)\n",
485
+ "- Productize 2–3 high-potential offerings (e.g., \"AI-augmented Forecasting Package\", \"Regulatory AI Governance & Ops\", \"M&A Data Room + Insights as a Service\").\n",
486
+ "- Launch managed services: run-rate, subscription pricing (e.g., Managed Insights or MLOps).\n",
487
+ "- Reskilling program: cohort training for consultants (AI tools, prompt engineering, data literacy, change mgmt).\n",
488
+ "- Establish partnerships with 1–2 cloud/AI vendors (AWS/Azure/GCP, OpenAI/Databricks) for tech & go-to-market.\n",
489
+ "KPIs: number of productized offerings, subscription/recurring revenue, staff upskilled.\n",
490
+ "\n",
491
+ "180–365 days — Scale & optimize (CEO / CFO / CRO)\n",
492
+ "- Scale sales motions for packaged offerings with playbooks and verticalized sales teams.\n",
493
+ "- Launch outcome-based pricing pilots (gainshare / risk-sharing) on 3–5 deals.\n",
494
+ "- Institutionalize reuse: knowledge base, accelerators, IP marketplaces, delivery templates.\n",
495
+ "- Explore bolt-on acquisition of an AI boutique or platform if gaps remain.\n",
496
+ "KPIs: ARR from productized services, average project margin, NPS, pipeline conversion.\n",
497
+ "\n",
498
+ "Detailed initiatives (what to build & sell)\n",
499
+ "- Advisory & transformation: AI strategy, operating model, data strategy, regulatory & ethics advisory — priced by value, not hours.\n",
500
+ "- AI-enabled “diagnostic + pilot” package: standardized discovery, rapid PoV, 6-8 week ROI pilot with dashboard and decision pack.\n",
501
+ "- Managed Insights / AI Ops: continuous model monitoring, governance, retraining, performance reporting as a subscription.\n",
502
+ "- Industry-specific solutions: focus on 2–3 verticals where domain nuance matters (healthcare, financial services, manufacturing, energy).\n",
503
+ "- Change & adoption services: training, behavior change, process redesign — these remain hard to automate.\n",
504
+ "- Productized accelerators: reusable ETL connectors, templates, dashboards, prompt libraries, model wrappers — sell as add-ons or license.\n",
505
+ "\n",
506
+ "Sales & pricing playbook\n",
507
+ "- Move from hourly to outcome-based selling: define measurable client KPIs (cost savings, time-to-insight, revenue uplift) and tie fees to outcomes.\n",
508
+ "- Pilot-to-scale path: discovery → low-cost pilot (fixed fee) → scaled implementation (subscription / gainshare).\n",
509
+ "- Account-based marketing and EVP: target accounts with specific case studies showing X% ROI in Y months.\n",
510
+ "- Value calculator and case-study repository for rapid ROI proof.\n",
511
+ "\n",
512
+ "Talent & organization\n",
513
+ "- Create AI CoE to centralize platform, IP, accelerators, and best practices.\n",
514
+ "- Build multidisciplinary squads: PM, data eng, data scientist, domain consultant, change lead.\n",
515
+ "- Reskill senior consultants via certification tracks (cloud + AI + domain).\n",
516
+ "- Use blended workforce: permanent core + vetted freelance network for surge capacity.\n",
517
+ "- Revise performance incentives: reward landing productized deals, subscription growth, client retention, and reuse/IP contributions.\n",
518
+ "\n",
519
+ "Technology & delivery\n",
520
+ "- Adopt internal AI tools to improve utilization (automate proposals, scoping, coding, reporting).\n",
521
+ "- Standardize cloud infra, CI/CD, MLOps to speed delivery and reduce cost.\n",
522
+ "- Invest in reusable data and model pipelines to lower delivery time for repeatable tasks.\n",
523
+ "\n",
524
+ "Partnerships & M&A\n",
525
+ "- Strategic partnerships with cloud providers for credits, solution certifications and co-selling.\n",
526
+ "- Partner with niche AI firms for rapid capability injection.\n",
527
+ "- Consider acquiring a small AI shop to accelerate capability if financially viable.\n",
528
+ "\n",
529
+ "Financial plan & cost management\n",
530
+ "- Prioritize high-margin and strategic accounts; pause or offboard low-margin work.\n",
531
+ "- Short-term cost reductions: pause hiring, reduce travel, renegotiate vendors.\n",
532
+ "- Reinvest savings into CoE, sales enablement, and 2–3 productization projects.\n",
533
+ "- Target: improve gross margins by 6–10% within 12 months; reach break-even on product development via recurring contracts in 9–12 months.\n",
534
+ "\n",
535
+ "Governance & change management\n",
536
+ "- Appoint a Turnaround Leader (CRO or COO) with 90-day and 12-month accountability.\n",
537
+ "- Weekly steering committee (CEO, CFO, CRO, Head of Delivery, Head of Product) for rapid decisions.\n",
538
+ "- Monthly reviews of KPIs and client recovery plan status.\n",
539
+ "- Communicate transparently to staff and priority clients to maintain confidence.\n",
540
+ "\n",
541
+ "KPIs to track\n",
542
+ "- Client churn rate and retention of top-20 accounts\n",
543
+ "- Pipeline value and conversion rate for productized offers\n",
544
+ "- Revenue mix: % recurring/subscription vs. time-and-materials\n",
545
+ "- Average project margin and utilization\n",
546
+ "- Number of pilots converted to paid engagements\n",
547
+ "- NPS / client satisfaction\n",
548
+ "- Time-to-value for pilots (target < 90 days)\n",
549
+ "\n",
550
+ "Top 6 quick wins (week 1–8)\n",
551
+ "1. Executive outreach to top 10 at-risk clients with retention offers and pilot proposals.\n",
552
+ "2. Free/discounted AI Health Check as a client win-back mechanism.\n",
553
+ "3. Stop or renegotiate low-margin contracts and redeploy staff to pilots.\n",
554
+ "4. Build a one-page “ROI for automation vs. buy advisory” calculator for sales.\n",
555
+ "5. Stand up a 2–4 person AI CoE (mix of hires + contractors).\n",
556
+ "6. Publish 2 short case studies/POVs from pilots to use in marketing.\n",
557
+ "\n",
558
+ "Risks and mitigations\n",
559
+ "- Revenue drop during transition: mitigate with prioritized retention, rapid pilots, and cost reductions.\n",
560
+ "- Talent attrition: communicate vision, fast reskilling, and incentives for new behaviors.\n",
561
+ "- Execution overload: sequence initiatives, focus on 2–3 productized offerings first.\n",
562
+ "- Client skepticism of new models: use small guaranteed pilots and outcome-based pricing to build trust.\n",
563
+ "\n",
564
+ "Estimated resource needs (ballpark)\n",
565
+ "- AI CoE launch: $200–500k initial (contractors + tooling) if lean; $1–2M if hiring full-time team and tooling.\n",
566
+ "- Productization & GTM: $150–400k for 2–3 productized offers (PM, engineering, marketing, pilot subsidies).\n",
567
+ "- Reskilling program: $50–150k for cohorts, training content, and certifications.\n",
568
+ "(Adjust to actual firm size and burn runway)\n",
569
+ "\n",
570
+ "Immediate next steps (first week)\n",
571
+ "1. CEO convenes leadership to approve turnaround plan and appoint Turnaround Leader.\n",
572
+ "2. Create playbook and one-pager for AI Health Check pilot; assign sales owners for top-10 accounts.\n",
573
+ "3. Freeze non-essential spend and start client outreach.\n",
574
+ "4. Hire/contract 2 technical resources for CoE and prepare pilot templates.\n",
575
+ "\n",
576
+ "Closing thought\n",
577
+ "Clients aren’t rejecting consulting — they’re rejecting low-differentiation, labor-heavy delivery. The firm’s path back to growth is to combine domain expertise, outcome-oriented commercial models, and AI-native delivery with repeatable, productized offerings and managed services. Focus the first 90 days on retaining clients and proving quick ROI pilots; use those wins to fund the transformation to a scalable, differentiated business.\n",
578
+ "\n",
579
+ "If you want, I can:\n",
580
+ "- Draft the 90-day execution checklist with owners and dates,\n",
581
+ "- Sketch 3 productized service packages (scope, pricing model, metrics),\n",
582
+ "- Prepare a client outreach script and ROI calculator template. Which would help most right now?\n"
583
+ ]
584
+ }
585
+ ],
586
+ "source": [
587
+ "user_question = \"A mid-sized consulting firm is losing clients due to AI automation. Propose a structured turnaround strategy.\"\n",
588
+ "\n",
589
+ "result = route_and_execute(user_question)\n",
590
+ "\n",
591
+ "print(\"\\nFinal Answer:\\n\")\n",
592
+ "print(result)"
593
+ ]
594
+ },
595
+ {
596
+ "cell_type": "code",
597
+ "execution_count": 15,
598
+ "metadata": {},
599
+ "outputs": [
600
+ {
601
+ "name": "stdout",
602
+ "output_type": "stream",
603
+ "text": [
604
+ "Classifying task...\n",
605
+ "Task type: strategic_analysis\n",
606
+ "Selected model: gpt-5-mini\n",
607
+ "Executing\n",
608
+ "\n",
609
+ "Final Answer:\n",
610
+ "\n",
611
+ "Executive summary\n",
612
+ "- Problem: Clients are switching to AI automation (tools/products) that replace parts of traditional consulting work. That erodes revenue, pipeline and perceived relevance.\n",
613
+ "- Goal: Stabilize revenue, stop client churn, and rebuild a differentiated, sustainable services/offering model where the firm adds value that AI alone cannot.\n",
614
+ "- Approach: Three-phase turnaround (Stabilize 0–3 months; Rebuild 3–12 months; Grow & Scale 12–36 months) built on five strategic pillars: client centricity & retention, productized outcome offerings, AI-native advisory + delivery, talent & operating model, and partnerships & IP.\n",
615
+ "\n",
616
+ "Diagnosis (what to check immediately)\n",
617
+ "- Client churn analysis: Which segments, services, and clients left and why (cost, speed, perceived equivalence of AI)?\n",
618
+ "- Service mapping: Which consulting tasks are commoditized by AI vs. which remain high-value (strategy, leadership, change, complex data integration, regulatory)?\n",
619
+ "- Revenue concentration & pipeline health.\n",
620
+ "- Cost base & utilization of consultants.\n",
621
+ "- Current AI skills, tools, accelerators, proprietary IP.\n",
622
+ "- Sales messaging: Are you selling outputs (reports, PPTs) or outcomes (revenue, cost, risk reduction)?\n",
623
+ "\n",
624
+ "Strategic objectives (90 days / 12 months)\n",
625
+ "- 90 days: Stop urgent churn, stabilize cash flow, get leadership alignment, quick-win AI-enabled offerings.\n",
626
+ "- 12 months: Launch 3-5 differentiated, outcome-based service lines; retrain top talent; sign new contracts with outcome or subscription pricing.\n",
627
+ "- 24–36 months: Grow recurring revenue, expand IP, become a recognized AI + domain specialist in 1–2 verticals.\n",
628
+ "\n",
629
+ "Five strategic pillars and concrete actions\n",
630
+ "\n",
631
+ "1) Client retention & win-back (Immediate)\n",
632
+ "- Triage clients: segment by risk and lifetime value. Prioritize Top 20% and at-risk accounts.\n",
633
+ "- Outreach program: executive-to-executive win-back calls, present a short “AI impact and recovery” plan and free diagnostics/workshop.\n",
634
+ "- Offer immediate value: free or discounted AI-readiness assessment and a 4-week proof-of-value (PoV) focused on a revenue/cost/risk metric.\n",
635
+ "- Contract tactics: short-term renewal discounts tied to pilots or outcome guarantees to lock revenue while you rebuild offerings.\n",
636
+ "\n",
637
+ "2) Productize outcomes (Short—Medium term)\n",
638
+ "- Move from time-and-materials / slide decks to productized services: “AI-enabled forecasting as a service,” “Regulatory AI compliance program,” “Sales opportunity prediction + remediation.”\n",
639
+ "- Define standardized scopes, packaging, pricing, SLAs and KPIs.\n",
640
+ "- Launch managed services/subscription models for recurrent work. This de-risks clients and creates predictable revenue.\n",
641
+ "\n",
642
+ "3) AI-native advisory + delivery (Short—Medium term)\n",
643
+ "- Create an internal AI Center of Excellence (CoE) that combines domain experts, ML engineers, data engineers and experience designers.\n",
644
+ "- Offer integrated solutions: strategy + data platform + change management. Sell outcomes (e.g., X% cost reduction, Y% increase in sales conversion).\n",
645
+ "- Build accelerators: templates, pre-trained models, connectors to popular vendors (OpenAI, Azure, AWS, Snowflake, etc.) to shorten time-to-value.\n",
646
+ "- Governance & ethics practice: clients need help with model risk, compliance and trustworthy AI—package this as a service.\n",
647
+ "\n",
648
+ "4) Talent, organization & operating model (Immediate—Medium)\n",
649
+ "- Rapid skills triage: identify high-potential consultants to retrain (data engineering, prompt engineering, AI product management, change leadership).\n",
650
+ "- Training & certification plan (partner with vendors for bootcamps).\n",
651
+ "- Realign delivery teams from project-centric to product/engagement squads (cross-functional pods with accountability for outcomes).\n",
652
+ "- Incentives: shift compensation mix to reward subscription revenue, outcomes, client retention and IP reuse.\n",
653
+ "\n",
654
+ "5) Partnerships & IP (Medium)\n",
655
+ "- Form alliances with 2–3 technology vendors (cloud providers, LLM/AI platforms, specialized vertical AI vendors). Get partner enablement, co-marketing, and preferential pricing.\n",
656
+ "- Acquire or license vertical datasets or micro-IP where possible.\n",
657
+ "- Consider small bolt-on acquisitions (AI product, vertical SaaS, specialized data engineering shop) if capital allows.\n",
658
+ "\n",
659
+ "Phase-based roadmap\n",
660
+ "\n",
661
+ "Phase 1 — Stabilize (0–3 months)\n",
662
+ "- Actions: client triage & outreach; freeze non-essential hiring; quick Win PoV offers; pricing concessions tied to pilots; form leadership turnaround team.\n",
663
+ "- Deliverables: list of at-risk clients, 10–15 PoV offers, immediate cost savings plan, CoE charter.\n",
664
+ "- Metrics: churn rate stopped, pipeline stabilized, PoV conversion rate.\n",
665
+ "\n",
666
+ "Phase 2 — Rebuild (3–12 months)\n",
667
+ "- Actions: productize 3–5 service offerings; launch CoE and 2–3 client pilots; retrain top 20% staff; set new sales playbook and marketing (thought leadership on AI + domain).\n",
668
+ "- Deliverables: packaged offerings, managed services SLAs, partnerships with 1–2 vendors, first recurring contracts.\n",
669
+ "- Metrics: % revenue from new offerings, MRR from subscriptions, utilization, customer NPS.\n",
670
+ "\n",
671
+ "Phase 3 — Scale & Grow (12–36 months)\n",
672
+ "- Actions: expand vertical specialization, invest in IP (accelerators, data assets), pursue strategic hires or acquisitions, global go-to-market expansion.\n",
673
+ "- Deliverables: repeatable playbooks, marketplace assets, recognized brand in chosen verticals.\n",
674
+ "- Metrics: ARR, gross margin increase, client retention LTV, ROI on CoE.\n",
675
+ "\n",
676
+ "Go-to-market and pricing\n",
677
+ "- Messaging: shift from “we do analysis” to “we guarantee X outcome” and “we integrate AI safely into operations.”\n",
678
+ "- Sales plays: industry-specific AI transformation plays, fast PoV plays, compliance & governance play.\n",
679
+ "- Pricing: hybrid models — upfront AI assessment + subscription for managed services + outcome-based bonus. Example: 20% upfront, monthly fee, and a success fee tied to agreed KPI uplift.\n",
680
+ "- Case studies: document PoVs into short case studies for sales enablement.\n",
681
+ "\n",
682
+ "Operations & delivery\n",
683
+ "- Standardize delivery templates and reusable code/modules to lower cost-per-project.\n",
684
+ "- Implement DevOps and MLOps practices: CI/CD for models, monitoring, retraining schedules.\n",
685
+ "- Quality & compliance: run model risk assessments and client-facing runbooks for incidents.\n",
686
+ "\n",
687
+ "Talent & culture\n",
688
+ "- Fast-track \"AI Fellows\" program: upskill 5–10 client-facing leaders to become AI-practice leads who can sell PoVs.\n",
689
+ "- New roles: AI product manager, prompt engineer, ML engineer, data engineer, change lead.\n",
690
+ "- Cultural change: reward client outcomes and IP reuse; embed learning and experimentation time.\n",
691
+ "\n",
692
+ "Partnerships & ecosystem\n",
693
+ "- Tech partners for infrastructure and models (negotiate go-to-market support).\n",
694
+ "- Boutique specialists (NLP, computer vision) to augment capacity without heavy hiring.\n",
695
+ "- Universities / labs for advanced R&D if long-term differentiation desired.\n",
696
+ "\n",
697
+ "Financials & investment priority (rules of thumb)\n",
698
+ "- Prioritize revenue-stabilizing actions first (client retention, PoVs).\n",
699
+ "- Initial investment range: 3–8% of annual revenue to build CoE, accelerate sales, and run pilots (adjust to cash position).\n",
700
+ "- Reallocate existing spend: pause low-margin engagements and non-strategic initiatives.\n",
701
+ "- Track payback: aim for PoV-to-paid-contract conversion in <6 months.\n",
702
+ "\n",
703
+ "KPIs & OKRs (examples)\n",
704
+ "- OKR (90 days): Reduce churn by 40% among top 50 clients. Key results: 50 executive win-back calls completed, 20 PoVs sold.\n",
705
+ "- OKR (6 months): Launch three productized services with $X MRR. Key results: 3 contracts signed, CoE staffed, 2 published case studies.\n",
706
+ "- KPIs to monitor: client churn, renewal rate, % revenue from subscriptions, PoV conversion rate, utilization, average deal size, gross margin by offering.\n",
707
+ "\n",
708
+ "Risks & mitigations\n",
709
+ "- Risk: PoVs fail to convert — Mitigate: run very focused PoVs with clear, measurable KPIs and executive buy-in.\n",
710
+ "- Risk: Talent defection — Mitigate: retain top billers with short-term incentives and clear retraining paths.\n",
711
+ "- Risk: Cash constraints — Mitigate: prioritize high-ROI, low-capex pilots and use partner credits.\n",
712
+ "- Risk: Competitive pressure from large players — Mitigate: focus on vertical specialization, regulatory know-how, and trusted client relationships.\n",
713
+ "\n",
714
+ "Quick 10-step action checklist (first 30 days)\n",
715
+ "1. Convene leadership turnaround team and set weekly cadence.\n",
716
+ "2. Run client churn analysis and list top 50 clients by risk/LTV.\n",
717
+ "3. Launch executive outreach program for top accounts.\n",
718
+ "4. Define 5 short PoV packages (2–4 week) with pricing and success metrics.\n",
719
+ "5. Freeze non-essential hiring; reallocate training budget.\n",
720
+ "6. Appoint head of AI CoE and hire 2 senior engineers/architects (contract if needed).\n",
721
+ "7. Negotiate at least one vendor partnership for credits/support.\n",
722
+ "8. Create sales playbook and one-pager for new AI-enabled offerings.\n",
723
+ "9. Start retraining plan for 20% of consultants.\n",
724
+ "10. Set 30/60/90 day KPIs and reporting dashboard.\n",
725
+ "\n",
726
+ "Next step\n",
727
+ "If you want, I can:\n",
728
+ "- Turn this into a detailed 90-day implementation plan with owners, tasks, and estimated budgets;\n",
729
+ "- Draft sample PoV packages and pricing;\n",
730
+ "- Build a client outreach script and slide deck template for executive win-backs.\n",
731
+ "\n",
732
+ "Which would you like first, or tell me three specifics about the firm (annual revenue, top verticals, current AI skills) and I’ll tailor the plan.\n"
733
+ ]
734
+ }
735
+ ],
736
+ "source": [
737
+ "user_question = \"A mid-sized consulting firm is losing clients due to AI automation. Propose a structured turnaround strategy.\"\n",
738
+ "\n",
739
+ "result = route_and_execute(user_question)\n",
740
+ "\n",
741
+ "print(\"\\nFinal Answer:\\n\")\n",
742
+ "print(result)"
743
+ ]
744
+ }
745
+ ],
746
+ "metadata": {
747
+ "kernelspec": {
748
+ "display_name": "agents (3.12.12)",
749
+ "language": "python",
750
+ "name": "python3"
751
+ },
752
+ "language_info": {
753
+ "codemirror_mode": {
754
+ "name": "ipython",
755
+ "version": 3
756
+ },
757
+ "file_extension": ".py",
758
+ "mimetype": "text/x-python",
759
+ "name": "python",
760
+ "nbconvert_exporter": "python",
761
+ "pygments_lexer": "ipython3",
762
+ "version": "3.12.12"
763
+ }
764
+ },
765
+ "nbformat": 4,
766
+ "nbformat_minor": 2
767
+ }
community_contributions/2_lab2.ipynb ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": null,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# Start with imports - ask ChatGPT to explain any package that you don't know\n",
37
+ "\n",
38
+ "import os #allows the code to interact with the operating system\n",
39
+ "import json #imports Python's JSON library\n",
40
+ "from dotenv import load_dotenv #allows the code to load the .env file. A .env file must be explicity loaded\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
+ "# Always remember to do this!\n",
64
+ "load_dotenv(override=True) #prioritizes the local .env file and will replace existing env variables"
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
+ "OpenAI API Key exists and begins sk-proj-\n",
77
+ "Anthropic API Key not set (and this is optional)\n",
78
+ "Google API Key not set (and this is optional)\n",
79
+ "DeepSeek API Key not set (and this is optional)\n",
80
+ "Groq API Key not set (and this is optional)\n"
81
+ ]
82
+ }
83
+ ],
84
+ "source": [
85
+ "# Print the key prefixes to help with any debugging\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\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
95
+ "else:\n",
96
+ " print(\"OpenAI API Key not set\")\n",
97
+ " \n",
98
+ "if anthropic_api_key:\n",
99
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
100
+ "else:\n",
101
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
102
+ "\n",
103
+ "if google_api_key:\n",
104
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
105
+ "else:\n",
106
+ " print(\"Google API Key not set (and this is optional)\")\n",
107
+ "\n",
108
+ "if deepseek_api_key:\n",
109
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
110
+ "else:\n",
111
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
112
+ "\n",
113
+ "if groq_api_key:\n",
114
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
115
+ "else:\n",
116
+ " print(\"Groq API Key not set (and this is optional)\")"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
126
+ "request += \"Answer only with the question, no explanation. I want the question to be related to the cruelty of life\"\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': 'Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. Answer only with the question, no explanation.'}]"
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": 7,
154
+ "metadata": {},
155
+ "outputs": [
156
+ {
157
+ "name": "stdout",
158
+ "output_type": "stream",
159
+ "text": [
160
+ "In a scenario where two intelligent agents with differing ethical frameworks encounter a moral dilemma involving a choice between the greater good and individual rights, how should they navigate their decision-making process, and what factors should they consider to justify their final actions?\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": null,
188
+ "metadata": {},
189
+ "outputs": [],
190
+ "source": [
191
+ "# The API we know well\n",
192
+ "\n",
193
+ "model_name = \"gpt-4o-mini\"\n",
194
+ "\n",
195
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
196
+ "answer = response.choices[0].message.content\n",
197
+ "\n",
198
+ "display(Markdown(answer))\n",
199
+ "competitors.append(model_name)\n",
200
+ "answers.append(answer)"
201
+ ]
202
+ },
203
+ {
204
+ "cell_type": "code",
205
+ "execution_count": null,
206
+ "metadata": {},
207
+ "outputs": [],
208
+ "source": [
209
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
210
+ "\n",
211
+ "model_name = \"claude-3-7-sonnet-latest\"\n",
212
+ "\n",
213
+ "claude = Anthropic()\n",
214
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
215
+ "answer = response.content[0].text\n",
216
+ "\n",
217
+ "display(Markdown(answer))\n",
218
+ "competitors.append(model_name)\n",
219
+ "answers.append(answer)"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": null,
225
+ "metadata": {},
226
+ "outputs": [],
227
+ "source": [
228
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
229
+ "model_name = \"gemini-2.0-flash\"\n",
230
+ "\n",
231
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
232
+ "answer = response.choices[0].message.content\n",
233
+ "\n",
234
+ "display(Markdown(answer))\n",
235
+ "competitors.append(model_name)\n",
236
+ "answers.append(answer)"
237
+ ]
238
+ },
239
+ {
240
+ "cell_type": "code",
241
+ "execution_count": null,
242
+ "metadata": {},
243
+ "outputs": [],
244
+ "source": [
245
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
246
+ "model_name = \"deepseek-chat\"\n",
247
+ "\n",
248
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
249
+ "answer = response.choices[0].message.content\n",
250
+ "\n",
251
+ "display(Markdown(answer))\n",
252
+ "competitors.append(model_name)\n",
253
+ "answers.append(answer)"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": null,
259
+ "metadata": {},
260
+ "outputs": [],
261
+ "source": [
262
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
263
+ "model_name = \"llama-3.3-70b-versatile\"\n",
264
+ "\n",
265
+ "response = groq.chat.completions.create(model=model_name, messages=messages)\n",
266
+ "answer = response.choices[0].message.content\n",
267
+ "\n",
268
+ "display(Markdown(answer))\n",
269
+ "competitors.append(model_name)\n",
270
+ "answers.append(answer)\n"
271
+ ]
272
+ },
273
+ {
274
+ "cell_type": "markdown",
275
+ "metadata": {},
276
+ "source": [
277
+ "## For the next cell, we will use Ollama\n",
278
+ "\n",
279
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
280
+ "and runs models locally using high performance C++ code.\n",
281
+ "\n",
282
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
283
+ "\n",
284
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
285
+ "\n",
286
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
287
+ "\n",
288
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
289
+ "\n",
290
+ "`ollama pull <model_name>` downloads a model locally \n",
291
+ "`ollama ls` lists all the models you've downloaded \n",
292
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
293
+ ]
294
+ },
295
+ {
296
+ "cell_type": "markdown",
297
+ "metadata": {},
298
+ "source": [
299
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
300
+ " <tr>\n",
301
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
302
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
303
+ " </td>\n",
304
+ " <td>\n",
305
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
306
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
307
+ " </span>\n",
308
+ " </td>\n",
309
+ " </tr>\n",
310
+ "</table>"
311
+ ]
312
+ },
313
+ {
314
+ "cell_type": "code",
315
+ "execution_count": null,
316
+ "metadata": {},
317
+ "outputs": [],
318
+ "source": [
319
+ "!ollama pull llama3.2"
320
+ ]
321
+ },
322
+ {
323
+ "cell_type": "code",
324
+ "execution_count": null,
325
+ "metadata": {},
326
+ "outputs": [],
327
+ "source": [
328
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
329
+ "model_name = \"llama3.2\"\n",
330
+ "\n",
331
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
332
+ "answer = response.choices[0].message.content\n",
333
+ "\n",
334
+ "display(Markdown(answer))\n",
335
+ "competitors.append(model_name)\n",
336
+ "answers.append(answer)"
337
+ ]
338
+ },
339
+ {
340
+ "cell_type": "code",
341
+ "execution_count": null,
342
+ "metadata": {},
343
+ "outputs": [],
344
+ "source": [
345
+ "# So where are we?\n",
346
+ "\n",
347
+ "print(competitors)\n",
348
+ "print(answers)\n"
349
+ ]
350
+ },
351
+ {
352
+ "cell_type": "code",
353
+ "execution_count": null,
354
+ "metadata": {},
355
+ "outputs": [],
356
+ "source": [
357
+ "# It's nice to know how to use \"zip\"\n",
358
+ "for competitor, answer in zip(competitors, answers):\n",
359
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
360
+ ]
361
+ },
362
+ {
363
+ "cell_type": "code",
364
+ "execution_count": 20,
365
+ "metadata": {},
366
+ "outputs": [],
367
+ "source": [
368
+ "# Let's bring this together - note the use of \"enumerate\"\n",
369
+ "\n",
370
+ "together = \"\"\n",
371
+ "for index, answer in enumerate(answers):\n",
372
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
373
+ " together += answer + \"\\n\\n\""
374
+ ]
375
+ },
376
+ {
377
+ "cell_type": "code",
378
+ "execution_count": null,
379
+ "metadata": {},
380
+ "outputs": [],
381
+ "source": [
382
+ "print(together)"
383
+ ]
384
+ },
385
+ {
386
+ "cell_type": "code",
387
+ "execution_count": 22,
388
+ "metadata": {},
389
+ "outputs": [],
390
+ "source": [
391
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
392
+ "Each model has been given this question:\n",
393
+ "\n",
394
+ "{question}\n",
395
+ "\n",
396
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
397
+ "Respond with JSON, and only JSON, with the following format:\n",
398
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
399
+ "\n",
400
+ "Here are the responses from each competitor:\n",
401
+ "\n",
402
+ "{together}\n",
403
+ "\n",
404
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
405
+ ]
406
+ },
407
+ {
408
+ "cell_type": "code",
409
+ "execution_count": null,
410
+ "metadata": {},
411
+ "outputs": [],
412
+ "source": [
413
+ "print(judge)"
414
+ ]
415
+ },
416
+ {
417
+ "cell_type": "code",
418
+ "execution_count": 29,
419
+ "metadata": {},
420
+ "outputs": [],
421
+ "source": [
422
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
423
+ ]
424
+ },
425
+ {
426
+ "cell_type": "code",
427
+ "execution_count": null,
428
+ "metadata": {},
429
+ "outputs": [],
430
+ "source": [
431
+ "# Judgement time!\n",
432
+ "\n",
433
+ "openai = OpenAI()\n",
434
+ "response = openai.chat.completions.create(\n",
435
+ " model=\"o3-mini\",\n",
436
+ " messages=judge_messages,\n",
437
+ ")\n",
438
+ "results = response.choices[0].message.content\n",
439
+ "print(results)\n"
440
+ ]
441
+ },
442
+ {
443
+ "cell_type": "code",
444
+ "execution_count": null,
445
+ "metadata": {},
446
+ "outputs": [],
447
+ "source": [
448
+ "# OK let's turn this into results!\n",
449
+ "\n",
450
+ "results_dict = json.loads(results)\n",
451
+ "ranks = results_dict[\"results\"]\n",
452
+ "for index, result in enumerate(ranks):\n",
453
+ " competitor = competitors[int(result)-1]\n",
454
+ " print(f\"Rank {index+1}: {competitor}\")"
455
+ ]
456
+ },
457
+ {
458
+ "cell_type": "markdown",
459
+ "metadata": {},
460
+ "source": [
461
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
462
+ " <tr>\n",
463
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
464
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
465
+ " </td>\n",
466
+ " <td>\n",
467
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
468
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
469
+ " </span>\n",
470
+ " </td>\n",
471
+ " </tr>\n",
472
+ "</table>"
473
+ ]
474
+ },
475
+ {
476
+ "cell_type": "markdown",
477
+ "metadata": {},
478
+ "source": [
479
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
480
+ " <tr>\n",
481
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
482
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
483
+ " </td>\n",
484
+ " <td>\n",
485
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
486
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
487
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
488
+ " to business projects where accuracy is critical.\n",
489
+ " </span>\n",
490
+ " </td>\n",
491
+ " </tr>\n",
492
+ "</table>"
493
+ ]
494
+ }
495
+ ],
496
+ "metadata": {
497
+ "kernelspec": {
498
+ "display_name": ".venv",
499
+ "language": "python",
500
+ "name": "python3"
501
+ },
502
+ "language_info": {
503
+ "codemirror_mode": {
504
+ "name": "ipython",
505
+ "version": 3
506
+ },
507
+ "file_extension": ".py",
508
+ "mimetype": "text/x-python",
509
+ "name": "python",
510
+ "nbconvert_exporter": "python",
511
+ "pygments_lexer": "ipython3",
512
+ "version": "3.12.12"
513
+ }
514
+ },
515
+ "nbformat": 4,
516
+ "nbformat_minor": 2
517
+ }
community_contributions/2_lab2_Execution_measurement.py ADDED
@@ -0,0 +1,401 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import asyncio
4
+ import concurrent.futures
5
+ import time
6
+ from typing import Dict, List, Tuple, Optional
7
+ from dotenv import load_dotenv
8
+ from openai import OpenAI
9
+
10
+ load_dotenv(override=True)
11
+
12
+ openai = OpenAI()
13
+ competitors = []
14
+ answers = []
15
+ together = ""
16
+ openai_api_key = os.getenv('OPENAI_API_KEY')
17
+ anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')
18
+ google_api_key = os.getenv('GOOGLE_API_KEY')
19
+ deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')
20
+ groq_api_key = os.getenv('GROQ_API_KEY')
21
+
22
+ models_dict = {
23
+ 'openai': {
24
+ 'model': 'gpt-4o-mini',
25
+ 'api_key': openai_api_key,
26
+ 'base_url': None
27
+ },
28
+ 'gemini': {
29
+ 'model': 'gemini-2.0-flash',
30
+ 'api_key': google_api_key,
31
+ 'base_url': 'https://generativelanguage.googleapis.com/v1beta/openai/'
32
+ },
33
+ 'groq': {
34
+ 'model': 'llama-3.3-70b-versatile',
35
+ 'api_key': groq_api_key,
36
+ 'base_url': 'https://api.groq.com/openai/v1'
37
+ },
38
+ 'ollama': {
39
+ 'model': 'llama3.2',
40
+ 'api_key': 'ollama',
41
+ 'base_url': 'http://localhost:11434/v1'
42
+ }
43
+ }
44
+
45
+ def key_checker():
46
+
47
+ if openai_api_key:
48
+ print(f"OpenAI API Key exists and begins {openai_api_key[:8]}")
49
+ else:
50
+ print("OpenAI API Key not set")
51
+
52
+ if anthropic_api_key:
53
+ print(f"Anthropic API Key exists and begins {anthropic_api_key[:7]}")
54
+ else:
55
+ print("Anthropic API Key not set (and this is optional)")
56
+
57
+ if google_api_key:
58
+ print(f"Google API Key exists and begins {google_api_key[:2]}")
59
+ else:
60
+ print("Google API Key not set (and this is optional)")
61
+
62
+ if deepseek_api_key:
63
+ print(f"DeepSeek API Key exists and begins {deepseek_api_key[:3]}")
64
+ else:
65
+ print("DeepSeek API Key not set (and this is optional)")
66
+
67
+ if groq_api_key:
68
+ print(f"Groq API Key exists and begins {groq_api_key[:4]}")
69
+ else:
70
+ print("Groq API Key not set (and this is optional)")
71
+
72
+ def question_prompt_generator():
73
+ request = "Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. "
74
+ request += "Answer only with the question, no explanation."
75
+ messages = [{"role": "user", "content": request}]
76
+ return messages
77
+
78
+ def generate_competition_question():
79
+ """
80
+ Generate a challenging question for the LLM competition
81
+ Returns the question text and formatted messages for LLM calls
82
+ """
83
+ print("Generating competition question...")
84
+ question_prompt = question_prompt_generator()
85
+ question = llm_caller(question_prompt)
86
+ question_messages = [{"role": "user", "content": question}]
87
+ print(f"Question: \n{question}")
88
+ return question, question_messages
89
+
90
+ def llm_caller(messages):
91
+ response = openai.chat.completions.create(
92
+ model="gpt-4o-mini",
93
+ messages=messages,
94
+ )
95
+ return response.choices[0].message.content
96
+
97
+ def llm_caller_with_model(messages, model_name, api_key, base_url):
98
+ llm = None
99
+
100
+ if base_url:
101
+ try:
102
+ llm = OpenAI(api_key=api_key, base_url=base_url)
103
+ except Exception as e:
104
+ print(f"Error creating OpenAI client: {e}")
105
+ return None
106
+ else:
107
+ try:
108
+ llm = OpenAI(api_key=api_key)
109
+ except Exception as e:
110
+ print(f"Error creating OpenAI client: {e}")
111
+ return None
112
+
113
+ response = llm.chat.completions.create(model=model_name, messages=messages)
114
+ return response.choices[0].message.content
115
+
116
+ def get_single_model_answer(provider: str, details: Dict, question_messages: List[Dict]) -> Tuple[str, Optional[str]]:
117
+ """
118
+ Call a single model and return (provider, answer) or (provider, None) if failed.
119
+ This function is designed to be used with ThreadPoolExecutor.
120
+ """
121
+ print(f"Calling model {provider}...")
122
+ try:
123
+ answer = llm_caller_with_model(question_messages, details['model'], details['api_key'], details['base_url'])
124
+ print(f"Model {provider} was successfully called!")
125
+ return provider, answer
126
+ except Exception as e:
127
+ print(f"Model {provider} failed to call: {e}")
128
+ return provider, None
129
+
130
+ def get_models_answers(question_messages):
131
+ """
132
+ Sequential version - kept for backward compatibility
133
+ """
134
+ for provider, details in models_dict.items():
135
+ print(f"Calling model {provider}...")
136
+ try:
137
+ answer = llm_caller_with_model(question_messages, details['model'], details['api_key'], details['base_url'])
138
+ print(f"Model {provider} was successful called!")
139
+ except Exception as e:
140
+ print(f"Model {provider} failed to call: {e}")
141
+ continue
142
+ competitors.append(provider)
143
+ answers.append(answer)
144
+
145
+ def get_models_answers_parallel(question_messages, max_workers: int = 4):
146
+ """
147
+ Parallel version - calls all models simultaneously using ThreadPoolExecutor
148
+ """
149
+ print("Starting parallel execution of all models...")
150
+
151
+ # Clear previous results
152
+ competitors.clear()
153
+ answers.clear()
154
+
155
+ # Use ThreadPoolExecutor for parallel execution
156
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
157
+ # Submit all tasks
158
+ future_to_provider = {
159
+ executor.submit(get_single_model_answer, provider, details, question_messages): provider
160
+ for provider, details in models_dict.items()
161
+ }
162
+
163
+ # Collect results as they complete
164
+ for future in concurrent.futures.as_completed(future_to_provider):
165
+ provider, answer = future.result()
166
+ if answer is not None: # Only add successful calls
167
+ competitors.append(provider)
168
+ answers.append(answer)
169
+
170
+ print(f"Parallel execution completed. {len(competitors)} models responded successfully.")
171
+
172
+ async def get_single_model_answer_async(provider: str, details: Dict, question_messages: List[Dict]) -> Tuple[str, Optional[str]]:
173
+ """
174
+ Async version of single model call - for even better performance
175
+ """
176
+ print(f"Calling model {provider} (async)...")
177
+ try:
178
+ # Run the synchronous call in a thread pool
179
+ loop = asyncio.get_event_loop()
180
+ answer = await loop.run_in_executor(
181
+ None,
182
+ llm_caller_with_model,
183
+ question_messages,
184
+ details['model'],
185
+ details['api_key'],
186
+ details['base_url']
187
+ )
188
+ print(f"Model {provider} was successfully called!")
189
+ return provider, answer
190
+ except Exception as e:
191
+ print(f"Model {provider} failed to call: {e}")
192
+ return provider, None
193
+
194
+ async def get_models_answers_async(question_messages):
195
+ """
196
+ Async version - calls all models simultaneously using asyncio
197
+ """
198
+ print("Starting async execution of all models...")
199
+
200
+ # Clear previous results
201
+ competitors.clear()
202
+ answers.clear()
203
+
204
+ # Create tasks for all models
205
+ tasks = [
206
+ get_single_model_answer_async(provider, details, question_messages)
207
+ for provider, details in models_dict.items()
208
+ ]
209
+
210
+ # Wait for all tasks to complete
211
+ results = await asyncio.gather(*tasks, return_exceptions=True)
212
+
213
+ # Process results
214
+ for result in results:
215
+ if isinstance(result, Exception):
216
+ print(f"Task failed with exception: {result}")
217
+ continue
218
+ provider, answer = result
219
+ if answer is not None: # Only add successful calls
220
+ competitors.append(provider)
221
+ answers.append(answer)
222
+
223
+ print(f"Async execution completed. {len(competitors)} models responded successfully.")
224
+
225
+ def together_maker(answers):
226
+ together = ""
227
+ for index, answer in enumerate(answers):
228
+ together += f"# Response from competitor {index+1}\n\n"
229
+ together += answer + "\n\n"
230
+ return together
231
+
232
+ def judge_prompt_generator(competitors, question, together):
233
+ judge = f"""You are judging a competition between {len(competitors)} competitors.
234
+ Each model has been given this question:
235
+
236
+ {question}
237
+
238
+ Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.
239
+ Respond with JSON, and only JSON, with the following format:
240
+ {{"results": ["best competitor number", "second best competitor number", "third best competitor number", ...]}}
241
+
242
+ Here are the responses from each competitor:
243
+
244
+ {together}
245
+
246
+ Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks."""
247
+ return judge
248
+
249
+ def judge_caller(judge_prompt, competitors):
250
+ print(f"Calling judge...")
251
+ judge_messages = [{"role": "user", "content": judge_prompt}]
252
+ results = llm_caller_with_model(judge_messages, "o3-mini", openai_api_key, None)
253
+ results_dict = json.loads(results)
254
+ ranks = results_dict["results"]
255
+ for index, result in enumerate(ranks):
256
+ competitor = competitors[int(result)-1]
257
+ print(f"Rank {index+1}: {competitor}")
258
+ return ranks
259
+
260
+ def compare_execution_methods(question_messages, runs_per_method=1):
261
+ """
262
+ Compare performance of different execution methods
263
+ """
264
+ methods = ['sequential', 'parallel', 'async']
265
+ results = {}
266
+
267
+ for method in methods:
268
+ print(f"\n{'='*50}")
269
+ print(f"Testing {method} execution method")
270
+ print(f"{'='*50}")
271
+
272
+ method_times = []
273
+
274
+ for run in range(runs_per_method):
275
+ print(f"\nRun {run + 1}/{runs_per_method}")
276
+
277
+ # Clear previous results
278
+ competitors.clear()
279
+ answers.clear()
280
+
281
+ start_time = time.time()
282
+
283
+ if method == 'sequential':
284
+ get_models_answers(question_messages)
285
+ elif method == 'parallel':
286
+ get_models_answers_parallel(question_messages, max_workers=4)
287
+ elif method == 'async':
288
+ asyncio.run(get_models_answers_async(question_messages))
289
+
290
+ execution_time = time.time() - start_time
291
+ method_times.append(execution_time)
292
+ print(f"Run {run + 1} completed in {execution_time:.2f} seconds")
293
+
294
+ avg_time = sum(method_times) / len(method_times)
295
+ results[method] = {
296
+ 'times': method_times,
297
+ 'avg_time': avg_time,
298
+ 'successful_models': len(competitors)
299
+ }
300
+
301
+ print(f"\n{method.upper()} Results:")
302
+ print(f" Average time: {avg_time:.2f} seconds")
303
+ print(f" Successful models: {len(competitors)}")
304
+ print(f" All times: {[f'{t:.2f}s' for t in method_times]}")
305
+
306
+ # Print comparison summary
307
+ print(f"\n{'='*60}")
308
+ print("PERFORMANCE COMPARISON SUMMARY")
309
+ print(f"{'='*60}")
310
+
311
+ for method, data in results.items():
312
+ print(f"{method.upper():>12}: {data['avg_time']:>6.2f}s avg, {data['successful_models']} models")
313
+
314
+ # Calculate speedup
315
+ if 'sequential' in results:
316
+ seq_time = results['sequential']['avg_time']
317
+ print(f"\nSpeedup vs Sequential:")
318
+ for method, data in results.items():
319
+ if method != 'sequential':
320
+ speedup = seq_time / data['avg_time']
321
+ print(f" {method.upper()}: {speedup:.2f}x faster")
322
+
323
+ return results
324
+
325
+ def run_llm_competition(question_messages, execution_method, question):
326
+ """
327
+ Run the LLM competition with the specified execution method
328
+ """
329
+ print(f"\nUsing {execution_method} execution method...")
330
+ start_time = time.time()
331
+
332
+ if execution_method == 'sequential':
333
+ get_models_answers(question_messages)
334
+ elif execution_method == 'parallel':
335
+ get_models_answers_parallel(question_messages, max_workers=4)
336
+ elif execution_method == 'async':
337
+ asyncio.run(get_models_answers_async(question_messages))
338
+ else:
339
+ raise ValueError(f"Unknown execution method: {execution_method}")
340
+
341
+ execution_time = time.time() - start_time
342
+ print(f"Execution completed in {execution_time:.2f} seconds")
343
+
344
+ together = together_maker(answers)
345
+ judge_prompt = judge_prompt_generator(competitors, question, together)
346
+ judge_caller(judge_prompt, competitors)
347
+
348
+ return execution_time
349
+
350
+ # Interactive execution method selection
351
+ def get_execution_method():
352
+ """
353
+ Prompt user to select execution method
354
+ """
355
+ print("\n" + "="*60)
356
+ print("EXECUTION METHOD SELECTION")
357
+ print("="*60)
358
+ print("Choose how to execute the LLM calls:")
359
+ print("1. Sequential - Call models one after another (original method)")
360
+ print("2. Parallel - Call all models simultaneously (recommended)")
361
+ print("3. Async - Use async/await for maximum performance")
362
+ print("4. Compare - Run all methods and compare performance")
363
+ print("="*60)
364
+
365
+ while True:
366
+ try:
367
+ choice = input("Enter your choice (1-4): ").strip()
368
+
369
+ if choice == '1':
370
+ return 'sequential'
371
+ elif choice == '2':
372
+ return 'parallel'
373
+ elif choice == '3':
374
+ return 'async'
375
+ elif choice == '4':
376
+ return 'compare'
377
+ else:
378
+ print("Invalid choice. Please enter 1, 2, 3, or 4.")
379
+ continue
380
+ except KeyboardInterrupt:
381
+ print("\nExiting...")
382
+ exit(0)
383
+ except EOFError:
384
+ print("\nExiting...")
385
+ exit(0)
386
+
387
+ def main():
388
+ key_checker()
389
+
390
+ # Get user's execution method choice
391
+ EXECUTION_METHOD = get_execution_method()
392
+ # Generate the competition question and get the question messages
393
+ question, question_messages = generate_competition_question()
394
+
395
+ if EXECUTION_METHOD == 'compare':
396
+ print("\nRunning performance comparison...")
397
+ compare_execution_methods(question_messages, runs_per_method=1)
398
+ else:
399
+ run_llm_competition(question_messages, EXECUTION_METHOD, question)
400
+
401
+ main()
community_contributions/2_lab2_Japyh_Reflection_Pattern.ipynb ADDED
@@ -0,0 +1,484 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "# Start with imports - ask ChatGPT to explain any package that you don't know\n",
19
+ "import os\n",
20
+ "import json\n",
21
+ "from dotenv import load_dotenv\n",
22
+ "from openai import OpenAI\n",
23
+ "from anthropic import Anthropic\n",
24
+ "from IPython.display import Markdown, display"
25
+ ]
26
+ },
27
+ {
28
+ "cell_type": "code",
29
+ "execution_count": null,
30
+ "metadata": {},
31
+ "outputs": [],
32
+ "source": [
33
+ "# Always remember to do this!\n",
34
+ "load_dotenv(override=True)"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": null,
40
+ "metadata": {},
41
+ "outputs": [],
42
+ "source": [
43
+ "# Print the key prefixes to help with any debugging\n",
44
+ "\n",
45
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
46
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
47
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
48
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
49
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
50
+ "\n",
51
+ "if openai_api_key:\n",
52
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
53
+ "else:\n",
54
+ " print(\"OpenAI API Key not set\")\n",
55
+ " \n",
56
+ "if anthropic_api_key:\n",
57
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
58
+ "else:\n",
59
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
60
+ "\n",
61
+ "if google_api_key:\n",
62
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
63
+ "else:\n",
64
+ " print(\"Google API Key not set (and this is optional)\")\n",
65
+ "\n",
66
+ "if deepseek_api_key:\n",
67
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
68
+ "else:\n",
69
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
70
+ "\n",
71
+ "if groq_api_key:\n",
72
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
73
+ "else:\n",
74
+ " print(\"Groq API Key not set (and this is optional)\")"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": null,
80
+ "metadata": {},
81
+ "outputs": [],
82
+ "source": [
83
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
84
+ "request += \"Answer only with the question, no explanation.\"\n",
85
+ "messages = [{\"role\": \"user\", \"content\": request}]"
86
+ ]
87
+ },
88
+ {
89
+ "cell_type": "code",
90
+ "execution_count": null,
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "messages"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "openai = OpenAI()\n",
104
+ "response = openai.chat.completions.create(\n",
105
+ " model=\"gpt-5-mini\",\n",
106
+ " messages=messages,\n",
107
+ ")\n",
108
+ "question = response.choices[0].message.content\n",
109
+ "print(question)"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": null,
115
+ "metadata": {},
116
+ "outputs": [],
117
+ "source": [
118
+ "competitors = []\n",
119
+ "answers = []\n",
120
+ "messages = [{\"role\": \"user\", \"content\": question}]"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "code",
125
+ "execution_count": null,
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "# The API we know well\n",
130
+ "# I've updated this with the latest model, but it can take some time because it likes to think!\n",
131
+ "# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\n",
132
+ "\n",
133
+ "model_name = \"gpt-5-nano\"\n",
134
+ "\n",
135
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
136
+ "answer = response.choices[0].message.content\n",
137
+ "\n",
138
+ "display(Markdown(answer))\n",
139
+ "competitors.append(model_name)\n",
140
+ "answers.append(answer)"
141
+ ]
142
+ },
143
+ {
144
+ "cell_type": "code",
145
+ "execution_count": null,
146
+ "metadata": {},
147
+ "outputs": [],
148
+ "source": [
149
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
150
+ "model_name = \"gemini-2.5-flash\"\n",
151
+ "\n",
152
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
153
+ "answer = response.choices[0].message.content\n",
154
+ "\n",
155
+ "display(Markdown(answer))\n",
156
+ "competitors.append(model_name)\n",
157
+ "answers.append(answer)"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "model_name = \"gemini-3-flash-preview\"\n",
167
+ "\n",
168
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
169
+ "answer = response.choices[0].message.content\n",
170
+ "\n",
171
+ "display(Markdown(answer))\n",
172
+ "competitors.append(model_name)\n",
173
+ "answers.append(answer)"
174
+ ]
175
+ },
176
+ {
177
+ "cell_type": "code",
178
+ "execution_count": null,
179
+ "metadata": {},
180
+ "outputs": [],
181
+ "source": [
182
+ "# So where are we?\n",
183
+ "print(competitors)\n",
184
+ "print(answers)"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": null,
190
+ "metadata": {},
191
+ "outputs": [],
192
+ "source": [
193
+ "# It's nice to know how to use \"zip\"\n",
194
+ "for competitor, answer in zip(competitors, answers):\n",
195
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# Let's bring this together - note the use of \"enumerate\"\n",
205
+ "together = \"\"\n",
206
+ "for index, answer in enumerate(answers):\n",
207
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
208
+ " together += answer + \"\\n\\n\""
209
+ ]
210
+ },
211
+ {
212
+ "cell_type": "code",
213
+ "execution_count": null,
214
+ "metadata": {},
215
+ "outputs": [],
216
+ "source": [
217
+ "print(together)"
218
+ ]
219
+ },
220
+ {
221
+ "cell_type": "code",
222
+ "execution_count": null,
223
+ "metadata": {},
224
+ "outputs": [],
225
+ "source": [
226
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
227
+ "Each model has been given this question:\n",
228
+ "\n",
229
+ "{question}\n",
230
+ "\n",
231
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
232
+ "Respond with JSON, and only JSON, with the following format:\n",
233
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
234
+ "\n",
235
+ "Here are the responses from each competitor:\n",
236
+ "\n",
237
+ "{together}\n",
238
+ "\n",
239
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
240
+ ]
241
+ },
242
+ {
243
+ "cell_type": "code",
244
+ "execution_count": null,
245
+ "metadata": {},
246
+ "outputs": [],
247
+ "source": [
248
+ "print(judge)"
249
+ ]
250
+ },
251
+ {
252
+ "cell_type": "code",
253
+ "execution_count": null,
254
+ "metadata": {},
255
+ "outputs": [],
256
+ "source": [
257
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
258
+ ]
259
+ },
260
+ {
261
+ "cell_type": "code",
262
+ "execution_count": null,
263
+ "metadata": {},
264
+ "outputs": [],
265
+ "source": [
266
+ "# Judgement time!\n",
267
+ "openai = OpenAI()\n",
268
+ "response = openai.chat.completions.create(\n",
269
+ " model=\"gpt-5-mini\",\n",
270
+ " messages=judge_messages,\n",
271
+ ")\n",
272
+ "results = response.choices[0].message.content\n",
273
+ "print(results)\n"
274
+ ]
275
+ },
276
+ {
277
+ "cell_type": "code",
278
+ "execution_count": null,
279
+ "metadata": {},
280
+ "outputs": [],
281
+ "source": [
282
+ "# OK let's turn this into results!\n",
283
+ "results_dict = json.loads(results)\n",
284
+ "ranks = results_dict[\"results\"]\n",
285
+ "for index, result in enumerate(ranks):\n",
286
+ " competitor = competitors[int(result)-1]\n",
287
+ " print(f\"Rank {index+1}: {competitor}\")"
288
+ ]
289
+ },
290
+ {
291
+ "cell_type": "markdown",
292
+ "metadata": {},
293
+ "source": [
294
+ "### Pattern(s) already used in this notebook\n",
295
+ "\n",
296
+ "| Pattern | Where it appears |\n",
297
+ "|---|---|\n",
298
+ "| **Multi-Agent Collaboration** | Multiple LLMs (GPT, Gemini Flash, Gemini Pro) independently answer the same question |\n",
299
+ "| **LLM-as-a-Judge / Orchestration** | A separate GPT instance acts as an orchestrator: it generates the question, collects all responses, then evaluates and ranks them |\n",
300
+ "\n",
301
+ "Together these form the **\"parallel generation + judge\"** agentic workflow.\n",
302
+ "\n",
303
+ "---\n",
304
+ "\n",
305
+ "### New pattern being added below: **Reflection**\n",
306
+ "\n",
307
+ "The Reflection pattern adds a *feedback loop*:\n",
308
+ "1. **Critique** — the judge analyses *why* the worst answer lost\n",
309
+ "2. **Reflect & Revise** — the losing model sees the critique and rewrites its answer\n",
310
+ "3. **Re-judge** — the revised answer is compared against the original winner\n",
311
+ "\n",
312
+ "This loop can be iterated until quality converges."
313
+ ]
314
+ },
315
+ {
316
+ "cell_type": "code",
317
+ "execution_count": null,
318
+ "metadata": {},
319
+ "outputs": [],
320
+ "source": [
321
+ "# ============================================================\n",
322
+ "# REFLECTION PATTERN\n",
323
+ "# ============================================================\n",
324
+ "# Pattern summary:\n",
325
+ "# 1. CRITIQUE — Ask the judge WHY the last-place competitor lost\n",
326
+ "# and what specifically was weak in its response.\n",
327
+ "# 2. REFLECT — Feed that critique back to the losing competitor\n",
328
+ "# so it can revise its answer.\n",
329
+ "# 3. RE-JUDGE — Compare the revised answer against the original\n",
330
+ "# winner to see whether quality improved.\n",
331
+ "#\n",
332
+ "# This closes the \"generate → evaluate → improve\" loop, which is\n",
333
+ "# the defining characteristic of the Reflection agentic pattern.\n",
334
+ "# ============================================================\n",
335
+ "\n",
336
+ "import json\n",
337
+ "from openai import OpenAI\n",
338
+ "\n",
339
+ "openai_client = OpenAI()\n",
340
+ "\n",
341
+ "# ----------------------------------------------------------\n",
342
+ "# Step 0: Identify the loser from the previous judge ranking\n",
343
+ "# ----------------------------------------------------------\n",
344
+ "# 'ranks' — list of competitor numbers ordered best→worst (from previous cells)\n",
345
+ "# 'competitors' — list of model names in the same positional order\n",
346
+ "# 'answers' — list of model answers in the same positional order\n",
347
+ "# 'question' — the original question every competitor answered\n",
348
+ "\n",
349
+ "# The last element in `ranks` is the worst-ranked competitor number (1-based string)\n",
350
+ "loser_rank_number = ranks[-1] # e.g. \"3\"\n",
351
+ "loser_index = int(loser_rank_number) - 1 # convert to 0-based index\n",
352
+ "loser_model = competitors[loser_index]\n",
353
+ "loser_answer = answers[loser_index]\n",
354
+ "\n",
355
+ "winner_rank_number = ranks[0]\n",
356
+ "winner_index = int(winner_rank_number) - 1\n",
357
+ "winner_model = competitors[winner_index]\n",
358
+ "winner_answer = answers[winner_index]\n",
359
+ "\n",
360
+ "print(f\"Winner : {winner_model}\")\n",
361
+ "print(f\"Loser : {loser_model}\")\n",
362
+ "\n",
363
+ "# ----------------------------------------------------------\n",
364
+ "# Step 1: CRITIQUE — ask the judge to explain the loser's flaws\n",
365
+ "# ----------------------------------------------------------\n",
366
+ "critique_prompt = f\"\"\"You previously judged responses to this question:\n",
367
+ "\n",
368
+ "{question}\n",
369
+ "\n",
370
+ "The weakest response was from Competitor {loser_rank_number}:\n",
371
+ "\n",
372
+ "{loser_answer}\n",
373
+ "\n",
374
+ "Please provide specific, constructive critique. Explain exactly what was unclear,\n",
375
+ "missing, or logically weak. Be direct so the model can act on your feedback.\"\"\"\n",
376
+ "\n",
377
+ "critique_messages = [{\"role\": \"user\", \"content\": critique_prompt}]\n",
378
+ "\n",
379
+ "critique_response = openai_client.chat.completions.create(\n",
380
+ " model=\"gpt-4.1-mini\", # Judge model — can use any capable LLM\n",
381
+ " messages=critique_messages,\n",
382
+ ")\n",
383
+ "critique = critique_response.choices[0].message.content\n",
384
+ "print(\"\\n--- CRITIQUE ---\\n\", critique)\n",
385
+ "\n",
386
+ "# ----------------------------------------------------------\n",
387
+ "# Step 2: REFLECT — send the critique back to the losing model\n",
388
+ "# so it can revise its answer (Reflection loop)\n",
389
+ "# ----------------------------------------------------------\n",
390
+ "# We re-use whichever client matches the losing competitor.\n",
391
+ "# For simplicity we route through the gemini client if it is a\n",
392
+ "# Gemini model, otherwise fall back to the OpenAI-compatible client.\n",
393
+ "\n",
394
+ "if \"gemini\" in loser_model.lower():\n",
395
+ " reflect_client = OpenAI(\n",
396
+ " api_key=google_api_key,\n",
397
+ " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n",
398
+ " )\n",
399
+ "else:\n",
400
+ " reflect_client = openai_client # Works for any OpenAI model\n",
401
+ "\n",
402
+ "reflect_prompt = f\"\"\"You previously answered this question:\n",
403
+ "\n",
404
+ "{question}\n",
405
+ "\n",
406
+ "Your original answer was:\n",
407
+ "\n",
408
+ "{loser_answer}\n",
409
+ "\n",
410
+ "A judge reviewed your answer and gave the following critique:\n",
411
+ "\n",
412
+ "{critique}\n",
413
+ "\n",
414
+ "Please reflect on this critique and write an improved answer.\n",
415
+ "Focus on addressing every point raised.\"\"\"\n",
416
+ "\n",
417
+ "reflect_messages = [{\"role\": \"user\", \"content\": reflect_prompt}]\n",
418
+ "\n",
419
+ "reflect_response = reflect_client.chat.completions.create(\n",
420
+ " model=loser_model, # Same model attempts to self-improve\n",
421
+ " messages=reflect_messages,\n",
422
+ ")\n",
423
+ "revised_answer = reflect_response.choices[0].message.content\n",
424
+ "print(\"\\n--- REVISED ANSWER ---\\n\", revised_answer)\n",
425
+ "\n",
426
+ "# ----------------------------------------------------------\n",
427
+ "# Step 3: RE-JUDGE — compare the revised answer against the\n",
428
+ "# original winner to see whether the Reflection loop helped\n",
429
+ "# ----------------------------------------------------------\n",
430
+ "rejudge_prompt = f\"\"\"You are evaluating two responses to this question:\n",
431
+ "\n",
432
+ "{question}\n",
433
+ "\n",
434
+ "Response A (original winner, from {winner_model}):\n",
435
+ "{winner_answer}\n",
436
+ "\n",
437
+ "Response B (revised answer, from {loser_model} after reflection):\n",
438
+ "{revised_answer}\n",
439
+ "\n",
440
+ "Evaluate which response is better: clearer, more accurate, and more insightful.\n",
441
+ "Respond with JSON only, in this format:\n",
442
+ "{{\"winner\": \"A or B\", \"reason\": \"one sentence explanation\"}}\"\"\"\n",
443
+ "\n",
444
+ "rejudge_messages = [{\"role\": \"user\", \"content\": rejudge_prompt}]\n",
445
+ "\n",
446
+ "rejudge_response = openai_client.chat.completions.create(\n",
447
+ " model=\"gpt-4.1-mini\",\n",
448
+ " messages=rejudge_messages,\n",
449
+ ")\n",
450
+ "rejudge_result = json.loads(rejudge_response.choices[0].message.content)\n",
451
+ "\n",
452
+ "print(\"\\n--- RE-JUDGE RESULT ---\")\n",
453
+ "print(f\"Winner after Reflection loop: Response {rejudge_result['winner']}\")\n",
454
+ "print(f\"Reason: {rejudge_result['reason']}\")\n",
455
+ "\n",
456
+ "if rejudge_result[\"winner\"] == \"B\":\n",
457
+ " print(f\"\\n✓ Reflection worked — {loser_model} improved enough to beat {winner_model}!\")\n",
458
+ "else:\n",
459
+ " print(f\"\\n✗ Reflection did not flip the result — {winner_model} still leads.\")"
460
+ ]
461
+ }
462
+ ],
463
+ "metadata": {
464
+ "kernelspec": {
465
+ "display_name": "agents",
466
+ "language": "python",
467
+ "name": "python3"
468
+ },
469
+ "language_info": {
470
+ "codemirror_mode": {
471
+ "name": "ipython",
472
+ "version": 3
473
+ },
474
+ "file_extension": ".py",
475
+ "mimetype": "text/x-python",
476
+ "name": "python",
477
+ "nbconvert_exporter": "python",
478
+ "pygments_lexer": "ipython3",
479
+ "version": "3.12.12"
480
+ }
481
+ },
482
+ "nbformat": 4,
483
+ "nbformat_minor": 2
484
+ }
community_contributions/2_lab2_Mohan_M.ipynb ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": null,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# 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": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "# Always remember to do this!\n",
53
+ "load_dotenv(override=True)"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "code",
58
+ "execution_count": null,
59
+ "metadata": {},
60
+ "outputs": [],
61
+ "source": [
62
+ "# Print the key prefixes to help with any debugging\n",
63
+ "\n",
64
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
65
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
66
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
67
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
68
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
69
+ "\n",
70
+ "if openai_api_key:\n",
71
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
72
+ "else:\n",
73
+ " print(\"OpenAI API Key not set\")\n",
74
+ " \n",
75
+ "if anthropic_api_key:\n",
76
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
77
+ "else:\n",
78
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
79
+ "\n",
80
+ "if google_api_key:\n",
81
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
82
+ "else:\n",
83
+ " print(\"Google API Key not set (and this is optional)\")\n",
84
+ "\n",
85
+ "if deepseek_api_key:\n",
86
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
87
+ "else:\n",
88
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
89
+ "\n",
90
+ "if groq_api_key:\n",
91
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
92
+ "else:\n",
93
+ " print(\"Groq API Key not set (and this is optional)\")"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": null,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
103
+ "request += \"Answer only with the question, no explanation.\"\n",
104
+ "messages = [{\"role\": \"user\", \"content\": request}]"
105
+ ]
106
+ },
107
+ {
108
+ "cell_type": "code",
109
+ "execution_count": null,
110
+ "metadata": {},
111
+ "outputs": [],
112
+ "source": [
113
+ "messages"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": null,
119
+ "metadata": {},
120
+ "outputs": [],
121
+ "source": [
122
+ "openai = OpenAI()\n",
123
+ "response = openai.chat.completions.create(\n",
124
+ " model=\"gpt-5-mini\",\n",
125
+ " messages=messages,\n",
126
+ ")\n",
127
+ "question = response.choices[0].message.content\n",
128
+ "print(question)\n"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "competitors = []\n",
138
+ "answers = []\n",
139
+ "messages = [{\"role\": \"user\", \"content\": question}]"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "markdown",
144
+ "metadata": {},
145
+ "source": [
146
+ "## Note - update since the videos\n",
147
+ "\n",
148
+ "I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video."
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "code",
153
+ "execution_count": null,
154
+ "metadata": {},
155
+ "outputs": [],
156
+ "source": [
157
+ "# The API we know well\n",
158
+ "# I've updated this with the latest model, but it can take some time because it likes to think!\n",
159
+ "# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\n",
160
+ "\n",
161
+ "model_name = \"gpt-5-nano\"\n",
162
+ "\n",
163
+ "response = openai.chat.completions.create(model=model_name, messages=messages)\n",
164
+ "answer = response.choices[0].message.content\n",
165
+ "\n",
166
+ "display(Markdown(answer))\n",
167
+ "competitors.append(model_name)\n",
168
+ "answers.append(answer)"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": null,
174
+ "metadata": {},
175
+ "outputs": [],
176
+ "source": [
177
+ "# Anthropic has a slightly different API, and Max Tokens is required\n",
178
+ "\n",
179
+ "model_name = \"claude-sonnet-4-5\"\n",
180
+ "\n",
181
+ "claude = Anthropic()\n",
182
+ "response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
183
+ "answer = response.content[0].text\n",
184
+ "\n",
185
+ "display(Markdown(answer))\n",
186
+ "competitors.append(model_name)\n",
187
+ "answers.append(answer)"
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "metadata": {},
194
+ "outputs": [],
195
+ "source": [
196
+ "gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
197
+ "model_name = \"gemini-2.5-flash\"\n",
198
+ "\n",
199
+ "response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
200
+ "answer = response.choices[0].message.content\n",
201
+ "\n",
202
+ "display(Markdown(answer))\n",
203
+ "competitors.append(model_name)\n",
204
+ "answers.append(answer)"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "code",
209
+ "execution_count": null,
210
+ "metadata": {},
211
+ "outputs": [],
212
+ "source": [
213
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
214
+ "model_name = \"deepseek-chat\"\n",
215
+ "\n",
216
+ "response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
217
+ "answer = response.choices[0].message.content\n",
218
+ "\n",
219
+ "display(Markdown(answer))\n",
220
+ "competitors.append(model_name)\n",
221
+ "answers.append(answer)"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": null,
227
+ "metadata": {},
228
+ "outputs": [],
229
+ "source": [
230
+ "# Updated with the latest Open Source model from OpenAI\n",
231
+ "\n",
232
+ "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
233
+ "model_name = \"openai/gpt-oss-120b\"\n",
234
+ "\n",
235
+ "response = groq.chat.completions.create(model=model_name, messages=messages)\n",
236
+ "answer = response.choices[0].message.content\n",
237
+ "\n",
238
+ "display(Markdown(answer))\n",
239
+ "competitors.append(model_name)\n",
240
+ "answers.append(answer)\n"
241
+ ]
242
+ },
243
+ {
244
+ "cell_type": "markdown",
245
+ "metadata": {},
246
+ "source": [
247
+ "## For the next cell, we will use Ollama\n",
248
+ "\n",
249
+ "Ollama runs a local web service that gives an OpenAI compatible endpoint, \n",
250
+ "and runs models locally using high performance C++ code.\n",
251
+ "\n",
252
+ "If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\n",
253
+ "\n",
254
+ "After it's installed, you should be able to visit here: http://localhost:11434 and see the message \"Ollama is running\"\n",
255
+ "\n",
256
+ "You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\`) and run `ollama serve`\n",
257
+ "\n",
258
+ "Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\n",
259
+ "\n",
260
+ "`ollama pull <model_name>` downloads a model locally \n",
261
+ "`ollama ls` lists all the models you've downloaded \n",
262
+ "`ollama rm <model_name>` deletes the specified model from your downloads"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "markdown",
267
+ "metadata": {},
268
+ "source": [
269
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
270
+ " <tr>\n",
271
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
272
+ " <img src=\"../assets/stop.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
273
+ " </td>\n",
274
+ " <td>\n",
275
+ " <h2 style=\"color:#ff7800;\">Super important - ignore me at your peril!</h2>\n",
276
+ " <span style=\"color:#ff7800;\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\"https://ollama.com/models\">the Ollama models page</a> for a full list of models and sizes.\n",
277
+ " </span>\n",
278
+ " </td>\n",
279
+ " </tr>\n",
280
+ "</table>"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": null,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "!ollama pull llama3.2"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": null,
295
+ "metadata": {},
296
+ "outputs": [],
297
+ "source": [
298
+ "ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
299
+ "model_name = \"llama3.2\"\n",
300
+ "\n",
301
+ "response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
302
+ "answer = response.choices[0].message.content\n",
303
+ "\n",
304
+ "display(Markdown(answer))\n",
305
+ "competitors.append(model_name)\n",
306
+ "answers.append(answer)"
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "code",
311
+ "execution_count": null,
312
+ "metadata": {},
313
+ "outputs": [],
314
+ "source": [
315
+ "# So where are we?\n",
316
+ "\n",
317
+ "print(competitors)\n",
318
+ "print(answers)\n"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "code",
323
+ "execution_count": null,
324
+ "metadata": {},
325
+ "outputs": [],
326
+ "source": [
327
+ "# It's nice to know how to use \"zip\"\n",
328
+ "for competitor, answer in zip(competitors, answers):\n",
329
+ " print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
330
+ ]
331
+ },
332
+ {
333
+ "cell_type": "code",
334
+ "execution_count": null,
335
+ "metadata": {},
336
+ "outputs": [],
337
+ "source": [
338
+ "# Let's bring this together - note the use of \"enumerate\"\n",
339
+ "\n",
340
+ "together = \"\"\n",
341
+ "for index, answer in enumerate(answers):\n",
342
+ " together += f\"# Response from competitor {index+1}\\n\\n\"\n",
343
+ " together += answer + \"\\n\\n\""
344
+ ]
345
+ },
346
+ {
347
+ "cell_type": "code",
348
+ "execution_count": null,
349
+ "metadata": {},
350
+ "outputs": [],
351
+ "source": [
352
+ "print(together)"
353
+ ]
354
+ },
355
+ {
356
+ "cell_type": "markdown",
357
+ "metadata": {},
358
+ "source": []
359
+ },
360
+ {
361
+ "cell_type": "code",
362
+ "execution_count": null,
363
+ "metadata": {},
364
+ "outputs": [],
365
+ "source": [
366
+ "judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
367
+ "Each model has been given this question:\n",
368
+ "\n",
369
+ "{question}\n",
370
+ "\n",
371
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
372
+ "Respond with JSON, and only JSON, with the following format:\n",
373
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
374
+ "\n",
375
+ "Here are the responses from each competitor:\n",
376
+ "\n",
377
+ "{together}\n",
378
+ "\n",
379
+ "Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\"\"\"\n"
380
+ ]
381
+ },
382
+ {
383
+ "cell_type": "code",
384
+ "execution_count": null,
385
+ "metadata": {},
386
+ "outputs": [],
387
+ "source": [
388
+ "print(judge)"
389
+ ]
390
+ },
391
+ {
392
+ "cell_type": "code",
393
+ "execution_count": null,
394
+ "metadata": {},
395
+ "outputs": [],
396
+ "source": [
397
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
398
+ ]
399
+ },
400
+ {
401
+ "cell_type": "code",
402
+ "execution_count": null,
403
+ "metadata": {},
404
+ "outputs": [],
405
+ "source": [
406
+ "# Judgement time!\n",
407
+ "\n",
408
+ "openai = OpenAI()\n",
409
+ "response = openai.chat.completions.create(\n",
410
+ " model=\"gpt-5-mini\",\n",
411
+ " messages=judge_messages,\n",
412
+ ")\n",
413
+ "results = response.choices[0].message.content\n",
414
+ "print(results)\n"
415
+ ]
416
+ },
417
+ {
418
+ "cell_type": "code",
419
+ "execution_count": null,
420
+ "metadata": {},
421
+ "outputs": [],
422
+ "source": [
423
+ "# OK let's turn this into results!\n",
424
+ "\n",
425
+ "results_dict = json.loads(results)\n",
426
+ "ranks = results_dict[\"results\"]\n",
427
+ "for index, result in enumerate(ranks):\n",
428
+ " competitor = competitors[int(result)-1]\n",
429
+ " print(f\"Rank {index+1}: {competitor}\")"
430
+ ]
431
+ },
432
+ {
433
+ "cell_type": "markdown",
434
+ "metadata": {},
435
+ "source": [
436
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
437
+ " <tr>\n",
438
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
439
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
440
+ " </td>\n",
441
+ " <td>\n",
442
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
443
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
444
+ " </span>\n",
445
+ " </td>\n",
446
+ " </tr>\n",
447
+ "</table>"
448
+ ]
449
+ },
450
+ {
451
+ "cell_type": "markdown",
452
+ "metadata": {},
453
+ "source": [
454
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
455
+ " <tr>\n",
456
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
457
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
458
+ " </td>\n",
459
+ " <td>\n",
460
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
461
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
462
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
463
+ " to business projects where accuracy is critical.\n",
464
+ " </span>\n",
465
+ " </td>\n",
466
+ " </tr>\n",
467
+ "</table>"
468
+ ]
469
+ }
470
+ ],
471
+ "metadata": {
472
+ "kernelspec": {
473
+ "display_name": ".venv",
474
+ "language": "python",
475
+ "name": "python3"
476
+ },
477
+ "language_info": {
478
+ "codemirror_mode": {
479
+ "name": "ipython",
480
+ "version": 3
481
+ },
482
+ "file_extension": ".py",
483
+ "mimetype": "text/x-python",
484
+ "name": "python",
485
+ "nbconvert_exporter": "python",
486
+ "pygments_lexer": "ipython3",
487
+ "version": "3.12.9"
488
+ }
489
+ },
490
+ "nbformat": 4,
491
+ "nbformat_minor": 2
492
+ }
community_contributions/2_lab2_ReAct_Pattern.ipynb ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
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;\">Important point - please read</h2>\n",
23
+ " <span style=\"color:#ff7800;\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\n",
24
+ " </span>\n",
25
+ " </td>\n",
26
+ " </tr>\n",
27
+ "</table>"
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "markdown",
32
+ "metadata": {},
33
+ "source": [
34
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
35
+ " <tr>\n",
36
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
37
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
38
+ " </td>\n",
39
+ " <td>\n",
40
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
41
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
42
+ " </span>\n",
43
+ " </td>\n",
44
+ " </tr>\n",
45
+ "</table>"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "markdown",
50
+ "metadata": {},
51
+ "source": [
52
+ "# ReAct Pattern"
53
+ ]
54
+ },
55
+ {
56
+ "cell_type": "code",
57
+ "execution_count": 26,
58
+ "metadata": {},
59
+ "outputs": [],
60
+ "source": [
61
+ "import openai\n",
62
+ "import os\n",
63
+ "from dotenv import load_dotenv\n",
64
+ "import io\n",
65
+ "from anthropic import Anthropic\n",
66
+ "from IPython.display import Markdown, display"
67
+ ]
68
+ },
69
+ {
70
+ "cell_type": "code",
71
+ "execution_count": null,
72
+ "metadata": {},
73
+ "outputs": [],
74
+ "source": [
75
+ "# Print the key prefixes to help with any debugging\n",
76
+ "\n",
77
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
78
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
79
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
80
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
81
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
82
+ "\n",
83
+ "if openai_api_key:\n",
84
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
85
+ "else:\n",
86
+ " print(\"OpenAI API Key not set\")\n",
87
+ " \n",
88
+ "if anthropic_api_key:\n",
89
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
90
+ "else:\n",
91
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
92
+ "\n",
93
+ "if google_api_key:\n",
94
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
95
+ "else:\n",
96
+ " print(\"Google API Key not set (and this is optional)\")\n",
97
+ "\n",
98
+ "if deepseek_api_key:\n",
99
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
100
+ "else:\n",
101
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
102
+ "\n",
103
+ "if groq_api_key:\n",
104
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
105
+ "else:\n",
106
+ " print(\"Groq API Key not set (and this is optional)\")"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "code",
111
+ "execution_count": 50,
112
+ "metadata": {},
113
+ "outputs": [],
114
+ "source": [
115
+ "\n",
116
+ "from openai import OpenAI\n",
117
+ "\n",
118
+ "openai = OpenAI()\n",
119
+ "\n",
120
+ "# Request prompt\n",
121
+ "request = (\n",
122
+ " \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
123
+ " \"Answer only with the question, no explanation.\"\n",
124
+ ")\n",
125
+ "\n",
126
+ "\n",
127
+ "\n",
128
+ "def generate_question(prompt: str) -> str:\n",
129
+ " response = openai.chat.completions.create(\n",
130
+ " model='gpt-4o-mini',\n",
131
+ " messages=[{'role': 'user', 'content': prompt}]\n",
132
+ " )\n",
133
+ " question = response.choices[0].message.content\n",
134
+ " return question\n",
135
+ "\n",
136
+ "def react_agent_decide_model(question: str) -> str:\n",
137
+ " prompt = f\"\"\"\n",
138
+ " You are an intelligent AI assistant tasked with evaluating which language model is most suitable to answer a given question.\n",
139
+ "\n",
140
+ " Available models:\n",
141
+ " - OpenAI: excels at reasoning and factual answers.\n",
142
+ " - Claude: better for philosophical, nuanced, and ethical topics.\n",
143
+ " - Gemini: good for concise and structured summaries.\n",
144
+ " - Groq: good for creative or exploratory tasks.\n",
145
+ " - DeepSeek: strong at coding, technical reasoning, and multilingual responses.\n",
146
+ "\n",
147
+ " Here is the question to answer:\n",
148
+ " \"{question}\"\n",
149
+ "\n",
150
+ " ### Thought:\n",
151
+ " Which model is best suited to answer this question, and why?\n",
152
+ "\n",
153
+ " ### Action:\n",
154
+ " Respond with only the model name you choose (e.g., \"Claude\").\n",
155
+ " \"\"\"\n",
156
+ "\n",
157
+ " response = openai.chat.completions.create(\n",
158
+ " model=\"o3-mini\",\n",
159
+ " messages=[{\"role\": \"user\", \"content\": prompt}]\n",
160
+ " )\n",
161
+ " model = response.choices[0].message.content.strip()\n",
162
+ " return model\n",
163
+ "\n",
164
+ "def generate_answer_openai(prompt):\n",
165
+ " answer = openai.chat.completions.create(\n",
166
+ " model='gpt-4o-mini',\n",
167
+ " messages=[{'role': 'user', 'content': prompt}]\n",
168
+ " ).choices[0].message.content\n",
169
+ " return answer\n",
170
+ "\n",
171
+ "def generate_answer_anthropic(prompt):\n",
172
+ " anthropic = Anthropic(api_key=anthropic_api_key)\n",
173
+ " model_name = \"claude-3-5-sonnet-20240620\"\n",
174
+ " answer = anthropic.messages.create(\n",
175
+ " model=model_name,\n",
176
+ " messages=[{'role': 'user', 'content': prompt}],\n",
177
+ " max_tokens=1000\n",
178
+ " ).content[0].text\n",
179
+ " return answer\n",
180
+ "\n",
181
+ "def generate_answer_deepseek(prompt):\n",
182
+ " deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
183
+ " model_name = \"deepseek-chat\" \n",
184
+ " answer = deepseek.chat.completions.create(\n",
185
+ " model=model_name,\n",
186
+ " messages=[{'role': 'user', 'content': prompt}],\n",
187
+ " base_url='https://api.deepseek.com/v1'\n",
188
+ " ).choices[0].message.content\n",
189
+ " return answer\n",
190
+ "\n",
191
+ "def generate_answer_gemini(prompt):\n",
192
+ " gemini=OpenAI(base_url='https://generativelanguage.googleapis.com/v1beta/openai/',api_key=google_api_key)\n",
193
+ " model_name = \"gemini-2.0-flash\"\n",
194
+ " answer = gemini.chat.completions.create(\n",
195
+ " model=model_name,\n",
196
+ " messages=[{'role': 'user', 'content': prompt}],\n",
197
+ " ).choices[0].message.content\n",
198
+ " return answer\n",
199
+ "\n",
200
+ "def generate_answer_groq(prompt):\n",
201
+ " groq=OpenAI(base_url='https://api.groq.com/openai/v1',api_key=groq_api_key)\n",
202
+ " model_name=\"llama3-70b-8192\"\n",
203
+ " answer = groq.chat.completions.create(\n",
204
+ " model=model_name,\n",
205
+ " messages=[{'role': 'user', 'content': prompt}],\n",
206
+ " base_url=\"https://api.groq.com/openai/v1\"\n",
207
+ " ).choices[0].message.content\n",
208
+ " return answer\n",
209
+ "\n",
210
+ "def main():\n",
211
+ " print(\"Generating question...\")\n",
212
+ " question = generate_question(request)\n",
213
+ " print(f\"\\n🧠 Question: {question}\\n\")\n",
214
+ " selected_model = react_agent_decide_model(question)\n",
215
+ " print(f\"\\n🔹 {selected_model}:\\n\")\n",
216
+ " \n",
217
+ " if selected_model.lower() == \"openai\":\n",
218
+ " answer = generate_answer_openai(question)\n",
219
+ " elif selected_model.lower() == \"deepseek\":\n",
220
+ " answer = generate_answer_deepseek(question)\n",
221
+ " elif selected_model.lower() == \"gemini\":\n",
222
+ " answer = generate_answer_gemini(question)\n",
223
+ " elif selected_model.lower() == \"groq\":\n",
224
+ " answer = generate_answer_groq(question)\n",
225
+ " elif selected_model.lower() == \"claude\":\n",
226
+ " answer = generate_answer_anthropic(question)\n",
227
+ " print(f\"\\n🔹 {selected_model}:\\n{answer}\\n\")\n",
228
+ " \n"
229
+ ]
230
+ },
231
+ {
232
+ "cell_type": "code",
233
+ "execution_count": null,
234
+ "metadata": {},
235
+ "outputs": [],
236
+ "source": [
237
+ "main()"
238
+ ]
239
+ },
240
+ {
241
+ "cell_type": "code",
242
+ "execution_count": null,
243
+ "metadata": {},
244
+ "outputs": [],
245
+ "source": []
246
+ },
247
+ {
248
+ "cell_type": "markdown",
249
+ "metadata": {},
250
+ "source": [
251
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
252
+ " <tr>\n",
253
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
254
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
255
+ " </td>\n",
256
+ " <td>\n",
257
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
258
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
259
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
260
+ " to business projects where accuracy is critical.\n",
261
+ " </span>\n",
262
+ " </td>\n",
263
+ " </tr>\n",
264
+ "</table>"
265
+ ]
266
+ }
267
+ ],
268
+ "metadata": {
269
+ "kernelspec": {
270
+ "display_name": ".venv",
271
+ "language": "python",
272
+ "name": "python3"
273
+ },
274
+ "language_info": {
275
+ "codemirror_mode": {
276
+ "name": "ipython",
277
+ "version": 3
278
+ },
279
+ "file_extension": ".py",
280
+ "mimetype": "text/x-python",
281
+ "name": "python",
282
+ "nbconvert_exporter": "python",
283
+ "pygments_lexer": "ipython3",
284
+ "version": "3.12.4"
285
+ }
286
+ },
287
+ "nbformat": 4,
288
+ "nbformat_minor": 2
289
+ }
community_contributions/2_lab2_akash_parallelization.ipynb ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## Welcome to the Second Lab - Week 1, Day 3\n",
8
+ "\n",
9
+ "Today we will work with lots of models! This is a way to get comfortable with APIs."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "# Start with imports - ask ChatGPT to explain any package that you don't know\n",
19
+ "\n",
20
+ "import os\n",
21
+ "import json\n",
22
+ "from dotenv import load_dotenv\n",
23
+ "from openai import OpenAI, AsyncOpenAI\n",
24
+ "from IPython.display import Markdown, display\n",
25
+ "import asyncio\n",
26
+ "from functools import partial"
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "code",
31
+ "execution_count": null,
32
+ "metadata": {},
33
+ "outputs": [],
34
+ "source": [
35
+ "# Always remember to do this!\n",
36
+ "load_dotenv(override=True)"
37
+ ]
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "execution_count": null,
42
+ "metadata": {},
43
+ "outputs": [],
44
+ "source": [
45
+ "# Print the key prefixes to help with any debugging\n",
46
+ "\n",
47
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
48
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
49
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
50
+ "\n",
51
+ "if openai_api_key:\n",
52
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
53
+ "else:\n",
54
+ " print(\"OpenAI API Key not set\")\n",
55
+ "\n",
56
+ "\n",
57
+ "if google_api_key:\n",
58
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
59
+ "else:\n",
60
+ " print(\"Google API Key not set (and this is optional)\")\n",
61
+ "\n",
62
+ "if groq_api_key:\n",
63
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
64
+ "else:\n",
65
+ " print(\"Groq API Key not set (and this is optional)\")"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": null,
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \"\n",
75
+ "request += \"Answer only with the question, no explanation.\"\n",
76
+ "messages = [{\"role\": \"user\", \"content\": request}]"
77
+ ]
78
+ },
79
+ {
80
+ "cell_type": "code",
81
+ "execution_count": null,
82
+ "metadata": {},
83
+ "outputs": [],
84
+ "source": [
85
+ "openai = AsyncOpenAI()\n",
86
+ "response = await openai.chat.completions.create(\n",
87
+ " model=\"gpt-4o-mini\",\n",
88
+ " messages=messages,\n",
89
+ ")\n",
90
+ "question = response.choices[0].message.content\n",
91
+ "print(question)\n"
92
+ ]
93
+ },
94
+ {
95
+ "cell_type": "code",
96
+ "execution_count": null,
97
+ "metadata": {},
98
+ "outputs": [],
99
+ "source": [
100
+ "messages = [{\"role\": \"user\", \"content\": question}]"
101
+ ]
102
+ },
103
+ {
104
+ "cell_type": "code",
105
+ "execution_count": null,
106
+ "metadata": {},
107
+ "outputs": [],
108
+ "source": [
109
+ "from dataclasses import dataclass\n",
110
+ "\n",
111
+ "@dataclass\n",
112
+ "class LLMResource:\n",
113
+ " api_key: str\n",
114
+ " model: str\n",
115
+ " url: str = None # optional otherwise NOone\n",
116
+ "\n",
117
+ "llm_resources = [\n",
118
+ " LLMResource(api_key=openai_api_key, model=\"gpt-4o-mini\"),\n",
119
+ " LLMResource(api_key=google_api_key, model=\"gemini-2.5-flash\", url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"),\n",
120
+ " LLMResource(api_key=groq_api_key, model=\"qwen/qwen3-32b\", url=\"https://api.groq.com/openai/v1\"),\n",
121
+ " LLMResource(api_key=\"ollama\", model=\"deepseek-r1:1.5b\", url=\"http://localhost:11434/v1\" )\n",
122
+ "]\n"
123
+ ]
124
+ },
125
+ {
126
+ "cell_type": "code",
127
+ "execution_count": null,
128
+ "metadata": {},
129
+ "outputs": [],
130
+ "source": [
131
+ "\n",
132
+ "\n",
133
+ "async def llm_call(key, model_name, url, messages) -> tuple:\n",
134
+ " if url is None:\n",
135
+ " llm = AsyncOpenAI(api_key=key)\n",
136
+ " else: \n",
137
+ " llm = AsyncOpenAI(base_url=url,api_key=key)\n",
138
+ " \n",
139
+ " response = await llm.chat.completions.create(\n",
140
+ " model=model_name, messages=messages)\n",
141
+ " \n",
142
+ " answer = (model_name, response.choices[0].message.content)\n",
143
+ "\n",
144
+ " return answer #returns tuple of modle and response from LLM\n",
145
+ "\n",
146
+ "llm_callable = partial(llm_call, messages=messages) #prefill with messages\n",
147
+ "# Always remember to do this!"
148
+ ]
149
+ },
150
+ {
151
+ "cell_type": "code",
152
+ "execution_count": null,
153
+ "metadata": {},
154
+ "outputs": [],
155
+ "source": [
156
+ "#gather all responses concurrently\n",
157
+ "tasks = [llm_callable(res.api_key,res.model,res.url) for res in llm_resources]\n",
158
+ "results = await asyncio.gather(*tasks)\n",
159
+ "together = [f'Response from competitor {model}:{answer}' for model,answer in results]#gather results once all model finish running\n"
160
+ ]
161
+ },
162
+ {
163
+ "cell_type": "code",
164
+ "execution_count": null,
165
+ "metadata": {},
166
+ "outputs": [],
167
+ "source": [
168
+ "judge = f\"\"\"You are judging a competition between {len(llm_resources)} competitors.\n",
169
+ "Each model has been given this question:\n",
170
+ "\n",
171
+ "{request}\n",
172
+ "\n",
173
+ "Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\n",
174
+ "Respond with JSON, and only JSON, with the following format:\n",
175
+ "{{\"results\": [\"best competitor number\", \"second best competitor number\", \"third best competitor number\", ...]}}\n",
176
+ "\n",
177
+ "Here are the responses from each competitor:\n",
178
+ "\n",
179
+ "{together} # all responses\n",
180
+ "\n",
181
+ "Now respond with the JSON with the ranked order of the competitors name, nothing else. Do not include markdown formatting or code blocks.\"\"\""
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "code",
186
+ "execution_count": null,
187
+ "metadata": {},
188
+ "outputs": [],
189
+ "source": [
190
+ "print(judge)"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "metadata": {},
197
+ "outputs": [],
198
+ "source": [
199
+ "judge_messages = [{\"role\": \"user\", \"content\": judge}]"
200
+ ]
201
+ },
202
+ {
203
+ "cell_type": "code",
204
+ "execution_count": null,
205
+ "metadata": {},
206
+ "outputs": [],
207
+ "source": [
208
+ "# Judgement time!\n",
209
+ "\n",
210
+ "openai = OpenAI()\n",
211
+ "response = openai.chat.completions.create(\n",
212
+ " model=\"o3-mini\",\n",
213
+ " messages=judge_messages,\n",
214
+ ")\n",
215
+ "results = response.choices[0].message.content\n",
216
+ "print(results)\n"
217
+ ]
218
+ },
219
+ {
220
+ "cell_type": "code",
221
+ "execution_count": null,
222
+ "metadata": {},
223
+ "outputs": [],
224
+ "source": [
225
+ "# OK let's turn this into results!\n",
226
+ "\n",
227
+ "results_dict = json.loads(results)\n",
228
+ "\n",
229
+ "ranks = results_dict[\"results\"]\n",
230
+ "\n",
231
+ "for index, result in enumerate(ranks):\n",
232
+ " print(f\"Rank {index+1}: {result}\")"
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "markdown",
237
+ "metadata": {},
238
+ "source": [
239
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
240
+ " <tr>\n",
241
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
242
+ " <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
243
+ " </td>\n",
244
+ " <td>\n",
245
+ " <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
246
+ " <span style=\"color:#ff7800;\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\n",
247
+ " </span>\n",
248
+ " </td>\n",
249
+ " </tr>\n",
250
+ "</table>"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "markdown",
255
+ "metadata": {},
256
+ "source": [
257
+ "<table style=\"margin: 0; text-align: left; width:100%\">\n",
258
+ " <tr>\n",
259
+ " <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
260
+ " <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
261
+ " </td>\n",
262
+ " <td>\n",
263
+ " <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
264
+ " <span style=\"color:#00bfff;\">These kinds of patterns - to send a task to multiple models, and evaluate results,\n",
265
+ " are common where you need to improve the quality of your LLM response. This approach can be universally applied\n",
266
+ " to business projects where accuracy is critical.\n",
267
+ " </span>\n",
268
+ " </td>\n",
269
+ " </tr>\n",
270
+ "</table>"
271
+ ]
272
+ }
273
+ ],
274
+ "metadata": {
275
+ "kernelspec": {
276
+ "display_name": ".venv",
277
+ "language": "python",
278
+ "name": "python3"
279
+ },
280
+ "language_info": {
281
+ "codemirror_mode": {
282
+ "name": "ipython",
283
+ "version": 3
284
+ },
285
+ "file_extension": ".py",
286
+ "mimetype": "text/x-python",
287
+ "name": "python",
288
+ "nbconvert_exporter": "python",
289
+ "pygments_lexer": "ipython3",
290
+ "version": "3.12.3"
291
+ }
292
+ },
293
+ "nbformat": 4,
294
+ "nbformat_minor": 2
295
+ }