{ "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": 22, "id": "c1070317-3ed9-4659-abe3-828943230e03", "metadata": {}, "outputs": [], "source": [ "# imports\n", "import os\n", "import json\n", "from dotenv import load_dotenv\n", "from IPython.display import Markdown, display, update_display\n", "from openai import OpenAI\n", "import ollama" ] }, { "cell_type": "code", "execution_count": 2, "id": "4a456906-915a-4bfd-bb9d-57e505c5093f", "metadata": {}, "outputs": [], "source": [ "# constants\n", "\n", "MODEL_GPT = 'gpt-4o-mini'\n", "MODEL_LLAMA = 'llama3.2'" ] }, { "cell_type": "code", "execution_count": 10, "id": "93e65a84", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "API key looks good so far\n" ] } ], "source": [ "# set up environment\n", "\n", "load_dotenv(override=True)\n", "api_key = os.getenv('OPENAI_API_KEY')\n", "\n", "if api_key and api_key.startswith('sk-proj-') and len(api_key)>10:\n", " print(\"API key looks good so far\")\n", "else:\n", " print(\"There might be a problem with your API key? Please visit the troubleshooting notebook!\")\n", " \n", "openai = OpenAI()" ] }, { "cell_type": "code", "execution_count": 19, "id": "3f0d0137-52b0-47a8-81a8-11a90a010798", "metadata": {}, "outputs": [], "source": [ "# system prompt\n", "\n", "system_prompt = \"\"\"\n", "You are an assistant that answers questions concisely with technical details. The answer should be as descriptive as possible,\n", "using language that can be understood by a 5 year old.\n", "\"\"\"\n", "\n", "# here is the question; type over this to ask something new\n", "\n", "user_prompt = \"\"\"\n", "Please explain what this code does and why:\n", "yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 18, "id": "60ce7000-a4a5-4cce-a261-e75ef45063b4", "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "Alright! Imagine you have a magical treasure chest (that’s your code!) filled with sparkly books, and each book has a tag telling you who wrote it—the author! Now, let’s break down what’s happening:\n", "\n", "1. **Books Galore**: Think of `books` as a big shelf where all your storybooks are sitting in a neat line. Some books say who the author is, and some books are a bit shy and just sit there without telling you.\n", "\n", "2. **Searching for Authors**: The part `book.get(\"author\")` is like asking each book, \"Hey, who wrote you?\" If the book says \"Me! I'm written by Captain Awesome!\" then yay! You found an author! If the book goes “Umm... I forgot!”, you just move on to the next one.\n", "\n", "3. **Creating a List**: The fancy `{ ... for book in books if book.get(\"author\")}` part means you're gathering all the names of authors from the books that told you who they are. It's like putting a name sticker on all the books that have an author! \n", "\n", "4. **Sparkling Unique Names**: The curly braces `{}` mean you’re creating something special—a *set*! This is like a group of friends where nobody can have the same name, so if two books are written by Captain Awesome, he only gets one sticker!\n", "\n", "5. **The Magic of Yielding**: Finally, the `yield from` part is like saying, \"Okay, magic treasure chest, please start handing me those names one by one!\" It allows you to take each author’s name out, one at a time, as if you’re pulling out candy from a piñata—sweet and delightful!\n", "\n", "So, to sum it up with a giggle: This code is like a magical helper that goes through your book shelf, gathers all the brave authors who shouted their names, puts them in a special list without repeats, and then hands them out to you one by one like a candy parade! 🍭✨" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Get gpt-4o-mini to answer, with streaming\n", "\n", "def get_answer(question):\n", " stream = openai.chat.completions.create(\n", " model=MODEL_GPT,\n", " messages=[\n", " {\"role\": \"system\", \"content\": system_prompt},\n", " {\"role\": \"user\", \"content\": question}\n", " ],\n", " stream=True\n", " )\n", " \n", " response = \"\"\n", " display_handle = display(Markdown(\"\"), display_id=True)\n", " for chunk in stream:\n", " response += chunk.choices[0].delta.content or ''\n", " response = response.replace(\"```\",\"\").replace(\"markdown\", \"\")\n", " update_display(Markdown(response), display_id=display_handle.display_id)\n", "\n", "get_answer(user_prompt)" ] }, { "cell_type": "code", "execution_count": 24, "id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This line of code is doing something really cool with a bunch of books!\n", "\n", "Let's break it down:\n", "\n", "- `books` is like a big box full of books.\n", "- Each book is like a small container that has some information inside, like the author's name.\n", "\n", "Here's what this line does:\n", "\n", "1. It takes all the books in the box (`for book in books`).\n", "2. For each book, it checks if the book has an \"author\" inside (like a small treasure chest with a key: `\"author\"`).\n", "3. If a book does have an author (like finding a treasure), it gets the author's name from that book.\n", "4. It then makes the author's name available to someone else who is waiting for more information, like a helper.\n", "\n", "The magic part is `yield from`. Imagine you're on a treasure hunt with your friend. You find a clue and say \"Look! This is a map!\" Then, your friend can look at the map and see where the next clue is. That's kind of what `yield from` does: it says \"Hey, I found this information, here's more info about where to go next\"!\n", "\n", "In code terms, when you run this line, it will make each author's name available one by one, like a treasure chest with clues. \n", "\n", "Here is an example using python classes:\n", "\n", "```python\n", "class Book:\n", " def __init__(self, title, author):\n", " self.title = title\n", " self.author = author\n", "\n", "books = [\n", " Book(\"Harry Potter\", \"J.K. Rowling\"),\n", " Book(\"The Lion King\", \"Alexander Dumas\"),\n", "]\n", "\n", "def find_authors(books):\n", " for book in books:\n", " if 'author' in book.__dict__:\n", " yield from (book.author,)\n", "\n", "# Test the function\n", "for author in find_authors(books):\n", " print(author)\n", "```" ] } ], "source": [ "# Get Llama 3.2 to answer\n", "\n", "# Using ollama python package\n", "\n", "def get_answer(question):\n", " ollama_response = ollama.chat(\n", " model=MODEL_LLAMA,\n", " messages=[\n", " {\"role\": \"system\", \"content\": system_prompt},\n", " {\"role\": \"user\", \"content\": question}\n", " ],\n", " stream=True\n", " )\n", " \n", " # Printing out each piece of the generated response while preserving order\n", " for chunk in ollama_response:\n", " print(chunk['message']['content'], end='', flush=True)\n", "\n", "\n", "get_answer(user_prompt)\n" ] } ], "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.11.11" } }, "nbformat": 4, "nbformat_minor": 5 }