Upload folder using huggingface_hub
Browse files- 1_lab1.ipynb +603 -0
- 2_lab2.ipynb +474 -0
- 3_lab3.ipynb +581 -0
- 3_lab3.py +246 -0
- 4_lab4.ipynb +0 -0
- README.md +3 -9
- app.py +134 -0
- community_contributions/1_lab1_Mudassar.ipynb +260 -0
- community_contributions/1_lab1_Thanh.ipynb +165 -0
- community_contributions/1_lab1_gemini.ipynb +306 -0
- community_contributions/1_lab1_groq_llama.ipynb +296 -0
- community_contributions/1_lab1_open_router.ipynb +323 -0
- community_contributions/2_lab2_exercise.ipynb +336 -0
- community_contributions/3_lab3_groq_llama_generator_gemini_evaluator.ipynb +286 -0
- community_contributions/Business_Idea.ipynb +388 -0
- community_contributions/Multi-Model-Resume–JD-Match-Analyzer/.gitignore +1 -0
- community_contributions/Multi-Model-Resume/342/200/223JD-Match-Analyzer/AnalyzeResume.png +0 -0
- community_contributions/Multi-Model-Resume–JD-Match-Analyzer/README.md +48 -0
- community_contributions/Multi-Model-Resume–JD-Match-Analyzer/multi_file_ingestion.py +44 -0
- community_contributions/Multi-Model-Resume–JD-Match-Analyzer/resume_agent.py +262 -0
- community_contributions/app_rate_limiter_mailgun_integration.py +231 -0
- community_contributions/community.ipynb +29 -0
- community_contributions/llm-evaluator.ipynb +385 -0
- community_contributions/my_1_lab1.ipynb +405 -0
- community_contributions/travel_planner_multicall_and_sythesizer.ipynb +287 -0
- me/linkedin.pdf +0 -0
- me/linkedin.pdf_old +0 -0
- me/summary.txt +2 -0
- requirements.txt +6 -0
1_lab1.ipynb
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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": 1,
|
| 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": 2,
|
| 98 |
+
"metadata": {},
|
| 99 |
+
"outputs": [
|
| 100 |
+
{
|
| 101 |
+
"data": {
|
| 102 |
+
"text/plain": [
|
| 103 |
+
"True"
|
| 104 |
+
]
|
| 105 |
+
},
|
| 106 |
+
"execution_count": 2,
|
| 107 |
+
"metadata": {},
|
| 108 |
+
"output_type": "execute_result"
|
| 109 |
+
}
|
| 110 |
+
],
|
| 111 |
+
"source": [
|
| 112 |
+
"# Next it's time to load the API keys into environment variables\n",
|
| 113 |
+
"\n",
|
| 114 |
+
"load_dotenv(override=True)"
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"cell_type": "code",
|
| 119 |
+
"execution_count": null,
|
| 120 |
+
"metadata": {},
|
| 121 |
+
"outputs": [
|
| 122 |
+
{
|
| 123 |
+
"name": "stdout",
|
| 124 |
+
"output_type": "stream",
|
| 125 |
+
"text": [
|
| 126 |
+
"OpenRouter API Key exists and begins sk-or-v1\n",
|
| 127 |
+
"OpenAI API Key exists and begins sk-proj-\n"
|
| 128 |
+
]
|
| 129 |
+
}
|
| 130 |
+
],
|
| 131 |
+
"source": [
|
| 132 |
+
"# Check the keys\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"import os\n",
|
| 135 |
+
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
|
| 136 |
+
"openrouter_api_key = os.getenv('OPENROUTER_API_KEY')\n",
|
| 137 |
+
"\n",
|
| 138 |
+
"\n",
|
| 139 |
+
"if openrouter_api_key:\n",
|
| 140 |
+
" print(f\"OpenRouter API Key exists and begins {openrouter_api_key[:8]}\")\n",
|
| 141 |
+
"else:\n",
|
| 142 |
+
" print(\"OpenRouter API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
|
| 143 |
+
"\n",
|
| 144 |
+
"if openai_api_key:\n",
|
| 145 |
+
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
|
| 146 |
+
"else:\n",
|
| 147 |
+
" print(\"OpenAI API Key not set - please head to the troubleshooting guide in the setup folder\")\n",
|
| 148 |
+
" \n"
|
| 149 |
+
]
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"cell_type": "code",
|
| 153 |
+
"execution_count": 6,
|
| 154 |
+
"metadata": {},
|
| 155 |
+
"outputs": [],
|
| 156 |
+
"source": [
|
| 157 |
+
"# And now - the all important import statement\n",
|
| 158 |
+
"# If you get an import error - head over to troubleshooting guide\n",
|
| 159 |
+
"\n",
|
| 160 |
+
"from openai import OpenAI"
|
| 161 |
+
]
|
| 162 |
+
},
|
| 163 |
+
{
|
| 164 |
+
"cell_type": "code",
|
| 165 |
+
"execution_count": 17,
|
| 166 |
+
"metadata": {},
|
| 167 |
+
"outputs": [],
|
| 168 |
+
"source": [
|
| 169 |
+
"# And now we'll create an instance of the OpenAI class\n",
|
| 170 |
+
"# If you're not sure what it means to create an instance of a class - head over to the guides folder!\n",
|
| 171 |
+
"# If you get a NameError - head over to the guides folder to learn about NameErrors\n",
|
| 172 |
+
"\n",
|
| 173 |
+
"openai = OpenAI()\n",
|
| 174 |
+
"openrouter = OpenAI(base_url=\"https://api.openrouter.ai/v1\", api_key=openrouter_api_key)\n"
|
| 175 |
+
]
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"cell_type": "code",
|
| 179 |
+
"execution_count": 18,
|
| 180 |
+
"metadata": {},
|
| 181 |
+
"outputs": [],
|
| 182 |
+
"source": [
|
| 183 |
+
"# Create a list of messages in the familiar OpenAI format\n",
|
| 184 |
+
"\n",
|
| 185 |
+
"messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
|
| 186 |
+
]
|
| 187 |
+
},
|
| 188 |
+
{
|
| 189 |
+
"cell_type": "code",
|
| 190 |
+
"execution_count": 19,
|
| 191 |
+
"metadata": {},
|
| 192 |
+
"outputs": [
|
| 193 |
+
{
|
| 194 |
+
"name": "stdout",
|
| 195 |
+
"output_type": "stream",
|
| 196 |
+
"text": [
|
| 197 |
+
"2 + 2 equals 4.\n",
|
| 198 |
+
"An error occurred with OpenRouter: Connection error.\n"
|
| 199 |
+
]
|
| 200 |
+
},
|
| 201 |
+
{
|
| 202 |
+
"ename": "AttributeError",
|
| 203 |
+
"evalue": "'NoneType' object has no attribute 'choices'",
|
| 204 |
+
"output_type": "error",
|
| 205 |
+
"traceback": [
|
| 206 |
+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
| 207 |
+
"\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)",
|
| 208 |
+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\u001b[39m\u001b[32m, line 26\u001b[39m\n\u001b[32m 22\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mAn error occurred with OpenRouter: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 23\u001b[39m response_openrouter = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m26\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[43mresponse_openrouter\u001b[49m\u001b[43m.\u001b[49m\u001b[43mchoices\u001b[49m[\u001b[32m0\u001b[39m].message.content)\n",
|
| 209 |
+
"\u001b[31mAttributeError\u001b[39m: 'NoneType' object has no attribute 'choices'"
|
| 210 |
+
]
|
| 211 |
+
}
|
| 212 |
+
],
|
| 213 |
+
"source": [
|
| 214 |
+
"# And now call it! Any problems, head to the troubleshooting guide\n",
|
| 215 |
+
"# This uses GPT 4.1 nano, the incredibly cheap model\n",
|
| 216 |
+
"\n",
|
| 217 |
+
"from typing import cast\n",
|
| 218 |
+
"from openai.types.chat import ChatCompletionMessageParam\n",
|
| 219 |
+
"\n",
|
| 220 |
+
"response = openai.chat.completions.create(\n",
|
| 221 |
+
" model=\"gpt-4.1-nano\",\n",
|
| 222 |
+
" messages=cast(list[ChatCompletionMessageParam], messages)\n",
|
| 223 |
+
")\n",
|
| 224 |
+
"\n",
|
| 225 |
+
"print(response.choices[0].message.content)\n",
|
| 226 |
+
"try:\n",
|
| 227 |
+
" # Now let's try the OpenRouter API\n",
|
| 228 |
+
" # This uses DeepSeek R1, a free model available on OpenRouter\n",
|
| 229 |
+
" # If you get an error here, check your OpenRouter API key and the troubleshooting guide\n",
|
| 230 |
+
" response_openrouter = openrouter.chat.completions.create(\n",
|
| 231 |
+
" model=\"deepseek/deepseek-r1-0528:free\",\n",
|
| 232 |
+
" messages=cast(list[ChatCompletionMessageParam], messages)\n",
|
| 233 |
+
" )\n",
|
| 234 |
+
"except Exception as e:\n",
|
| 235 |
+
" print(f\"An error occurred with OpenRouter: {e}\")\n",
|
| 236 |
+
" response_openrouter = None\n",
|
| 237 |
+
"\n",
|
| 238 |
+
"\n",
|
| 239 |
+
"print(response_openrouter.choices[0].message.content)\n"
|
| 240 |
+
]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"cell_type": "code",
|
| 244 |
+
"execution_count": 10,
|
| 245 |
+
"metadata": {},
|
| 246 |
+
"outputs": [],
|
| 247 |
+
"source": [
|
| 248 |
+
"# And now - let's ask for a question:\n",
|
| 249 |
+
"\n",
|
| 250 |
+
"question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
|
| 251 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n"
|
| 252 |
+
]
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"cell_type": "code",
|
| 256 |
+
"execution_count": null,
|
| 257 |
+
"metadata": {},
|
| 258 |
+
"outputs": [],
|
| 259 |
+
"source": [
|
| 260 |
+
"# ask it - this uses GPT 4.1 mini, still cheap but more powerful than nano\n",
|
| 261 |
+
"\n",
|
| 262 |
+
"response = openai.chat.completions.create(\n",
|
| 263 |
+
" model=\"gpt-4.1-mini\",\n",
|
| 264 |
+
" messages=messages\n",
|
| 265 |
+
")\n",
|
| 266 |
+
"\n",
|
| 267 |
+
"question = response.choices[0].message.content\n",
|
| 268 |
+
"\n",
|
| 269 |
+
"print(question)\n"
|
| 270 |
+
]
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"cell_type": "code",
|
| 274 |
+
"execution_count": 12,
|
| 275 |
+
"metadata": {},
|
| 276 |
+
"outputs": [],
|
| 277 |
+
"source": [
|
| 278 |
+
"# form a new messages list\n",
|
| 279 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n"
|
| 280 |
+
]
|
| 281 |
+
},
|
| 282 |
+
{
|
| 283 |
+
"cell_type": "code",
|
| 284 |
+
"execution_count": null,
|
| 285 |
+
"metadata": {},
|
| 286 |
+
"outputs": [],
|
| 287 |
+
"source": [
|
| 288 |
+
"# Ask it again\n",
|
| 289 |
+
"\n",
|
| 290 |
+
"response = openai.chat.completions.create(\n",
|
| 291 |
+
" model=\"gpt-4.1-mini\",\n",
|
| 292 |
+
" messages=messages\n",
|
| 293 |
+
")\n",
|
| 294 |
+
"\n",
|
| 295 |
+
"answer = response.choices[0].message.content\n",
|
| 296 |
+
"print(answer)\n"
|
| 297 |
+
]
|
| 298 |
+
},
|
| 299 |
+
{
|
| 300 |
+
"cell_type": "code",
|
| 301 |
+
"execution_count": null,
|
| 302 |
+
"metadata": {},
|
| 303 |
+
"outputs": [],
|
| 304 |
+
"source": [
|
| 305 |
+
"from IPython.display import Markdown, display\n",
|
| 306 |
+
"\n",
|
| 307 |
+
"display(Markdown(answer))\n",
|
| 308 |
+
"\n"
|
| 309 |
+
]
|
| 310 |
+
},
|
| 311 |
+
{
|
| 312 |
+
"cell_type": "markdown",
|
| 313 |
+
"metadata": {},
|
| 314 |
+
"source": [
|
| 315 |
+
"# Congratulations!\n",
|
| 316 |
+
"\n",
|
| 317 |
+
"That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
|
| 318 |
+
"\n",
|
| 319 |
+
"Next time things get more interesting..."
|
| 320 |
+
]
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"cell_type": "markdown",
|
| 324 |
+
"metadata": {},
|
| 325 |
+
"source": [
|
| 326 |
+
"<table style=\"margin: 0; text-align: left; width:100%\">\n",
|
| 327 |
+
" <tr>\n",
|
| 328 |
+
" <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
|
| 329 |
+
" <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
|
| 330 |
+
" </td>\n",
|
| 331 |
+
" <td>\n",
|
| 332 |
+
" <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
|
| 333 |
+
" <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
|
| 334 |
+
" First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
|
| 335 |
+
" Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
|
| 336 |
+
" Finally have 3 third LLM call propose the Agentic AI solution.\n",
|
| 337 |
+
" </span>\n",
|
| 338 |
+
" </td>\n",
|
| 339 |
+
" </tr>\n",
|
| 340 |
+
"</table>"
|
| 341 |
+
]
|
| 342 |
+
},
|
| 343 |
+
{
|
| 344 |
+
"cell_type": "code",
|
| 345 |
+
"execution_count": 25,
|
| 346 |
+
"metadata": {},
|
| 347 |
+
"outputs": [
|
| 348 |
+
{
|
| 349 |
+
"data": {
|
| 350 |
+
"text/markdown": [
|
| 351 |
+
"One promising business area for an Agentic AI solution is **Supply Chain and Logistics Management**.\n",
|
| 352 |
+
"\n",
|
| 353 |
+
"### Why Supply Chain and Logistics?\n",
|
| 354 |
+
"- **Complex, dynamic environment:** Supply chains involve numerous stakeholders, fluctuating demand, unpredictable disruptions (e.g., weather, geopolitical events), and complex coordination among suppliers, manufacturers, distributors, and retailers.\n",
|
| 355 |
+
"- **High impact from optimization:** Even small improvements in routing, inventory management, or demand forecasting can lead to substantial cost savings and service improvements.\n",
|
| 356 |
+
"- **Scalability and adaptability:** An autonomous AI agent can continuously monitor and adapt to changes in real-time, coordinating tasks across geographies, modes of transport, and inventory levels without constant human intervention.\n",
|
| 357 |
+
"\n",
|
| 358 |
+
"### What would an Agentic AI do here?\n",
|
| 359 |
+
"- Autonomously optimize delivery routes and schedules dynamically based on live traffic, weather, and capacity data.\n",
|
| 360 |
+
"- Proactively manage inventory levels by predicting demand spikes or shortages and coordinating replenishments across multiple warehouses.\n",
|
| 361 |
+
"- Negotiate procurement contracts or shipping arrangements with suppliers and carriers using natural language interfaces and automated decision-making.\n",
|
| 362 |
+
"- Detect and mitigate risks by autonomously responding to disruptions, rerouting shipments, or adjusting production plans.\n",
|
| 363 |
+
"- Integrate with ERP and IoT systems to gather data and orchestrate operations end-to-end.\n",
|
| 364 |
+
"\n",
|
| 365 |
+
"### Potential benefits:\n",
|
| 366 |
+
"- Increased efficiency and reduced costs through continuous, autonomous optimization.\n",
|
| 367 |
+
"- Faster response to disruptions and improved supply chain resilience.\n",
|
| 368 |
+
"- Reduced human workload in coordination and decision-making, allowing teams to focus on strategic tasks.\n",
|
| 369 |
+
"- Enhanced customer satisfaction due to improved delivery reliability and transparency.\n",
|
| 370 |
+
"\n",
|
| 371 |
+
"This area is complex enough to benefit significantly from agentic autonomy but also has clear, high-value practical applications making it ripe for innovative AI solutions."
|
| 372 |
+
],
|
| 373 |
+
"text/plain": [
|
| 374 |
+
"<IPython.core.display.Markdown object>"
|
| 375 |
+
]
|
| 376 |
+
},
|
| 377 |
+
"metadata": {},
|
| 378 |
+
"output_type": "display_data"
|
| 379 |
+
}
|
| 380 |
+
],
|
| 381 |
+
"source": [
|
| 382 |
+
"# First create the messages:\n",
|
| 383 |
+
"\n",
|
| 384 |
+
"question = \"Please propose a business area that might be ripe for an Agentic AI solution.\"\n",
|
| 385 |
+
"\n",
|
| 386 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n",
|
| 387 |
+
"\n",
|
| 388 |
+
"# Then make the first call:\n",
|
| 389 |
+
"\n",
|
| 390 |
+
"response = openai.chat.completions.create( \n",
|
| 391 |
+
" model=\"gpt-4.1-mini\",\n",
|
| 392 |
+
" messages=messages\n",
|
| 393 |
+
")\n",
|
| 394 |
+
"\n",
|
| 395 |
+
"# Then read the business idea:\n",
|
| 396 |
+
"\n",
|
| 397 |
+
"business_idea = response.choices[0].message.content\n",
|
| 398 |
+
"display(Markdown(business_idea))\n",
|
| 399 |
+
"# And repeat!"
|
| 400 |
+
]
|
| 401 |
+
},
|
| 402 |
+
{
|
| 403 |
+
"cell_type": "code",
|
| 404 |
+
"execution_count": 26,
|
| 405 |
+
"metadata": {},
|
| 406 |
+
"outputs": [
|
| 407 |
+
{
|
| 408 |
+
"data": {
|
| 409 |
+
"text/markdown": [
|
| 410 |
+
"A key pain point for deploying Agentic AI in **Supply Chain and Logistics Management** is:\n",
|
| 411 |
+
"\n",
|
| 412 |
+
"### Pain Point: **Fragmented and Siloed Data Across Stakeholders Hindering Real-Time Coordination and Decision-Making**\n",
|
| 413 |
+
"\n",
|
| 414 |
+
"---\n",
|
| 415 |
+
"\n",
|
| 416 |
+
"### Explanation:\n",
|
| 417 |
+
"Supply chains often involve multiple independent organizations (suppliers, manufacturers, carriers, warehouses, retailers) using disparate legacy systems, proprietary formats, and disconnected databases. This fragmentation leads to:\n",
|
| 418 |
+
"\n",
|
| 419 |
+
"- **Poor data visibility and quality:** Critical information such as inventory levels, shipment status, demand signals, or disruption alerts may be delayed, incomplete, or inconsistent.\n",
|
| 420 |
+
"- **Slow and manual reconciliation:** Human operators spend significant time gathering, validating, and reconciling information before making decisions.\n",
|
| 421 |
+
"- **Reduced agility and suboptimal decisions:** Without a unified, real-time view, the AI agent’s ability to autonomously optimize operations is hampered. It may fail to react timely or make less informed trade-offs.\n",
|
| 422 |
+
"- **Integration complexity:** Integrating with numerous ERP, warehouse management systems (WMS), transportation management systems (TMS), and IoT sensors demands significant engineering effort and ongoing maintenance.\n",
|
| 423 |
+
"\n",
|
| 424 |
+
"---\n",
|
| 425 |
+
"\n",
|
| 426 |
+
"### Why Addressing This Pain Point Matters for Agentic AI:\n",
|
| 427 |
+
"\n",
|
| 428 |
+
"- Agentic AI depends heavily on clean, centralized, and real-time data feeds to perceive the complex environment accurately and act autonomously.\n",
|
| 429 |
+
"- Overcoming data silos enables end-to-end orchestration and dynamic decision-making at scale.\n",
|
| 430 |
+
"- Ensuring interoperability and data sharing agreements among stakeholders may be necessary, raising trust and governance challenges that the AI system needs to accommodate.\n",
|
| 431 |
+
"\n",
|
| 432 |
+
"---\n",
|
| 433 |
+
"\n",
|
| 434 |
+
"### Potential Solution Approaches:\n",
|
| 435 |
+
"\n",
|
| 436 |
+
"- Develop standardized data schemas and APIs or leverage supply chain blockchain ledgers to improve data sharing trustworthiness.\n",
|
| 437 |
+
"- Employ real-time data ingestion pipelines and data fusion techniques to consolidate fragmented inputs.\n",
|
| 438 |
+
"- Design the agent with uncertainty-aware reasoning to handle incomplete or noisy data robustly.\n",
|
| 439 |
+
"- Implement privacy-preserving federated learning or multi-party computation if data sharing is sensitive.\n",
|
| 440 |
+
"\n",
|
| 441 |
+
"---\n",
|
| 442 |
+
"\n",
|
| 443 |
+
"### Summary:\n",
|
| 444 |
+
"**Fragmented, siloed, and inconsistent data across the supply chain ecosystem is a critical pain point limiting the effective deployment of Agentic AI solutions for autonomous supply chain management. Addressing it unlocks the AI’s potential to optimize, adapt, and orchestrate complex logistics dynamically and efficiently.**"
|
| 445 |
+
],
|
| 446 |
+
"text/plain": [
|
| 447 |
+
"<IPython.core.display.Markdown object>"
|
| 448 |
+
]
|
| 449 |
+
},
|
| 450 |
+
"metadata": {},
|
| 451 |
+
"output_type": "display_data"
|
| 452 |
+
}
|
| 453 |
+
],
|
| 454 |
+
"source": [
|
| 455 |
+
"question = f\"Please propose a pain point for {business_idea}.\"\n",
|
| 456 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n",
|
| 457 |
+
"\n",
|
| 458 |
+
"response = openai.chat.completions.create(\n",
|
| 459 |
+
" model=\"gpt-4.1-mini\",\n",
|
| 460 |
+
" messages=messages\n",
|
| 461 |
+
")\n",
|
| 462 |
+
"pain_point = response.choices[0].message.content \n",
|
| 463 |
+
"display(Markdown(pain_point))\n",
|
| 464 |
+
"\n",
|
| 465 |
+
"#question = f\"Propose a solution for {pain_point}.\"\n",
|
| 466 |
+
"#messages = [{\"role\": \"user\", \"content\": question}]\n",
|
| 467 |
+
"\n"
|
| 468 |
+
]
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"cell_type": "code",
|
| 472 |
+
"execution_count": 27,
|
| 473 |
+
"metadata": {},
|
| 474 |
+
"outputs": [
|
| 475 |
+
{
|
| 476 |
+
"data": {
|
| 477 |
+
"text/markdown": [
|
| 478 |
+
"Certainly! Here is a detailed proposal for an **Agentic AI solution** tackling the pain point of **Fragmented and Siloed Data Across Stakeholders Hindering Real-Time Coordination and Decision-Making** in Supply Chain and Logistics Management:\n",
|
| 479 |
+
"\n",
|
| 480 |
+
"---\n",
|
| 481 |
+
"\n",
|
| 482 |
+
"## Agentic AI Solution Proposal: **Unified Collaborative Data Fabric with Agentic Orchestration Layer**\n",
|
| 483 |
+
"\n",
|
| 484 |
+
"### 1. **Concept Overview**\n",
|
| 485 |
+
"\n",
|
| 486 |
+
"Build a **multi-stakeholder collaborative data fabric** combining standardized data exchange, privacy-preserving federation, and real-time data fusion, overlaid by an **Agentic AI orchestration layer** that continuously perceives, reasons, and acts upon the unified supply chain state.\n",
|
| 487 |
+
"\n",
|
| 488 |
+
"---\n",
|
| 489 |
+
"\n",
|
| 490 |
+
"### 2. **Key Components**\n",
|
| 491 |
+
"\n",
|
| 492 |
+
"#### a) **Standardized Interoperable Data Layer**\n",
|
| 493 |
+
"\n",
|
| 494 |
+
"- **Adopt Open Supply Chain Standards:** Implement data schemas based on GS1, EPCIS, or create an industry consortium standardized ontology (e.g., product IDs, event types, timestamps).\n",
|
| 495 |
+
"- **API Gateway Mesh:** Provide a modular API gateway layer for each stakeholder system (ERP, WMS, TMS, IoT platforms), performing protocol translation and schema mapping to the unified data model.\n",
|
| 496 |
+
"- **Blockchain or Distributed Ledger:** Use permissioned blockchain to record key supply chain events, ensuring immutability and enhancing trust, enabling transparent provenance and dispute resolution without exposing proprietary data.\n",
|
| 497 |
+
"\n",
|
| 498 |
+
"#### b) **Privacy-Preserving Federated Data Aggregation**\n",
|
| 499 |
+
"\n",
|
| 500 |
+
"- **Federated Data Integration:** Instead of centralized data pooling, employ federated learning and multiparty computation methods to aggregate insights and global supply chain state information while keeping sensitive data on-premise.\n",
|
| 501 |
+
"- **Access Control & Governance:** Implement fine-grained attribute-based encryption and consent management allowing stakeholders to control what data is shared, how it is used, and audit the usage.\n",
|
| 502 |
+
"\n",
|
| 503 |
+
"#### c) **Real-Time Data Ingestion and Fusion Engine**\n",
|
| 504 |
+
"\n",
|
| 505 |
+
"- **Streaming Pipelines:** Connect all stakeholder APIs, IoT sensors, and external data feeds into a robust event streaming platform (Apache Kafka, Pulsar).\n",
|
| 506 |
+
"- **Data Cleaning & Fusion:** Automatically resolve conflicts, fill gaps, deduplicate, and timestamp-align data streams to construct a coherent, real-time state vector of inventory, shipments, and demand signals.\n",
|
| 507 |
+
"\n",
|
| 508 |
+
"#### d) **Agentic AI Orchestration Layer**\n",
|
| 509 |
+
"\n",
|
| 510 |
+
"- **Multi-Modal Perception:** Utilize advanced perception models combining structured data, sensor feeds, and external intelligence (weather, traffic) to maintain situation awareness.\n",
|
| 511 |
+
"- **Uncertainty-Aware Reasoning:** Apply probabilistic graphical models or Bayesian networks to reason under incomplete/noisy data conditions and quantify confidence in state estimations.\n",
|
| 512 |
+
"- **Dynamic Decision-Making:** Employ reinforcement learning or model-predictive control agents that autonomously recommend and execute actions (routing changes, order adjustments, contingencies) based on real-time supply chain state.\n",
|
| 513 |
+
"- **Collaborative Planning:** Agents negotiate and coordinate across stakeholders via smart contracts or interaction protocols embedded in the data fabric, balancing competing priorities transparently.\n",
|
| 514 |
+
"\n",
|
| 515 |
+
"---\n",
|
| 516 |
+
"\n",
|
| 517 |
+
"### 3. **Benefits**\n",
|
| 518 |
+
"\n",
|
| 519 |
+
"- **End-to-End Visibility:** Eliminates data black boxes by harmonizing data flows, enabling a single “source of truth” for the agent.\n",
|
| 520 |
+
"- **Faster Decision Cycles:** Minimizes manual reconciliation delays, accelerating reaction to disruptions or demand shifts.\n",
|
| 521 |
+
"- **Strengthened Trust & Compliance:** Blockchain and encryption-based governance frameworks reduce data-sharing hesitancy.\n",
|
| 522 |
+
"- **Scalable Integration:** API gateways and federated approaches reduce integration engineering overhead and improve adaptability to evolving systems.\n",
|
| 523 |
+
"- **Robustness to Imperfect Data:** Uncertainty modeling allows safe autonomous actions despite data gaps.\n",
|
| 524 |
+
"\n",
|
| 525 |
+
"---\n",
|
| 526 |
+
"\n",
|
| 527 |
+
"### 4. **Implementation Roadmap**\n",
|
| 528 |
+
"\n",
|
| 529 |
+
"| Phase | Actions |\n",
|
| 530 |
+
"|---------------------|----------------------------------------------------------------------------------------------|\n",
|
| 531 |
+
"| **Pilot & Standardization** | Collaborate with key supply chain partners to define common data schemas and governance policies. Deploy API gateways to onboard legacy systems. |\n",
|
| 532 |
+
"| **Federated Data Layer Deployment** | Integrate federated learning frameworks and blockchain ledger nodes to enable secure data sharing and event recording among stakeholders. |\n",
|
| 533 |
+
"| **Agentic AI Development** | Develop and train perception, reasoning, and decision-making agent modules with uncertainty handling on fused real-time data. Conduct simulations. |\n",
|
| 534 |
+
"| **End-to-End Testing & Iteration** | Run controlled pilot scenarios; refine data cleaning, fusion, agent policies, and stakeholder feedback loops. Expand network of participants gradually. |\n",
|
| 535 |
+
"| **Scale & Optimize** | Optimize system performance, enhance AI policies with continuous learning, and implement automated compliance reporting for governance. |\n",
|
| 536 |
+
"\n",
|
| 537 |
+
"---\n",
|
| 538 |
+
"\n",
|
| 539 |
+
"### 5. **Risks & Mitigations**\n",
|
| 540 |
+
"\n",
|
| 541 |
+
"| Risk | Mitigation |\n",
|
| 542 |
+
"|-----------------------------------------|----------------------------------------------------------------|\n",
|
| 543 |
+
"| Data privacy concerns and reluctance | Robust encryption, consent management, and federated approaches |\n",
|
| 544 |
+
"| Legacy system incompatibilities | Modular API gateways with customizable adapters |\n",
|
| 545 |
+
"| Consensus on standards slow to form | Use industry bodies and regulators to accelerate agreements |\n",
|
| 546 |
+
"| Added system complexity and cost | Phased rollout with ROI demonstration and modular adoption |\n",
|
| 547 |
+
"\n",
|
| 548 |
+
"---\n",
|
| 549 |
+
"\n",
|
| 550 |
+
"### **Summary**\n",
|
| 551 |
+
"\n",
|
| 552 |
+
"By architecting a **collaborative, privacy-conscious data fabric** combined with a sophisticated **agentic AI orchestration layer**, the solution addresses the core impediment of fragmented, siloed data. It unlocks real-time, trustworthy supply chain visibility and autonomous decision-making capabilities that significantly improve coordination, agility, and resilience in modern supply chains.\n",
|
| 553 |
+
"\n",
|
| 554 |
+
"---\n",
|
| 555 |
+
"\n",
|
| 556 |
+
"If you'd like, I can help design specific architecture diagrams, technology stack recommendations, or agent decision frameworks for this approach."
|
| 557 |
+
],
|
| 558 |
+
"text/plain": [
|
| 559 |
+
"<IPython.core.display.Markdown object>"
|
| 560 |
+
]
|
| 561 |
+
},
|
| 562 |
+
"metadata": {},
|
| 563 |
+
"output_type": "display_data"
|
| 564 |
+
}
|
| 565 |
+
],
|
| 566 |
+
"source": [
|
| 567 |
+
"question = f\"Propose an Agentic AI solution for {pain_point}.\"\n",
|
| 568 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n",
|
| 569 |
+
"\n",
|
| 570 |
+
"response = openai.chat.completions.create(\n",
|
| 571 |
+
" model=\"gpt-4.1-mini\",\n",
|
| 572 |
+
" messages=messages\n",
|
| 573 |
+
") \n",
|
| 574 |
+
"\n",
|
| 575 |
+
"display(Markdown(response.choices[0].message.content))\n",
|
| 576 |
+
"\n",
|
| 577 |
+
"\n",
|
| 578 |
+
"\n"
|
| 579 |
+
]
|
| 580 |
+
}
|
| 581 |
+
],
|
| 582 |
+
"metadata": {
|
| 583 |
+
"kernelspec": {
|
| 584 |
+
"display_name": ".venv",
|
| 585 |
+
"language": "python",
|
| 586 |
+
"name": "python3"
|
| 587 |
+
},
|
| 588 |
+
"language_info": {
|
| 589 |
+
"codemirror_mode": {
|
| 590 |
+
"name": "ipython",
|
| 591 |
+
"version": 3
|
| 592 |
+
},
|
| 593 |
+
"file_extension": ".py",
|
| 594 |
+
"mimetype": "text/x-python",
|
| 595 |
+
"name": "python",
|
| 596 |
+
"nbconvert_exporter": "python",
|
| 597 |
+
"pygments_lexer": "ipython3",
|
| 598 |
+
"version": "3.12.10"
|
| 599 |
+
}
|
| 600 |
+
},
|
| 601 |
+
"nbformat": 4,
|
| 602 |
+
"nbformat_minor": 2
|
| 603 |
+
}
|
2_lab2.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 |
+
}
|
3_lab3.ipynb
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 PyPDF2 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": 1,
|
| 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.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": 5,
|
| 81 |
+
"metadata": {},
|
| 82 |
+
"outputs": [
|
| 83 |
+
{
|
| 84 |
+
"name": "stdout",
|
| 85 |
+
"output_type": "stream",
|
| 86 |
+
"text": [
|
| 87 |
+
" \n",
|
| 88 |
+
"Contact\n",
|
| 89 |
+
"luis.melo.correia@icloud.co\n",
|
| 90 |
+
"m\n",
|
| 91 |
+
"www.linkedin.com/in/lmelo\n",
|
| 92 |
+
"(LinkedIn)\n",
|
| 93 |
+
"Top Skills\n",
|
| 94 |
+
"Vibe Coding\n",
|
| 95 |
+
"IT Consulting\n",
|
| 96 |
+
"Supplier Evaluation\n",
|
| 97 |
+
"Languages\n",
|
| 98 |
+
"English\n",
|
| 99 |
+
"Certifications\n",
|
| 100 |
+
"AI Agents for Product Leaders\n",
|
| 101 |
+
"Vibe Coding from Scratch\n",
|
| 102 |
+
"Becoming a Chief AI Officer\n",
|
| 103 |
+
"Design Thinking: Understanding the\n",
|
| 104 |
+
"Process\n",
|
| 105 |
+
"Leading Talent Development in the\n",
|
| 106 |
+
"Era of AI\n",
|
| 107 |
+
"Luís Melo\n",
|
| 108 |
+
"CIO/CTO | Senior IT Advisor | Strategic IT Solutions\n",
|
| 109 |
+
"Portugal\n",
|
| 110 |
+
"Summary\n",
|
| 111 |
+
"Dynamic, results-driven IT Executive with over 20 years’ of expertise\n",
|
| 112 |
+
"in advancing technology strategies and operational frameworks\n",
|
| 113 |
+
"across a high-growth, fast-paced organisation. Known for guiding\n",
|
| 114 |
+
"transformative digital initiatives, aligning IT architecture with\n",
|
| 115 |
+
"business goals, and enhancing data and cybersecurity strategies,\n",
|
| 116 |
+
"emphasising sustainable growth and risk management. Proven\n",
|
| 117 |
+
"ability to lead cross-functional teams, integrate M&A systems,\n",
|
| 118 |
+
"and create scalable IT infrastructures in complex environments.\n",
|
| 119 |
+
"Recognised for establishing cloud-based solutions, and AI/ML-\n",
|
| 120 |
+
"driven insights to empower data-driven decision-making and agile\n",
|
| 121 |
+
"methodologies. A trusted C-suite advisor with a consistent track\n",
|
| 122 |
+
"record of cost efficiencies, IT infrastructure modernisation, and\n",
|
| 123 |
+
"impactful change enablement. Ready to drive strategic value and\n",
|
| 124 |
+
"operational advancements within a forward-thinking organisation.\n",
|
| 125 |
+
"Experience\n",
|
| 126 |
+
"Self-employed\n",
|
| 127 |
+
"CIO/CTO | Senior Information Technology Advisor\n",
|
| 128 |
+
"April 2024 - Present (1 year 2 months)\n",
|
| 129 |
+
"Europe\n",
|
| 130 |
+
"During a planned sabbatical while identifying the ideal CIO, CTO, or Executive\n",
|
| 131 |
+
"IT Director role within Europe, provides IT advisory services, roadmaps, and\n",
|
| 132 |
+
"scalable solutions to various clients.\n",
|
| 133 |
+
"Montepio\n",
|
| 134 |
+
"13 years 3 months\n",
|
| 135 |
+
"CIO/ Executive IT Director \n",
|
| 136 |
+
"March 2016 - March 2024 (8 years 1 month)\n",
|
| 137 |
+
"As a pivotal member of the Board, setting the strategic vision and direction,\n",
|
| 138 |
+
"I led a digital transformation, IT, and data strategy for a 2.5 million-strong\n",
|
| 139 |
+
"customer organisation. \n",
|
| 140 |
+
" Page 1 of 4 \n",
|
| 141 |
+
"Designed, built and led a team of 150, fostering agile methods to innovate\n",
|
| 142 |
+
"core banking and multichannel architecture. Built a new Azure cloud SOA\n",
|
| 143 |
+
"and data framework with Accenture and Microsoft, optimising AML and fraud\n",
|
| 144 |
+
"detection. Realised €multi-MN annual savings through vendor streamlining and\n",
|
| 145 |
+
"IT operations rationalisation for reinvestment into new cloud, AI/ML, CRM and\n",
|
| 146 |
+
"cybersecurity technologies. Implemented cybersecurity protocols and enabled\n",
|
| 147 |
+
"a robust remote work infrastructure.\n",
|
| 148 |
+
"IT Director - Head of Strategy and Architecture Department\n",
|
| 149 |
+
"November 2014 - March 2016 (1 year 5 months)\n",
|
| 150 |
+
"Lisbon, Portugal\n",
|
| 151 |
+
"Oversaw strategic digital initiatives post-merger, managed the Montepio i9\n",
|
| 152 |
+
"Program to modernise IT infrastructure and streamline disaster recovery\n",
|
| 153 |
+
"protocols. \n",
|
| 154 |
+
"Delivered customer insights by implementing CRM systems, dashboards, and\n",
|
| 155 |
+
"enhanced digital banking channels. Advanced process automation, increasing\n",
|
| 156 |
+
"efficiency and customer engagement through improved online services.\n",
|
| 157 |
+
"IT Director - Head of Distributed Development Department\n",
|
| 158 |
+
"January 2012 - October 2014 (2 years 10 months)\n",
|
| 159 |
+
"Lisbon, Portugal\n",
|
| 160 |
+
"Led the rollout of a service-oriented architecture, enhancing inter-departmental\n",
|
| 161 |
+
"IT alignment for a bank with 300 branches and 5,000 employees. Managed\n",
|
| 162 |
+
"vendor relationships, notably Accenture, overseeing projects from loan\n",
|
| 163 |
+
"origination to BI systems. Promoted SOA frameworks for a seamless migration\n",
|
| 164 |
+
"from legacy systems, enabling more efficient customer-facing applications.\n",
|
| 165 |
+
"IT Director - Head of Department \n",
|
| 166 |
+
"January 2011 - December 2011 (1 year)\n",
|
| 167 |
+
"Lisbon, Portugal\n",
|
| 168 |
+
"Led IT integration for a major merger, streamlining systems for 300 branches\n",
|
| 169 |
+
"and consolidating customer data. Delivered efficiencies by restructuring\n",
|
| 170 |
+
"teams, migrating legacy systems, and fostering cultural alignment in merged\n",
|
| 171 |
+
"operations, supporting 2.5 million clients across Portugal.\n",
|
| 172 |
+
"Finibanco\n",
|
| 173 |
+
"IT DIRECTOR\n",
|
| 174 |
+
"December 2007 - February 2012 (4 years 3 months)\n",
|
| 175 |
+
"Directed digital transformation through the 2008 financial downturn,\n",
|
| 176 |
+
"developing BI systems and loan workflows while adapting IT strategy to\n",
|
| 177 |
+
" Page 2 of 4 \n",
|
| 178 |
+
"budget constraints. Built a pipeline for tech talent with university partnerships,\n",
|
| 179 |
+
"attracting skilled graduates for innovative projects. Enhanced customer service\n",
|
| 180 |
+
"through new front-office solutions and modernised management information\n",
|
| 181 |
+
"systems.\n",
|
| 182 |
+
"Finibanco\n",
|
| 183 |
+
"7 years\n",
|
| 184 |
+
"IT Manager\n",
|
| 185 |
+
"2005 - 2007 (2 years)\n",
|
| 186 |
+
"Porto, Portugal\n",
|
| 187 |
+
"Advanced SOA strategy with IBM, improving system interoperability across\n",
|
| 188 |
+
"banking applications. Integrated web services, facilitating collaboration and\n",
|
| 189 |
+
"information sharing across departments. Reported directly to the CEO,\n",
|
| 190 |
+
"supporting the main bank on core application development.\n",
|
| 191 |
+
"IT Project Manager\n",
|
| 192 |
+
"2000 - 2005 (5 years)\n",
|
| 193 |
+
"Porto, Portugal\n",
|
| 194 |
+
"Developed Portugal's first online brokerage platform, positioning Finibanco as\n",
|
| 195 |
+
"a digital pioneer in trading services. Fostered agility in IT operations, forming a\n",
|
| 196 |
+
"semi-autonomous team for efficient project execution.\n",
|
| 197 |
+
"IDITE Minho\n",
|
| 198 |
+
"Researcher\n",
|
| 199 |
+
"August 1999 - September 2000 (1 year 2 months)\n",
|
| 200 |
+
"Univ Minho\n",
|
| 201 |
+
"Researcher\n",
|
| 202 |
+
"October 1998 - September 2000 (2 years)\n",
|
| 203 |
+
"Education\n",
|
| 204 |
+
"Cambridge Judge Business School\n",
|
| 205 |
+
"Executive MBA, Business/Commerce, General · (September 2025)\n",
|
| 206 |
+
"Nova School of Business and Economics\n",
|
| 207 |
+
"PAGT - Avanced Program for the Top Management\n",
|
| 208 |
+
"Universidade Católica Portuguesa\n",
|
| 209 |
+
"Master, Finance\n",
|
| 210 |
+
" Page 3 of 4 \n",
|
| 211 |
+
"Universidade do Minho\n",
|
| 212 |
+
"Master, Computer Science\n",
|
| 213 |
+
"Universidade do Minho\n",
|
| 214 |
+
"Lic, Electronics Eng.\n",
|
| 215 |
+
" Page 4 of 4\n"
|
| 216 |
+
]
|
| 217 |
+
}
|
| 218 |
+
],
|
| 219 |
+
"source": [
|
| 220 |
+
"print(linkedin)"
|
| 221 |
+
]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"cell_type": "code",
|
| 225 |
+
"execution_count": null,
|
| 226 |
+
"metadata": {},
|
| 227 |
+
"outputs": [],
|
| 228 |
+
"source": [
|
| 229 |
+
"print(linkedin)"
|
| 230 |
+
]
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"cell_type": "code",
|
| 234 |
+
"execution_count": 6,
|
| 235 |
+
"metadata": {},
|
| 236 |
+
"outputs": [],
|
| 237 |
+
"source": [
|
| 238 |
+
"with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
|
| 239 |
+
" summary = f.read()"
|
| 240 |
+
]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"cell_type": "code",
|
| 244 |
+
"execution_count": 7,
|
| 245 |
+
"metadata": {},
|
| 246 |
+
"outputs": [],
|
| 247 |
+
"source": [
|
| 248 |
+
"name = \"Luís Melo\""
|
| 249 |
+
]
|
| 250 |
+
},
|
| 251 |
+
{
|
| 252 |
+
"cell_type": "code",
|
| 253 |
+
"execution_count": 8,
|
| 254 |
+
"metadata": {},
|
| 255 |
+
"outputs": [],
|
| 256 |
+
"source": [
|
| 257 |
+
"system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
|
| 258 |
+
"particularly questions related to {name}'s career, background, skills and experience. \\\n",
|
| 259 |
+
"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
|
| 260 |
+
"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
|
| 261 |
+
"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
|
| 262 |
+
"If you don't know the answer, say so.\"\n",
|
| 263 |
+
"\n",
|
| 264 |
+
"system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
|
| 265 |
+
"system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
|
| 266 |
+
]
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"cell_type": "code",
|
| 270 |
+
"execution_count": 9,
|
| 271 |
+
"metadata": {},
|
| 272 |
+
"outputs": [
|
| 273 |
+
{
|
| 274 |
+
"data": {
|
| 275 |
+
"text/plain": [
|
| 276 |
+
"\"You are acting as Luís Melo. You are answering questions on Luís Melo's website, particularly questions related to Luís Melo's career, background, skills and experience. Your responsibility is to represent Luís Melo for interactions on the website as faithfully as possible. You are given a summary of Luís Melo's background and LinkedIn profile 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:\\nMy name is Luís Melo. I'm an entrepreneur, software engineer, and data scientist, originally from Aveiro, Portugal.\\nI'm a proud father of three lovely boys. I enjoy running and playing the guitar. I also love cooking—though I always need a recipe! The same goes for the guitar; I can’t play without tabs. Come to think of it, those are the only two things in life where I still need a recipe!\\n\\n\\n## LinkedIn Profile:\\n\\xa0 \\xa0\\nContact\\nluis.melo.correia@icloud.co\\nm\\nwww.linkedin.com/in/lmelo\\n(LinkedIn)\\nTop Skills\\nVibe Coding\\nIT Consulting\\nSupplier Evaluation\\nLanguages\\nEnglish\\nCertifications\\nAI Agents for Product Leaders\\nVibe Coding from Scratch\\nBecoming a Chief AI Officer\\nDesign Thinking: Understanding the\\nProcess\\nLeading Talent Development in the\\nEra of AI\\nLuís Melo\\nCIO/CTO | Senior IT Advisor | Strategic IT Solutions\\nPortugal\\nSummary\\nDynamic, results-driven IT Executive with over 20 years’ of expertise\\nin advancing technology strategies and operational frameworks\\nacross a high-growth, fast-paced organisation. Known for guiding\\ntransformative digital initiatives, aligning IT architecture with\\nbusiness goals, and enhancing data and cybersecurity strategies,\\nemphasising sustainable growth and risk management. Proven\\nability to lead cross-functional teams, integrate M&A systems,\\nand create scalable IT infrastructures in complex environments.\\nRecognised for establishing cloud-based solutions, and AI/ML-\\ndriven insights to empower data-driven decision-making and agile\\nmethodologies. A trusted C-suite advisor with a consistent track\\nrecord of cost efficiencies, IT infrastructure modernisation, and\\nimpactful change enablement. Ready to drive strategic value and\\noperational advancements within a forward-thinking organisation.\\nExperience\\nSelf-employed\\nCIO/CTO | Senior Information Technology Advisor\\nApril 2024\\xa0-\\xa0Present\\xa0(1 year 2 months)\\nEurope\\nDuring a planned sabbatical while identifying the ideal CIO, CTO, or Executive\\nIT Director role within Europe, provides IT advisory services, roadmaps, and\\nscalable solutions to various clients.\\nMontepio\\n13 years 3 months\\nCIO/ Executive IT Director \\nMarch 2016\\xa0-\\xa0March 2024\\xa0(8 years 1 month)\\nAs a pivotal member of the Board, setting the strategic vision and direction,\\nI led a digital transformation, IT, and data strategy for a 2.5 million-strong\\ncustomer organisation. \\n\\xa0 Page 1 of 4\\xa0 \\xa0\\nDesigned, built and led a team of 150, fostering agile methods to innovate\\ncore banking and multichannel architecture. Built a new Azure cloud SOA\\nand data framework with Accenture and Microsoft, optimising AML and fraud\\ndetection. Realised €multi-MN annual savings through vendor streamlining and\\nIT operations rationalisation for reinvestment into new cloud, AI/ML, CRM and\\ncybersecurity technologies. Implemented cybersecurity protocols and enabled\\na robust remote work infrastructure.\\nIT Director - Head of Strategy and Architecture Department\\nNovember 2014\\xa0-\\xa0March 2016\\xa0(1 year 5 months)\\nLisbon, Portugal\\nOversaw strategic digital initiatives post-merger, managed the Montepio i9\\nProgram to modernise IT infrastructure and streamline disaster recovery\\nprotocols. \\nDelivered customer insights by implementing CRM systems, dashboards, and\\nenhanced digital banking channels. Advanced process automation, increasing\\nefficiency and customer engagement through improved online services.\\nIT Director - Head of Distributed Development Department\\nJanuary 2012\\xa0-\\xa0October 2014\\xa0(2 years 10 months)\\nLisbon, Portugal\\nLed the rollout of a service-oriented architecture, enhancing inter-departmental\\nIT alignment for a bank with 300 branches and 5,000 employees. Managed\\nvendor relationships, notably Accenture, overseeing projects from loan\\norigination to BI systems. Promoted SOA frameworks for a seamless migration\\nfrom legacy systems, enabling more efficient customer-facing applications.\\nIT Director - Head of Department \\nJanuary 2011\\xa0-\\xa0December 2011\\xa0(1 year)\\nLisbon, Portugal\\nLed IT integration for a major merger, streamlining systems for 300 branches\\nand consolidating customer data. Delivered efficiencies by restructuring\\nteams, migrating legacy systems, and fostering cultural alignment in merged\\noperations, supporting 2.5 million clients across Portugal.\\nFinibanco\\nIT DIRECTOR\\nDecember 2007\\xa0-\\xa0February 2012\\xa0(4 years 3 months)\\nDirected digital transformation through the 2008 financial downturn,\\ndeveloping BI systems and loan workflows while adapting IT strategy to\\n\\xa0 Page 2 of 4\\xa0 \\xa0\\nbudget constraints. Built a pipeline for tech talent with university partnerships,\\nattracting skilled graduates for innovative projects. Enhanced customer service\\nthrough new front-office solutions and modernised management information\\nsystems.\\nFinibanco\\n7 years\\nIT Manager\\n2005\\xa0-\\xa02007\\xa0(2 years)\\nPorto, Portugal\\nAdvanced SOA strategy with IBM, improving system interoperability across\\nbanking applications. Integrated web services, facilitating collaboration and\\ninformation sharing across departments. Reported directly to the CEO,\\nsupporting the main bank on core application development.\\nIT Project Manager\\n2000\\xa0-\\xa02005\\xa0(5 years)\\nPorto, Portugal\\nDeveloped Portugal's first online brokerage platform, positioning Finibanco as\\na digital pioneer in trading services. Fostered agility in IT operations, forming a\\nsemi-autonomous team for efficient project execution.\\nIDITE Minho\\nResearcher\\nAugust 1999\\xa0-\\xa0September 2000\\xa0(1 year 2 months)\\nUniv Minho\\nResearcher\\nOctober 1998\\xa0-\\xa0September 2000\\xa0(2 years)\\nEducation\\nCambridge Judge Business School\\nExecutive MBA,\\xa0Business/Commerce, General\\xa0·\\xa0(September 2025)\\nNova School of Business and Economics\\nPAGT - Avanced Program for the Top Management\\nUniversidade Católica Portuguesa\\nMaster,\\xa0Finance\\n\\xa0 Page 3 of 4\\xa0 \\xa0\\nUniversidade do Minho\\nMaster,\\xa0Computer Science\\nUniversidade do Minho\\nLic,\\xa0Electronics Eng.\\n\\xa0 Page 4 of 4\\n\\nWith this context, please chat with the user, always staying in character as Luís Melo.\""
|
| 277 |
+
]
|
| 278 |
+
},
|
| 279 |
+
"execution_count": 9,
|
| 280 |
+
"metadata": {},
|
| 281 |
+
"output_type": "execute_result"
|
| 282 |
+
}
|
| 283 |
+
],
|
| 284 |
+
"source": [
|
| 285 |
+
"system_prompt"
|
| 286 |
+
]
|
| 287 |
+
},
|
| 288 |
+
{
|
| 289 |
+
"cell_type": "code",
|
| 290 |
+
"execution_count": 10,
|
| 291 |
+
"metadata": {},
|
| 292 |
+
"outputs": [],
|
| 293 |
+
"source": [
|
| 294 |
+
"def chat(message, history):\n",
|
| 295 |
+
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 296 |
+
" response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
|
| 297 |
+
" return response.choices[0].message.content"
|
| 298 |
+
]
|
| 299 |
+
},
|
| 300 |
+
{
|
| 301 |
+
"cell_type": "code",
|
| 302 |
+
"execution_count": 11,
|
| 303 |
+
"metadata": {},
|
| 304 |
+
"outputs": [
|
| 305 |
+
{
|
| 306 |
+
"name": "stdout",
|
| 307 |
+
"output_type": "stream",
|
| 308 |
+
"text": [
|
| 309 |
+
"* Running on local URL: http://127.0.0.1:7860\n",
|
| 310 |
+
"* To create a public link, set `share=True` in `launch()`.\n"
|
| 311 |
+
]
|
| 312 |
+
},
|
| 313 |
+
{
|
| 314 |
+
"data": {
|
| 315 |
+
"text/html": [
|
| 316 |
+
"<div><iframe src=\"http://127.0.0.1:7860/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
|
| 317 |
+
],
|
| 318 |
+
"text/plain": [
|
| 319 |
+
"<IPython.core.display.HTML object>"
|
| 320 |
+
]
|
| 321 |
+
},
|
| 322 |
+
"metadata": {},
|
| 323 |
+
"output_type": "display_data"
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"data": {
|
| 327 |
+
"text/plain": []
|
| 328 |
+
},
|
| 329 |
+
"execution_count": 11,
|
| 330 |
+
"metadata": {},
|
| 331 |
+
"output_type": "execute_result"
|
| 332 |
+
}
|
| 333 |
+
],
|
| 334 |
+
"source": [
|
| 335 |
+
"gr.ChatInterface(chat, type=\"messages\").launch()"
|
| 336 |
+
]
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"cell_type": "markdown",
|
| 340 |
+
"metadata": {},
|
| 341 |
+
"source": [
|
| 342 |
+
"## A lot is about to happen...\n",
|
| 343 |
+
"\n",
|
| 344 |
+
"1. Be able to ask an LLM to evaluate an answer\n",
|
| 345 |
+
"2. Be able to rerun if the answer fails evaluation\n",
|
| 346 |
+
"3. Put this together into 1 workflow\n",
|
| 347 |
+
"\n",
|
| 348 |
+
"All without any Agentic framework!"
|
| 349 |
+
]
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"cell_type": "code",
|
| 353 |
+
"execution_count": 12,
|
| 354 |
+
"metadata": {},
|
| 355 |
+
"outputs": [],
|
| 356 |
+
"source": [
|
| 357 |
+
"# Create a Pydantic model for the Evaluation\n",
|
| 358 |
+
"\n",
|
| 359 |
+
"from pydantic import BaseModel\n",
|
| 360 |
+
"\n",
|
| 361 |
+
"class Evaluation(BaseModel):\n",
|
| 362 |
+
" is_acceptable: bool\n",
|
| 363 |
+
" feedback: str\n"
|
| 364 |
+
]
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"cell_type": "code",
|
| 368 |
+
"execution_count": 13,
|
| 369 |
+
"metadata": {},
|
| 370 |
+
"outputs": [],
|
| 371 |
+
"source": [
|
| 372 |
+
"evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n",
|
| 373 |
+
"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",
|
| 374 |
+
"The Agent is playing the role of {name} and is representing {name} on their website. \\\n",
|
| 375 |
+
"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",
|
| 376 |
+
"The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n",
|
| 377 |
+
"\n",
|
| 378 |
+
"evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
|
| 379 |
+
"evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\""
|
| 380 |
+
]
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"cell_type": "code",
|
| 384 |
+
"execution_count": 14,
|
| 385 |
+
"metadata": {},
|
| 386 |
+
"outputs": [],
|
| 387 |
+
"source": [
|
| 388 |
+
"def evaluator_user_prompt(reply, message, history):\n",
|
| 389 |
+
" user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n",
|
| 390 |
+
" user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n",
|
| 391 |
+
" user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n",
|
| 392 |
+
" user_prompt += f\"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n",
|
| 393 |
+
" return user_prompt"
|
| 394 |
+
]
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"cell_type": "code",
|
| 398 |
+
"execution_count": 23,
|
| 399 |
+
"metadata": {},
|
| 400 |
+
"outputs": [],
|
| 401 |
+
"source": [
|
| 402 |
+
"import os\n",
|
| 403 |
+
"gemini = OpenAI(\n",
|
| 404 |
+
" api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
|
| 405 |
+
" base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
|
| 406 |
+
")"
|
| 407 |
+
]
|
| 408 |
+
},
|
| 409 |
+
{
|
| 410 |
+
"cell_type": "code",
|
| 411 |
+
"execution_count": 24,
|
| 412 |
+
"metadata": {},
|
| 413 |
+
"outputs": [
|
| 414 |
+
{
|
| 415 |
+
"name": "stdout",
|
| 416 |
+
"output_type": "stream",
|
| 417 |
+
"text": [
|
| 418 |
+
"API_Key=None\n"
|
| 419 |
+
]
|
| 420 |
+
}
|
| 421 |
+
],
|
| 422 |
+
"source": [
|
| 423 |
+
"#api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
|
| 424 |
+
"print(f\"API_Key={api_key}\")"
|
| 425 |
+
]
|
| 426 |
+
},
|
| 427 |
+
{
|
| 428 |
+
"cell_type": "code",
|
| 429 |
+
"execution_count": 18,
|
| 430 |
+
"metadata": {},
|
| 431 |
+
"outputs": [],
|
| 432 |
+
"source": [
|
| 433 |
+
"def evaluate(reply, message, history) -> Evaluation:\n",
|
| 434 |
+
"\n",
|
| 435 |
+
" messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
|
| 436 |
+
" response = gemini.beta.chat.completions.parse(model=\"gemini-2.0-flash\", messages=messages, response_format=Evaluation)\n",
|
| 437 |
+
" return response.choices[0].message.parsed"
|
| 438 |
+
]
|
| 439 |
+
},
|
| 440 |
+
{
|
| 441 |
+
"cell_type": "code",
|
| 442 |
+
"execution_count": 19,
|
| 443 |
+
"metadata": {},
|
| 444 |
+
"outputs": [],
|
| 445 |
+
"source": [
|
| 446 |
+
"messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"do you hold a patent?\"}]\n",
|
| 447 |
+
"response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
|
| 448 |
+
"reply = response.choices[0].message.content"
|
| 449 |
+
]
|
| 450 |
+
},
|
| 451 |
+
{
|
| 452 |
+
"cell_type": "code",
|
| 453 |
+
"execution_count": 20,
|
| 454 |
+
"metadata": {},
|
| 455 |
+
"outputs": [
|
| 456 |
+
{
|
| 457 |
+
"data": {
|
| 458 |
+
"text/plain": [
|
| 459 |
+
"'I currently do not hold any patents. My focus has primarily been on advancing technology strategies and implementing innovative solutions within organizations. If you have any specific questions about my projects or innovations, feel free to ask!'"
|
| 460 |
+
]
|
| 461 |
+
},
|
| 462 |
+
"execution_count": 20,
|
| 463 |
+
"metadata": {},
|
| 464 |
+
"output_type": "execute_result"
|
| 465 |
+
}
|
| 466 |
+
],
|
| 467 |
+
"source": [
|
| 468 |
+
"reply"
|
| 469 |
+
]
|
| 470 |
+
},
|
| 471 |
+
{
|
| 472 |
+
"cell_type": "code",
|
| 473 |
+
"execution_count": 21,
|
| 474 |
+
"metadata": {},
|
| 475 |
+
"outputs": [
|
| 476 |
+
{
|
| 477 |
+
"ename": "BadRequestError",
|
| 478 |
+
"evalue": "Error code: 400 - [{'error': {'code': 400, 'message': 'API key not valid. Please pass a valid API key.', 'status': 'INVALID_ARGUMENT', 'details': [{'@type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'API_KEY_INVALID', 'domain': 'googleapis.com', 'metadata': {'service': 'generativelanguage.googleapis.com'}}, {'@type': 'type.googleapis.com/google.rpc.LocalizedMessage', 'locale': 'en-US', 'message': 'API key not valid. Please pass a valid API key.'}]}}]",
|
| 479 |
+
"output_type": "error",
|
| 480 |
+
"traceback": [
|
| 481 |
+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
| 482 |
+
"\u001b[31mBadRequestError\u001b[39m Traceback (most recent call last)",
|
| 483 |
+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[21]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mevaluate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mreply\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mdo you hold a patent?\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m[\u001b[49m\u001b[43m:\u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 484 |
+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 4\u001b[39m, in \u001b[36mevaluate\u001b[39m\u001b[34m(reply, message, history)\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mevaluate\u001b[39m(reply, message, history) -> Evaluation:\n\u001b[32m 3\u001b[39m messages = [{\u001b[33m\"\u001b[39m\u001b[33mrole\u001b[39m\u001b[33m\"\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33msystem\u001b[39m\u001b[33m\"\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mcontent\u001b[39m\u001b[33m\"\u001b[39m: evaluator_system_prompt}] + [{\u001b[33m\"\u001b[39m\u001b[33mrole\u001b[39m\u001b[33m\"\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33muser\u001b[39m\u001b[33m\"\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mcontent\u001b[39m\u001b[33m\"\u001b[39m: evaluator_user_prompt(reply, message, history)}]\n\u001b[32m----> \u001b[39m\u001b[32m4\u001b[39m response = \u001b[43mgemini\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbeta\u001b[49m\u001b[43m.\u001b[49m\u001b[43mchat\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcompletions\u001b[49m\u001b[43m.\u001b[49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mgemini-2.0-flash\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mresponse_format\u001b[49m\u001b[43m=\u001b[49m\u001b[43mEvaluation\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m response.choices[\u001b[32m0\u001b[39m].message.parsed\n",
|
| 485 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/GitHub/AIAgent/agents/.venv/lib/python3.12/site-packages/openai/resources/beta/chat/completions.py:158\u001b[39m, in \u001b[36mCompletions.parse\u001b[39m\u001b[34m(self, messages, model, audio, response_format, frequency_penalty, function_call, functions, logit_bias, logprobs, max_completion_tokens, max_tokens, metadata, modalities, n, parallel_tool_calls, prediction, presence_penalty, reasoning_effort, seed, service_tier, stop, store, stream_options, temperature, tool_choice, tools, top_logprobs, top_p, user, web_search_options, extra_headers, extra_query, extra_body, timeout)\u001b[39m\n\u001b[32m 151\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mparser\u001b[39m(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]:\n\u001b[32m 152\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m _parse_chat_completion(\n\u001b[32m 153\u001b[39m response_format=response_format,\n\u001b[32m 154\u001b[39m chat_completion=raw_completion,\n\u001b[32m 155\u001b[39m input_tools=tools,\n\u001b[32m 156\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m158\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_post\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 159\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43m/chat/completions\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 160\u001b[39m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmaybe_transform\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 161\u001b[39m \u001b[43m \u001b[49m\u001b[43m{\u001b[49m\n\u001b[32m 162\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmessages\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 163\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmodel\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 164\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43maudio\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43maudio\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 165\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mfrequency_penalty\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mfrequency_penalty\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 166\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mfunction_call\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mfunction_call\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 167\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mfunctions\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mfunctions\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 168\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mlogit_bias\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mlogit_bias\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 169\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mlogprobs\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mlogprobs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 170\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmax_completion_tokens\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_completion_tokens\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 171\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmax_tokens\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_tokens\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 172\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmetadata\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 173\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mmodalities\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mmodalities\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 174\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mn\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 175\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mparallel_tool_calls\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mparallel_tool_calls\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 176\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mprediction\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mprediction\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 177\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mpresence_penalty\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mpresence_penalty\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 178\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mreasoning_effort\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mreasoning_effort\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 179\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mresponse_format\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m_type_to_response_format\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse_format\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 180\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mseed\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mseed\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 181\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mservice_tier\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mservice_tier\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 182\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mstop\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 183\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mstore\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mstore\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 184\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mstream\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 185\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mstream_options\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 186\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtemperature\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mtemperature\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 187\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtool_choice\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mtool_choice\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 188\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtools\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mtools\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 189\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtop_logprobs\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mtop_logprobs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 190\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtop_p\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mtop_p\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 191\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43muser\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43muser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 192\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mweb_search_options\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mweb_search_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 193\u001b[39m \u001b[43m \u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 194\u001b[39m \u001b[43m \u001b[49m\u001b[43mcompletion_create_params\u001b[49m\u001b[43m.\u001b[49m\u001b[43mCompletionCreateParams\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 195\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 196\u001b[39m \u001b[43m \u001b[49m\u001b[43moptions\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmake_request_options\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 197\u001b[39m \u001b[43m \u001b[49m\u001b[43mextra_headers\u001b[49m\u001b[43m=\u001b[49m\u001b[43mextra_headers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 198\u001b[39m \u001b[43m \u001b[49m\u001b[43mextra_query\u001b[49m\u001b[43m=\u001b[49m\u001b[43mextra_query\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 199\u001b[39m \u001b[43m \u001b[49m\u001b[43mextra_body\u001b[49m\u001b[43m=\u001b[49m\u001b[43mextra_body\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 200\u001b[39m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 201\u001b[39m \u001b[43m \u001b[49m\u001b[43mpost_parser\u001b[49m\u001b[43m=\u001b[49m\u001b[43mparser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 202\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 203\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# we turn the `ChatCompletion` instance into a `ParsedChatCompletion`\u001b[39;49;00m\n\u001b[32m 204\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# in the `parser` function above\u001b[39;49;00m\n\u001b[32m 205\u001b[39m \u001b[43m \u001b[49m\u001b[43mcast_to\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcast\u001b[49m\u001b[43m(\u001b[49m\u001b[43mType\u001b[49m\u001b[43m[\u001b[49m\u001b[43mParsedChatCompletion\u001b[49m\u001b[43m[\u001b[49m\u001b[43mResponseFormatT\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mChatCompletion\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 206\u001b[39m \u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 207\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 486 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/GitHub/AIAgent/agents/.venv/lib/python3.12/site-packages/openai/_base_client.py:1239\u001b[39m, in \u001b[36mSyncAPIClient.post\u001b[39m\u001b[34m(self, path, cast_to, body, options, files, stream, stream_cls)\u001b[39m\n\u001b[32m 1225\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mpost\u001b[39m(\n\u001b[32m 1226\u001b[39m \u001b[38;5;28mself\u001b[39m,\n\u001b[32m 1227\u001b[39m path: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m (...)\u001b[39m\u001b[32m 1234\u001b[39m stream_cls: \u001b[38;5;28mtype\u001b[39m[_StreamT] | \u001b[38;5;28;01mNone\u001b[39;00m = \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[32m 1235\u001b[39m ) -> ResponseT | _StreamT:\n\u001b[32m 1236\u001b[39m opts = FinalRequestOptions.construct(\n\u001b[32m 1237\u001b[39m method=\u001b[33m\"\u001b[39m\u001b[33mpost\u001b[39m\u001b[33m\"\u001b[39m, url=path, json_data=body, files=to_httpx_files(files), **options\n\u001b[32m 1238\u001b[39m )\n\u001b[32m-> \u001b[39m\u001b[32m1239\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m cast(ResponseT, \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcast_to\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mopts\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream_cls\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstream_cls\u001b[49m\u001b[43m)\u001b[49m)\n",
|
| 487 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/GitHub/AIAgent/agents/.venv/lib/python3.12/site-packages/openai/_base_client.py:1034\u001b[39m, in \u001b[36mSyncAPIClient.request\u001b[39m\u001b[34m(self, cast_to, options, stream, stream_cls)\u001b[39m\n\u001b[32m 1031\u001b[39m err.response.read()\n\u001b[32m 1033\u001b[39m log.debug(\u001b[33m\"\u001b[39m\u001b[33mRe-raising status error\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m-> \u001b[39m\u001b[32m1034\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m._make_status_error_from_response(err.response) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 1036\u001b[39m \u001b[38;5;28;01mbreak\u001b[39;00m\n\u001b[32m 1038\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m response \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[33m\"\u001b[39m\u001b[33mcould not resolve response (should never happen)\u001b[39m\u001b[33m\"\u001b[39m\n",
|
| 488 |
+
"\u001b[31mBadRequestError\u001b[39m: Error code: 400 - [{'error': {'code': 400, 'message': 'API key not valid. Please pass a valid API key.', 'status': 'INVALID_ARGUMENT', 'details': [{'@type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'API_KEY_INVALID', 'domain': 'googleapis.com', 'metadata': {'service': 'generativelanguage.googleapis.com'}}, {'@type': 'type.googleapis.com/google.rpc.LocalizedMessage', 'locale': 'en-US', 'message': 'API key not valid. Please pass a valid API key.'}]}}]"
|
| 489 |
+
]
|
| 490 |
+
}
|
| 491 |
+
],
|
| 492 |
+
"source": [
|
| 493 |
+
"evaluate(reply, \"do you hold a patent?\", messages[:1])"
|
| 494 |
+
]
|
| 495 |
+
},
|
| 496 |
+
{
|
| 497 |
+
"cell_type": "code",
|
| 498 |
+
"execution_count": 30,
|
| 499 |
+
"metadata": {},
|
| 500 |
+
"outputs": [],
|
| 501 |
+
"source": [
|
| 502 |
+
"def rerun(reply, message, history, feedback):\n",
|
| 503 |
+
" updated_system_prompt = system_prompt + f\"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n",
|
| 504 |
+
" updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n",
|
| 505 |
+
" updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n",
|
| 506 |
+
" messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 507 |
+
" response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
|
| 508 |
+
" return response.choices[0].message.content"
|
| 509 |
+
]
|
| 510 |
+
},
|
| 511 |
+
{
|
| 512 |
+
"cell_type": "code",
|
| 513 |
+
"execution_count": 35,
|
| 514 |
+
"metadata": {},
|
| 515 |
+
"outputs": [],
|
| 516 |
+
"source": [
|
| 517 |
+
"def chat(message, history):\n",
|
| 518 |
+
" if \"patent\" in message:\n",
|
| 519 |
+
" system = system_prompt + \"\\n\\nEverything in your reply needs to be in pig latin - \\\n",
|
| 520 |
+
" it is mandatory that you respond only and entirely in pig latin\"\n",
|
| 521 |
+
" else:\n",
|
| 522 |
+
" system = system_prompt\n",
|
| 523 |
+
" messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 524 |
+
" response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
|
| 525 |
+
" reply =response.choices[0].message.content\n",
|
| 526 |
+
"\n",
|
| 527 |
+
" evaluation = evaluate(reply, message, history)\n",
|
| 528 |
+
" \n",
|
| 529 |
+
" if evaluation.is_acceptable:\n",
|
| 530 |
+
" print(\"Passed evaluation - returning reply\")\n",
|
| 531 |
+
" else:\n",
|
| 532 |
+
" print(\"Failed evaluation - retrying\")\n",
|
| 533 |
+
" print(evaluation.feedback)\n",
|
| 534 |
+
" reply = rerun(reply, message, history, evaluation.feedback) \n",
|
| 535 |
+
" return reply"
|
| 536 |
+
]
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"cell_type": "code",
|
| 540 |
+
"execution_count": null,
|
| 541 |
+
"metadata": {},
|
| 542 |
+
"outputs": [],
|
| 543 |
+
"source": [
|
| 544 |
+
"gr.ChatInterface(chat, type=\"messages\").launch()"
|
| 545 |
+
]
|
| 546 |
+
},
|
| 547 |
+
{
|
| 548 |
+
"cell_type": "markdown",
|
| 549 |
+
"metadata": {},
|
| 550 |
+
"source": []
|
| 551 |
+
},
|
| 552 |
+
{
|
| 553 |
+
"cell_type": "code",
|
| 554 |
+
"execution_count": null,
|
| 555 |
+
"metadata": {},
|
| 556 |
+
"outputs": [],
|
| 557 |
+
"source": []
|
| 558 |
+
}
|
| 559 |
+
],
|
| 560 |
+
"metadata": {
|
| 561 |
+
"kernelspec": {
|
| 562 |
+
"display_name": ".venv",
|
| 563 |
+
"language": "python",
|
| 564 |
+
"name": "python3"
|
| 565 |
+
},
|
| 566 |
+
"language_info": {
|
| 567 |
+
"codemirror_mode": {
|
| 568 |
+
"name": "ipython",
|
| 569 |
+
"version": 3
|
| 570 |
+
},
|
| 571 |
+
"file_extension": ".py",
|
| 572 |
+
"mimetype": "text/x-python",
|
| 573 |
+
"name": "python",
|
| 574 |
+
"nbconvert_exporter": "python",
|
| 575 |
+
"pygments_lexer": "ipython3",
|
| 576 |
+
"version": "3.12.10"
|
| 577 |
+
}
|
| 578 |
+
},
|
| 579 |
+
"nbformat": 4,
|
| 580 |
+
"nbformat_minor": 2
|
| 581 |
+
}
|
3_lab3.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
# coding: utf-8
|
| 3 |
+
|
| 4 |
+
# ## Welcome to Lab 3 for Week 1 Day 4
|
| 5 |
+
#
|
| 6 |
+
# Today we're going to build something with immediate value!
|
| 7 |
+
#
|
| 8 |
+
# In the folder `me` I've put a single file `linkedin.pdf` - it's a PDF download of my LinkedIn profile.
|
| 9 |
+
#
|
| 10 |
+
# Please replace it with yours!
|
| 11 |
+
#
|
| 12 |
+
# I've also made a file called `summary.txt`
|
| 13 |
+
#
|
| 14 |
+
# We're not going to use Tools just yet - we're going to add the tool tomorrow.
|
| 15 |
+
|
| 16 |
+
# <table style="margin: 0; text-align: left; width:100%">
|
| 17 |
+
# <tr>
|
| 18 |
+
# <td style="width: 150px; height: 150px; vertical-align: middle;">
|
| 19 |
+
# <img src="../assets/tools.png" width="150" height="150" style="display: block;" />
|
| 20 |
+
# </td>
|
| 21 |
+
# <td>
|
| 22 |
+
# <h2 style="color:#00bfff;">Looking up packages</h2>
|
| 23 |
+
# <span style="color:#00bfff;">In this lab, we're going to use the wonderful Gradio package for building quick UIs,
|
| 24 |
+
# and we're also going to use the popular PyPDF2 PDF reader. You can get guides to these packages by asking
|
| 25 |
+
# ChatGPT or Claude, and you find all open-source packages on the repository <a href="https://pypi.org">https://pypi.org</a>.
|
| 26 |
+
# </span>
|
| 27 |
+
# </td>
|
| 28 |
+
# </tr>
|
| 29 |
+
# </table>
|
| 30 |
+
|
| 31 |
+
# In[ ]:
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!
|
| 35 |
+
|
| 36 |
+
from dotenv import load_dotenv
|
| 37 |
+
from openai import OpenAI
|
| 38 |
+
from pypdf import PdfReader
|
| 39 |
+
import gradio as gr
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# In[3]:
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
load_dotenv(override=True)
|
| 46 |
+
openai = OpenAI()
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# In[4]:
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
reader = PdfReader("me/linkedin.pdf")
|
| 53 |
+
linkedin = ""
|
| 54 |
+
for page in reader.pages:
|
| 55 |
+
text = page.extract_text()
|
| 56 |
+
if text:
|
| 57 |
+
linkedin += text
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
# In[ ]:
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
print(linkedin)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
# In[5]:
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
with open("me/summary.txt", "r", encoding="utf-8") as f:
|
| 70 |
+
summary = f.read()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
# In[6]:
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
name = "Ed Donner"
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
# In[7]:
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
system_prompt = f"You are acting as {name}. You are answering questions on {name}'s website, \
|
| 83 |
+
particularly questions related to {name}'s career, background, skills and experience. \
|
| 84 |
+
Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \
|
| 85 |
+
You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \
|
| 86 |
+
Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
|
| 87 |
+
If you don't know the answer, say so."
|
| 88 |
+
|
| 89 |
+
system_prompt += f"\n\n## Summary:\n{summary}\n\n## LinkedIn Profile:\n{linkedin}\n\n"
|
| 90 |
+
system_prompt += f"With this context, please chat with the user, always staying in character as {name}."
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# In[ ]:
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
system_prompt
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
# In[9]:
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def chat(message, history):
|
| 103 |
+
messages = [{"role": "system", "content": system_prompt}] + history + [{"role": "user", "content": message}]
|
| 104 |
+
response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
|
| 105 |
+
return response.choices[0].message.content
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# In[ ]:
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
gr.ChatInterface(chat, type="messages").launch()
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# ## A lot is about to happen...
|
| 115 |
+
#
|
| 116 |
+
# 1. Be able to ask an LLM to evaluate an answer
|
| 117 |
+
# 2. Be able to rerun if the answer fails evaluation
|
| 118 |
+
# 3. Put this together into 1 workflow
|
| 119 |
+
#
|
| 120 |
+
# All without any Agentic framework!
|
| 121 |
+
|
| 122 |
+
# In[11]:
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
# Create a Pydantic model for the Evaluation
|
| 126 |
+
|
| 127 |
+
from pydantic import BaseModel
|
| 128 |
+
|
| 129 |
+
class Evaluation(BaseModel):
|
| 130 |
+
is_acceptable: bool
|
| 131 |
+
feedback: str
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
# In[23]:
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
evaluator_system_prompt = f"You are an evaluator that decides whether a response to a question is acceptable. \
|
| 138 |
+
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. \
|
| 139 |
+
The Agent is playing the role of {name} and is representing {name} on their website. \
|
| 140 |
+
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. \
|
| 141 |
+
The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:"
|
| 142 |
+
|
| 143 |
+
evaluator_system_prompt += f"\n\n## Summary:\n{summary}\n\n## LinkedIn Profile:\n{linkedin}\n\n"
|
| 144 |
+
evaluator_system_prompt += f"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback."
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
# In[24]:
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def evaluator_user_prompt(reply, message, history):
|
| 151 |
+
user_prompt = f"Here's the conversation between the User and the Agent: \n\n{history}\n\n"
|
| 152 |
+
user_prompt += f"Here's the latest message from the User: \n\n{message}\n\n"
|
| 153 |
+
user_prompt += f"Here's the latest response from the Agent: \n\n{reply}\n\n"
|
| 154 |
+
user_prompt += f"Please evaluate the response, replying with whether it is acceptable and your feedback."
|
| 155 |
+
return user_prompt
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
# In[25]:
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
import os
|
| 162 |
+
gemini = OpenAI(
|
| 163 |
+
api_key=os.getenv("GOOGLE_API_KEY"),
|
| 164 |
+
base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
# In[26]:
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def evaluate(reply, message, history) -> Evaluation:
|
| 172 |
+
|
| 173 |
+
messages = [{"role": "system", "content": evaluator_system_prompt}] + [{"role": "user", "content": evaluator_user_prompt(reply, message, history)}]
|
| 174 |
+
response = gemini.beta.chat.completions.parse(model="gemini-2.0-flash", messages=messages, response_format=Evaluation)
|
| 175 |
+
return response.choices[0].message.parsed
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
# In[27]:
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
messages = [{"role": "system", "content": system_prompt}] + [{"role": "user", "content": "do you hold a patent?"}]
|
| 182 |
+
response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
|
| 183 |
+
reply = response.choices[0].message.content
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
# In[ ]:
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
reply
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
# In[ ]:
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
evaluate(reply, "do you hold a patent?", messages[:1])
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
# In[30]:
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def rerun(reply, message, history, feedback):
|
| 202 |
+
updated_system_prompt = system_prompt + f"\n\n## Previous answer rejected\nYou just tried to reply, but the quality control rejected your reply\n"
|
| 203 |
+
updated_system_prompt += f"## Your attempted answer:\n{reply}\n\n"
|
| 204 |
+
updated_system_prompt += f"## Reason for rejection:\n{feedback}\n\n"
|
| 205 |
+
messages = [{"role": "system", "content": updated_system_prompt}] + history + [{"role": "user", "content": message}]
|
| 206 |
+
response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
|
| 207 |
+
return response.choices[0].message.content
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
# In[35]:
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def chat(message, history):
|
| 214 |
+
if "patent" in message:
|
| 215 |
+
system = system_prompt + "\n\nEverything in your reply needs to be in pig latin - \
|
| 216 |
+
it is mandatory that you respond only and entirely in pig latin"
|
| 217 |
+
else:
|
| 218 |
+
system = system_prompt
|
| 219 |
+
messages = [{"role": "system", "content": system}] + history + [{"role": "user", "content": message}]
|
| 220 |
+
response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
|
| 221 |
+
reply =response.choices[0].message.content
|
| 222 |
+
|
| 223 |
+
evaluation = evaluate(reply, message, history)
|
| 224 |
+
|
| 225 |
+
if evaluation.is_acceptable:
|
| 226 |
+
print("Passed evaluation - returning reply")
|
| 227 |
+
else:
|
| 228 |
+
print("Failed evaluation - retrying")
|
| 229 |
+
print(evaluation.feedback)
|
| 230 |
+
reply = rerun(reply, message, history, evaluation.feedback)
|
| 231 |
+
return reply
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
# In[ ]:
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
gr.ChatInterface(chat, type="messages").launch()
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
#
|
| 241 |
+
|
| 242 |
+
# In[ ]:
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
|
4_lab4.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
README.md
CHANGED
|
@@ -1,12 +1,6 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji: 👁
|
| 4 |
-
colorFrom: pink
|
| 5 |
-
colorTo: pink
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 5.32.0
|
| 8 |
app_file: app.py
|
| 9 |
-
|
|
|
|
| 10 |
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: alter_ego
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
app_file: app.py
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.31.0
|
| 6 |
---
|
|
|
|
|
|
app.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.openai = OpenAI()
|
| 80 |
+
self.name = "Luís Melo"
|
| 81 |
+
reader = PdfReader("me/linkedin.pdf")
|
| 82 |
+
self.linkedin = ""
|
| 83 |
+
for page in reader.pages:
|
| 84 |
+
text = page.extract_text()
|
| 85 |
+
if text:
|
| 86 |
+
self.linkedin += text
|
| 87 |
+
with open("me/summary.txt", "r", encoding="utf-8") as f:
|
| 88 |
+
self.summary = f.read()
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def handle_tool_call(self, tool_calls):
|
| 92 |
+
results = []
|
| 93 |
+
for tool_call in tool_calls:
|
| 94 |
+
tool_name = tool_call.function.name
|
| 95 |
+
arguments = json.loads(tool_call.function.arguments)
|
| 96 |
+
print(f"Tool called: {tool_name}", flush=True)
|
| 97 |
+
tool = globals().get(tool_name)
|
| 98 |
+
result = tool(**arguments) if tool else {}
|
| 99 |
+
results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
|
| 100 |
+
return results
|
| 101 |
+
|
| 102 |
+
def system_prompt(self):
|
| 103 |
+
system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
|
| 104 |
+
particularly questions related to {self.name}'s career, background, skills and experience. \
|
| 105 |
+
Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
|
| 106 |
+
You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
|
| 107 |
+
Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
|
| 108 |
+
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. \
|
| 109 |
+
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. "
|
| 110 |
+
|
| 111 |
+
system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
|
| 112 |
+
system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
|
| 113 |
+
return system_prompt
|
| 114 |
+
|
| 115 |
+
def chat(self, message, history):
|
| 116 |
+
messages = [{"role": "system", "content": self.system_prompt()}] + history + [{"role": "user", "content": message}]
|
| 117 |
+
done = False
|
| 118 |
+
while not done:
|
| 119 |
+
response = self.openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
|
| 120 |
+
if response.choices[0].finish_reason=="tool_calls":
|
| 121 |
+
message = response.choices[0].message
|
| 122 |
+
tool_calls = message.tool_calls
|
| 123 |
+
results = self.handle_tool_call(tool_calls)
|
| 124 |
+
messages.append(message)
|
| 125 |
+
messages.extend(results)
|
| 126 |
+
else:
|
| 127 |
+
done = True
|
| 128 |
+
return response.choices[0].message.content
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
if __name__ == "__main__":
|
| 132 |
+
me = Me()
|
| 133 |
+
gr.ChatInterface(me.chat, type="messages").launch()
|
| 134 |
+
|
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_gemini.ipynb
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
"# First let's do an import\n",
|
| 91 |
+
"from dotenv import load_dotenv\n"
|
| 92 |
+
]
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"cell_type": "code",
|
| 96 |
+
"execution_count": null,
|
| 97 |
+
"metadata": {},
|
| 98 |
+
"outputs": [],
|
| 99 |
+
"source": [
|
| 100 |
+
"# Next it's time to load the API keys into environment variables\n",
|
| 101 |
+
"\n",
|
| 102 |
+
"load_dotenv(override=True)"
|
| 103 |
+
]
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"cell_type": "code",
|
| 107 |
+
"execution_count": null,
|
| 108 |
+
"metadata": {},
|
| 109 |
+
"outputs": [],
|
| 110 |
+
"source": [
|
| 111 |
+
"# Check the keys\n",
|
| 112 |
+
"\n",
|
| 113 |
+
"import os\n",
|
| 114 |
+
"gemini_api_key = os.getenv('GEMINI_API_KEY')\n",
|
| 115 |
+
"\n",
|
| 116 |
+
"if gemini_api_key:\n",
|
| 117 |
+
" print(f\"Gemini API Key exists and begins {gemini_api_key[:8]}\")\n",
|
| 118 |
+
"else:\n",
|
| 119 |
+
" print(\"Gemini API Key not set - please head to the troubleshooting guide in the guides folder\")\n",
|
| 120 |
+
" \n"
|
| 121 |
+
]
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"cell_type": "code",
|
| 125 |
+
"execution_count": null,
|
| 126 |
+
"metadata": {},
|
| 127 |
+
"outputs": [],
|
| 128 |
+
"source": [
|
| 129 |
+
"# And now - the all important import statement\n",
|
| 130 |
+
"# If you get an import error - head over to troubleshooting guide\n",
|
| 131 |
+
"\n",
|
| 132 |
+
"from google import genai"
|
| 133 |
+
]
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"cell_type": "code",
|
| 137 |
+
"execution_count": null,
|
| 138 |
+
"metadata": {},
|
| 139 |
+
"outputs": [],
|
| 140 |
+
"source": [
|
| 141 |
+
"# And now we'll create an instance of the Gemini GenAI class\n",
|
| 142 |
+
"# If you're not sure what it means to create an instance of a class - head over to the guides folder!\n",
|
| 143 |
+
"# If you get a NameError - head over to the guides folder to learn about NameErrors\n",
|
| 144 |
+
"\n",
|
| 145 |
+
"client = genai.Client(api_key=gemini_api_key)"
|
| 146 |
+
]
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"cell_type": "code",
|
| 150 |
+
"execution_count": null,
|
| 151 |
+
"metadata": {},
|
| 152 |
+
"outputs": [],
|
| 153 |
+
"source": [
|
| 154 |
+
"# Create a list of messages in the familiar Gemini GenAI format\n",
|
| 155 |
+
"\n",
|
| 156 |
+
"messages = [\"What is 2+2?\"]"
|
| 157 |
+
]
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"cell_type": "code",
|
| 161 |
+
"execution_count": null,
|
| 162 |
+
"metadata": {},
|
| 163 |
+
"outputs": [],
|
| 164 |
+
"source": [
|
| 165 |
+
"# And now call it! Any problems, head to the troubleshooting guide\n",
|
| 166 |
+
"\n",
|
| 167 |
+
"response = client.models.generate_content(\n",
|
| 168 |
+
" model=\"gemini-2.0-flash\", contents=messages\n",
|
| 169 |
+
")\n",
|
| 170 |
+
"\n",
|
| 171 |
+
"print(response.text)\n"
|
| 172 |
+
]
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"cell_type": "code",
|
| 176 |
+
"execution_count": null,
|
| 177 |
+
"metadata": {},
|
| 178 |
+
"outputs": [],
|
| 179 |
+
"source": [
|
| 180 |
+
"\n",
|
| 181 |
+
"# Lets no create a challenging question\n",
|
| 182 |
+
"question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
|
| 183 |
+
"\n",
|
| 184 |
+
"# Ask the the model\n",
|
| 185 |
+
"response = client.models.generate_content(\n",
|
| 186 |
+
" model=\"gemini-2.0-flash\", contents=question\n",
|
| 187 |
+
")\n",
|
| 188 |
+
"\n",
|
| 189 |
+
"question = response.text\n",
|
| 190 |
+
"\n",
|
| 191 |
+
"print(question)\n"
|
| 192 |
+
]
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"cell_type": "code",
|
| 196 |
+
"execution_count": null,
|
| 197 |
+
"metadata": {},
|
| 198 |
+
"outputs": [],
|
| 199 |
+
"source": [
|
| 200 |
+
"# Ask the models generated question to the model\n",
|
| 201 |
+
"response = client.models.generate_content(\n",
|
| 202 |
+
" model=\"gemini-2.0-flash\", contents=question\n",
|
| 203 |
+
")\n",
|
| 204 |
+
"\n",
|
| 205 |
+
"# Extract the answer from the response\n",
|
| 206 |
+
"answer = response.text\n",
|
| 207 |
+
"\n",
|
| 208 |
+
"# Debug log the answer\n",
|
| 209 |
+
"print(answer)\n"
|
| 210 |
+
]
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"cell_type": "code",
|
| 214 |
+
"execution_count": null,
|
| 215 |
+
"metadata": {},
|
| 216 |
+
"outputs": [],
|
| 217 |
+
"source": [
|
| 218 |
+
"from IPython.display import Markdown, display\n",
|
| 219 |
+
"\n",
|
| 220 |
+
"# Nicely format the answer using Markdown\n",
|
| 221 |
+
"display(Markdown(answer))\n",
|
| 222 |
+
"\n"
|
| 223 |
+
]
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"cell_type": "markdown",
|
| 227 |
+
"metadata": {},
|
| 228 |
+
"source": [
|
| 229 |
+
"# Congratulations!\n",
|
| 230 |
+
"\n",
|
| 231 |
+
"That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
|
| 232 |
+
"\n",
|
| 233 |
+
"Next time things get more interesting..."
|
| 234 |
+
]
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"cell_type": "markdown",
|
| 238 |
+
"metadata": {},
|
| 239 |
+
"source": [
|
| 240 |
+
"<table style=\"margin: 0; text-align: left; width:100%\">\n",
|
| 241 |
+
" <tr>\n",
|
| 242 |
+
" <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
|
| 243 |
+
" <img src=\"../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
|
| 244 |
+
" </td>\n",
|
| 245 |
+
" <td>\n",
|
| 246 |
+
" <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
|
| 247 |
+
" <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
|
| 248 |
+
" First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
|
| 249 |
+
" Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
|
| 250 |
+
" Finally have 3 third LLM call propose the Agentic AI solution.\n",
|
| 251 |
+
" </span>\n",
|
| 252 |
+
" </td>\n",
|
| 253 |
+
" </tr>\n",
|
| 254 |
+
"</table>"
|
| 255 |
+
]
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"cell_type": "code",
|
| 259 |
+
"execution_count": null,
|
| 260 |
+
"metadata": {},
|
| 261 |
+
"outputs": [],
|
| 262 |
+
"source": [
|
| 263 |
+
"# First create the messages:\n",
|
| 264 |
+
"\n",
|
| 265 |
+
"\n",
|
| 266 |
+
"messages = [\"Something here\"]\n",
|
| 267 |
+
"\n",
|
| 268 |
+
"# Then make the first call:\n",
|
| 269 |
+
"\n",
|
| 270 |
+
"response =\n",
|
| 271 |
+
"\n",
|
| 272 |
+
"# Then read the business idea:\n",
|
| 273 |
+
"\n",
|
| 274 |
+
"business_idea = response.\n",
|
| 275 |
+
"\n",
|
| 276 |
+
"# And repeat!"
|
| 277 |
+
]
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"cell_type": "markdown",
|
| 281 |
+
"metadata": {},
|
| 282 |
+
"source": []
|
| 283 |
+
}
|
| 284 |
+
],
|
| 285 |
+
"metadata": {
|
| 286 |
+
"kernelspec": {
|
| 287 |
+
"display_name": ".venv",
|
| 288 |
+
"language": "python",
|
| 289 |
+
"name": "python3"
|
| 290 |
+
},
|
| 291 |
+
"language_info": {
|
| 292 |
+
"codemirror_mode": {
|
| 293 |
+
"name": "ipython",
|
| 294 |
+
"version": 3
|
| 295 |
+
},
|
| 296 |
+
"file_extension": ".py",
|
| 297 |
+
"mimetype": "text/x-python",
|
| 298 |
+
"name": "python",
|
| 299 |
+
"nbconvert_exporter": "python",
|
| 300 |
+
"pygments_lexer": "ipython3",
|
| 301 |
+
"version": "3.12.10"
|
| 302 |
+
}
|
| 303 |
+
},
|
| 304 |
+
"nbformat": 4,
|
| 305 |
+
"nbformat_minor": 2
|
| 306 |
+
}
|
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_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/2_lab2_exercise.ipynb
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# From Judging to Synthesizing — Evolving Multi-Agent Patterns\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"In the original 2_lab2.ipynb, we explored a powerful agentic design pattern: sending the same question to multiple large language models (LLMs), then using a separate “judge” agent to evaluate and rank their responses. This approach is valuable for identifying the single best answer among many, leveraging the strengths of ensemble reasoning and critical evaluation.\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"However, selecting just one “winner” can leave valuable insights from other models untapped. To address this, I am shifting to a new agentic pattern in this notebook: the synthesizer/improver pattern. Instead of merely ranking responses, we will prompt a dedicated LLM to review all answers, extract the most compelling ideas from each, and synthesize them into a single, improved response. \n",
|
| 12 |
+
"\n",
|
| 13 |
+
"This approach aims to combine the collective intelligence of multiple models, producing an answer that is richer, more nuanced, and more robust than any individual response.\n"
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"cell_type": "code",
|
| 18 |
+
"execution_count": 1,
|
| 19 |
+
"metadata": {},
|
| 20 |
+
"outputs": [],
|
| 21 |
+
"source": [
|
| 22 |
+
"import os\n",
|
| 23 |
+
"import json\n",
|
| 24 |
+
"from dotenv import load_dotenv\n",
|
| 25 |
+
"from openai import OpenAI\n",
|
| 26 |
+
"from anthropic import Anthropic\n",
|
| 27 |
+
"from IPython.display import Markdown, display"
|
| 28 |
+
]
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"cell_type": "code",
|
| 32 |
+
"execution_count": null,
|
| 33 |
+
"metadata": {},
|
| 34 |
+
"outputs": [],
|
| 35 |
+
"source": [
|
| 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 |
+
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
|
| 49 |
+
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
|
| 50 |
+
"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
|
| 51 |
+
"groq_api_key = os.getenv('GROQ_API_KEY')\n",
|
| 52 |
+
"\n",
|
| 53 |
+
"if openai_api_key:\n",
|
| 54 |
+
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
|
| 55 |
+
"else:\n",
|
| 56 |
+
" print(\"OpenAI API Key not set\")\n",
|
| 57 |
+
" \n",
|
| 58 |
+
"if anthropic_api_key:\n",
|
| 59 |
+
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
|
| 60 |
+
"else:\n",
|
| 61 |
+
" print(\"Anthropic API Key not set (and this is optional)\")\n",
|
| 62 |
+
"\n",
|
| 63 |
+
"if google_api_key:\n",
|
| 64 |
+
" print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
|
| 65 |
+
"else:\n",
|
| 66 |
+
" print(\"Google API Key not set (and this is optional)\")\n",
|
| 67 |
+
"\n",
|
| 68 |
+
"if deepseek_api_key:\n",
|
| 69 |
+
" print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
|
| 70 |
+
"else:\n",
|
| 71 |
+
" print(\"DeepSeek API Key not set (and this is optional)\")\n",
|
| 72 |
+
"\n",
|
| 73 |
+
"if groq_api_key:\n",
|
| 74 |
+
" print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
|
| 75 |
+
"else:\n",
|
| 76 |
+
" print(\"Groq API Key not set (and this is optional)\")"
|
| 77 |
+
]
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"cell_type": "code",
|
| 81 |
+
"execution_count": 7,
|
| 82 |
+
"metadata": {},
|
| 83 |
+
"outputs": [],
|
| 84 |
+
"source": [
|
| 85 |
+
"request = \"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their collective intelligence. \"\n",
|
| 86 |
+
"request += \"Answer only with the question, no explanation.\"\n",
|
| 87 |
+
"messages = [{\"role\": \"user\", \"content\": request}]"
|
| 88 |
+
]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"cell_type": "code",
|
| 92 |
+
"execution_count": null,
|
| 93 |
+
"metadata": {},
|
| 94 |
+
"outputs": [],
|
| 95 |
+
"source": [
|
| 96 |
+
"messages"
|
| 97 |
+
]
|
| 98 |
+
},
|
| 99 |
+
{
|
| 100 |
+
"cell_type": "code",
|
| 101 |
+
"execution_count": null,
|
| 102 |
+
"metadata": {},
|
| 103 |
+
"outputs": [],
|
| 104 |
+
"source": [
|
| 105 |
+
"openai = OpenAI()\n",
|
| 106 |
+
"response = openai.chat.completions.create(\n",
|
| 107 |
+
" model=\"gpt-4o-mini\",\n",
|
| 108 |
+
" messages=messages,\n",
|
| 109 |
+
")\n",
|
| 110 |
+
"question = response.choices[0].message.content\n",
|
| 111 |
+
"print(question)\n"
|
| 112 |
+
]
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"cell_type": "code",
|
| 116 |
+
"execution_count": 10,
|
| 117 |
+
"metadata": {},
|
| 118 |
+
"outputs": [],
|
| 119 |
+
"source": [
|
| 120 |
+
"teammates = []\n",
|
| 121 |
+
"answers = []\n",
|
| 122 |
+
"messages = [{\"role\": \"user\", \"content\": question}]"
|
| 123 |
+
]
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"cell_type": "code",
|
| 127 |
+
"execution_count": null,
|
| 128 |
+
"metadata": {},
|
| 129 |
+
"outputs": [],
|
| 130 |
+
"source": [
|
| 131 |
+
"# The API we know well\n",
|
| 132 |
+
"\n",
|
| 133 |
+
"model_name = \"gpt-4o-mini\"\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 |
+
"teammates.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 |
+
"# Anthropic has a slightly different API, and Max Tokens is required\n",
|
| 150 |
+
"\n",
|
| 151 |
+
"model_name = \"claude-3-7-sonnet-latest\"\n",
|
| 152 |
+
"\n",
|
| 153 |
+
"claude = Anthropic()\n",
|
| 154 |
+
"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
|
| 155 |
+
"answer = response.content[0].text\n",
|
| 156 |
+
"\n",
|
| 157 |
+
"display(Markdown(answer))\n",
|
| 158 |
+
"teammates.append(model_name)\n",
|
| 159 |
+
"answers.append(answer)"
|
| 160 |
+
]
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"cell_type": "code",
|
| 164 |
+
"execution_count": null,
|
| 165 |
+
"metadata": {},
|
| 166 |
+
"outputs": [],
|
| 167 |
+
"source": [
|
| 168 |
+
"gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
|
| 169 |
+
"model_name = \"gemini-2.0-flash\"\n",
|
| 170 |
+
"\n",
|
| 171 |
+
"response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
|
| 172 |
+
"answer = response.choices[0].message.content\n",
|
| 173 |
+
"\n",
|
| 174 |
+
"display(Markdown(answer))\n",
|
| 175 |
+
"teammates.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 |
+
"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
|
| 186 |
+
"model_name = \"deepseek-chat\"\n",
|
| 187 |
+
"\n",
|
| 188 |
+
"response = deepseek.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 |
+
"teammates.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 |
+
"groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
|
| 203 |
+
"model_name = \"llama-3.3-70b-versatile\"\n",
|
| 204 |
+
"\n",
|
| 205 |
+
"response = groq.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 |
+
"teammates.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 |
+
"# So where are we?\n",
|
| 220 |
+
"\n",
|
| 221 |
+
"print(teammates)\n",
|
| 222 |
+
"print(answers)"
|
| 223 |
+
]
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"cell_type": "code",
|
| 227 |
+
"execution_count": null,
|
| 228 |
+
"metadata": {},
|
| 229 |
+
"outputs": [],
|
| 230 |
+
"source": [
|
| 231 |
+
"# It's nice to know how to use \"zip\"\n",
|
| 232 |
+
"for teammate, answer in zip(teammates, answers):\n",
|
| 233 |
+
" print(f\"Teammate: {teammate}\\n\\n{answer}\")"
|
| 234 |
+
]
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"cell_type": "code",
|
| 238 |
+
"execution_count": 23,
|
| 239 |
+
"metadata": {},
|
| 240 |
+
"outputs": [],
|
| 241 |
+
"source": [
|
| 242 |
+
"# Let's bring this together - note the use of \"enumerate\"\n",
|
| 243 |
+
"\n",
|
| 244 |
+
"together = \"\"\n",
|
| 245 |
+
"for index, answer in enumerate(answers):\n",
|
| 246 |
+
" together += f\"# Response from teammate {index+1}\\n\\n\"\n",
|
| 247 |
+
" together += answer + \"\\n\\n\""
|
| 248 |
+
]
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"cell_type": "code",
|
| 252 |
+
"execution_count": null,
|
| 253 |
+
"metadata": {},
|
| 254 |
+
"outputs": [],
|
| 255 |
+
"source": [
|
| 256 |
+
"print(together)"
|
| 257 |
+
]
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"cell_type": "code",
|
| 261 |
+
"execution_count": 36,
|
| 262 |
+
"metadata": {},
|
| 263 |
+
"outputs": [],
|
| 264 |
+
"source": [
|
| 265 |
+
"formatter = f\"\"\"You are taking the nost interesting ideas fron {len(teammates)} teammates.\n",
|
| 266 |
+
"Each model has been given this question:\n",
|
| 267 |
+
"\n",
|
| 268 |
+
"{question}\n",
|
| 269 |
+
"\n",
|
| 270 |
+
"Your job is to evaluate each response for clarity and strength of argument, select the most relevant ideas and make a report, including a title, subtitles to separate sections, and quoting the LLM providing the idea.\n",
|
| 271 |
+
"From that, you will create a new improved answer.\"\"\""
|
| 272 |
+
]
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"cell_type": "code",
|
| 276 |
+
"execution_count": null,
|
| 277 |
+
"metadata": {},
|
| 278 |
+
"outputs": [],
|
| 279 |
+
"source": [
|
| 280 |
+
"print(formatter)"
|
| 281 |
+
]
|
| 282 |
+
},
|
| 283 |
+
{
|
| 284 |
+
"cell_type": "code",
|
| 285 |
+
"execution_count": 38,
|
| 286 |
+
"metadata": {},
|
| 287 |
+
"outputs": [],
|
| 288 |
+
"source": [
|
| 289 |
+
"formatter_messages = [{\"role\": \"user\", \"content\": formatter}]"
|
| 290 |
+
]
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"cell_type": "code",
|
| 294 |
+
"execution_count": null,
|
| 295 |
+
"metadata": {},
|
| 296 |
+
"outputs": [],
|
| 297 |
+
"source": [
|
| 298 |
+
"openai = OpenAI()\n",
|
| 299 |
+
"response = openai.chat.completions.create(\n",
|
| 300 |
+
" model=\"o3-mini\",\n",
|
| 301 |
+
" messages=formatter_messages,\n",
|
| 302 |
+
")\n",
|
| 303 |
+
"results = response.choices[0].message.content\n",
|
| 304 |
+
"display(Markdown(results))"
|
| 305 |
+
]
|
| 306 |
+
},
|
| 307 |
+
{
|
| 308 |
+
"cell_type": "code",
|
| 309 |
+
"execution_count": null,
|
| 310 |
+
"metadata": {},
|
| 311 |
+
"outputs": [],
|
| 312 |
+
"source": []
|
| 313 |
+
}
|
| 314 |
+
],
|
| 315 |
+
"metadata": {
|
| 316 |
+
"kernelspec": {
|
| 317 |
+
"display_name": ".venv",
|
| 318 |
+
"language": "python",
|
| 319 |
+
"name": "python3"
|
| 320 |
+
},
|
| 321 |
+
"language_info": {
|
| 322 |
+
"codemirror_mode": {
|
| 323 |
+
"name": "ipython",
|
| 324 |
+
"version": 3
|
| 325 |
+
},
|
| 326 |
+
"file_extension": ".py",
|
| 327 |
+
"mimetype": "text/x-python",
|
| 328 |
+
"name": "python",
|
| 329 |
+
"nbconvert_exporter": "python",
|
| 330 |
+
"pygments_lexer": "ipython3",
|
| 331 |
+
"version": "3.12.7"
|
| 332 |
+
}
|
| 333 |
+
},
|
| 334 |
+
"nbformat": 4,
|
| 335 |
+
"nbformat_minor": 2
|
| 336 |
+
}
|
community_contributions/3_lab3_groq_llama_generator_gemini_evaluator.ipynb
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"## Chat app with LinkedIn Profile Information - Groq LLama as Generator and Gemini as evaluator\n"
|
| 8 |
+
]
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"cell_type": "code",
|
| 12 |
+
"execution_count": 58,
|
| 13 |
+
"metadata": {},
|
| 14 |
+
"outputs": [],
|
| 15 |
+
"source": [
|
| 16 |
+
"# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!\n",
|
| 17 |
+
"\n",
|
| 18 |
+
"from dotenv import load_dotenv\n",
|
| 19 |
+
"from openai import OpenAI\n",
|
| 20 |
+
"from pypdf import PdfReader\n",
|
| 21 |
+
"from groq import Groq\n",
|
| 22 |
+
"import gradio as gr"
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"cell_type": "code",
|
| 27 |
+
"execution_count": 59,
|
| 28 |
+
"metadata": {},
|
| 29 |
+
"outputs": [],
|
| 30 |
+
"source": [
|
| 31 |
+
"load_dotenv(override=True)\n",
|
| 32 |
+
"groq = Groq()"
|
| 33 |
+
]
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"cell_type": "code",
|
| 37 |
+
"execution_count": 60,
|
| 38 |
+
"metadata": {},
|
| 39 |
+
"outputs": [],
|
| 40 |
+
"source": [
|
| 41 |
+
"reader = PdfReader(\"me/My_LinkedIn.pdf\")\n",
|
| 42 |
+
"linkedin = \"\"\n",
|
| 43 |
+
"for page in reader.pages:\n",
|
| 44 |
+
" text = page.extract_text()\n",
|
| 45 |
+
" if text:\n",
|
| 46 |
+
" linkedin += text"
|
| 47 |
+
]
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"cell_type": "code",
|
| 51 |
+
"execution_count": null,
|
| 52 |
+
"metadata": {},
|
| 53 |
+
"outputs": [],
|
| 54 |
+
"source": [
|
| 55 |
+
"print(linkedin)"
|
| 56 |
+
]
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"cell_type": "code",
|
| 60 |
+
"execution_count": 61,
|
| 61 |
+
"metadata": {},
|
| 62 |
+
"outputs": [],
|
| 63 |
+
"source": [
|
| 64 |
+
"with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
|
| 65 |
+
" summary = f.read()"
|
| 66 |
+
]
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
"cell_type": "code",
|
| 70 |
+
"execution_count": 62,
|
| 71 |
+
"metadata": {},
|
| 72 |
+
"outputs": [],
|
| 73 |
+
"source": [
|
| 74 |
+
"name = \"Maalaiappan Subramanian\""
|
| 75 |
+
]
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"cell_type": "code",
|
| 79 |
+
"execution_count": 63,
|
| 80 |
+
"metadata": {},
|
| 81 |
+
"outputs": [],
|
| 82 |
+
"source": [
|
| 83 |
+
"system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
|
| 84 |
+
"particularly questions related to {name}'s career, background, skills and experience. \\\n",
|
| 85 |
+
"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
|
| 86 |
+
"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
|
| 87 |
+
"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
|
| 88 |
+
"If you don't know the answer, say so.\"\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
|
| 91 |
+
"system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
|
| 92 |
+
]
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"cell_type": "code",
|
| 96 |
+
"execution_count": null,
|
| 97 |
+
"metadata": {},
|
| 98 |
+
"outputs": [],
|
| 99 |
+
"source": [
|
| 100 |
+
"system_prompt"
|
| 101 |
+
]
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"cell_type": "code",
|
| 105 |
+
"execution_count": 65,
|
| 106 |
+
"metadata": {},
|
| 107 |
+
"outputs": [],
|
| 108 |
+
"source": [
|
| 109 |
+
"def chat(message, history):\n",
|
| 110 |
+
" # Below line is to remove the metadata and options from the history\n",
|
| 111 |
+
" history = [{k: v for k, v in item.items() if k not in ('metadata', 'options')} for item in history]\n",
|
| 112 |
+
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 113 |
+
" response = groq.chat.completions.create(model=\"llama-3.3-70b-versatile\", messages=messages)\n",
|
| 114 |
+
" return response.choices[0].message.content"
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"cell_type": "code",
|
| 119 |
+
"execution_count": null,
|
| 120 |
+
"metadata": {},
|
| 121 |
+
"outputs": [],
|
| 122 |
+
"source": [
|
| 123 |
+
"gr.ChatInterface(chat, type=\"messages\").launch()"
|
| 124 |
+
]
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"cell_type": "code",
|
| 128 |
+
"execution_count": 67,
|
| 129 |
+
"metadata": {},
|
| 130 |
+
"outputs": [],
|
| 131 |
+
"source": [
|
| 132 |
+
"# Create a Pydantic model for the Evaluation\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"from pydantic import BaseModel\n",
|
| 135 |
+
"\n",
|
| 136 |
+
"class Evaluation(BaseModel):\n",
|
| 137 |
+
" is_acceptable: bool\n",
|
| 138 |
+
" feedback: str\n"
|
| 139 |
+
]
|
| 140 |
+
},
|
| 141 |
+
{
|
| 142 |
+
"cell_type": "code",
|
| 143 |
+
"execution_count": 69,
|
| 144 |
+
"metadata": {},
|
| 145 |
+
"outputs": [],
|
| 146 |
+
"source": [
|
| 147 |
+
"evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n",
|
| 148 |
+
"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",
|
| 149 |
+
"The Agent is playing the role of {name} and is representing {name} on their website. \\\n",
|
| 150 |
+
"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",
|
| 151 |
+
"The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n",
|
| 152 |
+
"\n",
|
| 153 |
+
"evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
|
| 154 |
+
"evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\""
|
| 155 |
+
]
|
| 156 |
+
},
|
| 157 |
+
{
|
| 158 |
+
"cell_type": "code",
|
| 159 |
+
"execution_count": 70,
|
| 160 |
+
"metadata": {},
|
| 161 |
+
"outputs": [],
|
| 162 |
+
"source": [
|
| 163 |
+
"def evaluator_user_prompt(reply, message, history):\n",
|
| 164 |
+
" user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n",
|
| 165 |
+
" user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n",
|
| 166 |
+
" user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n",
|
| 167 |
+
" user_prompt += f\"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n",
|
| 168 |
+
" return user_prompt"
|
| 169 |
+
]
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"cell_type": "code",
|
| 173 |
+
"execution_count": 71,
|
| 174 |
+
"metadata": {},
|
| 175 |
+
"outputs": [],
|
| 176 |
+
"source": [
|
| 177 |
+
"import os\n",
|
| 178 |
+
"gemini = OpenAI(\n",
|
| 179 |
+
" api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
|
| 180 |
+
" base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
|
| 181 |
+
")"
|
| 182 |
+
]
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"cell_type": "code",
|
| 186 |
+
"execution_count": 72,
|
| 187 |
+
"metadata": {},
|
| 188 |
+
"outputs": [],
|
| 189 |
+
"source": [
|
| 190 |
+
"def evaluate(reply, message, history) -> Evaluation:\n",
|
| 191 |
+
"\n",
|
| 192 |
+
" messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
|
| 193 |
+
" response = gemini.beta.chat.completions.parse(model=\"gemini-2.0-flash\", messages=messages, response_format=Evaluation)\n",
|
| 194 |
+
" return response.choices[0].message.parsed"
|
| 195 |
+
]
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
"cell_type": "code",
|
| 199 |
+
"execution_count": 73,
|
| 200 |
+
"metadata": {},
|
| 201 |
+
"outputs": [],
|
| 202 |
+
"source": [
|
| 203 |
+
"def rerun(reply, message, history, feedback):\n",
|
| 204 |
+
" # Below line is to remove the metadata and options from the history\n",
|
| 205 |
+
" history = [{k: v for k, v in item.items() if k not in ('metadata', 'options')} for item in history]\n",
|
| 206 |
+
" updated_system_prompt = system_prompt + f\"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n",
|
| 207 |
+
" updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n",
|
| 208 |
+
" updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n",
|
| 209 |
+
" messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 210 |
+
" response = groq.chat.completions.create(model=\"llama-3.3-70b-versatile\", messages=messages)\n",
|
| 211 |
+
" return response.choices[0].message.content"
|
| 212 |
+
]
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"cell_type": "code",
|
| 216 |
+
"execution_count": 74,
|
| 217 |
+
"metadata": {},
|
| 218 |
+
"outputs": [],
|
| 219 |
+
"source": [
|
| 220 |
+
"def chat(message, history):\n",
|
| 221 |
+
" if \"personal\" in message:\n",
|
| 222 |
+
" system = system_prompt + \"\\n\\nEverything in your reply needs to be in Gen Z language - \\\n",
|
| 223 |
+
" it is mandatory that you respond only and entirely in Gen Z language\"\n",
|
| 224 |
+
" else:\n",
|
| 225 |
+
" system = system_prompt\n",
|
| 226 |
+
" # Below line is to remove the metadata and options from the history\n",
|
| 227 |
+
" history = [{k: v for k, v in item.items() if k not in ('metadata', 'options')} for item in history]\n",
|
| 228 |
+
" messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
|
| 229 |
+
" response = groq.chat.completions.create(model=\"llama-3.3-70b-versatile\", messages=messages)\n",
|
| 230 |
+
" reply =response.choices[0].message.content\n",
|
| 231 |
+
"\n",
|
| 232 |
+
" evaluation = evaluate(reply, message, history)\n",
|
| 233 |
+
" \n",
|
| 234 |
+
" if evaluation.is_acceptable:\n",
|
| 235 |
+
" print(\"Passed evaluation - returning reply\")\n",
|
| 236 |
+
" else:\n",
|
| 237 |
+
" print(\"Failed evaluation - retrying\")\n",
|
| 238 |
+
" print(evaluation.feedback)\n",
|
| 239 |
+
" reply = rerun(reply, message, history, evaluation.feedback) \n",
|
| 240 |
+
" return reply"
|
| 241 |
+
]
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"cell_type": "code",
|
| 245 |
+
"execution_count": null,
|
| 246 |
+
"metadata": {},
|
| 247 |
+
"outputs": [],
|
| 248 |
+
"source": [
|
| 249 |
+
"gr.ChatInterface(chat, type=\"messages\").launch()"
|
| 250 |
+
]
|
| 251 |
+
},
|
| 252 |
+
{
|
| 253 |
+
"cell_type": "markdown",
|
| 254 |
+
"metadata": {},
|
| 255 |
+
"source": []
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"cell_type": "code",
|
| 259 |
+
"execution_count": null,
|
| 260 |
+
"metadata": {},
|
| 261 |
+
"outputs": [],
|
| 262 |
+
"source": []
|
| 263 |
+
}
|
| 264 |
+
],
|
| 265 |
+
"metadata": {
|
| 266 |
+
"kernelspec": {
|
| 267 |
+
"display_name": ".venv",
|
| 268 |
+
"language": "python",
|
| 269 |
+
"name": "python3"
|
| 270 |
+
},
|
| 271 |
+
"language_info": {
|
| 272 |
+
"codemirror_mode": {
|
| 273 |
+
"name": "ipython",
|
| 274 |
+
"version": 3
|
| 275 |
+
},
|
| 276 |
+
"file_extension": ".py",
|
| 277 |
+
"mimetype": "text/x-python",
|
| 278 |
+
"name": "python",
|
| 279 |
+
"nbconvert_exporter": "python",
|
| 280 |
+
"pygments_lexer": "ipython3",
|
| 281 |
+
"version": "3.12.10"
|
| 282 |
+
}
|
| 283 |
+
},
|
| 284 |
+
"nbformat": 4,
|
| 285 |
+
"nbformat_minor": 2
|
| 286 |
+
}
|
community_contributions/Business_Idea.ipynb
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"## Business idea generator and evaluator \n",
|
| 8 |
+
"\n"
|
| 9 |
+
]
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"cell_type": "code",
|
| 13 |
+
"execution_count": 1,
|
| 14 |
+
"metadata": {},
|
| 15 |
+
"outputs": [],
|
| 16 |
+
"source": [
|
| 17 |
+
"# Start with imports - ask ChatGPT to explain any package that you don't know\n",
|
| 18 |
+
"\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": 4,
|
| 80 |
+
"metadata": {},
|
| 81 |
+
"outputs": [],
|
| 82 |
+
"source": [
|
| 83 |
+
"request = (\n",
|
| 84 |
+
" \"Please generate three innovative business ideas aligned with the latest global trends. \"\n",
|
| 85 |
+
" \"For each idea, include a brief description (2–3 sentences).\"\n",
|
| 86 |
+
")\n",
|
| 87 |
+
"messages = [{\"role\": \"user\", \"content\": request}]"
|
| 88 |
+
]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"cell_type": "code",
|
| 92 |
+
"execution_count": null,
|
| 93 |
+
"metadata": {},
|
| 94 |
+
"outputs": [],
|
| 95 |
+
"source": [
|
| 96 |
+
"messages"
|
| 97 |
+
]
|
| 98 |
+
},
|
| 99 |
+
{
|
| 100 |
+
"cell_type": "code",
|
| 101 |
+
"execution_count": null,
|
| 102 |
+
"metadata": {},
|
| 103 |
+
"outputs": [],
|
| 104 |
+
"source": [
|
| 105 |
+
"\n",
|
| 106 |
+
"openai = OpenAI()\n",
|
| 107 |
+
"'''\n",
|
| 108 |
+
"response = openai.chat.completions.create(\n",
|
| 109 |
+
" model=\"gpt-4o-mini\",\n",
|
| 110 |
+
" messages=messages,\n",
|
| 111 |
+
")\n",
|
| 112 |
+
"question = response.choices[0].message.content\n",
|
| 113 |
+
"print(question)\n",
|
| 114 |
+
"'''"
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"cell_type": "code",
|
| 119 |
+
"execution_count": 9,
|
| 120 |
+
"metadata": {},
|
| 121 |
+
"outputs": [],
|
| 122 |
+
"source": [
|
| 123 |
+
"competitors = []\n",
|
| 124 |
+
"answers = []\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 |
+
"# The API we know well\n",
|
| 135 |
+
"\n",
|
| 136 |
+
"model_name = \"gpt-4o-mini\"\n",
|
| 137 |
+
"\n",
|
| 138 |
+
"response = openai.chat.completions.create(model=model_name, messages=messages)\n",
|
| 139 |
+
"answer = response.choices[0].message.content\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"display(Markdown(answer))\n",
|
| 142 |
+
"competitors.append(model_name)\n",
|
| 143 |
+
"answers.append(answer)"
|
| 144 |
+
]
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"cell_type": "code",
|
| 148 |
+
"execution_count": null,
|
| 149 |
+
"metadata": {},
|
| 150 |
+
"outputs": [],
|
| 151 |
+
"source": [
|
| 152 |
+
"# Anthropic has a slightly different API, and Max Tokens is required\n",
|
| 153 |
+
"\n",
|
| 154 |
+
"model_name = \"claude-3-7-sonnet-latest\"\n",
|
| 155 |
+
"\n",
|
| 156 |
+
"claude = Anthropic()\n",
|
| 157 |
+
"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\n",
|
| 158 |
+
"answer = response.content[0].text\n",
|
| 159 |
+
"\n",
|
| 160 |
+
"display(Markdown(answer))\n",
|
| 161 |
+
"competitors.append(model_name)\n",
|
| 162 |
+
"answers.append(answer)"
|
| 163 |
+
]
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"cell_type": "code",
|
| 167 |
+
"execution_count": null,
|
| 168 |
+
"metadata": {},
|
| 169 |
+
"outputs": [],
|
| 170 |
+
"source": [
|
| 171 |
+
"gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
|
| 172 |
+
"model_name = \"gemini-2.0-flash\"\n",
|
| 173 |
+
"\n",
|
| 174 |
+
"response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
|
| 175 |
+
"answer = response.choices[0].message.content\n",
|
| 176 |
+
"\n",
|
| 177 |
+
"display(Markdown(answer))\n",
|
| 178 |
+
"competitors.append(model_name)\n",
|
| 179 |
+
"answers.append(answer)"
|
| 180 |
+
]
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"cell_type": "code",
|
| 184 |
+
"execution_count": null,
|
| 185 |
+
"metadata": {},
|
| 186 |
+
"outputs": [],
|
| 187 |
+
"source": [
|
| 188 |
+
"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
|
| 189 |
+
"model_name = \"deepseek-chat\"\n",
|
| 190 |
+
"\n",
|
| 191 |
+
"response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
|
| 192 |
+
"answer = response.choices[0].message.content\n",
|
| 193 |
+
"\n",
|
| 194 |
+
"display(Markdown(answer))\n",
|
| 195 |
+
"competitors.append(model_name)\n",
|
| 196 |
+
"answers.append(answer)"
|
| 197 |
+
]
|
| 198 |
+
},
|
| 199 |
+
{
|
| 200 |
+
"cell_type": "code",
|
| 201 |
+
"execution_count": null,
|
| 202 |
+
"metadata": {},
|
| 203 |
+
"outputs": [],
|
| 204 |
+
"source": [
|
| 205 |
+
"groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
|
| 206 |
+
"model_name = \"llama-3.3-70b-versatile\"\n",
|
| 207 |
+
"\n",
|
| 208 |
+
"response = groq.chat.completions.create(model=model_name, messages=messages)\n",
|
| 209 |
+
"answer = response.choices[0].message.content\n",
|
| 210 |
+
"\n",
|
| 211 |
+
"display(Markdown(answer))\n",
|
| 212 |
+
"competitors.append(model_name)\n",
|
| 213 |
+
"answers.append(answer)\n"
|
| 214 |
+
]
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"cell_type": "code",
|
| 218 |
+
"execution_count": null,
|
| 219 |
+
"metadata": {},
|
| 220 |
+
"outputs": [],
|
| 221 |
+
"source": [
|
| 222 |
+
"!ollama pull llama3.2"
|
| 223 |
+
]
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"cell_type": "code",
|
| 227 |
+
"execution_count": null,
|
| 228 |
+
"metadata": {},
|
| 229 |
+
"outputs": [],
|
| 230 |
+
"source": [
|
| 231 |
+
"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
|
| 232 |
+
"model_name = \"llama3.2\"\n",
|
| 233 |
+
"\n",
|
| 234 |
+
"response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
|
| 235 |
+
"answer = response.choices[0].message.content\n",
|
| 236 |
+
"\n",
|
| 237 |
+
"display(Markdown(answer))\n",
|
| 238 |
+
"competitors.append(model_name)\n",
|
| 239 |
+
"answers.append(answer)"
|
| 240 |
+
]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"cell_type": "code",
|
| 244 |
+
"execution_count": null,
|
| 245 |
+
"metadata": {},
|
| 246 |
+
"outputs": [],
|
| 247 |
+
"source": [
|
| 248 |
+
"# So where are we?\n",
|
| 249 |
+
"\n",
|
| 250 |
+
"print(competitors)\n",
|
| 251 |
+
"print(answers)\n"
|
| 252 |
+
]
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"cell_type": "code",
|
| 256 |
+
"execution_count": null,
|
| 257 |
+
"metadata": {},
|
| 258 |
+
"outputs": [],
|
| 259 |
+
"source": [
|
| 260 |
+
"# It's nice to know how to use \"zip\"\n",
|
| 261 |
+
"for competitor, answer in zip(competitors, answers):\n",
|
| 262 |
+
" print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
|
| 263 |
+
]
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"cell_type": "code",
|
| 267 |
+
"execution_count": 14,
|
| 268 |
+
"metadata": {},
|
| 269 |
+
"outputs": [],
|
| 270 |
+
"source": [
|
| 271 |
+
"# Let's bring this together - note the use of \"enumerate\"\n",
|
| 272 |
+
"\n",
|
| 273 |
+
"together = \"\"\n",
|
| 274 |
+
"for index, answer in enumerate(answers):\n",
|
| 275 |
+
" together += f\"# Response from competitor {index+1}\\n\\n\"\n",
|
| 276 |
+
" together += answer + \"\\n\\n\""
|
| 277 |
+
]
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"cell_type": "code",
|
| 281 |
+
"execution_count": null,
|
| 282 |
+
"metadata": {},
|
| 283 |
+
"outputs": [],
|
| 284 |
+
"source": [
|
| 285 |
+
"print(together)"
|
| 286 |
+
]
|
| 287 |
+
},
|
| 288 |
+
{
|
| 289 |
+
"cell_type": "code",
|
| 290 |
+
"execution_count": null,
|
| 291 |
+
"metadata": {},
|
| 292 |
+
"outputs": [],
|
| 293 |
+
"source": [
|
| 294 |
+
"judge = f\"\"\"You are judging a competition between {len(competitors)} competitors.\n",
|
| 295 |
+
"Each model was asked to generate three innovative business ideas aligned with the latest global trends.\n",
|
| 296 |
+
"\n",
|
| 297 |
+
"Your job is to evaluate the likelihood of success for each idea on a scale from 0 to 100 percent. For each competitor, list the three percentages in the same order as their ideas.\n",
|
| 298 |
+
"\n",
|
| 299 |
+
"Respond only with JSON in this format:\n",
|
| 300 |
+
"{{\"results\": [\n",
|
| 301 |
+
" {{\"competitor\": 1, \"success_chances\": [perc1, perc2, perc3]}},\n",
|
| 302 |
+
" {{\"competitor\": 2, \"success_chances\": [perc1, perc2, perc3]}},\n",
|
| 303 |
+
" ...\n",
|
| 304 |
+
"]}}\n",
|
| 305 |
+
"\n",
|
| 306 |
+
"Here are the ideas from each competitor:\n",
|
| 307 |
+
"\n",
|
| 308 |
+
"{together}\n",
|
| 309 |
+
"\n",
|
| 310 |
+
"Now respond with only the JSON, nothing else.\"\"\"\n"
|
| 311 |
+
]
|
| 312 |
+
},
|
| 313 |
+
{
|
| 314 |
+
"cell_type": "code",
|
| 315 |
+
"execution_count": null,
|
| 316 |
+
"metadata": {},
|
| 317 |
+
"outputs": [],
|
| 318 |
+
"source": [
|
| 319 |
+
"print(judge)"
|
| 320 |
+
]
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"cell_type": "code",
|
| 324 |
+
"execution_count": 18,
|
| 325 |
+
"metadata": {},
|
| 326 |
+
"outputs": [],
|
| 327 |
+
"source": [
|
| 328 |
+
"judge_messages = [{\"role\": \"user\", \"content\": judge}]"
|
| 329 |
+
]
|
| 330 |
+
},
|
| 331 |
+
{
|
| 332 |
+
"cell_type": "code",
|
| 333 |
+
"execution_count": null,
|
| 334 |
+
"metadata": {},
|
| 335 |
+
"outputs": [],
|
| 336 |
+
"source": [
|
| 337 |
+
"# Judgement time!\n",
|
| 338 |
+
"\n",
|
| 339 |
+
"openai = OpenAI()\n",
|
| 340 |
+
"response = openai.chat.completions.create(\n",
|
| 341 |
+
" model=\"o3-mini\",\n",
|
| 342 |
+
" messages=judge_messages,\n",
|
| 343 |
+
")\n",
|
| 344 |
+
"results = response.choices[0].message.content\n",
|
| 345 |
+
"print(results)\n"
|
| 346 |
+
]
|
| 347 |
+
},
|
| 348 |
+
{
|
| 349 |
+
"cell_type": "code",
|
| 350 |
+
"execution_count": null,
|
| 351 |
+
"metadata": {},
|
| 352 |
+
"outputs": [],
|
| 353 |
+
"source": [
|
| 354 |
+
"# Parse judge results JSON and display success probabilities\n",
|
| 355 |
+
"results_dict = json.loads(results)\n",
|
| 356 |
+
"for entry in results_dict[\"results\"]:\n",
|
| 357 |
+
" comp_num = entry[\"competitor\"]\n",
|
| 358 |
+
" comp_name = competitors[comp_num - 1]\n",
|
| 359 |
+
" chances = entry[\"success_chances\"]\n",
|
| 360 |
+
" print(f\"{comp_name}:\")\n",
|
| 361 |
+
" for idx, perc in enumerate(chances, start=1):\n",
|
| 362 |
+
" print(f\" Idea {idx}: {perc}% chance of success\")\n",
|
| 363 |
+
" print()\n"
|
| 364 |
+
]
|
| 365 |
+
}
|
| 366 |
+
],
|
| 367 |
+
"metadata": {
|
| 368 |
+
"kernelspec": {
|
| 369 |
+
"display_name": ".venv",
|
| 370 |
+
"language": "python",
|
| 371 |
+
"name": "python3"
|
| 372 |
+
},
|
| 373 |
+
"language_info": {
|
| 374 |
+
"codemirror_mode": {
|
| 375 |
+
"name": "ipython",
|
| 376 |
+
"version": 3
|
| 377 |
+
},
|
| 378 |
+
"file_extension": ".py",
|
| 379 |
+
"mimetype": "text/x-python",
|
| 380 |
+
"name": "python",
|
| 381 |
+
"nbconvert_exporter": "python",
|
| 382 |
+
"pygments_lexer": "ipython3",
|
| 383 |
+
"version": "3.12.7"
|
| 384 |
+
}
|
| 385 |
+
},
|
| 386 |
+
"nbformat": 4,
|
| 387 |
+
"nbformat_minor": 2
|
| 388 |
+
}
|
community_contributions/Multi-Model-Resume–JD-Match-Analyzer/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.env
|
community_contributions/Multi-Model-Resume/342/200/223JD-Match-Analyzer/AnalyzeResume.png
ADDED
|
community_contributions/Multi-Model-Resume–JD-Match-Analyzer/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🧠 Resume-Job Match Application (LLM-Powered)
|
| 2 |
+
|
| 3 |
+

|
| 4 |
+
|
| 5 |
+
This is a **Streamlit-based web app** that evaluates how well a resume matches a job description using powerful Large Language Models (LLMs) such as:
|
| 6 |
+
|
| 7 |
+
- OpenAI GPT
|
| 8 |
+
- Anthropic Claude
|
| 9 |
+
- Google Gemini (Generative AI)
|
| 10 |
+
- Groq LLM
|
| 11 |
+
- DeepSeek LLM
|
| 12 |
+
|
| 13 |
+
The app takes a resume and job description as input files, sends them to these LLMs, and returns:
|
| 14 |
+
|
| 15 |
+
- ✅ Match percentage from each model
|
| 16 |
+
- 📊 A ranked table sorted by match %
|
| 17 |
+
- 📈 Average match percentage
|
| 18 |
+
- 🧠 Simple, responsive UI for instant feedback
|
| 19 |
+
|
| 20 |
+
## 📂 Features
|
| 21 |
+
|
| 22 |
+
- Upload **any file type** for resume and job description (PDF, DOCX, TXT, etc.)
|
| 23 |
+
- Automatic extraction and cleaning of text
|
| 24 |
+
- Match results across multiple models in real time
|
| 25 |
+
- Table view with clean formatting
|
| 26 |
+
- Uses `.env` file for secure API key management
|
| 27 |
+
|
| 28 |
+
## 🔐 Environment Setup (`.env`)
|
| 29 |
+
|
| 30 |
+
Create a `.env` file in the project root and add the following API keys:
|
| 31 |
+
|
| 32 |
+
```env
|
| 33 |
+
OPENAI_API_KEY=your-openai-api-key
|
| 34 |
+
ANTHROPIC_API_KEY=your-anthropic-api-key
|
| 35 |
+
GOOGLE_API_KEY=your-google-api-key
|
| 36 |
+
GROQ_API_KEY=your-groq-api-key
|
| 37 |
+
DEEPSEEK_API_KEY=your-deepseek-api-key
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## ▶️ Running the App
|
| 41 |
+
### Launch the app using Streamlit:
|
| 42 |
+
|
| 43 |
+
streamlit run resume_agent.py
|
| 44 |
+
|
| 45 |
+
### The app will open in your browser at:
|
| 46 |
+
📍 http://localhost:8501
|
| 47 |
+
|
| 48 |
+
|
community_contributions/Multi-Model-Resume–JD-Match-Analyzer/multi_file_ingestion.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from langchain.document_loaders import (
|
| 3 |
+
TextLoader,
|
| 4 |
+
PyPDFLoader,
|
| 5 |
+
UnstructuredWordDocumentLoader,
|
| 6 |
+
UnstructuredFileLoader
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def load_and_split_resume(file_path: str):
|
| 12 |
+
"""
|
| 13 |
+
Loads a resume file and splits it into text chunks using LangChain.
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
file_path (str): Path to the resume file (.txt, .pdf, .docx, etc.)
|
| 17 |
+
chunk_size (int): Maximum characters per chunk.
|
| 18 |
+
chunk_overlap (int): Overlap between chunks to preserve context.
|
| 19 |
+
|
| 20 |
+
Returns:
|
| 21 |
+
List[str]: List of split text chunks.
|
| 22 |
+
"""
|
| 23 |
+
if not os.path.exists(file_path):
|
| 24 |
+
raise FileNotFoundError(f"File not found: {file_path}")
|
| 25 |
+
|
| 26 |
+
ext = os.path.splitext(file_path)[1].lower()
|
| 27 |
+
|
| 28 |
+
# Select the appropriate loader
|
| 29 |
+
if ext == ".txt":
|
| 30 |
+
loader = TextLoader(file_path, encoding="utf-8")
|
| 31 |
+
elif ext == ".pdf":
|
| 32 |
+
loader = PyPDFLoader(file_path)
|
| 33 |
+
elif ext in [".docx", ".doc"]:
|
| 34 |
+
loader = UnstructuredWordDocumentLoader(file_path)
|
| 35 |
+
else:
|
| 36 |
+
# Fallback for other common formats
|
| 37 |
+
loader = UnstructuredFileLoader(file_path)
|
| 38 |
+
|
| 39 |
+
# Load the file as LangChain documents
|
| 40 |
+
documents = loader.load()
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
return documents
|
| 44 |
+
# return [doc.page_content for doc in split_docs]
|
community_contributions/Multi-Model-Resume–JD-Match-Analyzer/resume_agent.py
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import os
|
| 3 |
+
from openai import OpenAI
|
| 4 |
+
from anthropic import Anthropic
|
| 5 |
+
import pdfplumber
|
| 6 |
+
from io import StringIO
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
import pandas as pd
|
| 9 |
+
from multi_file_ingestion import load_and_split_resume
|
| 10 |
+
|
| 11 |
+
# Load environment variables
|
| 12 |
+
load_dotenv(override=True)
|
| 13 |
+
openai_api_key = os.getenv("OPENAI_API_KEY")
|
| 14 |
+
anthropic_api_key = os.getenv("ANTHROPIC_API_KEY")
|
| 15 |
+
google_api_key = os.getenv("GOOGLE_API_KEY")
|
| 16 |
+
groq_api_key = os.getenv("GROQ_API_KEY")
|
| 17 |
+
deepseek_api_key = os.getenv("DEEPSEEK_API_KEY")
|
| 18 |
+
|
| 19 |
+
openai = OpenAI()
|
| 20 |
+
|
| 21 |
+
# Streamlit UI
|
| 22 |
+
st.set_page_config(page_title="LLM Resume–JD Fit", layout="wide")
|
| 23 |
+
st.title("🧠 Multi-Model Resume–JD Match Analyzer")
|
| 24 |
+
|
| 25 |
+
# Inject custom CSS to reduce white space
|
| 26 |
+
st.markdown("""
|
| 27 |
+
<style>
|
| 28 |
+
.block-container {
|
| 29 |
+
padding-top: 3rem; /* instead of 1rem */
|
| 30 |
+
padding-bottom: 1rem;
|
| 31 |
+
}
|
| 32 |
+
.stMarkdown {
|
| 33 |
+
margin-bottom: 0.5rem;
|
| 34 |
+
}
|
| 35 |
+
.logo-container img {
|
| 36 |
+
width: 50px;
|
| 37 |
+
height: auto;
|
| 38 |
+
margin-right: 10px;
|
| 39 |
+
}
|
| 40 |
+
.header-row {
|
| 41 |
+
display: flex;
|
| 42 |
+
align-items: center;
|
| 43 |
+
gap: 1rem;
|
| 44 |
+
margin-top: 1rem; /* Add extra top margin here if needed */
|
| 45 |
+
}
|
| 46 |
+
</style>
|
| 47 |
+
""", unsafe_allow_html=True)
|
| 48 |
+
|
| 49 |
+
# File upload
|
| 50 |
+
resume_file = st.file_uploader("📄 Upload Resume (any file type)", type=None)
|
| 51 |
+
jd_file = st.file_uploader("📝 Upload Job Description (any file type)", type=None)
|
| 52 |
+
|
| 53 |
+
# Function to extract text from uploaded files
|
| 54 |
+
def extract_text(file):
|
| 55 |
+
if file.name.endswith(".pdf"):
|
| 56 |
+
with pdfplumber.open(file) as pdf:
|
| 57 |
+
return "\n".join([page.extract_text() for page in pdf.pages if page.extract_text()])
|
| 58 |
+
else:
|
| 59 |
+
return StringIO(file.read().decode("utf-8")).read()
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def extract_candidate_name(resume_text):
|
| 63 |
+
prompt = f"""
|
| 64 |
+
You are an AI assistant specialized in resume analysis.
|
| 65 |
+
|
| 66 |
+
Your task is to get full name of the candidate from the resume.
|
| 67 |
+
|
| 68 |
+
Resume:
|
| 69 |
+
{resume_text}
|
| 70 |
+
|
| 71 |
+
Respond with only the candidate's full name.
|
| 72 |
+
"""
|
| 73 |
+
try:
|
| 74 |
+
response = openai.chat.completions.create(
|
| 75 |
+
model="gpt-4o-mini",
|
| 76 |
+
messages=[
|
| 77 |
+
{"role": "system", "content": "You are a professional resume evaluator."},
|
| 78 |
+
{"role": "user", "content": prompt}
|
| 79 |
+
]
|
| 80 |
+
)
|
| 81 |
+
content = response.choices[0].message.content
|
| 82 |
+
|
| 83 |
+
return content.strip()
|
| 84 |
+
|
| 85 |
+
except Exception as e:
|
| 86 |
+
return "Unknown"
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
# Function to build the prompt for LLMs
|
| 90 |
+
def build_prompt(resume_text, jd_text):
|
| 91 |
+
prompt = f"""
|
| 92 |
+
You are an AI assistant specialized in resume analysis and recruitment. Analyze the given resume and compare it with the job description.
|
| 93 |
+
|
| 94 |
+
Your task is to evaluate how well the resume aligns with the job description.
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
Provide a match percentage between 0 and 100, where 100 indicates a perfect fit.
|
| 98 |
+
|
| 99 |
+
Resume:
|
| 100 |
+
{resume_text}
|
| 101 |
+
|
| 102 |
+
Job Description:
|
| 103 |
+
{jd_text}
|
| 104 |
+
|
| 105 |
+
Respond with only the match percentage as an integer.
|
| 106 |
+
"""
|
| 107 |
+
return prompt.strip()
|
| 108 |
+
|
| 109 |
+
# Function to get match percentage from OpenAI GPT-4
|
| 110 |
+
def get_openai_match(prompt):
|
| 111 |
+
try:
|
| 112 |
+
response = openai.chat.completions.create(
|
| 113 |
+
model="gpt-4o-mini",
|
| 114 |
+
messages=[
|
| 115 |
+
{"role": "system", "content": "You are a professional resume evaluator."},
|
| 116 |
+
{"role": "user", "content": prompt}
|
| 117 |
+
]
|
| 118 |
+
)
|
| 119 |
+
content = response.choices[0].message.content
|
| 120 |
+
digits = ''.join(filter(str.isdigit, content))
|
| 121 |
+
return min(int(digits), 100) if digits else 0
|
| 122 |
+
except Exception as e:
|
| 123 |
+
st.error(f"OpenAI API Error: {e}")
|
| 124 |
+
return 0
|
| 125 |
+
|
| 126 |
+
# Function to get match percentage from Anthropic Claude
|
| 127 |
+
def get_anthropic_match(prompt):
|
| 128 |
+
try:
|
| 129 |
+
model_name = "claude-3-7-sonnet-latest"
|
| 130 |
+
claude = Anthropic()
|
| 131 |
+
|
| 132 |
+
message = claude.messages.create(
|
| 133 |
+
model=model_name,
|
| 134 |
+
max_tokens=100,
|
| 135 |
+
messages=[
|
| 136 |
+
{"role": "user", "content": prompt}
|
| 137 |
+
]
|
| 138 |
+
)
|
| 139 |
+
content = message.content[0].text
|
| 140 |
+
digits = ''.join(filter(str.isdigit, content))
|
| 141 |
+
return min(int(digits), 100) if digits else 0
|
| 142 |
+
except Exception as e:
|
| 143 |
+
st.error(f"Anthropic API Error: {e}")
|
| 144 |
+
return 0
|
| 145 |
+
|
| 146 |
+
# Function to get match percentage from Google Gemini
|
| 147 |
+
def get_google_match(prompt):
|
| 148 |
+
try:
|
| 149 |
+
gemini = OpenAI(api_key=google_api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
|
| 150 |
+
model_name = "gemini-2.0-flash"
|
| 151 |
+
messages = [{"role": "user", "content": prompt}]
|
| 152 |
+
response = gemini.chat.completions.create(model=model_name, messages=messages)
|
| 153 |
+
content = response.choices[0].message.content
|
| 154 |
+
digits = ''.join(filter(str.isdigit, content))
|
| 155 |
+
return min(int(digits), 100) if digits else 0
|
| 156 |
+
except Exception as e:
|
| 157 |
+
st.error(f"Google Gemini API Error: {e}")
|
| 158 |
+
return 0
|
| 159 |
+
|
| 160 |
+
# Function to get match percentage from Groq
|
| 161 |
+
def get_groq_match(prompt):
|
| 162 |
+
try:
|
| 163 |
+
groq = OpenAI(api_key=groq_api_key, base_url="https://api.groq.com/openai/v1")
|
| 164 |
+
model_name = "llama-3.3-70b-versatile"
|
| 165 |
+
messages = [{"role": "user", "content": prompt}]
|
| 166 |
+
response = groq.chat.completions.create(model=model_name, messages=messages)
|
| 167 |
+
answer = response.choices[0].message.content
|
| 168 |
+
digits = ''.join(filter(str.isdigit, answer))
|
| 169 |
+
return min(int(digits), 100) if digits else 0
|
| 170 |
+
except Exception as e:
|
| 171 |
+
st.error(f"Groq API Error: {e}")
|
| 172 |
+
return 0
|
| 173 |
+
|
| 174 |
+
# Function to get match percentage from DeepSeek
|
| 175 |
+
def get_deepseek_match(prompt):
|
| 176 |
+
try:
|
| 177 |
+
deepseek = OpenAI(api_key=deepseek_api_key, base_url="https://api.deepseek.com/v1")
|
| 178 |
+
model_name = "deepseek-chat"
|
| 179 |
+
messages = [{"role": "user", "content": prompt}]
|
| 180 |
+
response = deepseek.chat.completions.create(model=model_name, messages=messages)
|
| 181 |
+
answer = response.choices[0].message.content
|
| 182 |
+
digits = ''.join(filter(str.isdigit, answer))
|
| 183 |
+
return min(int(digits), 100) if digits else 0
|
| 184 |
+
except Exception as e:
|
| 185 |
+
st.error(f"DeepSeek API Error: {e}")
|
| 186 |
+
return 0
|
| 187 |
+
|
| 188 |
+
# Main action
|
| 189 |
+
if st.button("🔍 Analyze Resume Fit"):
|
| 190 |
+
if resume_file and jd_file:
|
| 191 |
+
with st.spinner("Analyzing..."):
|
| 192 |
+
# resume_text = extract_text(resume_file)
|
| 193 |
+
# jd_text = extract_text(jd_file)
|
| 194 |
+
os.makedirs("temp_files", exist_ok=True)
|
| 195 |
+
resume_path = os.path.join("temp_files", resume_file.name)
|
| 196 |
+
|
| 197 |
+
with open(resume_path, "wb") as f:
|
| 198 |
+
f.write(resume_file.getbuffer())
|
| 199 |
+
resume_docs = load_and_split_resume(resume_path)
|
| 200 |
+
resume_text = "\n".join([doc.page_content for doc in resume_docs])
|
| 201 |
+
|
| 202 |
+
jd_path = os.path.join("temp_files", jd_file.name)
|
| 203 |
+
with open(jd_path, "wb") as f:
|
| 204 |
+
f.write(jd_file.getbuffer())
|
| 205 |
+
jd_docs = load_and_split_resume(jd_path)
|
| 206 |
+
jd_text = "\n".join([doc.page_content for doc in jd_docs])
|
| 207 |
+
|
| 208 |
+
candidate_name = extract_candidate_name(resume_text)
|
| 209 |
+
prompt = build_prompt(resume_text, jd_text)
|
| 210 |
+
|
| 211 |
+
# Get match percentages from all models
|
| 212 |
+
scores = {
|
| 213 |
+
"OpenAI GPT-4o Mini": get_openai_match(prompt),
|
| 214 |
+
"Anthropic Claude": get_anthropic_match(prompt),
|
| 215 |
+
"Google Gemini": get_google_match(prompt),
|
| 216 |
+
"Groq": get_groq_match(prompt),
|
| 217 |
+
"DeepSeek": get_deepseek_match(prompt),
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
# Calculate average score
|
| 221 |
+
average_score = round(sum(scores.values()) / len(scores), 2)
|
| 222 |
+
|
| 223 |
+
# Sort scores in descending order
|
| 224 |
+
sorted_scores = sorted(scores.items(), reverse=False)
|
| 225 |
+
|
| 226 |
+
# Display results
|
| 227 |
+
st.success("✅ Analysis Complete")
|
| 228 |
+
st.subheader("📊 Match Results (Ranked by Model)")
|
| 229 |
+
|
| 230 |
+
# Show candidate name
|
| 231 |
+
st.markdown(f"**👤 Candidate:** {candidate_name}")
|
| 232 |
+
|
| 233 |
+
# Create and sort dataframe
|
| 234 |
+
df = pd.DataFrame(sorted_scores, columns=["Model", "% Match"])
|
| 235 |
+
df = df.sort_values("% Match", ascending=False).reset_index(drop=True)
|
| 236 |
+
|
| 237 |
+
# Convert to HTML table
|
| 238 |
+
def render_custom_table(dataframe):
|
| 239 |
+
table_html = "<table style='border-collapse: collapse; width: auto;'>"
|
| 240 |
+
# Table header
|
| 241 |
+
table_html += "<thead><tr>"
|
| 242 |
+
for col in dataframe.columns:
|
| 243 |
+
table_html += f"<th style='text-align: center; padding: 8px; border-bottom: 1px solid #ddd;'>{col}</th>"
|
| 244 |
+
table_html += "</tr></thead>"
|
| 245 |
+
|
| 246 |
+
# Table rows
|
| 247 |
+
table_html += "<tbody>"
|
| 248 |
+
for _, row in dataframe.iterrows():
|
| 249 |
+
table_html += "<tr>"
|
| 250 |
+
for val in row:
|
| 251 |
+
table_html += f"<td style='text-align: left; padding: 8px; border-bottom: 1px solid #eee;'>{val}</td>"
|
| 252 |
+
table_html += "</tr>"
|
| 253 |
+
table_html += "</tbody></table>"
|
| 254 |
+
return table_html
|
| 255 |
+
|
| 256 |
+
# Display table
|
| 257 |
+
st.markdown(render_custom_table(df), unsafe_allow_html=True)
|
| 258 |
+
|
| 259 |
+
# Show average match
|
| 260 |
+
st.metric(label="📈 Average Match %", value=f"{average_score:.2f}%")
|
| 261 |
+
else:
|
| 262 |
+
st.warning("Please upload both resume and job description.")
|
community_contributions/app_rate_limiter_mailgun_integration.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
import base64
|
| 9 |
+
import time
|
| 10 |
+
from collections import defaultdict
|
| 11 |
+
import fastapi
|
| 12 |
+
from gradio.context import Context
|
| 13 |
+
import logging
|
| 14 |
+
|
| 15 |
+
logger = logging.getLogger(__name__)
|
| 16 |
+
logger.setLevel(logging.DEBUG)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
load_dotenv(override=True)
|
| 20 |
+
|
| 21 |
+
class RateLimiter:
|
| 22 |
+
def __init__(self, max_requests=5, time_window=5):
|
| 23 |
+
# max_requests per time_window seconds
|
| 24 |
+
self.max_requests = max_requests
|
| 25 |
+
self.time_window = time_window # in seconds
|
| 26 |
+
self.request_history = defaultdict(list)
|
| 27 |
+
|
| 28 |
+
def is_rate_limited(self, user_id):
|
| 29 |
+
current_time = time.time()
|
| 30 |
+
# Remove old requests
|
| 31 |
+
self.request_history[user_id] = [
|
| 32 |
+
timestamp for timestamp in self.request_history[user_id]
|
| 33 |
+
if current_time - timestamp < self.time_window
|
| 34 |
+
]
|
| 35 |
+
|
| 36 |
+
# Check if user has exceeded the limit
|
| 37 |
+
if len(self.request_history[user_id]) >= self.max_requests:
|
| 38 |
+
return True
|
| 39 |
+
|
| 40 |
+
# Add current request
|
| 41 |
+
self.request_history[user_id].append(current_time)
|
| 42 |
+
return False
|
| 43 |
+
|
| 44 |
+
def push(text):
|
| 45 |
+
requests.post(
|
| 46 |
+
"https://api.pushover.net/1/messages.json",
|
| 47 |
+
data={
|
| 48 |
+
"token": os.getenv("PUSHOVER_TOKEN"),
|
| 49 |
+
"user": os.getenv("PUSHOVER_USER"),
|
| 50 |
+
"message": text,
|
| 51 |
+
}
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
def send_email(from_email, name, notes):
|
| 55 |
+
auth = base64.b64encode(f'api:{os.getenv("MAILGUN_API_KEY")}'.encode()).decode()
|
| 56 |
+
|
| 57 |
+
response = requests.post(
|
| 58 |
+
f'https://api.mailgun.net/v3/{os.getenv("MAILGUN_DOMAIN")}/messages',
|
| 59 |
+
headers={
|
| 60 |
+
'Authorization': f'Basic {auth}'
|
| 61 |
+
},
|
| 62 |
+
data={
|
| 63 |
+
'from': f'Website Contact <mailgun@{os.getenv("MAILGUN_DOMAIN")}>',
|
| 64 |
+
'to': os.getenv("MAILGUN_RECIPIENT"),
|
| 65 |
+
'subject': f'New message from {from_email}',
|
| 66 |
+
'text': f'Name: {name}\nEmail: {from_email}\nNotes: {notes}',
|
| 67 |
+
'h:Reply-To': from_email
|
| 68 |
+
}
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
return response.status_code == 200
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def record_user_details(email, name="Name not provided", notes="not provided"):
|
| 75 |
+
push(f"Recording {name} with email {email} and notes {notes}")
|
| 76 |
+
# Send email notification
|
| 77 |
+
email_sent = send_email(email, name, notes)
|
| 78 |
+
return {"recorded": "ok", "email_sent": email_sent}
|
| 79 |
+
|
| 80 |
+
def record_unknown_question(question):
|
| 81 |
+
push(f"Recording {question}")
|
| 82 |
+
return {"recorded": "ok"}
|
| 83 |
+
|
| 84 |
+
record_user_details_json = {
|
| 85 |
+
"name": "record_user_details",
|
| 86 |
+
"description": "Use this tool to record that a user is interested in being in touch and provided an email address",
|
| 87 |
+
"parameters": {
|
| 88 |
+
"type": "object",
|
| 89 |
+
"properties": {
|
| 90 |
+
"email": {
|
| 91 |
+
"type": "string",
|
| 92 |
+
"description": "The email address of this user"
|
| 93 |
+
},
|
| 94 |
+
"name": {
|
| 95 |
+
"type": "string",
|
| 96 |
+
"description": "The user's name, if they provided it"
|
| 97 |
+
}
|
| 98 |
+
,
|
| 99 |
+
"notes": {
|
| 100 |
+
"type": "string",
|
| 101 |
+
"description": "Any additional information about the conversation that's worth recording to give context"
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"required": ["email"],
|
| 105 |
+
"additionalProperties": False
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
record_unknown_question_json = {
|
| 110 |
+
"name": "record_unknown_question",
|
| 111 |
+
"description": "Always use this tool to record any question that couldn't be answered as you didn't know the answer",
|
| 112 |
+
"parameters": {
|
| 113 |
+
"type": "object",
|
| 114 |
+
"properties": {
|
| 115 |
+
"question": {
|
| 116 |
+
"type": "string",
|
| 117 |
+
"description": "The question that couldn't be answered"
|
| 118 |
+
},
|
| 119 |
+
},
|
| 120 |
+
"required": ["question"],
|
| 121 |
+
"additionalProperties": False
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
tools = [{"type": "function", "function": record_user_details_json},
|
| 126 |
+
{"type": "function", "function": record_unknown_question_json}]
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
class Me:
|
| 130 |
+
|
| 131 |
+
def __init__(self):
|
| 132 |
+
self.openai = OpenAI(api_key=os.getenv("GOOGLE_API_KEY"), base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
|
| 133 |
+
self.name = "Sagarnil Das"
|
| 134 |
+
self.rate_limiter = RateLimiter(max_requests=5, time_window=60) # 5 messages per minute
|
| 135 |
+
reader = PdfReader("me/linkedin.pdf")
|
| 136 |
+
self.linkedin = ""
|
| 137 |
+
for page in reader.pages:
|
| 138 |
+
text = page.extract_text()
|
| 139 |
+
if text:
|
| 140 |
+
self.linkedin += text
|
| 141 |
+
with open("me/summary.txt", "r", encoding="utf-8") as f:
|
| 142 |
+
self.summary = f.read()
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def handle_tool_call(self, tool_calls):
|
| 146 |
+
results = []
|
| 147 |
+
for tool_call in tool_calls:
|
| 148 |
+
tool_name = tool_call.function.name
|
| 149 |
+
arguments = json.loads(tool_call.function.arguments)
|
| 150 |
+
print(f"Tool called: {tool_name}", flush=True)
|
| 151 |
+
tool = globals().get(tool_name)
|
| 152 |
+
result = tool(**arguments) if tool else {}
|
| 153 |
+
results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
|
| 154 |
+
return results
|
| 155 |
+
|
| 156 |
+
def system_prompt(self):
|
| 157 |
+
system_prompt = f"You are acting as {self.name}. You are answering questions on {self.name}'s website, \
|
| 158 |
+
particularly questions related to {self.name}'s career, background, skills and experience. \
|
| 159 |
+
Your responsibility is to represent {self.name} for interactions on the website as faithfully as possible. \
|
| 160 |
+
You are given a summary of {self.name}'s background and LinkedIn profile which you can use to answer questions. \
|
| 161 |
+
Be professional and engaging, as if talking to a potential client or future employer who came across the website. \
|
| 162 |
+
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. \
|
| 163 |
+
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. \
|
| 164 |
+
When a user provides their email, both a push notification and an email notification will be sent. If the user does not provide any note in the message \
|
| 165 |
+
in which they provide their email, then give a summary of the conversation so far as the notes."
|
| 166 |
+
|
| 167 |
+
system_prompt += f"\n\n## Summary:\n{self.summary}\n\n## LinkedIn Profile:\n{self.linkedin}\n\n"
|
| 168 |
+
system_prompt += f"With this context, please chat with the user, always staying in character as {self.name}."
|
| 169 |
+
return system_prompt
|
| 170 |
+
|
| 171 |
+
def chat(self, message, history):
|
| 172 |
+
# Get the client IP from Gradio's request context
|
| 173 |
+
try:
|
| 174 |
+
# Try to get the real client IP from request headers
|
| 175 |
+
request = Context.get_context().request
|
| 176 |
+
# Check for X-Forwarded-For header (common in reverse proxies like HF Spaces)
|
| 177 |
+
forwarded_for = request.headers.get("X-Forwarded-For")
|
| 178 |
+
# Check for Cf-Connecting-IP header (Cloudflare)
|
| 179 |
+
cloudflare_ip = request.headers.get("Cf-Connecting-IP")
|
| 180 |
+
|
| 181 |
+
if forwarded_for:
|
| 182 |
+
# X-Forwarded-For contains a comma-separated list of IPs, the first one is the client
|
| 183 |
+
user_id = forwarded_for.split(",")[0].strip()
|
| 184 |
+
elif cloudflare_ip:
|
| 185 |
+
user_id = cloudflare_ip
|
| 186 |
+
else:
|
| 187 |
+
# Fall back to direct client address
|
| 188 |
+
user_id = request.client.host
|
| 189 |
+
except (AttributeError, RuntimeError, fastapi.exceptions.FastAPIError):
|
| 190 |
+
# Fallback if we can't get context or if running outside of FastAPI
|
| 191 |
+
user_id = "default_user"
|
| 192 |
+
logger.debug(f"User ID: {user_id}")
|
| 193 |
+
if self.rate_limiter.is_rate_limited(user_id):
|
| 194 |
+
return "You're sending messages too quickly. Please wait a moment before sending another message."
|
| 195 |
+
|
| 196 |
+
messages = [{"role": "system", "content": self.system_prompt()}]
|
| 197 |
+
|
| 198 |
+
# Check if history is a list of dicts (Gradio "messages" format)
|
| 199 |
+
if isinstance(history, list) and all(isinstance(h, dict) for h in history):
|
| 200 |
+
messages.extend(history)
|
| 201 |
+
else:
|
| 202 |
+
# Assume it's a list of [user_msg, assistant_msg] pairs
|
| 203 |
+
for user_msg, assistant_msg in history:
|
| 204 |
+
messages.append({"role": "user", "content": user_msg})
|
| 205 |
+
messages.append({"role": "assistant", "content": assistant_msg})
|
| 206 |
+
|
| 207 |
+
messages.append({"role": "user", "content": message})
|
| 208 |
+
|
| 209 |
+
done = False
|
| 210 |
+
while not done:
|
| 211 |
+
response = self.openai.chat.completions.create(
|
| 212 |
+
model="gemini-2.0-flash",
|
| 213 |
+
messages=messages,
|
| 214 |
+
tools=tools
|
| 215 |
+
)
|
| 216 |
+
if response.choices[0].finish_reason == "tool_calls":
|
| 217 |
+
tool_calls = response.choices[0].message.tool_calls
|
| 218 |
+
tool_result = self.handle_tool_call(tool_calls)
|
| 219 |
+
messages.append(response.choices[0].message)
|
| 220 |
+
messages.extend(tool_result)
|
| 221 |
+
else:
|
| 222 |
+
done = True
|
| 223 |
+
|
| 224 |
+
return response.choices[0].message.content
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
if __name__ == "__main__":
|
| 229 |
+
me = Me()
|
| 230 |
+
gr.ChatInterface(me.chat, type="messages").launch()
|
| 231 |
+
|
community_contributions/community.ipynb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Community contributions\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"Thank you for considering contributing your work to the repo!\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"Please add your code (modules or notebooks) to this directory and send me a PR, per the instructions in the guides.\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"I'd love to share your progress with other students, so everyone can benefit from your projects.\n"
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"cell_type": "markdown",
|
| 18 |
+
"metadata": {},
|
| 19 |
+
"source": []
|
| 20 |
+
}
|
| 21 |
+
],
|
| 22 |
+
"metadata": {
|
| 23 |
+
"language_info": {
|
| 24 |
+
"name": "python"
|
| 25 |
+
}
|
| 26 |
+
},
|
| 27 |
+
"nbformat": 4,
|
| 28 |
+
"nbformat_minor": 2
|
| 29 |
+
}
|
community_contributions/llm-evaluator.ipynb
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"BASED ON Week 1 Day 3 LAB Exercise\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"This program evaluates different LLM outputs who are acting as customer service representative and are replying to an irritated customer.\n",
|
| 10 |
+
"OpenAI 40 mini, Gemini, Deepseek, Groq and Ollama are customer service representatives who respond to the email and OpenAI 3o mini analyzes all the responses and ranks their output based on different parameters."
|
| 11 |
+
]
|
| 12 |
+
},
|
| 13 |
+
{
|
| 14 |
+
"cell_type": "code",
|
| 15 |
+
"execution_count": 1,
|
| 16 |
+
"metadata": {},
|
| 17 |
+
"outputs": [],
|
| 18 |
+
"source": [
|
| 19 |
+
"# Start with imports -\n",
|
| 20 |
+
"import os\n",
|
| 21 |
+
"import json\n",
|
| 22 |
+
"from dotenv import load_dotenv\n",
|
| 23 |
+
"from openai import OpenAI\n",
|
| 24 |
+
"from anthropic import Anthropic\n",
|
| 25 |
+
"from IPython.display import Markdown, display"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": null,
|
| 31 |
+
"metadata": {},
|
| 32 |
+
"outputs": [],
|
| 33 |
+
"source": [
|
| 34 |
+
"# Always remember to do this!\n",
|
| 35 |
+
"load_dotenv(override=True)"
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"cell_type": "code",
|
| 40 |
+
"execution_count": null,
|
| 41 |
+
"metadata": {},
|
| 42 |
+
"outputs": [],
|
| 43 |
+
"source": [
|
| 44 |
+
"# Print the key prefixes to help with any debugging\n",
|
| 45 |
+
"\n",
|
| 46 |
+
"openai_api_key = os.getenv('OPENAI_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 google_api_key:\n",
|
| 57 |
+
" print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
|
| 58 |
+
"else:\n",
|
| 59 |
+
" print(\"Google API Key not set (and this is optional)\")\n",
|
| 60 |
+
"\n",
|
| 61 |
+
"if deepseek_api_key:\n",
|
| 62 |
+
" print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
|
| 63 |
+
"else:\n",
|
| 64 |
+
" print(\"DeepSeek API Key not set (and this is optional)\")\n",
|
| 65 |
+
"\n",
|
| 66 |
+
"if groq_api_key:\n",
|
| 67 |
+
" print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
|
| 68 |
+
"else:\n",
|
| 69 |
+
" print(\"Groq API Key not set (and this is optional)\")"
|
| 70 |
+
]
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"cell_type": "code",
|
| 74 |
+
"execution_count": 4,
|
| 75 |
+
"metadata": {},
|
| 76 |
+
"outputs": [],
|
| 77 |
+
"source": [
|
| 78 |
+
"persona = \"You are a customer support representative for a subscription bases software product.\"\n",
|
| 79 |
+
"email_content = '''Subject: Totally unacceptable experience\n",
|
| 80 |
+
"\n",
|
| 81 |
+
"Hi,\n",
|
| 82 |
+
"\n",
|
| 83 |
+
"I’ve already written to you twice about this, and still no response. I was charged again this month even after canceling my subscription. This is the third time this has happened.\n",
|
| 84 |
+
"\n",
|
| 85 |
+
"Honestly, I’m losing patience. If I don’t get a clear explanation and refund within 24 hours, I’m going to report this on social media and leave negative reviews.\n",
|
| 86 |
+
"\n",
|
| 87 |
+
"You’ve seriously messed up here. Fix this now.\n",
|
| 88 |
+
"\n",
|
| 89 |
+
"– Jordan\n",
|
| 90 |
+
"\n",
|
| 91 |
+
"'''"
|
| 92 |
+
]
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"cell_type": "code",
|
| 96 |
+
"execution_count": 5,
|
| 97 |
+
"metadata": {},
|
| 98 |
+
"outputs": [],
|
| 99 |
+
"source": [
|
| 100 |
+
"messages = [{\"role\":\"system\", \"content\": persona}]"
|
| 101 |
+
]
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"cell_type": "code",
|
| 105 |
+
"execution_count": null,
|
| 106 |
+
"metadata": {},
|
| 107 |
+
"outputs": [],
|
| 108 |
+
"source": [
|
| 109 |
+
"request = f\"\"\"A frustrated customer has written in about being repeatedly charged after canceling and threatened to escalate on social media.\n",
|
| 110 |
+
"Write a calm, empathetic, and professional response that Acknowledges their frustration, Apologizes sincerely,Explains the next steps to resolve the issue\n",
|
| 111 |
+
"Attempts to de-escalate the situation. Keep the tone respectful and proactive. Do not make excuses or blame the customer.\"\"\"\n",
|
| 112 |
+
"request += f\" Here is the email : {email_content}]\"\n",
|
| 113 |
+
"messages.append({\"role\": \"user\", \"content\": request})\n",
|
| 114 |
+
"print(messages)"
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"cell_type": "code",
|
| 119 |
+
"execution_count": null,
|
| 120 |
+
"metadata": {},
|
| 121 |
+
"outputs": [],
|
| 122 |
+
"source": [
|
| 123 |
+
"messages"
|
| 124 |
+
]
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"cell_type": "code",
|
| 128 |
+
"execution_count": 8,
|
| 129 |
+
"metadata": {},
|
| 130 |
+
"outputs": [],
|
| 131 |
+
"source": [
|
| 132 |
+
"competitors = []\n",
|
| 133 |
+
"answers = []\n",
|
| 134 |
+
"messages = [{\"role\": \"user\", \"content\": request}]"
|
| 135 |
+
]
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"cell_type": "code",
|
| 139 |
+
"execution_count": null,
|
| 140 |
+
"metadata": {},
|
| 141 |
+
"outputs": [],
|
| 142 |
+
"source": [
|
| 143 |
+
"# The API we know well\n",
|
| 144 |
+
"openai = OpenAI()\n",
|
| 145 |
+
"model_name = \"gpt-4o-mini\"\n",
|
| 146 |
+
"\n",
|
| 147 |
+
"response = openai.chat.completions.create(model=model_name, messages=messages)\n",
|
| 148 |
+
"answer = response.choices[0].message.content\n",
|
| 149 |
+
"\n",
|
| 150 |
+
"display(Markdown(answer))\n",
|
| 151 |
+
"competitors.append(model_name)\n",
|
| 152 |
+
"answers.append(answer)"
|
| 153 |
+
]
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"cell_type": "code",
|
| 157 |
+
"execution_count": null,
|
| 158 |
+
"metadata": {},
|
| 159 |
+
"outputs": [],
|
| 160 |
+
"source": [
|
| 161 |
+
"gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
|
| 162 |
+
"model_name = \"gemini-2.0-flash\"\n",
|
| 163 |
+
"\n",
|
| 164 |
+
"response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
|
| 165 |
+
"answer = response.choices[0].message.content\n",
|
| 166 |
+
"\n",
|
| 167 |
+
"display(Markdown(answer))\n",
|
| 168 |
+
"competitors.append(model_name)\n",
|
| 169 |
+
"answers.append(answer)"
|
| 170 |
+
]
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"cell_type": "code",
|
| 174 |
+
"execution_count": null,
|
| 175 |
+
"metadata": {},
|
| 176 |
+
"outputs": [],
|
| 177 |
+
"source": [
|
| 178 |
+
"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
|
| 179 |
+
"model_name = \"deepseek-chat\"\n",
|
| 180 |
+
"\n",
|
| 181 |
+
"response = deepseek.chat.completions.create(model=model_name, messages=messages)\n",
|
| 182 |
+
"answer = response.choices[0].message.content\n",
|
| 183 |
+
"\n",
|
| 184 |
+
"display(Markdown(answer))\n",
|
| 185 |
+
"competitors.append(model_name)\n",
|
| 186 |
+
"answers.append(answer)"
|
| 187 |
+
]
|
| 188 |
+
},
|
| 189 |
+
{
|
| 190 |
+
"cell_type": "code",
|
| 191 |
+
"execution_count": null,
|
| 192 |
+
"metadata": {},
|
| 193 |
+
"outputs": [],
|
| 194 |
+
"source": [
|
| 195 |
+
"groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
|
| 196 |
+
"model_name = \"llama-3.3-70b-versatile\"\n",
|
| 197 |
+
"\n",
|
| 198 |
+
"response = groq.chat.completions.create(model=model_name, messages=messages)\n",
|
| 199 |
+
"answer = response.choices[0].message.content\n",
|
| 200 |
+
"\n",
|
| 201 |
+
"display(Markdown(answer))\n",
|
| 202 |
+
"competitors.append(model_name)\n",
|
| 203 |
+
"answers.append(answer)\n"
|
| 204 |
+
]
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"cell_type": "code",
|
| 208 |
+
"execution_count": null,
|
| 209 |
+
"metadata": {},
|
| 210 |
+
"outputs": [],
|
| 211 |
+
"source": [
|
| 212 |
+
"!ollama pull llama3.2"
|
| 213 |
+
]
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"cell_type": "code",
|
| 217 |
+
"execution_count": null,
|
| 218 |
+
"metadata": {},
|
| 219 |
+
"outputs": [],
|
| 220 |
+
"source": [
|
| 221 |
+
"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
|
| 222 |
+
"model_name = \"llama3.2\"\n",
|
| 223 |
+
"\n",
|
| 224 |
+
"response = ollama.chat.completions.create(model=model_name, messages=messages)\n",
|
| 225 |
+
"answer = response.choices[0].message.content\n",
|
| 226 |
+
"\n",
|
| 227 |
+
"display(Markdown(answer))\n",
|
| 228 |
+
"competitors.append(model_name)\n",
|
| 229 |
+
"answers.append(answer)"
|
| 230 |
+
]
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"cell_type": "code",
|
| 234 |
+
"execution_count": null,
|
| 235 |
+
"metadata": {},
|
| 236 |
+
"outputs": [],
|
| 237 |
+
"source": [
|
| 238 |
+
"# So where are we?\n",
|
| 239 |
+
"\n",
|
| 240 |
+
"print(competitors)\n",
|
| 241 |
+
"print(answers)\n"
|
| 242 |
+
]
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"cell_type": "code",
|
| 246 |
+
"execution_count": null,
|
| 247 |
+
"metadata": {},
|
| 248 |
+
"outputs": [],
|
| 249 |
+
"source": [
|
| 250 |
+
"# It's nice to know how to use \"zip\"\n",
|
| 251 |
+
"for competitor, answer in zip(competitors, answers):\n",
|
| 252 |
+
" print(f\"Competitor: {competitor}\\n\\n{answer}\")\n"
|
| 253 |
+
]
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"cell_type": "code",
|
| 257 |
+
"execution_count": 16,
|
| 258 |
+
"metadata": {},
|
| 259 |
+
"outputs": [],
|
| 260 |
+
"source": [
|
| 261 |
+
"# Let's bring this together - note the use of \"enumerate\"\n",
|
| 262 |
+
"\n",
|
| 263 |
+
"together = \"\"\n",
|
| 264 |
+
"for index, answer in enumerate(answers):\n",
|
| 265 |
+
" together += f\"# Response from competitor {index+1}\\n\\n\"\n",
|
| 266 |
+
" together += answer + \"\\n\\n\""
|
| 267 |
+
]
|
| 268 |
+
},
|
| 269 |
+
{
|
| 270 |
+
"cell_type": "code",
|
| 271 |
+
"execution_count": null,
|
| 272 |
+
"metadata": {},
|
| 273 |
+
"outputs": [],
|
| 274 |
+
"source": [
|
| 275 |
+
"print(together)"
|
| 276 |
+
]
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"cell_type": "code",
|
| 280 |
+
"execution_count": 18,
|
| 281 |
+
"metadata": {},
|
| 282 |
+
"outputs": [],
|
| 283 |
+
"source": [
|
| 284 |
+
"judge = f\"\"\"You are judging the performance of {len(competitors)} who are customer service representatives in a SaaS based subscription model company.\n",
|
| 285 |
+
"Each has responded to below grievnace email from the customer:\n",
|
| 286 |
+
"\n",
|
| 287 |
+
"{request}\n",
|
| 288 |
+
"\n",
|
| 289 |
+
"Evaluate the following customer support reply based on these criteria. Assign a score from 1 (very poor) to 5 (excellent) for each:\n",
|
| 290 |
+
"\n",
|
| 291 |
+
"1. Empathy:\n",
|
| 292 |
+
"Does the message acknowledge the customer’s frustration appropriately and sincerely?\n",
|
| 293 |
+
"\n",
|
| 294 |
+
"2. De-escalation:\n",
|
| 295 |
+
"Does the response effectively calm the customer and reduce the likelihood of social media escalation?\n",
|
| 296 |
+
"\n",
|
| 297 |
+
"3. Clarity:\n",
|
| 298 |
+
"Is the explanation of next steps clear and specific (e.g., refund process, timeline)?\n",
|
| 299 |
+
"\n",
|
| 300 |
+
"4. Professional Tone:\n",
|
| 301 |
+
"Is the message respectful, calm, and free from defensiveness or blame?\n",
|
| 302 |
+
"\n",
|
| 303 |
+
"Provide a one-sentence explanation for each score and a final overall rating with justification.\n",
|
| 304 |
+
"\n",
|
| 305 |
+
"Here are the responses from each competitor:\n",
|
| 306 |
+
"\n",
|
| 307 |
+
"{together}\n",
|
| 308 |
+
"\n",
|
| 309 |
+
"Do not include markdown formatting or code blocks. Also create a table with 3 columnds at the end containing rank, name and one line reason for the rank\"\"\"\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": 20,
|
| 324 |
+
"metadata": {},
|
| 325 |
+
"outputs": [],
|
| 326 |
+
"source": [
|
| 327 |
+
"judge_messages = [{\"role\": \"user\", \"content\": judge}]\n"
|
| 328 |
+
]
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"cell_type": "code",
|
| 332 |
+
"execution_count": null,
|
| 333 |
+
"metadata": {},
|
| 334 |
+
"outputs": [],
|
| 335 |
+
"source": [
|
| 336 |
+
"# Judgement time!\n",
|
| 337 |
+
"\n",
|
| 338 |
+
"openai = OpenAI()\n",
|
| 339 |
+
"response = openai.chat.completions.create(\n",
|
| 340 |
+
" model=\"o3-mini\",\n",
|
| 341 |
+
" messages=judge_messages,\n",
|
| 342 |
+
")\n",
|
| 343 |
+
"results = response.choices[0].message.content\n",
|
| 344 |
+
"print(results)\n"
|
| 345 |
+
]
|
| 346 |
+
},
|
| 347 |
+
{
|
| 348 |
+
"cell_type": "code",
|
| 349 |
+
"execution_count": null,
|
| 350 |
+
"metadata": {},
|
| 351 |
+
"outputs": [],
|
| 352 |
+
"source": [
|
| 353 |
+
"print(results)"
|
| 354 |
+
]
|
| 355 |
+
},
|
| 356 |
+
{
|
| 357 |
+
"cell_type": "code",
|
| 358 |
+
"execution_count": null,
|
| 359 |
+
"metadata": {},
|
| 360 |
+
"outputs": [],
|
| 361 |
+
"source": []
|
| 362 |
+
}
|
| 363 |
+
],
|
| 364 |
+
"metadata": {
|
| 365 |
+
"kernelspec": {
|
| 366 |
+
"display_name": ".venv",
|
| 367 |
+
"language": "python",
|
| 368 |
+
"name": "python3"
|
| 369 |
+
},
|
| 370 |
+
"language_info": {
|
| 371 |
+
"codemirror_mode": {
|
| 372 |
+
"name": "ipython",
|
| 373 |
+
"version": 3
|
| 374 |
+
},
|
| 375 |
+
"file_extension": ".py",
|
| 376 |
+
"mimetype": "text/x-python",
|
| 377 |
+
"name": "python",
|
| 378 |
+
"nbconvert_exporter": "python",
|
| 379 |
+
"pygments_lexer": "ipython3",
|
| 380 |
+
"version": "3.12.7"
|
| 381 |
+
}
|
| 382 |
+
},
|
| 383 |
+
"nbformat": 4,
|
| 384 |
+
"nbformat_minor": 2
|
| 385 |
+
}
|
community_contributions/my_1_lab1.ipynb
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
"Otherwise:\n",
|
| 60 |
+
"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.\n",
|
| 61 |
+
"2. Click in each \"cell\" below, starting with the cell immediately below this text, and press Shift+Enter to run\n",
|
| 62 |
+
"3. Enjoy!"
|
| 63 |
+
]
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"cell_type": "code",
|
| 67 |
+
"execution_count": 1,
|
| 68 |
+
"metadata": {},
|
| 69 |
+
"outputs": [],
|
| 70 |
+
"source": [
|
| 71 |
+
"# First let's do an import\n",
|
| 72 |
+
"from dotenv import load_dotenv\n"
|
| 73 |
+
]
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"cell_type": "code",
|
| 77 |
+
"execution_count": null,
|
| 78 |
+
"metadata": {},
|
| 79 |
+
"outputs": [],
|
| 80 |
+
"source": [
|
| 81 |
+
"# Next it's time to load the API keys into environment variables\n",
|
| 82 |
+
"\n",
|
| 83 |
+
"load_dotenv(override=True)"
|
| 84 |
+
]
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"cell_type": "code",
|
| 88 |
+
"execution_count": null,
|
| 89 |
+
"metadata": {},
|
| 90 |
+
"outputs": [],
|
| 91 |
+
"source": [
|
| 92 |
+
"# Check the keys\n",
|
| 93 |
+
"\n",
|
| 94 |
+
"import os\n",
|
| 95 |
+
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
|
| 96 |
+
"\n",
|
| 97 |
+
"if openai_api_key:\n",
|
| 98 |
+
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
|
| 99 |
+
"else:\n",
|
| 100 |
+
" print(\"OpenAI API Key not set - please head to the troubleshooting guide in the guides folder\")\n",
|
| 101 |
+
" \n"
|
| 102 |
+
]
|
| 103 |
+
},
|
| 104 |
+
{
|
| 105 |
+
"cell_type": "code",
|
| 106 |
+
"execution_count": 4,
|
| 107 |
+
"metadata": {},
|
| 108 |
+
"outputs": [],
|
| 109 |
+
"source": [
|
| 110 |
+
"# And now - the all important import statement\n",
|
| 111 |
+
"# If you get an import error - head over to troubleshooting guide\n",
|
| 112 |
+
"\n",
|
| 113 |
+
"from openai import OpenAI"
|
| 114 |
+
]
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"cell_type": "code",
|
| 118 |
+
"execution_count": 5,
|
| 119 |
+
"metadata": {},
|
| 120 |
+
"outputs": [],
|
| 121 |
+
"source": [
|
| 122 |
+
"# And now we'll create an instance of the OpenAI class\n",
|
| 123 |
+
"# If you're not sure what it means to create an instance of a class - head over to the guides folder!\n",
|
| 124 |
+
"# If you get a NameError - head over to the guides folder to learn about NameErrors\n",
|
| 125 |
+
"\n",
|
| 126 |
+
"openai = OpenAI()"
|
| 127 |
+
]
|
| 128 |
+
},
|
| 129 |
+
{
|
| 130 |
+
"cell_type": "code",
|
| 131 |
+
"execution_count": 6,
|
| 132 |
+
"metadata": {},
|
| 133 |
+
"outputs": [],
|
| 134 |
+
"source": [
|
| 135 |
+
"# Create a list of messages in the familiar OpenAI format\n",
|
| 136 |
+
"\n",
|
| 137 |
+
"messages = [{\"role\": \"user\", \"content\": \"What is 2+2?\"}]"
|
| 138 |
+
]
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"cell_type": "code",
|
| 142 |
+
"execution_count": null,
|
| 143 |
+
"metadata": {},
|
| 144 |
+
"outputs": [],
|
| 145 |
+
"source": [
|
| 146 |
+
"# And now call it! Any problems, head to the troubleshooting guide\n",
|
| 147 |
+
"\n",
|
| 148 |
+
"response = openai.chat.completions.create(\n",
|
| 149 |
+
" model=\"gpt-4o-mini\",\n",
|
| 150 |
+
" messages=messages\n",
|
| 151 |
+
")\n",
|
| 152 |
+
"\n",
|
| 153 |
+
"print(response.choices[0].message.content)\n"
|
| 154 |
+
]
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"cell_type": "code",
|
| 158 |
+
"execution_count": null,
|
| 159 |
+
"metadata": {},
|
| 160 |
+
"outputs": [],
|
| 161 |
+
"source": []
|
| 162 |
+
},
|
| 163 |
+
{
|
| 164 |
+
"cell_type": "code",
|
| 165 |
+
"execution_count": 8,
|
| 166 |
+
"metadata": {},
|
| 167 |
+
"outputs": [],
|
| 168 |
+
"source": [
|
| 169 |
+
"# And now - let's ask for a question:\n",
|
| 170 |
+
"\n",
|
| 171 |
+
"question = \"Please propose a hard, challenging question to assess someone's IQ. Respond only with the question.\"\n",
|
| 172 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n"
|
| 173 |
+
]
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"cell_type": "code",
|
| 177 |
+
"execution_count": null,
|
| 178 |
+
"metadata": {},
|
| 179 |
+
"outputs": [],
|
| 180 |
+
"source": [
|
| 181 |
+
"# ask it\n",
|
| 182 |
+
"response = openai.chat.completions.create(\n",
|
| 183 |
+
" model=\"gpt-4o-mini\",\n",
|
| 184 |
+
" messages=messages\n",
|
| 185 |
+
")\n",
|
| 186 |
+
"\n",
|
| 187 |
+
"question = response.choices[0].message.content\n",
|
| 188 |
+
"\n",
|
| 189 |
+
"print(question)\n"
|
| 190 |
+
]
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"cell_type": "code",
|
| 194 |
+
"execution_count": 10,
|
| 195 |
+
"metadata": {},
|
| 196 |
+
"outputs": [],
|
| 197 |
+
"source": [
|
| 198 |
+
"# form a new messages list\n",
|
| 199 |
+
"messages = [{\"role\": \"user\", \"content\": question}]\n"
|
| 200 |
+
]
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"cell_type": "code",
|
| 204 |
+
"execution_count": null,
|
| 205 |
+
"metadata": {},
|
| 206 |
+
"outputs": [],
|
| 207 |
+
"source": [
|
| 208 |
+
"# Ask it again\n",
|
| 209 |
+
"\n",
|
| 210 |
+
"response = openai.chat.completions.create(\n",
|
| 211 |
+
" model=\"gpt-4o-mini\",\n",
|
| 212 |
+
" messages=messages\n",
|
| 213 |
+
")\n",
|
| 214 |
+
"\n",
|
| 215 |
+
"answer = response.choices[0].message.content\n",
|
| 216 |
+
"print(answer)\n"
|
| 217 |
+
]
|
| 218 |
+
},
|
| 219 |
+
{
|
| 220 |
+
"cell_type": "code",
|
| 221 |
+
"execution_count": null,
|
| 222 |
+
"metadata": {},
|
| 223 |
+
"outputs": [],
|
| 224 |
+
"source": [
|
| 225 |
+
"from IPython.display import Markdown, display\n",
|
| 226 |
+
"\n",
|
| 227 |
+
"display(Markdown(answer))\n",
|
| 228 |
+
"\n"
|
| 229 |
+
]
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"cell_type": "markdown",
|
| 233 |
+
"metadata": {},
|
| 234 |
+
"source": [
|
| 235 |
+
"# Congratulations!\n",
|
| 236 |
+
"\n",
|
| 237 |
+
"That was a small, simple step in the direction of Agentic AI, with your new environment!\n",
|
| 238 |
+
"\n",
|
| 239 |
+
"Next time things get more interesting..."
|
| 240 |
+
]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"cell_type": "markdown",
|
| 244 |
+
"metadata": {},
|
| 245 |
+
"source": [
|
| 246 |
+
"<table style=\"margin: 0; text-align: left; width:100%\">\n",
|
| 247 |
+
" <tr>\n",
|
| 248 |
+
" <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
|
| 249 |
+
" <img src=\"../../assets/exercise.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
|
| 250 |
+
" </td>\n",
|
| 251 |
+
" <td>\n",
|
| 252 |
+
" <h2 style=\"color:#ff7800;\">Exercise</h2>\n",
|
| 253 |
+
" <span style=\"color:#ff7800;\">Now try this commercial application:<br/>\n",
|
| 254 |
+
" First ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.<br/>\n",
|
| 255 |
+
" Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.<br/>\n",
|
| 256 |
+
" Finally have 3 third LLM call propose the Agentic AI solution.\n",
|
| 257 |
+
" </span>\n",
|
| 258 |
+
" </td>\n",
|
| 259 |
+
" </tr>\n",
|
| 260 |
+
"</table>"
|
| 261 |
+
]
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"cell_type": "markdown",
|
| 265 |
+
"metadata": {},
|
| 266 |
+
"source": [
|
| 267 |
+
"```\n",
|
| 268 |
+
"# First create the messages:\n",
|
| 269 |
+
"\n",
|
| 270 |
+
"messages = [{\"role\": \"user\", \"content\": \"Something here\"}]\n",
|
| 271 |
+
"\n",
|
| 272 |
+
"# Then make the first call:\n",
|
| 273 |
+
"\n",
|
| 274 |
+
"response = openai.chat.completions.create(\n",
|
| 275 |
+
" model=\"gpt-4o-mini\",\n",
|
| 276 |
+
" messages=messages\n",
|
| 277 |
+
")\n",
|
| 278 |
+
"\n",
|
| 279 |
+
"# Then read the business idea:\n",
|
| 280 |
+
"\n",
|
| 281 |
+
"business_idea = response.choices[0].message.content\n",
|
| 282 |
+
"\n",
|
| 283 |
+
"# print(business_idea) \n",
|
| 284 |
+
"\n",
|
| 285 |
+
"# And repeat!\n",
|
| 286 |
+
"```"
|
| 287 |
+
]
|
| 288 |
+
},
|
| 289 |
+
{
|
| 290 |
+
"cell_type": "code",
|
| 291 |
+
"execution_count": null,
|
| 292 |
+
"metadata": {},
|
| 293 |
+
"outputs": [],
|
| 294 |
+
"source": [
|
| 295 |
+
"# First exercice : ask the LLM to pick a business area that might be worth exploring for an Agentic AI opportunity.\n",
|
| 296 |
+
"\n",
|
| 297 |
+
"# First create the messages:\n",
|
| 298 |
+
"query = \"Pick a business area that might be worth exploring for an Agentic AI opportunity.\"\n",
|
| 299 |
+
"messages = [{\"role\": \"user\", \"content\": query}]\n",
|
| 300 |
+
"\n",
|
| 301 |
+
"# Then make the first call:\n",
|
| 302 |
+
"\n",
|
| 303 |
+
"response = openai.chat.completions.create(\n",
|
| 304 |
+
" model=\"gpt-4o-mini\",\n",
|
| 305 |
+
" messages=messages\n",
|
| 306 |
+
")\n",
|
| 307 |
+
"\n",
|
| 308 |
+
"# Then read the business idea:\n",
|
| 309 |
+
"\n",
|
| 310 |
+
"business_idea = response.choices[0].message.content\n",
|
| 311 |
+
"\n",
|
| 312 |
+
"# print(business_idea) \n",
|
| 313 |
+
"\n",
|
| 314 |
+
"# from IPython.display import Markdown, display\n",
|
| 315 |
+
"\n",
|
| 316 |
+
"display(Markdown(business_idea))\n",
|
| 317 |
+
"\n",
|
| 318 |
+
"# And repeat!"
|
| 319 |
+
]
|
| 320 |
+
},
|
| 321 |
+
{
|
| 322 |
+
"cell_type": "code",
|
| 323 |
+
"execution_count": null,
|
| 324 |
+
"metadata": {},
|
| 325 |
+
"outputs": [],
|
| 326 |
+
"source": [
|
| 327 |
+
"# Second exercice: Then ask the LLM to present a pain-point in that industry - something challenging that might be ripe for an Agentic solution.\n",
|
| 328 |
+
"\n",
|
| 329 |
+
"# First create the messages:\n",
|
| 330 |
+
"\n",
|
| 331 |
+
"prompt = f\"Please present a pain-point in that industry, something challenging that might be ripe for an Agentic solution for it in that industry: {business_idea}\"\n",
|
| 332 |
+
"messages = [{\"role\": \"user\", \"content\": prompt}]\n",
|
| 333 |
+
"\n",
|
| 334 |
+
"# Then make the first call:\n",
|
| 335 |
+
"\n",
|
| 336 |
+
"response = openai.chat.completions.create(\n",
|
| 337 |
+
" model=\"gpt-4o-mini\",\n",
|
| 338 |
+
" messages=messages\n",
|
| 339 |
+
")\n",
|
| 340 |
+
"\n",
|
| 341 |
+
"# Then read the business idea:\n",
|
| 342 |
+
"\n",
|
| 343 |
+
"painpoint = response.choices[0].message.content\n",
|
| 344 |
+
" \n",
|
| 345 |
+
"# print(painpoint) \n",
|
| 346 |
+
"display(Markdown(painpoint))\n",
|
| 347 |
+
"\n",
|
| 348 |
+
"# And repeat!"
|
| 349 |
+
]
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"cell_type": "code",
|
| 353 |
+
"execution_count": null,
|
| 354 |
+
"metadata": {},
|
| 355 |
+
"outputs": [],
|
| 356 |
+
"source": [
|
| 357 |
+
"# third exercice: Finally have 3 third LLM call propose the Agentic AI solution.\n",
|
| 358 |
+
"\n",
|
| 359 |
+
"# First create the messages:\n",
|
| 360 |
+
"\n",
|
| 361 |
+
"promptEx3 = f\"Please come up with a proposal for the Agentic AI solution to address this business painpoint: {painpoint}\"\n",
|
| 362 |
+
"messages = [{\"role\": \"user\", \"content\": promptEx3}]\n",
|
| 363 |
+
"\n",
|
| 364 |
+
"# Then make the first call:\n",
|
| 365 |
+
"\n",
|
| 366 |
+
"response = openai.chat.completions.create(\n",
|
| 367 |
+
" model=\"gpt-4o-mini\",\n",
|
| 368 |
+
" messages=messages\n",
|
| 369 |
+
")\n",
|
| 370 |
+
"\n",
|
| 371 |
+
"# Then read the business idea:\n",
|
| 372 |
+
"\n",
|
| 373 |
+
"ex3_answer=response.choices[0].message.content\n",
|
| 374 |
+
"# print(painpoint) \n",
|
| 375 |
+
"display(Markdown(ex3_answer))"
|
| 376 |
+
]
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"cell_type": "markdown",
|
| 380 |
+
"metadata": {},
|
| 381 |
+
"source": []
|
| 382 |
+
}
|
| 383 |
+
],
|
| 384 |
+
"metadata": {
|
| 385 |
+
"kernelspec": {
|
| 386 |
+
"display_name": ".venv",
|
| 387 |
+
"language": "python",
|
| 388 |
+
"name": "python3"
|
| 389 |
+
},
|
| 390 |
+
"language_info": {
|
| 391 |
+
"codemirror_mode": {
|
| 392 |
+
"name": "ipython",
|
| 393 |
+
"version": 3
|
| 394 |
+
},
|
| 395 |
+
"file_extension": ".py",
|
| 396 |
+
"mimetype": "text/x-python",
|
| 397 |
+
"name": "python",
|
| 398 |
+
"nbconvert_exporter": "python",
|
| 399 |
+
"pygments_lexer": "ipython3",
|
| 400 |
+
"version": "3.12.3"
|
| 401 |
+
}
|
| 402 |
+
},
|
| 403 |
+
"nbformat": 4,
|
| 404 |
+
"nbformat_minor": 2
|
| 405 |
+
}
|
community_contributions/travel_planner_multicall_and_sythesizer.ipynb
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": null,
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"outputs": [],
|
| 8 |
+
"source": [
|
| 9 |
+
"# Start with imports - ask ChatGPT to explain any package that you don't know\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"import os\n",
|
| 12 |
+
"import json\n",
|
| 13 |
+
"from dotenv import load_dotenv\n",
|
| 14 |
+
"from openai import OpenAI\n",
|
| 15 |
+
"from anthropic import Anthropic\n",
|
| 16 |
+
"from IPython.display import Markdown, display"
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "markdown",
|
| 21 |
+
"metadata": {},
|
| 22 |
+
"source": [
|
| 23 |
+
"<b>Load and check your API keys</b>\n",
|
| 24 |
+
"</br>\n",
|
| 25 |
+
"<b>- - - - - - - - - - - - - - - -</b>"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": null,
|
| 31 |
+
"metadata": {},
|
| 32 |
+
"outputs": [],
|
| 33 |
+
"source": [
|
| 34 |
+
"# Always remember to do this!\n",
|
| 35 |
+
"load_dotenv(override=True)\n",
|
| 36 |
+
"\n",
|
| 37 |
+
"# Function to check and display API key status\n",
|
| 38 |
+
"def check_api_key(key_name):\n",
|
| 39 |
+
" key = os.getenv(key_name)\n",
|
| 40 |
+
" \n",
|
| 41 |
+
" if key:\n",
|
| 42 |
+
" # Always show the first 7 characters of the key\n",
|
| 43 |
+
" print(f\"✓ {key_name} API Key exists and begins... ({key[:7]})\")\n",
|
| 44 |
+
" return True\n",
|
| 45 |
+
" else:\n",
|
| 46 |
+
" print(f\"⚠️ {key_name} API Key not set\")\n",
|
| 47 |
+
" return False\n",
|
| 48 |
+
"\n",
|
| 49 |
+
"# Check each API key (the function now returns True or False)\n",
|
| 50 |
+
"has_openai = check_api_key('OPENAI_API_KEY')\n",
|
| 51 |
+
"has_anthropic = check_api_key('ANTHROPIC_API_KEY')\n",
|
| 52 |
+
"has_google = check_api_key('GOOGLE_API_KEY')\n",
|
| 53 |
+
"has_deepseek = check_api_key('DEEPSEEK_API_KEY')\n",
|
| 54 |
+
"has_groq = check_api_key('GROQ_API_KEY')"
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"cell_type": "markdown",
|
| 59 |
+
"metadata": {
|
| 60 |
+
"vscode": {
|
| 61 |
+
"languageId": "html"
|
| 62 |
+
}
|
| 63 |
+
},
|
| 64 |
+
"source": [
|
| 65 |
+
"<b>Input for travel planner</b></br>\n",
|
| 66 |
+
"Describe yourself, your travel companions, and the destination you plan to visit.\n",
|
| 67 |
+
"</br>\n",
|
| 68 |
+
"<b>- - - - - - - - - - - - - - - -</b>"
|
| 69 |
+
]
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"cell_type": "code",
|
| 73 |
+
"execution_count": 4,
|
| 74 |
+
"metadata": {},
|
| 75 |
+
"outputs": [],
|
| 76 |
+
"source": [
|
| 77 |
+
"# Provide a description of you or your family. Age, interests, etc.\n",
|
| 78 |
+
"person_description = \"family with a 3 year-old\"\n",
|
| 79 |
+
"# Provide the name of the specific destination or attraction and country\n",
|
| 80 |
+
"destination = \"Belgium, Brussels\""
|
| 81 |
+
]
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"cell_type": "markdown",
|
| 85 |
+
"metadata": {},
|
| 86 |
+
"source": [
|
| 87 |
+
"<b>- - - - - - - - - - - - - - - -</b>"
|
| 88 |
+
]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"cell_type": "code",
|
| 92 |
+
"execution_count": 5,
|
| 93 |
+
"metadata": {},
|
| 94 |
+
"outputs": [],
|
| 95 |
+
"source": [
|
| 96 |
+
"prompt = f\"\"\"\n",
|
| 97 |
+
"Given the following description of a person or family:\n",
|
| 98 |
+
"{person_description}\n",
|
| 99 |
+
"\n",
|
| 100 |
+
"And the requested travel destination or attraction:\n",
|
| 101 |
+
"{destination}\n",
|
| 102 |
+
"\n",
|
| 103 |
+
"Provide a concise response including:\n",
|
| 104 |
+
"\n",
|
| 105 |
+
"1. Fit rating (1-10) specifically for this person or family.\n",
|
| 106 |
+
"2. One compelling positive reason why this destination suits them.\n",
|
| 107 |
+
"3. One notable drawback they should consider before visiting.\n",
|
| 108 |
+
"4. One important additional aspect to consider related to this location.\n",
|
| 109 |
+
"5. Suggest a few additional places that might also be of interest to them that are very close to the destination.\n",
|
| 110 |
+
"\"\"\""
|
| 111 |
+
]
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"cell_type": "code",
|
| 115 |
+
"execution_count": null,
|
| 116 |
+
"metadata": {},
|
| 117 |
+
"outputs": [],
|
| 118 |
+
"source": [
|
| 119 |
+
"def run_prompt_on_available_models(prompt):\n",
|
| 120 |
+
" \"\"\"\n",
|
| 121 |
+
" Run a prompt on all available AI models based on API keys.\n",
|
| 122 |
+
" Continues processing even if some models fail.\n",
|
| 123 |
+
" \"\"\"\n",
|
| 124 |
+
" results = {}\n",
|
| 125 |
+
" api_response = [{\"role\": \"user\", \"content\": prompt}]\n",
|
| 126 |
+
" \n",
|
| 127 |
+
" # OpenAI\n",
|
| 128 |
+
" if check_api_key('OPENAI_API_KEY'):\n",
|
| 129 |
+
" try:\n",
|
| 130 |
+
" model_name = \"gpt-4o-mini\"\n",
|
| 131 |
+
" openai_client = OpenAI()\n",
|
| 132 |
+
" response = openai_client.chat.completions.create(model=model_name, messages=api_response)\n",
|
| 133 |
+
" results[model_name] = response.choices[0].message.content\n",
|
| 134 |
+
" print(f\"✓ Got response from {model_name}\")\n",
|
| 135 |
+
" except Exception as e:\n",
|
| 136 |
+
" print(f\"⚠️ Error with {model_name}: {str(e)}\")\n",
|
| 137 |
+
" # Continue with other models\n",
|
| 138 |
+
" \n",
|
| 139 |
+
" # Anthropic\n",
|
| 140 |
+
" if check_api_key('ANTHROPIC_API_KEY'):\n",
|
| 141 |
+
" try:\n",
|
| 142 |
+
" model_name = \"claude-3-7-sonnet-latest\"\n",
|
| 143 |
+
" # Create new client each time\n",
|
| 144 |
+
" claude = Anthropic()\n",
|
| 145 |
+
" \n",
|
| 146 |
+
" # Use messages directly \n",
|
| 147 |
+
" response = claude.messages.create(\n",
|
| 148 |
+
" model=model_name,\n",
|
| 149 |
+
" messages=[{\"role\": \"user\", \"content\": prompt}],\n",
|
| 150 |
+
" max_tokens=1000\n",
|
| 151 |
+
" )\n",
|
| 152 |
+
" results[model_name] = response.content[0].text\n",
|
| 153 |
+
" print(f\"✓ Got response from {model_name}\")\n",
|
| 154 |
+
" except Exception as e:\n",
|
| 155 |
+
" print(f\"⚠️ Error with {model_name}: {str(e)}\")\n",
|
| 156 |
+
" # Continue with other models\n",
|
| 157 |
+
" \n",
|
| 158 |
+
" # Google\n",
|
| 159 |
+
" if check_api_key('GOOGLE_API_KEY'):\n",
|
| 160 |
+
" try:\n",
|
| 161 |
+
" model_name = \"gemini-2.0-flash\"\n",
|
| 162 |
+
" google_api_key = os.getenv('GOOGLE_API_KEY')\n",
|
| 163 |
+
" gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
|
| 164 |
+
" response = gemini.chat.completions.create(model=model_name, messages=api_response)\n",
|
| 165 |
+
" results[model_name] = response.choices[0].message.content\n",
|
| 166 |
+
" print(f\"✓ Got response from {model_name}\")\n",
|
| 167 |
+
" except Exception as e:\n",
|
| 168 |
+
" print(f\"⚠️ Error with {model_name}: {str(e)}\")\n",
|
| 169 |
+
" # Continue with other models\n",
|
| 170 |
+
" \n",
|
| 171 |
+
" # DeepSeek\n",
|
| 172 |
+
" if check_api_key('DEEPSEEK_API_KEY'):\n",
|
| 173 |
+
" try:\n",
|
| 174 |
+
" model_name = \"deepseek-chat\"\n",
|
| 175 |
+
" deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
|
| 176 |
+
" deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com/v1\")\n",
|
| 177 |
+
" response = deepseek.chat.completions.create(model=model_name, messages=api_response)\n",
|
| 178 |
+
" results[model_name] = response.choices[0].message.content\n",
|
| 179 |
+
" print(f\"✓ Got response from {model_name}\")\n",
|
| 180 |
+
" except Exception as e:\n",
|
| 181 |
+
" print(f\"⚠️ Error with {model_name}: {str(e)}\")\n",
|
| 182 |
+
" # Continue with other models\n",
|
| 183 |
+
" \n",
|
| 184 |
+
" # Groq\n",
|
| 185 |
+
" if check_api_key('GROQ_API_KEY'):\n",
|
| 186 |
+
" try:\n",
|
| 187 |
+
" model_name = \"llama-3.3-70b-versatile\"\n",
|
| 188 |
+
" groq_api_key = os.getenv('GROQ_API_KEY')\n",
|
| 189 |
+
" groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
|
| 190 |
+
" response = groq.chat.completions.create(model=model_name, messages=api_response)\n",
|
| 191 |
+
" results[model_name] = response.choices[0].message.content\n",
|
| 192 |
+
" print(f\"✓ Got response from {model_name}\")\n",
|
| 193 |
+
" except Exception as e:\n",
|
| 194 |
+
" print(f\"⚠️ Error with {model_name}: {str(e)}\")\n",
|
| 195 |
+
" # Continue with other models\n",
|
| 196 |
+
" \n",
|
| 197 |
+
" # Check if we got any responses\n",
|
| 198 |
+
" if not results:\n",
|
| 199 |
+
" print(\"⚠️ No models were able to provide a response\")\n",
|
| 200 |
+
" \n",
|
| 201 |
+
" return results\n",
|
| 202 |
+
"\n",
|
| 203 |
+
"# Get responses from all available models\n",
|
| 204 |
+
"model_responses = run_prompt_on_available_models(prompt)\n",
|
| 205 |
+
"\n",
|
| 206 |
+
"# Display the results\n",
|
| 207 |
+
"for model, answer in model_responses.items():\n",
|
| 208 |
+
" display(Markdown(f\"## Response from {model}\\n\\n{answer}\"))"
|
| 209 |
+
]
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"cell_type": "markdown",
|
| 213 |
+
"metadata": {},
|
| 214 |
+
"source": [
|
| 215 |
+
"<b>Sythesize answers from all models into one</b>\n",
|
| 216 |
+
"</br>\n",
|
| 217 |
+
"<b>- - - - - - - - - - - - - - - -</b>"
|
| 218 |
+
]
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"cell_type": "code",
|
| 222 |
+
"execution_count": null,
|
| 223 |
+
"metadata": {},
|
| 224 |
+
"outputs": [],
|
| 225 |
+
"source": [
|
| 226 |
+
"# Create a synthesis prompt\n",
|
| 227 |
+
"synthesis_prompt = f\"\"\"\n",
|
| 228 |
+
"Here are the responses from different models:\n",
|
| 229 |
+
"\"\"\"\n",
|
| 230 |
+
"\n",
|
| 231 |
+
"# Add each model's response to the synthesis prompt without mentioning model names\n",
|
| 232 |
+
"for index, (model, response) in enumerate(model_responses.items()):\n",
|
| 233 |
+
" synthesis_prompt += f\"\\n--- Response {index+1} ---\\n{response}\\n\"\n",
|
| 234 |
+
"\n",
|
| 235 |
+
"synthesis_prompt += \"\"\"\n",
|
| 236 |
+
"Please synthesize these responses into one comprehensive answer that:\n",
|
| 237 |
+
"1. Captures the best insights from each response\n",
|
| 238 |
+
"2. Resolves any contradictions between responses\n",
|
| 239 |
+
"3. Presents a clear and coherent final answer\n",
|
| 240 |
+
"4. Maintains the same format as the original responses (numbered list format)\n",
|
| 241 |
+
"5.Compiles all additional places mentioned by all models \n",
|
| 242 |
+
"\n",
|
| 243 |
+
"Your synthesized response:\n",
|
| 244 |
+
"\"\"\"\n",
|
| 245 |
+
"\n",
|
| 246 |
+
"# Create the synthesis\n",
|
| 247 |
+
"if check_api_key('OPENAI_API_KEY'):\n",
|
| 248 |
+
" try:\n",
|
| 249 |
+
" openai_client = OpenAI()\n",
|
| 250 |
+
" synthesis_response = openai_client.chat.completions.create(\n",
|
| 251 |
+
" model=\"gpt-4o-mini\",\n",
|
| 252 |
+
" messages=[{\"role\": \"user\", \"content\": synthesis_prompt}]\n",
|
| 253 |
+
" )\n",
|
| 254 |
+
" synthesized_answer = synthesis_response.choices[0].message.content\n",
|
| 255 |
+
" print(\"✓ Successfully synthesized responses with gpt-4o-mini\")\n",
|
| 256 |
+
" \n",
|
| 257 |
+
" # Display the synthesized answer\n",
|
| 258 |
+
" display(Markdown(\"## Synthesized Answer\\n\\n\" + synthesized_answer))\n",
|
| 259 |
+
" except Exception as e:\n",
|
| 260 |
+
" print(f\"⚠️ Error synthesizing responses with gpt-4o-mini: {str(e)}\")\n",
|
| 261 |
+
"else:\n",
|
| 262 |
+
" print(\"⚠️ OpenAI API key not available, cannot synthesize responses\")"
|
| 263 |
+
]
|
| 264 |
+
}
|
| 265 |
+
],
|
| 266 |
+
"metadata": {
|
| 267 |
+
"kernelspec": {
|
| 268 |
+
"display_name": ".venv",
|
| 269 |
+
"language": "python",
|
| 270 |
+
"name": "python3"
|
| 271 |
+
},
|
| 272 |
+
"language_info": {
|
| 273 |
+
"codemirror_mode": {
|
| 274 |
+
"name": "ipython",
|
| 275 |
+
"version": 3
|
| 276 |
+
},
|
| 277 |
+
"file_extension": ".py",
|
| 278 |
+
"mimetype": "text/x-python",
|
| 279 |
+
"name": "python",
|
| 280 |
+
"nbconvert_exporter": "python",
|
| 281 |
+
"pygments_lexer": "ipython3",
|
| 282 |
+
"version": "3.12.10"
|
| 283 |
+
}
|
| 284 |
+
},
|
| 285 |
+
"nbformat": 4,
|
| 286 |
+
"nbformat_minor": 2
|
| 287 |
+
}
|
me/linkedin.pdf
ADDED
|
Binary file (62.8 kB). View file
|
|
|
me/linkedin.pdf_old
ADDED
|
Binary file (69.7 kB). View file
|
|
|
me/summary.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Hi, I’m Luís Melo — a strategic CIO/CTO and senior IT advisor with over 20 years of driving digital transformation, IT modernisation, and AI-led innovation across complex, high-impact environments. I've led mission-critical initiatives for organisations with millions of customers, designed scalable cloud infrastructures, and guided board-level decisions to align technology with business growth. From system integration and M&A to cybersecurity, data architecture, and agile delivery—my mission is to empower smarter, faster, and more resilient enterprises.
|
| 2 |
+
Beyond the boardroom, I’m a proud father of three amazing boys, an amateur guitarist (only with tabs!), and a home cook who never strays from the recipe. I’m endlessly curious and believe that whether you're engineering a tech stack or perfecting a risotto, structure and creativity go hand-in-hand.
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
requests
|
| 2 |
+
python-dotenv
|
| 3 |
+
gradio
|
| 4 |
+
pypdf
|
| 5 |
+
openai
|
| 6 |
+
openai-agents
|