{ "cells": [ { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reading settings from ../../env/ai.json\n" ] } ], "source": [ "import os\n", "import json\n", "\n", "pathToSettings = '../../env/ai.json'\n", "if os.path.exists(pathToSettings):\n", " # Load setting from Json outside of project.\n", " print(f'Reading settings from {pathToSettings}')\n", " f = open(pathToSettings)\n", " settingsJson = json.load(f)\n", " del f\n", "\n", " for key in settingsJson:\n", " os.environ[key] = settingsJson[key]\n", " \n", " del settingsJson" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Setup Web Crawler and Lookup functions" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [], "source": [ "import requests\n", "from bs4 import BeautifulSoup\n", "import json\n", "import re \n", "\n", "pageCache = {}\n", "\n", "def json_safe_loads(jsonString):\n", " try:\n", " obj = json.loads(jsonString)\n", " except ValueError as e:\n", " return None\n", " return obj\n", "\n", "def remove_keys(dictionary: dict, keyList: list):\n", " for key in keyList: \n", " if key in dictionary:\n", " del dictionary[key] \n", "\n", "def get_recipe_as_json(url: str) -> dict: \n", " \n", " urlArray = re.findall(r'(https?://\\S+)', url)\n", " if len(urlArray) == 0: \n", " return {'error': 'Invalid url format, please try again using a fully qualified URL', 'url': url }\n", " \n", " url = urlArray[0]\n", " url = url.replace(\"'\", \"\").replace('\"', '')\n", " print()\n", " print(f'url: {url}') \n", " \n", " if url in pageCache:\n", " return pageCache[url] \n", "\n", " html = requests.get(url).text\n", " \n", " soup = BeautifulSoup(html)\n", " script = soup.find_all(\"script\", {\"id\": \"allrecipes-schema_1-0\"})\n", "\n", " if len(script) == 0: \n", " return \"No recipe found.\"\n", " \n", " recipeDict = json.loads(script[0].text)[0]\n", " print(type(recipeDict))\n", " print(recipeDict)\n", " remove_keys(recipeDict, ['review', 'image', 'mainEntityOfPage', 'publisher'])\n", " \n", " pageCache[url] = recipeDict\n", " \n", " return recipeDict\n", "\n", "# url = \"https://www.allrecipes.com/recipe/212498/easy-chicken-and-broccoli-alfredo/\"\n", "# obj = get_recipe_as_json(url)\n", "#x = get_recipe_as_json('{ \"url\": \"https://www.allrecipes.com/recipe/235153/easy-baked-chicken-thighs/\" }')\n", "# x = get_recipe_as_json('https://www.allrecipes.com/recipe/228363/crispy-roasted-chicken/')\n", "# print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Static recipe lists" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [], "source": [ "dessertList = [\n", "\"https://www.allrecipes.com/chocolate-snack-cake-recipe-8350343\",\n", "\"https://www.allrecipes.com/charred-spiced-pears-with-smoky-vanilla-cherry-sauce-recipe-8347080\",\n", "\"https://www.allrecipes.com/meringue-topped-banana-pudding-recipe-8347040\",\n", "\"https://www.allrecipes.com/white-chocolate-cinnamon-toast-crunch-bars-recipe-7556790\",\n", "\"https://www.allrecipes.com/plum-cobbler-for-two-recipe-8304143\",\n", "\"https://www.allrecipes.com/pumpkin-cheesecake-cookies-recipe-7972485\",\n", "\"https://www.allrecipes.com/chocolate-whipped-cottage-cheese-recipe-8303272\",\n", "\"https://www.allrecipes.com/nutella-ice-cream-recipe-7508716\",\n", "\"https://www.allrecipes.com/3-ingredient-banana-oatmeal-cookies-recipe-7972686\",\n", "\"https://www.allrecipes.com/caramel-apple-pie-cookies-recipe-7642173\"\n", "]\n", "\n", "chickenDishList = [\n", "\"https://www.allrecipes.com/recipe/228363/crispy-roasted-chicken/\",\n", "\"https://www.allrecipes.com/recipe/254877/roasted-spatchcocked-chicken-with-potatoes/\",\n", "\"https://www.allrecipes.com/recipe/235153/easy-baked-chicken-thighs/\",\n", "\"https://www.allrecipes.com/recipe/258878/crispy-baked-chicken-thighs/\",\n", "\"https://www.allrecipes.com/recipe/235151/crispy-and-tender-baked-chicken-thighs/\",\n", "\"https://www.allrecipes.com/recipe/233953/million-dollar-chicken/\",\n", "\"https://www.allrecipes.com/recipe/70679/simple-whole-roasted-chicken/\",\n", "\"https://www.allrecipes.com/recipe/214618/beer-can-chicken/\",\n", "\"https://www.allrecipes.com/recipe/272858/air-fryer-chicken-thighs/\",\n", "\"https://www.allrecipes.com/recipe/214478/happy-roast-chicken/\"\n", "]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Setup Tools" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [], "source": [ "# Tools \n", "from langchain.agents import Tool\n", "\n", "\n", "# Chicken functions\n", "def list_chicken_recipes(query: str): \n", " return chickenDishList\n", "\n", "list_chicken_recipes_tool = Tool(name='Chicken Recipes tool', func= list_chicken_recipes, \n", " description=\"\"\"\n", " This tools lists the available Chicken Recipes. \n", " Only call this tool to fetch Chicken recipes. \n", " \"\"\")\n", "\n", "# Dessert functions\n", "def list_dessert_recipes(query: str): \n", " return dessertList\n", "\n", "list_dessert_recipes_tool = Tool(name='Dessert Recipes tool', func=list_dessert_recipes, \n", "description=\"\"\" \n", " This tools lists the available Dessert Recipes.\n", " Only call this tool for fetching Dessert Recipes.\n", " \"\"\")\n", "\n", "# Recipe fetcher functions\n", "def get_recipe(fully_qualified_url: str): \n", " return get_recipe_as_json(fully_qualified_url)\n", "\n", "get_recipe_as_json_tool = Tool(name='Get a Recipe tool', func=get_recipe, description=\"\"\"\n", " Useful for fetching a particular recipe by passing in a fully qualified url. \n", " It is important that the parameter to pass in must be a fully qualified url and nothing else. \n", " Don't call this function unless you have fetched a url from one of the other Tools first.\n", " Parameter: \n", " url (str): A fully qualified URL, including the scheme (e.g., \"https://\").\n", " The tool uses the https://schema.org/Recipe format to store it's recipes. \n", " \"\"\")\n", "\n", "# Tool list\n", "#tools = [list_chicken_recipes_tool, list_dessert_recipes_tool, get_recipe_as_json_tool]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# LLM\n", "Links\n", "\n", "\n", "1 [tracking-inspecting-prompts-langchain-agents-weights-and-biases](https://kleiber.me/blog/2023/05/14/tracking-inspecting-prompts-langchain-agents-weights-and-biases/)" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [], "source": [ "from langchain.agents import load_tools\n", "from langchain.agents import initialize_agent\n", "from langchain.llms import OpenAI\n", "from langchain.chat_models import ChatOpenAI\n", "from langchain.load.dump import dumps\n", "\n", "def ask_query(model, apiKey, query, accessList):\n", " \n", " if len(apiKey) > 0:\n", " os.environ['OPENAI_API_KEY'] = apiKey\n", " \n", " #tools = [list_chicken_recipes_tool, list_dessert_recipes_tool, get_recipe_as_json_tool]\n", " if len(accessList) == 0:\n", " return \"Please select at least one recipe list from the Access List\"\n", " \n", " tools = [get_recipe_as_json_tool]\n", " if \"Chicken recipes\" in accessList:\n", " tools.append(list_chicken_recipes_tool)\n", " \n", " if \"Desert recipes\" in accessList:\n", " tools.append(list_dessert_recipes_tool)\n", " \n", " print('Chicken recipes selected:')\n", " accessListMsg = ''\n", " for i in accessList: \n", " print(i)\n", " accessListMsg += f'{i},'\n", " \n", " print(query)\n", " print(model)\n", " \n", " # LLM \n", " llm = ChatOpenAI(temperature=0.2, model_name=model) # 'gpt-3.5-turbo' # gpt-4\n", " agent = initialize_agent( \n", " agent=\"zero-shot-react-description\", tools=tools, llm=llm, verbose=True, \n", " max_iterations=7, return_intermediate_steps=True, \n", " handle_parsing_errors=\"Check your output and make sure it conforms.\")\n", " system = \"\"\"\n", " If the answer is not in the tools or context passed to you then don't answer. \\n\n", " If you don't know the answer then say so. \\n \n", " \"\"\" \n", " \n", " response = agent({\"input\": f\"{system} [[RECIPENAME]] {query}\"})\n", "\n", " # Show response \n", " stepsDict = json.loads(dumps(response[\"intermediate_steps\"], pretty=True))\n", " resp = 'Below are the steps the agent took to get to the Final Answer. \\n\"Thought\" is the LLMs internal dialogue, \\n\"Action\" is the tool it will use to fetch the next piece of information. \\n\"Action Input\" is the input it passes the tool to fetch this information. \\n\"Action Response\" is what was returned from the tool to the LLM at that given step.' \n", " resp += '\\n\\n'\n", " resp += 'Steps to solve answer using ReAct\\n'\n", " resp += 'You have access to the following recipe lists: \\n' + accessListMsg\n", " resp += '\\n'\n", " for i in range(len(stepsDict)):\n", " resp += '##########################################\\n'\n", " resp += f'Step: {i+1} of {len(stepsDict)}\\n'\n", " resp += f\"Thought: {stepsDict[i][0]['kwargs']['log']}\\n\"\n", " resp += 'Below is what the tool returned...\\n'\n", " resp += f\"Action response: {stepsDict[i][1]}\\n\" \n", " resp += '\\n'\n", "\n", " resp += '\\nFinal Thought:\\n'\n", " resp += response['output']\n", " return resp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# UI - Simple UI" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Running on local URL: http://127.0.0.1:7906\n", "\n", "To create a public link, set `share=True` in `launch()`.\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "