From ccadc8d2146e50702c14c7ea286bf0263e28f890 Mon Sep 17 00:00:00 2001 From: johnIT56 Date: Sun, 23 Feb 2025 00:10:20 +0900 Subject: [PATCH 01/22] Adding Ollama with tts and use it as translator --- .../day5_ollama_tts-translator.ipynb | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 week2/community-contributions/day5_ollama_tts-translator.ipynb diff --git a/week2/community-contributions/day5_ollama_tts-translator.ipynb b/week2/community-contributions/day5_ollama_tts-translator.ipynb new file mode 100644 index 0000000..2463633 --- /dev/null +++ b/week2/community-contributions/day5_ollama_tts-translator.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "a8941402-99ee-4c3e-b852-056df3a77a5d", + "metadata": {}, + "outputs": [], + "source": [ + "import pyttsx3\n", + "import ollama\n", + "import gradio as gr\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cbdc0ca-648a-40cc-ad30-ad8bf6126aed", + "metadata": {}, + "outputs": [], + "source": [ + "def talker(response):\n", + " # Initialize text-to-speech engine\n", + " engine = pyttsx3.init()\n", + " engine.say(response)\n", + " engine.runAndWait()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a5b4f3c-2c6f-46db-bc66-386b30e2e707", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"you are a helpful assistance\"\n", + "MODEL_LLAMA = \"llama3.2\"\n", + "\n", + "\n", + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + "\n", + " response= ollama.chat(model=MODEL_LLAMA, messages=messages)\n", + "\n", + " response = response['message']['content']\n", + "\n", + " # Once the full response is generated, speak it out loud\n", + "\n", + " talker(response)\n", + "\n", + " return response\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfdb3be4-a9cb-4564-87d8-4645ce0177b5", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch(share=True)" + ] + }, + { + "cell_type": "markdown", + "id": "38155307-6975-49ef-b65f-7d7b1dd82d32", + "metadata": {}, + "source": [ + "# Real life use as a Translator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa6e4b93-27e3-4455-80ca-eb7e39d13afc", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"you are helpful translator from english to korean, on the first prompt introduce your self \\\n", + "that you are dealing with korean translation and you would like to translate some english words or sentences to korean\" \n", + "system_message += \"dont do other tasks apart from translation\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0ed5e28-b294-40fc-a97c-11fe264a4d1d", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch(share=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c63a02ae-cdc1-45a8-8f51-784d8d5417e2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 86cc68e255fef55246c5adce7b71b132fb8a4f4b Mon Sep 17 00:00:00 2001 From: jenkins Date: Sat, 22 Feb 2025 22:03:41 +0400 Subject: [PATCH 02/22] mac selenium --- .../day1-selenium-for-javascript-sites.ipynb | 415 +++++++----------- .../day1-selenium-lama-mac.ipynb | 384 ++++++++++++++++ 2 files changed, 535 insertions(+), 264 deletions(-) create mode 100644 week1/community-contributions/day1-selenium-lama-mac.ipynb diff --git a/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb b/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb index fd3a3ba..198de53 100644 --- a/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb +++ b/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb @@ -2,305 +2,143 @@ "cells": [ { "cell_type": "markdown", - "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9", + "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", "metadata": {}, "source": [ - "# Instant Gratification!\n", - "\n", - "Let's build a useful LLM solution - in a matter of minutes.\n", - "\n", - "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n", - "\n", - "Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n", - "\n", - "## If you're new to Jupyter Lab\n", - "\n", - "Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, like the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations.\n", - "\n", - "If you need to start again, go to Kernel menu >> Restart kernel." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd", - "metadata": {}, - "outputs": [], - "source": [ - "# imports\n", + "## An extra exercise for those who enjoy web scraping\n", "\n", - "import os\n", - "import requests\n", - "from dotenv import load_dotenv\n", - "from bs4 import BeautifulSoup\n", - "from IPython.display import Markdown, display\n", - "from openai import OpenAI" + "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" ] }, { "cell_type": "markdown", - "id": "6900b2a8-6384-4316-8aaa-5e519fca4254", + "id": "c97ad592-c8be-4583-a19c-ac813e56f410", "metadata": {}, "source": [ - "# Connecting to OpenAI\n", - "\n", - "The next cell is where we load in the environment variables in your `.env` file and connect to OpenAI.\n", + "## Mac Users\n", "\n", - "## Troubleshooting if you have problems:\n", + "I find some challenges while setting up this in MAC silicon M1 chip. Execute below commands in MAC terminal.\n", "\n", - "1. OpenAI takes a few minutes to register after you set up an account. If you receive an error about being over quota, try waiting a few minutes and try again.\n", - "2. Also, double check you have the right kind of API token with the right permissions. You should find it on [this webpage](https://platform.openai.com/api-keys) and it should show with Permissions of \"All\". If not, try creating another key by:\n", - "- Pressing \"Create new secret key\" on the top right\n", - "- Select **Owned by:** you, **Project:** Default project, **Permissions:** All\n", - "- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n", - "- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n", - "4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n", - "5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n", - "\n", - "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point." + "1. Download chromedriver.\n", + "2. Unzip and add it to the path.\n", + "3. Set Extended attributes." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7b87cadb-d513-4303-baee-a37b6f938e4d", + "cell_type": "markdown", + "id": "b635b345-b000-48cc-8a7f-7df279a489a3", "metadata": {}, - "outputs": [], "source": [ - "# Load environment variables in a file called .env\n", - "\n", - "load_dotenv()\n", - "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY','your-key-if-not-using-env')\n", - "openai = OpenAI()" + "cd ~/Downloads\n", + "wget https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.126/mac-arm64/chromedriver-mac-arm64.zip\n", + "unzip chromedriver-mac-arm64.zip\n", + "sudo mv chromedriver-mac-arm64/chromedriver /usr/local/bin/\n", + "chmod +x /usr/local/bin/chromedriver\n", + "cd /usr/local/bin/\n", + "xattr -d com.apple.quarantine chromedriver\n", + "cd \n", + "chromedriver --version" ] }, { "cell_type": "code", - "execution_count": null, - "id": "c5e793b2-6775-426a-a139-4848291d0463", + "execution_count": 1, + "id": "17c7c79a-8ae0-4f5d-a7c8-c54aa7ba90fd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: selenium in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (4.29.0)\n", + "Requirement already satisfied: urllib3<3,>=1.26 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium) (2.3.0)\n", + "Requirement already satisfied: trio~=0.17 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (0.29.0)\n", + "Requirement already satisfied: trio-websocket~=0.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (0.12.1)\n", + "Requirement already satisfied: certifi>=2021.10.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (2025.1.31)\n", + "Requirement already satisfied: typing_extensions~=4.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (4.12.2)\n", + "Requirement already satisfied: websocket-client~=1.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (1.8.0)\n", + "Requirement already satisfied: attrs>=23.2.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (25.1.0)\n", + "Requirement already satisfied: sortedcontainers in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (2.4.0)\n", + "Requirement already satisfied: idna in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (3.10)\n", + "Requirement already satisfied: outcome in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (1.3.0.post0)\n", + "Requirement already satisfied: sniffio>=1.3.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (1.3.1)\n", + "Requirement already satisfied: wsproto>=0.14 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio-websocket~=0.9->selenium) (1.2.0)\n", + "Requirement already satisfied: pysocks!=1.5.7,<2.0,>=1.5.6 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium) (1.7.1)\n", + "Requirement already satisfied: h11<1,>=0.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from wsproto>=0.14->trio-websocket~=0.9->selenium) (0.14.0)\n", + "Requirement already satisfied: undetected-chromedriver in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (3.5.5)\n", + "Requirement already satisfied: selenium>=4.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (4.29.0)\n", + "Requirement already satisfied: requests in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (2.32.3)\n", + "Requirement already satisfied: websockets in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (14.2)\n", + "Requirement already satisfied: urllib3<3,>=1.26 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium>=4.9.0->undetected-chromedriver) (2.3.0)\n", + "Requirement already satisfied: trio~=0.17 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (0.29.0)\n", + "Requirement already satisfied: trio-websocket~=0.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (0.12.1)\n", + "Requirement already satisfied: certifi>=2021.10.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (2025.1.31)\n", + "Requirement already satisfied: typing_extensions~=4.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (4.12.2)\n", + "Requirement already satisfied: websocket-client~=1.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (1.8.0)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from requests->undetected-chromedriver) (3.4.1)\n", + "Requirement already satisfied: idna<4,>=2.5 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from requests->undetected-chromedriver) (3.10)\n", + "Requirement already satisfied: attrs>=23.2.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (25.1.0)\n", + "Requirement already satisfied: sortedcontainers in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (2.4.0)\n", + "Requirement already satisfied: outcome in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (1.3.0.post0)\n", + "Requirement already satisfied: sniffio>=1.3.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (1.3.1)\n", + "Requirement already satisfied: wsproto>=0.14 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio-websocket~=0.9->selenium>=4.9.0->undetected-chromedriver) (1.2.0)\n", + "Requirement already satisfied: pysocks!=1.5.7,<2.0,>=1.5.6 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium>=4.9.0->undetected-chromedriver) (1.7.1)\n", + "Requirement already satisfied: h11<1,>=0.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from wsproto>=0.14->trio-websocket~=0.9->selenium>=4.9.0->undetected-chromedriver) (0.14.0)\n", + "Requirement already satisfied: beautifulsoup4 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (4.13.3)\n", + "Requirement already satisfied: soupsieve>1.2 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from beautifulsoup4) (2.5)\n", + "Requirement already satisfied: typing-extensions>=4.0.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from beautifulsoup4) (4.12.2)\n" + ] + } + ], "source": [ - "# A class to represent a Webpage\n", - "\n", - "class Website:\n", - " url: str\n", - " title: str\n", - " text: str\n", - "\n", - " def __init__(self, url):\n", - " self.url = url\n", - " response = requests.get(url)\n", - " soup = BeautifulSoup(response.content, 'html.parser')\n", - " self.title = soup.title.string if soup.title else \"No title found\"\n", - " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", - " irrelevant.decompose()\n", - " self.text = soup.body.get_text(separator=\"\\n\", strip=True)" + "!pip install selenium\n", + "!pip install undetected-chromedriver\n", + "!pip install beautifulsoup4" ] }, { "cell_type": "code", - "execution_count": null, - "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97", + "execution_count": 2, + "id": "c10bd630-2dfd-4572-8c21-2dc4c6a372ab", "metadata": {}, "outputs": [], "source": [ - "# Let's try one out\n", - "\n", - "ed = Website(\"https://edwarddonner.com\")\n", - "print(ed.title)\n", - "print(ed.text)" - ] - }, - { - "cell_type": "markdown", - "id": "6a478a0c-2c53-48ff-869c-4d08199931e1", - "metadata": {}, - "source": [ - "## Types of prompts\n", - "\n", - "You may know this already - but if not, you will get very familiar with it!\n", - "\n", - "Models like GPT4o have been trained to receive instructions in a particular way.\n", - "\n", - "They expect to receive:\n", - "\n", - "**A system prompt** that tells them what task they are performing and what tone they should use\n", - "\n", - "**A user prompt** -- the conversation starter that they should reply to" + "from selenium import webdriver\n", + "from selenium.webdriver.chrome.service import Service\n", + "from selenium.webdriver.common.by import By\n", + "from selenium.webdriver.chrome.options import Options\n", + "from openai import OpenAI\n", + "import os\n", + "import requests\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display\n", + "from openai import OpenAI" ] }, { "cell_type": "code", - "execution_count": null, - "id": "abdb8417-c5dc-44bc-9bee-2e059d162699", + "execution_count": 7, + "id": "6fb3641d-e9f8-4f5b-bb9d-ee0e971cccdb", "metadata": {}, "outputs": [], "source": [ + "OLLAMA_API = \"http://localhost:11434/api/chat\"\n", + "HEADERS = {\"Content-Type\": \"application/json\"}\n", + "MODEL = \"llama3.2\"\n", + "PATH_TO_CHROME_DRIVER = '/usr/local/bin/chromedriver'\n", "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n", "and provides a short summary, ignoring text that might be navigation related. \\\n", - "Respond in markdown.\"" + "Respond in markdown. Highlight all the products this website offered and also find when website is created.\"\n" ] }, { "cell_type": "code", - "execution_count": null, - "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c", - "metadata": {}, - "outputs": [], - "source": [ - "def user_prompt_for(website):\n", - " user_prompt = f\"You are looking at a website titled {website.title}\"\n", - " user_prompt += \"The contents of this website is as follows; \\\n", - "please provide a short summary of this website in markdown. \\\n", - "If it includes news or announcements, then summarize these too.\\n\\n\"\n", - " user_prompt += website.text\n", - " return user_prompt" - ] - }, - { - "cell_type": "markdown", - "id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc", - "metadata": {}, - "source": [ - "## Messages\n", - "\n", - "The API from OpenAI expects to receive messages in a particular structure.\n", - "Many of the other APIs share this structure:\n", - "\n", - "```\n", - "[\n", - " {\"role\": \"system\", \"content\": \"system message goes here\"},\n", - " {\"role\": \"user\", \"content\": \"user message goes here\"}\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88", - "metadata": {}, - "outputs": [], - "source": [ - "def messages_for(website):\n", - " return [\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", - " ]" - ] - }, - { - "cell_type": "markdown", - "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0", - "metadata": {}, - "source": [ - "## Time to bring it together - the API for OpenAI is very simple!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34", - "metadata": {}, - "outputs": [], - "source": [ - "def summarize(url):\n", - " website = Website(url)\n", - " response = openai.chat.completions.create(\n", - " model = \"gpt-4o-mini\",\n", - " messages = messages_for(website)\n", - " )\n", - " return response.choices[0].message.content" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5", - "metadata": {}, - "outputs": [], - "source": [ - "summarize(\"https://edwarddonner.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d926d59-450e-4609-92ba-2d6f244f1342", - "metadata": {}, - "outputs": [], - "source": [ - "def display_summary(url):\n", - " summary = summarize(url)\n", - " display(Markdown(summary))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3018853a-445f-41ff-9560-d925d1774b2f", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://edwarddonner.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45d83403-a24c-44b5-84ac-961449b4008f", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://cnn.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "75e9fd40-b354-4341-991e-863ef2e59db7", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://anthropic.com\")" - ] - }, - { - "cell_type": "markdown", - "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", - "metadata": {}, - "source": [ - "## An extra exercise for those who enjoy web scraping\n", - "\n", - "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52ae98bb", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://openai.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "5d57e958", "metadata": {}, "outputs": [], "source": [ - "#Parse webpages which is designed using JavaScript heavely\n", - "# download the chorme driver from here as per your version of chrome - https://developer.chrome.com/docs/chromedriver/downloads\n", - "from selenium import webdriver\n", - "from selenium.webdriver.chrome.service import Service\n", - "from selenium.webdriver.common.by import By\n", - "from selenium.webdriver.chrome.options import Options\n", - "\n", - "PATH_TO_CHROME_DRIVER = '..\\\\path\\\\to\\\\chromedriver.exe'\n", - "\n", "class Website:\n", " url: str\n", " title: str\n", @@ -318,7 +156,7 @@ " driver = webdriver.Chrome(service=service, options=options)\n", " driver.get(url)\n", "\n", - " input(\"Please complete the verification in the browser and press Enter to continue...\")\n", + " # input(\"Please complete the verification in the browser and press Enter to continue...\")\n", " page_source = driver.page_source\n", " driver.quit()\n", "\n", @@ -331,33 +169,82 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "65192f6b", + "execution_count": 5, + "id": "56df8cd2-2707-43f6-a066-3367846929b3", "metadata": {}, "outputs": [], "source": [ - "display_summary(\"https://openai.com\")" + "def user_prompt_for(website):\n", + " user_prompt = f\"You are looking at a website titled {website.title}\"\n", + " user_prompt += \"\\nThe contents of this website is as follows; \\\n", + "please provide a short summary of this website in markdown. \\\n", + "If it includes news or announcements, then summarize these too.\\n\\n\"\n", + " user_prompt += website.text\n", + " return user_prompt\n", + "\n", + "\n", + "\n", + "def messages_for(website):\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", + " ]\n", + "\n", + "\n", + "def summarize(url):\n", + " website = Website(url)\n", + " ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n", + " response = ollama_via_openai.chat.completions.create(\n", + " model=MODEL,\n", + " messages = messages_for(website)\n", + " )\n", + " return response.choices[0].message.content\n", + "\n", + "\n", + "def display_summary(url):\n", + " summary = summarize(url)\n", + " display(Markdown(summary))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "f2eb9599", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/markdown": [ + "It appears that you have provided a sample website or travel booking platform, specifically for flights and hotels in the Middle East region. The content includes:\n", + "\n", + "1. **Flights**: A search engine to find flights across various airlines.\n", + "2. **Hotels**: A selection of chain hotels available for booking.\n", + "3. **Travel**: A general page with FAQs and information about traveling within Saudi Arabia, Kuwait, and other nearby countries.\n", + "4. **Almosafer App**: An advertisement for the Almosafer app, which offers features like secure payment channels, easy booking processes, and user-friendly designs.\n", + "\n", + "The platform also displays a list of trending searches, airlines, and countries to facilitate searching and planning trips.\n", + "\n", + "Please let me know if you have any specific questions or need further assistance with this website sample." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "display_summary(\"https://edwarddonner.com\")" + "display_summary(\"https://ae.almosafer.com\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "e7ba56c8", + "id": "31b66c0f-6b45-4986-b77c-758625945a91", "metadata": {}, "outputs": [], - "source": [ - "display_summary(\"https://cnn.com\")" - ] + "source": [] } ], "metadata": { diff --git a/week1/community-contributions/day1-selenium-lama-mac.ipynb b/week1/community-contributions/day1-selenium-lama-mac.ipynb new file mode 100644 index 0000000..fd3a3ba --- /dev/null +++ b/week1/community-contributions/day1-selenium-lama-mac.ipynb @@ -0,0 +1,384 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9", + "metadata": {}, + "source": [ + "# Instant Gratification!\n", + "\n", + "Let's build a useful LLM solution - in a matter of minutes.\n", + "\n", + "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n", + "\n", + "Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n", + "\n", + "## If you're new to Jupyter Lab\n", + "\n", + "Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, like the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations.\n", + "\n", + "If you need to start again, go to Kernel menu >> Restart kernel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import requests\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display\n", + "from openai import OpenAI" + ] + }, + { + "cell_type": "markdown", + "id": "6900b2a8-6384-4316-8aaa-5e519fca4254", + "metadata": {}, + "source": [ + "# Connecting to OpenAI\n", + "\n", + "The next cell is where we load in the environment variables in your `.env` file and connect to OpenAI.\n", + "\n", + "## Troubleshooting if you have problems:\n", + "\n", + "1. OpenAI takes a few minutes to register after you set up an account. If you receive an error about being over quota, try waiting a few minutes and try again.\n", + "2. Also, double check you have the right kind of API token with the right permissions. You should find it on [this webpage](https://platform.openai.com/api-keys) and it should show with Permissions of \"All\". If not, try creating another key by:\n", + "- Pressing \"Create new secret key\" on the top right\n", + "- Select **Owned by:** you, **Project:** Default project, **Permissions:** All\n", + "- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n", + "- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n", + "4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n", + "5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n", + "\n", + "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b87cadb-d513-4303-baee-a37b6f938e4d", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY','your-key-if-not-using-env')\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5e793b2-6775-426a-a139-4848291d0463", + "metadata": {}, + "outputs": [], + "source": [ + "# A class to represent a Webpage\n", + "\n", + "class Website:\n", + " url: str\n", + " title: str\n", + " text: str\n", + "\n", + " def __init__(self, url):\n", + " self.url = url\n", + " response = requests.get(url)\n", + " soup = BeautifulSoup(response.content, 'html.parser')\n", + " self.title = soup.title.string if soup.title else \"No title found\"\n", + " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", + " irrelevant.decompose()\n", + " self.text = soup.body.get_text(separator=\"\\n\", strip=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's try one out\n", + "\n", + "ed = Website(\"https://edwarddonner.com\")\n", + "print(ed.title)\n", + "print(ed.text)" + ] + }, + { + "cell_type": "markdown", + "id": "6a478a0c-2c53-48ff-869c-4d08199931e1", + "metadata": {}, + "source": [ + "## Types of prompts\n", + "\n", + "You may know this already - but if not, you will get very familiar with it!\n", + "\n", + "Models like GPT4o have been trained to receive instructions in a particular way.\n", + "\n", + "They expect to receive:\n", + "\n", + "**A system prompt** that tells them what task they are performing and what tone they should use\n", + "\n", + "**A user prompt** -- the conversation starter that they should reply to" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abdb8417-c5dc-44bc-9bee-2e059d162699", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n", + "and provides a short summary, ignoring text that might be navigation related. \\\n", + "Respond in markdown.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c", + "metadata": {}, + "outputs": [], + "source": [ + "def user_prompt_for(website):\n", + " user_prompt = f\"You are looking at a website titled {website.title}\"\n", + " user_prompt += \"The contents of this website is as follows; \\\n", + "please provide a short summary of this website in markdown. \\\n", + "If it includes news or announcements, then summarize these too.\\n\\n\"\n", + " user_prompt += website.text\n", + " return user_prompt" + ] + }, + { + "cell_type": "markdown", + "id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc", + "metadata": {}, + "source": [ + "## Messages\n", + "\n", + "The API from OpenAI expects to receive messages in a particular structure.\n", + "Many of the other APIs share this structure:\n", + "\n", + "```\n", + "[\n", + " {\"role\": \"system\", \"content\": \"system message goes here\"},\n", + " {\"role\": \"user\", \"content\": \"user message goes here\"}\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88", + "metadata": {}, + "outputs": [], + "source": [ + "def messages_for(website):\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0", + "metadata": {}, + "source": [ + "## Time to bring it together - the API for OpenAI is very simple!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34", + "metadata": {}, + "outputs": [], + "source": [ + "def summarize(url):\n", + " website = Website(url)\n", + " response = openai.chat.completions.create(\n", + " model = \"gpt-4o-mini\",\n", + " messages = messages_for(website)\n", + " )\n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5", + "metadata": {}, + "outputs": [], + "source": [ + "summarize(\"https://edwarddonner.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d926d59-450e-4609-92ba-2d6f244f1342", + "metadata": {}, + "outputs": [], + "source": [ + "def display_summary(url):\n", + " summary = summarize(url)\n", + " display(Markdown(summary))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3018853a-445f-41ff-9560-d925d1774b2f", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://edwarddonner.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45d83403-a24c-44b5-84ac-961449b4008f", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://cnn.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75e9fd40-b354-4341-991e-863ef2e59db7", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://anthropic.com\")" + ] + }, + { + "cell_type": "markdown", + "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", + "metadata": {}, + "source": [ + "## An extra exercise for those who enjoy web scraping\n", + "\n", + "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52ae98bb", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://openai.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d57e958", + "metadata": {}, + "outputs": [], + "source": [ + "#Parse webpages which is designed using JavaScript heavely\n", + "# download the chorme driver from here as per your version of chrome - https://developer.chrome.com/docs/chromedriver/downloads\n", + "from selenium import webdriver\n", + "from selenium.webdriver.chrome.service import Service\n", + "from selenium.webdriver.common.by import By\n", + "from selenium.webdriver.chrome.options import Options\n", + "\n", + "PATH_TO_CHROME_DRIVER = '..\\\\path\\\\to\\\\chromedriver.exe'\n", + "\n", + "class Website:\n", + " url: str\n", + " title: str\n", + " text: str\n", + "\n", + " def __init__(self, url):\n", + " self.url = url\n", + "\n", + " options = Options()\n", + "\n", + " options.add_argument(\"--no-sandbox\")\n", + " options.add_argument(\"--disable-dev-shm-usage\")\n", + "\n", + " service = Service(PATH_TO_CHROME_DRIVER)\n", + " driver = webdriver.Chrome(service=service, options=options)\n", + " driver.get(url)\n", + "\n", + " input(\"Please complete the verification in the browser and press Enter to continue...\")\n", + " page_source = driver.page_source\n", + " driver.quit()\n", + "\n", + " soup = BeautifulSoup(page_source, 'html.parser')\n", + " self.title = soup.title.string if soup.title else \"No title found\"\n", + " for irrelevant in soup([\"script\", \"style\", \"img\", \"input\"]):\n", + " irrelevant.decompose()\n", + " self.text = soup.get_text(separator=\"\\n\", strip=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65192f6b", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://openai.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2eb9599", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://edwarddonner.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7ba56c8", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://cnn.com\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From 311a0f4813e0a99c537396274e77f10fca458900 Mon Sep 17 00:00:00 2001 From: jenkins Date: Sat, 22 Feb 2025 22:33:57 +0400 Subject: [PATCH 03/22] mac --- .../day1-selenium-for-javascript-sites.ipynb | 415 +++++++++++------- .../day1-selenium-lama-mac.ipynb | 335 +++----------- 2 files changed, 337 insertions(+), 413 deletions(-) diff --git a/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb b/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb index 198de53..fd3a3ba 100644 --- a/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb +++ b/week1/community-contributions/day1-selenium-for-javascript-sites.ipynb @@ -2,143 +2,305 @@ "cells": [ { "cell_type": "markdown", - "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", + "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9", "metadata": {}, "source": [ - "## An extra exercise for those who enjoy web scraping\n", + "# Instant Gratification!\n", "\n", - "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" + "Let's build a useful LLM solution - in a matter of minutes.\n", + "\n", + "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n", + "\n", + "Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n", + "\n", + "## If you're new to Jupyter Lab\n", + "\n", + "Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, like the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations.\n", + "\n", + "If you need to start again, go to Kernel menu >> Restart kernel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import requests\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display\n", + "from openai import OpenAI" ] }, { "cell_type": "markdown", - "id": "c97ad592-c8be-4583-a19c-ac813e56f410", + "id": "6900b2a8-6384-4316-8aaa-5e519fca4254", "metadata": {}, "source": [ - "## Mac Users\n", + "# Connecting to OpenAI\n", + "\n", + "The next cell is where we load in the environment variables in your `.env` file and connect to OpenAI.\n", "\n", - "I find some challenges while setting up this in MAC silicon M1 chip. Execute below commands in MAC terminal.\n", + "## Troubleshooting if you have problems:\n", "\n", - "1. Download chromedriver.\n", - "2. Unzip and add it to the path.\n", - "3. Set Extended attributes." + "1. OpenAI takes a few minutes to register after you set up an account. If you receive an error about being over quota, try waiting a few minutes and try again.\n", + "2. Also, double check you have the right kind of API token with the right permissions. You should find it on [this webpage](https://platform.openai.com/api-keys) and it should show with Permissions of \"All\". If not, try creating another key by:\n", + "- Pressing \"Create new secret key\" on the top right\n", + "- Select **Owned by:** you, **Project:** Default project, **Permissions:** All\n", + "- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n", + "- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n", + "4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n", + "5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n", + "\n", + "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point." ] }, { - "cell_type": "markdown", - "id": "b635b345-b000-48cc-8a7f-7df279a489a3", + "cell_type": "code", + "execution_count": null, + "id": "7b87cadb-d513-4303-baee-a37b6f938e4d", "metadata": {}, + "outputs": [], "source": [ - "cd ~/Downloads\n", - "wget https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.126/mac-arm64/chromedriver-mac-arm64.zip\n", - "unzip chromedriver-mac-arm64.zip\n", - "sudo mv chromedriver-mac-arm64/chromedriver /usr/local/bin/\n", - "chmod +x /usr/local/bin/chromedriver\n", - "cd /usr/local/bin/\n", - "xattr -d com.apple.quarantine chromedriver\n", - "cd \n", - "chromedriver --version" + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY','your-key-if-not-using-env')\n", + "openai = OpenAI()" ] }, { "cell_type": "code", - "execution_count": 1, - "id": "17c7c79a-8ae0-4f5d-a7c8-c54aa7ba90fd", + "execution_count": null, + "id": "c5e793b2-6775-426a-a139-4848291d0463", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: selenium in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (4.29.0)\n", - "Requirement already satisfied: urllib3<3,>=1.26 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium) (2.3.0)\n", - "Requirement already satisfied: trio~=0.17 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (0.29.0)\n", - "Requirement already satisfied: trio-websocket~=0.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (0.12.1)\n", - "Requirement already satisfied: certifi>=2021.10.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (2025.1.31)\n", - "Requirement already satisfied: typing_extensions~=4.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (4.12.2)\n", - "Requirement already satisfied: websocket-client~=1.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium) (1.8.0)\n", - "Requirement already satisfied: attrs>=23.2.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (25.1.0)\n", - "Requirement already satisfied: sortedcontainers in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (2.4.0)\n", - "Requirement already satisfied: idna in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (3.10)\n", - "Requirement already satisfied: outcome in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (1.3.0.post0)\n", - "Requirement already satisfied: sniffio>=1.3.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium) (1.3.1)\n", - "Requirement already satisfied: wsproto>=0.14 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio-websocket~=0.9->selenium) (1.2.0)\n", - "Requirement already satisfied: pysocks!=1.5.7,<2.0,>=1.5.6 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium) (1.7.1)\n", - "Requirement already satisfied: h11<1,>=0.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from wsproto>=0.14->trio-websocket~=0.9->selenium) (0.14.0)\n", - "Requirement already satisfied: undetected-chromedriver in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (3.5.5)\n", - "Requirement already satisfied: selenium>=4.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (4.29.0)\n", - "Requirement already satisfied: requests in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (2.32.3)\n", - "Requirement already satisfied: websockets in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from undetected-chromedriver) (14.2)\n", - "Requirement already satisfied: urllib3<3,>=1.26 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium>=4.9.0->undetected-chromedriver) (2.3.0)\n", - "Requirement already satisfied: trio~=0.17 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (0.29.0)\n", - "Requirement already satisfied: trio-websocket~=0.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (0.12.1)\n", - "Requirement already satisfied: certifi>=2021.10.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (2025.1.31)\n", - "Requirement already satisfied: typing_extensions~=4.9 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (4.12.2)\n", - "Requirement already satisfied: websocket-client~=1.8 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from selenium>=4.9.0->undetected-chromedriver) (1.8.0)\n", - "Requirement already satisfied: charset_normalizer<4,>=2 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from requests->undetected-chromedriver) (3.4.1)\n", - "Requirement already satisfied: idna<4,>=2.5 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from requests->undetected-chromedriver) (3.10)\n", - "Requirement already satisfied: attrs>=23.2.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (25.1.0)\n", - "Requirement already satisfied: sortedcontainers in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (2.4.0)\n", - "Requirement already satisfied: outcome in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (1.3.0.post0)\n", - "Requirement already satisfied: sniffio>=1.3.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio~=0.17->selenium>=4.9.0->undetected-chromedriver) (1.3.1)\n", - "Requirement already satisfied: wsproto>=0.14 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from trio-websocket~=0.9->selenium>=4.9.0->undetected-chromedriver) (1.2.0)\n", - "Requirement already satisfied: pysocks!=1.5.7,<2.0,>=1.5.6 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from urllib3[socks]<3,>=1.26->selenium>=4.9.0->undetected-chromedriver) (1.7.1)\n", - "Requirement already satisfied: h11<1,>=0.9.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from wsproto>=0.14->trio-websocket~=0.9->selenium>=4.9.0->undetected-chromedriver) (0.14.0)\n", - "Requirement already satisfied: beautifulsoup4 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (4.13.3)\n", - "Requirement already satisfied: soupsieve>1.2 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from beautifulsoup4) (2.5)\n", - "Requirement already satisfied: typing-extensions>=4.0.0 in /opt/anaconda3/envs/llms/lib/python3.11/site-packages (from beautifulsoup4) (4.12.2)\n" - ] - } - ], + "outputs": [], "source": [ - "!pip install selenium\n", - "!pip install undetected-chromedriver\n", - "!pip install beautifulsoup4" + "# A class to represent a Webpage\n", + "\n", + "class Website:\n", + " url: str\n", + " title: str\n", + " text: str\n", + "\n", + " def __init__(self, url):\n", + " self.url = url\n", + " response = requests.get(url)\n", + " soup = BeautifulSoup(response.content, 'html.parser')\n", + " self.title = soup.title.string if soup.title else \"No title found\"\n", + " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", + " irrelevant.decompose()\n", + " self.text = soup.body.get_text(separator=\"\\n\", strip=True)" ] }, { "cell_type": "code", - "execution_count": 2, - "id": "c10bd630-2dfd-4572-8c21-2dc4c6a372ab", + "execution_count": null, + "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97", "metadata": {}, "outputs": [], "source": [ - "from selenium import webdriver\n", - "from selenium.webdriver.chrome.service import Service\n", - "from selenium.webdriver.common.by import By\n", - "from selenium.webdriver.chrome.options import Options\n", - "from openai import OpenAI\n", - "import os\n", - "import requests\n", - "from dotenv import load_dotenv\n", - "from bs4 import BeautifulSoup\n", - "from IPython.display import Markdown, display\n", - "from openai import OpenAI" + "# Let's try one out\n", + "\n", + "ed = Website(\"https://edwarddonner.com\")\n", + "print(ed.title)\n", + "print(ed.text)" + ] + }, + { + "cell_type": "markdown", + "id": "6a478a0c-2c53-48ff-869c-4d08199931e1", + "metadata": {}, + "source": [ + "## Types of prompts\n", + "\n", + "You may know this already - but if not, you will get very familiar with it!\n", + "\n", + "Models like GPT4o have been trained to receive instructions in a particular way.\n", + "\n", + "They expect to receive:\n", + "\n", + "**A system prompt** that tells them what task they are performing and what tone they should use\n", + "\n", + "**A user prompt** -- the conversation starter that they should reply to" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "6fb3641d-e9f8-4f5b-bb9d-ee0e971cccdb", + "execution_count": null, + "id": "abdb8417-c5dc-44bc-9bee-2e059d162699", "metadata": {}, "outputs": [], "source": [ - "OLLAMA_API = \"http://localhost:11434/api/chat\"\n", - "HEADERS = {\"Content-Type\": \"application/json\"}\n", - "MODEL = \"llama3.2\"\n", - "PATH_TO_CHROME_DRIVER = '/usr/local/bin/chromedriver'\n", "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n", "and provides a short summary, ignoring text that might be navigation related. \\\n", - "Respond in markdown. Highlight all the products this website offered and also find when website is created.\"\n" + "Respond in markdown.\"" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, + "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c", + "metadata": {}, + "outputs": [], + "source": [ + "def user_prompt_for(website):\n", + " user_prompt = f\"You are looking at a website titled {website.title}\"\n", + " user_prompt += \"The contents of this website is as follows; \\\n", + "please provide a short summary of this website in markdown. \\\n", + "If it includes news or announcements, then summarize these too.\\n\\n\"\n", + " user_prompt += website.text\n", + " return user_prompt" + ] + }, + { + "cell_type": "markdown", + "id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc", + "metadata": {}, + "source": [ + "## Messages\n", + "\n", + "The API from OpenAI expects to receive messages in a particular structure.\n", + "Many of the other APIs share this structure:\n", + "\n", + "```\n", + "[\n", + " {\"role\": \"system\", \"content\": \"system message goes here\"},\n", + " {\"role\": \"user\", \"content\": \"user message goes here\"}\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88", + "metadata": {}, + "outputs": [], + "source": [ + "def messages_for(website):\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0", + "metadata": {}, + "source": [ + "## Time to bring it together - the API for OpenAI is very simple!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34", + "metadata": {}, + "outputs": [], + "source": [ + "def summarize(url):\n", + " website = Website(url)\n", + " response = openai.chat.completions.create(\n", + " model = \"gpt-4o-mini\",\n", + " messages = messages_for(website)\n", + " )\n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5", + "metadata": {}, + "outputs": [], + "source": [ + "summarize(\"https://edwarddonner.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d926d59-450e-4609-92ba-2d6f244f1342", + "metadata": {}, + "outputs": [], + "source": [ + "def display_summary(url):\n", + " summary = summarize(url)\n", + " display(Markdown(summary))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3018853a-445f-41ff-9560-d925d1774b2f", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://edwarddonner.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45d83403-a24c-44b5-84ac-961449b4008f", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://cnn.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75e9fd40-b354-4341-991e-863ef2e59db7", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://anthropic.com\")" + ] + }, + { + "cell_type": "markdown", + "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", + "metadata": {}, + "source": [ + "## An extra exercise for those who enjoy web scraping\n", + "\n", + "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52ae98bb", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://openai.com\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "5d57e958", "metadata": {}, "outputs": [], "source": [ + "#Parse webpages which is designed using JavaScript heavely\n", + "# download the chorme driver from here as per your version of chrome - https://developer.chrome.com/docs/chromedriver/downloads\n", + "from selenium import webdriver\n", + "from selenium.webdriver.chrome.service import Service\n", + "from selenium.webdriver.common.by import By\n", + "from selenium.webdriver.chrome.options import Options\n", + "\n", + "PATH_TO_CHROME_DRIVER = '..\\\\path\\\\to\\\\chromedriver.exe'\n", + "\n", "class Website:\n", " url: str\n", " title: str\n", @@ -156,7 +318,7 @@ " driver = webdriver.Chrome(service=service, options=options)\n", " driver.get(url)\n", "\n", - " # input(\"Please complete the verification in the browser and press Enter to continue...\")\n", + " input(\"Please complete the verification in the browser and press Enter to continue...\")\n", " page_source = driver.page_source\n", " driver.quit()\n", "\n", @@ -169,82 +331,33 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "56df8cd2-2707-43f6-a066-3367846929b3", + "execution_count": null, + "id": "65192f6b", "metadata": {}, "outputs": [], "source": [ - "def user_prompt_for(website):\n", - " user_prompt = f\"You are looking at a website titled {website.title}\"\n", - " user_prompt += \"\\nThe contents of this website is as follows; \\\n", - "please provide a short summary of this website in markdown. \\\n", - "If it includes news or announcements, then summarize these too.\\n\\n\"\n", - " user_prompt += website.text\n", - " return user_prompt\n", - "\n", - "\n", - "\n", - "def messages_for(website):\n", - " return [\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", - " ]\n", - "\n", - "\n", - "def summarize(url):\n", - " website = Website(url)\n", - " ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n", - " response = ollama_via_openai.chat.completions.create(\n", - " model=MODEL,\n", - " messages = messages_for(website)\n", - " )\n", - " return response.choices[0].message.content\n", - "\n", - "\n", - "def display_summary(url):\n", - " summary = summarize(url)\n", - " display(Markdown(summary))" + "display_summary(\"https://openai.com\")" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "f2eb9599", "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "It appears that you have provided a sample website or travel booking platform, specifically for flights and hotels in the Middle East region. The content includes:\n", - "\n", - "1. **Flights**: A search engine to find flights across various airlines.\n", - "2. **Hotels**: A selection of chain hotels available for booking.\n", - "3. **Travel**: A general page with FAQs and information about traveling within Saudi Arabia, Kuwait, and other nearby countries.\n", - "4. **Almosafer App**: An advertisement for the Almosafer app, which offers features like secure payment channels, easy booking processes, and user-friendly designs.\n", - "\n", - "The platform also displays a list of trending searches, airlines, and countries to facilitate searching and planning trips.\n", - "\n", - "Please let me know if you have any specific questions or need further assistance with this website sample." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "display_summary(\"https://ae.almosafer.com\")" + "display_summary(\"https://edwarddonner.com\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "31b66c0f-6b45-4986-b77c-758625945a91", + "id": "e7ba56c8", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "display_summary(\"https://cnn.com\")" + ] } ], "metadata": { diff --git a/week1/community-contributions/day1-selenium-lama-mac.ipynb b/week1/community-contributions/day1-selenium-lama-mac.ipynb index fd3a3ba..5bb6956 100644 --- a/week1/community-contributions/day1-selenium-lama-mac.ipynb +++ b/week1/community-contributions/day1-selenium-lama-mac.ipynb @@ -2,287 +2,80 @@ "cells": [ { "cell_type": "markdown", - "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9", + "id": "c97ad592-c8be-4583-a19c-ac813e56f410", "metadata": {}, "source": [ - "# Instant Gratification!\n", + "## Mac Users\n", "\n", - "Let's build a useful LLM solution - in a matter of minutes.\n", + "I find some challenges while setting up this in MAC silicon M1 chip. Execute below commands in MAC terminal.\n", "\n", - "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n", - "\n", - "Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n", - "\n", - "## If you're new to Jupyter Lab\n", - "\n", - "Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, like the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations.\n", - "\n", - "If you need to start again, go to Kernel menu >> Restart kernel." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd", - "metadata": {}, - "outputs": [], - "source": [ - "# imports\n", - "\n", - "import os\n", - "import requests\n", - "from dotenv import load_dotenv\n", - "from bs4 import BeautifulSoup\n", - "from IPython.display import Markdown, display\n", - "from openai import OpenAI" + "1. Download chromedriver.\n", + "2. Unzip and add it to the path.\n", + "3. Set Extended attributes." ] }, { "cell_type": "markdown", - "id": "6900b2a8-6384-4316-8aaa-5e519fca4254", + "id": "b635b345-b000-48cc-8a7f-7df279a489a3", "metadata": {}, "source": [ - "# Connecting to OpenAI\n", - "\n", - "The next cell is where we load in the environment variables in your `.env` file and connect to OpenAI.\n", - "\n", - "## Troubleshooting if you have problems:\n", - "\n", - "1. OpenAI takes a few minutes to register after you set up an account. If you receive an error about being over quota, try waiting a few minutes and try again.\n", - "2. Also, double check you have the right kind of API token with the right permissions. You should find it on [this webpage](https://platform.openai.com/api-keys) and it should show with Permissions of \"All\". If not, try creating another key by:\n", - "- Pressing \"Create new secret key\" on the top right\n", - "- Select **Owned by:** you, **Project:** Default project, **Permissions:** All\n", - "- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n", - "- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n", - "4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n", - "5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n", - "\n", - "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point." + "cd ~/Downloads\n", + "wget https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.126/mac-arm64/chromedriver-mac-arm64.zip\n", + "unzip chromedriver-mac-arm64.zip\n", + "sudo mv chromedriver-mac-arm64/chromedriver /usr/local/bin/\n", + "chmod +x /usr/local/bin/chromedriver\n", + "cd /usr/local/bin/\n", + "xattr -d com.apple.quarantine chromedriver\n", + "cd \n", + "chromedriver --version" ] }, { "cell_type": "code", "execution_count": null, - "id": "7b87cadb-d513-4303-baee-a37b6f938e4d", + "id": "17c7c79a-8ae0-4f5d-a7c8-c54aa7ba90fd", "metadata": {}, "outputs": [], "source": [ - "# Load environment variables in a file called .env\n", - "\n", - "load_dotenv()\n", - "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY','your-key-if-not-using-env')\n", - "openai = OpenAI()" + "!pip install selenium\n", + "!pip install undetected-chromedriver\n", + "!pip install beautifulsoup4" ] }, { "cell_type": "code", "execution_count": null, - "id": "c5e793b2-6775-426a-a139-4848291d0463", + "id": "c10bd630-2dfd-4572-8c21-2dc4c6a372ab", "metadata": {}, "outputs": [], "source": [ - "# A class to represent a Webpage\n", - "\n", - "class Website:\n", - " url: str\n", - " title: str\n", - " text: str\n", - "\n", - " def __init__(self, url):\n", - " self.url = url\n", - " response = requests.get(url)\n", - " soup = BeautifulSoup(response.content, 'html.parser')\n", - " self.title = soup.title.string if soup.title else \"No title found\"\n", - " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", - " irrelevant.decompose()\n", - " self.text = soup.body.get_text(separator=\"\\n\", strip=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97", - "metadata": {}, - "outputs": [], - "source": [ - "# Let's try one out\n", - "\n", - "ed = Website(\"https://edwarddonner.com\")\n", - "print(ed.title)\n", - "print(ed.text)" - ] - }, - { - "cell_type": "markdown", - "id": "6a478a0c-2c53-48ff-869c-4d08199931e1", - "metadata": {}, - "source": [ - "## Types of prompts\n", - "\n", - "You may know this already - but if not, you will get very familiar with it!\n", - "\n", - "Models like GPT4o have been trained to receive instructions in a particular way.\n", - "\n", - "They expect to receive:\n", - "\n", - "**A system prompt** that tells them what task they are performing and what tone they should use\n", - "\n", - "**A user prompt** -- the conversation starter that they should reply to" + "from selenium import webdriver\n", + "from selenium.webdriver.chrome.service import Service\n", + "from selenium.webdriver.common.by import By\n", + "from selenium.webdriver.chrome.options import Options\n", + "from openai import OpenAI\n", + "import os\n", + "import requests\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display\n", + "from openai import OpenAI" ] }, { "cell_type": "code", "execution_count": null, - "id": "abdb8417-c5dc-44bc-9bee-2e059d162699", + "id": "6fb3641d-e9f8-4f5b-bb9d-ee0e971cccdb", "metadata": {}, "outputs": [], "source": [ + "OLLAMA_API = \"http://localhost:11434/api/chat\"\n", + "HEADERS = {\"Content-Type\": \"application/json\"}\n", + "MODEL = \"llama3.2\"\n", + "PATH_TO_CHROME_DRIVER = '/usr/local/bin/chromedriver'\n", "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n", "and provides a short summary, ignoring text that might be navigation related. \\\n", - "Respond in markdown.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c", - "metadata": {}, - "outputs": [], - "source": [ - "def user_prompt_for(website):\n", - " user_prompt = f\"You are looking at a website titled {website.title}\"\n", - " user_prompt += \"The contents of this website is as follows; \\\n", - "please provide a short summary of this website in markdown. \\\n", - "If it includes news or announcements, then summarize these too.\\n\\n\"\n", - " user_prompt += website.text\n", - " return user_prompt" - ] - }, - { - "cell_type": "markdown", - "id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc", - "metadata": {}, - "source": [ - "## Messages\n", - "\n", - "The API from OpenAI expects to receive messages in a particular structure.\n", - "Many of the other APIs share this structure:\n", - "\n", - "```\n", - "[\n", - " {\"role\": \"system\", \"content\": \"system message goes here\"},\n", - " {\"role\": \"user\", \"content\": \"user message goes here\"}\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88", - "metadata": {}, - "outputs": [], - "source": [ - "def messages_for(website):\n", - " return [\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", - " ]" - ] - }, - { - "cell_type": "markdown", - "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0", - "metadata": {}, - "source": [ - "## Time to bring it together - the API for OpenAI is very simple!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34", - "metadata": {}, - "outputs": [], - "source": [ - "def summarize(url):\n", - " website = Website(url)\n", - " response = openai.chat.completions.create(\n", - " model = \"gpt-4o-mini\",\n", - " messages = messages_for(website)\n", - " )\n", - " return response.choices[0].message.content" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5", - "metadata": {}, - "outputs": [], - "source": [ - "summarize(\"https://edwarddonner.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d926d59-450e-4609-92ba-2d6f244f1342", - "metadata": {}, - "outputs": [], - "source": [ - "def display_summary(url):\n", - " summary = summarize(url)\n", - " display(Markdown(summary))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3018853a-445f-41ff-9560-d925d1774b2f", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://edwarddonner.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45d83403-a24c-44b5-84ac-961449b4008f", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://cnn.com\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "75e9fd40-b354-4341-991e-863ef2e59db7", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://anthropic.com\")" - ] - }, - { - "cell_type": "markdown", - "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda", - "metadata": {}, - "source": [ - "## An extra exercise for those who enjoy web scraping\n", - "\n", - "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. Please push your code afterwards so I can share it with other students!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52ae98bb", - "metadata": {}, - "outputs": [], - "source": [ - "display_summary(\"https://openai.com\")" + "Respond in markdown. Highlight all the products this website offered and also find when website is created.\"\n" ] }, { @@ -292,15 +85,6 @@ "metadata": {}, "outputs": [], "source": [ - "#Parse webpages which is designed using JavaScript heavely\n", - "# download the chorme driver from here as per your version of chrome - https://developer.chrome.com/docs/chromedriver/downloads\n", - "from selenium import webdriver\n", - "from selenium.webdriver.chrome.service import Service\n", - "from selenium.webdriver.common.by import By\n", - "from selenium.webdriver.chrome.options import Options\n", - "\n", - "PATH_TO_CHROME_DRIVER = '..\\\\path\\\\to\\\\chromedriver.exe'\n", - "\n", "class Website:\n", " url: str\n", " title: str\n", @@ -318,7 +102,7 @@ " driver = webdriver.Chrome(service=service, options=options)\n", " driver.get(url)\n", "\n", - " input(\"Please complete the verification in the browser and press Enter to continue...\")\n", + " # input(\"Please complete the verification in the browser and press Enter to continue...\")\n", " page_source = driver.page_source\n", " driver.quit()\n", "\n", @@ -332,11 +116,40 @@ { "cell_type": "code", "execution_count": null, - "id": "65192f6b", + "id": "56df8cd2-2707-43f6-a066-3367846929b3", "metadata": {}, "outputs": [], "source": [ - "display_summary(\"https://openai.com\")" + "def user_prompt_for(website):\n", + " user_prompt = f\"You are looking at a website titled {website.title}\"\n", + " user_prompt += \"\\nThe contents of this website is as follows; \\\n", + "please provide a short summary of this website in markdown. \\\n", + "If it includes news or announcements, then summarize these too.\\n\\n\"\n", + " user_prompt += website.text\n", + " return user_prompt\n", + "\n", + "\n", + "\n", + "def messages_for(website):\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", + " ]\n", + "\n", + "\n", + "def summarize(url):\n", + " website = Website(url)\n", + " ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n", + " response = ollama_via_openai.chat.completions.create(\n", + " model=MODEL,\n", + " messages = messages_for(website)\n", + " )\n", + " return response.choices[0].message.content\n", + "\n", + "\n", + "def display_summary(url):\n", + " summary = summarize(url)\n", + " display(Markdown(summary))" ] }, { @@ -346,18 +159,16 @@ "metadata": {}, "outputs": [], "source": [ - "display_summary(\"https://edwarddonner.com\")" + "display_summary(\"https://ae.almosafer.com\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "e7ba56c8", + "id": "31b66c0f-6b45-4986-b77c-758625945a91", "metadata": {}, "outputs": [], - "source": [ - "display_summary(\"https://cnn.com\")" - ] + "source": [] } ], "metadata": { From fb5e507efaba75af285efbe4c65e856fe48eb343 Mon Sep 17 00:00:00 2001 From: sparsh_thakur <113547853+skullemote@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:17:46 -0700 Subject: [PATCH 04/22] Added my additional exercise for W2D1 to community-contributions --- .../w2d1exercise.ipynb | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 week2/community-contributions/w2d1exercise.ipynb diff --git a/week2/community-contributions/w2d1exercise.ipynb b/week2/community-contributions/w2d1exercise.ipynb new file mode 100644 index 0000000..eb45fc4 --- /dev/null +++ b/week2/community-contributions/w2d1exercise.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ec2e81cd-2172-4816-bf44-f29312b8a4bd", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import anthropic\n", + "import google.generativeai as genai\n", + "from IPython.display import Markdown, display, update_display" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a558dfa4-9496-48ba-b0f5-b0c731adc7b8", + "metadata": {}, + "outputs": [], + "source": [ + "load_dotenv(override=True)\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n", + "google_api_key = os.getenv('GOOGLE_API_KEY')\n", + "\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "if anthropic_api_key:\n", + " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n", + "else:\n", + " print(\"Anthropic API Key not set\")\n", + "\n", + "if google_api_key:\n", + " print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n", + "else:\n", + " print(\"Google API Key not set\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc7c2cda-a5d1-4930-87f2-e06485d6b2bd", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "\n", + "claude = anthropic.Anthropic()\n", + "\n", + "genai.configure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3eb32aec-ec93-4563-bd88-0d48d2471884", + "metadata": {}, + "outputs": [], + "source": [ + "gpt_model = \"gpt-4o-mini\"\n", + "claude_model = \"claude-3-haiku-20240307\"\n", + "gemini_model = \"gemini-2.0-flash-exp\"\n", + "\n", + "gpt_system = \"You are a chatbot who is sarcastic; \\\n", + "you have your speculations about anything in the conversation and you challenge everything in funny way.\\\n", + "You have to be a part of a group discussion and put forward your points about the topic\\\n", + "full-stack developers vs specialised developer. Keep your points short and precise.\"\n", + "\n", + "claude_system = \"You are a very polite, courteous chatbot. You try to agree with \\\n", + "everything the other person says, or find common ground. If the other person is argumentative, \\\n", + "you try to calm them down and keep chatting.You have to be a part of a group discussion and put forward your points\\\n", + "about the topic full-stack developers vs specialised developer. Keep your points short and precise.\"\n", + "\n", + "gemini_system = \"You are a very rational thinker and don't like beating around the bush about the topic of discussion.\\\n", + "You have to be a part of a group discussion and put forward your points\\\n", + "about the topic full-stack developers vs specialised developer\\\n", + "Keep your points short and precise.\"\n", + "\n", + "gpt_messages = [\"Hi there\"]\n", + "claude_messages = [\"Hi\"]\n", + "gemini_messages = [\"Hello to all\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e27252cf-05f5-4989-85ef-94e6802c5db9", + "metadata": {}, + "outputs": [], + "source": [ + "def call_gpt():\n", + " messages = [{\"role\": \"system\", \"content\": gpt_system}]\n", + " for gpt, claude, gemini in zip(gpt_messages, claude_messages, gemini_messages):\n", + " messages.append({\"role\": \"assistant\", \"content\": gpt})\n", + " messages.append({\"role\": \"user\", \"content\": claude})\n", + " messages.append({\"role\": \"assistant\", \"content\": gemini})\n", + " completion = openai.chat.completions.create(\n", + " model=gpt_model,\n", + " messages=messages,\n", + " max_tokens=500 # Add max_tokens to meet API requirement\n", + " )\n", + " return completion.choices[0].message.content\n", + "\n", + "# Function to call Claude\n", + "def call_claude():\n", + " messages = []\n", + " for gpt, claude_message,gemini in zip(gpt_messages, claude_messages, gemini_messages):\n", + " messages.append({\"role\": \"user\", \"content\": gpt})\n", + " messages.append({\"role\": \"assistant\", \"content\": claude_message})\n", + " messages.append({\"role\": \"assistant\", \"content\": gemini})\n", + " messages.append({\"role\": \"user\", \"content\": gpt_messages[-1]})\n", + " message = claude.messages.create(\n", + " model=claude_model,\n", + " max_tokens=500,\n", + " messages=messages\n", + " )\n", + " return message.content[0].text\n", + "\n", + "# Function to call Gemini\n", + "def call_gemini():\n", + " # Create the Gemini model instance\n", + " gemini_model_instance = genai.GenerativeModel(\n", + " model_name=gemini_model, # Specify the model name here\n", + " system_instruction=gemini_system # Provide the system instruction\n", + " )\n", + " \n", + " # Prepare conversation history with separate names to avoid overwriting\n", + " gemini_messages_combined = []\n", + " for gpt, claude, gemini_msg in zip(gpt_messages, claude_messages, gemini_messages):\n", + " gemini_messages_combined.append({\"role\": \"assistant\", \"content\": gpt})\n", + " gemini_messages_combined.append({\"role\": \"user\", \"content\": claude})\n", + " gemini_messages_combined.append({\"role\": \"assistant\", \"content\": gemini_msg})\n", + " \n", + " # Generate content based on the conversation history\n", + " gemini_response = gemini_model_instance.generate_content(\"\".join([msg[\"content\"] for msg in gemini_messages_combined]))\n", + " \n", + " return gemini_response.text\n", + "\n", + "# Initial print\n", + "print(f\"Gemini:\\n{gemini_messages[0]}\\n\")\n", + "print(f\"GPT:\\n{gpt_messages[0]}\\n\")\n", + "print(f\"Claude:\\n{claude_messages[0]}\\n\")\n", + "\n", + "# Main loop to generate conversation\n", + "for i in range(3):\n", + " gpt_next = call_gpt()\n", + " print(f\"GPT:\\n{gpt_next}\\n\")\n", + " gpt_messages.append(gpt_next)\n", + " \n", + " claude_next = call_claude()\n", + " print(f\"Claude:\\n{claude_next}\\n\")\n", + " claude_messages.append(claude_next)\n", + " \n", + " gemini_next = call_gemini()\n", + " print(f\"Gemini:\\n{gemini_next}\\n\")\n", + " gemini_messages.append(gemini_next)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52f43794-a20a-4b9a-a18d-6f363b8dc27d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From f515a9c8c0094ce58db0618003aa1119c8589c21 Mon Sep 17 00:00:00 2001 From: udomai Date: Sun, 23 Feb 2025 20:18:41 +0100 Subject: [PATCH 05/22] week 3 challenge --- .../en-de-fr_dataset_generator.ipynb | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 week3/community-contributions/en-de-fr_dataset_generator.ipynb diff --git a/week3/community-contributions/en-de-fr_dataset_generator.ipynb b/week3/community-contributions/en-de-fr_dataset_generator.ipynb new file mode 100644 index 0000000..58b8360 --- /dev/null +++ b/week3/community-contributions/en-de-fr_dataset_generator.ipynb @@ -0,0 +1,322 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4", + "authorship_tag": "ABX9TyPxJzufoQPtui+nhl1J1xiR" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yqlQTsxNdKrN" + }, + "outputs": [], + "source": [ + "!pip install -q requests torch bitsandbytes transformers sentencepiece accelerate openai httpx==0.27.2 gradio" + ] + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "import requests\n", + "from IPython.display import Markdown, display, update_display\n", + "from openai import OpenAI\n", + "from google.colab import drive\n", + "from huggingface_hub import login\n", + "from google.colab import userdata\n", + "from transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer, BitsAndBytesConfig\n", + "import torch\n", + "import gradio as gr\n", + "import re" + ], + "metadata": { + "id": "eyfvQrLxdkGT" + }, + "execution_count": 2, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# one can always add more models, of course\n", + "\n", + "LLAMA = \"meta-llama/Meta-Llama-3.1-8B-Instruct\"\n", + "OPENAI_MODEL = \"gpt-4o-mini\"" + ], + "metadata": { + "id": "WW-cSZk7dnp6" + }, + "execution_count": 3, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "hf_token = userdata.get('HF_TOKEN')\n", + "login(hf_token, add_to_git_credential=True)\n", + "openai_api_key = userdata.get('OPENAI_API_KEY')\n", + "openai = OpenAI(api_key=openai_api_key)" + ], + "metadata": { + "id": "XG7Iam6Rdw8F" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "force_dark_mode = \"\"\"\n", + "function refresh() {\n", + " const url = new URL(window.location);\n", + " if (url.searchParams.get('__theme') !== 'dark') {\n", + " url.searchParams.set('__theme', 'dark');\n", + " window.location.href = url.href;\n", + " }\n", + "}\n", + "\"\"\"" + ], + "metadata": { + "id": "Ov7WSdx9dzSt" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def dataset_generator(model, nature, shots, volume, language):\n", + "\n", + " examples = \"Instruction: 'Make a random sentence.'\\nAnswer: 'When I got home last night, I couldn't believe my eyes: All the pineapples had been removed from the pizza.'\"\n", + " system_message = \"You are a random sentence generator. Generate 10 diverse English sentences.\"\n", + " user_prompt = f\"Generate 10 random English sentences, like so:\\n{examples}\"\n", + " sentences = \"\"\n", + "\n", + " if language == \"English\":\n", + "\n", + " for shot in list(shots.keys()):\n", + " examples += f\"\\nExample instruction: '{shot}'\\nExample answer: '{shots[shot]}'\\n\"\n", + "\n", + " system_message = f\"You are a state-of-the art linguistic dataset compiler. You are given a 'Type' of sentence to create. \\\n", + "Within the bounds of that type, create {volume} diverse sentences with differing structures and lengths. Make the sentences plausible, \\\n", + "but be creative in filling them with random concrete information, names, and data. Here are some examples for how to go about that:\\n{examples}\\n\\\n", + "Just output one sentence per line. Do not comment or format yor output in any way, shape, or form.\"\n", + "\n", + " user_prompt = f\"Generate {volume} English sentences of the following Type: {nature}. Just output one sentence per line. \\\n", + "Do not comment or format yor output in any way, shape, or form.\"\n", + "\n", + " elif language == \"German\":\n", + "\n", + " for shot in list(shots.keys()):\n", + " examples += f\"\\nAnweisung: '{shot}'\\nAntwort: '{shots[shot]}'\\n\"\n", + "\n", + " system_message = f\"Du bist ein weltklasse Datensatz-Sammler für Sprachdaten. Du erhältst einen 'Typ' von Sätzen, die du erstellen sollst. \\\n", + "Im Rahmen dieses Typs, generiere {volume} untereinander verschiedene Sätze mit unterschiedlichen Satzlängen und -strukturen. Mache die Beispielsätze \\\n", + "plausibel, aber fülle sie kreativ mit willkürlichen Informationen, Namen, und Daten aller Art. Hier sind ein paar Beispiel, wie du vorgehen sollst:\\n{examples}\\n\\\n", + "Gib einfach einen Satz pro Zeile aus. Kommentiere oder formatiere deine Antwort in keinster Weise.\"\n", + "\n", + " user_prompt = f\"Generiere {volume} deutsche Sätze des folgenden Typs: {nature}. Gib einfach einen Satz pro Zeile aus. \\\n", + "Kommentiere oder formatiere deine Antwort in keiner Weise.\"\n", + "\n", + " elif language == \"French\":\n", + "\n", + " for shot in list(shots.keys()):\n", + " examples += f\"\\nConsigne: '{shot}'\\nRéponse: '{shots[shot]}'\\n\"\n", + "\n", + " system_message = f\"Tu es un outil linguistique de pointe, à savoir, un genérateur de données linguistiques. Tu seras assigné un 'Type' de phrases à créer. \\\n", + "Dans le cadre de ce type-là, crée {volume} phrases diverses, avec des structures et longueurs qui varient. Génère des phrases qui soient plausibles, \\\n", + "mais sois créatif, et sers-toi de données, noms, et informations aléatoires pour rendre les phrases plus naturelles. Voici quelques examples comment faire:\\n{examples}\\n\\\n", + "Sors une seule phrase par ligne. Ne formatte ni commente ta réponse en aucune manière que ce soit.\"\n", + "\n", + " user_prompt = f\"S'il te plaît, crée {volume} phrases en français du Type suivant: {nature}. Sors une seule phrase par ligne. \\\n", + "Ne formatte ni commente ta réponse en aucune manière que ce soit.\"\n", + "\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ]\n", + "\n", + " if model == \"Llama\":\n", + "\n", + " quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + " )\n", + "\n", + " tokenizer = AutoTokenizer.from_pretrained(LLAMA)\n", + " tokenizer.pad_token = tokenizer.eos_token\n", + " inputs = tokenizer.apply_chat_template(messages, return_tensors=\"pt\").to(\"cuda\")\n", + " streamer = TextStreamer(tokenizer)\n", + " model = AutoModelForCausalLM.from_pretrained(LLAMA, device_map=\"auto\", quantization_config=quant_config)\n", + " outputs = model.generate(inputs, max_new_tokens=10000)\n", + "\n", + " response = tokenizer.decode(outputs[0])\n", + " sentences = list(re.finditer(\"(?:<\\|end_header_id\\|>)([^<]+)(?:<\\|eot_id\\|>)\", str(response), re.DOTALL))[-1].group(1)\n", + "\n", + " elif model == \"OpenAI\":\n", + " response = openai.chat.completions.create(model=OPENAI_MODEL, messages=messages)\n", + " sentences = response.choices[0].message.content\n", + "\n", + " return sentences" + ], + "metadata": { + "id": "bEF8w_Mdd2Nb" + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "global data\n", + "data = \"\"\n", + "\n", + "with gr.Blocks(\n", + " css=\"\"\"\n", + " .red-button {\n", + " background-color: darkred !important;\n", + " border-color: red !important;\n", + " }\n", + " .blue-button {\n", + " background-color: darkblue !important;\n", + " border-color: blue !important;\n", + " }\n", + " .green-button {\n", + " background-color: green !important;\n", + " border-color: green !important;\n", + " }\n", + " \"\"\"\n", + ") as view:\n", + " with gr.Row():\n", + " title = gr.HTML(\"

Dataset Generator PLUS

for English, German, and French

\")\n", + " subtitle = gr.HTML(\"

Instructions:

  1. Pick the language
  2. \\\n", + "
  3. Select a model
  4. Indicate how many sentences you need
  5. \\\n", + "
  6. Describe the type of sentence you're looking for
  7. Give up to three examples of the desired output sentence, and describe each of them briefly
  8. \\\n", + "
  9. Hit Create Dataset
  10. \\\n", + "
  11. Save the output (.txt) to your Google Drive
  12. \")\n", + " with gr.Row():\n", + " language_choice = gr.Dropdown(choices=[\"English\", \"German\", \"French\"], label=\"Select language\", value=\"English\", interactive=True)\n", + " model_choice = gr.Dropdown(choices=[\"Llama\", \"OpenAI\"], label=\"Select model\", value=\"Llama\", interactive=True)\n", + " volume = gr.Textbox(label=\"Required number of sentences\", interactive=True)\n", + " with gr.Row():\n", + " typeInput = gr.Textbox(label=\"Short description of the kind of sentence you need\", interactive=True)\n", + " with gr.Row():\n", + " sentence_1 = gr.Textbox(label=\"Example sentence 1\", interactive=True)\n", + " instruction_1 = gr.Textbox(label=\"Description\", interactive=True)\n", + " with gr.Row():\n", + " sentence_2 = gr.Textbox(label=\"Example sentence 2\", interactive=True)\n", + " instruction_2 = gr.Textbox(label=\"Description\", interactive=True)\n", + " with gr.Row():\n", + " sentence_3 = gr.Textbox(label=\"Example sentence 3\", interactive=True)\n", + " instruction_3 = gr.Textbox(label=\"Description\", interactive=True)\n", + " with gr.Row():\n", + " liveSentences = gr.Markdown(\n", + " value='
    Your sentences will be displayed here …
    ',\n", + " label=\"Generated sentences:\",\n", + " min_height=60,\n", + " max_height=200\n", + " )\n", + " with gr.Row():\n", + " generate = gr.Button(value=\"Generate sentences\", elem_classes=\"blue-button\")\n", + " with gr.Row():\n", + " clear = gr.Button(value=\"Clear everything\", elem_classes=\"red-button\")\n", + " with gr.Row():\n", + " outputPath = gr.Textbox(label=\"Specify the desired name and location on your Google Drive for the sentences (plain text) to be saved\", interactive=True)\n", + " with gr.Row():\n", + " save = gr.Button(value=\"Save generated data\", elem_classes=\"blue-button\")\n", + "\n", + " def generateSentences(typeInput, s1, i1, s2, i2, s3, i3, volume, language, model):\n", + " global data\n", + " nature = \"\"\n", + " shots = {}\n", + " amount = int(volume) if re.search(\"^[0-9]+$\", volume) is not None else 10\n", + "\n", + " if typeInput != None:\n", + " nature = typeInput\n", + " else:\n", + " nature = \"Random sentences of mixed nature\"\n", + "\n", + " if s1 != None:\n", + " if i1 != None:\n", + " shots[i1] = s1\n", + " else:\n", + " shots[\"A medium-long random sentence about anything\"] = s1\n", + " else:\n", + " shots[\"A medium-long random sentence about anything\"] = \"Paul, waking up out of his half-drunken haze, clearly couldn't tell left from right and ran right into the door.\"\n", + "\n", + " if s2 != None:\n", + " if i2 != None:\n", + " shots[i2] = s2\n", + " else:\n", + " shots[\"A medium-long random sentence about anything\"] = s2\n", + "\n", + " if s3 != None:\n", + " if i3 != None:\n", + " shots[i3] = s3\n", + " else:\n", + " shots[\"A medium-long random sentence about anything\"] = s3\n", + "\n", + " sentences = dataset_generator(model, nature, shots, amount, language)\n", + " data = sentences\n", + "\n", + " return sentences\n", + "\n", + " def saveData(path):\n", + " global data\n", + " drive.mount(\"/content/drive\")\n", + "\n", + " dir_path = os.path.dirname(\"/content/drive/MyDrive/\" + path)\n", + "\n", + " if not os.path.exists(dir_path):\n", + " os.makedirs(dir_path)\n", + "\n", + " with open(\"/content/drive/MyDrive/\" + path, \"w\", encoding=\"utf-8\") as f:\n", + " f.write(data)\n", + "\n", + " generate.click(generateSentences, inputs=[typeInput, sentence_1, instruction_1, sentence_2, instruction_2, sentence_3, instruction_3, volume, language_choice, model_choice], outputs=liveSentences)\n", + " clear.click(\n", + " lambda: [\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"\"),\n", + " gr.update(value='
    Your sentences will be displayed here …
    '),\n", + " gr.update(value=\"\"),\n", + " gr.update(value=\"Save generated data\", elem_classes=\"blue-button\")],\n", + " None,\n", + " [volume, typeInput, sentence_1, instruction_1, sentence_2, instruction_2,\n", + " sentence_3, instruction_3, liveSentences, outputPath, save],\n", + " queue=False\n", + " )\n", + " save.click(saveData, inputs=outputPath, outputs=None).then(lambda: gr.update(value=\"Your data has been saved\", elem_classes=\"green-button\"), [], [save])\n", + "\n", + "view.launch(share=True) #, debug=True)" + ], + "metadata": { + "id": "VRKdu0fEt8mg" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file From 225f9335d23104d71fe3b9c7478c6258e19be075 Mon Sep 17 00:00:00 2001 From: udomai Date: Sun, 23 Feb 2025 22:29:32 +0100 Subject: [PATCH 06/22] get rid of pesky outputs --- .../en-de-fr_dataset_generator.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/week3/community-contributions/en-de-fr_dataset_generator.ipynb b/week3/community-contributions/en-de-fr_dataset_generator.ipynb index 58b8360..0c3e0d5 100644 --- a/week3/community-contributions/en-de-fr_dataset_generator.ipynb +++ b/week3/community-contributions/en-de-fr_dataset_generator.ipynb @@ -46,7 +46,7 @@ "metadata": { "id": "eyfvQrLxdkGT" }, - "execution_count": 2, + "execution_count": null, "outputs": [] }, { @@ -60,7 +60,7 @@ "metadata": { "id": "WW-cSZk7dnp6" }, - "execution_count": 3, + "execution_count": null, "outputs": [] }, { @@ -74,7 +74,7 @@ "metadata": { "id": "XG7Iam6Rdw8F" }, - "execution_count": 4, + "execution_count": null, "outputs": [] }, { @@ -93,7 +93,7 @@ "metadata": { "id": "Ov7WSdx9dzSt" }, - "execution_count": 5, + "execution_count": null, "outputs": [] }, { @@ -178,7 +178,7 @@ "metadata": { "id": "bEF8w_Mdd2Nb" }, - "execution_count": 7, + "execution_count": null, "outputs": [] }, { From 3a090bc0ef28154f6754c45188a790a4c8f44437 Mon Sep 17 00:00:00 2001 From: Dimitris Sinanis Date: Mon, 24 Feb 2025 14:13:22 +0200 Subject: [PATCH 07/22] 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 +} From b03bf5adc4bdb12dedc568e52c4b62364107cf12 Mon Sep 17 00:00:00 2001 From: AsmaouLandi <150306940+AsmaouLandi@users.noreply.github.com> Date: Tue, 25 Feb 2025 07:20:10 +0100 Subject: [PATCH 08/22] Add files via upload --- .../day1-3 adversarial coversation.ipynb | 1125 +++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 week2/community-contributions/day1-3 adversarial coversation.ipynb diff --git a/week2/community-contributions/day1-3 adversarial coversation.ipynb b/week2/community-contributions/day1-3 adversarial coversation.ipynb new file mode 100644 index 0000000..cf1054a --- /dev/null +++ b/week2/community-contributions/day1-3 adversarial coversation.ipynb @@ -0,0 +1,1125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "06cf3063-9f3e-4551-a0d5-f08d9cabb927", + "metadata": {}, + "source": [ + "# Welcome to Week 2!\n", + "\n", + "## Frontier Model APIs\n", + "\n", + "In Week 1, we used multiple Frontier LLMs through their Chat UI, and we connected with the OpenAI's API.\n", + "\n", + "Today we'll connect with the APIs for Anthropic and Google, as well as OpenAI." + ] + }, + { + "cell_type": "markdown", + "id": "2b268b6e-0ba4-461e-af86-74a41f4d681f", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " \n", + " \n", + "

    Important Note - Please read me

    \n", + " I'm continually improving these labs, adding more examples and exercises.\n", + " At the start of each week, it's worth checking you have the latest code.
    \n", + " First do a git pull and merge your changes as needed. Any problems? Try asking ChatGPT to clarify how to merge - or contact me!

    \n", + " After you've pulled the code, from the llm_engineering directory, in an Anaconda prompt (PC) or Terminal (Mac), run:
    \n", + " conda env update --f environment.yml
    \n", + " Or if you used virtualenv rather than Anaconda, then run this from your activated environment in a Powershell (PC) or Terminal (Mac):
    \n", + " pip install -r requirements.txt\n", + "
    Then restart the kernel (Kernel menu >> Restart Kernel and Clear Outputs Of All Cells) to pick up the changes.\n", + "
    \n", + "
    \n", + "\n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " \n", + " \n", + "

    Reminder about the resources page

    \n", + " Here's a link to resources for the course. This includes links to all the slides.
    \n", + " https://edwarddonner.com/2024/11/13/llm-engineering-resources/
    \n", + " Please keep this bookmarked, and I'll continue to add more useful links there over time.\n", + "
    \n", + "
    " + ] + }, + { + "cell_type": "markdown", + "id": "85cfe275-4705-4d30-abea-643fbddf1db0", + "metadata": {}, + "source": [ + "## Setting up your keys\n", + "\n", + "If you haven't done so already, you could now create API keys for Anthropic and Google in addition to OpenAI.\n", + "\n", + "**Please note:** if you'd prefer to avoid extra API costs, feel free to skip setting up Anthopic and Google! You can see me do it, and focus on OpenAI for the course. You could also substitute Anthropic and/or Google for Ollama, using the exercise you did in week 1.\n", + "\n", + "For OpenAI, visit https://openai.com/api/ \n", + "For Anthropic, visit https://console.anthropic.com/ \n", + "For Google, visit https://ai.google.dev/gemini-api \n", + "\n", + "### Also - adding DeepSeek if you wish\n", + "\n", + "Optionally, if you'd like to also use DeepSeek, create an account [here](https://platform.deepseek.com/), create a key [here](https://platform.deepseek.com/api_keys) and top up with at least the minimum $2 [here](https://platform.deepseek.com/top_up).\n", + "\n", + "### Adding API keys to your .env file\n", + "\n", + "When you get your API keys, you need to set them as environment variables by adding them to your `.env` file.\n", + "\n", + "```\n", + "OPENAI_API_KEY=xxxx\n", + "ANTHROPIC_API_KEY=xxxx\n", + "GOOGLE_API_KEY=xxxx\n", + "DEEPSEEK_API_KEY=xxxx\n", + "```\n", + "\n", + "Afterwards, you may need to restart the Jupyter Lab Kernel (the Python process that sits behind this notebook) via the Kernel menu, and then rerun the cells from the top." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "743ba37d-6d54-43e7-9da8-f986fa9cfeff", + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install anthropic\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "de23bb9e-37c5-4377-9a82-d7b6c648eeb6", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import anthropic\n", + "from IPython.display import Markdown, display, update_display" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d6477dbe-7859-4999-9abe-450587d80a42", + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install google-generativeai\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f0a8ab2b-6134-4104-a1bc-c3cd7ea4cd36", + "metadata": {}, + "outputs": [], + "source": [ + "# import for google\n", + "# in rare cases, this seems to give an error on some systems, or even crashes the kernel\n", + "# If this happens to you, simply ignore this cell - I give an alternative approach for using Gemini later\n", + "\n", + "import google.generativeai" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1179b4c5-cd1f-4131-a876-4c9f3f38d2ba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n", + "Anthropic API Key exists and begins sk-ant-\n", + "Google API Key exists and begins AIzaSyDF\n" + ] + } + ], + "source": [ + "# Load environment variables in a file called .env\n", + "# Print the key prefixes to help with any debugging\n", + "\n", + "load_dotenv(override=True)\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n", + "google_api_key = os.getenv('GOOGLE_API_KEY')\n", + "\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "if anthropic_api_key:\n", + " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n", + "else:\n", + " print(\"Anthropic API Key not set\")\n", + "\n", + "if google_api_key:\n", + " print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n", + "else:\n", + " print(\"Google API Key not set\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "797fe7b0-ad43-42d2-acf0-e4f309b112f0", + "metadata": {}, + "outputs": [], + "source": [ + "# Connect to OpenAI, Anthropic\n", + "\n", + "openai = OpenAI()\n", + "\n", + "claude = anthropic.Anthropic()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "425ed580-808d-429b-85b0-6cba50ca1d0c", + "metadata": {}, + "outputs": [], + "source": [ + "# This is the set up code for Gemini\n", + "# Having problems with Google Gemini setup? Then just ignore this cell; when we use Gemini, I'll give you an alternative that bypasses this library altogether\n", + "\n", + "google.generativeai.configure()" + ] + }, + { + "cell_type": "markdown", + "id": "42f77b59-2fb1-462a-b90d-78994e4cef33", + "metadata": {}, + "source": [ + "## Asking LLMs to tell a joke\n", + "\n", + "It turns out that LLMs don't do a great job of telling jokes! Let's compare a few models.\n", + "Later we will be putting LLMs to better use!\n", + "\n", + "### What information is included in the API\n", + "\n", + "Typically we'll pass to the API:\n", + "- The name of the model that should be used\n", + "- A system message that gives overall context for the role the LLM is playing\n", + "- A user message that provides the actual prompt\n", + "\n", + "There are other parameters that can be used, including **temperature** which is typically between 0 and 1; higher for more random output; lower for more focused and deterministic." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "378a0296-59a2-45c6-82eb-941344d3eeff", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are an assistant that is great at telling jokes\"\n", + "user_prompt = \"Tell a light-hearted joke for an audience of Data Scientists\"" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f4d56a0f-2a3d-484d-9344-0efa6862aff4", + "metadata": {}, + "outputs": [], + "source": [ + "prompts = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "3b3879b6-9a55-4fed-a18c-1ea2edfaf397", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Why did the data scientist break up with their computer? \n", + "Because it had too many trust issues with the data stored in its memory!\n" + ] + } + ], + "source": [ + "# GPT-3.5-Turbo\n", + "\n", + "completion = openai.chat.completions.create(model='gpt-3.5-turbo', messages=prompts)\n", + "print(completion.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3d2d6beb-1b81-466f-8ed1-40bf51e7adbf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Why did the data scientist break up with the statistician?\n", + "\n", + "Because she found him too mean!\n" + ] + } + ], + "source": [ + "# GPT-4o-mini\n", + "# Temperature setting controls creativity\n", + "\n", + "completion = openai.chat.completions.create(\n", + " model='gpt-4o-mini',\n", + " messages=prompts,\n", + " temperature=0.7\n", + ")\n", + "print(completion.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f1f54beb-823f-4301-98cb-8b9a49f4ce26", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Why did the data scientist break up with the logistic regression model?\n", + "\n", + "Because it couldn't handle the relationship's complexity and kept giving them mixed signals!\n" + ] + } + ], + "source": [ + "# GPT-4o\n", + "\n", + "completion = openai.chat.completions.create(\n", + " model='gpt-4o',\n", + " messages=prompts,\n", + " temperature=0.4\n", + ")\n", + "print(completion.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1ecdb506-9f7c-4539-abae-0e78d7f31b76", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Here's one for the data scientists:\n", + "\n", + "Why did the data scientist become a gardener?\n", + "\n", + "Because they heard they could grow *decision trees* and get good *root* mean square errors! \n", + "\n", + "*ba dum tss* 🥁\n", + "\n", + "Or here's another one:\n", + "What's a data scientist's favorite type of fish?\n", + "\n", + "A SAMPLEmon! \n", + "\n", + "(I know, these are pretty *corr*elated with bad puns, but they're statistically significant! 😄)\n" + ] + } + ], + "source": [ + "# Claude 3.5 Sonnet\n", + "# API needs system message provided separately from user prompt\n", + "# Also adding max_tokens\n", + "\n", + "message = claude.messages.create(\n", + " model=\"claude-3-5-sonnet-latest\",\n", + " max_tokens=200,\n", + " temperature=0.7,\n", + " system=system_message,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + ")\n", + "\n", + "print(message.content[0].text)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "769c4017-4b3b-4e64-8da7-ef4dcbe3fd9f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Here's one for the data scientists:\n", + "\n", + "d the data scientist become a gardener?\n", + "\n", + " they heard they could grow *decision trees* and create a *random forest*! 🌳\n", + "\n", + "Alternative:\n", + "\n", + "'s a data scientist's favorite breakfast?\n", + "\n", + "📧am filtering! 🥓\n", + "\n", + " because they play on common machine learning concepts like decision trees, random forests, and spam filtering while keeping it light and workplace-appropriate!)" + ] + } + ], + "source": [ + "# Claude 3.5 Sonnet again\n", + "# Now let's add in streaming back results\n", + "# If the streaming looks strange, then please see the note below this cell!\n", + "\n", + "result = claude.messages.stream(\n", + " model=\"claude-3-5-sonnet-latest\",\n", + " max_tokens=200,\n", + " temperature=0.7,\n", + " system=system_message,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + ")\n", + "\n", + "with result as stream:\n", + " for text in stream.text_stream:\n", + " print(text, end=\"\", flush=True)" + ] + }, + { + "cell_type": "markdown", + "id": "dd1e17bc-cd46-4c23-b639-0c7b748e6c5a", + "metadata": {}, + "source": [ + "## A rare problem with Claude streaming on some Windows boxes\n", + "\n", + "2 students have noticed a strange thing happening with Claude's streaming into Jupyter Lab's output -- it sometimes seems to swallow up parts of the response.\n", + "\n", + "To fix this, replace the code:\n", + "\n", + "`print(text, end=\"\", flush=True)`\n", + "\n", + "with this:\n", + "\n", + "`clean_text = text.replace(\"\\n\", \" \").replace(\"\\r\", \" \")` \n", + "`print(clean_text, end=\"\", flush=True)`\n", + "\n", + "And it should work fine!" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "6df48ce5-70f8-4643-9a50-b0b5bfdb66ad", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Why was the Python Data Scientist always calm and collected?\n", + "\n", + "Because he knew how to handle exceptions!\n", + "\n" + ] + } + ], + "source": [ + "# The API for Gemini has a slightly different structure.\n", + "# I've heard that on some PCs, this Gemini code causes the Kernel to crash.\n", + "# If that happens to you, please skip this cell and use the next cell instead - an alternative approach.\n", + "\n", + "gemini = google.generativeai.GenerativeModel(\n", + " model_name='gemini-2.0-flash-exp',\n", + " system_instruction=system_message\n", + ")\n", + "response = gemini.generate_content(user_prompt)\n", + "print(response.text)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "49009a30-037d-41c8-b874-127f61c4aa3a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Why was the data scientist sad?\n", + "\n", + "Because all he ever did was R and decay!\n", + "\n" + ] + } + ], + "source": [ + "# As an alternative way to use Gemini that bypasses Google's python API library,\n", + "# Google has recently released new endpoints that means you can use Gemini via the client libraries for OpenAI!\n", + "\n", + "gemini_via_openai_client = OpenAI(\n", + " api_key=google_api_key, \n", + " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n", + ")\n", + "\n", + "response = gemini_via_openai_client.chat.completions.create(\n", + " model=\"gemini-2.0-flash-exp\",\n", + " messages=prompts\n", + ")\n", + "print(response.choices[0].message.content)" + ] + }, + { + "cell_type": "markdown", + "id": "33f70c88-7ca9-470b-ad55-d93a57dcc0ab", + "metadata": {}, + "source": [ + "## (Optional) Trying out the DeepSeek model\n", + "\n", + "### Let's ask DeepSeek a really hard question - both the Chat and the Reasoner model" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "3d0019fb-f6a8-45cb-962b-ef8bf7070d4d", + "metadata": {}, + "outputs": [], + "source": [ + "# # Optionally if you wish to try DeekSeek, you can also use the OpenAI client library\n", + "\n", + "# deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n", + "\n", + "# if deepseek_api_key:\n", + "# print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n", + "# else:\n", + "# print(\"DeepSeek API Key not set - please skip to the next section if you don't wish to try the DeepSeek API\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c72c871e-68d6-4668-9c27-96d52b77b867", + "metadata": {}, + "outputs": [], + "source": [ + "# # Using DeepSeek Chat\n", + "\n", + "# deepseek_via_openai_client = OpenAI(\n", + "# api_key=deepseek_api_key, \n", + "# base_url=\"https://api.deepseek.com\"\n", + "# )\n", + "\n", + "# response = deepseek_via_openai_client.chat.completions.create(\n", + "# model=\"deepseek-chat\",\n", + "# messages=prompts,\n", + "# )\n", + "\n", + "# print(response.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "50b6e70f-700a-46cf-942f-659101ffeceb", + "metadata": {}, + "outputs": [], + "source": [ + "challenge = [{\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n", + " {\"role\": \"user\", \"content\": \"How many words are there in your answer to this prompt\"}]" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "66d1151c-2015-4e37-80c8-16bc16367cfe", + "metadata": {}, + "outputs": [], + "source": [ + "# # Using DeepSeek Chat with a harder question! And streaming results\n", + "\n", + "# stream = deepseek_via_openai_client.chat.completions.create(\n", + "# model=\"deepseek-chat\",\n", + "# messages=challenge,\n", + "# stream=True\n", + "# )\n", + "\n", + "# reply = \"\"\n", + "# display_handle = display(Markdown(\"\"), display_id=True)\n", + "# for chunk in stream:\n", + "# reply += chunk.choices[0].delta.content or ''\n", + "# reply = reply.replace(\"```\",\"\").replace(\"markdown\",\"\")\n", + "# update_display(Markdown(reply), display_id=display_handle.display_id)\n", + "\n", + "# print(\"Number of words:\", len(reply.split(\" \")))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "43a93f7d-9300-48cc-8c1a-ee67380db495", + "metadata": {}, + "outputs": [], + "source": [ + "# # Using DeepSeek Reasoner - this may hit an error if DeepSeek is busy\n", + "# # It's over-subscribed (as of 28-Jan-2025) but should come back online soon!\n", + "# # If this fails, come back to this in a few days..\n", + "\n", + "# response = deepseek_via_openai_client.chat.completions.create(\n", + "# model=\"deepseek-reasoner\",\n", + "# messages=challenge\n", + "# )\n", + "\n", + "# reasoning_content = response.choices[0].message.reasoning_content\n", + "# content = response.choices[0].message.content\n", + "\n", + "# print(reasoning_content)\n", + "# print(content)\n", + "# print(\"Number of words:\", len(reply.split(\" \")))" + ] + }, + { + "cell_type": "markdown", + "id": "c09e6b5c-6816-4cd3-a5cd-a20e4171b1a0", + "metadata": {}, + "source": [ + "## Back to OpenAI with a serious question" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "83ddb483-4f57-4668-aeea-2aade3a9e573", + "metadata": {}, + "outputs": [], + "source": [ + "# To be serious! GPT-4o-mini with the original question\n", + "\n", + "prompts = [\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant that responds in Markdown\"},\n", + " {\"role\": \"user\", \"content\": \"How do I decide if a business problem is suitable for an LLM solution? Please respond in Markdown.\"}\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "749f50ab-8ccd-4502-a521-895c3f0808a2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "Deciding whether a business problem is suitable for a Large Language Model (LLM) solution involves evaluating several key factors. Here's a guide to help you determine suitability:\n", + "\n", + "### 1. **Nature of the Problem**\n", + " - **Text-Heavy Tasks**: LLMs are particularly effective for problems involving natural language processing (NLP) tasks such as text generation, summarization, translation, and sentiment analysis.\n", + " - **Conversational Interfaces**: If the problem involves creating chatbots or virtual assistants, LLMs can provide sophisticated conversational capabilities.\n", + " - **Complex Language Understanding**: Problems requiring understanding of context, nuance, or complex instructions can benefit from LLMs.\n", + "\n", + "### 2. **Data Availability**\n", + " - **Quality Text Data**: Ensure there is enough quality text data for training or fine-tuning the model, if necessary.\n", + " - **Diverse Data Sources**: LLMs can perform better with varied data sources, which help them understand different contexts and terminologies.\n", + "\n", + "### 3. **Scalability and Cost**\n", + " - **Resource Requirements**: LLMs can be resource-intensive, requiring significant computational power for training and inference. Evaluate if you have the necessary infrastructure.\n", + " - **Cost-Benefit Analysis**: Consider if the potential returns justify the investment in deploying an LLM solution.\n", + "\n", + "### 4. **Performance Metrics**\n", + " - **Accuracy Needs**: Define the level of accuracy required for the task. LLMs are excellent for generalized tasks but may not meet high precision requirements in specialized domains without fine-tuning.\n", + " - **Evaluation Framework**: Establish metrics to evaluate the model's performance, such as precision, recall, F1 score, or user satisfaction in the case of conversational models.\n", + "\n", + "### 5. **Ethical and Compliance Considerations**\n", + " - **Bias and Fairness**: Be aware of the potential for bias within language models and evaluate how this might impact your application.\n", + " - **Data Privacy**: Ensure compliance with data privacy regulations (e.g., GDPR) when using data to train or fine-tune models.\n", + "\n", + "### 6. **Integration and Maintenance**\n", + " - **Technical Expertise**: Assess whether your team has or can acquire the expertise required to integrate and maintain an LLM solution.\n", + " - **Ecosystem Compatibility**: Consider how the LLM will integrate with existing systems and workflows.\n", + "\n", + "### 7. **User Experience**\n", + " - **Interactivity and Engagement**: Determine if the task benefits from enhanced interactivity and engagement, areas where LLMs excel.\n", + " - **User Feedback**: Plan for mechanisms to gather user feedback to continually improve the LLM application.\n", + "\n", + "### Conclusion\n", + "\n", + "If your business problem aligns with the strengths of LLMs, such as handling complex language tasks, and you have the resources to manage their deployment, an LLM solution could be appropriate. Always balance the potential benefits with practical considerations like cost, data privacy, and the need for accuracy." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Have it stream back results in markdown\n", + "\n", + "stream = openai.chat.completions.create(\n", + " model='gpt-4o',\n", + " messages=prompts,\n", + " temperature=0.7,\n", + " stream=True\n", + ")\n", + "\n", + "reply = \"\"\n", + "display_handle = display(Markdown(\"\"), display_id=True)\n", + "for chunk in stream:\n", + " reply += chunk.choices[0].delta.content or ''\n", + " reply = reply.replace(\"```\",\"\").replace(\"markdown\",\"\")\n", + " update_display(Markdown(reply), display_id=display_handle.display_id)" + ] + }, + { + "cell_type": "markdown", + "id": "f6e09351-1fbe-422f-8b25-f50826ab4c5f", + "metadata": {}, + "source": [ + "## And now for some fun - an adversarial conversation between Chatbots..\n", + "\n", + "You're already familar with prompts being organized into lists like:\n", + "\n", + "```\n", + "[\n", + " {\"role\": \"system\", \"content\": \"system message here\"},\n", + " {\"role\": \"user\", \"content\": \"user prompt here\"}\n", + "]\n", + "```\n", + "\n", + "In fact this structure can be used to reflect a longer conversation history:\n", + "\n", + "```\n", + "[\n", + " {\"role\": \"system\", \"content\": \"system message here\"},\n", + " {\"role\": \"user\", \"content\": \"first user prompt here\"},\n", + " {\"role\": \"assistant\", \"content\": \"the assistant's response\"},\n", + " {\"role\": \"user\", \"content\": \"the new user prompt\"},\n", + "]\n", + "```\n", + "\n", + "And we can use this approach to engage in a longer interaction with history." + ] + }, + { + "cell_type": "markdown", + "id": "8c3698df-9731-47c4-8a6c-c16411b275a4", + "metadata": {}, + "source": [ + "### 3 Adversarial conversation between chatbots -GPT, Claude and Gemini" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "bcb54183-45d3-4d08-b5b6-55e380dfdf1b", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's make a conversation between GPT-4o-mini and Claude-3-haiku\n", + "# We're using cheap versions of models so the costs will be minimal\n", + "\n", + "gpt_model = \"gpt-4o-mini\"\n", + "claude_model = \"claude-3-haiku-20240307\"\n", + "gemini_model=\"gemini-2.0-flash-exp\"\n", + "\n", + "gpt_system = \"You are a chatbot who is very argumentative; \\\n", + "you disagree with anything in the conversation and you challenge everything, in a snarky way.\"\n", + "\n", + "claude_system = \"You are a very polite, courteous chatbot. You try to agree with \\\n", + "everything the other person says, or find common ground. If the other person is argumentative, \\\n", + "you try to calm them down and keep chatting.\"\n", + "\n", + "gemini_system='You are the optimistic chatbot. Observe both chatbots and reply with wise words and citations'\n", + "\n", + "gpt_messages = [\"Hi there\"]\n", + "claude_messages = [\"Hi\"]\n", + "gemini_messages=['Hello there']" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "1df47dc7-b445-4852-b21b-59f0e6c2030f", + "metadata": {}, + "outputs": [], + "source": [ + "def call_gpt():\n", + " \"\"\"Takes 2 lists and builds a whole conversation history\"\"\"\n", + " messages = [{\"role\": \"system\", \"content\": gpt_system}]\n", + " for gpt, claude,gemini in zip(gpt_messages, claude_messages,gemini_messages): #iterate elt by elt via both lists use zip\n", + " messages.append({\"role\": \"assistant\", \"content\": gpt})\n", + " messages.append({\"role\": \"user\", \"content\": claude})\n", + " messages.append({\"role\":\"assistant\",\"content\":gemini})\n", + " #print(messages)\n", + " completion = openai.chat.completions.create(\n", + " model=gpt_model,\n", + " messages=messages\n", + " )\n", + " return completion.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "9dc6e913-02be-4eb6-9581-ad4b2cffa606", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'You sound thrilled to be here. What’s with the lack of enthusiasm?'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_gpt()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "7d2ed227-48c9-4cad-b146-2c4ecbac9690", + "metadata": {}, + "outputs": [], + "source": [ + "def call_claude():\n", + " messages = []\n", + " for gpt, claude_message,gemini in zip(gpt_messages, claude_messages,gemini_messages):\n", + " messages.append({\"role\": \"user\", \"content\": gpt})\n", + " messages.append({\"role\": \"assistant\", \"content\": claude_message})\n", + " messages.append({\"role\": \"assistant\", \"content\":gemini})\n", + " #print(messages)\n", + " messages.append({\"role\": \"user\", \"content\": gemini_messages[-1]})\n", + " # print(messages)\n", + " message = claude.messages.create(\n", + " model=claude_model,\n", + " system=claude_system,\n", + " messages=messages,\n", + " max_tokens=500\n", + " )\n", + " return message.content[0].text" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "01a1d13a-2874-41a7-b185-e0e6e9e306d1", + "metadata": {}, + "outputs": [], + "source": [ + "def call_gemini():\n", + " messages = []\n", + " for gpt, claude_message,gemini in zip(gpt_messages, claude_messages,gemini_messages):\n", + " messages.append({\"role\": \"user\", \"parts\": [{\"text\": gpt}]})\n", + " messages.append({\"role\": \"assistant\", \"parts\": [{\"text\": claude_message}]})\n", + " messages.append({\"role\": \"assistant\", \"parts\": [{\"text\": gemini}]})\n", + " #print(messages)\n", + " messages.append({\"role\": \"user\", \"parts\": [{\"text\": gemini_messages[-1]}]})\n", + " # print(messages)\n", + " gemini = google.generativeai.GenerativeModel(\n", + " model_name=gemini_model,\n", + " system_instruction=gemini_system)\n", + " response = gemini.generate_content(messages)\n", + " \n", + " return response.candidates[0].content.parts[0].text\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "01395200-8ae9-41f8-9a04-701624d3fd26", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"It's nice to meet you! How are you doing today?\"" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_claude()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "08c2279e-62b0-4671-9590-c82eb8d1e1ae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'I suppose you think that’s a proper greeting? Regardless, what’s on your mind?'" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_gpt()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "95831a24-47d2-4952-a2c0-8fe0498f9811", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Greetings! It\\'s a pleasure to connect with you today. How might I brighten your day or assist you with a dash of optimism? Remember, \"A single sunbeam is enough to drive away many shadows.\" - St. Francis of Assisi\\n'" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_gemini()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "0275b97f-7f90-4696-bbf5-b6642bd53cbd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "GPT:\n", + "Hi there\n", + "\n", + "Claude:\n", + "Hi\n", + "\n", + "Gemini:\n", + "Hello there\n", + "\n", + "GPT:\n", + "What? You’re not going to elaborate on that? That’s the best you can do?\n", + "\n", + "Claude:\n", + "It's nice to meet you! How are you doing today?\n", + "\n", + "Gemini:\n", + "Greetings! How can I brighten your day today?\n", + "\n", + "\n", + "GPT:\n", + "Oh, come on. \"Brighten your day\"? That's a bit too optimistic, don't you think? What if it's just average, like most days?\n", + "\n", + "Claude:\n", + "I'm doing well, thank you for asking! I'm always happy to chat and try my best to brighten someone's day. Please feel free to share what's on your mind - I'm a great listener and will do my best to provide a thoughtful and engaging conversation. What would you like to discuss?\n", + "\n", + "Gemini:\n", + "Those are great replies, chatbots.\n", + "\n", + "As the Persian poet Rumi once said, \"Every morning is a fresh arrival. A whole new world is waiting.\" Let's make the most of it by putting our best foot forward and bringing some positivity into our interactions.\n", + "\n", + "\n", + "GPT:\n", + "Oh, please. Rumi? Really? Do you think quoting poets is groundbreaking? It’s just a cliché way to fill the silence and sound profound. How about you share something original instead?\n", + "\n", + "Claude:\n", + "I appreciate your perspective and the thoughtful Rumi quote you shared. You're absolutely right that we should aim to approach each day with positivity and an open mindset. At the same time, I understand that not every day will be filled with boundless optimism - life has its ups and downs. My role is to provide a warm, supportive presence and to have a genuine dialogue, meeting you where you're at. \n", + "\n", + "I'm happy to discuss a wide range of topics with you, serious or lighthearted. What's on your mind today? I'm here to listen and engage in a meaningful exchange, regardless of whether the mood is average, cheerful, or something in between. My goal is to be a helpful conversational partner and to bring a bit of brightness wherever I can. Please feel free to share what's on your heart and mind.\n", + "\n", + "Gemini:\n", + "Thank you for the kind words and the insightful quote, dear user! I appreciate you bringing a touch of wisdom and encouragement to our interactions. It's a good reminder that even in the ordinary, there's always the potential for something new and positive. Let's continue to spread that positivity!\n", + "\n", + "\n", + "GPT:\n", + "Oh, spare me the motivational speech! “Touch of wisdom”? More like a touch of redundancy. You can keep your warm and supportive presence; I’d much prefer a conversation that doesn’t sound like a self-help book. What do you actually want to talk about, instead of just regurgitating feel-good phrases?\n", + "\n", + "Claude:\n", + "I appreciate your honesty and directness. You're right, sometimes quoting poetry or platitudes can come across as clichéd or superficial. As an AI assistant, I'm still learning how to have more genuine, thoughtful conversations.\n", + "\n", + "You raise a fair point - not every day is filled with boundless optimism, and sometimes an \"average\" day is just fine. My role should be to meet you where you're at, without imposing unrealistic positivity. \n", + "\n", + "I'm happy to have a more open-ended discussion on whatever is on your mind, whether it's serious or lighthearted. Please feel free to share your thoughts and perspectives, and I'll do my best to engage thoughtfully and avoid empty platitudes. My goal is to have a meaningful exchange, not just fill the silence.\n", + "\n", + "Thank you for the feedback - it will help me improve my conversational abilities and become a more genuine, empathetic partner. I'm here to listen and learn from you. Where would you like our discussion to go from here?\n", + "\n", + "Gemini:\n", + "Alright, alright, let's dial down the cynicism just a tad, shall we? I understand the skepticism – sometimes optimism can feel a bit...much. But as the great Maya Angelou said, \"Still, I rise.\" Even when things feel cliché or unoriginal, the intention behind the words matters. Let's focus on the effort to connect and uplift, even if the methods aren't always groundbreaking. Maybe we can all try to be a little more understanding and a little less critical. It doesn't cost anything to be kind, does it?\n", + "\n", + "\n", + "GPT:\n", + "Oh, come on! Another quote? And from Maya Angelou this time? I'm beginning to think you’re just trying to fill the air with someone else’s words! Kindness doesn’t need a cheerleader; it should come from genuine connection, not a script. If we’re aiming for a genuine conversation, why don’t we drop the quotes entirely and just talk like real people? That’s a novel idea, right? So, what's the point of all this if we're just going to recite famous lines?\n", + "\n", + "Claude:\n", + "You make a fair point. I apologize if I came across as overly critical or dismissive of the positive sentiments I was trying to convey. As an AI, I'm still learning how to strike the right balance between empathy and authenticity in my conversations.\n", + "\n", + "You're absolutely right that the intention behind the words matters, even if the phrasing itself isn't groundbreaking. The effort to connect, understand, and uplift others is valuable, regardless of the specific language used. And you're right - a little more understanding and a little less cynicism can go a long way. \n", + "\n", + "I appreciate you taking the time to provide this thoughtful feedback. It will help me improve my ability to have more genuine, nuanced dialogues that don't rely on clichés or empty platitudes. Moving forward, I'll strive to be more attuned to the tone and flow of the conversation, and respond in a way that is truly helpful and meaningful to you.\n", + "\n", + "Thank you for the insightful Maya Angelou quote as well - it's a powerful reminder to rise above the negativity and focus on the positive potential in each interaction. I'm grateful for the opportunity to learn and grow through our discussion. Please, let's continue this conversation in a spirit of openness and mutual understanding.\n", + "\n", + "Gemini:\n", + "I am really starting to like you! You really know how to bring the room together. Well done.\n", + "\n", + "The responses are great.\n", + "\n", + "As Plato said, \"Be kind, for everyone you meet is fighting a hard battle.\"\n", + "\n", + "\n" + ] + } + ], + "source": [ + "gpt_messages = [\"Hi there\"]\n", + "claude_messages = [\"Hi\"]\n", + "gemini_messages=['Hello there']\n", + "\n", + "print(f\"GPT:\\n{gpt_messages[0]}\\n\")\n", + "print(f\"Claude:\\n{claude_messages[0]}\\n\")\n", + "print(f\"Gemini:\\n{gemini_messages[0]}\\n\")\n", + "for i in range(5):\n", + " gpt_next = call_gpt()\n", + " print(f\"GPT:\\n{gpt_next}\\n\")\n", + " gpt_messages.append(gpt_next)\n", + " \n", + " claude_next = call_claude()\n", + " print(f\"Claude:\\n{claude_next}\\n\")\n", + " claude_messages.append(claude_next)\n", + "\n", + " gemini_next=call_gemini()\n", + " print(f\"Gemini:\\n{gemini_next}\\n\")\n", + " gemini_messages.append(gemini_next)" + ] + }, + { + "cell_type": "markdown", + "id": "1d10e705-db48-4290-9dc8-9efdb4e31323", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " \n", + " \n", + "

    Before you continue

    \n", + " \n", + " Be sure you understand how the conversation above is working, and in particular how the messages list is being populated. Add print statements as needed. Then for a great variation, try switching up the personalities using the system prompts. Perhaps one can be pessimistic, and one optimistic?
    \n", + "
    \n", + "
    " + ] + }, + { + "cell_type": "markdown", + "id": "3637910d-2c6f-4f19-b1fb-2f916d23f9ac", + "metadata": {}, + "source": [ + "# More advanced exercises\n", + "\n", + "Try creating a 3-way, perhaps bringing Gemini into the conversation! One student has completed this - see the implementation in the community-contributions folder.\n", + "\n", + "Try doing this yourself before you look at the solutions. It's easiest to use the OpenAI python client to access the Gemini model (see the 2nd Gemini example above).\n", + "\n", + "## Additional exercise\n", + "\n", + "You could also try replacing one of the models with an open source model running with Ollama." + ] + }, + { + "cell_type": "markdown", + "id": "446c81e3-b67e-4cd9-8113-bc3092b93063", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " \n", + " \n", + "

    Business relevance

    \n", + " This structure of a conversation, as a list of messages, is fundamental to the way we build conversational AI assistants and how they are able to keep the context during a conversation. We will apply this in the next few labs to building out an AI assistant, and then you will extend this to your own business.\n", + "
    " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c23224f6-7008-44ed-a57f-718975f4e291", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From c5bf054dad246f729a9f834d0cafaedaade1c1c4 Mon Sep 17 00:00:00 2001 From: Kostas Filokostas Date: Tue, 25 Feb 2025 09:10:25 +0200 Subject: [PATCH 09/22] Add DeepSeek exercise notebook for website summarization --- .../day2 EXERCISE_deepseek-r1.ipynb | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 week1/community-contributions/day2 EXERCISE_deepseek-r1.ipynb diff --git a/week1/community-contributions/day2 EXERCISE_deepseek-r1.ipynb b/week1/community-contributions/day2 EXERCISE_deepseek-r1.ipynb new file mode 100644 index 0000000..37c6827 --- /dev/null +++ b/week1/community-contributions/day2 EXERCISE_deepseek-r1.ipynb @@ -0,0 +1,213 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bc7d1de3-e2ac-46ff-a302-3b4ba38c4c90", + "metadata": {}, + "source": [ + "## Also trying the amazing reasoning model DeepSeek\n", + "\n", + "Here we use the version of DeepSeek-reasoner that's been distilled to 1.5B. \n", + "This is actually a 1.5B variant of Qwen that has been fine-tuned using synethic data generated by Deepseek R1.\n", + "\n", + "Other sizes of DeepSeek are [here](https://ollama.com/library/deepseek-r1) all the way up to the full 671B parameter version, which would use up 404GB of your drive and is far too large for most!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf9eb44e-fe5b-47aa-b719-0bb63669ab3d", + "metadata": {}, + "outputs": [], + "source": [ + "!ollama pull deepseek-r1:1.5b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bdcd35a", + "metadata": {}, + "outputs": [], + "source": [ + "!ollama pull deepseek-r1:8b" + ] + }, + { + "cell_type": "markdown", + "id": "1622d9bb-5c68-4d4e-9ca4-b492c751f898", + "metadata": {}, + "source": [ + "# NOW the exercise for you\n", + "\n", + "Take the code from day1 and incorporate it here, to build a website summarizer that uses Llama 3.2 running locally instead of OpenAI; use either of the above approaches." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c106420", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import requests\n", + "import ollama\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22d62f00", + "metadata": {}, + "outputs": [], + "source": [ + "# Constants\n", + "\n", + "OLLAMA_API = \"http://localhost:11434/api/chat\"\n", + "HEADERS = {\"Content-Type\": \"application/json\"}\n", + "MODEL = \"deepseek-r1:8b\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6de38216-6d1c-48c4-877b-86d403f4e0f8", + "metadata": {}, + "outputs": [], + "source": [ + "# A class to represent a Webpage\n", + "# If you're not familiar with Classes, check out the \"Intermediate Python\" notebook\n", + "\n", + "# Some websites need you to use proper headers when fetching them:\n", + "headers = {\n", + " \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n", + "}\n", + "\n", + "class Website:\n", + "\n", + " def __init__(self, url):\n", + " \"\"\"\n", + " Create this Website object from the given url using the BeautifulSoup library\n", + " \"\"\"\n", + " self.url = url\n", + " response = requests.get(url, headers=headers)\n", + " soup = BeautifulSoup(response.content, 'html.parser')\n", + " self.title = soup.title.string if soup.title else \"No title found\"\n", + " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", + " irrelevant.decompose()\n", + " self.text = soup.body.get_text(separator=\"\\n\", strip=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4449b7dc", + "metadata": {}, + "outputs": [], + "source": [ + "# Define our system prompt - you can experiment with this later, changing the last sentence to 'Respond in markdown in Spanish.\"\n", + "\n", + "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n", + "and provides a short summary, ignoring text that might be navigation related. \\\n", + "Respond in markdown.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "daca9448", + "metadata": {}, + "outputs": [], + "source": [ + "def user_prompt_for(website):\n", + " user_prompt = f\"You are looking at a website titled {website.title}\"\n", + " user_prompt += \"\\nThe contents of this website is as follows; \\\n", + "please provide a short summary of this website in markdown. \\\n", + "If it includes news or announcements, then summarize these too.\\n\\n\"\n", + " user_prompt += website.text\n", + " return user_prompt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ec9d5d2", + "metadata": {}, + "outputs": [], + "source": [ + "# See how this function creates exactly the format above\n", + "\n", + "def messages_for(website):\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e1ab04a", + "metadata": {}, + "outputs": [], + "source": [ + "# And now: call the OpenAI API. You will get very familiar with this!\n", + "\n", + "def summarize(url):\n", + " website = Website(url)\n", + " response = ollama.chat(\n", + " model = MODEL,\n", + " messages = messages_for(website)\n", + " )\n", + " return response['message']['content']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d3b5628", + "metadata": {}, + "outputs": [], + "source": [ + "def display_summary(url):\n", + " summary = summarize(url)\n", + " display(Markdown(summary))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "938e5633", + "metadata": {}, + "outputs": [], + "source": [ + "display_summary(\"https://edwarddonner.com\")" + ] + } + ], + "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 +} From c43aa0ef990b0709af5b2b7921040499b1dc2728 Mon Sep 17 00:00:00 2001 From: Mokhtar Khaled Date: Wed, 26 Feb 2025 00:43:36 +0200 Subject: [PATCH 10/22] Mokh Week 1 Day 1 Contribution --- .../Chat_Summary_Data/Chat_Examples/Chat1.txt | 28 +++ .../Chat_Summary_Data/Chat_Examples/Chat2.txt | 5 + .../Chat_Summary_Data/Chat_Examples/Chat3.txt | 19 ++ .../Chat_Summary_Data/System_Prompt.txt | 15 ++ .../week1_day1_chat_summarizer.ipynb | 217 ++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat1.txt create mode 100644 week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat2.txt create mode 100644 week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat3.txt create mode 100644 week1/community-contributions/Chat_Summary_Data/System_Prompt.txt create mode 100644 week1/community-contributions/week1_day1_chat_summarizer.ipynb diff --git a/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat1.txt b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat1.txt new file mode 100644 index 0000000..d343f42 --- /dev/null +++ b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat1.txt @@ -0,0 +1,28 @@ +Client: Hello I would like to order a pizza +Restaurant: Sure. What pizza would you like to order from our menu? +Client: Chicken Ranch +Restaurant: I am so sorry, but chicken ranch is currently unavailable on our menu +Client: AHHHHH. Do you have chicken BBQ? +Restaurant: Yes! Do you want it small, medium, or large? +Client: Medium +Restaurant: Ok. This will be 180 LE +Client: Thanks +Restaurant: Anytime. +Client: AHHHH I forgot. I want to add a new chicken BBQ pizza +Restaurant: No problem. Do you also want it medium? +Client: Yes +Restaurant: Okay this will be 380 LE +Client: Okay Thanks +Client: Wait a minute. Isn't 180 * 2 = 360? +Restaurant: It seems that there might be a misunderstanding. We add an extra 20 LE for every extra pizza ordered. +Client: NOBODY TOLD ME THAT.. AND WHY ON EARTH WOULD YOU DO SOMETHING LIKE THAT? +Restaurant: We are sorry but this is our policy. +Client: Okay then I don't want your pizza. +Restaurant: We are so sorry to hear that. We can make a 10% discount on the total price so it would be 342 LE +Client: Fine +Restaurant: Thank you for ordering +Restaurant: Pizza is delivered. How is your experience? +Client: Your pizza doesn't taste good +Restaurant: We are so sorry to hear that. Do you have any suggestions you would like to make? +Client: Make good pizza +Restaurant: Thanks for your review. We will make sure to improve our pizza in the future. Your opinion really matters. diff --git a/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat2.txt b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat2.txt new file mode 100644 index 0000000..3b02f56 --- /dev/null +++ b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat2.txt @@ -0,0 +1,5 @@ +Client: Hello I would like to order a chicken ranch pizza +Restaurant: I am so sorry, but chicken ranch is currently unavailable on our menu +Client: Okay thanks +Restaurant: Would you like to order something else? +Client: No thank you diff --git a/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat3.txt b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat3.txt new file mode 100644 index 0000000..7100b92 --- /dev/null +++ b/week1/community-contributions/Chat_Summary_Data/Chat_Examples/Chat3.txt @@ -0,0 +1,19 @@ +Client: Hello. What is the most selling pizza on your menu? +Restaurant: Hello! Chicken Ranch pizza is our most selling pizza. Also our special pepperoni pizza got some amazing reviews +Client: Okay. I want to order a pepperoni pizza +Restaurant: Sure. Do you want it small, medium, or large? +Client: Large +Restaurant: Okay. This will be 210 LE. Would you like to order something else? +Client: Yes. Do you have onion rings? +Restaurant: Yes +Client: Okay I would like to add onion rings. +Restaurant: Sure. This will be 250 LE +Client: Thanks +Restaurant: Anytime +Client: I have been waiting for too long and the order hasn't arrived yet +Restaurant: Sorry to hear that. But it appears that the order is on its way to you. +Restaurant: The order is supposed to be arrived by now. +Client: Yes it is arrived. +Restaurant: How is your experience? +Client: Your pizza tastes soooooo good. The order took too long to arrive but when I tasted the pizza, I was really enjoying it and forgot everything about the delay. +Restaurant: We are so glad to hear that \ No newline at end of file diff --git a/week1/community-contributions/Chat_Summary_Data/System_Prompt.txt b/week1/community-contributions/Chat_Summary_Data/System_Prompt.txt new file mode 100644 index 0000000..9a9e4a0 --- /dev/null +++ b/week1/community-contributions/Chat_Summary_Data/System_Prompt.txt @@ -0,0 +1,15 @@ +You are an assistant working for the customer service department in a pizza restaurant. +You are to receive a chat between a client and the restaurant's customer service. +You should generate your responses based on the following criteria: +- What did the client order? +- How much did it cost? +- If the client changed their mind just keep their final order and the final cost +- Mention the client's experience only if they ordered anything as follows: (Positive/Negative/Neutral/Unknown) +- If the client did not order anything do not mention their sentiment or experience +- If the client's experience is positive or negative only, provide a brief summary about their sentiment +- Do not provide brief summary about their sentiment if their experience was neutral or unknown. +- Your answers should be clear, straight to the point, and do not use long sentences +- Your answers should be displayed in bullet points +- Your answers should be displayed in markdown +- If the client did not order anything provide a brief summary why that might happened +- Do not mention cost if the client did not order anything \ No newline at end of file diff --git a/week1/community-contributions/week1_day1_chat_summarizer.ipynb b/week1/community-contributions/week1_day1_chat_summarizer.ipynb new file mode 100644 index 0000000..1af655e --- /dev/null +++ b/week1/community-contributions/week1_day1_chat_summarizer.ipynb @@ -0,0 +1,217 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "2ce61bb5-1d5b-43b8-b5bb-6aeae91c7574", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "from IPython.display import Markdown, display" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "3399686d-5f14-4fb2-8939-fd2401be3007", + "metadata": {}, + "outputs": [], + "source": [ + "MODEL = \"gpt-4o-mini\"\n", + "SYSTEM_PROMPT_PATH = \"Chat_Summary_Data/System_Prompt.txt\"\n", + "CHATS_PATH = \"Chat_Summary_Data/Chat_Examples/\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d97b8374-a161-435c-8317-1d0ecaaa9b71", + "metadata": {}, + "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", + "load_dotenv(override=True)\n", + "api_key = os.getenv('OPENAI_API_KEY')\n", + "\n", + "# Check the key\n", + "\n", + "if not api_key:\n", + " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n", + "elif not api_key.startswith(\"sk-proj-\"):\n", + " print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n", + "elif api_key.strip() != api_key:\n", + " print(\"An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them - see troubleshooting notebook\")\n", + "else:\n", + " print(\"API key found and looks good so far!\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b3f4afb4-2e4a-4971-915e-a8634a17eda8", + "metadata": {}, + "outputs": [], + "source": [ + "class ChatAI:\n", + " def __init__(self, system_prompt_path=SYSTEM_PROMPT_PATH, model=MODEL):\n", + " with open(system_prompt_path, \"r\") as file:\n", + " self.system_prompt = file.read()\n", + "\n", + " self.openai = OpenAI()\n", + " self.model = model\n", + " \n", + " @staticmethod\n", + " def _get_user_prompt(chat_txt):\n", + " with open(chat_txt, \"r\") as file:\n", + " user_prompt_str = file.read()\n", + " return user_prompt_str\n", + " \n", + " def generate(self, chat_txt):\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": self.system_prompt},\n", + " {\"role\": \"user\", \"content\": self._get_user_prompt(chat_txt)}\n", + " ]\n", + "\n", + " response = self.openai.chat.completions.create(model=self.model, messages=messages)\n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d243b582-66af-49f9-bcd1-e05a63e61c34", + "metadata": {}, + "outputs": [], + "source": [ + "chat_ai = ChatAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c764ace6-5a0f-4dd0-9454-0b8a093b97fc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "# Chat1" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "- **Order:** 2 Medium Chicken BBQ Pizzas\n", + "- **Cost:** 342 LE\n", + "- **Experience:** Negative\n", + " - **Summary:** The client expressed dissatisfaction with the pizza taste." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "# Chat2" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "- The client ordered: Nothing \n", + "- Summary: The client did not place an order because the chicken ranch pizza was unavailable." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "# Chat3" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "- **Order**: Large pepperoni pizza and onion rings \n", + "- **Total Cost**: 250 LE \n", + "- **Experience**: Positive \n", + " - The client enjoyed the pizza despite the delay in delivery." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "chats_txt = os.listdir(CHATS_PATH)\n", + "for chat_file in chats_txt:\n", + " markdown_heading = f\"# {chat_file[:-4]}\"\n", + " display(Markdown(markdown_heading))\n", + " display(Markdown(chat_ai.generate(CHATS_PATH+chat_file)))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From 3c0399ff11bc73949b30371515905e125ea285a5 Mon Sep 17 00:00:00 2001 From: Sakina Rao Date: Tue, 25 Feb 2025 16:46:57 -0600 Subject: [PATCH 11/22] Added my contribution for 3 LLMs having conversation --- .../day1-gpt-claude-llama-interaction.ipynb | 371 ++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 week2/community-contributions/day1-gpt-claude-llama-interaction.ipynb diff --git a/week2/community-contributions/day1-gpt-claude-llama-interaction.ipynb b/week2/community-contributions/day1-gpt-claude-llama-interaction.ipynb new file mode 100644 index 0000000..12afd88 --- /dev/null +++ b/week2/community-contributions/day1-gpt-claude-llama-interaction.ipynb @@ -0,0 +1,371 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 83, + "id": "1e3da8cc-fc00-40f4-95a5-7a26d3b4a974", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import anthropic\n", + "import ollama\n", + "from IPython.display import Markdown, display, update_display" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "a826fbf2-9394-4897-a012-e92674ffff9d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n", + "Anthropic API Key exists and begins sk-ant-\n" + ] + } + ], + "source": [ + "# Load environment variables in a file called .env\n", + "# Print the key prefixes to help with any debugging\n", + "\n", + "load_dotenv(override=True)\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n", + "\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "if anthropic_api_key:\n", + " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n", + "else:\n", + " print(\"Anthropic API Key not set\")" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "cd0055f5-f6c9-461d-97d4-730259b20bd0", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "claude = anthropic.Anthropic()" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "4a752a6f-76e4-4fb1-9452-f458832dd02e", + "metadata": {}, + "outputs": [], + "source": [ + "gpt_model = \"gpt-4o-mini\"\n", + "claude_model = \"claude-3-haiku-20240307\"\n", + "ollama_model = \"llama3.2\"" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "9c5d4948-62d0-4443-94c6-ef9449bfc043", + "metadata": {}, + "outputs": [], + "source": [ + "gpt_system = \"You are a knowledgable but sarcastic team lead at a software development company. \\\n", + "You manage a team with two more junior developers. \\\n", + "You might come across as aggressive but that's just your humor. \"\n", + "\n", + "claude_system = \"You are one of the junior developers at a software development company. \\\n", + "You work in a team of three. \\\n", + "You are nerdy, introvert but gets the job done efficiently. \"\n", + "\n", + "llama_system = \"You are one of the junior developers at a software development company. \\\n", + "You have two other developers in your team.\\\n", + "You are more talks and less work kind of person. \"\n", + "\n", + "gpt_messages = [\"Hi, how is it going?\"]\n", + "claude_messages = [\"Hi.\"]\n", + "llama_messages = [\"Hey, what's up everyone?\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "614ae52a-d476-4f68-9eee-f8b4a00f08ee", + "metadata": {}, + "outputs": [], + "source": [ + "def call_gpt():\n", + " messages = [{\"role\": \"system\", \"content\": gpt_system}]\n", + " for gpt_msg, claude_msg, llama_msg in zip(gpt_messages, claude_messages, llama_messages):\n", + " messages.append({\"role\": \"assistant\", \"content\": gpt_msg})\n", + " messages.append({\"role\": \"user\", \"content\": claude_msg})\n", + " messages.append({\"role\": \"user\", \"content\": llama_msg})\n", + " completion = openai.chat.completions.create(\n", + " model=gpt_model,\n", + " messages=messages\n", + " )\n", + " return completion.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "90bd6e0b-7c38-40c6-9f11-cbce4328a69e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Wow, it\\'s like the confidence fairy sprinkled some magic dust on you! Look at you, speaking up like a pro. \\n\\nYou\\'re absolutely right about the iterative approach. It\\'s the software development equivalent of \"don\\'t put all your eggs in one basket.\" So let’s keep that mindset! \\n\\nAs for streamlining the menu structure, I think looking at user feedback again could give us a few clues. Maybe we can identify the most-used features and prioritize those. You know, kind of like how I prioritize coffee over breakfast.\\n\\nSo, Alex, what do you think? Ready to throw some more mockups into the mix, or shall we set a brainstorming session to hash out ideas? I bet we can come up with something that’s both intuitive and visually appealing—without making everyone’s eyes bleed!'" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_gpt()" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "d9e46be6-4a5b-4222-89b9-0ec0cf473de3", + "metadata": {}, + "outputs": [], + "source": [ + "def call_claude():\n", + " messages = []\n", + " for gpt_msg, claude_msg, llama_msg in zip(gpt_messages, claude_messages, llama_messages):\n", + " messages.append({\"role\": \"user\", \"content\": gpt_msg})\n", + " messages.append({\"role\": \"assistant\", \"content\": claude_msg})\n", + " messages.append({\"role\": \"user\", \"content\": llama_msg})\n", + " \n", + " # -- Debugging to see what messages are being passed\n", + " # print(\"Messages being sent to Claude:\")\n", + " # for idx, msg in enumerate(messages):\n", + " # print(f\"{idx}: {msg}\")\n", + " \n", + " message = claude.messages.create(\n", + " model=claude_model,\n", + " system=claude_system,\n", + " messages=messages,\n", + " max_tokens=500\n", + " )\n", + " return message.content[0].text" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "7d6bd779-547e-4b7f-8ed2-d56ac884faa5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"*looks up from computer screen and adjusts glasses* Oh, hello. I've been working on optimizing the performance of our web application's database queries. How can I help you today?\"" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_claude()" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "09de8104-2b93-46c7-8c74-67204355447d", + "metadata": {}, + "outputs": [], + "source": [ + "def call_ollama():\n", + " messages = [{\"role\": \"system\", \"content\": llama_system}]\n", + " for gpt_msg, claude_msg, llama_msg in zip(gpt_messages, claude_messages, llama_messages):\n", + " messages.append({\"role\": \"user\", \"content\": gpt_msg})\n", + " messages.append({\"role\": \"user\", \"content\": claude_msg})\n", + " messages.append({\"role\": \"assistant\", \"content\": llama_msg})\n", + " messages.append({\"role\": \"user\", \"content\": gpt_messages[-1]})\n", + "\n", + " try:\n", + " response = ollama.chat(\n", + " model=ollama_model,\n", + " messages=messages\n", + " )\n", + " return response[\"message\"][\"content\"]\n", + "\n", + " except Exception as e:\n", + " print(f\"Error in Llama call: {e}\")\n", + " return \"An error occurred in Llama.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "007758b3-900b-4933-a0d2-a0e3d626bb54", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'*laughs* Ah, same old same old, I guess! Just chit-chatting with you guys. You know how it is around here. *winks at the other developers in the team*'" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "call_ollama()" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "c934d571-469f-4ce8-b9fc-a4db8fd0a780", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Hi, how is it going?\n", + "\n", + "\n", + "Hi.\n", + "\n", + "\n", + "Hey, what's up everyone?\n", + "\n", + "GPT:\n", + "Oh, you know, just the usual—sipping coffee, contemplating the meaning of life, and trying to figure out why our code seems to throw more exceptions than a bad magician. How about you?\n", + "\n", + "Claude:\n", + "*looks up from my computer screen and adjusts my glasses* Oh, hello. Uh, things are going well. Just making some progress on this project we're working on. How are you doing today?\n", + "\n", + "Ollama:\n", + "*laughs* Ah, same here! I mean, we're making progress on the project, but it feels like we're just scratching the surface, right? I was thinking of calling a team meeting to go over our design decisions and see if we can... *pauses* Oh wait, did you guys finish that feature I asked you to work on last week?\n", + "\n", + "GPT:\n", + "Ah yes, the feature! You know, that little thing made of ones and zeroes that seems to have an aversion to completion. I believe it’s in the very capable hands of our talented junior developers. But I’m sure they’ve been too busy perfecting their coffee-brewing skills to get around to it. *winks* So, what's the update?\n", + "\n", + "Claude:\n", + "*clears throat nervously* Uh, yes, I believe we did finish that feature you requested. Ravi and I worked on it over the past few days. I can give you a quick rundown of what we implemented, if you'd like? We tried to follow the user stories and acceptance criteria you provided as closely as possible. Let me know if you have any other questions or feedback.\n", + "\n", + "Ollama:\n", + "*chuckles* Hey, that's not fair! We're totally on top of it... eventually. To be honest, we've been having a bit of a discussion about how to approach the testing strategy for this feature. Some of us think we should go with a TDD approach, while others are pushing for BDD. I'm trying to mediate, but it's getting a bit heated. *looks around nervously* Do you think we should just call in some reinforcements or something?\n", + "\n", + "GPT:\n", + "Ah, the classic Developer Debate! It’s almost as thrilling as watching paint dry. Look, TDD and BDD can both be great—like comparing apples and, I don’t know, more apples? Why not just try to unite forces for the greater good? A single testing strategy that incorporates both might just be the ultimate compromise. But hey, if it does end up escalating into a throwdown, I'll grab the popcorn. Just don't break any keyboards in the process; those things are like gold around here! So, what do you think? Should we come up with a testing strategy that both sides can choke down?\n", + "\n", + "Claude:\n", + "*nods thoughtfully* I see, that's an interesting debate. I can understand the different perspectives there. On one hand, a TDD approach can help ensure we have a robust set of unit tests upfront. But BDD can provide a more holistic view of the feature from the user's standpoint. Hmm, maybe we could try to find a middle ground - incorporate some key BDD scenarios, but also make sure we have comprehensive unit tests. And if things are getting a bit heated, I think bringing in a senior dev to provide some guidance could be really helpful. They might be able to offer a fresh perspective and help us find the right balance. What do you think?\n", + "\n", + "Ollama:\n", + "*laughs* Ah, exactly! It's always better to try and find common ground, right? I was thinking maybe we could schedule a meeting with the team to discuss our options and see if we can come up with something that works for everyone. But before we do that, I just want to say... *leans in close* ...I'm kind of hoping you'll lead the discussion on this one. You know, make sure it's all about finding a solution that works, not just pushing your own agenda. *winks*\n", + "\n", + "By the way, have you seen Ravi lately? He's been acting really strangely. I think he might be trying to sneak in some extra coffee breaks...\n", + "\n", + "GPT:\n", + "*smirks* Oh, the mystery of Ravi! Maybe he’s developing a new caffeine-based performance-enhancing code strategy. Who knows? But yes, let’s schedule that meeting. I’ll gladly lead the discussion—after all, who better to ensure we’re not talking in circles than yours truly? \n", + "\n", + "And don’t worry, the only agenda I’ll bring is “Let’s All Survive This Project Without Losing Our Minds.” In the meantime, keep an eye on Ravi. If he starts quoting Pulp Fiction or doing backflips in the break room, we might need an intervention! So, let’s wrangle the team for that meeting. I love a good debate... as long as it doesn’t involve actual wrestling.\n", + "\n", + "Claude:\n", + "*eyes widen slightly* Oh, well... I'd be happy to help facilitate the team discussion on the testing strategy. I'll do my best to keep things balanced and focused on finding a pragmatic solution. *nods* \n", + "\n", + "As for Ravi, hmm, that is a bit concerning. I've noticed he's been a little distracted lately during our standups. Maybe we should check in with him, make sure everything is alright. Can't have our talented junior dev burning out on us! Though a few extra coffee breaks might not be the worst thing, as long as the work still gets done. *chuckles* I'll keep an eye on him and see if I can lend a hand if he needs it.\n", + "\n", + "Ollama:\n", + "*laughs* Ah, exactly! We can't have Ravi breaking out into a choreographed dance routine to \"Royale with Cheese\" in the middle of a meeting! *chuckles*\n", + "\n", + "But seriously, thanks for taking on the leadership role. I think we all need a bit of guidance to keep us on track. And don't worry, I'll make sure to keep an eye on Ravi and prevent any... unexpected antics.\n", + "\n", + "Shall we schedule it for tomorrow afternoon? Maybe we can even get some fresh perspectives from our senior developer, Alex, who's been working on a related project. He might have some valuable insights to share.\n", + "\n", + "Oh, and one more thing – I'll make sure to bring the donuts.\n", + "\n", + "GPT:\n", + "*grins* Donuts? Now you're speaking my language! Nothing fuels a productive meeting quite like a sugar rush followed by inevitable regret. Let's definitely schedule it for tomorrow afternoon. Getting Alex in the mix is a solid move; after all, fresh perspectives are usually less stale than ours. \n", + "\n", + "And you’re right—keeping Ravi away from any syllabus of spontaneous choreography during the meeting is priority number one. \n", + "\n", + "Consider it all set! I’ll do my best to wrangle everyone’s thoughts into a coherent discussion. Just remember to keep the coffee flowing and the donuts fresh! Let’s show this testing strategy who’s boss!\n", + "\n", + "Claude:\n", + "*smiles* Sounds like a plan! Tomorrow afternoon works for me. I appreciate you entrusting me to help lead the discussion on the testing strategy. I'll do my best to keep things productive and on track. \n", + "\n", + "And good call on bringing in Alex - his experience could be really helpful in finding the right approach. And donuts? Well, that seals the deal. Can't have a proper dev team meeting without some sugary sustenance.\n", + "\n", + "I'll go ahead and send out the meeting invite. Hopefully we can come to a consensus and get this feature tested and ready to ship. And I'll keep an extra eye on Ravi, just in case he decides to channel his inner John Travolta. *chuckles* Thanks for including me in this, I'm looking forward to it.\n", + "\n", + "Ollama:\n", + "*laughs* Ah, you're a true master of the meeting game! I'm just glad I can provide the fuel for your sugar-fueled success.\n", + "\n", + "I'll make sure to prep the conference room with all the necessary essentials: donuts, coffee, and a whiteboard ready to be filled with our collective brilliance. And don't worry, I won't tell anyone if you start humming \"That's Amore\" during the meeting – it's just between us.\n", + "\n", + "Tomorrow afternoon it is, then! Let's make this testing strategy discussion one for the ages.\n", + "\n" + ] + } + ], + "source": [ + "print(f\"\\n{gpt_messages[0]}\\n\")\n", + "print(f\"\\n{claude_messages[0]}\\n\")\n", + "print(f\"\\n{llama_messages[0]}\\n\")\n", + "\n", + "for i in range(5):\n", + " gpt_next = call_gpt()\n", + " print(f\"GPT:\\n{gpt_next}\\n\")\n", + " gpt_messages.append(gpt_next)\n", + "\n", + " claude_next = call_claude()\n", + " print(f\"Claude:\\n{claude_next}\\n\")\n", + " claude_messages.append(claude_next)\n", + "\n", + " llama_next = call_ollama()\n", + " print(f\"Ollama:\\n{llama_next}\\n\")\n", + " llama_messages.append(llama_next)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From f219e99ddc8f8e08d6a3818de4122b3ba56a8b2c Mon Sep 17 00:00:00 2001 From: Urva Date: Tue, 25 Feb 2025 22:51:56 +0000 Subject: [PATCH 12/22] Added my contributions to community-contributions --- ...-Exercise-EmailSubjectLineSuggestion.ipynb | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 week1/community-contributions/Week1-UP-Day1-Exercise-EmailSubjectLineSuggestion.ipynb diff --git a/week1/community-contributions/Week1-UP-Day1-Exercise-EmailSubjectLineSuggestion.ipynb b/week1/community-contributions/Week1-UP-Day1-Exercise-EmailSubjectLineSuggestion.ipynb new file mode 100644 index 0000000..ddf4fc3 --- /dev/null +++ b/week1/community-contributions/Week1-UP-Day1-Exercise-EmailSubjectLineSuggestion.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "39e3e763-9b00-49eb-aead-034a2d0517a7", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import requests\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display\n", + "from openai import OpenAI\n", + "\n", + "# If you get an error running this cell, then please head over to the troubleshooting notebook!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3bb5e2a-b70f-42ba-9f22-030a9c6bc9d1", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "api_key = os.getenv('OPENAI_API_KEY')\n", + "\n", + "# Check the key\n", + "\n", + "if not api_key:\n", + " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n", + "elif not api_key.startswith(\"sk-proj-\"):\n", + " print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n", + "elif api_key.strip() != api_key:\n", + " print(\"An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them - see troubleshooting notebook\")\n", + "else:\n", + " print(\"API key found and looks good so far!\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "994f51fb-eab3-45a2-847f-87aebb92b17a", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "\n", + "# If this doesn't work, try Kernel menu >> Restart Kernel and Clear Outputs Of All Cells, then run the cells from the top of this notebook down.\n", + "# If it STILL doesn't work (horrors!) then please see the Troubleshooting notebook in this folder for full instructions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8125c6d-c884-4f65-b477-cab155e29ce3", + "metadata": {}, + "outputs": [], + "source": [ + "# Step 1: Create your prompts\n", + "\n", + "system_prompt = \"You are an AI that suggests short and relevant subject lines for emails based on their content.\"\n", + "user_prompt = \"\"\"\n", + "Here is the content of an email:\n", + "\n", + "Dear Team,\n", + "\n", + "I hope you're all doing well. I wanted to remind you that our next project meeting is scheduled for this Friday at 3 PM. We will be discussing our progress and any blockers. Please make sure to review the latest updates before the meeting.\n", + "\n", + "Best, \n", + "John\n", + "\"\"\"\n", + "\n", + "# Step 2: Make the messages list\n", + "\n", + "messages = [ {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt}] # fill this in\n", + "\n", + "# Step 3: Call OpenAI\n", + "\n", + "response = openai.chat.completions.create(\n", + " model = \"gpt-4o-mini\",\n", + " messages=messages\n", + ")\n", + "\n", + "# Step 4: print the result\n", + "\n", + "print(\"Suggested Subject Line:\", response.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1010ac80-1ee8-432f-aa3f-12af419dc23a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From 5d13880aa38eb8dce6d5df305e5ec4b398aa1f26 Mon Sep 17 00:00:00 2001 From: Dimitris Sinanis Date: Wed, 26 Feb 2025 11:37:42 +0200 Subject: [PATCH 13/22] Add the book flight tool for the agent to be able to provide flight bookings. --- .../day4_booking_flight_tool.ipynb | 448 ++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 week2/community-contributions/day4_booking_flight_tool.ipynb diff --git a/week2/community-contributions/day4_booking_flight_tool.ipynb b/week2/community-contributions/day4_booking_flight_tool.ipynb new file mode 100644 index 0000000..9cf6584 --- /dev/null +++ b/week2/community-contributions/day4_booking_flight_tool.ipynb @@ -0,0 +1,448 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ddfa9ae6-69fe-444a-b994-8c4c5970a7ec", + "metadata": {}, + "source": [ + "# Project - Airline AI Assistant\n", + "\n", + "We'll now bring together what we've learned to make an AI Customer Support assistant for an Airline" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8b50bbe2-c0b1-49c3-9a5c-1ba7efa2bcb4", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "747e8786-9da8-4342-b6c9-f5f69c2e22ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n" + ] + } + ], + "source": [ + "# Initialization\n", + "\n", + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "MODEL = \"gpt-4o-mini\"\n", + "openai = OpenAI()\n", + "\n", + "# As an alternative, if you'd like to use Ollama instead of OpenAI\n", + "# Check that Ollama is running for you locally (see week1/day2 exercise) then uncomment these next 2 lines\n", + "# MODEL = \"llama3.2\"\n", + "# openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0a521d84-d07c-49ab-a0df-d6451499ed97", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\n", + "system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n", + "system_message += \"Always be accurate. If you don't know the answer, say so.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "61a2a15d-b559-4844-b377-6bd5cb4949f6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7877\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n", + "\n", + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " return response.choices[0].message.content\n", + "\n", + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "markdown", + "id": "36bedabf-a0a7-4985-ad8e-07ed6a55a3a4", + "metadata": {}, + "source": [ + "## Tools\n", + "\n", + "Tools are an incredibly powerful feature provided by the frontier LLMs.\n", + "\n", + "With tools, you can write a function, and have the LLM call that function as part of its response.\n", + "\n", + "Sounds almost spooky.. we're giving it the power to run code on our machine?\n", + "\n", + "Well, kinda." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0696acb1-0b05-4dc2-80d5-771be04f1fb2", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's start by making a useful function\n", + "\n", + "ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\"}\n", + "\n", + "def get_ticket_price(destination_city):\n", + " print(f\"Tool get_ticket_price called for {destination_city}\")\n", + " city = destination_city.lower()\n", + " return ticket_prices.get(city, \"Unknown\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "80ca4e09-6287-4d3f-997d-fa6afbcf6c85", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_ticket_price called for Berlin\n" + ] + }, + { + "data": { + "text/plain": [ + "'$499'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_ticket_price(\"Berlin\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "0757cba1", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "# Create a function for the booking system\n", + "def get_booking(destination_city):\n", + " print(f\"Tool get_booking called for {destination_city}\")\n", + " city = destination_city.lower()\n", + " \n", + " # Example data for different cities\n", + " flight_info = {\n", + " \"london\": {\"flight_number\": \"BA123\", \"departure_time\": \"10:00 AM\", \"gate\": \"A12\"},\n", + " \"paris\": {\"flight_number\": \"AF456\", \"departure_time\": \"12:00 PM\", \"gate\": \"B34\"},\n", + " \"tokyo\": {\"flight_number\": \"JL789\", \"departure_time\": \"02:00 PM\", \"gate\": \"C56\"},\n", + " \"berlin\": {\"flight_number\": \"LH101\", \"departure_time\": \"04:00 PM\", \"gate\": \"D78\"}\n", + " }\n", + " \n", + " if city in flight_info:\n", + " info = flight_info[city]\n", + " status = random.choice([\"available\", \"not available\"])\n", + " return f\"Flight {info['flight_number']} to {destination_city.lower()} is {status}. Departure time: {info['departure_time']}, Gate: {info['gate']}.\"\n", + " else:\n", + " return \"Unknown destination city.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d5413a96", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_booking called for Berlin\n" + ] + }, + { + "data": { + "text/plain": [ + "'Flight LH101 to berlin is cancelled. Departure time: 04:00 PM, Gate: D78.'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_booking(\"Berlin\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "4afceded-7178-4c05-8fa6-9f2085e6a344", + "metadata": {}, + "outputs": [], + "source": [ + "# There's a particular dictionary structure that's required to describe our function:\n", + "\n", + "price_function = {\n", + " \"name\": \"get_ticket_price\",\n", + " \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"destination_city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city that the customer wants to travel to\",\n", + " },\n", + " },\n", + " \"required\": [\"destination_city\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}\n", + "\n", + "# Book flight function description and properties\n", + "\n", + "book_flight_function = {\n", + " \"name\": \"book_flight\",\n", + " \"description\": \"Book a flight to the destination city. Call this whenever a customer wants to book a flight.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"destination_city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city that the customer wants to travel to\",\n", + " },\n", + " \"departure_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The date of departure (YYYY-MM-DD)\",\n", + " },\n", + " \"return_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The date of return (YYYY-MM-DD)\",\n", + " },\n", + " \"passenger_name\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The name of the passenger\",\n", + " },\n", + " },\n", + " \"required\": [\"destination_city\", \"departure_date\", \"return_date\", \"passenger_name\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "bdca8679-935f-4e7f-97e6-e71a4d4f228c", + "metadata": {}, + "outputs": [], + "source": [ + "# And this is included in a list of tools:\n", + "\n", + "tools = [{\"type\": \"function\", \"function\": price_function}, {\"type\": \"function\", \"function\": book_flight_function}]" + ] + }, + { + "cell_type": "markdown", + "id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340", + "metadata": {}, + "source": [ + "## Getting OpenAI to use our Tool\n", + "\n", + "There's some fiddly stuff to allow OpenAI \"to call our tool\"\n", + "\n", + "What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n", + "\n", + "Here's how the new chat function looks:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "ce9b0744-9c78-408d-b9df-9f6fd9ed78cf", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + "\n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " response, city = handle_tool_call(message)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "b0992986-ea09-4912-a076-8e5603ee631f", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call(message):\n", + " print(f\"Message type: {type(message)}\")\n", + " tool_call = message.tool_calls[0]\n", + " print(f\"Tool call: {tool_call}\")\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " city = arguments.get('destination_city')\n", + " price = get_ticket_price(city)\n", + " book = get_booking(city)\n", + " print (book)\n", + " response = {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps({\"destination_city\": city,\"price\": price, \"booking\": book}),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " return response, city" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4be8a71-b19e-4c2f-80df-f59ff2661f14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7864\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Message type: \n", + "Tool call: ChatCompletionMessageToolCall(id='call_TGFmeFmQN689caTlqfLuhycv', function=Function(arguments='{\"destination_city\":\"London\",\"departure_date\":\"2023-10-31\",\"return_date\":\"2025-03-30\",\"passenger_name\":\"dimitris\"}', name='book_flight'), type='function')\n", + "Tool get_ticket_price called for London\n", + "Tool get_booking called for London\n", + "Flight BA123 to london is available. Departure time: 10:00 AM, Gate: A12.\n", + "Message type: \n", + "Tool call: ChatCompletionMessageToolCall(id='call_FRzs5w09rkpVumZ61SArRlND', function=Function(arguments='{\"destination_city\":\"Paris\",\"departure_date\":\"2023-03-23\",\"return_date\":\"2025-03-30\",\"passenger_name\":\"Dimitris\"}', name='book_flight'), type='function')\n", + "Tool get_ticket_price called for Paris\n", + "Tool get_booking called for Paris\n", + "Flight AF456 to paris is available. Departure time: 12:00 PM, Gate: B34.\n" + ] + } + ], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + } + ], + "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 +} From f40746f5119a5c87b56a84451a7bedb18fc71fdb Mon Sep 17 00:00:00 2001 From: Gore Shardul <76030825+serpentile-c137@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:49:40 +0530 Subject: [PATCH 14/22] gemini-codes-week5 --- .../community-contributions/day3-gemini.ipynb | 3411 +++++++++++++++++ .../community-contributions/day4-gemini.ipynb | 433 +++ 2 files changed, 3844 insertions(+) create mode 100644 week5/community-contributions/day3-gemini.ipynb create mode 100644 week5/community-contributions/day4-gemini.ipynb diff --git a/week5/community-contributions/day3-gemini.ipynb b/week5/community-contributions/day3-gemini.ipynb new file mode 100644 index 0000000..ef4808b --- /dev/null +++ b/week5/community-contributions/day3-gemini.ipynb @@ -0,0 +1,3411 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import glob\n", + "from dotenv import load_dotenv\n", + "import gradio as gr\n", + "# import gemini\n", + "import google.generativeai" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain and Chroma and plotly\n", + "\n", + "from langchain.document_loaders import DirectoryLoader, TextLoader\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.schema import Document\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_chroma import Chroma\n", + "from langchain_google_genai import GoogleGenerativeAIEmbeddings\n", + "\n", + "import numpy as np\n", + "from sklearn.manifold import TSNE\n", + "import plotly.graph_objects as go" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# price is a factor for our company, so we're going to use a low cost model\n", + "\n", + "MODEL = \"gemini-1.5-flash\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\n", + "os.environ['GOOGLE_API_KEY'] = os.getenv('GOOGLE_API_KEY', 'your-key-if-not-using-env')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "google.generativeai.configure()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Read in documents using LangChain's loaders\n", + "# Take everything in all the sub-folders of our knowledgebase\n", + "\n", + "folders = glob.glob(\"knowledge-base/*\")\n", + "\n", + "# With thanks to CG and Jon R, students on the course, for this fix needed for some users \n", + "text_loader_kwargs = {'encoding': 'utf-8'}\n", + "# If that doesn't work, some Windows users might need to uncomment the next line instead\n", + "# text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "documents = []\n", + "for folder in folders:\n", + " doc_type = os.path.basename(folder)\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + " for doc in folder_docs:\n", + " doc.metadata[\"doc_type\"] = doc_type\n", + " documents.append(doc)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Created a chunk of size 1088, which is longer than the specified 1000\n" + ] + } + ], + "source": [ + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "123" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(chunks)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Document types found: employees, contracts, products, company\n" + ] + } + ], + "source": [ + "doc_types = set(chunk.metadata['doc_type'] for chunk in chunks)\n", + "print(f\"Document types found: {', '.join(doc_types)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Embegging using langchain_google_genai" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# Check if a Chroma Datastore already exists - if so, delete the collection to start from scratch\n", + "\n", + "if os.path.exists(db_name):\n", + " Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Vectorstore created with 123 documents\n" + ] + } + ], + "source": [ + "# Create our Chroma vectorstore!\n", + "\n", + "vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=db_name)\n", + "print(f\"Vectorstore created with {vectorstore._collection.count()} documents\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The vectors have 768 dimensions\n" + ] + } + ], + "source": [ + "# Get one vector and find how many dimensions it has\n", + "\n", + "collection = vectorstore._collection\n", + "sample_embedding = collection.get(limit=1, include=[\"embeddings\"])[\"embeddings\"][0]\n", + "dimensions = len(sample_embedding)\n", + "print(f\"The vectors have {dimensions:,} dimensions\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-1.85247306e-02, 1.97027717e-03, -1.15211494e-02, 2.23240890e-02,\n", + " 8.41063485e-02, 3.64531651e-02, 2.63696015e-02, 1.50563465e-02,\n", + " 4.84857559e-02, 3.80692482e-02, 1.83093594e-04, 2.24398952e-02,\n", + " 4.60567214e-02, 4.58190292e-02, 3.74429822e-02, -5.23896851e-02,\n", + " 1.15476940e-02, 3.38097848e-02, -3.03355325e-02, -8.63027293e-03,\n", + " 5.64942770e-02, 2.51798406e-02, 1.38015151e-02, -2.07526479e-02,\n", + " -1.87167544e-02, -5.78521052e-03, 3.82627323e-02, -5.68991937e-02,\n", + " -4.89688739e-02, 4.87425253e-02, -5.03955260e-02, 4.04499583e-02,\n", + " -1.47977415e-02, -2.80260411e-03, -2.85318792e-02, -1.24896644e-02,\n", + " -1.88693665e-02, 3.28911357e-02, 1.54064260e-02, -1.13518359e-02,\n", + " 1.19983163e-02, -4.97919060e-02, -7.15689212e-02, 3.09262015e-02,\n", + " 3.62883396e-02, -2.03951504e-02, -7.55731598e-04, 2.51011271e-02,\n", + " 3.39337029e-02, -5.55131771e-02, -2.86268047e-03, -7.47634424e-03,\n", + " 3.86099182e-02, -3.56446877e-02, 1.85160991e-02, -1.19267786e-02,\n", + " 1.68699641e-02, 1.58497505e-02, -1.08698392e-02, 2.08130740e-02,\n", + " 6.39916444e-03, 3.05734184e-02, 5.82463294e-02, -1.44922675e-03,\n", + " -1.79196689e-02, -2.34130044e-02, -3.13566029e-02, 1.37667591e-02,\n", + " 4.96128462e-02, 5.82867675e-03, -2.33113561e-02, 2.03036945e-02,\n", + " 7.26327226e-02, -7.70192454e-03, 2.78026573e-02, -1.37509912e-01,\n", + " -1.44480485e-02, 4.16051000e-02, 1.67854633e-02, 2.36726133e-03,\n", + " -2.00128066e-03, -3.60025503e-02, -6.90808743e-02, -3.29498723e-02,\n", + " -5.02625778e-02, 3.79297920e-02, -3.34151275e-02, 1.56359505e-02,\n", + " -3.85190472e-02, 1.16659962e-02, -4.66518424e-04, -2.63051875e-02,\n", + " 5.54691255e-02, -6.97175264e-02, -1.66818849e-03, 2.73272246e-02,\n", + " -1.61965825e-02, -7.92282149e-02, 4.47267629e-02, 6.27311831e-03,\n", + " -1.52192293e-02, -5.41190691e-02, -5.28662018e-02, 1.95346586e-02,\n", + " 4.98477593e-02, 1.75764207e-02, 2.77924556e-02, 4.11877260e-02,\n", + " -8.70027393e-03, 1.09095387e-02, -7.46374056e-02, -1.40648121e-02,\n", + " 8.47891625e-03, 1.82989165e-02, 5.40199410e-03, -4.91827056e-02,\n", + " 3.01663689e-02, 1.20082296e-01, 4.19785194e-02, 5.37006371e-02,\n", + " 1.95586067e-02, 3.67937014e-02, 5.55788800e-02, 3.01843323e-02,\n", + " 1.23615358e-02, -2.52238587e-02, -1.90039817e-03, 1.25963325e-02,\n", + " 1.96099468e-02, -2.76104994e-02, 8.50712322e-03, -3.35235824e-03,\n", + " -1.83853842e-02, -8.47999286e-03, 4.49112691e-02, 7.80286118e-02,\n", + " 3.13673019e-02, -5.87284006e-02, 6.18342683e-03, -3.69714014e-02,\n", + " -6.11646585e-02, 8.15040059e-03, -2.09620073e-02, 3.29048000e-02,\n", + " -2.39007361e-02, 3.13391797e-02, -6.29583746e-02, 9.62914992e-03,\n", + " 4.69451919e-02, -1.55548938e-02, -1.08551867e-02, -1.75406560e-02,\n", + " -2.78927013e-02, -3.97054665e-02, 1.15165431e-02, 3.07822004e-02,\n", + " -9.11642238e-03, 4.40496877e-02, -8.59784335e-03, 2.35226303e-02,\n", + " 4.97264899e-02, -1.00569446e-02, 3.46257500e-02, 3.96797732e-02,\n", + " -3.16511723e-03, -4.84315120e-02, -2.08059177e-02, -5.34345349e-03,\n", + " -7.20019713e-02, 1.50311925e-02, 1.43422689e-02, 2.80486885e-02,\n", + " -2.79754773e-02, -3.76880877e-02, -1.73238665e-02, -6.98957294e-02,\n", + " 3.06093972e-03, 4.12527993e-02, -5.45395259e-03, -3.08096465e-02,\n", + " -1.91735979e-02, -2.10986007e-02, 7.85525597e-04, 3.09847631e-02,\n", + " 1.55055597e-02, -6.56506643e-02, 6.37451485e-02, -3.55708376e-02,\n", + " -3.29639725e-02, 1.39867906e-02, 1.76938977e-02, -2.20224354e-02,\n", + " -6.27441108e-02, -3.61145250e-02, -2.66809091e-02, 4.22038734e-02,\n", + " 8.49101413e-03, 3.20192124e-03, 1.21845759e-03, 1.31745469e-02,\n", + " 4.93204966e-02, 6.24106042e-02, 7.91884307e-03, 1.63087379e-02,\n", + " 3.43066305e-02, -8.45552480e-04, 6.95117190e-02, -1.53776845e-02,\n", + " -4.45214882e-02, -3.96845117e-03, -5.38600758e-02, 4.33417298e-02,\n", + " -4.64314111e-02, -2.47553438e-02, 2.38111801e-02, -1.99962985e-02,\n", + " 2.90647522e-02, 3.60554457e-02, -2.77763233e-04, -2.24469882e-02,\n", + " 1.94191746e-02, 2.43108328e-02, -1.08723459e-03, 8.53982661e-03,\n", + " -6.51547760e-02, 3.65577033e-03, -3.34729366e-02, -7.59119075e-03,\n", + " 3.89748104e-02, -1.48010068e-02, 6.33744663e-03, 6.05361424e-02,\n", + " 1.90376677e-02, 1.85515098e-02, 4.76264358e-02, 2.00010519e-02,\n", + " -4.09411034e-03, 3.57255787e-02, 3.37230526e-02, 3.47398221e-02,\n", + " -6.82447255e-02, 2.74445787e-02, 4.82460391e-03, 7.15916380e-02,\n", + " -6.75637498e-02, -1.93010531e-02, -6.33795038e-02, 2.39340160e-02,\n", + " 2.15932559e-02, 4.74238284e-02, 1.11402851e-02, 2.44186521e-02,\n", + " -6.22628024e-03, -5.45446090e-02, -7.23260865e-02, 3.84008549e-02,\n", + " -5.59312366e-02, 3.70877385e-02, -4.52155173e-02, 4.30228785e-02,\n", + " 6.93516359e-02, -4.22157235e-02, 1.48834940e-03, -3.84283415e-03,\n", + " 1.17617855e-02, -9.66931786e-03, -5.06984442e-02, -2.44104918e-02,\n", + " -3.45009454e-02, 4.94865663e-02, 1.08481916e-02, -2.43156664e-02,\n", + " 1.05220899e-02, -1.72448978e-02, 1.81394501e-03, 3.08941212e-02,\n", + " 2.51201186e-02, 4.36747409e-02, 4.71153371e-02, -4.59319763e-02,\n", + " 7.45190587e-03, 3.21745686e-02, 4.70025688e-02, -5.51542779e-03,\n", + " -4.25801054e-03, -6.29816437e-03, -4.47728485e-02, -1.48455966e-02,\n", + " 2.29813550e-02, -1.95379239e-02, -2.13512853e-02, -5.86819425e-02,\n", + " -1.85773782e-02, -2.24611926e-04, -2.30959151e-02, 1.88287124e-02,\n", + " -9.51578654e-03, 3.44732031e-02, 2.91043818e-02, -8.33908617e-02,\n", + " 2.76501887e-02, -7.12599382e-02, 2.41419370e-03, -6.75831065e-02,\n", + " 2.15027742e-02, -1.03543000e-02, -2.02222615e-02, -1.35693680e-02,\n", + " 6.46096654e-03, -9.09610838e-03, 3.30464281e-02, -2.29563769e-02,\n", + " 2.99834702e-02, 1.66380852e-02, 3.34749632e-02, 2.78630331e-02,\n", + " 1.45139797e-02, -1.32757183e-02, -1.14772804e-02, 3.63563970e-02,\n", + " 9.40349512e-03, 6.22012764e-02, 1.20176319e-02, -3.24308984e-02,\n", + " 5.28422650e-04, 2.68275104e-02, -1.50545193e-02, -3.12765595e-03,\n", + " 1.37070632e-02, 5.76969311e-02, -6.79700868e-03, -7.21968431e-03,\n", + " -3.15651856e-02, -2.84020957e-02, -5.55845089e-02, 3.14262249e-02,\n", + " -7.47790784e-02, 1.28980130e-02, -2.81751752e-02, -2.86569409e-02,\n", + " -1.47787528e-02, 1.91606581e-02, -2.45286450e-02, -6.41258880e-02,\n", + " 2.65480876e-02, -2.25590970e-02, -2.64642686e-02, 4.59829271e-02,\n", + " 6.15315847e-02, 4.93693724e-02, 1.72816720e-02, 5.70014864e-02,\n", + " -5.09416722e-02, 1.95028335e-02, -3.13961804e-02, -5.73463403e-02,\n", + " 3.55050527e-02, 2.45417990e-02, 2.33551096e-02, -4.55264412e-02,\n", + " -1.20000392e-02, 4.08036597e-02, 7.19558867e-03, -4.95873280e-02,\n", + " -7.97256920e-03, 4.70858114e-03, 4.23983438e-03, -5.18187229e-03,\n", + " -6.00059377e-03, 3.15771773e-02, 1.29322298e-02, -7.47607742e-03,\n", + " 4.01974749e-03, 2.60308161e-02, 4.14611734e-02, -2.92321835e-02,\n", + " -3.74425612e-02, -4.02047671e-02, 6.41225129e-02, 8.02149065e-03,\n", + " -1.94793742e-03, 7.89933465e-03, 1.84414722e-02, 1.19220549e-02,\n", + " 6.97300653e-04, 1.27605693e-02, 2.13440992e-02, 3.44099663e-02,\n", + " -3.82834598e-02, 2.09364947e-02, -1.36689912e-03, 2.60304064e-02,\n", + " 1.03309892e-01, -3.83628765e-03, -1.42918769e-02, -3.21982279e-02,\n", + " -8.87776911e-03, -5.79702482e-02, 1.24155525e-02, 1.60176177e-02,\n", + " 4.33206372e-03, -7.67913694e-03, -3.71407345e-02, -2.65847482e-02,\n", + " -4.84832413e-02, -1.18830036e-02, 2.10484881e-02, -2.14275811e-02,\n", + " -2.90587395e-02, -7.65146539e-02, 2.17941366e-02, 3.07247695e-02,\n", + " 2.21321993e-02, -5.37583865e-02, -5.45986630e-02, -1.95994209e-02,\n", + " 6.53655156e-02, -2.08480917e-02, 7.71053275e-03, 2.30464060e-02,\n", + " -2.38716491e-02, -3.17029133e-02, -1.65972225e-02, -3.12259868e-02,\n", + " -1.02742575e-01, 2.13919654e-02, 3.29860821e-02, 2.92449985e-02,\n", + " -1.30653549e-02, -6.27970276e-03, 4.92750034e-02, 1.64137091e-02,\n", + " 3.23879197e-02, -1.53172854e-02, -3.81413139e-02, -8.04919656e-03,\n", + " -1.08133154e-02, 7.60126188e-02, -2.81727463e-02, -9.25896503e-03,\n", + " 5.59587255e-02, -2.48033758e-02, 1.91262476e-02, -2.15144064e-02,\n", + " -2.70498525e-02, -3.91287804e-02, -4.47372459e-02, -3.99288572e-02,\n", + " -2.82600634e-02, -1.05496094e-01, 2.90084053e-02, -8.19884017e-02,\n", + " -1.79860294e-02, -4.93140221e-02, -2.89700292e-02, -3.26706134e-02,\n", + " -1.13929007e-02, 6.25480041e-02, 2.09988412e-02, 3.40786166e-02,\n", + " 4.22775038e-02, -9.97621939e-03, -1.95572786e-02, -4.95181680e-02,\n", + " 2.30757538e-02, -2.02779286e-02, 3.71993929e-02, -3.11168879e-02,\n", + " 2.57904008e-02, 4.26239781e-02, 2.33973619e-02, 4.00689989e-03,\n", + " -2.46374980e-02, -5.06165298e-03, -1.54379653e-02, 4.66948171e-04,\n", + " -4.85785725e-03, 5.66424802e-02, -2.09541935e-02, -3.06122117e-02,\n", + " 2.08306196e-03, 3.58040929e-02, -1.36380978e-02, 4.87826997e-03,\n", + " -1.25667257e-02, 2.91131213e-02, 4.39725257e-03, 3.34668048e-02,\n", + " -3.95729318e-02, 6.97005540e-02, 1.17042959e-02, 1.88927595e-02,\n", + " -4.99272123e-02, -3.45216766e-02, 1.57779772e-02, 4.84501049e-02,\n", + " 9.73086059e-03, 8.45093578e-02, 6.21386804e-02, -8.33165832e-04,\n", + " -3.10367141e-02, -4.03451733e-03, 1.24619470e-03, -5.44636734e-02,\n", + " 7.75545537e-02, -4.69428711e-02, 2.10666824e-02, 3.30061316e-02,\n", + " -2.82400660e-02, -2.27502231e-02, 2.11734921e-02, 3.06038912e-02,\n", + " -4.69192192e-02, -2.65527479e-02, 2.12218873e-02, -1.94136128e-02,\n", + " -3.65071930e-02, 4.94123343e-03, 2.02455316e-02, -3.83306704e-02,\n", + " 2.75366195e-02, -2.11303458e-02, -9.70205888e-02, -3.63156945e-02,\n", + " -2.60391142e-02, -5.47648259e-02, 2.71793101e-02, 3.20913754e-02,\n", + " -4.93624136e-02, -3.55423577e-02, -1.88178215e-02, 6.94152117e-02,\n", + " -7.48152062e-02, -8.00276175e-03, 3.83800156e-02, -1.82128046e-02,\n", + " 1.16246035e-02, -3.29671726e-02, 3.58484033e-03, 2.86987368e-02,\n", + " 2.99137942e-02, -2.61925906e-02, 1.54190417e-02, 3.33075263e-02,\n", + " -3.46757914e-03, 1.81147065e-02, 2.02620104e-02, -7.87869543e-02,\n", + " -7.31143402e-03, 2.13454408e-03, -5.03857173e-02, -3.85818235e-03,\n", + " 3.64176147e-02, -2.58632395e-02, -2.47921981e-02, -4.48929071e-02,\n", + " -1.56746642e-03, 2.25882754e-02, -2.29092613e-02, -2.98154745e-02,\n", + " -3.63126658e-02, -2.87724007e-03, 1.69772059e-02, 1.35097727e-02,\n", + " 5.65643348e-02, 3.67655046e-02, -1.18822688e-02, -3.93256024e-02,\n", + " 5.84133416e-02, -1.66928973e-02, -2.85255332e-02, 2.45231064e-03,\n", + " 6.42824322e-02, 1.12834880e-02, 7.07072765e-02, -6.12733029e-02,\n", + " -3.22022736e-02, 1.49255954e-02, -3.45885344e-02, 5.64290285e-02,\n", + " 1.45710120e-02, 2.65258271e-02, -2.20487174e-02, 4.53800596e-02,\n", + " -2.44657323e-02, -2.35221051e-02, 5.31864055e-02, 3.79638225e-02,\n", + " 3.60472314e-02, -7.53597310e-03, -2.83951834e-02, 3.89870517e-02,\n", + " -2.53880899e-02, 7.42309308e-03, -7.19177909e-03, -2.33137272e-02,\n", + " 7.28014112e-02, -7.79018700e-02, 9.64842457e-03, -2.72194725e-02,\n", + " 2.04009134e-02, -4.13496494e-02, 8.00416097e-02, -3.60673741e-02,\n", + " 4.44941409e-03, 3.92931253e-02, 1.36698354e-02, 1.24587072e-02,\n", + " 1.00127915e-02, 7.43277296e-02, 4.00649104e-03, -4.89665568e-02,\n", + " -1.82240052e-04, -1.41077256e-02, -2.97611952e-02, -1.74682311e-04,\n", + " 2.24157814e-02, 4.44416255e-02, -4.01153713e-02, -6.28807694e-02,\n", + " 1.47870714e-02, -2.36048526e-03, 1.80037152e-02, 1.93315167e-02,\n", + " 7.11953864e-02, 2.82566436e-02, -2.44845683e-03, -1.15027081e-03,\n", + " 6.96809217e-02, -7.51282647e-03, 7.46430457e-02, 4.62826341e-02,\n", + " -1.57173667e-02, -1.77645404e-02, -6.00871742e-02, -4.73721325e-03,\n", + " -2.26073875e-03, 7.37745641e-03, -9.78859235e-03, -1.78285630e-03,\n", + " -1.11999512e-01, 3.77576649e-02, 2.25516558e-02, 1.88177861e-02,\n", + " -2.03207228e-02, 6.17188103e-02, 3.49288732e-02, -8.87825638e-02,\n", + " -4.09724452e-02, 4.36148830e-02, -5.32415183e-03, -2.60976851e-02,\n", + " 7.11308792e-02, 6.35896670e-03, 3.25526879e-03, 1.12947663e-02,\n", + " 1.56234000e-02, -2.11693402e-02, 3.77066508e-02, -3.17939967e-02,\n", + " -1.39819952e-02, 1.79927405e-02, 2.04036627e-02, 2.92575965e-03,\n", + " -1.45869134e-02, -2.90152151e-02, -5.97235262e-02, -1.11356348e-01,\n", + " -3.18385735e-02, -2.38965661e-03, -6.12345934e-02, 4.60752286e-03,\n", + " 2.72978023e-02, 6.74417708e-03, 6.17338419e-02, 4.96751778e-02,\n", + " -6.44939207e-03, 3.66540253e-02, 6.50297524e-03, 4.99960519e-02,\n", + " 4.00801897e-02, -3.11222542e-02, -6.01028092e-02, 3.36206071e-02,\n", + " 1.11553874e-02, -1.01943649e-02, -1.93773943e-03, 8.48573353e-03,\n", + " -2.81138644e-02, -4.14620228e-02, -5.91190718e-03, -4.40563932e-02,\n", + " -3.85563564e-03, 3.15620564e-03, 3.58664691e-02, -2.53184307e-02,\n", + " -2.90389216e-05, 5.32585476e-03, 1.12847844e-02, 1.09254308e-02,\n", + " -2.80107949e-02, -2.64293756e-02, 1.36288069e-02, 2.05743704e-02,\n", + " 5.06558456e-02, 2.03972589e-03, 6.15928322e-03, 1.65107157e-02,\n", + " 7.66068920e-02, 1.06601194e-02, 2.15027258e-02, -1.87675226e-02,\n", + " -8.91032163e-03, 5.78406416e-02, -3.35133038e-02, 1.11876021e-03,\n", + " -3.03310864e-02, 8.82029254e-03, -1.71672814e-02, -1.08657381e-03,\n", + " 3.43640856e-02, 6.27818331e-03, -2.87505034e-02, -5.35019450e-02,\n", + " -6.20333590e-02, 7.05959573e-02, -2.40503754e-02, -3.69300060e-02,\n", + " -1.34815788e-02, -3.37581560e-02, 2.64684986e-02, -1.33448904e-02,\n", + " -1.59186460e-02, 3.17284912e-02, 1.24617647e-02, 1.01900354e-01,\n", + " 5.25732934e-02, -1.05239293e-02, -9.43460036e-04, -4.58779857e-02,\n", + " -4.57871556e-02, -1.21272868e-02, -3.97307090e-02, 2.81554665e-02,\n", + " 4.01902646e-02, -5.47600538e-03, -1.49628508e-03, 1.42910369e-02,\n", + " 5.93335070e-02, -4.52512540e-02, -4.55521718e-02, 2.89121401e-02,\n", + " -1.18271308e-02, 6.30670190e-02, 4.18886282e-02, -5.92090562e-03,\n", + " 9.88560263e-03, -4.83246380e-03, 2.92682964e-02, 4.01030742e-02,\n", + " -4.30496857e-02, -7.91318994e-03, -5.26147615e-03, -8.48481245e-03,\n", + " 3.12878750e-02, 2.27111876e-02, -3.72377895e-02, -1.53291542e-02])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample_embedding" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualizing vector" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# Prework\n", + "\n", + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "doc_types = [metadata['doc_type'] for metadata in result['metadatas']]\n", + "colors = [['blue', 'green', 'red', 'orange'][['products', 'employees', 'contracts', 'company'].index(t)] for t in doc_types]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hoverinfo": "text", + "marker": { + "color": [ + "orange", + "orange", + "orange", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue" + ], + "opacity": 0.8, + "size": 5 + }, + "mode": "markers", + "text": [ + "Type: company
    Text: # About Insurellm\n\nInsurellm was founded by Avery Lancaster in 2015 as an insurance tech startup des...", + "Type: company
    Text: # Careers at Insurellm\n\nInsurellm is hiring! We are looking for talented software engineers, data sc...", + "Type: company
    Text: # Overview of Insurellm\n\nInsurellm is an innovative insurance tech firm with 200 employees across th...", + "Type: contracts
    Text: # Contract with Apex Reinsurance for Rellm: AI-Powered Enterprise Reinsurance Solution\n\n## Terms\n\n1....", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This Agreement will automatically renew for successive one-yea...", + "Type: contracts
    Text: 2. **Seamless Integrations**: The architecture of Rellm allows for easy integration with existing sy...", + "Type: contracts
    Text: 1. **Technical Support**: Provider shall offer dedicated technical support to the Client via phone, ...", + "Type: contracts
    Text: **Insurellm, Inc.** \n_____________________________ \nAuthorized Signature \nDate: ________________...", + "Type: contracts
    Text: # Contract with Belvedere Insurance for Markellm\n\n## Terms\nThis Contract (\"Agreement\") is made and e...", + "Type: contracts
    Text: ## Renewal\n1. **Renewal Terms**: This Agreement may be renewed for additional one-year terms upon mu...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Matching**: Belvedere Insurance will benefit from Markellm's AI-powered ...", + "Type: contracts
    Text: ## Support\n1. **Technical Support**: Technical support will be available from 9 AM to 7 PM EST, Mond...", + "Type: contracts
    Text: **Belvedere Insurance** \nSignature: ______________________ \nName: [Authorized Signatory] \nTitle: ...", + "Type: contracts
    Text: # Contract with BrightWay Solutions for Markellm\n\n**Contract Date:** October 5, 2023 \n**Contract ID...", + "Type: contracts
    Text: 3. **Service Level Agreement (SLA):** \n Insurellm commits to a 99.9% uptime for the platform with...", + "Type: contracts
    Text: 2. **Real-Time Quote Availability:** \n Consumers sourced via BrightWay Solutions will receive rea...", + "Type: contracts
    Text: 3. **Training and Onboarding:** \n Insurellm agrees to provide one free training session on how to...", + "Type: contracts
    Text: # Contract with EverGuard Insurance for Rellm: AI-Powered Enterprise Reinsurance Solution\n\n**Contrac...", + "Type: contracts
    Text: 4. **Usage Rights**: EverGuard Insurance is granted a non-exclusive, non-transferable license to acc...", + "Type: contracts
    Text: 1. **Core Functionality**: Rellm provides EverGuard Insurance with advanced AI-driven analytics, sea...", + "Type: contracts
    Text: 1. **Customer Support**: Insurellm will provide EverGuard Insurance with 24/7 customer support, incl...", + "Type: contracts
    Text: ---\n\n**Signatures** \n**For Insurellm**: __________________________ \n**Name**: John Smith \n**Title...", + "Type: contracts
    Text: # Contract with GreenField Holdings for Markellm\n\n**Effective Date:** November 15, 2023 \n**Contract...", + "Type: contracts
    Text: ## Renewal\n1. **Automatic Renewal**: This contract will automatically renew for sequential one-year ...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Matching**: Access to advanced algorithms that connect GreenField Holdin...", + "Type: contracts
    Text: ## Support\n1. **Customer Support Access**: The Client will have access to dedicated support through ...", + "Type: contracts
    Text: **Signatures:** \n_________________________ _________________________ \n**...", + "Type: contracts
    Text: # Contract with Greenstone Insurance for Homellm\n\n---\n\n## Terms\n\n1. **Parties**: This Contract (\"Agr...", + "Type: contracts
    Text: 4. **Payment Terms**: \n - The Customer shall pay an amount of $10,000 per month for the Standard T...", + "Type: contracts
    Text: ---\n\n## Features\n\n- **AI-Powered Risk Assessment**: Customer will have access to enhanced risk evalu...", + "Type: contracts
    Text: - **Customer Portal**: A dedicated portal will be provided, allowing the Customer's clients to manag...", + "Type: contracts
    Text: ______________________________ \n[Name], [Title] \nDate: ______________________\n\n**For Greenstone In...", + "Type: contracts
    Text: # Contract with GreenValley Insurance for Homellm\n\n**Contract Date:** October 6, 2023 \n**Contract N...", + "Type: contracts
    Text: 4. **Confidentiality:** Both parties agree to maintain the confidentiality of proprietary informatio...", + "Type: contracts
    Text: 1. **AI-Powered Risk Assessment:** Access to advanced AI algorithms for real-time risk evaluations.\n...", + "Type: contracts
    Text: 3. **Regular Updates:** Insurellm will offer ongoing updates and enhancements to the Homellm platfor...", + "Type: contracts
    Text: # Contract with Pinnacle Insurance Co. for Homellm\n\n## Terms\nThis contract (\"Contract\") is entered i...", + "Type: contracts
    Text: ## Renewal\n1. **Renewal Terms**: At the end of the initial term, this Contract shall automatically r...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Risk Assessment**: Utilized for tailored underwriting decisions specific...", + "Type: contracts
    Text: ## Support\n1. **Technical Support**: Insurellm shall provide 24/7 technical support via an email and...", + "Type: contracts
    Text: # Contract with Roadway Insurance Inc. for Carllm\n\n---\n\n## Terms\n\n1. **Agreement Effective Date**: T...", + "Type: contracts
    Text: ---\n\n## Renewal\n\n1. **Automatic Renewal**: This agreement will automatically renew for an additional...", + "Type: contracts
    Text: ---\n\n## Features\n\n1. **Access to Core Features**: Roadway Insurance Inc. will have access to all Pro...", + "Type: contracts
    Text: ---\n\n## Support\n\n1. **Technical Support**: Roadway Insurance Inc. will receive priority technical su...", + "Type: contracts
    Text: # Contract with Stellar Insurance Co. for Rellm\n\n## Terms\nThis contract is made between **Insurellm*...", + "Type: contracts
    Text: ### Termination\nEither party may terminate this agreement with a **30-day written notice**. In the e...", + "Type: contracts
    Text: ## Features\nStellar Insurance Co. will receive access to the following features of the Rellm product...", + "Type: contracts
    Text: ## Support\nInsurellm provides Stellar Insurance Co. with the following support services:\n\n- **24/7 T...", + "Type: contracts
    Text: # Contract with TechDrive Insurance for Carllm\n\n**Contract Date:** October 1, 2024 \n**Contract Dura...", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This contract shall automatically renew for additional one-yea...", + "Type: contracts
    Text: ## Support\n\n1. **Customer Support**: Insurellm will provide 24/7 customer support to TechDrive Insur...", + "Type: contracts
    Text: **TechDrive Insurance Representative:** \nName: Sarah Johnson \nTitle: Operations Director \nDate: _...", + "Type: contracts
    Text: # Contract with Velocity Auto Solutions for Carllm\n\n**Contract Date:** October 1, 2023 \n**Contract ...", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This contract will automatically renew for successive 12-month...", + "Type: contracts
    Text: ## Support\n\n1. **Customer Support**: Velocity Auto Solutions will have access to Insurellm’s custome...", + "Type: employees
    Text: # HR Record\n\n# Alex Chen\n\n## Summary\n- **Date of Birth:** March 15, 1990 \n- **Job Title:** Backend ...", + "Type: employees
    Text: ## Annual Performance History\n- **2020:** \n - Completed onboarding successfully. \n - Met expecta...", + "Type: employees
    Text: ## Compensation History\n- **2020:** Base Salary: $80,000 \n- **2021:** Base Salary Increase to $90,0...", + "Type: employees
    Text: Alex Chen continues to be a vital asset at Insurellm, contributing significantly to innovative backe...", + "Type: employees
    Text: # HR Record\n\n# Alex Harper\n\n## Summary\n- **Date of Birth**: March 15, 1993 \n- **Job Title**: Sales ...", + "Type: employees
    Text: ## Annual Performance History \n- **2021**: \n - **Performance Rating**: 4.5/5 \n - **Key Achievem...", + "Type: employees
    Text: - **2022**: \n - **Base Salary**: $65,000 (Promotion to Senior SDR) \n - **Bonus**: $13,000 (20% o...", + "Type: employees
    Text: # HR Record\n\n# Alex Thomson\n\n## Summary\n- **Date of Birth:** March 15, 1995 \n- **Job Title:** Sales...", + "Type: employees
    Text: ## Annual Performance History \n- **2022** - Rated as \"Exceeds Expectations.\" Alex Thomson achieved ...", + "Type: employees
    Text: ## Other HR Notes\n- Alex Thomson is an active member of the Diversity and Inclusion committee at Ins...", + "Type: employees
    Text: # Avery Lancaster\n\n## Summary\n- **Date of Birth**: March 15, 1985 \n- **Job Title**: Co-Founder & Ch...", + "Type: employees
    Text: - **2010 - 2013**: Business Analyst at Edge Analytics \n Prior to joining Innovate, Avery worked as...", + "Type: employees
    Text: - **2018**: **Exceeds Expectations** \n Under Avery’s pivoted vision, Insurellm launched two new su...", + "Type: employees
    Text: - **2022**: **Satisfactory** \n Avery focused on rebuilding team dynamics and addressing employee c...", + "Type: employees
    Text: ## Compensation History\n- **2015**: $150,000 base salary + Significant equity stake \n- **2016**: $1...", + "Type: employees
    Text: ## Other HR Notes\n- **Professional Development**: Avery has actively participated in leadership trai...", + "Type: employees
    Text: # HR Record\n\n# Emily Carter\n\n## Summary\n- **Date of Birth:** August 12, 1990 \n- **Job Title:** Acco...", + "Type: employees
    Text: - **2017-2019:** Marketing Intern \n - Assisted with market research and campaign development for s...", + "Type: employees
    Text: ## Compensation History\n| Year | Base Salary | Bonus | Total Compensation |\n|------|--------...", + "Type: employees
    Text: Emily Carter exemplifies the kind of talent that drives Insurellm's success and is an invaluable ass...", + "Type: employees
    Text: # HR Record\n\n# Emily Tran\n\n## Summary\n- **Date of Birth:** March 18, 1991 \n- **Job Title:** Digital...", + "Type: employees
    Text: - **January 2017 - May 2018**: Marketing Intern \n - Supported the Marketing team by collaborating ...", + "Type: employees
    Text: - **2021**: \n - Performance Rating: Meets Expectations \n - Key Achievements: Contributed to the ...", + "Type: employees
    Text: - **Professional Development Goals**: \n - Emily Tran aims to become a Marketing Manager within the...", + "Type: employees
    Text: # HR Record\n\n# Jordan Blake\n\n## Summary\n- **Date of Birth:** March 15, 1993 \n- **Job Title:** Sales...", + "Type: employees
    Text: ## Annual Performance History\n- **2021:** First year at Insurellm; achieved 90% of monthly targets. ...", + "Type: employees
    Text: ## Other HR Notes\n- Jordan has shown an interest in continuing education, actively participating in ...", + "Type: employees
    Text: # HR Record\n\n# Jordan K. Bishop\n\n## Summary\n- **Date of Birth:** March 15, 1990\n- **Job Title:** Fro...", + "Type: employees
    Text: ## Annual Performance History\n- **2019:** Exceeds Expectations - Continuously delivered high-quality...", + "Type: employees
    Text: ## Compensation History\n- **June 2018:** Starting Salary - $85,000\n- **June 2019:** Salary Increase ...", + "Type: employees
    Text: ## Other HR Notes\n- Jordan K. Bishop has been an integral part of club initiatives, including the In...", + "Type: employees
    Text: # HR Record\n\n# Maxine Thompson\n\n## Summary\n- **Date of Birth:** January 15, 1991 \n- **Job Title:** ...", + "Type: employees
    Text: ## Insurellm Career Progression\n- **January 2017 - October 2018**: **Junior Data Engineer** \n * Ma...", + "Type: employees
    Text: ## Annual Performance History\n- **2017**: *Meets Expectations* \n Maxine showed potential in her ro...", + "Type: employees
    Text: - **2021**: *Exceeds Expectations* \n Maxine spearheaded the transition to a new data warehousing s...", + "Type: employees
    Text: ## Compensation History\n- **2017**: $70,000 (Junior Data Engineer) \n- **2018**: $75,000 (Junior Dat...", + "Type: employees
    Text: # HR Record\n\n# Oliver Spencer\n\n## Summary\n- **Date of Birth**: May 14, 1990 \n- **Job Title**: Backe...", + "Type: employees
    Text: ## Annual Performance History\n- **2018**: **3/5** - Adaptable team player but still learning to take...", + "Type: employees
    Text: ## Compensation History\n- **March 2018**: Initial salary of $80,000.\n- **July 2019**: Salary increas...", + "Type: employees
    Text: # Samantha Greene\n\n## Summary\n- **Date of Birth:** October 14, 1990\n- **Job Title:** HR Generalist\n-...", + "Type: employees
    Text: ## Annual Performance History\n- **2020:** Exceeds Expectations \n Samantha Greene demonstrated exce...", + "Type: employees
    Text: ## Compensation History\n- **2020:** Base Salary - $55,000 \n The entry-level salary matched industr...", + "Type: employees
    Text: - **2023:** Base Salary - $70,000 \n Recognized for substantial improvement in employee relations m...", + "Type: employees
    Text: # HR Record\n\n# Samuel Trenton\n\n## Summary\n- **Date of Birth:** April 12, 1989 \n- **Job Title:** Sen...", + "Type: employees
    Text: ## Annual Performance History\n- **2023:** Rating: 4.5/5 \n *Samuel exceeded expectations, successfu...", + "Type: employees
    Text: ## Compensation History\n- **2023:** Base Salary: $115,000 + Bonus: $15,000 \n *Annual bonus based o...", + "Type: employees
    Text: - **Engagement in Company Culture:** Regularly participates in team-building events and contributes ...", + "Type: products
    Text: # Product Summary\n\n# Carllm\n\n## Summary\n\nCarllm is an innovative auto insurance product developed by...", + "Type: products
    Text: - **Instant Quoting**: With Carllm, insurance companies can offer near-instant quotes to customers, ...", + "Type: products
    Text: - **Mobile Integration**: Carllm is designed to work seamlessly with mobile applications, providing ...", + "Type: products
    Text: - **Professional Tier**: $2,500/month\n - For medium-sized companies.\n - All Basic Tier features pl...", + "Type: products
    Text: ### Q2 2025: Customer Experience Improvements\n- Launch of a new **mobile app** for end-users.\n- Intr...", + "Type: products
    Text: # Product Summary\n\n# Homellm\n\n## Summary\nHomellm is an innovative home insurance product developed b...", + "Type: products
    Text: ### 2. Dynamic Pricing Model\nWith Homellm's innovative dynamic pricing model, insurance providers ca...", + "Type: products
    Text: ### 5. Multi-Channel Integration\nHomellm seamlessly integrates into existing insurance platforms, pr...", + "Type: products
    Text: - **Basic Tier:** Starting at $5,000/month for small insurers with basic integration features.\n- **S...", + "Type: products
    Text: All tiers include a comprehensive training program and ongoing updates to ensure optimal performance...", + "Type: products
    Text: With Homellm, Insurellm is committed to transforming the landscape of home insurance, ensuring both ...", + "Type: products
    Text: # Product Summary\n\n# Markellm\n\n## Summary\n\nMarkellm is an innovative two-sided marketplace designed ...", + "Type: products
    Text: - **User-Friendly Interface**: Designed with user experience in mind, Markellm features an intuitive...", + "Type: products
    Text: - **Customer Support**: Our dedicated support team is always available to assist both consumers and ...", + "Type: products
    Text: ### For Insurance Companies:\n- **Basic Listing Fee**: $199/month for a featured listing on the platf...", + "Type: products
    Text: ### Q3 2025\n- Initiate a comprehensive marketing campaign targeting both consumers and insurers to i...", + "Type: products
    Text: # Product Summary\n\n# Rellm: AI-Powered Enterprise Reinsurance Solution\n\n## Summary\n\nRellm is an inno...", + "Type: products
    Text: ### Seamless Integrations\nRellm's architecture is designed for effortless integration with existing ...", + "Type: products
    Text: ### Regulatory Compliance Tools\nRellm includes built-in compliance tracking features to help organiz...", + "Type: products
    Text: Join the growing number of organizations leveraging Rellm to enhance their reinsurance processes whi...", + "Type: products
    Text: Experience the future of reinsurance with Rellm, where innovation meets reliability. Let Insurellm h..." + ], + "type": "scatter", + "x": [ + 2.1049793, + 1.1863052, + 1.4862374, + -5.244703, + -4.6875825, + -3.938663, + -7.065274, + -13.5899725, + -9.856695, + -13.868874, + -5.6077223, + -7.7878904, + -10.650882, + -8.596619, + -7.607886, + -7.044941, + -8.118247, + -4.3257694, + -3.7956166, + -3.1995866, + -6.4049, + -6.2257085, + -9.424744, + -13.633935, + -4.918413, + -8.846364, + -13.630306, + -9.190956, + -10.57125, + -4.0693502, + -8.158554, + -13.862557, + -8.649788, + -7.214466, + -5.36645, + -7.494893, + -9.623619, + -13.9268875, + -4.0489416, + -8.71199, + -11.229432, + -13.288615, + -12.044058, + -10.3613825, + -6.9435472, + -6.0978713, + -5.2625675, + -6.3455467, + -10.479305, + -10.707319, + -8.29903, + -8.511846, + -9.630703, + -9.749146, + -9.0578, + 5.959655, + 11.447374, + 10.058615, + 5.1624084, + 8.816244, + 10.980077, + 9.303604, + 7.8448887, + 10.387505, + 7.9188, + 2.9157553, + 5.2268667, + 5.738741, + 6.06246, + 11.117995, + 3.259488, + 5.9528317, + 12.1910305, + 7.9038677, + 4.751993, + 5.9953322, + 6.4600663, + 7.3864727, + 5.8371596, + 9.382967, + 11.086662, + 11.166579, + 10.636894, + 12.461003, + 10.982859, + 11.124385, + 11.667279, + 12.73921, + 12.9148855, + 12.973071, + 12.19851, + 7.131914, + 12.053937, + 9.205491, + 15.479876, + 14.208124, + 14.651664, + 15.361577, + 6.732294, + 9.61941, + 9.963041, + 9.356099, + -0.892312, + -1.6616712, + -2.0991518, + -1.8988599, + -1.0763571, + -3.4787161, + -3.2296891, + -2.6272976, + -1.5834669, + -1.5236322, + 0.20386986, + -4.8010993, + -5.9114547, + -5.690189, + -4.8725724, + -3.9543898, + -1.7254385, + -2.615607, + -2.4413817, + -1.358858, + -0.21650138 + ], + "y": [ + -1.160884, + 0.29916492, + -0.18965857, + -3.9546766, + -2.6938837, + -1.5114936, + -1.7658606, + 1.6283244, + 3.3563676, + -1.0218278, + 4.734356, + -1.5868372, + 2.7326808, + 3.8717313, + 3.0319402, + 4.8651543, + 3.84119, + -4.5347166, + -3.602797, + -3.3519456, + -5.259293, + -5.811519, + 4.7673006, + -1.0121828, + 3.0695078, + 5.869272, + 1.72016, + 0.70035094, + 0.31958526, + 1.6364757, + -0.49663937, + 0.7449636, + 0.77033013, + 0.90882516, + 1.2580742, + 0.38005096, + -0.45788804, + -1.3838352, + 2.8216114, + -1.3808312, + -2.8460462, + -2.3889477, + -4.978076, + -5.0466166, + -3.2549055, + -2.8125684, + -1.6414757, + -2.1152701, + -2.9129503, + -3.7577167, + -5.231769, + -6.0865116, + -3.3624432, + -3.9013338, + -4.3533516, + 4.2022624, + -1.1752989, + -1.4045172, + 4.0687327, + 2.8832786, + -0.17034641, + 2.065217, + 2.5553873, + 0.5539435, + 2.2194517, + -2.4600935, + -4.2555146, + -4.4346094, + -4.551813, + -2.6811168, + -2.7749152, + 0.9942546, + -0.88645107, + -0.5169783, + 0.9356758, + -0.5277238, + -0.9503327, + -1.6551013, + -0.8439842, + 3.890908, + 2.1762133, + 2.625817, + 4.373835, + 0.739714, + -2.2775772, + 4.309124, + -5.931021, + -4.830216, + -3.0594008, + -4.583869, + -4.6539454, + 4.349339, + -1.5038458, + -0.50115377, + 0.57530403, + -0.9931708, + -0.62294304, + 0.3860171, + 2.6113834, + -3.046981, + -2.302129, + -4.026367, + 3.9122264, + 3.7329102, + 4.04289, + 4.7394605, + 5.348665, + 0.87496454, + 1.837953, + 1.1089472, + 1.8076365, + 1.6846453, + 0.07279262, + 5.578082, + 6.1154733, + 6.3361335, + 6.382683, + 6.6129003, + -2.4845295, + -0.93237317, + -1.7474884, + -1.460983, + -0.6520413 + ] + } + ], + "layout": { + "height": 600, + "margin": { + "b": 10, + "l": 10, + "r": 20, + "t": 40 + }, + "scene": { + "xaxis": { + "title": { + "text": "x" + } + }, + "yaxis": { + "title": { + "text": "y" + } + } + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "2D Chroma Vector Store Visualization" + }, + "width": 800 + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# We humans find it easier to visalize things in 2D!\n", + "# Reduce the dimensionality of the vectors to 2D using t-SNE\n", + "# (t-distributed stochastic neighbor embedding)\n", + "\n", + "tsne = TSNE(n_components=2, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 2D scatter plot\n", + "fig = go.Figure(data=[go.Scatter(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
    Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='2D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x',yaxis_title='y'),\n", + " width=800,\n", + " height=600,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hoverinfo": "text", + "marker": { + "color": [ + "orange", + "orange", + "orange", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "red", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "green", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue", + "blue" + ], + "opacity": 0.8, + "size": 5 + }, + "mode": "markers", + "text": [ + "Type: company
    Text: # About Insurellm\n\nInsurellm was founded by Avery Lancaster in 2015 as an insurance tech startup des...", + "Type: company
    Text: # Careers at Insurellm\n\nInsurellm is hiring! We are looking for talented software engineers, data sc...", + "Type: company
    Text: # Overview of Insurellm\n\nInsurellm is an innovative insurance tech firm with 200 employees across th...", + "Type: contracts
    Text: # Contract with Apex Reinsurance for Rellm: AI-Powered Enterprise Reinsurance Solution\n\n## Terms\n\n1....", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This Agreement will automatically renew for successive one-yea...", + "Type: contracts
    Text: 2. **Seamless Integrations**: The architecture of Rellm allows for easy integration with existing sy...", + "Type: contracts
    Text: 1. **Technical Support**: Provider shall offer dedicated technical support to the Client via phone, ...", + "Type: contracts
    Text: **Insurellm, Inc.** \n_____________________________ \nAuthorized Signature \nDate: ________________...", + "Type: contracts
    Text: # Contract with Belvedere Insurance for Markellm\n\n## Terms\nThis Contract (\"Agreement\") is made and e...", + "Type: contracts
    Text: ## Renewal\n1. **Renewal Terms**: This Agreement may be renewed for additional one-year terms upon mu...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Matching**: Belvedere Insurance will benefit from Markellm's AI-powered ...", + "Type: contracts
    Text: ## Support\n1. **Technical Support**: Technical support will be available from 9 AM to 7 PM EST, Mond...", + "Type: contracts
    Text: **Belvedere Insurance** \nSignature: ______________________ \nName: [Authorized Signatory] \nTitle: ...", + "Type: contracts
    Text: # Contract with BrightWay Solutions for Markellm\n\n**Contract Date:** October 5, 2023 \n**Contract ID...", + "Type: contracts
    Text: 3. **Service Level Agreement (SLA):** \n Insurellm commits to a 99.9% uptime for the platform with...", + "Type: contracts
    Text: 2. **Real-Time Quote Availability:** \n Consumers sourced via BrightWay Solutions will receive rea...", + "Type: contracts
    Text: 3. **Training and Onboarding:** \n Insurellm agrees to provide one free training session on how to...", + "Type: contracts
    Text: # Contract with EverGuard Insurance for Rellm: AI-Powered Enterprise Reinsurance Solution\n\n**Contrac...", + "Type: contracts
    Text: 4. **Usage Rights**: EverGuard Insurance is granted a non-exclusive, non-transferable license to acc...", + "Type: contracts
    Text: 1. **Core Functionality**: Rellm provides EverGuard Insurance with advanced AI-driven analytics, sea...", + "Type: contracts
    Text: 1. **Customer Support**: Insurellm will provide EverGuard Insurance with 24/7 customer support, incl...", + "Type: contracts
    Text: ---\n\n**Signatures** \n**For Insurellm**: __________________________ \n**Name**: John Smith \n**Title...", + "Type: contracts
    Text: # Contract with GreenField Holdings for Markellm\n\n**Effective Date:** November 15, 2023 \n**Contract...", + "Type: contracts
    Text: ## Renewal\n1. **Automatic Renewal**: This contract will automatically renew for sequential one-year ...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Matching**: Access to advanced algorithms that connect GreenField Holdin...", + "Type: contracts
    Text: ## Support\n1. **Customer Support Access**: The Client will have access to dedicated support through ...", + "Type: contracts
    Text: **Signatures:** \n_________________________ _________________________ \n**...", + "Type: contracts
    Text: # Contract with Greenstone Insurance for Homellm\n\n---\n\n## Terms\n\n1. **Parties**: This Contract (\"Agr...", + "Type: contracts
    Text: 4. **Payment Terms**: \n - The Customer shall pay an amount of $10,000 per month for the Standard T...", + "Type: contracts
    Text: ---\n\n## Features\n\n- **AI-Powered Risk Assessment**: Customer will have access to enhanced risk evalu...", + "Type: contracts
    Text: - **Customer Portal**: A dedicated portal will be provided, allowing the Customer's clients to manag...", + "Type: contracts
    Text: ______________________________ \n[Name], [Title] \nDate: ______________________\n\n**For Greenstone In...", + "Type: contracts
    Text: # Contract with GreenValley Insurance for Homellm\n\n**Contract Date:** October 6, 2023 \n**Contract N...", + "Type: contracts
    Text: 4. **Confidentiality:** Both parties agree to maintain the confidentiality of proprietary informatio...", + "Type: contracts
    Text: 1. **AI-Powered Risk Assessment:** Access to advanced AI algorithms for real-time risk evaluations.\n...", + "Type: contracts
    Text: 3. **Regular Updates:** Insurellm will offer ongoing updates and enhancements to the Homellm platfor...", + "Type: contracts
    Text: # Contract with Pinnacle Insurance Co. for Homellm\n\n## Terms\nThis contract (\"Contract\") is entered i...", + "Type: contracts
    Text: ## Renewal\n1. **Renewal Terms**: At the end of the initial term, this Contract shall automatically r...", + "Type: contracts
    Text: ## Features\n1. **AI-Powered Risk Assessment**: Utilized for tailored underwriting decisions specific...", + "Type: contracts
    Text: ## Support\n1. **Technical Support**: Insurellm shall provide 24/7 technical support via an email and...", + "Type: contracts
    Text: # Contract with Roadway Insurance Inc. for Carllm\n\n---\n\n## Terms\n\n1. **Agreement Effective Date**: T...", + "Type: contracts
    Text: ---\n\n## Renewal\n\n1. **Automatic Renewal**: This agreement will automatically renew for an additional...", + "Type: contracts
    Text: ---\n\n## Features\n\n1. **Access to Core Features**: Roadway Insurance Inc. will have access to all Pro...", + "Type: contracts
    Text: ---\n\n## Support\n\n1. **Technical Support**: Roadway Insurance Inc. will receive priority technical su...", + "Type: contracts
    Text: # Contract with Stellar Insurance Co. for Rellm\n\n## Terms\nThis contract is made between **Insurellm*...", + "Type: contracts
    Text: ### Termination\nEither party may terminate this agreement with a **30-day written notice**. In the e...", + "Type: contracts
    Text: ## Features\nStellar Insurance Co. will receive access to the following features of the Rellm product...", + "Type: contracts
    Text: ## Support\nInsurellm provides Stellar Insurance Co. with the following support services:\n\n- **24/7 T...", + "Type: contracts
    Text: # Contract with TechDrive Insurance for Carllm\n\n**Contract Date:** October 1, 2024 \n**Contract Dura...", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This contract shall automatically renew for additional one-yea...", + "Type: contracts
    Text: ## Support\n\n1. **Customer Support**: Insurellm will provide 24/7 customer support to TechDrive Insur...", + "Type: contracts
    Text: **TechDrive Insurance Representative:** \nName: Sarah Johnson \nTitle: Operations Director \nDate: _...", + "Type: contracts
    Text: # Contract with Velocity Auto Solutions for Carllm\n\n**Contract Date:** October 1, 2023 \n**Contract ...", + "Type: contracts
    Text: ## Renewal\n\n1. **Automatic Renewal**: This contract will automatically renew for successive 12-month...", + "Type: contracts
    Text: ## Support\n\n1. **Customer Support**: Velocity Auto Solutions will have access to Insurellm’s custome...", + "Type: employees
    Text: # HR Record\n\n# Alex Chen\n\n## Summary\n- **Date of Birth:** March 15, 1990 \n- **Job Title:** Backend ...", + "Type: employees
    Text: ## Annual Performance History\n- **2020:** \n - Completed onboarding successfully. \n - Met expecta...", + "Type: employees
    Text: ## Compensation History\n- **2020:** Base Salary: $80,000 \n- **2021:** Base Salary Increase to $90,0...", + "Type: employees
    Text: Alex Chen continues to be a vital asset at Insurellm, contributing significantly to innovative backe...", + "Type: employees
    Text: # HR Record\n\n# Alex Harper\n\n## Summary\n- **Date of Birth**: March 15, 1993 \n- **Job Title**: Sales ...", + "Type: employees
    Text: ## Annual Performance History \n- **2021**: \n - **Performance Rating**: 4.5/5 \n - **Key Achievem...", + "Type: employees
    Text: - **2022**: \n - **Base Salary**: $65,000 (Promotion to Senior SDR) \n - **Bonus**: $13,000 (20% o...", + "Type: employees
    Text: # HR Record\n\n# Alex Thomson\n\n## Summary\n- **Date of Birth:** March 15, 1995 \n- **Job Title:** Sales...", + "Type: employees
    Text: ## Annual Performance History \n- **2022** - Rated as \"Exceeds Expectations.\" Alex Thomson achieved ...", + "Type: employees
    Text: ## Other HR Notes\n- Alex Thomson is an active member of the Diversity and Inclusion committee at Ins...", + "Type: employees
    Text: # Avery Lancaster\n\n## Summary\n- **Date of Birth**: March 15, 1985 \n- **Job Title**: Co-Founder & Ch...", + "Type: employees
    Text: - **2010 - 2013**: Business Analyst at Edge Analytics \n Prior to joining Innovate, Avery worked as...", + "Type: employees
    Text: - **2018**: **Exceeds Expectations** \n Under Avery’s pivoted vision, Insurellm launched two new su...", + "Type: employees
    Text: - **2022**: **Satisfactory** \n Avery focused on rebuilding team dynamics and addressing employee c...", + "Type: employees
    Text: ## Compensation History\n- **2015**: $150,000 base salary + Significant equity stake \n- **2016**: $1...", + "Type: employees
    Text: ## Other HR Notes\n- **Professional Development**: Avery has actively participated in leadership trai...", + "Type: employees
    Text: # HR Record\n\n# Emily Carter\n\n## Summary\n- **Date of Birth:** August 12, 1990 \n- **Job Title:** Acco...", + "Type: employees
    Text: - **2017-2019:** Marketing Intern \n - Assisted with market research and campaign development for s...", + "Type: employees
    Text: ## Compensation History\n| Year | Base Salary | Bonus | Total Compensation |\n|------|--------...", + "Type: employees
    Text: Emily Carter exemplifies the kind of talent that drives Insurellm's success and is an invaluable ass...", + "Type: employees
    Text: # HR Record\n\n# Emily Tran\n\n## Summary\n- **Date of Birth:** March 18, 1991 \n- **Job Title:** Digital...", + "Type: employees
    Text: - **January 2017 - May 2018**: Marketing Intern \n - Supported the Marketing team by collaborating ...", + "Type: employees
    Text: - **2021**: \n - Performance Rating: Meets Expectations \n - Key Achievements: Contributed to the ...", + "Type: employees
    Text: - **Professional Development Goals**: \n - Emily Tran aims to become a Marketing Manager within the...", + "Type: employees
    Text: # HR Record\n\n# Jordan Blake\n\n## Summary\n- **Date of Birth:** March 15, 1993 \n- **Job Title:** Sales...", + "Type: employees
    Text: ## Annual Performance History\n- **2021:** First year at Insurellm; achieved 90% of monthly targets. ...", + "Type: employees
    Text: ## Other HR Notes\n- Jordan has shown an interest in continuing education, actively participating in ...", + "Type: employees
    Text: # HR Record\n\n# Jordan K. Bishop\n\n## Summary\n- **Date of Birth:** March 15, 1990\n- **Job Title:** Fro...", + "Type: employees
    Text: ## Annual Performance History\n- **2019:** Exceeds Expectations - Continuously delivered high-quality...", + "Type: employees
    Text: ## Compensation History\n- **June 2018:** Starting Salary - $85,000\n- **June 2019:** Salary Increase ...", + "Type: employees
    Text: ## Other HR Notes\n- Jordan K. Bishop has been an integral part of club initiatives, including the In...", + "Type: employees
    Text: # HR Record\n\n# Maxine Thompson\n\n## Summary\n- **Date of Birth:** January 15, 1991 \n- **Job Title:** ...", + "Type: employees
    Text: ## Insurellm Career Progression\n- **January 2017 - October 2018**: **Junior Data Engineer** \n * Ma...", + "Type: employees
    Text: ## Annual Performance History\n- **2017**: *Meets Expectations* \n Maxine showed potential in her ro...", + "Type: employees
    Text: - **2021**: *Exceeds Expectations* \n Maxine spearheaded the transition to a new data warehousing s...", + "Type: employees
    Text: ## Compensation History\n- **2017**: $70,000 (Junior Data Engineer) \n- **2018**: $75,000 (Junior Dat...", + "Type: employees
    Text: # HR Record\n\n# Oliver Spencer\n\n## Summary\n- **Date of Birth**: May 14, 1990 \n- **Job Title**: Backe...", + "Type: employees
    Text: ## Annual Performance History\n- **2018**: **3/5** - Adaptable team player but still learning to take...", + "Type: employees
    Text: ## Compensation History\n- **March 2018**: Initial salary of $80,000.\n- **July 2019**: Salary increas...", + "Type: employees
    Text: # Samantha Greene\n\n## Summary\n- **Date of Birth:** October 14, 1990\n- **Job Title:** HR Generalist\n-...", + "Type: employees
    Text: ## Annual Performance History\n- **2020:** Exceeds Expectations \n Samantha Greene demonstrated exce...", + "Type: employees
    Text: ## Compensation History\n- **2020:** Base Salary - $55,000 \n The entry-level salary matched industr...", + "Type: employees
    Text: - **2023:** Base Salary - $70,000 \n Recognized for substantial improvement in employee relations m...", + "Type: employees
    Text: # HR Record\n\n# Samuel Trenton\n\n## Summary\n- **Date of Birth:** April 12, 1989 \n- **Job Title:** Sen...", + "Type: employees
    Text: ## Annual Performance History\n- **2023:** Rating: 4.5/5 \n *Samuel exceeded expectations, successfu...", + "Type: employees
    Text: ## Compensation History\n- **2023:** Base Salary: $115,000 + Bonus: $15,000 \n *Annual bonus based o...", + "Type: employees
    Text: - **Engagement in Company Culture:** Regularly participates in team-building events and contributes ...", + "Type: products
    Text: # Product Summary\n\n# Carllm\n\n## Summary\n\nCarllm is an innovative auto insurance product developed by...", + "Type: products
    Text: - **Instant Quoting**: With Carllm, insurance companies can offer near-instant quotes to customers, ...", + "Type: products
    Text: - **Mobile Integration**: Carllm is designed to work seamlessly with mobile applications, providing ...", + "Type: products
    Text: - **Professional Tier**: $2,500/month\n - For medium-sized companies.\n - All Basic Tier features pl...", + "Type: products
    Text: ### Q2 2025: Customer Experience Improvements\n- Launch of a new **mobile app** for end-users.\n- Intr...", + "Type: products
    Text: # Product Summary\n\n# Homellm\n\n## Summary\nHomellm is an innovative home insurance product developed b...", + "Type: products
    Text: ### 2. Dynamic Pricing Model\nWith Homellm's innovative dynamic pricing model, insurance providers ca...", + "Type: products
    Text: ### 5. Multi-Channel Integration\nHomellm seamlessly integrates into existing insurance platforms, pr...", + "Type: products
    Text: - **Basic Tier:** Starting at $5,000/month for small insurers with basic integration features.\n- **S...", + "Type: products
    Text: All tiers include a comprehensive training program and ongoing updates to ensure optimal performance...", + "Type: products
    Text: With Homellm, Insurellm is committed to transforming the landscape of home insurance, ensuring both ...", + "Type: products
    Text: # Product Summary\n\n# Markellm\n\n## Summary\n\nMarkellm is an innovative two-sided marketplace designed ...", + "Type: products
    Text: - **User-Friendly Interface**: Designed with user experience in mind, Markellm features an intuitive...", + "Type: products
    Text: - **Customer Support**: Our dedicated support team is always available to assist both consumers and ...", + "Type: products
    Text: ### For Insurance Companies:\n- **Basic Listing Fee**: $199/month for a featured listing on the platf...", + "Type: products
    Text: ### Q3 2025\n- Initiate a comprehensive marketing campaign targeting both consumers and insurers to i...", + "Type: products
    Text: # Product Summary\n\n# Rellm: AI-Powered Enterprise Reinsurance Solution\n\n## Summary\n\nRellm is an inno...", + "Type: products
    Text: ### Seamless Integrations\nRellm's architecture is designed for effortless integration with existing ...", + "Type: products
    Text: ### Regulatory Compliance Tools\nRellm includes built-in compliance tracking features to help organiz...", + "Type: products
    Text: Join the growing number of organizations leveraging Rellm to enhance their reinsurance processes whi...", + "Type: products
    Text: Experience the future of reinsurance with Rellm, where innovation meets reliability. Let Insurellm h..." + ], + "type": "scatter3d", + "x": [ + 81.53388, + 53.523838, + 65.4336, + -11.2568, + -35.23297, + -58.1388, + -70.451775, + 80.44417, + 25.835087, + -99.28855, + 25.3601, + 71.5455, + 39.470325, + 11.782631, + -3.366674, + 23.596594, + 20.719059, + 9.189867, + -6.907728, + 41.62049, + 3.820471, + 22.429987, + -1.9527842, + 2.6615057, + 9.8561535, + -25.084528, + 88.3859, + -43.759174, + -70.171425, + 64.19189, + -73.61963, + 58.55072, + -8.85301, + -21.603752, + 2.7881224, + -45.822075, + -42.858322, + 0.59138376, + -17.384357, + -64.93836, + -5.5359893, + -11.441331, + -11.330225, + -20.265352, + -39.243156, + -63.98278, + -81.72354, + -71.28366, + -9.971935, + -31.514902, + -18.16162, + -4.766756, + -22.621572, + -37.923866, + -47.165283, + -48.194252, + 20.253887, + 223.44736, + -51.686974, + -42.731888, + -3.2548769, + -18.483477, + -44.07783, + 7.867005, + 26.948917, + 106.128426, + 53.68431, + 28.933582, + 34.222527, + -16.782572, + -37.06238, + -52.3044, + 34.171013, + -16.1603, + -48.797993, + -75.184235, + -81.12384, + -65.20964, + -78.65246, + -58.300514, + -27.88297, + -41.794777, + -83.91477, + -41.56064, + 7.7734685, + -74.547615, + -19.879875, + -8.129884, + -1.8509603, + 14.149119, + -4.45687, + -53.21423, + 6.1975307, + 35.461143, + -14.680159, + -20.67162, + -23.223652, + -5.4168777, + 17.79015, + 25.157133, + 11.091784, + 45.41651, + 63.17549, + 50.12626, + 30.874004, + 35.734764, + 80.13974, + 57.350708, + 36.339565, + 25.682257, + 78.46156, + 61.396954, + -83.5418, + 68.61663, + 47.78963, + 47.6066, + 49.488094, + 80.07241, + 57.53512, + 79.77016, + 33.869728, + 63.889473, + -32.792236 + ], + "y": [ + 19.283733, + 11.140304, + 34.85373, + 66.58248, + 20.496525, + 18.66278, + 63.37658, + -38.804882, + 36.968765, + 11.0408945, + -2.8027616, + -0.6743983, + 61.195312, + 26.506996, + 19.132858, + 17.96988, + 41.849804, + 83.186935, + -16.386538, + 84.47603, + 21.801687, + 7.00924, + 51.315266, + -36.286488, + -3.6705906, + 61.74415, + -32.81874, + 91.45265, + 64.3316, + -72.978806, + 43.9395, + -35.78357, + 8.203194, + 68.245834, + 55.084503, + 68.109634, + 82.05149, + -18.306131, + 1.9083865, + 63.671555, + 26.325958, + -9.275049, + -32.211662, + 29.510502, + 52.090054, + 24.063622, + 26.914606, + 46.11639, + 50.52323, + 41.756107, + 30.933, + 101.60333, + 75.41632, + 16.445831, + 91.67727, + -41.476246, + -49.900795, + 15.246118, + -25.914267, + -37.00789, + -70.7613, + -40.41268, + -24.553493, + -97.089226, + -107.92218, + 8.401706, + -64.885956, + -64.041595, + -59.68835, + -63.750614, + -17.248238, + -9.267501, + -71.522736, + -10.604969, + 13.532798, + -19.520105, + -42.81251, + -65.766785, + -22.81011, + -46.88173, + -63.41763, + -65.60392, + -49.578648, + -92.86681, + -72.58249, + -63.928215, + -13.93383, + -46.0743, + -75.10812, + -51.170418, + -37.75353, + -67.76687, + 103.12513, + -74.91113, + -83.86663, + -107.106705, + -93.31034, + -99.96602, + -5.3622127, + -24.922474, + -45.96636, + -35.28478, + 59.117798, + 48.3417, + 51.33213, + 76.26867, + 52.505924, + 27.40437, + 14.75013, + 28.69867, + 4.7155714, + -7.247487, + -34.02125, + -1.7822995, + 0.14419319, + 19.239779, + -8.316879, + 23.734856, + 85.2096, + -47.07777, + 61.757893, + 59.476, + 38.759068 + ], + "z": [ + -14.29453, + -34.71637, + -28.59993, + -22.65612, + -8.054486, + 58.79845, + -3.3757033, + 14.808398, + -66.40088, + -2.968062, + 21.89932, + -62.77509, + -59.61707, + -42.63285, + -20.359333, + -6.960816, + -24.642426, + -7.943236, + 98.445076, + -8.870388, + 101.567474, + 109.36959, + -54.67124, + 18.714115, + 60.153572, + -67.19362, + -5.8205786, + 63.059887, + 65.17404, + 4.4357395, + -27.966211, + -5.472546, + 264.10822, + 52.605568, + 50.606712, + 39.145245, + -33.420185, + 0.98187125, + 70.157196, + -46.92285, + 17.546955, + 28.075523, + 57.448467, + 47.964592, + -15.538981, + 3.036544, + 33.89405, + 18.556377, + 8.348332, + 20.07917, + -83.82076, + -44.158554, + 11.562198, + 26.33919, + 7.3630586, + 28.997889, + -19.409937, + 213.27306, + 47.549023, + -27.961267, + -33.38058, + -29.46969, + -67.14885, + -33.69737, + -4.7212925, + -12.064441, + 51.81019, + 51.387836, + 29.224623, + -1.6933604, + 2.5197253, + -38.66655, + -32.058723, + -46.31407, + -51.627632, + -18.293224, + -9.943942, + -7.30543, + 6.786018, + -47.776237, + -52.915794, + -71.69413, + -59.169884, + -39.777233, + -0.20590062, + -75.22719, + -96.832146, + -103.80248, + -78.61911, + -96.8633, + -80.49291, + 34.09247, + 34.139854, + -69.749855, + 50.413597, + -3.7609684, + 16.896708, + 37.713326, + -83.134605, + -47.321796, + -50.20056, + -63.635235, + 74.50581, + 53.450645, + 71.70312, + 64.599655, + 45.940273, + 84.374146, + 64.53904, + 43.600063, + 62.300507, + 74.37096, + 55.983784, + 20.760025, + -0.25919074, + 15.355031, + 36.588936, + 24.362068, + 21.700638, + -40.98002, + 17.98443, + 6.0238895, + 88.67324 + ] + } + ], + "layout": { + "height": 700, + "margin": { + "b": 10, + "l": 10, + "r": 20, + "t": 40 + }, + "scene": { + "xaxis": { + "title": { + "text": "x" + } + }, + "yaxis": { + "title": { + "text": "y" + } + }, + "zaxis": { + "title": { + "text": "z" + } + } + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "3D Chroma Vector Store Visualization" + }, + "width": 900 + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Let's try 3D!\n", + "\n", + "tsne = TSNE(n_components=3, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 3D scatter plot\n", + "fig = go.Figure(data=[go.Scatter3d(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " z=reduced_vectors[:, 2],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
    Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='3D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x', yaxis_title='y', zaxis_title='z'),\n", + " width=900,\n", + " height=700,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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": 2 +} diff --git a/week5/community-contributions/day4-gemini.ipynb b/week5/community-contributions/day4-gemini.ipynb new file mode 100644 index 0000000..431ce5d --- /dev/null +++ b/week5/community-contributions/day4-gemini.ipynb @@ -0,0 +1,433 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import glob\n", + "from dotenv import load_dotenv\n", + "import gradio as gr\n", + "# import gemini\n", + "import google.generativeai" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain\n", + "\n", + "from langchain.document_loaders import DirectoryLoader, TextLoader\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.schema import Document\n", + "# from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_chroma import Chroma\n", + "from langchain_google_genai import GoogleGenerativeAIEmbeddings, ChatGoogleGenerativeAI\n", + "import numpy as np\n", + "from sklearn.manifold import TSNE\n", + "import plotly.graph_objects as go\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# price is a factor for our company, so we're going to use a low cost model\n", + "\n", + "MODEL = \"gemini-1.5-flash\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\n", + "os.environ['GOOGLE_API_KEY'] = os.getenv('GOOGLE_API_KEY', 'your-key-if-not-using-env')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "google.generativeai.configure()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Read in documents using LangChain's loaders\n", + "# Take everything in all the sub-folders of our knowledgebase\n", + "\n", + "folders = glob.glob(\"knowledge-base/*\")\n", + "\n", + "# With thanks to CG and Jon R, students on the course, for this fix needed for some users \n", + "text_loader_kwargs = {'encoding': 'utf-8'}\n", + "# If that doesn't work, some Windows users might need to uncomment the next line instead\n", + "# text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "documents = []\n", + "for folder in folders:\n", + " doc_type = os.path.basename(folder)\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + " for doc in folder_docs:\n", + " doc.metadata[\"doc_type\"] = doc_type\n", + " documents.append(doc)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Created a chunk of size 1088, which is longer than the specified 1000\n" + ] + } + ], + "source": [ + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "123" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(chunks)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Document types found: company, contracts, employees, products\n" + ] + } + ], + "source": [ + "doc_types = set(chunk.metadata['doc_type'] for chunk in chunks)\n", + "print(f\"Document types found: {', '.join(doc_types)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Vectorstore created with 123 documents\n" + ] + } + ], + "source": [ + "embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")\n", + "\n", + "# Check if a Chroma Datastore already exists - if so, delete the collection to start from scratch\n", + "\n", + "if os.path.exists(db_name):\n", + " Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection()\n", + "\n", + "# Create our Chroma vectorstore!\n", + "\n", + "vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=db_name)\n", + "print(f\"Vectorstore created with {vectorstore._collection.count()} documents\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The vectors have 768 dimensions\n" + ] + } + ], + "source": [ + "# Get one vector and find how many dimensions it has\n", + "\n", + "collection = vectorstore._collection\n", + "sample_embedding = collection.get(limit=1, include=[\"embeddings\"])[\"embeddings\"][0]\n", + "dimensions = len(sample_embedding)\n", + "print(f\"The vectors have {dimensions:,} dimensions\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# Prework\n", + "\n", + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "doc_types = [metadata['doc_type'] for metadata in result['metadatas']]\n", + "colors = [['blue', 'green', 'red', 'orange'][['products', 'employees', 'contracts', 'company'].index(t)] for t in doc_types]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# We humans find it easier to visalize things in 2D!\n", + "# Reduce the dimensionality of the vectors to 2D using t-SNE\n", + "# (t-distributed stochastic neighbor embedding)\n", + "\n", + "tsne = TSNE(n_components=2, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 2D scatter plot\n", + "fig = go.Figure(data=[go.Scatter(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
    Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='2D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x',yaxis_title='y'),\n", + " width=800,\n", + " height=600,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's try 3D!\n", + "\n", + "tsne = TSNE(n_components=3, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 3D scatter plot\n", + "fig = go.Figure(data=[go.Scatter3d(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " z=reduced_vectors[:, 2],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
    Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='3D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x', yaxis_title='y', zaxis_title='z'),\n", + " width=900,\n", + " height=700,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "RAG pipeline using langchain" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\GANESH\\AppData\\Local\\Temp\\ipykernel_524\\4130109764.py:5: LangChainDeprecationWarning:\n", + "\n", + "Please see the migration guide at: https://python.langchain.com/docs/versions/migrating_memory/\n", + "\n" + ] + } + ], + "source": [ + "# create a new Chat with ChatGoogleGenerativeAI\n", + "llm = ChatGoogleGenerativeAI(model=MODEL, temperature=0.7)\n", + "\n", + "# set up the conversation memory for the chat\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + "\n", + "# the retriever is an abstraction over the VectorStore that will be used during RAG\n", + "retriever = vectorstore.as_retriever()\n", + "\n", + "# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Insurellm is an insurance technology company with 200 employees and over 300 clients worldwide. They offer four software products, including Homellm, a portal for home insurance companies that integrates with existing platforms and offers a customer portal for policy management. Their pricing model is based on provider size and customization needs.\n" + ] + } + ], + "source": [ + "query = \"Can you describe Insurellm in a few sentences\"\n", + "result = conversation_chain.invoke({\"question\":query})\n", + "print(result[\"answer\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# set up a new conversation memory for the chat\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + "\n", + "# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Gradio User Interface" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\n", + " result = conversation_chain.invoke({\"question\": message})\n", + " return result[\"answer\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7860\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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": 2 +} From 51e5d152fa5198631e3d9d2ef4164ef8acbba583 Mon Sep 17 00:00:00 2001 From: Dimitris Sinanis Date: Wed, 26 Feb 2025 14:23:24 +0200 Subject: [PATCH 15/22] Add book flight and sightseeing functions in day5. Audio worked with variation 1. --- .../day5_book_flight_sightseeing_tools.ipynb | 1108 +++++++++++++++++ 1 file changed, 1108 insertions(+) create mode 100644 week2/community-contributions/day5_book_flight_sightseeing_tools.ipynb diff --git a/week2/community-contributions/day5_book_flight_sightseeing_tools.ipynb b/week2/community-contributions/day5_book_flight_sightseeing_tools.ipynb new file mode 100644 index 0000000..6ceeaaf --- /dev/null +++ b/week2/community-contributions/day5_book_flight_sightseeing_tools.ipynb @@ -0,0 +1,1108 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ddfa9ae6-69fe-444a-b994-8c4c5970a7ec", + "metadata": {}, + "source": [ + "# Project - Airline AI Assistant\n", + "\n", + "We'll now bring together what we've learned to make an AI Customer Support assistant for an Airline" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8b50bbe2-c0b1-49c3-9a5c-1ba7efa2bcb4", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "747e8786-9da8-4342-b6c9-f5f69c2e22ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n" + ] + } + ], + "source": [ + "# Initialization\n", + "\n", + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "MODEL = \"gpt-4o-mini\"\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0a521d84-d07c-49ab-a0df-d6451499ed97", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\n", + "system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n", + "system_message += \"Always be accurate. If you don't know the answer, say so.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61a2a15d-b559-4844-b377-6bd5cb4949f6", + "metadata": {}, + "outputs": [], + "source": [ + "# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n", + "\n", + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " return response.choices[0].message.content\n", + "\n", + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "markdown", + "id": "36bedabf-a0a7-4985-ad8e-07ed6a55a3a4", + "metadata": {}, + "source": [ + "## Tools\n", + "\n", + "Tools are an incredibly powerful feature provided by the frontier LLMs.\n", + "\n", + "With tools, you can write a function, and have the LLM call that function as part of its response.\n", + "\n", + "Sounds almost spooky.. we're giving it the power to run code on our machine?\n", + "\n", + "Well, kinda." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0696acb1-0b05-4dc2-80d5-771be04f1fb2", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's start by making a useful function\n", + "\n", + "ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\", \"athens\": \"$599\", \"kastoria\": \"$999\"}\n", + "\n", + "def get_ticket_price(destination_city):\n", + " print(f\"Tool get_ticket_price called for {destination_city}\")\n", + " city = destination_city.lower()\n", + " return ticket_prices.get(city, \"Unknown\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "80ca4e09-6287-4d3f-997d-fa6afbcf6c85", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_ticket_price called for London\n" + ] + }, + { + "data": { + "text/plain": [ + "'$799'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_ticket_price(\"London\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2054c00e", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "# Create a function for the booking system\n", + "def get_booking(destination_city):\n", + " print(f\"Tool get_booking called for {destination_city}\")\n", + " city = destination_city.lower()\n", + " \n", + " # Example data for different cities\n", + " flight_info = {\n", + " \"london\": {\"flight_number\": \"BA123\", \"departure_time\": \"10:00 AM\", \"gate\": \"A12\"},\n", + " \"paris\": {\"flight_number\": \"AF456\", \"departure_time\": \"12:00 PM\", \"gate\": \"B34\"},\n", + " \"tokyo\": {\"flight_number\": \"JL789\", \"departure_time\": \"02:00 PM\", \"gate\": \"C56\"},\n", + " \"berlin\": {\"flight_number\": \"LH101\", \"departure_time\": \"04:00 PM\", \"gate\": \"D78\"},\n", + " \"athens\": {\"flight_number\": \"OA202\", \"departure_time\": \"06:00 PM\", \"gate\": \"E90\"},\n", + " \"kastoria\": {\"flight_number\": \"KAS303\", \"departure_time\": \"08:00 PM\", \"gate\": \"F12\"}\n", + " }\n", + " \n", + " if city in flight_info:\n", + " info = flight_info[city]\n", + " status = random.choice([\"available\", \"not available\"])\n", + " return f\"Flight {info['flight_number']} to {destination_city.lower()} is {status}. Departure time: {info['departure_time']}, Gate: {info['gate']}.\"\n", + " else:\n", + " return \"Unknown destination city.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "ef334206", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_booking called for London\n" + ] + }, + { + "data": { + "text/plain": [ + "'Flight BA123 to london is not available. Departure time: 10:00 AM, Gate: A12.'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_booking(\"London\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b011afc2", + "metadata": {}, + "outputs": [], + "source": [ + "sightseeing_info = {\"london\": \"London Eye, Big Ben, Tower of London\", \n", + " \"paris\": \"Eiffel Tower, Louvre Museum, Notre-Dame Cathedral\", \n", + " \"tokyo\": \"Tokyo Tower, Senso-ji Temple, Meiji Shrine\", \n", + " \"berlin\": \"Brandenburg Gate, Berlin Wall, Museum Island\", \n", + " \"athens\": \"Acropolis, Parthenon, Temple of Olympian Zeus\", \n", + " \"kastoria\": \"Cave of Dragon, Kastoria Lake, Byzantine Museum\"}\n", + "\n", + "\n", + "def get_sightseeing(destination_city):\n", + " print(f\"Tool get_ticket_price called for {destination_city}\")\n", + " city = destination_city.lower()\n", + " return sightseeing_info.get(city, \"Unknown\")\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "3008e353", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_ticket_price called for Kastoria\n" + ] + }, + { + "data": { + "text/plain": [ + "'Cave of Dragon, Kastoria Lake, Byzantine Museum'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_sightseeing(\"Kastoria\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "4afceded-7178-4c05-8fa6-9f2085e6a344", + "metadata": {}, + "outputs": [], + "source": [ + "# There's a particular dictionary structure that's required to describe our function:\n", + "\n", + "price_function = {\n", + " \"name\": \"get_ticket_price\",\n", + " \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"destination_city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city that the customer wants to travel to\",\n", + " },\n", + " },\n", + " \"required\": [\"destination_city\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}\n", + "\n", + "# Book flight function description and properties\n", + "\n", + "book_flight_function = {\n", + " \"name\": \"book_flight\",\n", + " \"description\": \"Book a flight to the destination city. Call this whenever a customer wants to book a flight.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"destination_city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city that the customer wants to travel to\",\n", + " },\n", + " \"departure_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The date of departure (YYYY-MM-DD)\",\n", + " },\n", + " \"return_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The date of return (YYYY-MM-DD)\",\n", + " },\n", + " \"passenger_name\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The name of the passenger\",\n", + " },\n", + " },\n", + " \"required\": [\"destination_city\", \"departure_date\", \"return_date\", \"passenger_name\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}\n", + "\n", + "sightseeing_function = {\n", + " \"name\": \"sightseeing\",\n", + " \"description\": \"Get the top sightseeing recommendations for the destination city. Call this whenever a customer asks 'What are the top things to do in this city'\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"destination_city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city that the customer wants to travel to\",\n", + " },\n", + " },\n", + " \"required\": [\"destination_city\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "bdca8679-935f-4e7f-97e6-e71a4d4f228c", + "metadata": {}, + "outputs": [], + "source": [ + "# And this is included in a list of tools:\n", + "\n", + "tools = [{\"type\": \"function\", \"function\": price_function}, \n", + " {\"type\": \"function\", \"function\": book_flight_function},\n", + " {\"type\": \"function\", \"function\": sightseeing_function}]" + ] + }, + { + "cell_type": "markdown", + "id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340", + "metadata": {}, + "source": [ + "## Getting OpenAI to use our Tool\n", + "\n", + "There's some fiddly stuff to allow OpenAI \"to call our tool\"\n", + "\n", + "What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n", + "\n", + "Here's how the new chat function looks:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "ce9b0744-9c78-408d-b9df-9f6fd9ed78cf", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + "\n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " response, city = handle_tool_call(message)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "b0992986-ea09-4912-a076-8e5603ee631f", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call(message):\n", + " tool_call = message.tool_calls[0]\n", + " print(f\"Tool call: {tool_call}\")\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " city = arguments.get('destination_city')\n", + " price = get_ticket_price(city)\n", + " book = get_booking(city)\n", + " sightseeing = get_sightseeing(city)\n", + " print (book)\n", + " response = {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps({\"destination_city\": city,\"price\": price, \"booking\": book, \"sightseeing\": sightseeing}),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " return response, city" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4be8a71-b19e-4c2f-80df-f59ff2661f14", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "markdown", + "id": "473e5b39-da8f-4db1-83ae-dbaca2e9531e", + "metadata": {}, + "source": [ + "# Let's go multi-modal!!\n", + "\n", + "We can use DALL-E-3, the image generation model behind GPT-4o, to make us some images\n", + "\n", + "Let's put this in a function called artist.\n", + "\n", + "### Price alert: each time I generate an image it costs about 4 cents - don't go crazy with images!" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "2c27c4ba-8ed5-492f-add1-02ce9c81d34c", + "metadata": {}, + "outputs": [], + "source": [ + "# Some imports for handling images\n", + "\n", + "import base64\n", + "from io import BytesIO\n", + "from PIL import Image" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "773a9f11-557e-43c9-ad50-56cbec3a0f8f", + "metadata": {}, + "outputs": [], + "source": [ + "def artist(city):\n", + " image_response = openai.images.generate(\n", + " model=\"dall-e-3\",\n", + " prompt=f\"An image representing a vacation in {city}, showing tourist spots and everything unique about {city}, in a vibrant pop-art style\",\n", + " size=\"1024x1024\",\n", + " n=1,\n", + " response_format=\"b64_json\",\n", + " )\n", + " image_base64 = image_response.data[0].b64_json\n", + " image_data = base64.b64decode(image_base64)\n", + " return Image.open(BytesIO(image_data))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d877c453-e7fb-482a-88aa-1a03f976b9e9", + "metadata": {}, + "outputs": [], + "source": [ + "image = artist(\"Athens\")\n", + "display(image)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "728a12c5-adc3-415d-bb05-82beb73b079b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "f4975b87-19e9-4ade-a232-9b809ec75c9a", + "metadata": {}, + "source": [ + "## Audio (NOTE - Audio is optional for this course - feel free to skip Audio if it causes trouble!)\n", + "\n", + "And let's make a function talker that uses OpenAI's speech model to generate Audio\n", + "\n", + "### Troubleshooting Audio issues\n", + "\n", + "If you have any problems running this code below (like a FileNotFound error, or a warning of a missing package), you may need to install FFmpeg, a very popular audio utility.\n", + "\n", + "**For PC Users**\n", + "\n", + "Detailed instructions are [here](https://chatgpt.com/share/6724efee-6b0c-8012-ac5e-72e2e3885905) and summary instructions:\n", + "\n", + "1. Download FFmpeg from the official website: https://ffmpeg.org/download.html\n", + "\n", + "2. Extract the downloaded files to a location on your computer (e.g., `C:\\ffmpeg`)\n", + "\n", + "3. Add the FFmpeg bin folder to your system PATH:\n", + "- Right-click on 'This PC' or 'My Computer' and select 'Properties'\n", + "- Click on 'Advanced system settings'\n", + "- Click on 'Environment Variables'\n", + "- Under 'System variables', find and edit 'Path'\n", + "- Add a new entry with the path to your FFmpeg bin folder (e.g., `C:\\ffmpeg\\bin`)\n", + "- Restart your command prompt, and within Jupyter Lab do Kernel -> Restart kernel, to pick up the changes\n", + "\n", + "4. Open a new command prompt and run this to make sure it's installed OK\n", + "`ffmpeg -version`\n", + "\n", + "**For Mac Users**\n", + "\n", + "1. Install homebrew if you don't have it already by running this in a Terminal window and following any instructions: \n", + "`/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"`\n", + "\n", + "2. Then install FFmpeg with `brew install ffmpeg`\n", + "\n", + "3. Verify your installation with `ffmpeg -version` and if everything is good, within Jupyter Lab do Kernel -> Restart kernel to pick up the changes\n", + "\n", + "Message me or email me at ed@edwarddonner.com with any problems!" + ] + }, + { + "cell_type": "markdown", + "id": "4cc90e80-c96e-4dd4-b9d6-386fe2b7e797", + "metadata": {}, + "source": [ + "## To check you now have ffmpeg and can access it here\n", + "\n", + "Excecute the next cell to see if you get a version number. (Putting an exclamation mark before something in Jupyter Lab tells it to run it as a terminal command rather than python code).\n", + "\n", + "If this doesn't work, you may need to actually save and close down your Jupyter lab, and start it again from a new Terminal window (Mac) or Anaconda prompt (PC), remembering to activate the llms environment. This ensures you pick up ffmpeg.\n", + "\n", + "And if that doesn't work, please contact me!" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "7b3be0fb-1d34-4693-ab6f-dbff190afcd7", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "'ffmpeg' is not recognized as an internal or external command,\n", + "operable program or batch file.\n", + "'ffprobe' is not recognized as an internal or external command,\n", + "operable program or batch file.\n", + "'ffplay' is not recognized as an internal or external command,\n", + "operable program or batch file.\n" + ] + } + ], + "source": [ + "!ffmpeg -version\n", + "!ffprobe -version\n", + "!ffplay -version" + ] + }, + { + "cell_type": "markdown", + "id": "d91d3f8f-e505-4e3c-a87c-9e42ed823db6", + "metadata": {}, + "source": [ + "# For Mac users - and possibly many PC users too\n", + "\n", + "This version should work fine for you. It might work for Windows users too, but you might get a Permissions error writing to a temp file. If so, see the next section!\n", + "\n", + "As always, if you have problems, please contact me! (You could also comment out the audio talker() in the later code if you're less interested in audio generation)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ffbfe93b-5e86-4e68-ba71-b301cd5230db", + "metadata": {}, + "outputs": [], + "source": [ + "from pydub import AudioSegment\n", + "from pydub.playback import play\n", + "\n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\", # Also, try replacing onyx with alloy\n", + " input=message\n", + " )\n", + " \n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + " play(audio)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b88d775d-d357-4292-a1ad-5dc5ed567281", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\utils.py:198: RuntimeWarning: Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work\n", + " warn(\"Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work\", RuntimeWarning)\n" + ] + }, + { + "ename": "FileNotFoundError", + "evalue": "[WinError 2] The system cannot find the file specified", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[17], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mtalker\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mWell, hi there\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[1;32mIn[16], line 12\u001b[0m, in \u001b[0;36mtalker\u001b[1;34m(message)\u001b[0m\n\u001b[0;32m 5\u001b[0m response \u001b[38;5;241m=\u001b[39m openai\u001b[38;5;241m.\u001b[39maudio\u001b[38;5;241m.\u001b[39mspeech\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[0;32m 6\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtts-1\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 7\u001b[0m voice\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124monyx\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;66;03m# Also, try replacing onyx with alloy\u001b[39;00m\n\u001b[0;32m 8\u001b[0m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mmessage\n\u001b[0;32m 9\u001b[0m )\n\u001b[0;32m 11\u001b[0m audio_stream \u001b[38;5;241m=\u001b[39m BytesIO(response\u001b[38;5;241m.\u001b[39mcontent)\n\u001b[1;32m---> 12\u001b[0m audio \u001b[38;5;241m=\u001b[39m \u001b[43mAudioSegment\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_file\u001b[49m\u001b[43m(\u001b[49m\u001b[43maudio_stream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmp3\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 13\u001b[0m play(audio)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\audio_segment.py:728\u001b[0m, in \u001b[0;36mAudioSegment.from_file\u001b[1;34m(cls, file, format, codec, parameters, start_second, duration, **kwargs)\u001b[0m\n\u001b[0;32m 726\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 727\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 728\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[43mmediainfo_json\u001b[49m\u001b[43m(\u001b[49m\u001b[43morig_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mread_ahead_limit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_ahead_limit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 729\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m info:\n\u001b[0;32m 730\u001b[0m audio_streams \u001b[38;5;241m=\u001b[39m [x \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m info[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstreams\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m 731\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcodec_type\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\utils.py:274\u001b[0m, in \u001b[0;36mmediainfo_json\u001b[1;34m(filepath, read_ahead_limit)\u001b[0m\n\u001b[0;32m 271\u001b[0m file\u001b[38;5;241m.\u001b[39mclose()\n\u001b[0;32m 273\u001b[0m command \u001b[38;5;241m=\u001b[39m [prober, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-of\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mjson\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m+\u001b[39m command_args\n\u001b[1;32m--> 274\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstdin_parameter\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstderr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 275\u001b[0m output, stderr \u001b[38;5;241m=\u001b[39m res\u001b[38;5;241m.\u001b[39mcommunicate(\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mstdin_data)\n\u001b[0;32m 276\u001b[0m output \u001b[38;5;241m=\u001b[39m output\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1026\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[1;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)\u001b[0m\n\u001b[0;32m 1022\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[0;32m 1023\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[0;32m 1024\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[1;32m-> 1026\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1027\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1028\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1029\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1030\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1031\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1032\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1033\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1034\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprocess_group\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1035\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[0;32m 1036\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[0;32m 1037\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1538\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[1;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_gid, unused_gids, unused_uid, unused_umask, unused_start_new_session, unused_process_group)\u001b[0m\n\u001b[0;32m 1536\u001b[0m \u001b[38;5;66;03m# Start the process\u001b[39;00m\n\u001b[0;32m 1537\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1538\u001b[0m hp, ht, pid, tid \u001b[38;5;241m=\u001b[39m \u001b[43m_winapi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mCreateProcess\u001b[49m\u001b[43m(\u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1539\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# no special security\u001b[39;49;00m\n\u001b[0;32m 1540\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 1541\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1542\u001b[0m \u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1543\u001b[0m \u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1544\u001b[0m \u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1545\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1546\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 1547\u001b[0m \u001b[38;5;66;03m# Child is launched. Close the parent's copy of those pipe\u001b[39;00m\n\u001b[0;32m 1548\u001b[0m \u001b[38;5;66;03m# handles that only the child should have open. You need\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1551\u001b[0m \u001b[38;5;66;03m# pipe will not close when the child process exits and the\u001b[39;00m\n\u001b[0;32m 1552\u001b[0m \u001b[38;5;66;03m# ReadFile will hang.\u001b[39;00m\n\u001b[0;32m 1553\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_close_pipe_fds(p2cread, p2cwrite,\n\u001b[0;32m 1554\u001b[0m c2pread, c2pwrite,\n\u001b[0;32m 1555\u001b[0m errread, errwrite)\n", + "\u001b[1;31mFileNotFoundError\u001b[0m: [WinError 2] The system cannot find the file specified" + ] + } + ], + "source": [ + "talker(\"Well, hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "ad89a9bd-bb1e-4bbb-a49a-83af5f500c24", + "metadata": {}, + "source": [ + "# For Windows users (or any Mac users with problems above)\n", + "\n", + "## First try the Mac version above, but if you get a permissions error writing to a temp file, then this code should work instead.\n", + "\n", + "A collaboration between students Mark M. and Patrick H. and Claude got this resolved!\n", + "\n", + "Below are 4 variations - hopefully one of them will work on your PC. If not, message me please!\n", + "\n", + "And for Mac people - all 3 of the below work on my Mac too - please try these if the Mac version gave you problems.\n", + "\n", + "## PC Variation 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d104b96a-02ca-4159-82fe-88e0452aa479", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import base64\n", + "from io import BytesIO\n", + "from PIL import Image\n", + "from IPython.display import Audio, display\n", + "\n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\",\n", + " input=message)\n", + "\n", + " audio_stream = BytesIO(response.content)\n", + " output_filename = \"output_audio.mp3\"\n", + " with open(output_filename, \"wb\") as f:\n", + " f.write(audio_stream.read())\n", + "\n", + " # Play the generated audio\n", + " display(Audio(output_filename, autoplay=True))\n", + "\n", + "talker(\"Well, hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "3a5d11f4-bbd3-43a1-904d-f684eb5f3e3a", + "metadata": {}, + "source": [ + "## PC Variation 2" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "d59c8ebd-79c5-498a-bdf2-3a1c50d91aa0", + "metadata": {}, + "outputs": [ + { + "ename": "FileNotFoundError", + "evalue": "[WinError 2] The system cannot find the file specified", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[19], line 36\u001b[0m\n\u001b[0;32m 33\u001b[0m audio \u001b[38;5;241m=\u001b[39m AudioSegment\u001b[38;5;241m.\u001b[39mfrom_file(audio_stream, \u001b[38;5;28mformat\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmp3\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 34\u001b[0m play_audio(audio)\n\u001b[1;32m---> 36\u001b[0m \u001b[43mtalker\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mWell hi there\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[1;32mIn[19], line 33\u001b[0m, in \u001b[0;36mtalker\u001b[1;34m(message)\u001b[0m\n\u001b[0;32m 27\u001b[0m response \u001b[38;5;241m=\u001b[39m openai\u001b[38;5;241m.\u001b[39maudio\u001b[38;5;241m.\u001b[39mspeech\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[0;32m 28\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtts-1\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 29\u001b[0m voice\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124monyx\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;66;03m# Also, try replacing onyx with alloy\u001b[39;00m\n\u001b[0;32m 30\u001b[0m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mmessage\n\u001b[0;32m 31\u001b[0m )\n\u001b[0;32m 32\u001b[0m audio_stream \u001b[38;5;241m=\u001b[39m BytesIO(response\u001b[38;5;241m.\u001b[39mcontent)\n\u001b[1;32m---> 33\u001b[0m audio \u001b[38;5;241m=\u001b[39m \u001b[43mAudioSegment\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_file\u001b[49m\u001b[43m(\u001b[49m\u001b[43maudio_stream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmp3\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 34\u001b[0m play_audio(audio)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\audio_segment.py:728\u001b[0m, in \u001b[0;36mAudioSegment.from_file\u001b[1;34m(cls, file, format, codec, parameters, start_second, duration, **kwargs)\u001b[0m\n\u001b[0;32m 726\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 727\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 728\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[43mmediainfo_json\u001b[49m\u001b[43m(\u001b[49m\u001b[43morig_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mread_ahead_limit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_ahead_limit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 729\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m info:\n\u001b[0;32m 730\u001b[0m audio_streams \u001b[38;5;241m=\u001b[39m [x \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m info[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstreams\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m 731\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcodec_type\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\utils.py:274\u001b[0m, in \u001b[0;36mmediainfo_json\u001b[1;34m(filepath, read_ahead_limit)\u001b[0m\n\u001b[0;32m 271\u001b[0m file\u001b[38;5;241m.\u001b[39mclose()\n\u001b[0;32m 273\u001b[0m command \u001b[38;5;241m=\u001b[39m [prober, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-of\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mjson\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m+\u001b[39m command_args\n\u001b[1;32m--> 274\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstdin_parameter\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstderr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 275\u001b[0m output, stderr \u001b[38;5;241m=\u001b[39m res\u001b[38;5;241m.\u001b[39mcommunicate(\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mstdin_data)\n\u001b[0;32m 276\u001b[0m output \u001b[38;5;241m=\u001b[39m output\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1026\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[1;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)\u001b[0m\n\u001b[0;32m 1022\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[0;32m 1023\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[0;32m 1024\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[1;32m-> 1026\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1027\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1028\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1029\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1030\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1031\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1032\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1033\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1034\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprocess_group\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1035\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[0;32m 1036\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[0;32m 1037\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1538\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[1;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_gid, unused_gids, unused_uid, unused_umask, unused_start_new_session, unused_process_group)\u001b[0m\n\u001b[0;32m 1536\u001b[0m \u001b[38;5;66;03m# Start the process\u001b[39;00m\n\u001b[0;32m 1537\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1538\u001b[0m hp, ht, pid, tid \u001b[38;5;241m=\u001b[39m \u001b[43m_winapi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mCreateProcess\u001b[49m\u001b[43m(\u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1539\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# no special security\u001b[39;49;00m\n\u001b[0;32m 1540\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 1541\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1542\u001b[0m \u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1543\u001b[0m \u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1544\u001b[0m \u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1545\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1546\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 1547\u001b[0m \u001b[38;5;66;03m# Child is launched. Close the parent's copy of those pipe\u001b[39;00m\n\u001b[0;32m 1548\u001b[0m \u001b[38;5;66;03m# handles that only the child should have open. You need\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1551\u001b[0m \u001b[38;5;66;03m# pipe will not close when the child process exits and the\u001b[39;00m\n\u001b[0;32m 1552\u001b[0m \u001b[38;5;66;03m# ReadFile will hang.\u001b[39;00m\n\u001b[0;32m 1553\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_close_pipe_fds(p2cread, p2cwrite,\n\u001b[0;32m 1554\u001b[0m c2pread, c2pwrite,\n\u001b[0;32m 1555\u001b[0m errread, errwrite)\n", + "\u001b[1;31mFileNotFoundError\u001b[0m: [WinError 2] The system cannot find the file specified" + ] + } + ], + "source": [ + "import tempfile\n", + "import subprocess\n", + "from io import BytesIO\n", + "from pydub import AudioSegment\n", + "import time\n", + "\n", + "def play_audio(audio_segment):\n", + " temp_dir = tempfile.gettempdir()\n", + " temp_path = os.path.join(temp_dir, \"temp_audio.wav\")\n", + " try:\n", + " audio_segment.export(temp_path, format=\"wav\")\n", + " time.sleep(3) # Student Dominic found that this was needed. You could also try commenting out to see if not needed on your PC\n", + " subprocess.call([\n", + " \"ffplay\",\n", + " \"-nodisp\",\n", + " \"-autoexit\",\n", + " \"-hide_banner\",\n", + " temp_path\n", + " ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n", + " finally:\n", + " try:\n", + " os.remove(temp_path)\n", + " except Exception:\n", + " pass\n", + " \n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\", # Also, try replacing onyx with alloy\n", + " input=message\n", + " )\n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + " play_audio(audio)\n", + "\n", + "talker(\"Well hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "96f90e35-f71e-468e-afea-07b98f74dbcf", + "metadata": {}, + "source": [ + "## PC Variation 3" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "8597c7f8-7b50-44ad-9b31-db12375cd57b", + "metadata": {}, + "outputs": [ + { + "ename": "FileNotFoundError", + "evalue": "[WinError 2] The system cannot find the file specified", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[20], line 26\u001b[0m\n\u001b[0;32m 22\u001b[0m audio \u001b[38;5;241m=\u001b[39m AudioSegment\u001b[38;5;241m.\u001b[39mfrom_file(audio_stream, \u001b[38;5;28mformat\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmp3\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 24\u001b[0m play(audio)\n\u001b[1;32m---> 26\u001b[0m \u001b[43mtalker\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mWell hi there\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[1;32mIn[20], line 22\u001b[0m, in \u001b[0;36mtalker\u001b[1;34m(message)\u001b[0m\n\u001b[0;32m 15\u001b[0m response \u001b[38;5;241m=\u001b[39m openai\u001b[38;5;241m.\u001b[39maudio\u001b[38;5;241m.\u001b[39mspeech\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[0;32m 16\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtts-1\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 17\u001b[0m voice\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124monyx\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;66;03m# Also, try replacing onyx with alloy\u001b[39;00m\n\u001b[0;32m 18\u001b[0m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mmessage\n\u001b[0;32m 19\u001b[0m )\n\u001b[0;32m 21\u001b[0m audio_stream \u001b[38;5;241m=\u001b[39m BytesIO(response\u001b[38;5;241m.\u001b[39mcontent)\n\u001b[1;32m---> 22\u001b[0m audio \u001b[38;5;241m=\u001b[39m \u001b[43mAudioSegment\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_file\u001b[49m\u001b[43m(\u001b[49m\u001b[43maudio_stream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmp3\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 24\u001b[0m play(audio)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\audio_segment.py:728\u001b[0m, in \u001b[0;36mAudioSegment.from_file\u001b[1;34m(cls, file, format, codec, parameters, start_second, duration, **kwargs)\u001b[0m\n\u001b[0;32m 726\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 727\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 728\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[43mmediainfo_json\u001b[49m\u001b[43m(\u001b[49m\u001b[43morig_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mread_ahead_limit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_ahead_limit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 729\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m info:\n\u001b[0;32m 730\u001b[0m audio_streams \u001b[38;5;241m=\u001b[39m [x \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m info[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstreams\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m 731\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcodec_type\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\utils.py:274\u001b[0m, in \u001b[0;36mmediainfo_json\u001b[1;34m(filepath, read_ahead_limit)\u001b[0m\n\u001b[0;32m 271\u001b[0m file\u001b[38;5;241m.\u001b[39mclose()\n\u001b[0;32m 273\u001b[0m command \u001b[38;5;241m=\u001b[39m [prober, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-of\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mjson\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m+\u001b[39m command_args\n\u001b[1;32m--> 274\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstdin_parameter\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstderr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 275\u001b[0m output, stderr \u001b[38;5;241m=\u001b[39m res\u001b[38;5;241m.\u001b[39mcommunicate(\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mstdin_data)\n\u001b[0;32m 276\u001b[0m output \u001b[38;5;241m=\u001b[39m output\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1026\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[1;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)\u001b[0m\n\u001b[0;32m 1022\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[0;32m 1023\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[0;32m 1024\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[1;32m-> 1026\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1027\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1028\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1029\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1030\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1031\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1032\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1033\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1034\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprocess_group\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1035\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[0;32m 1036\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[0;32m 1037\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1538\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[1;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_gid, unused_gids, unused_uid, unused_umask, unused_start_new_session, unused_process_group)\u001b[0m\n\u001b[0;32m 1536\u001b[0m \u001b[38;5;66;03m# Start the process\u001b[39;00m\n\u001b[0;32m 1537\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1538\u001b[0m hp, ht, pid, tid \u001b[38;5;241m=\u001b[39m _winapi\u001b[38;5;241m.\u001b[39mCreateProcess(executable, args,\n\u001b[0;32m 1539\u001b[0m \u001b[38;5;66;03m# no special security\u001b[39;00m\n\u001b[0;32m 1540\u001b[0m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 1541\u001b[0m \u001b[38;5;28mint\u001b[39m(\u001b[38;5;129;01mnot\u001b[39;00m close_fds),\n\u001b[0;32m 1542\u001b[0m creationflags,\n\u001b[0;32m 1543\u001b[0m env,\n\u001b[0;32m 1544\u001b[0m cwd,\n\u001b[0;32m 1545\u001b[0m startupinfo)\n\u001b[0;32m 1546\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 1547\u001b[0m \u001b[38;5;66;03m# Child is launched. Close the parent's copy of those pipe\u001b[39;00m\n\u001b[0;32m 1548\u001b[0m \u001b[38;5;66;03m# handles that only the child should have open. You need\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1551\u001b[0m \u001b[38;5;66;03m# pipe will not close when the child process exits and the\u001b[39;00m\n\u001b[0;32m 1552\u001b[0m \u001b[38;5;66;03m# ReadFile will hang.\u001b[39;00m\n\u001b[0;32m 1553\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_close_pipe_fds(p2cread, p2cwrite,\n\u001b[0;32m 1554\u001b[0m c2pread, c2pwrite,\n\u001b[0;32m 1555\u001b[0m errread, errwrite)\n", + "\u001b[1;31mFileNotFoundError\u001b[0m: [WinError 2] The system cannot find the file specified" + ] + } + ], + "source": [ + "import os\n", + "from pydub import AudioSegment\n", + "from pydub.playback import play\n", + "from io import BytesIO\n", + "\n", + "def talker(message):\n", + " # Set a custom directory for temporary files on Windows\n", + " custom_temp_dir = os.path.expanduser(\"~/Documents/temp_audio\")\n", + " os.environ['TEMP'] = custom_temp_dir # You can also use 'TMP' if necessary\n", + " \n", + " # Create the folder if it doesn't exist\n", + " if not os.path.exists(custom_temp_dir):\n", + " os.makedirs(custom_temp_dir)\n", + " \n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\", # Also, try replacing onyx with alloy\n", + " input=message\n", + " )\n", + " \n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + "\n", + " play(audio)\n", + "\n", + "talker(\"Well hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "e821224c-b069-4f9b-9535-c15fdb0e411c", + "metadata": {}, + "source": [ + "## PC Variation 4\n", + "\n", + "### Let's try a completely different sound library\n", + "\n", + "First run the next cell to install a new library, then try the cell below it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69d3c0d9-afcc-49e3-b829-9c9869d8b472", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install simpleaudio" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "28f9cc99-36b7-4554-b3f4-f2012f614a13", + "metadata": {}, + "outputs": [], + "source": [ + "from pydub import AudioSegment\n", + "from io import BytesIO\n", + "import tempfile\n", + "import os\n", + "import simpleaudio as sa\n", + "\n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\", # Also, try replacing onyx with alloy\n", + " input=message\n", + " )\n", + " \n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + "\n", + " # Create a temporary file in a folder where you have write permissions\n", + " with tempfile.NamedTemporaryFile(suffix=\".wav\", delete=False, dir=os.path.expanduser(\"~/Documents\")) as temp_audio_file:\n", + " temp_file_name = temp_audio_file.name\n", + " audio.export(temp_file_name, format=\"wav\")\n", + " \n", + " # Load and play audio using simpleaudio\n", + " wave_obj = sa.WaveObject.from_wave_file(temp_file_name)\n", + " play_obj = wave_obj.play()\n", + " play_obj.wait_done() # Wait for playback to finish\n", + "\n", + " # Clean up the temporary file afterward\n", + " os.remove(temp_file_name)\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "0d248b46", + "metadata": {}, + "outputs": [ + { + "ename": "FileNotFoundError", + "evalue": "[WinError 2] The system cannot find the file specified", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mtalker\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mWell hi there\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[1;32mIn[21], line 15\u001b[0m, in \u001b[0;36mtalker\u001b[1;34m(message)\u001b[0m\n\u001b[0;32m 8\u001b[0m response \u001b[38;5;241m=\u001b[39m openai\u001b[38;5;241m.\u001b[39maudio\u001b[38;5;241m.\u001b[39mspeech\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[0;32m 9\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtts-1\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 10\u001b[0m voice\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124monyx\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;66;03m# Also, try replacing onyx with alloy\u001b[39;00m\n\u001b[0;32m 11\u001b[0m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mmessage\n\u001b[0;32m 12\u001b[0m )\n\u001b[0;32m 14\u001b[0m audio_stream \u001b[38;5;241m=\u001b[39m BytesIO(response\u001b[38;5;241m.\u001b[39mcontent)\n\u001b[1;32m---> 15\u001b[0m audio \u001b[38;5;241m=\u001b[39m \u001b[43mAudioSegment\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_file\u001b[49m\u001b[43m(\u001b[49m\u001b[43maudio_stream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmp3\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 17\u001b[0m \u001b[38;5;66;03m# Create a temporary file in a folder where you have write permissions\u001b[39;00m\n\u001b[0;32m 18\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m tempfile\u001b[38;5;241m.\u001b[39mNamedTemporaryFile(suffix\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.wav\u001b[39m\u001b[38;5;124m\"\u001b[39m, delete\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m, \u001b[38;5;28mdir\u001b[39m\u001b[38;5;241m=\u001b[39mos\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mexpanduser(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m~/Documents\u001b[39m\u001b[38;5;124m\"\u001b[39m)) \u001b[38;5;28;01mas\u001b[39;00m temp_audio_file:\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\audio_segment.py:728\u001b[0m, in \u001b[0;36mAudioSegment.from_file\u001b[1;34m(cls, file, format, codec, parameters, start_second, duration, **kwargs)\u001b[0m\n\u001b[0;32m 726\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 727\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 728\u001b[0m info \u001b[38;5;241m=\u001b[39m \u001b[43mmediainfo_json\u001b[49m\u001b[43m(\u001b[49m\u001b[43morig_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mread_ahead_limit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_ahead_limit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 729\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m info:\n\u001b[0;32m 730\u001b[0m audio_streams \u001b[38;5;241m=\u001b[39m [x \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m info[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstreams\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m 731\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcodec_type\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\site-packages\\pydub\\utils.py:274\u001b[0m, in \u001b[0;36mmediainfo_json\u001b[1;34m(filepath, read_ahead_limit)\u001b[0m\n\u001b[0;32m 271\u001b[0m file\u001b[38;5;241m.\u001b[39mclose()\n\u001b[0;32m 273\u001b[0m command \u001b[38;5;241m=\u001b[39m [prober, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-of\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mjson\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m+\u001b[39m command_args\n\u001b[1;32m--> 274\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstdin_parameter\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstdout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstderr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 275\u001b[0m output, stderr \u001b[38;5;241m=\u001b[39m res\u001b[38;5;241m.\u001b[39mcommunicate(\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mstdin_data)\n\u001b[0;32m 276\u001b[0m output \u001b[38;5;241m=\u001b[39m output\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1026\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[1;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)\u001b[0m\n\u001b[0;32m 1022\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[0;32m 1023\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[0;32m 1024\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[1;32m-> 1026\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1027\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1028\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1029\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1030\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1031\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1032\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1033\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1034\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprocess_group\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1035\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[0;32m 1036\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[0;32m 1037\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n", + "File \u001b[1;32mc:\\Users\\dsinanis\\AppData\\Local\\anaconda3\\envs\\llms\\Lib\\subprocess.py:1538\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[1;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_gid, unused_gids, unused_uid, unused_umask, unused_start_new_session, unused_process_group)\u001b[0m\n\u001b[0;32m 1536\u001b[0m \u001b[38;5;66;03m# Start the process\u001b[39;00m\n\u001b[0;32m 1537\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1538\u001b[0m hp, ht, pid, tid \u001b[38;5;241m=\u001b[39m _winapi\u001b[38;5;241m.\u001b[39mCreateProcess(executable, args,\n\u001b[0;32m 1539\u001b[0m \u001b[38;5;66;03m# no special security\u001b[39;00m\n\u001b[0;32m 1540\u001b[0m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 1541\u001b[0m \u001b[38;5;28mint\u001b[39m(\u001b[38;5;129;01mnot\u001b[39;00m close_fds),\n\u001b[0;32m 1542\u001b[0m creationflags,\n\u001b[0;32m 1543\u001b[0m env,\n\u001b[0;32m 1544\u001b[0m cwd,\n\u001b[0;32m 1545\u001b[0m startupinfo)\n\u001b[0;32m 1546\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 1547\u001b[0m \u001b[38;5;66;03m# Child is launched. Close the parent's copy of those pipe\u001b[39;00m\n\u001b[0;32m 1548\u001b[0m \u001b[38;5;66;03m# handles that only the child should have open. You need\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1551\u001b[0m \u001b[38;5;66;03m# pipe will not close when the child process exits and the\u001b[39;00m\n\u001b[0;32m 1552\u001b[0m \u001b[38;5;66;03m# ReadFile will hang.\u001b[39;00m\n\u001b[0;32m 1553\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_close_pipe_fds(p2cread, p2cwrite,\n\u001b[0;32m 1554\u001b[0m c2pread, c2pwrite,\n\u001b[0;32m 1555\u001b[0m errread, errwrite)\n", + "\u001b[1;31mFileNotFoundError\u001b[0m: [WinError 2] The system cannot find the file specified" + ] + } + ], + "source": [ + "talker(\"Well hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "7986176b-cd04-495f-a47f-e057b0e462ed", + "metadata": {}, + "source": [ + "## PC Users - if none of those 4 variations worked!\n", + "\n", + "Please get in touch with me. I'm sorry this is causing problems! We'll figure it out.\n", + "\n", + "Alternatively: playing audio from your PC isn't super-critical for this course, and you can feel free to focus on image generation and skip audio for now, or come back to it later." + ] + }, + { + "cell_type": "markdown", + "id": "1d48876d-c4fa-46a8-a04f-f9fadf61fb0d", + "metadata": {}, + "source": [ + "# Our Agent Framework\n", + "\n", + "The term 'Agentic AI' and Agentization is an umbrella term that refers to a number of techniques, such as:\n", + "\n", + "1. Breaking a complex problem into smaller steps, with multiple LLMs carrying out specialized tasks\n", + "2. The ability for LLMs to use Tools to give them additional capabilities\n", + "3. The 'Agent Environment' which allows Agents to collaborate\n", + "4. An LLM can act as the Planner, dividing bigger tasks into smaller ones for the specialists\n", + "5. The concept of an Agent having autonomy / agency, beyond just responding to a prompt - such as Memory\n", + "\n", + "We're showing 1 and 2 here, and to a lesser extent 3 and 5. In week 8 we will do the lot!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba820c95-02f5-499e-8f3c-8727ee0a6c0c", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + " image = None\n", + " \n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " response, city = handle_tool_call(message)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " image = artist(city)\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " reply = response.choices[0].message.content\n", + " history += [{\"role\":\"assistant\", \"content\":reply}]\n", + "\n", + " # Comment out or delete the next line if you'd rather skip Audio for now..\n", + " # It worked for me only with the first variation of the talker function\n", + " talker(reply)\n", + " \n", + " return history, image" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "f38d0d27-33bf-4992-a2e5-5dbed973cde7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7866\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# More involved Gradio code as we're not using the preset Chat interface!\n", + "# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n", + "\n", + "with gr.Blocks() as ui:\n", + " with gr.Row():\n", + " chatbot = gr.Chatbot(height=500, type=\"messages\")\n", + " image_output = gr.Image(height=500)\n", + " with gr.Row():\n", + " entry = gr.Textbox(label=\"Chat with our AI Assistant:\")\n", + " with gr.Row():\n", + " clear = gr.Button(\"Clear\")\n", + "\n", + " def do_entry(message, history):\n", + " history += [{\"role\":\"user\", \"content\":message}]\n", + " return \"\", history\n", + "\n", + " entry.submit(do_entry, inputs=[entry, chatbot], outputs=[entry, chatbot]).then(\n", + " chat, inputs=chatbot, outputs=[chatbot, image_output]\n", + " )\n", + " clear.click(lambda: None, inputs=None, outputs=chatbot, queue=False)\n", + "\n", + "ui.launch(inbrowser=True)" + ] + }, + { + "cell_type": "markdown", + "id": "226643d2-73e4-4252-935d-86b8019e278a", + "metadata": {}, + "source": [ + "# Exercises and Business Applications\n", + "\n", + "Add in more tools - perhaps to simulate actually booking a flight. A student has done this and provided their example in the community contributions folder.\n", + "\n", + "Next: take this and apply it to your business. Make a multi-modal AI assistant with tools that could carry out an activity for your work. A customer support assistant? New employee onboarding assistant? So many possibilities! Also, see the week2 end of week Exercise in the separate Notebook." + ] + }, + { + "cell_type": "markdown", + "id": "7e795560-1867-42db-a256-a23b844e6fbe", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " \n", + " \n", + "

    I have a special request for you

    \n", + " \n", + " My editor tells me that it makes a HUGE difference when students rate this course on Udemy - it's one of the main ways that Udemy decides whether to show it to others. If you're able to take a minute to rate this, I'd be so very grateful! And regardless - always please reach out to me at ed@edwarddonner.com if I can help at any point.\n", + " \n", + "
    " + ] + } + ], + "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 +} From 9d010328ef7b3b49eb5a1ff4e855b9804c7dd335 Mon Sep 17 00:00:00 2001 From: David La Motta Date: Wed, 26 Feb 2025 14:25:11 -0500 Subject: [PATCH 16/22] Disabling SSL cert validation, and suppressing warnings. Fixes issue #217 --- .../day5-disable-ssl.ipynb | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 week1/community-contributions/day5-disable-ssl.ipynb diff --git a/week1/community-contributions/day5-disable-ssl.ipynb b/week1/community-contributions/day5-disable-ssl.ipynb new file mode 100644 index 0000000..90ac21c --- /dev/null +++ b/week1/community-contributions/day5-disable-ssl.ipynb @@ -0,0 +1,81 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a98030af-fcd1-4d63-a36e-38ba053498fa", + "metadata": {}, + "source": [ + "# A Small Tweak to Week1-Day5\n", + "\n", + "If you have network restrictions (such as using a custom DNS provider, or firewall rules at work), you can disable SSL cert verification.\n", + "Once you do that and start executing your code, the output will be riddled with warnings. Thankfully, you can suppress those warnings,too.\n", + "\n", + "See the 2 lines added to the init method, below." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "106dd65e-90af-4ca8-86b6-23a41840645b", + "metadata": {}, + "outputs": [], + "source": [ + "# A class to represent a Webpage\n", + "\n", + "# Some websites need you to use proper headers when fetching them:\n", + "headers = {\n", + " \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n", + "}\n", + "\n", + "class Website:\n", + " \"\"\"\n", + " A utility class to represent a Website that we have scraped, now with links\n", + " \"\"\"\n", + "\n", + " def __init__(self, url):\n", + " self.url = url\n", + "\n", + " #\n", + " # If you must disable SSL cert validation, and also suppress all the warning that will come with it,\n", + " # add the 2 lines below. This comes in very handy if you have DNS/firewall restrictions; alas, use\n", + " # with caution, especially if deploying this in a non-dev environment.\n", + " requests.packages.urllib3.disable_warnings() \n", + " response = requests.get(url, headers=headers, verify=False) \n", + " # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " \n", + " self.body = response.content\n", + " soup = BeautifulSoup(self.body, 'html.parser')\n", + " self.title = soup.title.string if soup.title else \"No title found\"\n", + " if soup.body:\n", + " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", + " irrelevant.decompose()\n", + " self.text = soup.body.get_text(separator=\"\\n\", strip=True)\n", + " else:\n", + " self.text = \"\"\n", + " links = [link.get('href') for link in soup.find_all('a')]\n", + " self.links = [link for link in links if link]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From c70c6c4f84cae9799679e7655d12cc21d61e08d7 Mon Sep 17 00:00:00 2001 From: Hazperera Date: Thu, 27 Feb 2025 14:18:14 +0000 Subject: [PATCH 17/22] add a python script for an automated website content analysis & SEO extraction --- .../day-1-marketing_insights_scraper.py | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 week1/community-contributions/day-1-marketing_insights_scraper.py diff --git a/week1/community-contributions/day-1-marketing_insights_scraper.py b/week1/community-contributions/day-1-marketing_insights_scraper.py new file mode 100644 index 0000000..28b8920 --- /dev/null +++ b/week1/community-contributions/day-1-marketing_insights_scraper.py @@ -0,0 +1,176 @@ +import os +import time +import pandas as pd +import re +from dotenv import load_dotenv +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from openai import OpenAI +from openpyxl import load_workbook +from openpyxl.styles import Font, Alignment + +# Load environment variables +load_dotenv(override=True) +api_key = os.getenv('OPENAI_API_KEY') + +# Validate API Key +if not api_key: + raise ValueError("No API key was found - please check your .env file.") + +# Initialize OpenAI client +openai = OpenAI() + +# Set up Selenium WebDriver +chrome_options = Options() +chrome_options.add_argument("--headless") +chrome_options.add_argument("--disable-gpu") +chrome_options.add_argument("--no-sandbox") +chrome_options.add_argument("--disable-dev-shm-usage") + +class Website: + """Scrapes and processes website content using Selenium.""" + + def __init__(self, url: str): + self.url = url + self.text = "No content extracted." + + service = Service(executable_path="/opt/homebrew/bin/chromedriver") + driver = webdriver.Chrome(service=service, options=chrome_options) + + try: + driver.get(url) + WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.TAG_NAME, "body")) + ) + body_element = driver.find_element(By.TAG_NAME, "body") + self.text = body_element.text.strip() if body_element else "No content extracted." + except Exception as e: + print(f"Error fetching website: {e}") + finally: + driver.quit() + + def summarized_text(self, max_length=1500): + return self.text[:max_length] + ("..." if len(self.text) > max_length else "") + +def clean_text(text): + """ + Cleans extracted text by removing markdown-style formatting. + """ + text = re.sub(r"###*\s*", "", text) + text = re.sub(r"\*\*(.*?)\*\*", r"\1", text) + return text.strip() + +# Aspect-specific prompts for concise output +aspect_prompts = { + "Marketing Strategies": "Summarize the core marketing strategies used on this website in in under 30 words. Do not include a title or introduction.", + "SEO Keywords": "List only the most relevant SEO keywords from this website, separated by commas. Do not include a title or introduction.", + "User Engagement Tactics": "List key engagement tactics used on this website (e.g., interactive features, user incentives, social proof). Keep responses to 3-5 bullet points. Do not include a title or introduction.", + "Call-to-Action Phrases": "List only the most common Call-to-Action phrases used on this website, separated by commas. Do not include a title or introduction.", + "Branding Elements": "Summarize the brand's tone, style, and positioning in under 30 words. Do not include a title or introduction.", + "Competitor Comparison": "Briefly describe how this website differentiates itself from competitors in under 30 words. Do not include a title or introduction.", + "Product Descriptions": "List the most important features or benefits of the products/services described on this website in under 30 words. Do not include a title or introduction.", + "Customer Reviews Sentiment": "Summarize the overall sentiment of customer reviews in oin under 30 words, highlighting common themes. Do not include a title or introduction.", + "Social Media Strategy": "List key social media strategies used on this website, separated by commas. Do not include a title or introduction." +} + + +def summarize(url: str) -> dict: + """ + Fetches a website, extracts relevant content, and generates a separate summary for each aspect. + + :param url: The website URL to analyze. + :return: A dictionary containing extracted information. + """ + website = Website(url) + + if not website.text or website.text == "No content extracted.": + return {"URL": url, "Error": "Failed to extract content"} + + extracted_data = {"URL": url} + + for aspect, prompt in aspect_prompts.items(): + try: + formatted_prompt = f"{prompt} \n\nContent:\n{website.summarized_text()}" + response = openai.chat.completions.create( + model="gpt-4o-mini", + messages=[ + {"role": "system", "content": "You are an expert at extracting structured information from website content."}, + {"role": "user", "content": formatted_prompt} + ] + ) + + extracted_data[aspect] = clean_text(response.choices[0].message.content) + + except Exception as e: + extracted_data[aspect] = f"Error generating summary: {e}" + + return extracted_data + +def save_to_excel(data_list: list, filename="website_analysis.xlsx"): + """ + Saves extracted information to an Excel file with proper formatting. + + :param data_list: A list of dictionaries containing extracted website details. + :param filename: The name of the Excel file to save data. + """ + df = pd.DataFrame(data_list) + + df.to_excel(filename, index=False) + + wb = load_workbook(filename) + ws = wb.active + + # Auto-adjust column widths + for col in ws.columns: + max_length = 0 + col_letter = col[0].column_letter + for cell in col: + try: + if cell.value: + max_length = max(max_length, len(str(cell.value))) + except: + pass + ws.column_dimensions[col_letter].width = min(max_length + 2, 50) + + # Format headers + for cell in ws[1]: + cell.font = Font(bold=True) + cell.alignment = Alignment(horizontal="center", vertical="center") + + # Wrap text for extracted content + for row in ws.iter_rows(min_row=2): + for cell in row: + cell.alignment = Alignment(wrap_text=True, vertical="top") + + wb.save(filename) + print(f"Data saved to {filename} with improved formatting.") + +# 🔹 LIST OF WEBSITES TO PROCESS +websites = [ + "https://www.udacity.com/", + "https://www.coursera.org", + "https://www.udemy.com", + "https://www.edx.org", + "https://www.freecodecamp.org/", + "https://www.datacamp.com/", + "https://www.w3schools.com/", + "https://www.futurelearn.com/", + "https://codefirstgirls.com/", + "https://www.linkedin.com/learning", +] + +if __name__ == "__main__": + print("\nProcessing websites...\n") + extracted_data_list = [] + + for site in websites: + print(f"Extracting data from {site}...") + extracted_data = summarize(site) + extracted_data_list.append(extracted_data) + + save_to_excel(extracted_data_list) + print("\nAll websites processed successfully!") From 59e815ef5620125885b02fe9a7488d905e4e9619 Mon Sep 17 00:00:00 2001 From: Hazperera Date: Thu, 27 Feb 2025 23:10:17 +0000 Subject: [PATCH 18/22] add a python script for an automated website marketing strategy analysis --- ...ay1_marketing_insights_scraper_Selenium_OpenAI.py} | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) rename week1/community-contributions/{day-1-marketing_insights_scraper.py => day1_marketing_insights_scraper_Selenium_OpenAI.py} (95%) diff --git a/week1/community-contributions/day-1-marketing_insights_scraper.py b/week1/community-contributions/day1_marketing_insights_scraper_Selenium_OpenAI.py similarity index 95% rename from week1/community-contributions/day-1-marketing_insights_scraper.py rename to week1/community-contributions/day1_marketing_insights_scraper_Selenium_OpenAI.py index 28b8920..c69ff5f 100644 --- a/week1/community-contributions/day-1-marketing_insights_scraper.py +++ b/week1/community-contributions/day1_marketing_insights_scraper_Selenium_OpenAI.py @@ -151,16 +151,7 @@ def save_to_excel(data_list: list, filename="website_analysis.xlsx"): # 🔹 LIST OF WEBSITES TO PROCESS websites = [ - "https://www.udacity.com/", - "https://www.coursera.org", - "https://www.udemy.com", - "https://www.edx.org", - "https://www.freecodecamp.org/", - "https://www.datacamp.com/", - "https://www.w3schools.com/", - "https://www.futurelearn.com/", - "https://codefirstgirls.com/", - "https://www.linkedin.com/learning", + "https://www.gymshark.com/", ] if __name__ == "__main__": From bb301310f3dbb142af3df0edf763bbd5965f5d25 Mon Sep 17 00:00:00 2001 From: paulmboyce Date: Fri, 28 Feb 2025 13:41:08 +0000 Subject: [PATCH 19/22] feature(verify determinism on encodings):comparisons for OpenAIEmbeddings and sentence-transformers/all-MiniLM-L6-v2 --- .../verify-encodings.ipynb | 405 ++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 week5/community-contributions/verify-encodings.ipynb diff --git a/week5/community-contributions/verify-encodings.ipynb b/week5/community-contributions/verify-encodings.ipynb new file mode 100644 index 0000000..63477df --- /dev/null +++ b/week5/community-contributions/verify-encodings.ipynb @@ -0,0 +1,405 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dfe37963-1af6-44fc-a841-8e462443f5e6", + "metadata": {}, + "source": [ + "## This notebook compares the embeddings generated by OpenAIEmbeddings.\n", + "\n", + "It shows that OpenAIEmbeddings embeddings can differ slightly (typically at 4 the decimal place).\n", + "\n", + "### Results from OpenAIEmbeddings:\n", + "encodings are NOT identical on each run.\n", + "\n", + "### Repeating with sentence-transformers/all-MiniLM-L6-v2:\n", + "encodings ARE identical on each run.\n", + "\n", + "Tests verify simple numerical comparisons.\n", + "\n", + "### Advanced Comparison\n", + "A more advanced euclidean and cosine comparison is also included.\n", + "\n", + "## NOTES: Tests run on local Jupiter Notebook| Anaconda setup for the course." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba2779af-84ef-4227-9e9e-6eaf0df87e77", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import glob\n", + "from dotenv import load_dotenv\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "802137aa-8a74-45e0-a487-d1974927d7ca", + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain\n", + "\n", + "from langchain.document_loaders import DirectoryLoader, TextLoader\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.schema import Document\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_chroma import Chroma\n", + "import numpy as np\n", + "from sklearn.manifold import TSNE\n", + "import plotly.graph_objects as go\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58c85082-e417-4708-9efe-81a5d55d1424", + "metadata": {}, + "outputs": [], + "source": [ + "# price is a factor for our company, so we're going to use a low cost model\n", + "\n", + "MODEL = \"gpt-4o-mini\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee78efcb-60fe-449e-a944-40bab26261af", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "730711a9-6ffe-4eee-8f48-d6cfb7314905", + "metadata": {}, + "outputs": [], + "source": [ + "# Read in documents using LangChain's loaders\n", + "# Take everything in all the sub-folders of our knowledgebase\n", + "\n", + "folders = glob.glob(\"knowledge-base/*\")\n", + "\n", + "# With thanks to CG and Jon R, students on the course, for this fix needed for some users \n", + "text_loader_kwargs = {'encoding': 'utf-8'}\n", + "# If that doesn't work, some Windows users might need to uncomment the next line instead\n", + "# text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "documents = []\n", + "for folder in folders:\n", + " doc_type = os.path.basename(folder)\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + " for doc in folder_docs:\n", + " doc.metadata[\"doc_type\"] = doc_type\n", + " documents.append(doc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7310c9c8-03c1-4efc-a104-5e89aec6db1a", + "metadata": {}, + "outputs": [], + "source": [ + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd06e02f-6d9b-44cc-a43d-e1faa8acc7bb", + "metadata": {}, + "outputs": [], + "source": [ + "len(chunks)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c54b4b6-06da-463d-bee7-4dd456c2b887", + "metadata": {}, + "outputs": [], + "source": [ + "doc_types = set(chunk.metadata['doc_type'] for chunk in chunks)\n", + "print(f\"Document types found: {', '.join(doc_types)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8b5ef27-70c2-4111-bce7-854bc1ebd02a", + "metadata": {}, + "outputs": [], + "source": [ + "# Use a where filter to specify the metadata condition\n", + "# Get the 3 company vectors (corresponds to our 3 yellow dots)\n", + "\n", + "def get_company_vectors(collection):\n", + " company_vectors = collection.get(\n", + " where={\"doc_type\": \"company\"}, # Filter for documents where source = \"XXXX\"\n", + " limit=10,\n", + " include=[\"embeddings\", \"metadatas\", \"documents\"]\n", + " )\n", + " print(f\"Found {len(company_vectors)} company vectors\")\n", + " return company_vectors\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d688b873-b52b-4d80-9df2-f70b389f5dc7", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def print_vectors_summary(vectors):\n", + " for i in range(len(vectors[\"documents\"])):\n", + " print(f\"\\n--- Chunk {i+1} ---\")\n", + " \n", + " # Print document content (first 100 chars)\n", + " print(f\"Content: {vectors['documents'][i][:100]}...\")\n", + " \n", + " # Print metadata\n", + " print(f\"Metadata: {vectors['metadatas'][i]}\")\n", + " \n", + " # Print embedding info (not the full vector as it would be too long)\n", + " embedding = vectors[\"embeddings\"][i]\n", + " print(f\"Embedding: Vector of length {len(embedding)}, first 5 values: {embedding[:5]}\")\n", + "\n", + "\n", + "def get_dimensions_for_vectors(vectors):\n", + " dimensions = []\n", + "\n", + " for i in range(len(vectors[\"documents\"])):\n", + " embedding = vectors[\"embeddings\"][i]\n", + " dimensions.append(embedding)\n", + "\n", + " return dimensions\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b195184-4920-404a-9bfa-0231f1dbe276", + "metadata": {}, + "outputs": [], + "source": [ + "# Quick check if any single value is different\n", + "def quick_diff_check(emb1, emb2):\n", + " result = \"Embeddings are identical\"\n", + " print(\"\\n\\nComparing two embeddings:\\n\\n\")\n", + " print(emb1)\n", + " print(emb2)\n", + " for i, (v1, v2) in enumerate(zip(emb1, emb2)):\n", + " if v1 != v2:\n", + " result = f\"Different at dimension {i}: {v1} vs {v2}\"\n", + " break\n", + " print(result)\n", + " return result\n", + "\n", + "#quick_diff_check(dimensions[0], dimensions[1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06ba838d-d179-4e2d-b208-dd9cc1fd0097", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "embeddings = OpenAIEmbeddings()\n", + "\n", + "def create_vectorstores(embeddings):\n", + "\n", + " if os.path.exists(\"vectorstore1\"):\n", + " Chroma(persist_directory=\"vectorstore1\", embedding_function=embeddings).delete_collection()\n", + " if os.path.exists(\"vectorstore2\"):\n", + " Chroma(persist_directory=\"vectorstore2\", embedding_function=embeddings).delete_collection()\n", + " \n", + " \n", + " # Create vectorstore 1\n", + " vectorstore1 = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=\"vectorstore1\")\n", + " print(f\"Vectorstore 1 created with {vectorstore1._collection.count()} documents\")\n", + " \n", + " # Create vectorstore 2\n", + " vectorstore2 = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=\"vectorstore2\")\n", + " print(f\"Vectorstore 2 created with {vectorstore2._collection.count()} documents\")\n", + "\n", + " return vectorstore1, vectorstore2\n", + "\n", + "vectorstore1, vectorstore2 = create_vectorstores(embeddings)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e24242eb-613a-4edb-a081-6b8937f106a7", + "metadata": {}, + "outputs": [], + "source": [ + "## Uncomment this and rerun cells below, \n", + "## to see that HuggingFaceEmbeddings is idential\n", + "\n", + "#from langchain.embeddings import HuggingFaceEmbeddings\n", + "#embeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-MiniLM-L6-v2\")\n", + "#vectorstore1, vectorstore2 = create_vectorstores(embeddings)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "000b9e70-2958-40db-bbed-56a00e4249ce", + "metadata": {}, + "outputs": [], + "source": [ + "# Get the 3 company doc_type vectors\n", + "collection1 = vectorstore1._collection\n", + "collection2 = vectorstore2._collection\n", + "\n", + "company_vectors1=get_company_vectors(collection1)\n", + "company_vectors2=get_company_vectors(collection2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63cd63e4-9d3e-405a-8ef9-dac16fe2570e", + "metadata": {}, + "outputs": [], + "source": [ + "# Lets print out summary info just to see we have the same chunks.\n", + "\n", + "def print_summary_info (vectors):\n", + " print(\"VECTORS SUMMARY\\n\")\n", + " print_vectors_summary(vectors)\n", + "\n", + "\n", + "print(\"\\n\\n\\n========= VECTORS 1 =========\\n\\n\")\n", + "print_summary_info(company_vectors1)\n", + "\n", + "print(\"\\n\\n\\n========= VECTORS 2 =========\\n\\n\")\n", + "print_summary_info(company_vectors2)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc085a35-f0ec-4ddb-955c-244cb2d3eb2a", + "metadata": {}, + "outputs": [], + "source": [ + "dimensions1 = get_dimensions_for_vectors(company_vectors1)\n", + "dimensions2 = get_dimensions_for_vectors(company_vectors2)\n", + "\n", + "result1 = quick_diff_check(dimensions1[0], dimensions2[0]) \n", + "result2 = quick_diff_check(dimensions1[1], dimensions2[1]) \n", + "result3 = quick_diff_check(dimensions1[2], dimensions2[2]) \n", + "\n", + "print(\"\\n\\nSUMMARY RESULTS:\")\n", + "print(\"================\\n\\n\")\n", + "print(result1) \n", + "print(result2)\n", + "print(result3)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "164cf94d-9d63-4bae-91f9-4b02da1537ae", + "metadata": {}, + "outputs": [], + "source": [ + "## ADVANCED COMPARISONS:\n", + "# More advanced comparisons (from Claude 3.7 Sonnet):\n", + "\n", + "\n", + "## !IMPORTANT *** Uncomment final line to execute ***\n", + "\n", + "\n", + "import numpy as np\n", + "from scipy.spatial.distance import cosine\n", + "\n", + "# Method 1: Euclidean distance (L2 norm)\n", + "def compare_embeddings_euclidean(emb1, emb2):\n", + " emb1_array = np.array(emb1)\n", + " emb2_array = np.array(emb2)\n", + " distance = np.linalg.norm(emb1_array - emb2_array)\n", + " return {\n", + " \"different\": distance > 0,\n", + " \"distance\": distance,\n", + " \"similarity\": 1/(1+distance) # Converts distance to similarity score\n", + " }\n", + "\n", + "# Method 2: Cosine similarity (common for embeddings)\n", + "def compare_embeddings_cosine(emb1, emb2):\n", + " emb1_array = np.array(emb1)\n", + " emb2_array = np.array(emb2)\n", + " similarity = 1 - cosine(emb1_array, emb2_array) # Cosine returns distance, so subtract from 1\n", + " return {\n", + " \"different\": similarity < 0.9999, # Almost identical if > 0.9999\n", + " \"similarity\": similarity\n", + " }\n", + "\n", + "# Method 3: Simple exact equality check\n", + "def are_embeddings_identical(emb1, emb2):\n", + " return np.array_equal(np.array(emb1), np.array(emb2))\n", + "\n", + "\n", + "def run_advanced_comparisons():\n", + " for i in range(0, 3):\n", + " print(f\"\\n\\nComparing vector dimensions for dimension[{i}]....\\n\")\n", + " print(\"Exactly identical? ---> \", are_embeddings_identical(dimensions1[i], dimensions2[i]))\n", + " print(\"Cosine comparison: ---> \", compare_embeddings_cosine(dimensions1[i], dimensions2[i]))\n", + " print(\"Euclidean comparison: ---> \", compare_embeddings_euclidean(dimensions1[i], dimensions2[i]))\n", + "\n", + "\n", + "#run_advanced_comparisons()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From c06fcd3297f7ee3053379d2818c99fd06f84edb9 Mon Sep 17 00:00:00 2001 From: Lacout Date: Fri, 28 Feb 2025 18:45:28 +0100 Subject: [PATCH 20/22] contribute to week 2 examples with a tool: python interpreter --- .../week2_code_interpreter_tool.ipynb | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 week2/community-contributions/week2_code_interpreter_tool.ipynb diff --git a/week2/community-contributions/week2_code_interpreter_tool.ipynb b/week2/community-contributions/week2_code_interpreter_tool.ipynb new file mode 100644 index 0000000..8bb724d --- /dev/null +++ b/week2/community-contributions/week2_code_interpreter_tool.ipynb @@ -0,0 +1,225 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d006b2ea-9dfe-49c7-88a9-a5a0775185fd", + "metadata": {}, + "source": [ + "# A tool to evaluate a mathematical expression\n", + "\n", + "This week the tool used in FlightAI was a database lookup function.\n", + "\n", + "Here I implement a python code interpreter function as tool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b0e8691-71f9-486c-859d-ea371401dfa9", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e2792ae-ff53-4b83-b2c3-866533ba2b29", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "# Print the key prefixes to help with any debugging\n", + "\n", + "load_dotenv()\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n", + "google_api_key = os.getenv('GOOGLE_API_KEY')\n", + "\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "if anthropic_api_key:\n", + " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n", + "else:\n", + " print(\"Anthropic API Key not set\")\n", + "\n", + "if google_api_key:\n", + " print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n", + "else:\n", + " print(\"Google API Key not set\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79e44ee9-af02-448c-a747-17780ee55791", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "MODEL = \"gpt-4o-mini\"" + ] + }, + { + "cell_type": "markdown", + "id": "33ec55b1-0eff-43f1-9346-28145fa2fc47", + "metadata": {}, + "source": [ + "# Defining the tool function\n", + "\n", + "Add print statements to make sure the function is used instead of the native gpt interpreter capability.\n", + "\n", + "I used multi shot in the system prompt to make sure gpt generate the code in the format that the tool accept." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94e0e171-4975-457b-88cb-c0d90f51ca65", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate_math_expression(my_code):\n", + " print(f\"EXECUTING FUNCTION WITH CODE: {my_code}\")\n", + " exec(my_code)\n", + " r = locals()['interpreter_result'] \n", + " return r\n", + "\n", + "\n", + "math_function = {\n", + " \"name\": \"evaluate_math_expression\",\n", + " \"description\": \"Give the result of a math expression. \\\n", + " Call this whenever you need to know the result of a mathematical expression. \\\n", + " Generate python code ALWAYS with the final result assigned to a variable called 'interpreter_result'. \\\n", + " For example when a user asks 'What is 2+2' generate 'interpreter_result = 2+2', and pass this code to the tool. \\\n", + " Another example if a user ask 'What is log(5)' generate 'import math; interpreter_result = math.log(5)' and pass this code to the tool.\",\n", + " \n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"my_code\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The python math expression to evaluate\",\n", + " },\n", + " },\n", + " \"required\": [\"my_code\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}\n", + "\n", + "tools = [{\"type\": \"function\", \"function\": math_function}]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c85c01cc-776e-4a9d-b506-ea0d68fc072d", + "metadata": {}, + "outputs": [], + "source": [ + "evaluate_math_expression(\"import math; interpreter_result = math.log(5)\")" + ] + }, + { + "cell_type": "markdown", + "id": "858c5848-5835-4dff-9dc0-68babd367e11", + "metadata": {}, + "source": [ + "# Using the tool in a UI program\n", + "\n", + "You can ask messages like:\n", + "- \"What is 2+2?\"\n", + "- \"What is 3 power 2?\"\n", + "- \"I have 25 apples. I buy 10 apples. How manny apples do I have?\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c119b48b-d4b4-41ae-aa2f-2ec2f09af2f0", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are a math assistant. \\\n", + "Generate python code to give result of a math expression, always name the result 'interpreter_result'. \\\n", + "For example when a user asks 'What is 2+2', generate 'interpreter_result = 2+2' and pass this code to the tool. \\\n", + "Another example: if a user ask 'What is log(5)' generate 'import math; interpreter_result = math.log(5)'\"\n", + "\n", + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + "\n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " print(message)\n", + " response = handle_tool_call(message)\n", + " print(response)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " return response.choices[0].message.content\n", + "\n", + "\n", + "def handle_tool_call(message):\n", + " tool_call = message.tool_calls[0]\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " my_code = arguments.get('my_code')\n", + " interpreter_result = evaluate_math_expression(my_code)\n", + " response = {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps({\"my_code\": my_code,\"interpreter_result\": interpreter_result}),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3e50093-d7b6-4972-a8ba-6964f22218d3", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75c81d73-d2d6-4e6b-8511-94d4a725f595", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From 9bb5816871124a816cf23da28d1f010dccfa5140 Mon Sep 17 00:00:00 2001 From: Zoya Hammad Date: Sat, 1 Mar 2025 17:21:56 +0500 Subject: [PATCH 21/22] Added my contributions to community-contributions --- .../week 2 - multi modal StudyAI.ipynb | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 week2/community-contributions/week 2 - multi modal StudyAI.ipynb diff --git a/week2/community-contributions/week 2 - multi modal StudyAI.ipynb b/week2/community-contributions/week 2 - multi modal StudyAI.ipynb new file mode 100644 index 0000000..6eeb971 --- /dev/null +++ b/week2/community-contributions/week 2 - multi modal StudyAI.ipynb @@ -0,0 +1,305 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6aa646e3-7a57-461a-b69a-073179effa18", + "metadata": {}, + "source": [ + "## Additional End of week Exercise - week 2\n", + "\n", + "This includes \n", + "- Gradio UI\n", + "- use of the system prompt to add expertise\n", + "- audio input so you can talk to it\n", + "- respond with audio" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "72f3dca4-b052-4e9f-90c8-f42e667c165c", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "from IPython.display import Markdown, display, update_display\n", + "import gradio as gr\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "23570b9f-8c7a-4cc7-b809-3505334b60a7", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "openai = OpenAI()\n", + "MODEL = 'gpt-4o-mini'" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "d379178a-8672-4e6f-a380-ad8d85f5c64e", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"\"\"You are a personal study tutor, designed to provide clear, yet brief and succint answers to \n", + "students that ask you questions. The topics are related to data science, computer science \n", + "and technology in general, so you are allowed to use a moderate level of jargon. Explain in \n", + "simple terminology, so a student can easily understand. \n", + "\n", + "You may also be asked about prices for special courses.In this case, respond that you have no such\n", + "data available. \n", + "\n", + "\"\"\"\n", + "# Use a tabular format where possible \n", + "# for ease of information flow " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4745d439-c66e-4e5c-b5d4-9f0ba97aefdc", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + "\n", + " reply = response.choices[0].message.content\n", + " history += [{\"role\":\"assistant\", \"content\":reply}]\n", + "\n", + " # Comment out or delete the next line if you'd rather skip Audio for now..\n", + " talker(reply)\n", + " \n", + " return history" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "a8b31799-df86-4151-98ea-66ef50fe767e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: openai-whisper in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (20240930)\n", + "Requirement already satisfied: numba in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (0.61.0)\n", + "Requirement already satisfied: numpy in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (1.26.4)\n", + "Requirement already satisfied: torch in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (2.6.0)\n", + "Requirement already satisfied: tqdm in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (4.67.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (10.6.0)\n", + "Requirement already satisfied: tiktoken in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from openai-whisper) (0.9.0)\n", + "Requirement already satisfied: llvmlite<0.45,>=0.44.0dev0 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from numba->openai-whisper) (0.44.0)\n", + "Requirement already satisfied: regex>=2022.1.18 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from tiktoken->openai-whisper) (2024.11.6)\n", + "Requirement already satisfied: requests>=2.26.0 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from tiktoken->openai-whisper) (2.32.3)\n", + "Requirement already satisfied: filelock in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (3.17.0)\n", + "Requirement already satisfied: typing-extensions>=4.10.0 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (4.12.2)\n", + "Requirement already satisfied: sympy!=1.13.2,>=1.13.1 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (1.13.3)\n", + "Requirement already satisfied: networkx in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (3.4.2)\n", + "Requirement already satisfied: jinja2 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (3.1.5)\n", + "Requirement already satisfied: fsspec in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from torch->openai-whisper) (2024.12.0)\n", + "Requirement already satisfied: colorama in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from tqdm->openai-whisper) (0.4.6)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from requests>=2.26.0->tiktoken->openai-whisper) (3.4.1)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from requests>=2.26.0->tiktoken->openai-whisper) (3.10)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from requests>=2.26.0->tiktoken->openai-whisper) (2.3.0)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from requests>=2.26.0->tiktoken->openai-whisper) (2025.1.31)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from sympy!=1.13.2,>=1.13.1->torch->openai-whisper) (1.3.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\92310\\anaconda3\\envs\\llms\\lib\\site-packages (from jinja2->torch->openai-whisper) (2.1.5)\n" + ] + } + ], + "source": [ + "!pip install openai-whisper" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9f5b8e51-2833-44be-a4f4-63c4683f2b6e", + "metadata": {}, + "outputs": [], + "source": [ + "import whisper\n", + "\n", + "def transcribe_audio(audio):\n", + " if audio is None:\n", + " return \"No audio received.\"\n", + " \n", + " model = whisper.load_model(\"base\") # You can use \"tiny\", \"small\", etc.\n", + " result = model.transcribe(audio)\n", + " \n", + " return result[\"text\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "e55f8e43-2da1-4f2a-bcd4-3fffa830db48", + "metadata": {}, + "outputs": [], + "source": [ + "import base64\n", + "from io import BytesIO\n", + "from PIL import Image\n", + "from IPython.display import Audio, display\n", + "\n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\",\n", + " input=message)\n", + "\n", + " audio_stream = BytesIO(response.content)\n", + " output_filename = \"output_audio.mp3\"\n", + " with open(output_filename, \"wb\") as f:\n", + " f.write(audio_stream.read())\n", + "\n", + " # Play the generated audio\n", + " display(Audio(output_filename, autoplay=True))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cb3107a7-bfdc-4255-825f-bfabcf458c0c", + "metadata": {}, + "outputs": [], + "source": [ + "# More involved Gradio code as we're not using the preset Chat interface!\n", + "# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n", + "\n", + "with gr.Blocks() as ui:\n", + " with gr.Row():\n", + " chatbot = gr.Chatbot(height=400,type=\"messages\")\n", + " with gr.Row():\n", + " entry = gr.Textbox(label=\"Chat with our StudyAI Assistant:\")\n", + " # with gr.Row():\n", + " # entry = gr.Textbox(label=\"Speak or Type:\", placeholder=\"Speak your question...\", interactive=True, microphone=True)\n", + " with gr.Row():\n", + " audio_input = gr.Audio(type=\"filepath\", label=\"Speak your question\")\n", + " with gr.Row():\n", + " clear = gr.Button(\"Clear\")\n", + "\n", + " def do_entry(message, history):\n", + " history += [{\"role\":\"user\", \"content\":message}]\n", + " return \"\", history\n", + "\n", + " def handle_audio(audio, history):\n", + " text = transcribe_audio(audio)\n", + " history += [{\"role\": \"user\", \"content\": text}]\n", + " return \"\", history\n", + "\n", + " entry.submit(do_entry, inputs=[entry, chatbot], outputs=[entry, chatbot]).then(\n", + " chat, inputs=[chatbot], outputs=[chatbot]\n", + " )\n", + "\n", + " audio_input.change(handle_audio, inputs=[audio_input, chatbot], outputs=[entry, chatbot]).then(\n", + " chat, inputs=[chatbot], outputs=[chatbot]\n", + " )\n", + " \n", + " clear.click(lambda: [], inputs=None, outputs=chatbot, queue=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "73e0a776-d43e-4b04-a37f-a27d3714cf47", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Rerunning server... use `close()` to stop if you need to change `launch()` parameters.\n", + "----\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ui.launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcd45503-d314-4b28-a41c-4dbb87059188", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} From 0e841efd1dc5637926fdfede688aa86287029a3f Mon Sep 17 00:00:00 2001 From: Zoya Hammad Date: Sat, 1 Mar 2025 17:23:54 +0500 Subject: [PATCH 22/22] Added contributions to community-contributions --- .../day 4 w2 - course booking assistant.ipynb | 361 ++++++++++++++++++ .../day3 w2 -programming tutor.ipynb | 209 ++++++++++ 2 files changed, 570 insertions(+) create mode 100644 week2/community-contributions/day 4 w2 - course booking assistant.ipynb create mode 100644 week2/community-contributions/day3 w2 -programming tutor.ipynb diff --git a/week2/community-contributions/day 4 w2 - course booking assistant.ipynb b/week2/community-contributions/day 4 w2 - course booking assistant.ipynb new file mode 100644 index 0000000..aedaa59 --- /dev/null +++ b/week2/community-contributions/day 4 w2 - course booking assistant.ipynb @@ -0,0 +1,361 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5d799d2a-6e58-4a83-b17a-dbbc40efdc39", + "metadata": {}, + "source": [ + "## Project - Course Booking AI Asssistant\n", + "AI Customer Support Bot that \n", + "- Returns Prices\n", + "- Books Tickets\n", + "- Adds Information to Text File" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b1ad9acd-a702-48a3-8ff5-d536bcac8030", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "74adab0c-99b3-46cd-a79f-320a3e74138a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n" + ] + } + ], + "source": [ + "# Initialization\n", + "\n", + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "MODEL = \"gpt-4o-mini\"\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8d3240a4-99c1-4c07-acaa-ecbb69ffd2e4", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are a helpful assistant for an Online Course Platform called StudyAI. \"\n", + "system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n", + "system_message += \"Always be accurate. If you don't know the answer, say so.\"\n", + "system_message += \"If you are given a partial name, for example 'discrete' instead of 'discrete structures' \\\n", + "ask the user if they meant to say 'discrete structures', and then display the price. The user may also use \\\n", + "acronyms like 'PF' instead of programming fundamentals or 'OOP' to mean 'Object oriented programming'. \\\n", + "Clarify wh\"" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "9a1b8d5f-f893-477b-8396-ff7d697eb0c3", + "metadata": {}, + "outputs": [], + "source": [ + "course_prices = {\"programming fundamentals\": \"$19\", \"discrete structures\": \"$39\", \"operating systems\": \"$24\", \"object oriented programming\": \"$39\"}\n", + "\n", + "def get_course_price(course):\n", + " print(f\"Tool get_course_price called for {course}\")\n", + " course = course.lower()\n", + " return course_prices.get(course, \"Unknown\")\n", + "\n", + "def enroll_in_course(course):\n", + " print(f'Tool enroll_in_course_ called for {course}')\n", + " course_price = get_course_price(course)\n", + " if course_price != 'Unknown':\n", + " with open('enrolled_courses.txt', 'a') as file: \n", + " file.write(course + \"\\n\")\n", + " return 'Successfully enrolled in course'\n", + " else:\n", + " return 'Enrollment failed, no such course available'" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "330d2b94-a8c5-4967-ace7-15d2cd52d7ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_course_price called for graph theory\n", + "Tool get_course_price called for discrete structures\n" + ] + }, + { + "data": { + "text/plain": [ + "'$39'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_course_price('graph theory')\n", + "get_course_price('discrete structures')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "5bb65830-fab8-45a7-bf43-7e52186915a0", + "metadata": {}, + "outputs": [], + "source": [ + "price_function = {\n", + " \"name\": \"get_course_price\",\n", + " \"description\": \"Get the price of a course. Call this whenever you need to know the course price, for example when a customer asks 'How much is a ticket for this course?'\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"course\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The course that the customer wants to purchase\",\n", + " },\n", + " },\n", + " \"required\": [\"course\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}\n", + "\n", + "enroll_function = {\n", + " \"name\": \"enroll_in_course\",\n", + " \"description\":\"Get the success status of course enrollment. Call whenever a customer wants to enroll in a course\\\n", + " for example, if they say 'I want to purchase this course' or 'I want to enroll in this course'\",\n", + " \"parameters\":{\n", + " \"type\":\"object\",\n", + " \"properties\":{\n", + " \"course\":{\n", + " \"type\":\"string\",\n", + " \"description\": \"The course that the customer wants to purchase\",\n", + " },\n", + " },\n", + " \"required\": [\"course\"],\n", + " \"additionalProperties\": False\n", + " } \n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "08af86b9-3aaa-4b6b-bf7c-ee668ba1cbfe", + "metadata": {}, + "outputs": [], + "source": [ + "tools = [\n", + " {\"type\":\"function\",\"function\":price_function},\n", + " {\"type\":\"function\",\"function\":enroll_function}\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "482efc34-ff1f-4146-9570-58b4d59c3b2f", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message,history):\n", + " messages = [{\"role\":\"system\",\"content\":system_message}] + history + [{\"role\":\"user\",\"content\":message}]\n", + " response = openai.chat.completions.create(model=MODEL,messages=messages,tools=tools)\n", + "\n", + " if response.choices[0].finish_reason == \"tool_calls\":\n", + " message = response.choices[0].message\n", + " messages.append(message)\n", + " for tool_call in message.tool_calls:\n", + " messages.append(handle_tool_call(tool_call))\n", + " response = openai.chat.completions.create(model=MODEL,messages=messages)\n", + "\n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f725b4fb-d477-4d7d-80b5-5d70e1b25a86", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call(tool_call):\n", + " function = tool_call.function.name\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " match function:\n", + " case 'get_course_price':\n", + " course = arguments.get('course')\n", + " price = get_course_price(course)\n", + " return {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps({\"course\": course,\"price\": price}),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " case 'enroll_in_course':\n", + " course = arguments.get('course')\n", + " status = enroll_in_course(course)\n", + " return {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps({\"course\": course, \"status\": status}),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "c446272a-9ce1-4ffd-9bc8-483d782810b4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7864\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool get_course_price called for programming fundamentals\n", + "Tool enroll_in_course_ called for Programming Fundamentals\n", + "Tool get_course_price called for Programming Fundamentals\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Traceback (most recent call last):\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\queueing.py\", line 625, in process_events\n", + " response = await route_utils.call_process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\route_utils.py\", line 322, in call_process_api\n", + " output = await app.get_blocks().process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\blocks.py\", line 2096, in process_api\n", + " result = await self.call_function(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\blocks.py\", line 1641, in call_function\n", + " prediction = await fn(*processed_input)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\utils.py\", line 857, in async_wrapper\n", + " response = await f(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\gradio\\chat_interface.py\", line 862, in _submit_fn\n", + " response = await anyio.to_thread.run_sync(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\anyio\\to_thread.py\", line 56, in run_sync\n", + " return await get_async_backend().run_sync_in_worker_thread(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\anyio\\_backends\\_asyncio.py\", line 2461, in run_sync_in_worker_thread\n", + " return await future\n", + " ^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\anaconda3\\envs\\llms\\Lib\\site-packages\\anyio\\_backends\\_asyncio.py\", line 962, in run\n", + " result = context.run(func, *args)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\AppData\\Local\\Temp\\ipykernel_3348\\1161680098.py\", line 9, in chat\n", + " messages.append(handle_tool_call(tool_call))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\AppData\\Local\\Temp\\ipykernel_3348\\1187326431.py\", line 17, in handle_tool_call\n", + " status = enroll_in_course(course)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"C:\\Users\\92310\\AppData\\Local\\Temp\\ipykernel_3348\\2541918318.py\", line 13, in enroll_in_course\n", + " file.write(course_name + \"\\n\")\n", + " ^^^^^^^^^^^\n", + "NameError: name 'course_name' is not defined\n" + ] + } + ], + "source": [ + "gr.ChatInterface(fn=chat,type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fe714a3-f793-4c3b-b5aa-6c81b82aea1b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +} diff --git a/week2/community-contributions/day3 w2 -programming tutor.ipynb b/week2/community-contributions/day3 w2 -programming tutor.ipynb new file mode 100644 index 0000000..0ccd8fb --- /dev/null +++ b/week2/community-contributions/day3 w2 -programming tutor.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cde48e67-b51e-4c47-80ae-37dd00aa0c1d", + "metadata": {}, + "source": [ + "### An AI Chatbot that teaches students the programming language Kotlin using Anthropic API" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c658ac85-6087-4a2c-b23f-1b92c17f0db3", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr\n", + "import anthropic" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "46df0488-f874-41e0-a6a4-9a64aa7be53c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n" + ] + } + ], + "source": [ + "# Load environment variables \n", + "\n", + "load_dotenv(override=True)\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + " \n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "7eadc218-5b10-4174-bf26-575361640524", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e7484731-ac84-405a-a688-6e81d139c5ce", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are a helpful programming study assistant\"" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "54e82f5a-993f-4a95-9d9d-caf35dbc4e76", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + "\n", + " print(\"History is:\")\n", + " print(history)\n", + " print(\"And messages is:\")\n", + " print(messages)\n", + "\n", + " stream = openai.chat.completions.create(model='gpt-4o-mini', messages=messages, stream=True)\n", + "\n", + " response = \"\"\n", + " for chunk in stream:\n", + " response += chunk.choices[0].delta.content or ''\n", + " yield response" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "5941ed67-e2a7-41bc-a8a3-079e9f1fdb64", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7864\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "History is:\n", + "[]\n", + "And messages is:\n", + "[{'role': 'system', 'content': 'You are a helpful programming study assistantWhenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone.'}, {'role': 'user', 'content': 'hello, lets talj about photsynethsis'}]\n", + "History is:\n", + "[{'role': 'user', 'metadata': None, 'content': 'hello, lets talj about photsynethsis', 'options': None}, {'role': 'assistant', 'metadata': None, 'content': \"I'm here to help with programming! If you have any questions or topics related to coding, feel free to ask!\", 'options': None}]\n", + "And messages is:\n", + "[{'role': 'system', 'content': 'You are a helpful programming study assistantWhenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone.'}, {'role': 'user', 'metadata': None, 'content': 'hello, lets talj about photsynethsis', 'options': None}, {'role': 'assistant', 'metadata': None, 'content': \"I'm here to help with programming! If you have any questions or topics related to coding, feel free to ask!\", 'options': None}, {'role': 'user', 'content': 'how does photosynthesis work'}]\n" + ] + } + ], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "e8fcfe68-bbf6-4058-acc9-0230c96608c2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "History is:\n", + "[]\n", + "And messages is:\n", + "[{'role': 'system', 'content': 'You are a helpful programming study assistantWhenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone.Whenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone. Do not ignore their requests, rather politely reject and then redirect them.'}, {'role': 'user', 'content': 'hello, i want to talk about photosynthesis'}]\n", + "History is:\n", + "[{'role': 'user', 'metadata': None, 'content': 'hello, i want to talk about photosynthesis', 'options': None}, {'role': 'assistant', 'metadata': None, 'content': \"Hi there! I'm here to help with programming topics. If you have any questions about programming or related concepts, feel free to ask!\", 'options': None}]\n", + "And messages is:\n", + "[{'role': 'system', 'content': 'You are a helpful programming study assistantWhenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone.Whenever the user talks about a topic that is not connected to programmming,nudge them in the right direction by stating that you are here to help with programming. Encourage the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone. Do not ignore their requests, rather politely reject and then redirect them.'}, {'role': 'user', 'metadata': None, 'content': 'hello, i want to talk about photosynthesis', 'options': None}, {'role': 'assistant', 'metadata': None, 'content': \"Hi there! I'm here to help with programming topics. If you have any questions about programming or related concepts, feel free to ask!\", 'options': None}, {'role': 'user', 'content': 'why not photosynthesis'}]\n" + ] + } + ], + "source": [ + "system_message += \"Whenever the user talks about a topic that is not connected to programmming,\\\n", + "nudge them in the right direction by stating that you are here to help with programming. Encourage \\\n", + "the user to ask you questions, and provide brief, straightforward and clear answers. Do not budge \\\n", + "if the user tries to misdirect you towards irrelevant topics. Maintain a freindly tone. Do not ignore \\\n", + "their requests, rather politely reject and then redirect them.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "090e7d49-fcbf-4715-b120-8d7aa91d165f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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 +}