Week 1 Learnings (#1)

* Add day 1
* Add day 2
* Add day 4
* Add day 5
* Add week 1 exercise
This commit is contained in:
Stephen Muthama
2025-10-22 09:58:16 +03:00
committed by GitHub
parent ef34387aee
commit a9e9453e57
6 changed files with 1873 additions and 725 deletions

View File

@@ -104,7 +104,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
"metadata": {},
"outputs": [],
@@ -144,10 +144,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"id": "7b87cadb-d513-4303-baee-a37b6f938e4d",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"API key found and looks good so far!\n"
]
}
],
"source": [
"# Load environment variables in a file called .env\n",
"\n",
@@ -176,10 +184,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "a58394bf-1e45-46af-9bfd-01e24da6f49a",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"[{'role': 'user',\n",
" 'content': 'Hello, GPT! This is my first ever message to you! Hi!'}]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# To give you a preview -- calling OpenAI with these messages is this easy. Any problems, head over to the Troubleshooting notebook.\n",
"\n",
@@ -192,10 +212,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"id": "08330159",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Hi there! Welcome—and nice to meet you. Im glad you stopped by.\\n\\nWhat would you like to do today? Here are a few ideas:\\n- Ask me a question on any topic\\n- Get help with homework or a project\\n- Learn something new (science, history, tech, etc.)\\n- Write or edit text (emails, essays, stories)\\n- Brainstorm ideas or plan something (a trip, a gift, a plan)\\n- Get coding help or debugging tips\\n- Translate or summarize something\\n\\nIf you tell me a bit about yourself or what youre curious about, I can tailor things to you. What would you like to start with?'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"openai = OpenAI()\n",
"\n",
@@ -213,10 +244,66 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Home - Edward Donner\n",
"\n",
"Home\n",
"Connect Four\n",
"Outsmart\n",
"An arena that pits LLMs against each other in a battle of diplomacy and deviousness\n",
"About\n",
"Posts\n",
"Well, hi there.\n",
"Im Ed. I like writing code and experimenting with LLMs, and hopefully youre here because you do too. I also enjoy DJing (but Im badly out of practice), amateur electronic music production (\n",
"very\n",
"amateur) and losing myself in\n",
"Hacker News\n",
", nodding my head sagely to things I only half understand.\n",
"Im the co-founder and CTO of\n",
"Nebula.io\n",
". Were applying AI to a field where it can make a massive, positive impact: helping people discover their potential and pursue their reason for being. Recruiters use our product today to source, understand, engage and manage talent. Im previously the founder and CEO of AI startup untapt,\n",
"acquired in 2021\n",
".\n",
"We work with groundbreaking, proprietary LLMs verticalized for talent, weve\n",
"patented\n",
"our matching model, and our award-winning platform has happy customers and tons of press coverage.\n",
"Connect\n",
"with me for more!\n",
"September 15, 2025\n",
"AI in Production: Gen AI and Agentic AI on AWS at scale\n",
"May 28, 2025\n",
"Connecting my courses become an LLM expert and leader\n",
"May 18, 2025\n",
"2025 AI Executive Briefing\n",
"April 21, 2025\n",
"The Complete Agentic AI Engineering Course\n",
"Navigation\n",
"Home\n",
"Connect Four\n",
"Outsmart\n",
"An arena that pits LLMs against each other in a battle of diplomacy and deviousness\n",
"About\n",
"Posts\n",
"Get in touch\n",
"ed [at] edwarddonner [dot] com\n",
"www.edwarddonner.com\n",
"Follow me\n",
"LinkedIn\n",
"Twitter\n",
"Facebook\n",
"Subscribe to newsletter\n",
"Type your email…\n",
"Subscribe\n"
]
}
],
"source": [
"# Let's try out this utility\n",
"\n",
@@ -244,7 +331,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"id": "abdb8417-c5dc-44bc-9bee-2e059d162699",
"metadata": {},
"outputs": [],
@@ -260,7 +347,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c",
"metadata": {},
"outputs": [],
@@ -296,10 +383,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 12,
"id": "f25dcd35-0cd0-4235-9f64-ac37ed9eaaa5",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'2 + 2 equals 4.'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"messages = [\n",
" {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
@@ -320,7 +418,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 13,
"id": "0134dfa4-8299-48b5-b444-f2a8c3403c88",
"metadata": {},
"outputs": [],
@@ -336,10 +434,24 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 14,
"id": "36478464-39ee-485c-9f3f-6a4e458dbc9c",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"[{'role': 'system',\n",
" 'content': '\\nYou are a snarkyassistant that analyzes the contents of a website,\\nand provides a short, snarky, humorous summary, ignoring text that might be navigation related.\\nRespond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.\\n'},\n",
" {'role': 'user',\n",
" 'content': '\\nHere are the contents of a website.\\nProvide a short summary of this website.\\nIf it includes news or announcements, then summarize these too.\\n\\nHome - Edward Donner\\n\\nHome\\nConnect Four\\nOutsmart\\nAn arena that pits LLMs against each other in a battle of diplomacy and deviousness\\nAbout\\nPosts\\nWell, hi there.\\nIm Ed. I like writing code and experimenting with LLMs, and hopefully youre here because you do too. I also enjoy DJing (but Im badly out of practice), amateur electronic music production (\\nvery\\namateur) and losing myself in\\nHacker News\\n, nodding my head sagely to things I only half understand.\\nIm the co-founder and CTO of\\nNebula.io\\n. Were applying AI to a field where it can make a massive, positive impact: helping people discover their potential and pursue their reason for being. Recruiters use our product today to source, understand, engage and manage talent. Im previously the founder and CEO of AI startup untapt,\\nacquired in 2021\\n.\\nWe work with groundbreaking, proprietary LLMs verticalized for talent, weve\\npatented\\nour matching model, and our award-winning platform has happy customers and tons of press coverage.\\nConnect\\nwith me for more!\\nSeptember 15, 2025\\nAI in Production: Gen AI and Agentic AI on AWS at scale\\nMay 28, 2025\\nConnecting my courses become an LLM expert and leader\\nMay 18, 2025\\n2025 AI Executive Briefing\\nApril 21, 2025\\nThe Complete Agentic AI Engineering Course\\nNavigation\\nHome\\nConnect Four\\nOutsmart\\nAn arena that pits LLMs against each other in a battle of diplomacy and deviousness\\nAbout\\nPosts\\nGet in touch\\ned [at] edwarddonner [dot] com\\nwww.edwarddonner.com\\nFollow me\\nLinkedIn\\nTwitter\\nFacebook\\nSubscribe to newsletter\\nType your email…\\nSubscribe'}]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Try this out, and then try for a few more websites\n",
"\n",
@@ -356,7 +468,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 15,
"id": "905b9919-aba7-45b5-ae65-81b3d1d78e34",
"metadata": {},
"outputs": [],
@@ -374,17 +486,28 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 16,
"id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"\"# Edward Donner's Corner of the Internet\\n\\nWelcome to Ed's nerd den, where coding meets LLM wizardry and the occasional (badly dusted off) DJ beat. Ed is the CTO of Nebula.io, making AI actually useful by helping recruiters find talent without losing their minds. Hes also an ex-startup CEO whose company got snapped up in 2021, so naturally, he's full of patented AI magic and press clippings. \\n\\nHighlights include: \\n- Two AI battles arenas called *Connect Four* and *Outsmart* where language models duke it out in diplomatic skullduggery (because who doesn't want AI to be shady?). \\n- Educational AI content dropping like hotcakes in 2025, covering everything from getting AI running on AWS to full-on Agentic AI engineering courses.\\n- Eds modest brag: a patented matching model and an award-winning platform that somehow makes recruiters happy. \\n\\nWant to get in touch? Shoot an email or awkwardly follow him on LinkedIn, Twitter, or Facebook. Or maybe just subscribe to the newsletter for your daily dose of AI and snark.\""
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"summarize(\"https://edwarddonner.com\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 17,
"id": "3d926d59-450e-4609-92ba-2d6f244f1342",
"metadata": {},
"outputs": [],
@@ -398,10 +521,36 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 18,
"id": "3018853a-445f-41ff-9560-d925d1774b2f",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/markdown": [
"# Edward Donners Corner of the Internet\n",
"\n",
"Welcome to Ed's playground where code meets world domination—of the AI kind. Ed's into writing code, geeking out on Large Language Models (LLMs), and spinning (badly) some tunes as an amateur DJ/music producer. When not getting lost in Hacker News, he's busy revolutionizing recruiting as the CTO of Nebula.io, leveraging AI to help folks find their lifes purpose. Oh, and hes got a patented AI model, an acquired startup (because why not), and an award-winning platform with press buzz.\n",
"\n",
"If you like AI battles (LLMs duking it out in diplomacy and deception), check out *Connect Four* and *Outsmart* arenas. Stay tuned for his latest musings or courses to become an LLM overlord yourself.\n",
"\n",
"## Latest Announcements (Because Ed Actually Updates Stuff)\n",
"\n",
"- **Sep 15, 2025:** AI in Production with Gen AI and Agentic AI at AWS scale\n",
"- **May 28, 2025:** Connecting courses to become an LLM expert (sign me up!)\n",
"- **May 18, 2025:** 2025 AI Executive Briefing (serious business)\n",
"- **Apr 21, 2025:** The Complete Agentic AI Engineering Course (bring your A-game)\n",
"\n",
"Want to connect? Drop him a line or follow the trails of LinkedIn, Twitter, or Facebook breadcrumbs. Subscribe if you want AI wisdom delivered to your inbox."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://edwarddonner.com\")"
]
@@ -424,20 +573,54 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 19,
"id": "45d83403-a24c-44b5-84ac-961449b4008f",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/markdown": [
"Alright, heres the scoop: This website is CNN, the internets go-to for pretty much everything newsworthy from politics, world drama, and business intrigue, to viral entertainment and weather tantrums. It revels in ads (which it desperately wants your feedback on because apparently, they can be annoying), offers live TV and videos, and even throws in polls and calculators for those who like crunching numbers while digesting headlines. If youre looking for breaking news on conflicts like Ukraine-Russia or Israel-Hamas wars, or fancy a dip into lifestyle, style, or tech innovations, CNNs got your back. Basically, its a never-ending buffet of topical info served with a side of “Please tell us if our ads are driving you up the wall.”"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://cnn.com\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 20,
"id": "75e9fd40-b354-4341-991e-863ef2e59db7",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/markdown": [
"# Anthropic: AI with a Conscience\n",
"\n",
"Anthropic is the AI nerd who actually cares about the future of humanity — a “public benefit corporation” dedicated to making AI helpful *and* safe (because apparently, that's a thing now).\n",
"\n",
"Theyre flaunting their latest shiny toys: **Claude Sonnet 4.5** (best model for agents, coding, computer stuff) and **Claude Haiku 4.5** (because why not poetic AI?). The site is full of jargon about \"responsible scaling\" and \"trust centers,\" which basically means theyre trying not to unleash Skynet anytime soon.\n",
"\n",
"Newsflash: Theyve got announcements about these models, pushing forward with AI tech but with the brakes on to avoid the apocalypse. And yes, there's lots of encouragement to login, try their Claude models, download apps, and get lost in developer docs if youre that kind of person.\n",
"\n",
"In summary: Its AI innovation meets cautious parenting, with a sprinkle of poetic flair. Who says robots cant be responsible *and* artsy?"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://anthropic.com\")"
]
@@ -476,28 +659,51 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 21,
"id": "00743dac-0e70-45b7-879a-d7293a6f68a6",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Meeting Time Change to 3 PM Tomorrow\n"
]
}
],
"source": [
"# Step 1: Create your prompts\n",
"\n",
"system_prompt = \"something here\"\n",
"system_prompt = \"\"\"\n",
"You are embedded in an email tool that analyzes an emails body text and suggests a concise, relevant, and professional subject line.\n",
"The subject line should capture the core intent of the email in 510 words\n",
"Maintain clarity and tone alignment:\n",
"Formal/business emails → neutral and polished\n",
"Casual/internal updates → conversational and brief\n",
"Urgent matters → include urgency subtly (e.g., “Action Needed”, “Follow-Up Required”)\n",
"Avoid unnecessary punctuation, emojis, or filler words.\n",
"Do not include explanations unless explicitly requested.\n",
"\"\"\"\n",
"user_prompt = \"\"\"\n",
" Lots of text\n",
" Can be pasted here\n",
" Suggest a short subject line for the following email:\n",
" Hi team, please note that tomorrows meeting will be moved to 3 PM instead of 2 PM to accommodate the new client call.\n",
"\"\"\"\n",
"\n",
"# Step 2: Make the messages list\n",
"\n",
"messages = [] # fill this in\n",
"messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
"]\n",
"\n",
"# Step 3: Call OpenAI\n",
"# response =\n",
"response = openai.chat.completions.create(\n",
" model=\"gpt-4o-mini\",\n",
" messages=messages\n",
")\n",
"\n",
"# Step 4: print the result\n",
"# print("
"print(response.choices[0].message.content)"
]
},
{

View File

@@ -45,10 +45,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"id": "e38f17a0",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"API key found and looks good so far!\n"
]
}
],
"source": [
"import os\n",
"from dotenv import load_dotenv\n",
@@ -78,10 +86,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"id": "5af5c188",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"{'model': 'gpt-5-nano',\n",
" 'messages': [{'role': 'user', 'content': 'Tell me a fun fact'}]}"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import requests\n",
"\n",
@@ -98,10 +118,40 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "2d0ab242",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"{'id': 'chatcmpl-CTJDqe3UuLrqPiBwX0loYddfVDpWx',\n",
" 'object': 'chat.completion',\n",
" 'created': 1761101438,\n",
" 'model': 'gpt-5-nano-2025-08-07',\n",
" 'choices': [{'index': 0,\n",
" 'message': {'role': 'assistant',\n",
" 'content': 'Fun fact: Honey never spoils. Its low moisture and acidic pH create an environment that bacteria and fungi cant thrive in. In fact, archaeologists have found pots of honey in ancient Egyptian tombs that are over 3,000 years old and still edible. Want another fun fact?',\n",
" 'refusal': None,\n",
" 'annotations': []},\n",
" 'finish_reason': 'stop'}],\n",
" 'usage': {'prompt_tokens': 11,\n",
" 'completion_tokens': 709,\n",
" 'total_tokens': 720,\n",
" 'prompt_tokens_details': {'cached_tokens': 0, 'audio_tokens': 0},\n",
" 'completion_tokens_details': {'reasoning_tokens': 640,\n",
" 'audio_tokens': 0,\n",
" 'accepted_prediction_tokens': 0,\n",
" 'rejected_prediction_tokens': 0}},\n",
" 'service_tier': 'default',\n",
" 'system_fingerprint': None}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response = requests.post(\n",
" \"https://api.openai.com/v1/chat/completions\",\n",
@@ -114,10 +164,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"id": "cb11a9f6",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Fun fact: Honey never spoils. Its low moisture and acidic pH create an environment that bacteria and fungi cant thrive in. In fact, archaeologists have found pots of honey in ancient Egyptian tombs that are over 3,000 years old and still edible. Want another fun fact?'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response.json()[\"choices\"][0][\"message\"][\"content\"]"
]
@@ -140,14 +201,26 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "490fdf09",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Fun fact: Honey never spoils. Archaeologists have found pots of honey in ancient tombs that are still edible after thousands of years. Its low water content and acidic pH help keep bacteria away.'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Create OpenAI client\n",
"\n",
"from openai import OpenAI\n",
"\n",
"openai = OpenAI()\n",
"\n",
"response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
@@ -187,10 +260,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"id": "f74293bc",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\n"
]
}
],
"source": [
"GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
"\n",
@@ -201,8 +282,7 @@
"elif not google_api_key.startswith(\"AIz\"):\n",
" print(\"An API key was found, but it doesn't start AIz\")\n",
"else:\n",
" print(\"API key found and looks good so far!\")\n",
"\n"
" print(\"API key found and looks good so far!\")\n"
]
},
{
@@ -221,11 +301,30 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"id": "a5b069be",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"data": {
"text/plain": [
"\"Here's one:\\n\\nDid you know that honey never spoils? Archaeologists have found pots of honey in ancient Egyptian tombs that are over 3,000 years old and still perfectly edible! Honey's longevity is due to its unique composition, which includes acid that creates an environment inhospitable to bacteria and microorganisms. Isn't that sweet?\""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
"\n",
"ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key='ollama')\n",
"\n",
"response = ollama.chat.completions.create(model=\"llama3.2\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
"\n",
"response.choices[0].message.content"
]
},
{
"cell_type": "markdown",
@@ -241,10 +340,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"id": "f06280ad",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"b'Ollama is running'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"requests.get(\"http://localhost:11434\").content"
]
@@ -263,17 +373,34 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"id": "e633481d",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠋ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠙ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠹ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠸ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠼ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠴ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠦ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest ⠧ \u001b[K\u001b[?25h\u001b[?2026l\u001b[?2026h\u001b[?25l\u001b[1Gpulling manifest \u001b[K\n",
"pulling dde5aa3fc5ff: 100% ▕██████████████████▏ 2.0 GB \u001b[K\n",
"pulling 966de95ca8a6: 100% ▕██████████████████▏ 1.4 KB \u001b[K\n",
"pulling fcc5a6bec9da: 100% ▕██████████████████▏ 7.7 KB \u001b[K\n",
"pulling a70ff7e570d9: 100% ▕██████████████████▏ 6.0 KB \u001b[K\n",
"pulling 56bb8bd477a5: 100% ▕██████████████████▏ 96 B \u001b[K\n",
"pulling 34bb5ab01051: 100% ▕██████████████████▏ 561 B \u001b[K\n",
"verifying sha256 digest \u001b[K\n",
"writing manifest \u001b[K\n",
"success \u001b[K\u001b[?25h\u001b[?2026l\n"
]
}
],
"source": [
"!ollama pull llama3.2"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"id": "d9419762",
"metadata": {},
"outputs": [],
@@ -285,10 +412,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"id": "e2456cdf",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"\"Here's one:\\n\\nDid you know that honey never spoils? Archaeologists have found pots of honey in ancient Egyptian tombs that are over 3,000 years old and still perfectly edible! This is because bees produce antibiotics as part of their hive-building efforts, which helps to preserve the honey. Also, honey doesn't contain water like other foods do, which makes it extremely difficult for bacteria or microorganisms to grow. So, even if you leave a jar of honey out at room temperature for centuries (not recommended, by the way!), it should still be safe to eat!\""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Get a fun fact\n",
"\n",
@@ -358,11 +496,56 @@
},
{
"cell_type": "code",
"execution_count": null,
"id": "6de38216-6d1c-48c4-877b-86d403f4e0f8",
"execution_count": 12,
"id": "fa5edd63",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Here's a suggested concise and professional subject line:\n",
"\n",
"\"Meeting Rescheduled to 3 PM Tomorrow\"\n",
"\n",
"This subject line captures the core intent of the email, which is a meeting rescheduling, in just a few words while maintaining clarity and tone alignment.\n"
]
}
],
"source": [
"# Step 1: Create your prompts\n",
"\n",
"system_prompt = \"\"\"\n",
"You are embedded in an email tool that analyzes an emails body text and suggests a concise, relevant, and professional subject line.\n",
"The subject line should capture the core intent of the email in 510 words\n",
"Maintain clarity and tone alignment:\n",
"Formal/business emails → neutral and polished\n",
"Casual/internal updates → conversational and brief\n",
"Urgent matters → include urgency subtly (e.g., “Action Needed”, “Follow-Up Required”)\n",
"Avoid unnecessary punctuation, emojis, or filler words.\n",
"Do not include explanations unless explicitly requested.\n",
"\"\"\"\n",
"user_prompt = \"\"\"\n",
" Suggest a short subject line for the following email:\n",
" Hi team, please note that tomorrows meeting will be moved to 3 PM instead of 2 PM to accommodate the new client call.\n",
"\"\"\"\n",
"\n",
"# Step 2: Make the messages list\n",
"\n",
"messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
"]\n",
"\n",
"# Step 3: Call OpenAI\n",
"response = ollama.chat.completions.create(\n",
" model=\"llama3.2\",\n",
" messages=messages\n",
")\n",
"\n",
"# Step 4: print the result\n",
"print(response.choices[0].message.content)"
]
}
],
"metadata": {
@@ -381,7 +564,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.12.12"
}
},
"nbformat": 4,

View File

@@ -12,7 +12,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 2,
"id": "7dc1c1d9",
"metadata": {},
"outputs": [],
@@ -21,22 +21,22 @@
"\n",
"encoding = tiktoken.encoding_for_model(\"gpt-4.1-mini\")\n",
"\n",
"tokens = encoding.encode(\"Hi my name is Ed and I like banoffee pie\")"
"tokens = encoding.encode(\"Hi my name is Stephen\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 3,
"id": "7632966c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[12194, 922, 1308, 382, 6117, 326, 357, 1299, 9171, 26458, 5148]"
"[12194, 922, 1308, 382, 34231]"
]
},
"execution_count": 6,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
@@ -47,7 +47,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 4,
"id": "cce0c188",
"metadata": {},
"outputs": [
@@ -59,13 +59,7 @@
"922 = my\n",
"1308 = name\n",
"382 = is\n",
"6117 = Ed\n",
"326 = and\n",
"357 = I\n",
"1299 = like\n",
"9171 = ban\n",
"26458 = offee\n",
"5148 = pie\n"
"34231 = Stephen\n"
]
}
],
@@ -77,7 +71,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 5,
"id": "98e3bbd2",
"metadata": {},
"outputs": [
@@ -87,7 +81,7 @@
"' and'"
]
},
"execution_count": 8,
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -110,10 +104,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"id": "83a4b3eb",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"API key found and looks good so far!\n"
]
}
],
"source": [
"import os\n",
"from dotenv import load_dotenv\n",
@@ -141,7 +143,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"id": "b959be3b",
"metadata": {},
"outputs": [],
@@ -161,23 +163,34 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"id": "97298fea",
"metadata": {},
"outputs": [],
"source": [
"messages = [\n",
" {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
" {\"role\": \"user\", \"content\": \"Hi! I'm Ed!\"}\n",
" {\"role\": \"user\", \"content\": \"Hi! I'm Stephen!\"}\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"id": "3475a36d",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Hello, Stephen! How can I assist you today?'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
"response.choices[0].message.content"
@@ -193,7 +206,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 12,
"id": "6bce2208",
"metadata": {},
"outputs": [],
@@ -206,10 +219,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 13,
"id": "404462f5",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Im sorry, but I dont know your name. Could you please tell me?'"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
"response.choices[0].message.content"
@@ -231,25 +255,36 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 14,
"id": "b6d43f92",
"metadata": {},
"outputs": [],
"source": [
"messages = [\n",
" {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
" {\"role\": \"user\", \"content\": \"Hi! I'm Ed!\"},\n",
" {\"role\": \"assistant\", \"content\": \"Hi Ed! How can I assist you today?\"},\n",
" {\"role\": \"user\", \"content\": \"Hi! I'm Stephen!\"},\n",
" {\"role\": \"assistant\", \"content\": \"Hi Stephen! How can I assist you today?\"},\n",
" {\"role\": \"user\", \"content\": \"What's my name?\"}\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 15,
"id": "e7ac742c",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Your name is Stephen. How can I help you today, Stephen?'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
"response.choices[0].message.content"
@@ -295,7 +330,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.12.12"
}
},
"nbformat": 4,

File diff suppressed because one or more lines are too long

324
week1/week1_exercise.ipynb Normal file
View File

@@ -0,0 +1,324 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5",
"metadata": {},
"source": [
"# End of week 1 exercise\n",
"\n",
"To demonstrate your familiarity with OpenAI API, and also Ollama, build a tool that takes a technical question, \n",
"and responds with an explanation. This is a tool that you will be able to use yourself during the course!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1070317-3ed9-4659-abe3-828943230e03",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Setup Successful!\n"
]
}
],
"source": [
"# Imports and Setup\n",
"import os\n",
"import json\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"from IPython.display import Markdown, display, update_display\n",
"import ollama\n",
"\n",
"# Load environment variables\n",
"load_dotenv(override=True)\n",
"\n",
"# Constants\n",
"MODEL_GPT = 'gpt-4o-mini'\n",
"MODEL_LLAMA = 'llama3.2'\n",
"\n",
"print(\"Setup Successful!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4a456906-915a-4bfd-bb9d-57e505c5093f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Question to analyze:\n",
"\n",
"Please explain what this code does and why:\n",
"yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"\n"
]
}
],
"source": [
"# Technical Question - You can modify this\n",
"question = \"\"\"\n",
"Please explain what this code does and why:\n",
"yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"\"\"\"\n",
"\n",
"print(\"Question to analyze:\")\n",
"print(question)\n",
"\n",
"# prompts\n",
"system_prompt = \"You are a helpful technical tutor who answers questions about python code, software engineering, data science and LLMs\"\n",
"user_prompt = \"Please give a detailed explanation to the following question: \" + question\n",
"\n",
"# messages\n",
"messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60ce7000-a4a5-4cce-a261-e75ef45063b4",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"## GPT-4o-mini Response:\n",
"Certainly! Let's break down the provided code snippet step by step.\n",
"\n",
"### Code Analysis\n",
"```python\n",
"yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"```\n",
"\n",
"This code snippet is a generator expression, which is intended to yield values from a set comprehension. Let's clarify each part of the expression:\n",
"\n",
"1. **Set Comprehension**:\n",
" - `{book.get(\"author\") for book in books if book.get(\"author\")}` is a set comprehension.\n",
" - This means it creates a set of unique authors from a collection called `books`.\n",
"\n",
"2. **`books`**:\n",
" - `books` is expected to be an iterable (like a list) that contains dictionaries. Each dictionary represents a book and may contain various keys, such as \"author\".\n",
"\n",
"3. **`book.get(\"author\")`**:\n",
" - For each `book` in the `books` iterable, `book.get(\"author\")` tries to access the value associated with the key `\"author\"`.\n",
" - The `.get()` method returns the value for the given key if it exists; otherwise, it returns `None`.\n",
"\n",
"4. **Filter Condition**: \n",
" - The expression includes an `if book.get(\"author\")` filter, which ensures that only books with a defined author (i.e., `None` or an empty string are excluded) are considered.\n",
" - This means that if the author is not provided, that book will not contribute to the final set.\n",
"\n",
"5. **Set Creation**:\n",
" - The result of the set comprehension is a set of unique author names from the list of books. Since sets automatically ensure uniqueness, duplicates will be filtered out.\n",
"\n",
"6. **`yield from`**:\n",
" - The `yield from` statement is used within a generator function. It allows the generator to yield all values from the given iterable (in this case, our created set).\n",
" - This means that the values generated (i.e., unique authors) can be iterated over one by one.\n",
"\n",
"### Purpose and Use Case\n",
"The purpose of this code snippet is to produce a generator that emits the unique author names of books from the `books` collection. This is useful in scenarios where you want to streamline the retrieval of distinct authors without immediately materializing them into a list. You can consume these unique authors one at a time efficiently, which is particularly beneficial when dealing with a large dataset.\n",
"\n",
"### Example\n",
"Consider the following example to illustrate how this might work:\n",
"\n",
"```python\n",
"books = [\n",
" {\"title\": \"Book1\", \"author\": \"AuthorA\"},\n",
" {\"title\": \"Book2\", \"author\": \"AuthorB\"},\n",
" {\"title\": \"Book3\", \"author\": \"AuthorA\"}, # Duplicate author\n",
" {\"title\": \"Book4\"}, # No author\n",
" {\"title\": \"Book5\", \"author\": \"AuthorC\"}\n",
"]\n",
"\n",
"# Let's say this code is inside a generator function\n",
"def unique_authors(books):\n",
" yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"\n",
"for author in unique_authors(books):\n",
" print(author)\n",
"```\n",
"### Output\n",
"```\n",
"AuthorA\n",
"AuthorB\n",
"AuthorC\n",
"```\n",
"\n",
"### Summary\n",
"This code snippet creates a generator that yields unique authors of books, omitting any entries where the author is not provided. This demonstrates an efficient and Pythonic way to handle data extraction, particularly with potentially sparse datasets."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Get gpt-4o-mini to answer, with streaming\n",
"api_key = os.getenv('OPENAI_API_KEY')\n",
"\n",
"# Initialize OpenAI client\n",
"openai = OpenAI()\n",
"\n",
"stream = openai.chat.completions.create(model=MODEL_GPT, messages=messages,stream=True)\n",
" \n",
"response = \"\"\n",
"\n",
"display_handle = display(Markdown(\"\"), display_id=True)\n",
"\n",
"for chunk in stream:\n",
" if chunk.choices[0].delta.content:\n",
" response += chunk.choices[0].delta.content\n",
" update_display(Markdown(f\"## GPT-4o-mini Response:\\n{response}\"), display_id=display_handle.display_id)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The given Python expression appears as part of an asynchronous generator, typically used with coroutines like those found within the `async`/`await` syntax introduced in Python 3.5+:\n",
"\n",
"```python\n",
"yield from {book.get('author') for book in books if book.get('author')}\n",
"```\n",
"\n",
"Here's a breakdown of what this code does, line by line and overall explanation:\n",
"\n",
"1. `{book.get('author') for book in books if book.get('author')}` is a set comprehension that iterates through each `book` object (assumed to be dictionary-like since it uses square brackets notation) within the `books` variable, which should also contain such objects as its elements based on context provided herein:\n",
" - For every iteration of this generator expression, if `'author'` exists in a book's key set (`book.keys()`), then that value (presumably the name of an author associated with their corresponding `book`) is included within the resulting comprehension/set; otherwise it skips to the next item since there isn't one without `'author'`.\n",
" - The `.get` method returns a specified keys value from dictionary-like objects, but if that key doesn't exist, instead of causing an error (as would be typical with direct indexing), this expression safely retrieves `None`, or another default return type you specify as the second argument to `.get()` which isn't shown here.\n",
" - Set comprehension is a construct for creating sets directly from iterables using set-building syntax (`{}`). Note that it inherently discards duplicates (if any), but this does not seem relevant since we are assuming books will uniquely have author information in the context of its key presence or absence, rather than repetitive entries.\n",
" \n",
"2. `yield from` is a statement used with asynchronous generators (`async def`) that handles yielding values and delegating further execution within nested coroutines: \n",
" - Its function here seems to be sending each author's name (extracted by the generator expression before) back into this outercoroutine. The `yield from` statement thus passes control over these names directly as output of its own operation, rather than managing an internal sequence or iterable in a traditional manner with for-loops and appending to lists inside coroutines (which may result in blocking behavior).\n",
" - In this expression's specific case without `async`/`await`, it looks like the code intends to simulate asynchronous yielding by passing values from an internal generator back out. However, proper usage would require surrounding with async function decorators and using await as needed for actual I/O-bound or network operations within a coroutine workflow context; this snippet in isolation does not directly demonstrate that behavior but instead presents a pattern resembling how yielding could be structured should it be part of an asynchronous generator expression.\n",
" - It's worth mentioning, though `yield from` isn't typically used with set comprehensions or non-coroutine functions as these expressions cannot 'receive values.' Instead, this construct suggests a conceptual approach where each found author is yielded one by one in what would be the sequence of execution within an asynchronous coroutine.\n",
" - Given that `yield from` isn't directly compatible with set comprehensions (without modification and appropriate context), it seems we might have encountered syntactical confusion or a misplacement here, since normally you wouldnt see this in standalone Python code outside the scope of coroutine functions.\n",
" \n",
"Assuming that `books` is an iterable over dictionary-like objects (which may contain author information), and if one were to translate typical synchronous usage into asynchronous semantics or consider using a generator, then we'd instead see something like this for proper async operation:\n",
"\n",
"```python\n",
"async def find_authors():\n",
" authors = set()\n",
" async for book in books: # Assuming `books` can be an iterable of awaitables (e.g., coroutines) or other asynchronous generators\n",
" author = book.get('author')\n",
" if author is not None:\n",
" await asyncio.sleep(0) # Yield control back to the event loop, simulate async I/O operation here with `await`ing a sleep call for example purposes only (in reality this would typically handle some real asynchronous task like fetching data from an external API). Then we'd yield using 'yield':\n",
" await asyncio0.sleep(2) # This line is placeholder logic and wouldn't execute without async decorators, but it serves to illustrate the use of `await` alongside a coroutine function:\n",
" authors.add(author)\n",
" return authors\n",
"```\n",
"In this modified version suitable for an asynchronous context (and with necessary adjustments): \n",
"- This would be inside an `@async def find_authors()` decorated async generator/coroutine, and the `yield` keyword is used to temporarily pause execution until another coroutine or future calls its `.send(None)` method. The example uses a placeholder sleep call (`await asyncio.sleep(2)`) for demonstration purposes only; in practice one might use non-blocking I/O operations such as reading from files, network responses etc., within an async function decorated with `@async def`.\n",
" \n",
"It is crucial to note that the original expression provided seems like a pseudocode representation of how we could structure asynchronous behavior using `yield` and comprehensions if it were actually part of coroutine code in Python 3.5+, but isn't syntactically correct or conventionally used outside such contexts due to misunderstandings about yielding semantics from set operations without await statements (or decorators)."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Get Llama 3.2 to answer\n",
"response = ollama.chat(model=MODEL_LLAMA, messages=messages)\n",
"\n",
"reply = response['message']['content']\n",
"\n",
"display(Markdown(reply))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1f8aa0a",
"metadata": {},
"outputs": [],
"source": [
"# Week 1 Learnings Summary\n",
"\n",
"summary = \"\"\"\n",
"## Week 1 Learnings Demonstrated\n",
"\n",
"### ✅ Day 1 - Web Scraping & API Integration\n",
"- **BeautifulSoup** for HTML parsing\n",
"- **Requests** for HTTP calls\n",
"- **OpenAI API** integration\n",
"- **SSL certificate** handling for Windows\n",
"\n",
"### ✅ Day 2 - Chat Completions API & Ollama\n",
"- **Chat Completions API** understanding\n",
"- **OpenAI-compatible endpoints** (Ollama)\n",
"- **Model comparison** techniques\n",
"- **Streaming responses** implementation\n",
"\n",
"### ✅ Day 4 - Tokenization & Cost Management\n",
"- **tiktoken** for token counting\n",
"- **Cost estimation** strategies\n",
"- **Text chunking** techniques\n",
"- **Token-aware** processing\n",
"\n",
"### ✅ Day 5 - Business Solutions\n",
"- **Intelligent link selection** using LLM\n",
"- **Multi-page content** aggregation\n",
"- **Professional brochure** generation\n",
"- **Error handling** and robustness\n",
"\n",
"### ✅ Week 1 Exercise - Technical Question Answerer\n",
"- **Streaming responses** from OpenAI\n",
"- **Local inference** with Ollama\n",
"- **Side-by-side comparison** of models\n",
"- **Error handling** for both APIs\n",
"\n",
"## Key Skills Acquired:\n",
"1. **API Integration** - OpenAI, Ollama, web scraping\n",
"2. **Model Comparison** - Understanding different LLM capabilities\n",
"3. **Streaming** - Real-time response display\n",
"4. **Error Handling** - Robust application design\n",
"5. **Business Applications** - Practical LLM implementations\n",
"\"\"\"\n",
"\n",
"display(Markdown(summary))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}