{ "cells": [ { "cell_type": "markdown", "id": "8b0e11f2-9ea4-48c2-b8d2-d0a4ba967827", "metadata": {}, "source": [ "# Gradio Day!\n", "\n", "Today we will build User Interfaces using the outrageously simple Gradio framework.\n", "\n", "Prepare for joy!\n", "\n", "Please note: your Gradio screens may appear in 'dark mode' or 'light mode' depending on your computer settings." ] }, { "cell_type": "code", "execution_count": null, "id": "c44c5494-950d-4d2f-8d4f-b87b57c5b330", "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 requests\n", "from bs4 import BeautifulSoup" ] }, { "cell_type": "code", "execution_count": null, "id": "337d5dfc-0181-4e3b-8ab9-e78e0c3f657b", "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(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": "010ba7ae-7b74-44fc-b1b0-d21860588093", "metadata": {}, "outputs": [], "source": [ "# Set base url\n", "\n", "ANTHROPIC_BASE_URL = \"https://api.anthropic.com/v1/\"\n", "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"" ] }, { "cell_type": "code", "execution_count": null, "id": "22586021-1795-4929-8079-63f5bb4edd4c", "metadata": {}, "outputs": [], "source": [ "# Connect to OpenAI, Anthropic and Google; comment out the Claude or Google lines if you're not using them\n", "\n", "openai = OpenAI()\n", "\n", "claude = OpenAI(base_url=ANTHROPIC_BASE_URL, api_key=anthropic_api_key)\n", "\n", "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)" ] }, { "cell_type": "code", "execution_count": null, "id": "e3895dde-3d02-4807-9e86-5a3eb48c5260", "metadata": {}, "outputs": [], "source": [ "# Set models\n", "\n", "gpt_model = \"gpt-4.1-mini\"\n", "claude_model = \"claude-3-5-haiku-latest\"\n", "gemini_model = \"gemini-2.0-flash\"" ] }, { "cell_type": "code", "execution_count": null, "id": "af9a3262-e626-4e4b-80b0-aca152405e63", "metadata": {}, "outputs": [], "source": [ "system_message = \"You are a helpful assistant that responds in markdown\"" ] }, { "cell_type": "code", "execution_count": null, "id": "88c04ebf-0671-4fea-95c9-bc1565d4bb4f", "metadata": {}, "outputs": [], "source": [ "def stream_gpt(prompt):\n", " messages = [\n", " {\"role\": \"system\", \"content\": system_message},\n", " {\"role\": \"user\", \"content\": prompt}\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": null, "id": "901256fd-675c-432d-bd6e-49ab8dade125", "metadata": {}, "outputs": [], "source": [ "def stream_claude(prompt):\n", " messages = [\n", " {\"role\": \"system\", \"content\": system_message},\n", " {\"role\": \"user\", \"content\": prompt}\n", " ]\n", " stream = claude.chat.completions.create(\n", " model=claude_model,\n", " messages=messages,\n", " max_tokens=1000,\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": null, "id": "6d7e0d48-6140-484c-81aa-2f6aa6da8f25", "metadata": {}, "outputs": [], "source": [ "def stream_gemini(prompt):\n", " messages = [\n", " {\"role\": \"system\", \"content\": system_message},\n", " {\"role\": \"user\", \"content\": prompt}\n", " ]\n", " stream = gemini.chat.completions.create(\n", " model=gemini_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": null, "id": "0087623a-4e31-470b-b2e6-d8d16fc7bcf5", "metadata": {}, "outputs": [], "source": [ "def stream_model(prompt, model):\n", " if model==\"GPT\":\n", " result = stream_gpt(prompt)\n", " elif model==\"Claude\":\n", " result = stream_claude(prompt)\n", " elif model==\"Gemini\":\n", " result = stream_gemini(prompt)\n", " else:\n", " raise ValueError(\"Unknown model\")\n", " yield from result" ] }, { "cell_type": "code", "execution_count": null, "id": "8d8ce810-997c-4b6a-bc4f-1fc847ac8855", "metadata": {}, "outputs": [], "source": [ "view = gr.Interface(\n", " fn=stream_model,\n", " inputs=[gr.Textbox(label=\"Your message:\"), gr.Dropdown([\"GPT\", \"Claude\", \"Gemini\"], label=\"Select model\", value=\"GPT\")],\n", " outputs=[gr.Markdown(label=\"Response:\")],\n", " flagging_mode=\"never\"\n", ")\n", "view.launch()" ] }, { "cell_type": "markdown", "id": "d933865b-654c-4b92-aa45-cf389f1eda3d", "metadata": {}, "source": [ "# Building a company brochure generator\n", "\n", "Now you know how - it's simple!" ] }, { "cell_type": "code", "execution_count": null, "id": "1626eb2e-eee8-4183-bda5-1591b58ae3cf", "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", " 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", " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n", " irrelevant.decompose()\n", " self.text = soup.body.get_text(separator=\"\\n\", strip=True)\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": null, "id": "c701ec17-ecd5-4000-9f68-34634c8ed49d", "metadata": {}, "outputs": [], "source": [ "# With massive thanks to Bill G. who noticed that a prior version of this had a bug! Now fixed.\n", "\n", "base_system_message = \"You are an assistant that analyzes the contents of a company website landing page \\\n", "and creates a short brochure about the company for prospective customers, investors and recruits. Respond in markdown.\"\n", "system_message = base_system_message" ] }, { "cell_type": "code", "execution_count": null, "id": "11e9debb-9500-4783-a72e-fc3659214a8e", "metadata": {}, "outputs": [], "source": [ "def system_personality(personality) -> str:\n", " match personality:\n", " case \"Hostile\":\n", " return base_system_message + \" Use a critical and sarcastic tone that highlights flaws, inconsistencies, or poor design choices in the company's website.\"\n", " case \"Formal\":\n", " return base_system_message + \" Use a professional and respectful tone, with precise language and a structured presentation that inspires trust.\"\n", " case \"Funny\":\n", " return base_system_message + \" Use a lighthearted and humorous tone, incorporating playful language, witty remarks and engaging expressions.\"\n", " case _:\n", " return base_system_message" ] }, { "cell_type": "code", "execution_count": null, "id": "5def90e0-4343-4f58-9d4a-0e36e445efa4", "metadata": {}, "outputs": [], "source": [ "def stream_brochure(company_name, url, model, personality):\n", " yield \"\"\n", " prompt = f\"Please generate a company brochure for {company_name}. Here is their landing page:\\n\"\n", " prompt += Website(url).get_contents()\n", " global system_message\n", " system_message = system_personality(personality)\n", " if model==\"GPT\":\n", " result = stream_gpt(prompt)\n", " elif model==\"Claude\":\n", " result = stream_claude(prompt)\n", " elif model==\"Gemini\":\n", " result = stream_gemini(prompt)\n", " else:\n", " raise ValueError(\"Unknown model\")\n", " yield from result" ] }, { "cell_type": "code", "execution_count": null, "id": "66399365-5d67-4984-9d47-93ed26c0bd3d", "metadata": {}, "outputs": [], "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.Dropdown([\"GPT\", \"Claude\", \"Gemini\"], label=\"Select model\"),\n", " gr.Dropdown([\"Funny\",\"Formal\", \"Hostile\"], label=\"Select a personality\")],\n", " outputs=[gr.Markdown(label=\"Brochure:\")],\n", " flagging_mode=\"never\"\n", ")\n", "view.launch()" ] } ], "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.13" } }, "nbformat": 4, "nbformat_minor": 5 }