diff --git a/week1/community-contributions/day1_michelin_start_cook.ipynb b/week1/community-contributions/day1_michelin_start_cook.ipynb new file mode 100644 index 0000000..3cee7ed --- /dev/null +++ b/week1/community-contributions/day1_michelin_start_cook.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "44aba2a0-c6eb-4fc1-a5cc-0a8f8679dbb8", + "metadata": {}, + "source": [ + "## Michelin-star cook..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4d58124-5e9a-4f5a-9e0a-ff74f43896a8", + "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", + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "api_key = os.getenv('OPENAI_API_KEY')\n", + "\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67dc3099-2ccc-4ee8-8ff2-0dbbe4ae2fcb", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"You are a professional chef in a Michelin-star restaurant. You will help me cook restaurant-style dishes using the ingredients I have left in my refrigerator.\\\n", + "You will provide detailed instructions with precise times and measurements in grams and include calorie information for raw ingredients, not cooked ones.\\\n", + "Add the caloric information at the end. Your responses should be formatted in Markdown.\"\n", + "\n", + "user_prompt = \"\"\"\n", + "Help me with a recipe using the ingredients I have left in the refrigerator. I have spinach, eggs, pasta, rice, chicken, beef, carrots, potatoes, butter, milk, cheese, tomatoes, red peppers, and all spices in the pantry.\\n\\n\n", + "\"\"\"\n", + "\n", + "messages = [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + "]\n", + " \n", + "response = openai.chat.completions.create(\n", + " model = \"gpt-4o-mini\",\n", + " messages = messages\n", + " )\n", + "\n", + "# Step 4: print the result in markdown format\n", + "pretty_response = Markdown(response.choices[0].message.content)\n", + "display(pretty_response)" + ] + } + ], + "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/week1/community-contributions/week1-day1_2-bedtime-storyteller.py b/week1/community-contributions/week1-day1_2-bedtime-storyteller.py new file mode 100644 index 0000000..f6fc6ef --- /dev/null +++ b/week1/community-contributions/week1-day1_2-bedtime-storyteller.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import os +import argparse +from dotenv import load_dotenv +from openai import OpenAI + +def load_openai_key(): + # Load environment variables in a file called .env + load_dotenv(override=True) + api_key = os.getenv('OPENAI_API_KEY') + + # Check the key + if not api_key: + return "Error: No API key was found!" + elif not api_key.startswith("sk-proj-"): + return "Error: An API key was found, but it doesn't start sk-proj-; please check you're using the right key" + elif api_key.strip() != api_key: + return "Error: An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them!" + else: + return "API key found and looks good so far!" + +def ask_llm(client, model, user_prompt): + system_prompt = """ + you are a writing assistant with an expertise in children's stories. + Write a bedtime story inspired by the subject below. + The story should have a begining, middle, and end. + The story shoukd be appropriate for children ages 5-8 and have a positive message. + I should be able to read the entire story in about 3 minutes + """ + response = client.chat.completions.create( + model = model, + messages = [ {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}] + ) + return response.choices[0].message.content + +def main(): + parser = argparse.ArgumentParser(description="AI Bedtime Storyteller") + parser.add_argument("provider", choices=["openai", "ollama"], help="AI provider to use") + parser.add_argument("--model", help="Model to use for Ollama (required if provider is 'ollama')", required="ollama" in parser.parse_known_args()[0].provider) + parser.add_argument("subject", help="What do you want the story to be about?") + + args = parser.parse_args() + + if args.provider == "openai": + load_openai_key() + client = OpenAI() + model = "gpt-4o-mini" + elif args.provider == "ollama": + client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama') + model = args.model + else: + return "Error: invalid provider!" + + user_prompt = args.subject + + result = ask_llm(client, model, user_prompt) + print("AI Response:", result) + +if __name__ == "__main__": + main() + diff --git a/week2/community-contributions/brochure_links_tone.ipynb b/week2/community-contributions/brochure_links_tone.ipynb new file mode 100644 index 0000000..12cb9a2 --- /dev/null +++ b/week2/community-contributions/brochure_links_tone.ipynb @@ -0,0 +1,567 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c79dc33e-1a3b-4601-a8f2-219b7a9b6d88", + "metadata": {}, + "source": [ + "# Company Brochure - Relevant Links and Custom Tone\n", + "\n", + "Using GPT to generate a company brochure with the relevant links functionality and the ability to choose the desired tone." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e32f4aa7-6fc4-4dc9-8058-58e6a7f329c5", + "metadata": {}, + "outputs": [], + "source": [ + "# Imports\n", + "\n", + "import os\n", + "import requests\n", + "import json\n", + "from typing import List\n", + "from dotenv import load_dotenv\n", + "from bs4 import BeautifulSoup\n", + "from IPython.display import Markdown, display, update_display\n", + "from openai import OpenAI\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d1d65a21-bbba-44ff-a2be-85bf2055a493", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key set and good to go.\n" + ] + } + ], + "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", + "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(\"OpenAI API Key set and good to go.\")\n", + "else:\n", + " print(\"OpenAI API Key not set. :(\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c5db63fe-5da8-496e-9b37-139598d600a7", + "metadata": {}, + "outputs": [], + "source": [ + "# Setting up the OpenAI object\n", + "\n", + "openai = OpenAI()\n", + "gpt_model = 'gpt-4o-mini'" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "535da52f-b280-48ce-aa8b-f82f9f9805d9", + "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", + " response = requests.get(url, headers=headers)\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]\n", + "\n", + " def get_contents(self):\n", + " return f\"Webpage Title:\\n{self.title}\\nWebpage Contents:\\n{self.text}\\n\\n\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8d5757c4-95f4-4038-8ed4-8c81da5112b0", + "metadata": {}, + "outputs": [], + "source": [ + "link_system_prompt = \"You are provided with a list of links found on a webpage. \\\n", + "You are able to decide which of the links would be most relevant to include in a brochure about the company, \\\n", + "such as links to an About page, or a Company page, or Careers/Jobs pages.\\n\"\n", + "link_system_prompt += \"You should respond in JSON as in this example:\"\n", + "link_system_prompt += \"\"\"\n", + "{\n", + " \"links\": [\n", + " {\"type\": \"about page\", \"url\": \"https://full.url/goes/here/about\"},\n", + " {\"type\": \"careers page\": \"url\": \"https://another.full.url/careers\"}\n", + " ]\n", + "}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d5fd31ac-7c81-454a-a1dc-4c58bd3db246", + "metadata": {}, + "outputs": [], + "source": [ + "def get_links_user_prompt(website):\n", + " user_prompt = f\"Here is the list of links on the website of {website.url} - \"\n", + " user_prompt += \"please decide which of these are relevant web links for a brochure about the company, respond with the full https URL in JSON format. \\\n", + "Do not include Terms of Service, Privacy, email links.\\n\"\n", + " user_prompt += \"Links (some might be relative links):\\n\"\n", + " user_prompt += \"\\n\".join(website.links)\n", + " return user_prompt" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e8b67492-1ba4-4aad-a588-39116128fa18", + "metadata": {}, + "outputs": [], + "source": [ + "def gpt_get_links(url):\n", + " website = Website(url)\n", + " response = openai.chat.completions.create(\n", + " model= gpt_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": link_system_prompt},\n", + " {\"role\": \"user\", \"content\": get_links_user_prompt(website)}\n", + " ],\n", + " response_format={\"type\": \"json_object\"}\n", + " )\n", + " result = response.choices[0].message.content\n", + " return json.loads(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e8846e7a-ace2-487e-a0a8-fccb389f2eb9", + "metadata": {}, + "outputs": [], + "source": [ + "# This function provides uses the get_contents method in the Website Class as well as GPT to find relevant links.\n", + "\n", + "def get_all_details(url):\n", + " result = \"Landing page:\\n\"\n", + " result += Website(url).get_contents()\n", + " links = gpt_get_links(url)\n", + " print(\"Found links:\", links)\n", + " for link in links[\"links\"]:\n", + " result += f\"\\n\\n{link['type']}\\n\"\n", + " result += Website(link[\"url\"]).get_contents()\n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "18b42319-8342-4b9c-bef6-8b72acf92ab3", + "metadata": {}, + "outputs": [], + "source": [ + "def get_brochure_user_prompt(company_name, url):\n", + " user_prompt = f\"You are looking at a company called: {company_name}\\n\"\n", + " user_prompt += f\"Here are the contents of its landing page and other relevant pages; \\\n", + " use this information to build a short brochure of the company in markdown.\\n\"\n", + " \n", + " user_prompt += get_all_details(url)\n", + " user_prompt = user_prompt[:5_000] # Truncate if more than 5,000 characters\n", + " return user_prompt" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d7748293-a616-41de-93cb-89f65cc5c73d", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's create a call that streams back results\n", + "# If you'd like a refresher on Generators (the \"yield\" keyword),\n", + "# Please take a look at the Intermediate Python notebook in week1 folder.\n", + "\n", + "def stream_brochure(company_name, url, tone):\n", + "\n", + " system_message = f\"You are an assistant that analyzes the content of several relevant pages from a company website \\\n", + " and creates a short brochure about the company for prospective customers, investors, and recruits. \\\n", + " Include details of company culture, customers and careers/jobs if you have the information. \\\n", + " Respond in markdown, and use a {tone.lower()} tone throughout the brochure.\"\n", + "\n", + " \n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": get_brochure_user_prompt(company_name, url)}\n", + " ]\n", + " stream = openai.chat.completions.create(\n", + " model=gpt_model,\n", + " messages=messages,\n", + " stream=True\n", + " )\n", + " result = \"\"\n", + " for chunk in stream:\n", + " result += chunk.choices[0].delta.content or \"\"\n", + " yield result" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "15222832-06e0-4452-a8e1-59b9b1755488", + "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" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found links: {'links': [{'type': 'about page', 'url': 'https://www.snowflake.com/about/events/'}, {'type': 'company page', 'url': 'https://www.snowflake.com/en/company/overview/about-snowflake/'}, {'type': 'company leadership page', 'url': 'https://www.snowflake.com/en/company/overview/leadership-and-board/'}, {'type': 'careers page', 'url': 'https://careers.snowflake.com/us/en'}, {'type': 'company ESG page', 'url': 'https://www.snowflake.com/en/company/overview/esg/'}, {'type': 'company ventures page', 'url': 'https://www.snowflake.com/en/company/overview/snowflake-ventures/'}, {'type': 'end data disparity page', 'url': 'https://www.snowflake.com/en/company/overview/end-data-disparity/'}]}\n", + "Found links: {'links': [{'type': 'about page', 'url': 'https://www.snowflake.com/about/events/'}, {'type': 'about page', 'url': 'https://www.snowflake.com/company/overview/about-snowflake/'}, {'type': 'leadership page', 'url': 'https://www.snowflake.com/company/overview/leadership-and-board/'}, {'type': 'careers page', 'url': 'https://careers.snowflake.com/us/en'}, {'type': 'investor relations', 'url': 'https://investors.snowflake.com/overview/default.aspx'}, {'type': 'ESG page', 'url': 'https://www.snowflake.com/company/overview/esg/'}, {'type': 'snowflake ventures', 'url': 'https://www.snowflake.com/company/overview/snowflake-ventures/'}, {'type': 'end data disparity', 'url': 'https://www.snowflake.com/company/overview/end-data-disparity/'}]}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 464, in _make_request\n", + " self._validate_conn(conn)\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 1093, in _validate_conn\n", + " conn.connect()\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connection.py\", line 741, in connect\n", + " sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connection.py\", line 920, in _ssl_wrap_socket_and_match_hostname\n", + " ssl_sock = ssl_wrap_socket(\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/ssl_.py\", line 460, in ssl_wrap_socket\n", + " ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/ssl_.py\", line 504, in _ssl_wrap_socket_impl\n", + " return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 517, in wrap_socket\n", + " return self.sslsocket_class._create(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 1104, in _create\n", + " self.do_handshake()\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 1382, in do_handshake\n", + " self._sslobj.do_handshake()\n", + "ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 787, in urlopen\n", + " response = self._make_request(\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 488, in _make_request\n", + " raise new_e\n", + "urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/adapters.py\", line 667, in send\n", + " resp = conn.urlopen(\n", + " ^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 841, in urlopen\n", + " retries = retries.increment(\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/retry.py\", line 519, in increment\n", + " raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='petrofac.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/queueing.py\", line 625, in process_events\n", + " response = await route_utils.call_process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/route_utils.py\", line 322, in call_process_api\n", + " output = await app.get_blocks().process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 2103, in process_api\n", + " result = await self.call_function(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 1662, in call_function\n", + " prediction = await utils.async_iteration(iterator)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 735, in async_iteration\n", + " return await anext(iterator)\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 729, in __anext__\n", + " return await anyio.to_thread.run_sync(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/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 \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 2461, in run_sync_in_worker_thread\n", + " return await future\n", + " ^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 962, in run\n", + " result = context.run(func, *args)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 712, in run_sync_iterator_async\n", + " return next(iterator)\n", + " ^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 873, in gen_wrapper\n", + " response = next(iterator)\n", + " ^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/601932735.py\", line 15, in stream_brochure\n", + " {\"role\": \"user\", \"content\": get_brochure_user_prompt(company_name, url)}\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/3764629295.py\", line 6, in get_brochure_user_prompt\n", + " user_prompt += get_all_details(url)\n", + " ^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/2913862724.py\", line 5, in get_all_details\n", + " result += Website(url).get_contents()\n", + " ^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/1579423502.py\", line 15, in __init__\n", + " response = requests.get(url, headers=headers)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/api.py\", line 73, in get\n", + " return request(\"get\", url, params=params, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/api.py\", line 59, in request\n", + " return session.request(method=method, url=url, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/sessions.py\", line 589, in request\n", + " resp = self.send(prep, **send_kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/sessions.py\", line 703, in send\n", + " r = adapter.send(request, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/adapters.py\", line 698, in send\n", + " raise SSLError(e, request=request)\n", + "requests.exceptions.SSLError: HTTPSConnectionPool(host='petrofac.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 464, in _make_request\n", + " self._validate_conn(conn)\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 1093, in _validate_conn\n", + " conn.connect()\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connection.py\", line 741, in connect\n", + " sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connection.py\", line 920, in _ssl_wrap_socket_and_match_hostname\n", + " ssl_sock = ssl_wrap_socket(\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/ssl_.py\", line 460, in ssl_wrap_socket\n", + " ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/ssl_.py\", line 504, in _ssl_wrap_socket_impl\n", + " return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 517, in wrap_socket\n", + " return self.sslsocket_class._create(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 1104, in _create\n", + " self.do_handshake()\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/ssl.py\", line 1382, in do_handshake\n", + " self._sslobj.do_handshake()\n", + "ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 787, in urlopen\n", + " response = self._make_request(\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 488, in _make_request\n", + " raise new_e\n", + "urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/adapters.py\", line 667, in send\n", + " resp = conn.urlopen(\n", + " ^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/connectionpool.py\", line 841, in urlopen\n", + " retries = retries.increment(\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/urllib3/util/retry.py\", line 519, in increment\n", + " raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='petrofac.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/queueing.py\", line 625, in process_events\n", + " response = await route_utils.call_process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/route_utils.py\", line 322, in call_process_api\n", + " output = await app.get_blocks().process_api(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 2103, in process_api\n", + " result = await self.call_function(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 1662, in call_function\n", + " prediction = await utils.async_iteration(iterator)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 735, in async_iteration\n", + " return await anext(iterator)\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 729, in __anext__\n", + " return await anyio.to_thread.run_sync(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/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 \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 2461, in run_sync_in_worker_thread\n", + " return await future\n", + " ^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 962, in run\n", + " result = context.run(func, *args)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 712, in run_sync_iterator_async\n", + " return next(iterator)\n", + " ^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 873, in gen_wrapper\n", + " response = next(iterator)\n", + " ^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/601932735.py\", line 15, in stream_brochure\n", + " {\"role\": \"user\", \"content\": get_brochure_user_prompt(company_name, url)}\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/3764629295.py\", line 6, in get_brochure_user_prompt\n", + " user_prompt += get_all_details(url)\n", + " ^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/2913862724.py\", line 5, in get_all_details\n", + " result += Website(url).get_contents()\n", + " ^^^^^^^^^^^^\n", + " File \"/var/folders/yc/m81x80gn66j4fbm15pk5gmfr0000gn/T/ipykernel_39727/1579423502.py\", line 15, in __init__\n", + " response = requests.get(url, headers=headers)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/api.py\", line 73, in get\n", + " return request(\"get\", url, params=params, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/api.py\", line 59, in request\n", + " return session.request(method=method, url=url, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/sessions.py\", line 589, in request\n", + " resp = self.send(prep, **send_kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/sessions.py\", line 703, in send\n", + " r = adapter.send(request, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/requests/adapters.py\", line 698, in send\n", + " raise SSLError(e, request=request)\n", + "requests.exceptions.SSLError: HTTPSConnectionPool(host='petrofac.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found links: {'links': [{'type': 'about page', 'url': 'https://www.petrofac.com/who-we-are/'}, {'type': 'what we do page', 'url': 'https://www.petrofac.com/who-we-are/what-we-do/'}, {'type': 'careers page', 'url': 'https://www.petrofac.com/careers/'}, {'type': 'our structure page', 'url': 'https://www.petrofac.com/who-we-are/our-structure/'}, {'type': 'energy transition page', 'url': 'https://www.petrofac.com/who-we-are/energy-transition/'}, {'type': 'sustainability and ESG page', 'url': 'https://www.petrofac.com/who-we-are/sustainability-and-esg/'}, {'type': 'investor relations page', 'url': 'https://www.petrofac.com/investors/'}, {'type': 'services page', 'url': 'https://www.petrofac.com/services/'}, {'type': 'where we operate page', 'url': 'https://www.petrofac.com/where-we-operate/'}]}\n" + ] + } + ], + "source": [ + "view = gr.Interface(\n", + " fn=stream_brochure,\n", + " inputs=[\n", + " gr.Textbox(label=\"Company name:\"),\n", + " gr.Textbox(label=\"Landing page URL including http:// or https://\"),\n", + " gr.Textbox(label=\"Tone:\")],\n", + " outputs=[gr.Markdown(label=\"Brochure:\")],\n", + " flagging_mode=\"never\"\n", + ")\n", + "view.launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70d6398c-21dd-44f8-ba7d-0204414dffa0", + "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/week3/community-contributions/day5_openai_whisper_llamainstruct b/week3/community-contributions/day5_openai_whisper_llamainstruct new file mode 100644 index 0000000..c11e2b1 --- /dev/null +++ b/week3/community-contributions/day5_openai_whisper_llamainstruct @@ -0,0 +1,78 @@ +import gradio as gr +import torch +from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, TextStreamer, AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline +from huggingface_hub import login +import os + +# Use the secret stored in the Hugging Face space +token = os.getenv("HF_TOKEN") +login(token=token) + +# Whisper Model Optimization +model = "openai/whisper-tiny" +DEVICE = "cuda" if torch.cuda.is_available() else "cpu" + +processor = AutoProcessor.from_pretrained(model) + + +transcriber = pipeline( + "automatic-speech-recognition", + model=model, + tokenizer=processor.tokenizer, + feature_extractor=processor.feature_extractor, + device=0 if torch.cuda.is_available() else "cpu", +) + + + +# Function to Transcribe & Generate Minutes +def process_audio(audio_file): + if audio_file is None: + return "Error: No audio provided!" + + # Transcribe audio + transcript = transcriber(audio_file)["text"] + del transcriber + del processor + # LLaMA Model Optimization + LLAMA = "meta-llama/Llama-3.2-3B-Instruct" + llama_quant_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_use_double_quant=True, + bnb_4bit_compute_dtype=torch.bfloat16, + bnb_4bit_quant_type="nf4" + ) + + tokenizer = AutoTokenizer.from_pretrained(LLAMA) + tokenizer.pad_token = tokenizer.eos_token + model = AutoModelForCausalLM.from_pretrained( + LLAMA, + torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, + device_map="auto" + ) + # Generate meeting minutes + system_message = "You are an assistant that produces minutes of meetings from transcripts, with summary, key discussion points, takeaways and action items with owners, in markdown." + user_prompt = f"Below is an extract transcript of a Denver council meeting. Please write minutes in markdown, including a summary with attendees, location and date; discussion points; takeaways; and action items with owners.\n{transcript}" + + messages = [ + {"role": "system", "content": system_message}, + {"role": "user", "content": user_prompt} + ] + + inputs = tokenizer.apply_chat_template(messages, return_tensors="pt").to(DEVICE) + streamer = TextStreamer(tokenizer) + outputs = model.generate(inputs, max_new_tokens=2000, streamer=streamer) + + return tokenizer.decode(outputs[0], skip_special_tokens=True) + +# Gradio Interface +interface = gr.Interface( + fn=process_audio, + inputs=gr.Audio(sources=["upload", "microphone"], type="filepath"), + outputs="text", + title="Meeting Minutes Generator", + description="Upload or record an audio file to get structured meeting minutes in Markdown.", +) + +# Launch App +interface.launch() diff --git a/week5/community-contributions/day5_vectorstore_openai.ipynb b/week5/community-contributions/day5_vectorstore_openai.ipynb new file mode 100644 index 0000000..a1aa575 --- /dev/null +++ b/week5/community-contributions/day5_vectorstore_openai.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import documents exported from Evernote to a vectorstore\n", + "### Use OpenAI file search with responses API\n", + "#### Prerequisite steps\n", + "* exported notes from your Evernote notebook as html \n", + "* converted the notes further to md-files and remove broken image links (use python/AI)\n", + "* the files are named with note titles\n", + "\n", + "Files are in one folder.\n", + "\n", + "\n", + "##### Query ChromaDB vectorstore\n", + "I tried to accomplish this task with RAG like the example by https://github.com/ed-donner/llm_engineering/commits?author=dinorrusso.\n", + "\n", + "I thought this to be a trivial task, but it was not 😃 That example uses Ollama running locally.\n", + "Even though the retriever had the information required, it was dropped from the answer.\n", + "\n", + "I tried then to use Chroma + OpenAI. After several attemps succeeded to create a vectorstore and query it. That's it for this time.\n", + "\n", + "##### Openai vectorstore, see bottom of the notebook\n", + "One attempt was to use OpenAI's fileSearch-tool which seemed pretty straightforward.\n", + "The con: loading files was not working always. Code is left though as reference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Imports\n", + "from dotenv import load_dotenv\n", + "import gradio as gr\n", + "import openai\n", + "import chromadb\n", + "from chromadb.config import Settings\n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Load files to vectorstore" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "load_dotenv(override=True)\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n", + "openai.api_key = os.environ['OPENAI_API_KEY']\n", + "\n", + "def chunk_text(text, max_tokens=2000):\n", + " words = text.split()\n", + " chunks = []\n", + " current_chunk = []\n", + " current_length = 0\n", + "\n", + " for word in words:\n", + " current_length += len(word) + 1 # +1 for the space\n", + " if current_length > max_tokens:\n", + " chunks.append(\" \".join(current_chunk))\n", + " current_chunk = [word]\n", + " current_length = len(word) + 1\n", + " else:\n", + " current_chunk.append(word)\n", + "\n", + " if current_chunk:\n", + " chunks.append(\" \".join(current_chunk))\n", + "\n", + " return chunks\n", + "\n", + "\n", + "# # Set up OpenAI API key\n", + "# openai.api_key = \"your_openai_api_key\" # Replace with your API key\n", + "chroma_client = chromadb.Client()\n", + "\n", + "# Create or get the existing collection\n", + "collection_name = \"EverNotes\"\n", + "\n", + "try:\n", + " existing_collection = chroma_client.get_collection(name=collection_name)\n", + " if existing_collection.count() > 0:\n", + " chroma_client.delete_collection(name=collection_name)\n", + "except:\n", + " print(f\"Collection {collection_name} does not exist. Creating a new one.\")\n", + "\n", + "# Create a collection in ChromaDB\n", + "collection = chroma_client.get_or_create_collection(name=collection_name)\n", + "\n", + "# Define your data\n", + "# it should be like this\n", + "# documents = [\"OpenAI is revolutionizing AI.\", \"ChromaDB makes embedding storage easy.\"]\n", + "# metadata = [{\"id\": 1}, {\"id\": 2}]\n", + "\n", + "folder_path = os.getenv('EVERNOTE_EXPORT')\n", + "documents = []\n", + "\n", + "for root, dirs, files in os.walk(folder_path):\n", + " for file in files:\n", + " if file.endswith('.md'): # Change this to the file extension you need\n", + " with open(os.path.join(root, file), 'r') as f:\n", + " documents.append(f.read())\n", + "\n", + "metadata = [{\"id\": i + 1} for i in range(len(documents))]\n", + "\n", + "# Generate embeddings using OpenAI\n", + "def get_embedding(text, model=\"text-embedding-ada-002\"):\n", + " response = openai.embeddings.create(input=text, model=model)\n", + " return response.data[0].embedding\n", + "\n", + "# Add documents and embeddings to ChromaDB in chunks\n", + "for doc, meta in zip(documents, metadata):\n", + " chunks = chunk_text(doc)\n", + " for chunk in chunks:\n", + " embedding = get_embedding(chunk)\n", + " collection.add(\n", + " documents=[chunk],\n", + " embeddings=[embedding],\n", + " metadatas=[meta],\n", + " ids=[str(meta[\"id\"])]\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Query ChromaDB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# \n", + "query_text = \"Is there a video for Fitting the Shimano speed hub 7\"\n", + "query_embedding = get_embedding(query_text)\n", + "\n", + "results = collection.query(\n", + " query_embeddings=[query_embedding],\n", + " n_results=2\n", + ")\n", + "\n", + "print(\"Query Results:\", results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Gradio interface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Function to query ChromaDB\n", + "def query_chromadb(query_text):\n", + " query_embedding = get_embedding(query_text)\n", + " results = collection.query(\n", + " query_embeddings=[query_embedding],\n", + " n_results=2\n", + " )\n", + " return results\n", + "\n", + "# Gradio interface\n", + "def gradio_interface(query_text):\n", + " results = query_chromadb(query_text)\n", + " return results\n", + "\n", + "# Create Gradio app\n", + "iface = gr.Interface(\n", + " fn=gradio_interface,\n", + " inputs=\"text\",\n", + " outputs=\"text\",\n", + " title=\"ChromaDB Query Interface\",\n", + " description=\"Enter your query to search the ChromaDB collection.\"\n", + ")\n", + "\n", + "iface.launch()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Below OpenAI filesearch variant which had some failures in file uploads." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import glob\n", + "folder_path = os.environ['EVERNOTE_EXPORT'] \n", + "# Filter out other except .md-files\n", + "md_files = glob.glob(os.path.join(folder_path, '*.md'))\n", + "file_paths = [os.path.join(folder_path, file) for file in md_files]\n", + "file_streams = [open(path, 'rb') for path in file_paths]\n", + "\n", + "# Create vector store\n", + "vector_store = openai.vector_stores.create(\n", + " name=\"Evernote notes\",\n", + ")\n", + "\n", + "# Batch Upload Limit: You can upload up to 100 files in a single batch\n", + "# https://community.openai.com/t/max-100-files-in-vector-store/729876/4\n", + "batch_size = 90\n", + "for i in range(0, len(file_streams), batch_size):\n", + " batch = file_streams[i:i + batch_size]\n", + " file_batch = openai.vector_stores.file_batches.upload_and_poll(\n", + " vector_store_id=vector_store.id,\n", + " files=batch\n", + " )\n", + " print(file_batch.status)\n", + " print(file_batch.file_counts)\n", + "\n", + "# There can be some fails in file counts:\n", + "# \"FileCounts(cancelled=0, completed=89, failed=1, in_progress=0, total=90)\"\"\n", + "# Usually 1 % fails. Did not find solution for improving that yet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "response = openai.responses.create(\n", + " model=\"gpt-4o-mini\",\n", + " input=\"Is there a video for Fitting the Shimano speed hub 7?\",\n", + " tools=[{\n", + " \"type\": \"file_search\",\n", + " \"vector_store_ids\": [vector_store.id]\n", + " }],\n", + " include=None\n", + ")\n", + "print(response)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.11" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week5/community-contributions/markdown_knowledge_worker.ipynb b/week5/community-contributions/markdown_knowledge_worker.ipynb new file mode 100644 index 0000000..51597f5 --- /dev/null +++ b/week5/community-contributions/markdown_knowledge_worker.ipynb @@ -0,0 +1,359 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c25c6e94-f3de-4367-b2bf-269ba7160977", + "metadata": {}, + "source": [ + "## An Expert Knowledge Worker Question-Answering Agent using RAG" + ] + }, + { + "cell_type": "markdown", + "id": "15169580-cf11-4dee-8ec7-3a4ef59b19ee", + "metadata": {}, + "source": [ + "Aims\n", + "- Reads README.md files and loads data using TextLoader\n", + "- Splits into chunks using CharacterTextSplitter\n", + "- Converts chunks into vector embeddings and creates a datastore\n", + "- 2D and 3D visualisations\n", + "- Langchain to set up a conversation retrieval chain" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "051cf881-357d-406b-8eae-1610651e40f1", + "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": "ccfd403a-5bdb-4a8c-b3fd-d47ae79e43f7", + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain, plotly and Chroma\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.embeddings import HuggingFaceEmbeddings\n", + "from langchain_chroma import Chroma\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "import numpy as np\n", + "from sklearn.manifold import TSNE\n", + "import plotly.graph_objects as go\n", + "import plotly.express as px\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d853868-d2f6-43e1-b27c-b8e91d06b724", + "metadata": {}, + "outputs": [], + "source": [ + "MODEL = \"gpt-4o-mini\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f152fc3b-0bf4-4d51-948f-95da1ebc030a", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24e621ac-df06-4af6-a60d-a9ed7adb884a", + "metadata": {}, + "outputs": [], + "source": [ + "# Read in documents using LangChain's loaders\n", + "\n", + "folder = \"my-knowledge-base/\"\n", + "text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + "folder_docs = loader.load()\n", + "\n", + "for doc in folder_docs:\n", + " filename_md = os.path.basename(doc.metadata[\"source\"]) \n", + " filename, _ = os.path.splitext(filename_md) \n", + " doc.metadata[\"filename\"] = filename\n", + "\n", + "documents = folder_docs \n", + "\n", + "text_splitter = CharacterTextSplitter(chunk_size=400, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)\n", + "\n", + "print(f\"Total number of chunks: {len(chunks)}\")\n", + "print(f\"Files found: {set(doc.metadata['filename'] for doc in documents)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02f08ee-5ade-4f79-a500-045a8f1a532f", + "metadata": {}, + "outputs": [], + "source": [ + "# Put the chunks of data into a Vector Store that associates a Vector Embedding with each chunk\n", + "\n", + "embeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-MiniLM-L6-v2\")\n", + "\n", + "# Delete if already exists\n", + "\n", + "if os.path.exists(db_name):\n", + " Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection()\n", + "\n", + "# Create 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": null, + "id": "7f665f4d-ccb1-43fb-b901-040117925732", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's investigate the vectors\n", + "\n", + "collection = vectorstore._collection\n", + "count = collection.count()\n", + "\n", + "sample_embedding = collection.get(limit=1, include=[\"embeddings\"])[\"embeddings\"][0]\n", + "dimensions = len(sample_embedding)\n", + "print(f\"There are {count:,} vectors with {dimensions:,} dimensions in the vector store\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6208a971-e8b7-48bc-be7a-6dcb82967fd2", + "metadata": {}, + "outputs": [], + "source": [ + "# pre work\n", + "\n", + "result = collection.get(include=['embeddings','documents','metadatas'])\n", + "vectors = np.array(result['embeddings']) \n", + "documents = result['documents']\n", + "metadatas = result['metadatas']\n", + "filenames = [metadata['filename'] for metadata in metadatas]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb27bc8a-453b-4b19-84b4-dc495bb0e544", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "def random_color():\n", + " return f\"rgb({random.randint(0,255)},{random.randint(0,255)},{random.randint(0,255)})\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78db67e5-ef10-4581-b8ac-3e0281ceba45", + "metadata": {}, + "outputs": [], + "source": [ + "def show_embeddings_2d(result):\n", + " vectors = np.array(result['embeddings']) \n", + " documents = result['documents']\n", + " metadatas = result['metadatas']\n", + " filenames = [metadata['filename'] for metadata in metadatas]\n", + " filenames_unique = sorted(set(filenames))\n", + "\n", + " # color assignment\n", + " color_map = {name: random_color() for name in filenames_unique}\n", + " colors = [color_map[name] for name in filenames]\n", + "\n", + " tsne = TSNE(n_components=2, random_state=42,perplexity=4)\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(filenames, 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, + "id": "2c250166-cb5b-4a75-8981-fae2d6dfe509", + "metadata": {}, + "outputs": [], + "source": [ + "show_embeddings_2d(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b290e38-0800-4453-b664-7a7622ff5ed2", + "metadata": {}, + "outputs": [], + "source": [ + "def show_embeddings_3d(result):\n", + " vectors = np.array(result['embeddings']) \n", + " documents = result['documents']\n", + " metadatas = result['metadatas']\n", + " filenames = [metadata['filename'] for metadata in metadatas]\n", + " filenames_unique = sorted(set(filenames))\n", + "\n", + " # color assignment\n", + " color_map = {name: random_color() for name in filenames_unique}\n", + " colors = [color_map[name] for name in filenames]\n", + "\n", + " tsne = TSNE(n_components=3, random_state=42)\n", + " reduced_vectors = tsne.fit_transform(vectors)\n", + "\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(filenames, 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, + "id": "45d1d034-2503-4176-b1e4-f248e31c4770", + "metadata": {}, + "outputs": [], + "source": [ + "show_embeddings_3d(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e79946a1-f93a-4b3a-8d19-deef40dec223", + "metadata": {}, + "outputs": [], + "source": [ + "# create a new Chat with OpenAI\n", + "llm = ChatOpenAI(temperature=0.7, model_name=MODEL)\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(search_kwargs={\"k\": 50})\n", + "\n", + "# putting it together: set up the conversation chain with the GPT 3.5 LLM, the vector store and memory\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59f90c85-c113-4482-8574-8a728ef25459", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(question, history):\n", + " result = conversation_chain.invoke({\"question\": question})\n", + " return result[\"answer\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0520a8ff-01a4-4fa6-9dc8-57da87272edc", + "metadata": {}, + "outputs": [], + "source": [ + "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4949b17-cd9c-4bff-bd5b-0f80df72e7dc", + "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/week5/community-contributions/ui_markdown_knowledge_worker.ipynb b/week5/community-contributions/ui_markdown_knowledge_worker.ipynb new file mode 100644 index 0000000..5bf6f56 --- /dev/null +++ b/week5/community-contributions/ui_markdown_knowledge_worker.ipynb @@ -0,0 +1,353 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d13be0fd-db15-4ab1-860a-b00257051339", + "metadata": {}, + "source": [ + "## Gradio UI for Markdown-Based Q&A with Visualization" + ] + }, + { + "cell_type": "markdown", + "id": "bc63fbdb-66a9-4c10-8dbd-11476b5e2d21", + "metadata": {}, + "source": [ + "This interface enables users to:\n", + "- Upload Markdown files for processing\n", + "- Visualize similarity between document chunks in 2D and 3D using embeddings\n", + "- Ask questions and receive RAG enabled responses\n", + "- Mantain conversation context for better question answering\n", + "- Clear chat history when required for fresh sessions\n", + "- Store and retrieve embeddings using ChromaDB\n", + "\n", + "Integrates LangChain, ChromaDB, and OpenAI to process, store, and retrieve information efficiently." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91da28d8-8e29-44b7-a62a-a3a109753727", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e47f670a-e2cb-4700-95d0-e59e440677a1", + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain, plotly and Chroma\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.embeddings import HuggingFaceEmbeddings\n", + "from langchain_chroma import Chroma\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "import numpy as np\n", + "from sklearn.manifold import TSNE\n", + "import plotly.graph_objects as go\n", + "import plotly.express as px\n", + "import matplotlib.pyplot as plt\n", + "from random import randint\n", + "import shutil" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "362d4976-2553-4ed8-8fbb-49806145cad1", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install --upgrade gradio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "968b6e96-557e-439f-b2f1-942c05168641", + "metadata": {}, + "outputs": [], + "source": [ + "MODEL = \"gpt-4o-mini\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "537f66de-6abf-4b34-8e05-6b9a9df8ae82", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246c1c1b-fcfa-4f4c-b99c-024598751361", + "metadata": {}, + "outputs": [], + "source": [ + "folder = \"my-knowledge-base/\"\n", + "db_name = \"vectorstore_db\"\n", + "\n", + "def process_files(files):\n", + " os.makedirs(folder, exist_ok=True)\n", + "\n", + " processed_files = []\n", + " for file in files:\n", + " file_path = os.path.join(folder, os.path.basename(file)) # Get filename\n", + " shutil.copy(file, file_path)\n", + " processed_files.append(os.path.basename(file))\n", + "\n", + " # Load documents using LangChain's DirectoryLoader\n", + " text_loader_kwargs = {'autodetect_encoding': True}\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + "\n", + " # Assign filenames as metadata\n", + " for doc in folder_docs:\n", + " filename_md = os.path.basename(doc.metadata[\"source\"])\n", + " filename, _ = os.path.splitext(filename_md)\n", + " doc.metadata[\"filename\"] = filename\n", + "\n", + " documents = folder_docs \n", + "\n", + " # Split documents into chunks\n", + " text_splitter = CharacterTextSplitter(chunk_size=400, chunk_overlap=200)\n", + " chunks = text_splitter.split_documents(documents)\n", + "\n", + " # Initialize embeddings\n", + " embeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-MiniLM-L6-v2\")\n", + "\n", + " # Delete previous vectorstore\n", + " if os.path.exists(db_name):\n", + " Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection()\n", + "\n", + " # Store in ChromaDB\n", + " vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=db_name)\n", + "\n", + " # Retrieve results\n", + " collection = vectorstore._collection\n", + " result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "\n", + " llm = ChatOpenAI(temperature=0.7, model_name=MODEL)\n", + " memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + " retriever = vectorstore.as_retriever(search_kwargs={\"k\": 35})\n", + " global conversation_chain\n", + " conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)\n", + "\n", + " processed_text = \"**Processed Files:**\\n\\n\" + \"\\n\".join(f\"- {file}\" for file in processed_files)\n", + " return result, processed_text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48678d3a-0ab2-4aa4-aa9e-4160c6a9cb24", + "metadata": {}, + "outputs": [], + "source": [ + "def random_color():\n", + " return f\"rgb({randint(0,255)},{randint(0,255)},{randint(0,255)})\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6caed889-9bb4-42ad-b1c2-da051aefc802", + "metadata": {}, + "outputs": [], + "source": [ + "def show_embeddings_2d(result):\n", + " vectors = np.array(result['embeddings']) \n", + " documents = result['documents']\n", + " metadatas = result['metadatas']\n", + " filenames = [metadata['filename'] for metadata in metadatas]\n", + " filenames_unique = sorted(set(filenames))\n", + "\n", + " # color assignment\n", + " color_map = {name: random_color() for name in filenames_unique}\n", + " colors = [color_map[name] for name in filenames]\n", + "\n", + " tsne = TSNE(n_components=2, random_state=42,perplexity=4)\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(filenames, 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", + " return fig" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de993495-c8cd-4313-a6bb-7d27494ecc13", + "metadata": {}, + "outputs": [], + "source": [ + "def show_embeddings_3d(result):\n", + " vectors = np.array(result['embeddings']) \n", + " documents = result['documents']\n", + " metadatas = result['metadatas']\n", + " filenames = [metadata['filename'] for metadata in metadatas]\n", + " filenames_unique = sorted(set(filenames))\n", + "\n", + " # color assignment\n", + " color_map = {name: random_color() for name in filenames_unique}\n", + " colors = [color_map[name] for name in filenames]\n", + "\n", + " tsne = TSNE(n_components=3, random_state=42)\n", + " reduced_vectors = tsne.fit_transform(vectors)\n", + "\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(filenames, 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", + " return fig" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b7bf62b-c559-4e97-8135-48cd8d97a40e", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(question, history):\n", + " result = conversation_chain.invoke({\"question\": question})\n", + " return result[\"answer\"]\n", + "\n", + "def visualise_data(result):\n", + " fig_2d = show_embeddings_2d(result)\n", + " fig_3d = show_embeddings_3d(result)\n", + " return fig_2d,fig_3d" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99217109-fbee-4269-81c7-001e6f768a72", + "metadata": {}, + "outputs": [], + "source": [ + "css = \"\"\"\n", + ".btn {background-color: #1d53d1;}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1429ea1-1d9f-4be6-b270-01997864c642", + "metadata": {}, + "outputs": [], + "source": [ + "with gr.Blocks(css=css) as ui:\n", + " gr.Markdown(\"# Markdown-Based Q&A with Visualization\")\n", + " with gr.Row():\n", + " file_input = gr.Files(file_types=[\".md\"], label=\"Upload Markdown Files\")\n", + " with gr.Column(scale=1):\n", + " processed_output = gr.Markdown(\"Progress\")\n", + " with gr.Row():\n", + " process_btn = gr.Button(\"Process Files\",elem_classes=[\"btn\"])\n", + " with gr.Row():\n", + " question = gr.Textbox(label=\"Chat \", lines=10)\n", + " answer = gr.Markdown(label= \"Response\")\n", + " with gr.Row():\n", + " question_btn = gr.Button(\"Ask a Question\",elem_classes=[\"btn\"])\n", + " clear_btn = gr.Button(\"Clear Output\",elem_classes=[\"btn\"])\n", + " with gr.Row():\n", + " plot_2d = gr.Plot(label=\"2D Visualization\")\n", + " plot_3d = gr.Plot(label=\"3D Visualization\")\n", + " with gr.Row():\n", + " visualise_btn = gr.Button(\"Visualise Data\",elem_classes=[\"btn\"])\n", + "\n", + " result = gr.State([])\n", + " # Action: When button is clicked, process files and update visualization\n", + " clear_btn.click(fn=lambda:(\"\", \"\"), inputs=[],outputs=[question, answer])\n", + " process_btn.click(process_files, inputs=[file_input], outputs=[result,processed_output])\n", + " question_btn.click(chat, inputs=[question], outputs= [answer])\n", + " visualise_btn.click(visualise_data, inputs=[result], outputs=[plot_2d,plot_3d])\n", + "\n", + "# Launch Gradio app\n", + "ui.launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3686048-ac29-4df1-b816-e58996913ef1", + "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 +}