From 3a090bc0ef28154f6754c45188a790a4c8f44437 Mon Sep 17 00:00:00 2001 From: Dimitris Sinanis Date: Mon, 24 Feb 2025 14:13:22 +0200 Subject: [PATCH] Add week 1 exercise notebook for OpenAI API and Ollama integration, the AI Technician. --- .../week1 EXERCISE_AI_techician.ipynb | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 week1/community-contributions/week1 EXERCISE_AI_techician.ipynb diff --git a/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb b/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb new file mode 100644 index 0000000..7824df8 --- /dev/null +++ b/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb @@ -0,0 +1,202 @@ +{ + "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": 9, + "id": "c1070317-3ed9-4659-abe3-828943230e03", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "from IPython.display import Markdown, display, update_display\n", + "import openai\n", + "from openai import OpenAI\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "4a456906-915a-4bfd-bb9d-57e505c5093f", + "metadata": {}, + "outputs": [], + "source": [ + "# constants\n", + "models = {\n", + " 'MODEL_GPT': 'gpt-4o-mini',\n", + " 'MODEL_LLAMA': 'llama3.2'\n", + "}\n", + "\n", + "# To use ollama using openai API (ensure that ollama is running on localhost)\n", + "ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n", + "\n", + "def model_choices(model):\n", + " if model in models:\n", + " return models[model]\n", + " else:\n", + " raise ValueError(f\"Model {model} not found in models dictionary\")\n", + "\n", + "def get_model_api(model='MODEL_GPT'):\n", + " if model == 'MODEL_GPT':\n", + " return openai, model_choices(model)\n", + " elif model == 'MODEL_LLAMA':\n", + " return ollama_via_openai, model_choices(model)\n", + " else:\n", + " raise ValueError(f\"Model {model} not found in models dictionary\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a8d7923c-5f28-4c30-8556-342d7c8497c1", + "metadata": {}, + "outputs": [], + "source": [ + "# set up environment\n", + "\n", + "system_prompt = \"\"\" You are an AI assistant helping a user find information about a product. \n", + "The user asks you a technical question about code, and you provide a response with code snippets and explanations.\"\"\"\n", + "\n", + "def stream_brochure(question, model):\n", + " api, model_name = get_model_api(model)\n", + " stream = api.chat.completions.create(\n", + " model=model_name,\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" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3f0d0137-52b0-47a8-81a8-11a90a010798", + "metadata": {}, + "outputs": [], + "source": [ + "# Here is the question; type over this to ask something new\n", + "\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", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60ce7000-a4a5-4cce-a261-e75ef45063b4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "**Understanding the Code Snippet**\n", + "\n", + "This Python code snippet uses a combination of built-in functions, dictionary iteration, and generator expressions to extract and yield author names from a list of `Book` objects.\n", + "\n", + "Here's a breakdown:\n", + "\n", + "1. **Dictionary Iteration**: The expression `for book in books if book.get(\"author\")`\n", + " - Iterates over each element (`book`) in the container `books`.\n", + " - Filters out elements whose `'author'` key does not have a value (i.e., `None`, `False`, or an empty string). This leaves only dictionaries with author information.\n", + "\n", + "2. **Dictionary Access**: The expression `{book.get(\"author\") for book in books if book.get(\"author\")}`\n", + " - Uses dictionary membership testing to access only the values associated with the `'author'` key.\n", + " - If the value is not found or is considered false, it's skipped in this particular case.\n", + "\n", + "3. **Generator Expression**: This generates an iterator that iterates over the filtered author names.\n", + " - Yields each author name (i.e., a single `'name'` from the book dictionary) on demand.\n", + " - Since these are generator expressions, they use memory less than equivalent Python lists and also create results on-demand.\n", + "\n", + "4. **`yield from`**: This statement takes the generator expression as an argument and uses it to generate a nested iterator structure.\n", + " - It essentially \"decompresses\" the single level of nested iterator created by `list(iter(x))`, allowing for simpler use cases and potentially significant efficiency improvements for more complex structures where every value must be iterated, while in the latter case just the first item per iterable in the outer expression's sequence needs to actually be yielded into result stream.\n", + " - By \"yielding\" a nested iterator (the generator expression), we can simplify code by avoiding repetitive structure like `for book, book_author in zip(iterating over), ...` or list creation.\n", + "\n", + "**Example Use Case**\n", + "\n", + "In this hypothetical example:\n", + "\n", + "# Example Book objects\n", + "class Book:\n", + " def __init__(self, author, title):\n", + " self.author = author # str\n", + " self.title = title\n", + "\n", + "books = [\n", + " {\"author\": \"John Doe\", \"title\": f\"Book 1 by John Doe\"},\n", + " {\"author\": None, \"title\": f\"Book 2 without Author\"},\n", + " {\"author\": \"Jane Smith\", \"title\": f\"Book 3 by Jane Smith\"}\n", + "]\n", + "\n", + "# The given expression to extract and yield author names\n", + "for author in yield from {book.get(\"author\") for book in books if book.get(\"author\")}:\n", + "\n", + " print(author) \n", + "\n", + "In this code snippet, printing the extracted authors would output `John Doe`, `Jane Smith` (since only dictionaries with author information pass the filtering test).\n", + "\n", + "Please modify it like as you wish and use `yield from` along with dictionary iteration, list comprehension or generator expression if needed, and explain what purpose your version has." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Get the model of your choice (choices appeared below) to answer, with streaming \n", + "\n", + "\"\"\"models = {\n", + " 'MODEL_GPT': 'gpt-4o-mini',\n", + " 'MODEL_LLAMA': 'llama3.2'\n", + "}\"\"\"\n", + "\n", + "stream_brochure(question,'MODEL_LLAMA')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "llms", + "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 +}