diff --git a/week1/community-contributions/day2_grocery_list_generator_with_recipe_scaler.ipynb b/week1/community-contributions/day2_grocery_list_generator_with_recipe_scaler.ipynb new file mode 100644 index 0000000..8b2e731 --- /dev/null +++ b/week1/community-contributions/day2_grocery_list_generator_with_recipe_scaler.ipynb @@ -0,0 +1,266 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "0", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "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" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv()\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!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's just make sure the model is loaded\n", + "!ollama pull llama3.2\n", + "import ollama\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# System prompt - defines the AI's behavior\n", + "SYSTEM_PROMPT = \"\"\"You are a helpful cooking assistant that provides ingredient lists for recipes.\n", + "Format your response as clean markdown with this structure:\n", + "\n", + "# [Dish Name]\n", + "**Serves:** [number] people \n", + "**Cook Time:** [estimated time]\n", + "\n", + "## Shopping List\n", + "- [ ] [amount] [unit] [ingredient]\n", + "- [ ] [amount] [unit] [ingredient]\n", + "\n", + "Guidelines:\n", + "- Use common grocery store measurements (cups, lbs, oz, pieces, cans, etc.)\n", + "- Round to practical shopping amounts (1.5 lbs instead of 1.47 lbs)\n", + "- Group similar items when logical (all spices together)\n", + "- Include pantry staples only if they're essential (salt, oil, etc.)\n", + "- Assume basic seasonings are available unless recipe-specific\n", + "- For produce, specify size when important (large onion, medium tomatoes)\n", + "- Keep optional items at the end of similar item groups or end of the list\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_recipe_openai(dish_name: str, num_people: int):\n", + " \"\"\"Get scaled recipe ingredients using system and user prompts\"\"\"\n", + "\n", + " user_prompt = f\"Give me the ingredients needed to make {dish_name} for {num_people} people.\"\n", + " \n", + " try:\n", + " response = openai.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ],\n", + " max_tokens=400\n", + " )\n", + " \n", + " return response.choices[0].message.content\n", + " \n", + " except Exception as e:\n", + " return f\"āŒ Error: Failed to get recipe - {str(e)}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "OLLAMA_MODEL = \"llama3.2\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "metadata": {}, + "outputs": [], + "source": [ + "def get_recipe_ollama(dish_name: str, num_people: int):\n", + " \"\"\"Get recipe using Ollama API\"\"\"\n", + " user_prompt = f\"Give me the ingredients needed to make {dish_name} for {num_people} people.\"\n", + " \n", + " messages = [\n", + " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ]\n", + " \n", + " try:\n", + " response = ollama.chat(model=OLLAMA_MODEL, messages=messages)\n", + " return response['message']['content']\n", + " except Exception as e:\n", + " return f\"āŒ Ollama Error: {str(e)}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def print_shopping_list(recipe_markdown):\n", + " \"\"\"Print the markdown response\"\"\"\n", + " display(Markdown(recipe_markdown))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "print(\"šŸ³ Recipe Scaler & Grocery List Maker\")\n", + "print(\"=\" * 40)\n", + " \n", + "ai_service_choice = input(\"\\nChoose AI service (1 for OpenAI, 2 for Ollama): \").strip()\n", + "\n", + "dish = input(\"What dish do you want to make? \")\n", + "num_people = int(input(\"How many people? \"))\n", + " \n", + "print(f\"\\nšŸ” Getting recipe for {dish}...\")\n", + " \n", + "# Get and display recipe\n", + "if ai_service_choice == '1':\n", + " print(\"Using OpenAI API...\")\n", + " recipe_markdown = get_recipe_openai(dish, num_people)\n", + "else:\n", + " print(\"Using Ollama (local)...\")\n", + " recipe_markdown = get_recipe_ollama(dish, num_people)\n", + "\n", + "print_shopping_list(recipe_markdown)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}