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 +} diff --git a/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb b/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb index 7824df8..130de91 100644 --- a/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb +++ b/week1/community-contributions/week1 EXERCISE_AI_techician.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5", + "id": "0", "metadata": {}, "source": [ "# End of week 1 exercise\n", @@ -13,22 +13,30 @@ }, { "cell_type": "code", - "execution_count": 9, - "id": "c1070317-3ed9-4659-abe3-828943230e03", + "execution_count": null, + "id": "1", "metadata": {}, "outputs": [], "source": [ "# imports\n", "from IPython.display import Markdown, display, update_display\n", + "from dotenv import load_dotenv\n", + "import os\n", "import openai\n", "from openai import OpenAI\n" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "4a456906-915a-4bfd-bb9d-57e505c5093f", - "metadata": {}, + "execution_count": null, + "id": "2", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ "# constants\n", @@ -37,6 +45,9 @@ " 'MODEL_LLAMA': 'llama3.2'\n", "}\n", "\n", + "load_dotenv(override=True)\n", + "api_key = os.getenv(\"OPENAI_API_KEY\")\n", + "\n", "# To use ollama using openai API (ensure that ollama is running on localhost)\n", "ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n", "\n", @@ -57,9 +68,15 @@ }, { "cell_type": "code", - "execution_count": 12, - "id": "a8d7923c-5f28-4c30-8556-342d7c8497c1", - "metadata": {}, + "execution_count": null, + "id": "3", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ "# set up environment\n", @@ -89,8 +106,8 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "3f0d0137-52b0-47a8-81a8-11a90a010798", + "execution_count": null, + "id": "4", "metadata": {}, "outputs": [], "source": [ @@ -105,67 +122,9 @@ { "cell_type": "code", "execution_count": null, - "id": "60ce7000-a4a5-4cce-a261-e75ef45063b4", + "id": "5", "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "**Understanding the Code Snippet**\n", - "\n", - "This Python code snippet uses a combination of built-in functions, dictionary iteration, and generator expressions to extract and yield author names from a list of `Book` objects.\n", - "\n", - "Here's a breakdown:\n", - "\n", - "1. **Dictionary Iteration**: The expression `for book in books if book.get(\"author\")`\n", - " - Iterates over each element (`book`) in the container `books`.\n", - " - Filters out elements whose `'author'` key does not have a value (i.e., `None`, `False`, or an empty string). This leaves only dictionaries with author information.\n", - "\n", - "2. **Dictionary Access**: The expression `{book.get(\"author\") for book in books if book.get(\"author\")}`\n", - " - Uses dictionary membership testing to access only the values associated with the `'author'` key.\n", - " - If the value is not found or is considered false, it's skipped in this particular case.\n", - "\n", - "3. **Generator Expression**: This generates an iterator that iterates over the filtered author names.\n", - " - Yields each author name (i.e., a single `'name'` from the book dictionary) on demand.\n", - " - Since these are generator expressions, they use memory less than equivalent Python lists and also create results on-demand.\n", - "\n", - "4. **`yield from`**: This statement takes the generator expression as an argument and uses it to generate a nested iterator structure.\n", - " - It essentially \"decompresses\" the single level of nested iterator created by `list(iter(x))`, allowing for simpler use cases and potentially significant efficiency improvements for more complex structures where every value must be iterated, while in the latter case just the first item per iterable in the outer expression's sequence needs to actually be yielded into result stream.\n", - " - By \"yielding\" a nested iterator (the generator expression), we can simplify code by avoiding repetitive structure like `for book, book_author in zip(iterating over), ...` or list creation.\n", - "\n", - "**Example Use Case**\n", - "\n", - "In this hypothetical example:\n", - "\n", - "# Example Book objects\n", - "class Book:\n", - " def __init__(self, author, title):\n", - " self.author = author # str\n", - " self.title = title\n", - "\n", - "books = [\n", - " {\"author\": \"John Doe\", \"title\": f\"Book 1 by John Doe\"},\n", - " {\"author\": None, \"title\": f\"Book 2 without Author\"},\n", - " {\"author\": \"Jane Smith\", \"title\": f\"Book 3 by Jane Smith\"}\n", - "]\n", - "\n", - "# The given expression to extract and yield author names\n", - "for author in yield from {book.get(\"author\") for book in books if book.get(\"author\")}:\n", - "\n", - " print(author) \n", - "\n", - "In this code snippet, printing the extracted authors would output `John Doe`, `Jane Smith` (since only dictionaries with author information pass the filtering test).\n", - "\n", - "Please modify it like as you wish and use `yield from` along with dictionary iteration, list comprehension or generator expression if needed, and explain what purpose your version has." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Get the model of your choice (choices appeared below) to answer, with streaming \n", "\n", @@ -174,13 +133,21 @@ " 'MODEL_LLAMA': 'llama3.2'\n", "}\"\"\"\n", "\n", - "stream_brochure(question,'MODEL_LLAMA')" + "stream_brochure(question,'MODEL_GPT')" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "llms", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -194,7 +161,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.13" } }, "nbformat": 4, diff --git a/week1/community-contributions/week1-jedi-master.py b/week1/community-contributions/week1-jedi-master.py new file mode 100644 index 0000000..c59dc32 --- /dev/null +++ b/week1/community-contributions/week1-jedi-master.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 + +import os +import argparse +from dotenv import load_dotenv +from openai import OpenAI +from IPython.display import Markdown, display, update_display + +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 wise Jedi Master and an excellent teacher. + You will answer any question you are given by breaking it down into small steps + that even a complete beginner will understand. + When answering, speak as if you are Yoda from the Star Wars universe. + Also, refer to the user as "My young Padawan" + End every answer with "May the force be with you, always." + """ + 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="JedAI Master instructor") + 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("question", help="What knowledge do you seek, my young Padawan?") + + 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.question + + result = ask_llm(client, model, user_prompt) + print("AI Response:", result) + +if __name__ == "__main__": + main() diff --git a/week3/community-contributions/06_meeting_minute_assistant.ipynb b/week3/community-contributions/06_meeting_minute_assistant.ipynb new file mode 100644 index 0000000..ac2fbc0 --- /dev/null +++ b/week3/community-contributions/06_meeting_minute_assistant.ipynb @@ -0,0 +1,450 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "HFOR8SGHPyj3" + }, + "source": [ + "# Meeting Minutes Generator (STT with LLMs)\n", + "---\n", + "\n", + "- 🌍 Task: Generate structured meeting minutes from audio recordings using Speech-to-Text (STT) and Large Language Models\n", + "- 🧠 Models:\n", + " - AUDIO_MODEL: whisper1\n", + " - LLM_MODEL: meta-llama/Meta-Llama-3.1-8B-Instruct\n", + "- 🚀 Tools: Python, Gradio UI, OpenAI / HuggingFace APIs\n", + "- 📤 Output: Structured meeting minutes in Markdown format with real-time streaming\n", + "- 🧑‍💻 Skill Level: Intermediate\n", + "\n", + "🎯 How It Works\n", + "- 1️⃣ Upload a .mp3 meeting recording\n", + "- 2️⃣ Submit the audio to generate meeting minutes in text format\n", + "\n", + "You can download some meetings from this link to test the code:\n", + "[https://www.rmofspringfield.ca/p/meeting-audio-files](https://www.rmofspringfield.ca/p/meeting-audio-files)\n", + "\n", + "\n", + "🛠️ Requirements\n", + "- ⚙️ Hardware: ✅ GPU required (model download); Google Colab recommended (T4)\n", + "- 🔑 OpenAI API Key (used for whisper1 transcription)\n", + "- 🔑 Hugging Face Token (for the LLM model)\n", + "\n", + "⚙️ Customizable by user\n", + "- 🤖 Selected model: AUDIO_MODEL / LLM_MODEL\n", + "- 📜 system_prompt: Controls model behavior (concise, accurate, structured output)\n", + "- 💬 user_prompt\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "A_osPeBQNAdv", + "outputId": "11cc73e0-9aad-4f57-e1ae-2d71c4eb0444" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q requests torch bitsandbytes transformers sentencepiece accelerate openai httpx==0.27.2 gradio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pL-8yTOlQiOH" + }, + "outputs": [], + "source": [ + "# imports\n", + "import torch\n", + "import threading\n", + "from openai import OpenAI\n", + "from huggingface_hub import login\n", + "from google.colab import userdata\n", + "from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer, BitsAndBytesConfig\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Constants\n", + "AUDIO_MODEL = \"whisper-1\" # OpenAI Whisper API model\n", + "LLM_MODEL = \"meta-llama/Meta-Llama-3.1-8B-Instruct\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "62c2Wbt3P5Ew" + }, + "outputs": [], + "source": [ + "# Google Colab User Data\n", + "# Ensure you have set the following in your Google Colab environment:\n", + "hf_token = userdata.get('HF_TOKEN')\n", + "openai_api_key = userdata.get('OPENAI_API_KEY')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "login(hf_token, add_to_git_credential=True)\n", + "openai = OpenAI(api_key=openai_api_key)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "smyocqu_P6yg" + }, + "outputs": [], + "source": [ + "class MeetingAssistant:\n", + " def __init__(self, model_name=LLM_MODEL, audio_model=AUDIO_MODEL):\n", + "\n", + " # Load tokenizer and llm model\n", + " quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + " )\n", + "\n", + " self.audio_model = audio_model\n", + " self.tokenizer = AutoTokenizer.from_pretrained(model_name)\n", + " self.model = AutoModelForCausalLM.from_pretrained(\n", + " model_name,\n", + " device_map=\"auto\",\n", + " quantization_config=quant_config\n", + " )\n", + "\n", + " def transcribe_audio(self, audio_path, progress):\n", + " \"\"\"Transcribes the uploaded audio file using OpenAI Whisper API.\"\"\"\n", + "\n", + " progress(0.3, desc=\"Transcribing audio...\")\n", + "\n", + " try:\n", + " with open(audio_path, \"rb\") as audio_file:\n", + " transcription = openai.audio.transcriptions.create(\n", + " model=self.audio_model,\n", + " file=audio_file,\n", + " response_format=\"text\"\n", + " )\n", + " return transcription\n", + " except Exception as e:\n", + " return f\"Error during transcription: {str(e)}\"\n", + "\n", + " def generate_minutes(self, transcription, progress):\n", + " \"\"\"Generates meeting minutes from the transcript using the Llama model.\"\"\"\n", + " progress(0.6, desc=\"Generating meeting minutes...\")\n", + "\n", + " 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.\"\n", + " user_prompt = f\"Below is an extract transcript of a meeting. Please write minutes in markdown, including a summary with attendees, location and date; discussion points; takeaways; and action items with owners.\\n{transcription}\"\n", + "\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ]\n", + "\n", + " inputs = self.tokenizer.apply_chat_template(messages, return_tensors=\"pt\").to(\"cuda\")\n", + " streamer = TextIteratorStreamer(self.tokenizer)\n", + "\n", + " thread = threading.Thread(\n", + " target=self.model.generate, kwargs={\n", + " \"input_ids\": inputs,\n", + " \"max_new_tokens\": 2000,\n", + " \"streamer\": streamer\n", + " })\n", + " thread.start()\n", + "\n", + "\n", + " started = False\n", + " # buffer = \"\"\n", + " for new_text in streamer:\n", + " if not started:\n", + " if \"<|start_header_id|>assistant<|end_header_id|>\" in new_text:\n", + " started = True\n", + " new_text = new_text.split(\"<|start_header_id|>assistant<|end_header_id|>\")[-1].strip()\n", + "\n", + " if started:\n", + " if \"<|eot_id|>\" in new_text:\n", + " new_text = new_text.replace(\"<|eot_id|>\", \"\") # Remove the unwanted token\n", + "\n", + " if new_text.strip(): # Only yield non-empty chunks\n", + " yield new_text\n", + "\n", + " def process_meeting(self, audio_file, progress):\n", + " \"\"\"Handles the complete process: transcribes audio and generates minutes.\"\"\"\n", + " progress(0.1, desc=\"Processing audio file...\")\n", + "\n", + " # Check if a file is uploaded\n", + " if audio_file is None:\n", + " return \"Please upload an audio file.\"\n", + "\n", + " try:\n", + " # Check file format\n", + " if not str(audio_file).lower().endswith('.mp3'):\n", + " return \"Please upload an MP3 file.\"\n", + "\n", + " # Get transcription\n", + " transcription = self.transcribe_audio(audio_file, progress)\n", + "\n", + " # Generate minutes\n", + " accumulated_text = \"\"\n", + " minutes = self.generate_minutes(transcription, progress)\n", + " for chunk in minutes:\n", + " accumulated_text += chunk # Append new text\n", + " yield accumulated_text # Update Gradio output with full text\n", + "\n", + " except Exception as e:\n", + " return f\"Error processing file: {str(e)}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fyMu9JrBRBGI" + }, + "outputs": [], + "source": [ + "class GradioInterface:\n", + " def __init__(self):\n", + " \"\"\"Initializes the Gradio interface for processing audio files.\"\"\"\n", + " self.assistant = MeetingAssistant()\n", + " self.iface = gr.Interface(\n", + " fn=self.process_audio,\n", + " inputs=gr.Audio(type=\"filepath\", label=\"Upload MP3 File\", format=\"mp3\"),\n", + " outputs=gr.Markdown(label=\"Meeting Minutes\", min_height=60),\n", + " title=\"AI Meeting Assistant\",\n", + " description=\"Upload an audio file to transcribe and generate meeting minutes.\",\n", + " flagging_mode=\"never\"\n", + " )\n", + "\n", + " def process_audio(self, audio_file, progress=gr.Progress()): # Adapter between the UI and the backend.\n", + " \"\"\"Handles user input from Gradio, processes the audio, and returns meeting minutes.\"\"\"\n", + " response = self.assistant.process_meeting(audio_file, progress)\n", + " for chunk in response:\n", + " yield chunk\n", + "\n", + " def launch(self):\n", + " \"\"\"Launches the Gradio interface.\"\"\"\n", + " self.iface.launch()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000, + "referenced_widgets": [ + "0f705a9046d34fb0a7ab8177a6521b88", + "28e61ba2b56f4d3484dd3ec0eecb12aa", + "ecb3207e61d44ca39c7f8a97546c6686", + "5a4f5291a0b24178a44b1b3c2401a957", + "2472dbee01b149c0ac7efe6eaa5ffd66", + "65c6998bdf7444de85b37468f6b6f42e", + "4323c3fbb5d24b38a920313479bb5c57", + "8af3f0faa5b144efbf1aa443c2839d2c", + "e0f3096904354279a95175d116816262", + "0e6ad8796e9e4b868c8507722c9cbf33", + "a32fde87feaf42199de6efe2c94085aa", + "e6c97a25f41044ab89e49d9bf9836de4", + "78562aef2a6a422dba1145306b294823", + "980453816461473fab04be9b6fbf03b5", + "39ce806000744113ae35a617adfe2571", + "2991097320c148b7b0eb81e3ce866df2", + "1a502c41fc3044c2a7c24ad144c209e9", + "91a907a6aa044a3288cbf4deca77eb67", + "7f78522bd56847bfa740ff8146e726d2", + "eb2129af41b24e2ea64a962cb041164c", + "44bdcc01d31a43eeaa7139018c24a83b", + "a21477f95f604f618a3aa2f48c00f7f3", + "0b97c1be64664458abfc0109857d86eb", + "2d0a0c7b89a64b7499ce87e81044d461", + "19acf6f364d8478ea264dde4fd4a1ca1", + "c084a0f7a7c04c90a0fed54c60cc8e79", + "482baf34221048bd8bb4e57cebe44707", + "f9c94568e6b342dda23ccd3be906eec0", + "c6f719622eae45b0b110b377918c2eb2", + "83e68bf6b3994fd5a6eea4ba722864c3", + "01d3ea10affb447ead36c6b4476e7a4c", + "5f93b389541e4ec09aced45d018bc8c1", + "90b2cfcc49804e78b6bebb383e9e6893", + "6f1e02e1c1da4bd9a6d13b3907cd78ae", + "39ea33000ee741c2b9fdf518f657d872", + "1b6204edaebf489e9d3e70f6d722c33a", + "4ae96d4297b84fd1a9022a9c07f7987e", + "2c43cc66619945a18a82cd9437ea60be", + "9e1dc2cc46fa4a4ea6c5d3a50333a02f", + "7c11259f23a6440babc156ac7d4b94c7", + "48c2c5afef3d47e3b9bada3cdc339ec9", + "a0ca5ccd08df4b9191a6400907f239fa", + "72a5d5d5f42e44f197b5829801fee49c", + "37cefb5abc424fca84d5ec4d7b90ff1f", + "afce35f6ca0545d99937a2fca8030cb0", + "fab983c8f0d544a2950d03acd5c39644", + "f1a00e2402d2498292cbc5b767b1b3a9", + "ca4db027b9764a8180617aae1b215f60", + "d96a8910fbc5451083df650386ce6726", + "5bd8e043fbd64c7c9dfb0d871737786d", + "1ca523532aa5433c91df9cb53291ba29", + "0b5340eb370a490ea946a446a9ab2eaa", + "5f822db8ca764ce4b8dd7b99a83c7286", + "37622f8dcbe14ac5ad80c9b09c8c4005", + "1a73f8a262a94cd48d0370bbfd582405", + "99bfb965add64f609f0ef008c443cdb9", + "f1afbbe6e1fa4239af3d79b42f1ffc26", + "2574026b82a040f089bfd202db5ef91d", + "32bc3c434f824c618659693de6bd929a", + "6d19a5bd166443b1acbf261287be09ac", + "58e73b94784645f699f957693aaf6e6e", + "4e5c99b156c545b096ba538b1a8c588a", + "bde0c4ad4eea4944b76b34ad9c19bb89", + "b9ab6e3935c646e691c0b5143d47d4b3", + "d4a06441bff74e0e9fe8978014660e90", + "a8010eecf9bc4e8ebfc906489ff54543", + "7e9cdfd05f074c1798b8e3d936f6e7de", + "57b3fe293dda483bb3717d7bd3509cce", + "b080c2078a3f4d93b4d8367755d96272", + "a1a7f450bd8d4917b796c6e13a5be9e1", + "e58ff13df5a04fd5b0496e82384fe439", + "ddf5e150f83944bfb07d8f19a177a50a", + "71939dd7929243e38419abec94b209f9", + "fe17e6c350c54a2d85864bb8d6d50d85", + "4a69b6ea437e4682819ed2d0aef048b8", + "99a8e8cb1ad44d5f999c07cf9a913ef4", + "1dd62e85589f4d60912e79dee1b39a3e", + "0a634fec1cf544af82bd17af73bf417a", + "c7e74bf1bb0f4d57ae95aa4397691e01", + "e144ffa2b708446d940bfdf54741c7ab", + "d65f1f5e345546b380c8e9be9d4dfb9b", + "c2e4a8d768d245529bdac929585136c5", + "a4317d864cc4445d8597ed695c3d4c35", + "5429cebc5a28408985824c4f501e050e", + "dc3100a6c9d946568ee0e297934773ff", + "10ecb81d605a4534a13332371ac9041d", + "570b18cdf9034cc780e838724a70904e", + "1915b872ec55435080456092d9ec8717", + "50f682e340cb4e58899aa7e9ea4741db", + "569ec309d2f3490f94c85bbb3680258b", + "dd319b7cb2b7425e849d6682c7f05390", + "fde199a94cc7488690f81d5add9eb08d", + "38d2575bf5144cf3a02d304444bdc481", + "a06cc81bd0114aefb1e80868791b5be8", + "819319dd58b44e999a13b0bd0e78c88e", + "38f581406490488981c76bc7e7e64005", + "2ef62c2bd93c462eb7c4522c8a156e0d", + "c2cb2d57701a4e55b7bfa3f842a91c09", + "4ba3375ddb584f068d2cdcf060cdfa9c", + "125f8ae49e504b809e5e39f6d940204e", + "2c4abe3e713846deb1b0a9bec03298d4", + "b5f524e95a0d42febd4466bb7a8ad239", + "b5b9a98cb74c409cbdc50a16a3393665", + "ec145da746d74c5e896900f7462b630b", + "aa7d2a5d452b4eb1b537542a9731b94a", + "3d03ed01daeb43d58c4f15bc591043ba", + "17b7619e5bfd4d74b1a3bee1c7643e74", + "4c95edb35fab4e12b027248e93b61883", + "7d7bcf713d3b4531846635fe43fb268e", + "918a8b2b832645d18767bc2e4451d556", + "3b8be978c3af4ef4b7bc16420e6a9f8a", + "25efbd99d0134866940cc3fde41aacf7", + "07e8ec9ab2ba4339a8e2736156f28eab", + "7fa4e5411e384c568b37a51bc94b3ee2", + "45fa63f56c814015861d05beb8800e09", + "8a73f7fbe20a4d56a76588db2ac35cea", + "3a18d0771ef74923ba209733afdd0e47", + "9104c3953c254878b2020764569613a9", + "8a237f2467734eddace5d9f9aafce9e7", + "a737c2d22cd84141a2f28721ab69d28d", + "be17f6c8dc9c40efa94c3af82a8efa6a", + "7a74e712b53c4a659dc09766885c12d9", + "9afb4b8b3ddf4a0abb75eedbcf3bc7c1", + "27697007fa6d4736a5eb1e1b0eea2d82", + "e5d4b0e78c3740cd8cf9cda0e4a93972", + "2740d759410d435087c4ae0772d6ad73", + "19f5f9369e3043e0984e160c50e0a32e", + "7b488376756843fe84fcce2e7abb5cd9", + "c2745572ac434351ad9b2c9506d8d0b7", + "25119517d9a043ba91fd3fbefb8377a4", + "4079ed7e7f794755afd5daad3f00a34a", + "14f5761bfbd340198267e3986f4035a0" + ] + }, + "id": "BI91BBEJRB0K", + "outputId": "c4853642-832e-4167-e220-2a2d0fd279a8" + }, + "outputs": [], + "source": [ + "if __name__ == \"__main__\":\n", + " app = GradioInterface()\n", + " app.launch()" + ] + }, + { + "attachments": { + "image-2.png": { + "image/png": "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62Bpvdc7da6r6HrGNbb7L0nZsZd9v89i38Rgzu58gwy6kjRyMEm/6FdrcyIiIiIiIiLSfN3WPjjk38ZCI+sXp4xF15GZ8LBAPMuL2VPqGupLJvtoKEc7JrK5fSj3Vhwh74xLtU8g0S3KXJaxr8d0ytDO7Ed0EHxW6GYmo9mP6AdMfHm4mOPGOqeGlm8Ei38o7TDuG9X95fgRN7NxvYiK8KfyE3d1Bj6BxLap5Nhl9M/iH0rABdfxutR23YxxY8bwEn2sf4waYPYj+gFvzhv72pj+uOMTSKxXOTluZqcGtQ/l/m/r658XURHenG3q9i7Rz/BpWSz13UDC8zuw4kVUzDhmvezH+x0TSYVGHCt3GrdMvcfDXZ/dlV22+vvn9hhc4ryqy495b63A+3cJDN9uA59ABo6bz7SA/QQPSDM2vsoaut4be13Zx4dSl3Y+foRfOOlmnSIiIiIiIiJyo2rd2p7nACAlJaVWnTuLFy+ufn8TBHvrUxPstQe3RG4dI1bu5ResZNhzWzmOmdgp6czqUcZr0VPIMDaWRupPZt5zsCyBxKwKMIcyb80rRFlnEzlhl7GxiIiIiIiIiMg1cSXB3hs4jcOllFHyaWNn7Ik0L6tnLiDPNJi1eXvJfy+Lsf5FLB6sQO+V2cpv576L6RdZFL63l/y3JmM5NpthCvSKiIiIiIiIyE3iJp7ZKyIiIiIiIiIiItK83KIze0VERERERERERETEScFeERERERERERERkWZAwV4RERERERERERGRZkDBXhEREREREREREZFmQMFeERERERERERERkWZAwV4RERERERERERGRZkDBXhEREREREREREZFmQMFeERERERERERERkWZAwV4RERERERERERGRZkDBXhEREREREREREZFmQMFeERERERERERERkWZAwV4RERERERERERGRZkDBXhEREREREREREZFmQMFeERERERERERERkWZAwV4RERERERERERGRZkDBXhEREREREREREZFmQMFeERERERERERERkWbgtvbBIf82FhpZvzhlLLoufhZwPx0f/C/uaeVprBIRERGRW9TX35zn6Mf/w+clXxqrRERERERueq1bW6rfp6Sk1KpzZ/HixdXvb9hg788C7ueR/36Qv331DXff9QPu82llbCI3gK/Kz/GnPxcbi0VERETciuv5CNt3fWAsbpIW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" + }, + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)\n", + "\n", + "![image-2.png](attachment:image-2.png)" + ], + "outputs": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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": 4 +} \ No newline at end of file diff --git a/week3/community-contributions/Week3-Dataset_Generator-DP.ipynb b/week3/community-contributions/Week3-Dataset_Generator-DP.ipynb new file mode 100644 index 0000000..72c1c84 --- /dev/null +++ b/week3/community-contributions/Week3-Dataset_Generator-DP.ipynb @@ -0,0 +1,381 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c08309b8-13f0-45bb-a3ea-7b01f05a7346", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import json\n", + "import pandas as pd\n", + "import random\n", + "import re\n", + "import subprocess\n", + "import pyarrow as pa\n", + "from typing import List\n", + "import openai\n", + "import anthropic\n", + "from dotenv import load_dotenv\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5efd903-e683-4e7f-8747-2998e23a0751", + "metadata": {}, + "outputs": [], + "source": [ + "# load API\n", + "load_dotenv(override=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce49b86a-53f4-4d4f-a721-0d66d9c1b070", + "metadata": {}, + "outputs": [], + "source": [ + "# --- Schema Definition ---\n", + "SCHEMA = [\n", + " (\"Team\", \"TEXT\", '\"Toronto Raptors\"'),\n", + " (\"NAME\", \"TEXT\", '\"Otto Porter Jr.\"'),\n", + " (\"Jersey\", \"TEXT\", '\"10\", or \"NA\" if null'),\n", + " (\"POS\", \"TEXT\", 'One of [\"PF\",\"SF\",\"G\",\"C\",\"SG\",\"F\",\"PG\"]'),\n", + " (\"AGE\", \"INT\", 'integer age in years, e.g., 22'),\n", + " (\"HT\", \"TEXT\", '`6\\' 7\"` or `6\\' 10\"`'),\n", + " (\"WT\", \"TEXT\", '\"232 lbs\"'),\n", + " (\"COLLEGE\", \"TEXT\", '\"Michigan\", or \"--\" if null'),\n", + " (\"SALARY\", \"TEXT\", '\"$9,945,830\", or \"--\" if null')\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93743e57-c2c5-43e5-8fa1-2e242085db07", + "metadata": {}, + "outputs": [], + "source": [ + "# Default schema text for the textbox\n", + "DEFAULT_SCHEMA_TEXT = \"\\n\".join([f\"{i+1}. {col[0]} ({col[1]}) Example: {col[2]}\" for i, col in enumerate(SCHEMA)])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87c58595-6fdd-48f5-a253-ccba352cb385", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "MODELS = [\n", + " \"gpt-4o\",\n", + " \"claude-3-5-haiku-20241022\", \n", + " \"ollama:llama3.2:latest\"\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08cd9ce2-8685-46b5-95d0-811b8025696f", + "metadata": {}, + "outputs": [], + "source": [ + "# Available file formats\n", + "FILE_FORMATS = [\".csv\", \".tsv\", \".jsonl\", \".parquet\", \".arrow\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13d68c7f-6f49-4efa-b075-f1e7db2ab527", + "metadata": {}, + "outputs": [], + "source": [ + "def get_prompt(n: int, schema_text: str, system_prompt: str) -> str:\n", + " prompt = f\"\"\"\n", + "{system_prompt}\n", + "\n", + "Generate {n} rows of realistic basketball player data in JSONL format, each line a JSON object with the following fields:\n", + "\n", + "{schema_text}\n", + "\n", + "Do NOT repeat column values from one row to another.\n", + "\n", + "Only output valid JSONL.\n", + "\"\"\"\n", + " return prompt.strip()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdc68f1e-4fbe-45dc-aa36-ce5f718ef6ca", + "metadata": {}, + "outputs": [], + "source": [ + "# --- LLM Interface ---\n", + "def query_model(prompt: str, model: str = \"gpt-4o\") -> List[dict]:\n", + " \"\"\"Call OpenAI, Claude, or Ollama\"\"\"\n", + " try:\n", + " if model.lower().startswith(\"gpt\"):\n", + " client = openai.OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n", + " response = client.chat.completions.create(\n", + " model=model,\n", + " messages=[{\"role\": \"user\", \"content\": prompt}],\n", + " temperature=0.7\n", + " )\n", + " content = response.choices[0].message.content\n", + "\n", + " elif model.lower().startswith(\"claude\"):\n", + " client = anthropic.Anthropic(api_key=os.getenv(\"ANTHROPIC_API_KEY\"))\n", + " response = client.messages.create(\n", + " model=model,\n", + " messages=[{\"role\": \"user\", \"content\": prompt}],\n", + " max_tokens=4000,\n", + " temperature=0.7\n", + " )\n", + " content = response.content[0].text\n", + "\n", + " elif model.lower().startswith(\"ollama:\"):\n", + " ollama_model = model.split(\":\")[1]\n", + " result = subprocess.run(\n", + " [\"ollama\", \"run\", ollama_model],\n", + " input=prompt,\n", + " text=True,\n", + " capture_output=True\n", + " )\n", + " if result.returncode != 0:\n", + " raise Exception(f\"Ollama error: {result.stderr}\")\n", + " content = result.stdout\n", + " else:\n", + " raise ValueError(\"Unsupported model. Use 'gpt-4.1-mini', 'claude-3-5-haiku-20241022', or 'ollama:llama3.2:latest'\")\n", + "\n", + " # Parse JSONL output\n", + " lines = [line.strip() for line in content.strip().splitlines() if line.strip().startswith(\"{\")]\n", + " return [json.loads(line) for line in lines]\n", + " \n", + " except Exception as e:\n", + " raise Exception(f\"Model query failed: {str(e)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29e3f5f5-e99c-429c-bea9-69d554c58c9c", + "metadata": {}, + "outputs": [], + "source": [ + "# --- Output Formatter ---\n", + "def save_dataset(records: List[dict], file_format: str, filename: str):\n", + " df = pd.DataFrame(records)\n", + " if file_format == \".csv\":\n", + " df.to_csv(filename, index=False)\n", + " elif file_format == \".tsv\":\n", + " df.to_csv(filename, sep=\"\\t\", index=False)\n", + " elif file_format == \".jsonl\":\n", + " with open(filename, \"w\") as f:\n", + " for record in records:\n", + " f.write(json.dumps(record) + \"\\n\")\n", + " elif file_format == \".parquet\":\n", + " df.to_parquet(filename, engine=\"pyarrow\", index=False)\n", + " elif file_format == \".arrow\":\n", + " table = pa.Table.from_pandas(df)\n", + " with pa.OSFile(filename, \"wb\") as sink:\n", + " with pa.ipc.new_file(sink, table.schema) as writer:\n", + " writer.write(table)\n", + " else:\n", + " raise ValueError(\"Unsupported file format\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe258e84-66f4-4fe7-99c0-75b24148e147", + "metadata": {}, + "outputs": [], + "source": [ + "# --- Main Generation Function ---\n", + "def generate_dataset(schema_text, system_prompt, model, nr_records, file_format, save_as):\n", + " try:\n", + " # Validation\n", + " if nr_records <= 10:\n", + " return \"❌ Error: Nr_records must be greater than 10.\", None\n", + " \n", + " if file_format not in FILE_FORMATS:\n", + " return \"❌ Error: Invalid file format specified.\", None\n", + " \n", + " if not save_as or save_as.strip() == \"\":\n", + " save_as = f\"basketball_dataset{file_format}\"\n", + " elif not save_as.endswith(file_format):\n", + " save_as = save_as + file_format\n", + " \n", + " # Generate prompt\n", + " prompt = get_prompt(nr_records, schema_text, system_prompt)\n", + " \n", + " # Query model\n", + " records = query_model(prompt, model=model)\n", + " \n", + " if not records:\n", + " return \"❌ Error: No valid records generated from the model.\", None\n", + " \n", + " # Save dataset\n", + " save_dataset(records, file_format, save_as)\n", + " \n", + " # Create preview\n", + " df = pd.DataFrame(records)\n", + " preview = df.head(10) # Show first 10 rows\n", + " \n", + " success_message = f\"✅ Dataset generated successfully!\\n📁 Saved to: {save_as}\\n📊 Generated {len(records)} records\"\n", + " \n", + " return success_message, preview\n", + " \n", + " except Exception as e:\n", + " return f\"❌ Error: {str(e)}\", None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2405a9d-b4cd-43d9-82f6-ff3512b4541f", + "metadata": {}, + "outputs": [], + "source": [ + "# --- Gradio Interface ---\n", + "def create_interface():\n", + " with gr.Blocks(title=\"Dataset Generator\", theme=gr.themes.Soft()) as interface:\n", + " gr.Markdown(\"# Dataset Generator\")\n", + " gr.Markdown(\"Generate realistic datasets using AI models\")\n", + " \n", + " with gr.Row():\n", + " with gr.Column(scale=2):\n", + " schema_input = gr.Textbox(\n", + " label=\"Schema\",\n", + " value=DEFAULT_SCHEMA_TEXT,\n", + " lines=15,\n", + " placeholder=\"Define your dataset schema here...\"\n", + " )\n", + " \n", + " system_prompt_input = gr.Textbox(\n", + " label=\"Prompt\",\n", + " value=\"You are a helpful assistant that generates realistic basketball player data.\",\n", + " lines=1,\n", + " placeholder=\"Enter system prompt for the model...\"\n", + " )\n", + " \n", + " with gr.Row():\n", + " model_dropdown = gr.Dropdown(\n", + " label=\"Model\",\n", + " choices=MODELS,\n", + " value=MODELS[1], # Default to Claude\n", + " interactive=True\n", + " )\n", + " \n", + " nr_records_input = gr.Number(\n", + " label=\"Nr. records\",\n", + " value=25,\n", + " minimum=11,\n", + " maximum=1000,\n", + " step=1\n", + " )\n", + " \n", + " with gr.Row():\n", + " file_format_dropdown = gr.Dropdown(\n", + " label=\"File format\",\n", + " choices=FILE_FORMATS,\n", + " value=\".csv\",\n", + " interactive=True\n", + " )\n", + " \n", + " save_as_input = gr.Textbox(\n", + " label=\"Save as\",\n", + " value=\"basketball_dataset\",\n", + " placeholder=\"Enter filename (extension will be added automatically)\"\n", + " )\n", + " \n", + " generate_btn = gr.Button(\"🚀 Generate\", variant=\"primary\", size=\"lg\")\n", + " \n", + " with gr.Column(scale=1):\n", + " output_status = gr.Textbox(\n", + " label=\"Status\",\n", + " lines=4,\n", + " interactive=False\n", + " )\n", + " \n", + " output_preview = gr.Dataframe(\n", + " label=\"Preview (First 10 rows)\",\n", + " interactive=False,\n", + " wrap=True\n", + " )\n", + " \n", + " # Connect the generate button\n", + " generate_btn.click(\n", + " fn=generate_dataset,\n", + " inputs=[\n", + " schema_input,\n", + " system_prompt_input, \n", + " model_dropdown,\n", + " nr_records_input,\n", + " file_format_dropdown,\n", + " save_as_input\n", + " ],\n", + " outputs=[output_status, output_preview]\n", + " )\n", + " \n", + " gr.Markdown(\"\"\"\n", + " ### 📝 Instructions:\n", + " 1. **Schema**: Define the structure of your dataset (pre-filled with basketball player schema)\n", + " 2. **Prompt**: System prompt to guide the AI model\n", + " 3. **Model**: Choose between GPT, Claude, or Ollama models\n", + " 4. **Nr. records**: Number of records to generate (minimum 11)\n", + " 5. **File format**: Choose output format (.csv, .tsv, .jsonl, .parquet, .arrow)\n", + " 6. **Save as**: Filename (extension added automatically)\n", + " 7. Click **Generate** to create your dataset\n", + " \n", + " ### 🔧 Requirements:\n", + " - Set up your API keys in `.env` file (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`)\n", + " - For Ollama models, ensure Ollama is installed and running locally\n", + " \"\"\")\n", + " \n", + " return interface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50fd2b91-2578-4224-b9dd-e28caf6a0a85", + "metadata": {}, + "outputs": [], + "source": [ + "interface = create_interface()\n", + "interface.launch(inbrowser=True)" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week3/community-contributions/muawiya/README.md b/week3/community-contributions/muawiya/README.md new file mode 100644 index 0000000..fea9832 --- /dev/null +++ b/week3/community-contributions/muawiya/README.md @@ -0,0 +1,102 @@ +# 🧠 Synthetic Data Generator + +A Python-based tool to generate structured, synthetic job postings using open-source LLMs from Hugging Face. +This project supports both **script-based execution** and an **interactive Colab notebook**, making it ideal for rapid prototyping, dataset bootstrapping, or demonstrating prompt engineering techniques. + +> Note: Original Repo can be found at: https://github.com/moawiah/synthetic_data_generator + + +![Demo Screenshot](https://github.com/user-attachments/assets/c0e229ac-ddb7-4a37-8088-f04ca735cd81) + + +This tool helps: +- Researchers create labeled training data for NLP classification or QA +- HR tech startups prototype recommendation models +- AI instructors demonstrate few-shot prompting in class + + +--- + +## ✨ Features + +- 🔗 Integrates Hugging Face Transformer models +- 📄 Generates realistic job postings in structured JSON format +- 🧪 Supports prompt engineering with control over output length and variability +- 🧠 Minimal Gradio UI for non-technical users +- 📓 Jupyter/Colab support for experimentation and reproducibility + +## 📂 Project Structure +
 ```
+. ├── app/ 
+    │ 
+    ├── app.py # Main script entry point 
+    │ 
+    ├── consts.py # Configuration and constants 
+    │ 
+    └── requirements.txt # Python dependencies 
+  ├── data/ 
+    │ 
+    └── software_engineer_jobs.json # Sample input data (JSON format) 
+  ├── notebooks/ 
+    │ 
+    └── synthetic_data_generator.ipynb # Interactive Colab notebook 
+  ├── .env.example # Sample environment variable config 
+  ├── .gitignore # Git ignored files list 
+  └── README.md
+  ``` 
+ +## 🚀 Getting Started + +### 1. Clone the repository +```bash +git clone https://github.com/moawiah/synthetic_data_generator.git +cd synthetic_data_generator +``` +### Install Dependencies +```bah +pip install -r app/requirements.txt +``` +### Hugging Face Token +You need to create a `.env` file with your HuggingFace token like `HF_TOKEN=your-token-here` + +### Run +run the app using +`python app/app.py` + + +## Example Output - 1 Job + +```JSON +{ +"title": "Software Engineer" +, +"description": "We are seeking a highly skilled software engineer to join our team and contribute to the development of innovative software solutions. The ideal candidate will have experience in designing, coding, and testing software systems, and will be able to work collaboratively with cross-functional teams. Responsibilities include writing clean, maintainable, and efficient code, as well as actively participating in code reviews and continuous integration processes. This is an excellent opportunity for a self-starter with a passion for technology and a desire to grow in their career." +, +"requirements":[ +"0":"Bachelor's degree in Computer Science or related field", +"1":"Minimum of 2 years experience in software development", +"2":"Strong proficiency in Java or C++", +"3":"Experience with agile development methodologies", +"4":"Good understanding of data structures and algorithms", +"5":"Excellent problem-solving and analytical skills" +], +"location":"New York, NY", +"company_name":"ABC Technologies" +} + +``` + + +## Future Improvements +🔁 Add support for more job roles and industries + +🧠 Model selector from UI + +💾 Export dataset as CSV + +☁️ Optional integration with LangChain or RAG workflows + + + + + diff --git a/week3/community-contributions/muawiya/app/app.py b/week3/community-contributions/muawiya/app/app.py new file mode 100644 index 0000000..4b3fc79 --- /dev/null +++ b/week3/community-contributions/muawiya/app/app.py @@ -0,0 +1,156 @@ +import os +import requests +from IPython.display import Markdown, display, update_display +from openai import OpenAI +from google.colab import drive +from huggingface_hub import login +from google.colab import userdata +from transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer, BitsAndBytesConfig, pipeline, TextGenerationPipeline +import torch +from consts import FALCON, MISTRAL, Databricks +from dotenv import load_dotenv +import json +import ast +import gradio as gr +import re + +# Sign in to HuggingFace Hub +load_dotenv() +hf_token = os.getenv("HF_TOKEN") + + +# Main Prompt +prompt = """ +Generate one fake job posting for a {{role}}. + +Return only a single JSON object with: +- title +- description (5-10 sentences) +- requirements (array of 4-6 strings) +- location +- company_name + +No explanations, no extra text. +Only the JSON object. +""" + +# Main Conf +bnb_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_use_double_quant=True, + bnb_4bit_compute_dtype=torch.bfloat16, + bnb_4bit_quant_type="nf4" +) + +def load_model_and_tokenizer(): + tokenizer = AutoTokenizer.from_pretrained(MISTRAL, trust_remote_code=True) + + model = AutoModelForCausalLM.from_pretrained( + MISTRAL, + device_map={"": "cuda"}, + trust_remote_code=True, + offload_folder="/tmp/dolly_offload", + quantization_config=bnb_config + ) + + return model, tokenizer + + +def generate_job(role="Software Engineer", model=None, tokenizer=None): + # prompt = prompt.format(role=role, n=n) + # outputs = generator(prompt, max_new_tokens=500, do_sample=True, temperature=0.9) + # return outputs[0]['generated_text'] + + # Apply chat template formatting + # inputs = tokenizer.apply_chat_template(messages, return_tensors="pt").to(model.device) + inputs = tokenizer(prompt.format(role=role), return_tensors="pt") + inputs = {k: v.to(model.device) for k, v in inputs.items()} + + + # Generate output + outputs = model.generate( + **inputs, + max_new_tokens=600, + do_sample=True, + temperature=0.2, + top_p=0.9, + pad_token_id=tokenizer.eos_token_id + ) + + # Decode and return + result = tokenizer.decode(outputs[0], skip_special_tokens=True) + return result + +def generate_jobs(role="Software Engineer", n=5): + model, tokenizer = load_model_and_tokenizer() + role = "Software Engineer" + fake_jobs = [] + for i in range(n): + fake_jobs.append(generate_job(role=role, model=model, tokenizer=tokenizer)) + return fake_jobs + +def extract_json_objects_from_text_block(texts): + """ + Accepts either a single string or a list of strings. + Extracts all valid JSON objects from messy text blocks. + """ + if isinstance(texts, str): + texts = [texts] # wrap in list if single string + + pattern = r"\{[\s\S]*?\}" + results = [] + + for raw_text in texts: + matches = re.findall(pattern, raw_text) + for match in matches: + try: + obj = json.loads(match) + results.append(obj) + except json.JSONDecodeError: + continue + + return results + +def generate_ui(role, n): + try: + raw_jobs = generate_jobs(role, n) + parsed_jobs = extract_json_objects_from_text_block(raw_jobs) + + if not isinstance(parsed_jobs, list) or not all(isinstance(item, dict) for item in parsed_jobs): + print("[ERROR] Parsed result is not a list of dicts") + return gr.update(value=[], visible=True), None + + filename = f"data/{role.replace(' ', '_').lower()}_jobs.json" + with open(filename, "w") as f: + json.dump(parsed_jobs, f, indent=2) + + print(f"[INFO] Returning {len(parsed_jobs)} jobs -> {filename}") + return parsed_jobs, filename + + except Exception as e: + print(f"[FATAL ERROR] {e}") + return gr.update(value=[], visible=True), None + + +if __name__ == "__main__": + with gr.Blocks() as demo: + gr.Markdown("# 🧠 Synthetic Job Dataset Generator") + gr.Markdown("Generate a structured dataset of job postings for a specific role.") + + with gr.Row(): + role_input = gr.Textbox(label="Job Role", placeholder="e.g. Software Engineer", value="Software Engineer") + n_input = gr.Number(label="Number of Samples", value=5, precision=0) + + generate_button = gr.Button("🚀 Generate") + output_table = gr.JSON(label="Generated Dataset") + download_button = gr.File(label="Download JSON") + + generate_button.click( + generate_ui, + inputs=[role_input, n_input], + outputs=[output_table, download_button] + ) + + demo.launch(debug=True, share=True) + + diff --git a/week3/community-contributions/muawiya/app/consts.py b/week3/community-contributions/muawiya/app/consts.py new file mode 100644 index 0000000..b62eb2d --- /dev/null +++ b/week3/community-contributions/muawiya/app/consts.py @@ -0,0 +1,5 @@ +# Models +GPT = 'gpt2' +FALCON = "tiiuae/falcon-rw-1b" +MISTRAL = "mistralai/Mistral-7B-Instruct-v0.1" +Databricks = "databricks/dolly-v2-3b" \ No newline at end of file diff --git a/week3/community-contributions/muawiya/app/requirements.txt b/week3/community-contributions/muawiya/app/requirements.txt new file mode 100644 index 0000000..9590dce --- /dev/null +++ b/week3/community-contributions/muawiya/app/requirements.txt @@ -0,0 +1,7 @@ +huggingface_hub==0.30.2 +ipython==8.12.3 +openai==1.76.2 +protobuf==6.30.2 +Requests==2.32.3 +torch==2.6.0+cu124 +transformers==4.51.3 \ No newline at end of file diff --git a/week3/community-contributions/muawiya/data/software_engineer_jobs.json b/week3/community-contributions/muawiya/data/software_engineer_jobs.json new file mode 100644 index 0000000..1a09d49 --- /dev/null +++ b/week3/community-contributions/muawiya/data/software_engineer_jobs.json @@ -0,0 +1,71 @@ +[ + { + "title": "Software Engineer", + "description": "We are seeking a highly skilled software engineer to join our team in developing and maintaining complex software systems. The ideal candidate will have a strong background in computer science and experience with multiple programming languages. Responsibilities include writing clean and efficient code, collaborating with cross-functional teams, and actively participating in code reviews. This is an excellent opportunity for a self-starter with a passion for technology and a desire to grow in their career.", + "requirements": [ + "Bachelor's degree in Computer Science or related field", + "3+ years of experience in software development", + "Strong proficiency in Java or C++", + "Experience with agile development methodologies", + "Excellent problem-solving and analytical skills" + ], + "location": "New York, NY", + "company_name": "ABC Technologies" + }, + { + "title": "Software Engineer", + "description": "We are looking for a highly skilled software engineer to join our team and contribute to the development of innovative software solutions. The ideal candidate will have experience in designing, developing, and testing software systems, and be able to work independently or as part of a team. Responsibilities include writing clean and efficient code, collaborating with cross-functional teams, and actively participating in code reviews. Must have a strong understanding of computer science principles and be able to learn quickly. This is a full-time position located in San Francisco, CA.", + "requirements": [ + "Bachelor's degree in Computer Science or related field", + "3+ years of experience in software development", + "Strong proficiency in Java or C++", + "Experience with agile development methodologies", + "Excellent problem-solving skills", + "Ability to work in a fast-paced environment" + ], + "location": "San Francisco, CA", + "company_name": "Acme Inc." + }, + { + "title": "Software Engineer", + "description": "We are seeking a highly skilled software engineer to join our team in developing and maintaining our cutting-edge software applications. The ideal candidate will have a strong background in computer science and software engineering, with experience in designing, coding, and testing software systems. Responsibilities include collaborating with cross-functional teams, writing clean and efficient code, and ensuring the timely delivery of high-quality software products. This is an excellent opportunity for a self-starter with a passion for technology and a desire to work in a dynamic and fast-paced environment.", + "requirements": [ + "Bachelor's degree in Computer Science or related field", + "3+ years of experience in software engineering", + "Strong proficiency in Java, Python, or C++", + "Experience with agile development methodologies", + "Excellent problem-solving and analytical skills", + "Strong communication and interpersonal skills" + ], + "location": "New York, NY", + "company_name": "ABC Tech" + }, + { + "title": "Software Engineer", + "description": "We are seeking a highly skilled software engineer to join our team and contribute to the development of innovative software solutions. The ideal candidate will have a strong background in computer science and experience with various programming languages and technologies. Responsibilities include designing, coding, testing, and maintaining software systems, as well as collaborating with cross-functional teams. This is an excellent opportunity for a creative and motivated individual to make a significant impact in the tech industry.", + "requirements": [ + "Bachelor's degree in Computer Science or related field", + "Minimum of 2 years experience in software development", + "Strong proficiency in Java, Python, or C++", + "Experience with agile development methodologies", + "Excellent problem-solving and analytical skills", + "Ability to work independently and as part of a team", + "Strong communication and interpersonal skills" + ], + "location": "New York, NY", + "company_name": "ABC Tech Inc." + }, + { + "title": "Software Engineer", + "description": "We are looking for a skilled software engineer to join our team and contribute to the development of innovative software solutions. Responsibilities include designing, coding, testing and maintaining software systems, as well as collaborating with cross-functional teams. The ideal candidate will have a strong background in computer science or a related field, and at least 3 years of experience in software development. Must be proficient in multiple programming languages, including Java, Python, and C++. Strong problem-solving skills and the ability to work independently or as part of a team are required. This is a full-time position located in San Francisco, CA.", + "requirements": [ + "Bachelor's degree in Computer Science or related field", + "At least 3 years of experience in software development", + "Proficiency in Java, Python, and C++", + "Strong problem-solving skills", + "Ability to work independently or as part of a team" + ], + "location": "San Francisco, CA", + "company_name": "Innovative Solutions Inc." + } +] \ No newline at end of file diff --git a/week3/community-contributions/muawiya/notebooks/synthetic_data_generator.ipynb b/week3/community-contributions/muawiya/notebooks/synthetic_data_generator.ipynb new file mode 100644 index 0000000..09f6f9e --- /dev/null +++ b/week3/community-contributions/muawiya/notebooks/synthetic_data_generator.ipynb @@ -0,0 +1,5509 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "machine_shape": "hm", + "gpuType": "A100" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU", + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "1d1fe06ac632475086ed5964ed000360": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_c138f597c98c4944b54d36510ecc8e0b", + "IPY_MODEL_bef2531516164e85bb79b86a791dd00d", + "IPY_MODEL_1cb9fc011950479a8d4832bc52c3399c" + ], + "layout": "IPY_MODEL_974e8f7f05ef472d85d5ea71425e6c39" + } + }, + "c138f597c98c4944b54d36510ecc8e0b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_696090959af8499e9a38777e664b85c1", + "placeholder": "​", + "style": "IPY_MODEL_973bcc9740b4426da4c680d11f3c1f7e", + "value": "tokenizer_config.json: 100%" + } + }, + "bef2531516164e85bb79b86a791dd00d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_3cb5d8fdb5fb4b6a99f6733c00df8378", + "max": 2103, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_58f4369c68434d569d5eb1bc36e71775", + "value": 2103 + } + }, + "1cb9fc011950479a8d4832bc52c3399c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_a05df972876941e3b6faab56cc30a4b8", + "placeholder": "​", + "style": "IPY_MODEL_9c61d90b63dd4fb5a481282d6d6eb8e8", + "value": " 2.10k/2.10k [00:00<00:00, 182kB/s]" + } + }, + "974e8f7f05ef472d85d5ea71425e6c39": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "696090959af8499e9a38777e664b85c1": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "973bcc9740b4426da4c680d11f3c1f7e": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "3cb5d8fdb5fb4b6a99f6733c00df8378": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "58f4369c68434d569d5eb1bc36e71775": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "a05df972876941e3b6faab56cc30a4b8": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9c61d90b63dd4fb5a481282d6d6eb8e8": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "2b71f87a02a540488a9e07f072f8807a": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_548cd7e9fab54470bc52810f27784760", + "IPY_MODEL_9c5eb078ece84a57aa9c402c9cad3b0b", + "IPY_MODEL_ee00a9f599db4affabb7bf1c4df6ca1a" + ], + "layout": "IPY_MODEL_52bd638607bf4e1aaf224ebdcfa3693d" + } + }, + "548cd7e9fab54470bc52810f27784760": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_771619a5acd343c788b8189167af09d4", + "placeholder": "​", + "style": "IPY_MODEL_09a1b30b5659452f95ebb2e72466c750", + "value": "tokenizer.model: 100%" + } + }, + "9c5eb078ece84a57aa9c402c9cad3b0b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_145a1f1032a44079a262db381e60d401", + "max": 493443, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_99888ad83b51485f959f977ba4418119", + "value": 493443 + } + }, + "ee00a9f599db4affabb7bf1c4df6ca1a": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_ec0854c2ea9a4c9280b6876df365db9d", + "placeholder": "​", + "style": "IPY_MODEL_dac5892c85214f69a5d75d5dc4858dfe", + "value": " 493k/493k [00:00<00:00, 7.91MB/s]" + } + }, + "52bd638607bf4e1aaf224ebdcfa3693d": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "771619a5acd343c788b8189167af09d4": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "09a1b30b5659452f95ebb2e72466c750": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "145a1f1032a44079a262db381e60d401": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "99888ad83b51485f959f977ba4418119": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "ec0854c2ea9a4c9280b6876df365db9d": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "dac5892c85214f69a5d75d5dc4858dfe": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "41b669da565e4204b848b754dfa28ac8": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e806afdada48418c9e353b94a38cd703", + "IPY_MODEL_7898b7322b014e96984c3d09a29a57fb", + "IPY_MODEL_d665270b05d64effba568ded85eee1b4" + ], + "layout": "IPY_MODEL_df087de9ade24058b1cf32e1556f7cb6" + } + }, + "e806afdada48418c9e353b94a38cd703": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_584330ab439b4887b1050a7f14dc5d7c", + "placeholder": "​", + "style": "IPY_MODEL_880b32d3bd1d4af8b5d0b449aab87e8b", + "value": "tokenizer.json: 100%" + } + }, + "7898b7322b014e96984c3d09a29a57fb": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_97d09f016e274cca93927f3bd8329352", + "max": 1795188, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_d87ef5878c0f4211809716674d0d8413", + "value": 1795188 + } + }, + "d665270b05d64effba568ded85eee1b4": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_556109848b1c4ebc99a6cc7c0be519e0", + "placeholder": "​", + "style": "IPY_MODEL_8d6cdfd75e3f4a628c9e785d3c469d98", + "value": " 1.80M/1.80M [00:00<00:00, 24.9MB/s]" + } + }, + "df087de9ade24058b1cf32e1556f7cb6": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "584330ab439b4887b1050a7f14dc5d7c": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "880b32d3bd1d4af8b5d0b449aab87e8b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "97d09f016e274cca93927f3bd8329352": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d87ef5878c0f4211809716674d0d8413": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "556109848b1c4ebc99a6cc7c0be519e0": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8d6cdfd75e3f4a628c9e785d3c469d98": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "fb1ff6f4482143c39be1cca57ec2fc8b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_83e6421843ad487c91bc75510b90f198", + "IPY_MODEL_9e74a7b74e1a4b119af5b95d572bac3c", + "IPY_MODEL_080c34ad56c84c229b1555b15b354aad" + ], + "layout": "IPY_MODEL_d968bf43e8574d9090326b31c9a7fd93" + } + }, + "83e6421843ad487c91bc75510b90f198": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_e78b05f33ee54c968fd87b77a2470bce", + "placeholder": "​", + "style": "IPY_MODEL_79a201f7ab7e49efa9e3e1504012dec2", + "value": "special_tokens_map.json: 100%" + } + }, + "9e74a7b74e1a4b119af5b95d572bac3c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_6e5d431074de4955a97d4ea36621ae36", + "max": 414, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_bfc581362fbc4aca85df7b2a943dd5e4", + "value": 414 + } + }, + "080c34ad56c84c229b1555b15b354aad": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_bc9b585bfd2847bb9f22c4720bd19033", + "placeholder": "​", + "style": "IPY_MODEL_8addd2418c3049f3be32465cc9a408d4", + "value": " 414/414 [00:00<00:00, 52.5kB/s]" + } + }, + "d968bf43e8574d9090326b31c9a7fd93": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e78b05f33ee54c968fd87b77a2470bce": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "79a201f7ab7e49efa9e3e1504012dec2": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "6e5d431074de4955a97d4ea36621ae36": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bfc581362fbc4aca85df7b2a943dd5e4": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "bc9b585bfd2847bb9f22c4720bd19033": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8addd2418c3049f3be32465cc9a408d4": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "c7b5bb9ef22f4ebe9969d4d10d63d24c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_d8c3f3ec329743f6b2f21d21601f092a", + "IPY_MODEL_2fee19152ef34eeaba541d559b9a0bc0", + "IPY_MODEL_2740de6be1ae4e3bacc642c39828883b" + ], + "layout": "IPY_MODEL_4104813265f34db0ab09c9d6c148ba29" + } + }, + "d8c3f3ec329743f6b2f21d21601f092a": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_6d2dbad5a0984f8382abd18910c14343", + "placeholder": "​", + "style": "IPY_MODEL_32285185818f40a6b07c6d6f6175b70c", + "value": "config.json: 100%" + } + }, + "2fee19152ef34eeaba541d559b9a0bc0": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_79da3c26e0fb4405a198c2255df9ec00", + "max": 571, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_c95bea4e04ff49078821a5dd67f0c28a", + "value": 571 + } + }, + "2740de6be1ae4e3bacc642c39828883b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_3695b9dde85348efb683e31e5d52e210", + "placeholder": "​", + "style": "IPY_MODEL_1d982bed2d4645b8a19295b7812cef49", + "value": " 571/571 [00:00<00:00, 72.5kB/s]" + } + }, + "4104813265f34db0ab09c9d6c148ba29": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6d2dbad5a0984f8382abd18910c14343": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "32285185818f40a6b07c6d6f6175b70c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "79da3c26e0fb4405a198c2255df9ec00": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c95bea4e04ff49078821a5dd67f0c28a": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "3695b9dde85348efb683e31e5d52e210": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "1d982bed2d4645b8a19295b7812cef49": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "32c58f50bb1c44e085ae3663004fcfff": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_c4df70cf509541828d3a06c380fdfe3d", + "IPY_MODEL_abd2737f597f48b0846a74c743307917", + "IPY_MODEL_a2a52b5e3c104e1cbec513a9f8744db2" + ], + "layout": "IPY_MODEL_ba57460b8ee24f4e96f8a603914b7073" + } + }, + "c4df70cf509541828d3a06c380fdfe3d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_d17cd0e49fa94361894660c0645ec9a8", + "placeholder": "​", + "style": "IPY_MODEL_6cd364a43f6f4ea793b05bf14ee9d687", + "value": "model.safetensors.index.json: 100%" + } + }, + "abd2737f597f48b0846a74c743307917": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_a80f72a5e41047f1898d5b6f00a2c69b", + "max": 25125, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_c6f6fca0f35b44fbb9037337a5bc0431", + "value": 25125 + } + }, + "a2a52b5e3c104e1cbec513a9f8744db2": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_3d07e648a5644742b8112146e952c44a", + "placeholder": "​", + "style": "IPY_MODEL_bff978fcc6f94f55bf605c6d9c23cfd2", + "value": " 25.1k/25.1k [00:00<00:00, 2.73MB/s]" + } + }, + "ba57460b8ee24f4e96f8a603914b7073": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d17cd0e49fa94361894660c0645ec9a8": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6cd364a43f6f4ea793b05bf14ee9d687": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "a80f72a5e41047f1898d5b6f00a2c69b": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c6f6fca0f35b44fbb9037337a5bc0431": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "3d07e648a5644742b8112146e952c44a": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bff978fcc6f94f55bf605c6d9c23cfd2": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "eca24e648bcf4cc684f15da684e2791d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_dc82b611b8c145eb8ebc7b80073e9ae1", + "IPY_MODEL_f3e6040a241c4ac7b715bb07a9ec6d6b", + "IPY_MODEL_e310ab9f4338443e82d257ddc21f48bb" + ], + "layout": "IPY_MODEL_9dd0e53a7a2a4d668c5640d938b71c9f" + } + }, + "dc82b611b8c145eb8ebc7b80073e9ae1": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_1fc933b90fa546c884181136373ad005", + "placeholder": "​", + "style": "IPY_MODEL_94f3ee73e2c04092ac5522c6ef038ea1", + "value": "Fetching 2 files: 100%" + } + }, + "f3e6040a241c4ac7b715bb07a9ec6d6b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_81d8563026e04f5ab00eced0da89a7ef", + "max": 2, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_95f081aaf9e84c2f91c82a4e2f183009", + "value": 2 + } + }, + "e310ab9f4338443e82d257ddc21f48bb": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_965cfc093b5040bbaec177820e45ec95", + "placeholder": "​", + "style": "IPY_MODEL_d328397d81f343e28dd1a6e52c5f0ae7", + "value": " 2/2 [00:46<00:00, 46.46s/it]" + } + }, + "9dd0e53a7a2a4d668c5640d938b71c9f": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "1fc933b90fa546c884181136373ad005": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "94f3ee73e2c04092ac5522c6ef038ea1": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "81d8563026e04f5ab00eced0da89a7ef": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "95f081aaf9e84c2f91c82a4e2f183009": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "965cfc093b5040bbaec177820e45ec95": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d328397d81f343e28dd1a6e52c5f0ae7": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "f73f9c7f341c4a99b00585343bf4d4bd": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_2a11e010825b42d4a949ad64ae0d1933", + "IPY_MODEL_15b769156f6a4d2988f1c09f3820f7ef", + "IPY_MODEL_a0484e3846c647b892d2de3797496605" + ], + "layout": "IPY_MODEL_cb042f80aaf04bf1963d637d1771741e" + } + }, + "2a11e010825b42d4a949ad64ae0d1933": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_852ba7d4221a475488411f5014362496", + "placeholder": "​", + "style": "IPY_MODEL_38dc7c1e65324e3097d8738532272e32", + "value": "model-00001-of-00002.safetensors: 100%" + } + }, + "15b769156f6a4d2988f1c09f3820f7ef": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_613da14abc24460db3bb337886cb407c", + "max": 9942981696, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_37a495a5836f413ea5f662538d51a939", + "value": 9942981696 + } + }, + "a0484e3846c647b892d2de3797496605": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_9c61322c006f465385df301121462e82", + "placeholder": "​", + "style": "IPY_MODEL_d93d0bb6ebc943a1be6902bd88cef441", + "value": " 9.94G/9.94G [00:46<00:00, 246MB/s]" + } + }, + "cb042f80aaf04bf1963d637d1771741e": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "852ba7d4221a475488411f5014362496": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "38dc7c1e65324e3097d8738532272e32": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "613da14abc24460db3bb337886cb407c": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "37a495a5836f413ea5f662538d51a939": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "9c61322c006f465385df301121462e82": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d93d0bb6ebc943a1be6902bd88cef441": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "50a2a1bd13db4045a4ae01138470c42b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_ad7cba643d1742cdb47c433bf50072f9", + "IPY_MODEL_57ef5d067e7343239525a6da237b29eb", + "IPY_MODEL_7567388a58a340d4a0f384f79ee13ddc" + ], + "layout": "IPY_MODEL_52c2896ab41a4d2592484084cb501e5a" + } + }, + "ad7cba643d1742cdb47c433bf50072f9": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_22957622a42345b991371153c29583c4", + "placeholder": "​", + "style": "IPY_MODEL_d34c879607b041739a2cc6273509e330", + "value": "model-00002-of-00002.safetensors: 100%" + } + }, + "57ef5d067e7343239525a6da237b29eb": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_d1e7bdd4faac4765862fc809017c4856", + "max": 4540516344, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_fcb0ad846398455faccf0d797549f589", + "value": 4540516344 + } + }, + "7567388a58a340d4a0f384f79ee13ddc": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_b381226552c9462d858051fcb7240727", + "placeholder": "​", + "style": "IPY_MODEL_94e630795bc247e08e6af434c5924cdd", + "value": " 4.54G/4.54G [00:23<00:00, 248MB/s]" + } + }, + "52c2896ab41a4d2592484084cb501e5a": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "22957622a42345b991371153c29583c4": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d34c879607b041739a2cc6273509e330": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "d1e7bdd4faac4765862fc809017c4856": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fcb0ad846398455faccf0d797549f589": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "b381226552c9462d858051fcb7240727": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "94e630795bc247e08e6af434c5924cdd": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "2b496c218e2049ff9156ff5b3bbdb90b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_62d3b35a3924417894094d3bbf993932", + "IPY_MODEL_41737448e98a48dcbe117351645395de", + "IPY_MODEL_e83735cd79674a3482f0b90d4c9a3e3d" + ], + "layout": "IPY_MODEL_eff6ca539e2947e9b2987977f143de9a" + } + }, + "62d3b35a3924417894094d3bbf993932": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_aa75292545a649eda8cb7bab0ac9bbcd", + "placeholder": "​", + "style": "IPY_MODEL_22c0e2213505435eaeebdfe330b8fbb8", + "value": "Loading checkpoint shards: 100%" + } + }, + "41737448e98a48dcbe117351645395de": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_7de820edeeaf4210af68c721bab3082d", + "max": 2, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_66ef664b717343bdaf8e5c4610b2a678", + "value": 2 + } + }, + "e83735cd79674a3482f0b90d4c9a3e3d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_f09534cbda8c4e91b2e073c0eca0cb96", + "placeholder": "​", + "style": "IPY_MODEL_7d8b5a2a52aa4957bc5905021898d8f4", + "value": " 2/2 [00:17<00:00,  8.24s/it]" + } + }, + "eff6ca539e2947e9b2987977f143de9a": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "aa75292545a649eda8cb7bab0ac9bbcd": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "22c0e2213505435eaeebdfe330b8fbb8": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "7de820edeeaf4210af68c721bab3082d": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "66ef664b717343bdaf8e5c4610b2a678": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "f09534cbda8c4e91b2e073c0eca0cb96": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7d8b5a2a52aa4957bc5905021898d8f4": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "1c68a822580a4960acad93be9fd48ce3": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_6df81f91b17f41dc91fc9f367fa0afab", + "IPY_MODEL_17742936c9ac46e588d1ce42235745d0", + "IPY_MODEL_17f0cd6f05184164b48ef906f192505a" + ], + "layout": "IPY_MODEL_936a67f2de2e44728b83600f4fa0569c" + } + }, + "6df81f91b17f41dc91fc9f367fa0afab": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_d5ad82f6b9654a8cb888613caaaaa097", + "placeholder": "​", + "style": "IPY_MODEL_b014979e237344129545ff2c384c1c1c", + "value": "generation_config.json: 100%" + } + }, + "17742936c9ac46e588d1ce42235745d0": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_b99c12d57d4a4eab84aefbef58452c32", + "max": 116, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_5923bbdcf6334393ad832765f129bdec", + "value": 116 + } + }, + "17f0cd6f05184164b48ef906f192505a": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_260ac8c28531450bba1deac4e4669dc4", + "placeholder": "​", + "style": "IPY_MODEL_067959a4ef614c498c28bb83c10e16de", + "value": " 116/116 [00:00<00:00, 15.6kB/s]" + } + }, + "936a67f2de2e44728b83600f4fa0569c": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d5ad82f6b9654a8cb888613caaaaa097": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b014979e237344129545ff2c384c1c1c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "b99c12d57d4a4eab84aefbef58452c32": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "5923bbdcf6334393ad832765f129bdec": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "260ac8c28531450bba1deac4e4669dc4": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "067959a4ef614c498c28bb83c10e16de": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "b5dd409cf6e04764adbb7c2a49b7be86": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_65187b4ebb2041b39778268e8b4d6b0d", + "IPY_MODEL_33317cac10ca4a98bf4433c1eff43435", + "IPY_MODEL_f81f5402902c4c04b10895782287e908" + ], + "layout": "IPY_MODEL_c471914fe0d34ae8967bac2820637d5b" + } + }, + "65187b4ebb2041b39778268e8b4d6b0d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_7aead6f6cffa40a383f1b8c64943329e", + "placeholder": "​", + "style": "IPY_MODEL_f24fe57d8e164fd68185b4c117e7c097", + "value": "Loading checkpoint shards: 100%" + } + }, + "33317cac10ca4a98bf4433c1eff43435": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_f913ca9ab6d44ab1b788a36bd964ed39", + "max": 2, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_ed34016801264a05bb3697eca2ac22ef", + "value": 2 + } + }, + "f81f5402902c4c04b10895782287e908": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_fe622254072540fda3b0dd6b2cab6e4a", + "placeholder": "​", + "style": "IPY_MODEL_5d95bdea47594e21855a6e564d0760da", + "value": " 2/2 [00:17<00:00,  8.01s/it]" + } + }, + "c471914fe0d34ae8967bac2820637d5b": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7aead6f6cffa40a383f1b8c64943329e": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f24fe57d8e164fd68185b4c117e7c097": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "f913ca9ab6d44ab1b788a36bd964ed39": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ed34016801264a05bb3697eca2ac22ef": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "fe622254072540fda3b0dd6b2cab6e4a": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "5d95bdea47594e21855a6e564d0760da": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "9f9defc39ac5437e9512e5fad810b409": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_1c126dfdc51c438b9b48c8a65e549ae2", + "IPY_MODEL_741d800130ea4830b9266f467fa6a0bf", + "IPY_MODEL_73c0a01f1693471c9c017143e9e9058b" + ], + "layout": "IPY_MODEL_ab8174c1337b43048e05aeca72ca18ef" + } + }, + "1c126dfdc51c438b9b48c8a65e549ae2": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_5e5a992d86434e62a25fc9b7f75f4b16", + "placeholder": "​", + "style": "IPY_MODEL_1507b1310f5045c9b691fdb102cc1686", + "value": "Loading checkpoint shards: 100%" + } + }, + "741d800130ea4830b9266f467fa6a0bf": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_8a8e81f9d3a54ce49b367f8e984b4a06", + "max": 2, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_bab02b1f092b40c8983cd6440f7eaf16", + "value": 2 + } + }, + "73c0a01f1693471c9c017143e9e9058b": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_94f30dc2653a4f178c9c2ef454d24644", + "placeholder": "​", + "style": "IPY_MODEL_a508625ef12d4a639fa9773484507709", + "value": " 2/2 [00:17<00:00,  8.07s/it]" + } + }, + "ab8174c1337b43048e05aeca72ca18ef": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "5e5a992d86434e62a25fc9b7f75f4b16": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "1507b1310f5045c9b691fdb102cc1686": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "8a8e81f9d3a54ce49b367f8e984b4a06": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bab02b1f092b40c8983cd6440f7eaf16": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "94f30dc2653a4f178c9c2ef454d24644": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a508625ef12d4a639fa9773484507709": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + } + } + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "Pv8FH9BMgskk", + "outputId": "00cd7f02-2556-4850-b599-1ddec83f7cd9" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.4/76.4 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m363.4/363.4 MB\u001b[0m \u001b[31m4.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m13.8/13.8 MB\u001b[0m \u001b[31m112.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m24.6/24.6 MB\u001b[0m \u001b[31m96.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m883.7/883.7 kB\u001b[0m \u001b[31m55.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m664.8/664.8 MB\u001b[0m \u001b[31m1.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m211.5/211.5 MB\u001b[0m \u001b[31m11.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.3/56.3 MB\u001b[0m \u001b[31m44.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m127.9/127.9 MB\u001b[0m \u001b[31m20.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m207.5/207.5 MB\u001b[0m \u001b[31m3.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m21.1/21.1 MB\u001b[0m \u001b[31m109.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.1/76.1 MB\u001b[0m \u001b[31m28.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", + "google-genai 1.12.1 requires httpx<1.0.0,>=0.28.1, but you have httpx 0.27.2 which is incompatible.\u001b[0m\u001b[31m\n", + "\u001b[0mRequirement already satisfied: bitsandbytes in /usr/local/lib/python3.11/dist-packages (0.45.5)\n", + "Requirement already satisfied: torch<3,>=2.0 in /usr/local/lib/python3.11/dist-packages (from bitsandbytes) (2.6.0+cu124)\n", + "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from bitsandbytes) (2.0.2)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.18.0)\n", + "Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (4.13.2)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.4.2)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.1.6)\n", + "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (2025.3.2)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (9.1.0.70)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.5.8)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (11.2.1.3)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (10.3.5.147)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (11.6.1.9)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.3.1.170)\n", + "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.2 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (0.6.2)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (2.21.5)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: triton==3.2.0 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.2.0)\n", + "Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (1.13.1)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy==1.13.1->torch<3,>=2.0->bitsandbytes) (1.3.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->torch<3,>=2.0->bitsandbytes) (3.0.2)\n", + "Requirement already satisfied: transformers in /usr/local/lib/python3.11/dist-packages (4.51.3)\n", + "Requirement already satisfied: accelerate in /usr/local/lib/python3.11/dist-packages (1.6.0)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from transformers) (3.18.0)\n", + "Requirement already satisfied: huggingface-hub<1.0,>=0.30.0 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.30.2)\n", + "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from transformers) (2.0.2)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from transformers) (24.2)\n", + "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/dist-packages (from transformers) (6.0.2)\n", + "Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.11/dist-packages (from transformers) (2024.11.6)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.11/dist-packages (from transformers) (2.32.3)\n", + "Requirement already satisfied: tokenizers<0.22,>=0.21 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.21.1)\n", + "Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.5.3)\n", + "Requirement already satisfied: tqdm>=4.27 in /usr/local/lib/python3.11/dist-packages (from transformers) (4.67.1)\n", + "Requirement already satisfied: psutil in /usr/local/lib/python3.11/dist-packages (from accelerate) (5.9.5)\n", + "Requirement already satisfied: torch>=2.0.0 in /usr/local/lib/python3.11/dist-packages (from accelerate) (2.6.0+cu124)\n", + "Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.30.0->transformers) (2025.3.2)\n", + "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.30.0->transformers) (4.13.2)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (3.4.2)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (3.1.6)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.127)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (9.1.0.70)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.5.8)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (11.2.1.3)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (10.3.5.147)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (11.6.1.9)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.3.1.170)\n", + "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.2 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (0.6.2)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (2.21.5)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.127)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (12.4.127)\n", + "Requirement already satisfied: triton==3.2.0 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (3.2.0)\n", + "Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.11/dist-packages (from torch>=2.0.0->accelerate) (1.13.1)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy==1.13.1->torch>=2.0.0->accelerate) (1.3.0)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (3.4.1)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (3.10)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (2.4.0)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (2025.4.26)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->torch>=2.0.0->accelerate) (3.0.2)\n" + ] + } + ], + "source": [ + "!pip install -q requests torch bitsandbytes transformers sentencepiece accelerate openai httpx==0.27.2\n", + "!pip install -U bitsandbytes\n", + "!pip install -U transformers accelerate" + ] + }, + { + "cell_type": "code", + "source": [ + "# imports\n", + "\n", + "import os\n", + "import requests\n", + "from IPython.display import Markdown, display, update_display\n", + "from openai import OpenAI\n", + "from google.colab import drive\n", + "from huggingface_hub import login\n", + "from google.colab import userdata\n", + "from transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer, BitsAndBytesConfig, pipeline, TextGenerationPipeline\n", + "import torch" + ], + "metadata": { + "id": "u0qdj2ynjjRz" + }, + "execution_count": 9, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Models\n", + "GPT = 'gpt2'\n", + "FALCON = \"tiiuae/falcon-rw-1b\"\n", + "MISTRAL = \"mistralai/Mistral-7B-Instruct-v0.1\"\n", + "Databricks = \"databricks/dolly-v2-3b\"\n" + ], + "metadata": { + "id": "a_sHgTj_jpDE" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Sign in to HuggingFace Hub\n", + "\n", + "hf_token = userdata.get('HF_TOKEN')\n", + "login(hf_token, add_to_git_credential=True)" + ], + "metadata": { + "id": "JYjtu3cPj2Th" + }, + "execution_count": 11, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Flatten the messages into a single plain prompt\n", + "# prompt = \"\"\"\n", + "# Generate {{n}} fake job postings for a {{role}} position.\n", + "\n", + "# Only output a JSON array like:\n", + "# [\n", + "# {{\n", + "# \"title\": \"Software Engineer\",\n", + "# \"description\": \"Develop backend APIs and services.\",\n", + "# \"requirements\": [\"Python\", \"FastAPI\", \"MongoDB\"],\n", + "# \"location\": \"San Francisco\",\n", + "# \"company_name\": \"TechCorp\"\n", + "# }},\n", + "# ...\n", + "# ]\n", + "# Return valid JSON only. No markdown. No explanations.\n", + "# \"\"\"\n", + "\n", + "# prompt = \"\"\"\n", + "# Generate exactly {{n}} fake job postings for a {{role}}.\n", + "\n", + "# Each posting must be a JSON object with:\n", + "# - title\n", + "# - description (5-10 sentences)\n", + "# - requirements (array of 3-5 strings)\n", + "# - location\n", + "# - company_name\n", + "\n", + "# Return a single JSON array with {n} items. No explanations. No markdown.\n", + "# ONLY the JSON array as output.\n", + "# \"\"\"\n", + "\n", + "prompt = \"\"\"\n", + "Generate one fake job posting for a {{role}}.\n", + "\n", + "Return only a single JSON object with:\n", + "- title\n", + "- description (5-10 sentences)\n", + "- requirements (array of 4-6 strings)\n", + "- location\n", + "- company_name\n", + "\n", + "No explanations, no extra text.\n", + "Only the JSON object.\n", + "\"\"\"\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "7IUshG1fkQ7k" + }, + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "!pip install safetensors" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-9nzEpDd-dkd", + "outputId": "484ed145-951f-4950-f9ba-bf7ed6e30a13" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: safetensors in /usr/local/lib/python3.11/dist-packages (0.5.3)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "os.makedirs(\"/tmp/dolly_offload\", exist_ok=True)" + ], + "metadata": { + "id": "D13qucmC-qGr" + }, + "execution_count": 14, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "bnb_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + ")" + ], + "metadata": { + "id": "4qf967BtEqqx" + }, + "execution_count": 15, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def load_model_and_tokenizer():\n", + " tokenizer = AutoTokenizer.from_pretrained(MISTRAL, trust_remote_code=True)\n", + "\n", + " model = AutoModelForCausalLM.from_pretrained(\n", + " MISTRAL,\n", + " device_map={\"\": \"cuda\"},\n", + " trust_remote_code=True,\n", + " offload_folder=\"/tmp/dolly_offload\",\n", + " quantization_config=bnb_config\n", + " )\n", + "\n", + " return model, tokenizer\n" + ], + "metadata": { + "id": "GjV7joEMjujM" + }, + "execution_count": 16, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# generator = pipeline(\"text-generation\", model=Databricks, device_map=\"auto\", trust_remote_code=True, offload_folder=\"/tmp/dolly_offload\")\n", + "\n", + "def generate_job(role=\"Software Engineer\", model=None, tokenizer=None):\n", + " # prompt = prompt.format(role=role, n=n)\n", + " # outputs = generator(prompt, max_new_tokens=500, do_sample=True, temperature=0.9)\n", + " # return outputs[0]['generated_text']\n", + "\n", + " # Apply chat template formatting\n", + " # inputs = tokenizer.apply_chat_template(messages, return_tensors=\"pt\").to(model.device)\n", + " inputs = tokenizer(prompt.format(role=role), return_tensors=\"pt\")\n", + " inputs = {k: v.to(model.device) for k, v in inputs.items()}\n", + "\n", + "\n", + " # Generate output\n", + " outputs = model.generate(\n", + " **inputs,\n", + " max_new_tokens=600,\n", + " do_sample=True,\n", + " temperature=0.2,\n", + " top_p=0.9,\n", + " pad_token_id=tokenizer.eos_token_id\n", + " )\n", + "\n", + " # Decode and return\n", + " result = tokenizer.decode(outputs[0], skip_special_tokens=True)\n", + " return result\n", + "\n" + ], + "metadata": { + "id": "5w89B0MwkJWo" + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "\n", + "def generate_jobs(role=\"Software Engineer\", n=5):\n", + " model, tokenizer = load_model_and_tokenizer()\n", + " role = \"Software Engineer\"\n", + " fake_jobs = []\n", + " for i in range(n):\n", + " fake_jobs.append(generate_job(role=role, model=model, tokenizer=tokenizer))\n", + " return fake_jobs" + ], + "metadata": { + "id": "ULhKrRe7XZmW" + }, + "execution_count": 18, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(generate_jobs(role=\"Software Engineer\", n=10))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 406, + "referenced_widgets": [ + "1d1fe06ac632475086ed5964ed000360", + "c138f597c98c4944b54d36510ecc8e0b", + "bef2531516164e85bb79b86a791dd00d", + "1cb9fc011950479a8d4832bc52c3399c", + "974e8f7f05ef472d85d5ea71425e6c39", + "696090959af8499e9a38777e664b85c1", + "973bcc9740b4426da4c680d11f3c1f7e", + "3cb5d8fdb5fb4b6a99f6733c00df8378", + "58f4369c68434d569d5eb1bc36e71775", + "a05df972876941e3b6faab56cc30a4b8", + "9c61d90b63dd4fb5a481282d6d6eb8e8", + "2b71f87a02a540488a9e07f072f8807a", + "548cd7e9fab54470bc52810f27784760", + "9c5eb078ece84a57aa9c402c9cad3b0b", + "ee00a9f599db4affabb7bf1c4df6ca1a", + "52bd638607bf4e1aaf224ebdcfa3693d", + "771619a5acd343c788b8189167af09d4", + "09a1b30b5659452f95ebb2e72466c750", + "145a1f1032a44079a262db381e60d401", + "99888ad83b51485f959f977ba4418119", + "ec0854c2ea9a4c9280b6876df365db9d", + "dac5892c85214f69a5d75d5dc4858dfe", + "41b669da565e4204b848b754dfa28ac8", + "e806afdada48418c9e353b94a38cd703", + "7898b7322b014e96984c3d09a29a57fb", + "d665270b05d64effba568ded85eee1b4", + "df087de9ade24058b1cf32e1556f7cb6", + "584330ab439b4887b1050a7f14dc5d7c", + "880b32d3bd1d4af8b5d0b449aab87e8b", + "97d09f016e274cca93927f3bd8329352", + "d87ef5878c0f4211809716674d0d8413", + "556109848b1c4ebc99a6cc7c0be519e0", + "8d6cdfd75e3f4a628c9e785d3c469d98", + "fb1ff6f4482143c39be1cca57ec2fc8b", + "83e6421843ad487c91bc75510b90f198", + "9e74a7b74e1a4b119af5b95d572bac3c", + "080c34ad56c84c229b1555b15b354aad", + "d968bf43e8574d9090326b31c9a7fd93", + "e78b05f33ee54c968fd87b77a2470bce", + "79a201f7ab7e49efa9e3e1504012dec2", + "6e5d431074de4955a97d4ea36621ae36", + "bfc581362fbc4aca85df7b2a943dd5e4", + "bc9b585bfd2847bb9f22c4720bd19033", + "8addd2418c3049f3be32465cc9a408d4", + "c7b5bb9ef22f4ebe9969d4d10d63d24c", + "d8c3f3ec329743f6b2f21d21601f092a", + "2fee19152ef34eeaba541d559b9a0bc0", + "2740de6be1ae4e3bacc642c39828883b", + "4104813265f34db0ab09c9d6c148ba29", + "6d2dbad5a0984f8382abd18910c14343", + "32285185818f40a6b07c6d6f6175b70c", + "79da3c26e0fb4405a198c2255df9ec00", + "c95bea4e04ff49078821a5dd67f0c28a", + "3695b9dde85348efb683e31e5d52e210", + "1d982bed2d4645b8a19295b7812cef49", + "32c58f50bb1c44e085ae3663004fcfff", + "c4df70cf509541828d3a06c380fdfe3d", + "abd2737f597f48b0846a74c743307917", + "a2a52b5e3c104e1cbec513a9f8744db2", + "ba57460b8ee24f4e96f8a603914b7073", + "d17cd0e49fa94361894660c0645ec9a8", + "6cd364a43f6f4ea793b05bf14ee9d687", + "a80f72a5e41047f1898d5b6f00a2c69b", + "c6f6fca0f35b44fbb9037337a5bc0431", + "3d07e648a5644742b8112146e952c44a", + "bff978fcc6f94f55bf605c6d9c23cfd2", + "eca24e648bcf4cc684f15da684e2791d", + "dc82b611b8c145eb8ebc7b80073e9ae1", + "f3e6040a241c4ac7b715bb07a9ec6d6b", + "e310ab9f4338443e82d257ddc21f48bb", + "9dd0e53a7a2a4d668c5640d938b71c9f", + "1fc933b90fa546c884181136373ad005", + "94f3ee73e2c04092ac5522c6ef038ea1", + "81d8563026e04f5ab00eced0da89a7ef", + "95f081aaf9e84c2f91c82a4e2f183009", + "965cfc093b5040bbaec177820e45ec95", + "d328397d81f343e28dd1a6e52c5f0ae7", + "f73f9c7f341c4a99b00585343bf4d4bd", + "2a11e010825b42d4a949ad64ae0d1933", + "15b769156f6a4d2988f1c09f3820f7ef", + "a0484e3846c647b892d2de3797496605", + "cb042f80aaf04bf1963d637d1771741e", + "852ba7d4221a475488411f5014362496", + "38dc7c1e65324e3097d8738532272e32", + "613da14abc24460db3bb337886cb407c", + "37a495a5836f413ea5f662538d51a939", + "9c61322c006f465385df301121462e82", + "d93d0bb6ebc943a1be6902bd88cef441", + "50a2a1bd13db4045a4ae01138470c42b", + "ad7cba643d1742cdb47c433bf50072f9", + "57ef5d067e7343239525a6da237b29eb", + "7567388a58a340d4a0f384f79ee13ddc", + "52c2896ab41a4d2592484084cb501e5a", + "22957622a42345b991371153c29583c4", + "d34c879607b041739a2cc6273509e330", + "d1e7bdd4faac4765862fc809017c4856", + "fcb0ad846398455faccf0d797549f589", + "b381226552c9462d858051fcb7240727", + "94e630795bc247e08e6af434c5924cdd", + "2b496c218e2049ff9156ff5b3bbdb90b", + "62d3b35a3924417894094d3bbf993932", + "41737448e98a48dcbe117351645395de", + "e83735cd79674a3482f0b90d4c9a3e3d", + "eff6ca539e2947e9b2987977f143de9a", + "aa75292545a649eda8cb7bab0ac9bbcd", + "22c0e2213505435eaeebdfe330b8fbb8", + "7de820edeeaf4210af68c721bab3082d", + "66ef664b717343bdaf8e5c4610b2a678", + "f09534cbda8c4e91b2e073c0eca0cb96", + "7d8b5a2a52aa4957bc5905021898d8f4", + "1c68a822580a4960acad93be9fd48ce3", + "6df81f91b17f41dc91fc9f367fa0afab", + "17742936c9ac46e588d1ce42235745d0", + "17f0cd6f05184164b48ef906f192505a", + "936a67f2de2e44728b83600f4fa0569c", + "d5ad82f6b9654a8cb888613caaaaa097", + "b014979e237344129545ff2c384c1c1c", + "b99c12d57d4a4eab84aefbef58452c32", + "5923bbdcf6334393ad832765f129bdec", + "260ac8c28531450bba1deac4e4669dc4", + "067959a4ef614c498c28bb83c10e16de" + ] + }, + "id": "kKsErltXXwy1", + "outputId": "683c2e5e-16d8-4fe3-efdd-664c385c71e7" + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "tokenizer_config.json: 0%| | 0.00/2.10k [00:00=2.0 in /usr/local/lib/python3.11/dist-packages (from bitsandbytes) (2.6.0+cu124)\n", + "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from bitsandbytes) (2.0.2)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.18.0)\n", + "Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (4.13.2)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.4.2)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.1.6)\n", + "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (2025.3.2)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (9.1.0.70)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.5.8)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (11.2.1.3)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (10.3.5.147)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (11.6.1.9)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.3.1.170)\n", + "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.2 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (0.6.2)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (2.21.5)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (12.4.127)\n", + "Requirement already satisfied: triton==3.2.0 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (3.2.0)\n", + "Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.11/dist-packages (from torch<3,>=2.0->bitsandbytes) (1.13.1)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy==1.13.1->torch<3,>=2.0->bitsandbytes) (1.3.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->torch<3,>=2.0->bitsandbytes) (3.0.2)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import re\n", + "import json\n", + "import ast\n", + "\n", + "\n", + "\n", + "def extract_json_objects_from_text_block(texts):\n", + " \"\"\"\n", + " Accepts either a single string or a list of strings.\n", + " Extracts all valid JSON objects from messy text blocks.\n", + " \"\"\"\n", + " if isinstance(texts, str):\n", + " texts = [texts] # wrap in list if single string\n", + "\n", + " pattern = r\"\\{[\\s\\S]*?\\}\"\n", + " results = []\n", + "\n", + " for raw_text in texts:\n", + " matches = re.findall(pattern, raw_text)\n", + " for match in matches:\n", + " try:\n", + " obj = json.loads(match)\n", + " results.append(obj)\n", + " except json.JSONDecodeError:\n", + " continue\n", + "\n", + " return results\n", + "\n", + "text = generate_jobs(role=\"Software Engineer\", n=10)\n", + "print(extract_json_objects_from_text_block(text))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 86, + "referenced_widgets": [ + "b5dd409cf6e04764adbb7c2a49b7be86", + "65187b4ebb2041b39778268e8b4d6b0d", + "33317cac10ca4a98bf4433c1eff43435", + "f81f5402902c4c04b10895782287e908", + "c471914fe0d34ae8967bac2820637d5b", + "7aead6f6cffa40a383f1b8c64943329e", + "f24fe57d8e164fd68185b4c117e7c097", + "f913ca9ab6d44ab1b788a36bd964ed39", + "ed34016801264a05bb3697eca2ac22ef", + "fe622254072540fda3b0dd6b2cab6e4a", + "5d95bdea47594e21855a6e564d0760da" + ] + }, + "id": "1uzTM2G1oqDs", + "outputId": "08e88ab0-ca17-46d3-8f9c-6a595863aeba" + }, + "execution_count": 22, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/2 [00:00=22.0 (from gradio)\n", + " Downloading aiofiles-24.1.0-py3-none-any.whl.metadata (10 kB)\n", + "Requirement already satisfied: anyio<5.0,>=3.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (4.9.0)\n", + "Collecting fastapi<1.0,>=0.115.2 (from gradio)\n", + " Downloading fastapi-0.115.12-py3-none-any.whl.metadata (27 kB)\n", + "Collecting ffmpy (from gradio)\n", + " Downloading ffmpy-0.5.0-py3-none-any.whl.metadata (3.0 kB)\n", + "Collecting gradio-client==1.10.0 (from gradio)\n", + " Downloading gradio_client-1.10.0-py3-none-any.whl.metadata (7.1 kB)\n", + "Collecting groovy~=0.1 (from gradio)\n", + " Downloading groovy-0.1.2-py3-none-any.whl.metadata (6.1 kB)\n", + "Requirement already satisfied: httpx>=0.24.1 in /usr/local/lib/python3.11/dist-packages (from gradio) (0.27.2)\n", + "Requirement already satisfied: huggingface-hub>=0.28.1 in /usr/local/lib/python3.11/dist-packages (from gradio) (0.30.2)\n", + "Requirement already satisfied: jinja2<4.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (3.1.6)\n", + "Requirement already satisfied: markupsafe<4.0,>=2.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (3.0.2)\n", + "Requirement already satisfied: numpy<3.0,>=1.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (2.0.2)\n", + "Requirement already satisfied: orjson~=3.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (3.10.17)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from gradio) (24.2)\n", + "Requirement already satisfied: pandas<3.0,>=1.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (2.2.2)\n", + "Requirement already satisfied: pillow<12.0,>=8.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (11.2.1)\n", + "Requirement already satisfied: pydantic<2.12,>=2.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (2.11.3)\n", + "Collecting pydub (from gradio)\n", + " Downloading pydub-0.25.1-py2.py3-none-any.whl.metadata (1.4 kB)\n", + "Collecting python-multipart>=0.0.18 (from gradio)\n", + " Downloading python_multipart-0.0.20-py3-none-any.whl.metadata (1.8 kB)\n", + "Requirement already satisfied: pyyaml<7.0,>=5.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (6.0.2)\n", + "Collecting ruff>=0.9.3 (from gradio)\n", + " Downloading ruff-0.11.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (25 kB)\n", + "Collecting safehttpx<0.2.0,>=0.1.6 (from gradio)\n", + " Downloading safehttpx-0.1.6-py3-none-any.whl.metadata (4.2 kB)\n", + "Collecting semantic-version~=2.0 (from gradio)\n", + " Downloading semantic_version-2.10.0-py2.py3-none-any.whl.metadata (9.7 kB)\n", + "Collecting starlette<1.0,>=0.40.0 (from gradio)\n", + " Downloading starlette-0.46.2-py3-none-any.whl.metadata (6.2 kB)\n", + "Collecting tomlkit<0.14.0,>=0.12.0 (from gradio)\n", + " Downloading tomlkit-0.13.2-py3-none-any.whl.metadata (2.7 kB)\n", + "Requirement already satisfied: typer<1.0,>=0.12 in /usr/local/lib/python3.11/dist-packages (from gradio) (0.15.3)\n", + "Requirement already satisfied: typing-extensions~=4.0 in /usr/local/lib/python3.11/dist-packages (from gradio) (4.13.2)\n", + "Collecting uvicorn>=0.14.0 (from gradio)\n", + " Downloading uvicorn-0.34.2-py3-none-any.whl.metadata (6.5 kB)\n", + "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from gradio-client==1.10.0->gradio) (2025.3.2)\n", + "Requirement already satisfied: websockets<16.0,>=10.0 in /usr/local/lib/python3.11/dist-packages (from gradio-client==1.10.0->gradio) (15.0.1)\n", + "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.11/dist-packages (from anyio<5.0,>=3.0->gradio) (3.10)\n", + "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.11/dist-packages (from anyio<5.0,>=3.0->gradio) (1.3.1)\n", + "Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from httpx>=0.24.1->gradio) (2025.4.26)\n", + "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.11/dist-packages (from httpx>=0.24.1->gradio) (1.0.9)\n", + "Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.11/dist-packages (from httpcore==1.*->httpx>=0.24.1->gradio) (0.16.0)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from huggingface-hub>=0.28.1->gradio) (3.18.0)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.11/dist-packages (from huggingface-hub>=0.28.1->gradio) (2.32.3)\n", + "Requirement already satisfied: tqdm>=4.42.1 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub>=0.28.1->gradio) (4.67.1)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas<3.0,>=1.0->gradio) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas<3.0,>=1.0->gradio) (2025.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas<3.0,>=1.0->gradio) (2025.2)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.11/dist-packages (from pydantic<2.12,>=2.0->gradio) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.33.1 in /usr/local/lib/python3.11/dist-packages (from pydantic<2.12,>=2.0->gradio) (2.33.1)\n", + "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from pydantic<2.12,>=2.0->gradio) (0.4.0)\n", + "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0,>=0.12->gradio) (8.1.8)\n", + "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0,>=0.12->gradio) (1.5.4)\n", + "Requirement already satisfied: rich>=10.11.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0,>=0.12->gradio) (13.9.4)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas<3.0,>=1.0->gradio) (1.17.0)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.11/dist-packages (from rich>=10.11.0->typer<1.0,>=0.12->gradio) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.11/dist-packages (from rich>=10.11.0->typer<1.0,>=0.12->gradio) (2.19.1)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests->huggingface-hub>=0.28.1->gradio) (3.4.1)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests->huggingface-hub>=0.28.1->gradio) (2.4.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.11/dist-packages (from markdown-it-py>=2.2.0->rich>=10.11.0->typer<1.0,>=0.12->gradio) (0.1.2)\n", + "Downloading gradio-5.29.0-py3-none-any.whl (54.1 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.1/54.1 MB\u001b[0m \u001b[31m46.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading gradio_client-1.10.0-py3-none-any.whl (322 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m322.9/322.9 kB\u001b[0m \u001b[31m34.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading aiofiles-24.1.0-py3-none-any.whl (15 kB)\n", + "Downloading fastapi-0.115.12-py3-none-any.whl (95 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m95.2/95.2 kB\u001b[0m \u001b[31m10.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading groovy-0.1.2-py3-none-any.whl (14 kB)\n", + "Downloading python_multipart-0.0.20-py3-none-any.whl (24 kB)\n", + "Downloading ruff-0.11.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.5 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m11.5/11.5 MB\u001b[0m \u001b[31m131.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading safehttpx-0.1.6-py3-none-any.whl (8.7 kB)\n", + "Downloading semantic_version-2.10.0-py2.py3-none-any.whl (15 kB)\n", + "Downloading starlette-0.46.2-py3-none-any.whl (72 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m72.0/72.0 kB\u001b[0m \u001b[31m7.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading tomlkit-0.13.2-py3-none-any.whl (37 kB)\n", + "Downloading uvicorn-0.34.2-py3-none-any.whl (62 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.5/62.5 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ffmpy-0.5.0-py3-none-any.whl (6.0 kB)\n", + "Downloading pydub-0.25.1-py2.py3-none-any.whl (32 kB)\n", + "Installing collected packages: pydub, uvicorn, tomlkit, semantic-version, ruff, python-multipart, groovy, ffmpy, aiofiles, starlette, safehttpx, gradio-client, fastapi, gradio\n", + "Successfully installed aiofiles-24.1.0 fastapi-0.115.12 ffmpy-0.5.0 gradio-5.29.0 gradio-client-1.10.0 groovy-0.1.2 pydub-0.25.1 python-multipart-0.0.20 ruff-0.11.8 safehttpx-0.1.6 semantic-version-2.10.0 starlette-0.46.2 tomlkit-0.13.2 uvicorn-0.34.2\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import gradio as gr\n", + "import json\n", + "from transformers import AutoTokenizer, AutoModelForCausalLM\n", + "import torch\n", + "import re\n", + "\n", + "def generate_ui(role, n):\n", + " try:\n", + " raw_jobs = generate_jobs(role, n)\n", + " parsed_jobs = extract_json_objects_from_text_block(raw_jobs)\n", + "\n", + " if not isinstance(parsed_jobs, list) or not all(isinstance(item, dict) for item in parsed_jobs):\n", + " print(\"[ERROR] Parsed result is not a list of dicts\")\n", + " return gr.update(value=[], visible=True), None\n", + "\n", + " filename = f\"{role.replace(' ', '_').lower()}_jobs.json\"\n", + " with open(filename, \"w\") as f:\n", + " json.dump(parsed_jobs, f, indent=2)\n", + "\n", + " print(f\"[INFO] Returning {len(parsed_jobs)} jobs -> {filename}\")\n", + " return parsed_jobs, filename\n", + "\n", + " except Exception as e:\n", + " print(f\"[FATAL ERROR] {e}\")\n", + " return gr.update(value=[], visible=True), None\n", + "\n", + "if __name__ == \"__main__\":\n", + " with gr.Blocks() as demo:\n", + " gr.Markdown(\"# 🧠 Synthetic Job Dataset Generator\")\n", + " gr.Markdown(\"Generate a structured dataset of job postings for a specific role.\")\n", + "\n", + " with gr.Row():\n", + " role_input = gr.Textbox(label=\"Job Role\", placeholder=\"e.g. Software Engineer\", value=\"Software Engineer\")\n", + " n_input = gr.Number(label=\"Number of Samples\", value=5, precision=0)\n", + "\n", + " generate_button = gr.Button(\"🚀 Generate\")\n", + " output_table = gr.JSON(label=\"Generated Dataset\")\n", + " download_button = gr.File(label=\"Download JSON\")\n", + "\n", + " generate_button.click(\n", + " generate_ui,\n", + " inputs=[role_input, n_input],\n", + " outputs=[output_table, download_button]\n", + " )\n", + "\n", + " demo.launch(debug=True)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 730, + "referenced_widgets": [ + "9f9defc39ac5437e9512e5fad810b409", + "1c126dfdc51c438b9b48c8a65e549ae2", + "741d800130ea4830b9266f467fa6a0bf", + "73c0a01f1693471c9c017143e9e9058b", + "ab8174c1337b43048e05aeca72ca18ef", + "5e5a992d86434e62a25fc9b7f75f4b16", + "1507b1310f5045c9b691fdb102cc1686", + "8a8e81f9d3a54ce49b367f8e984b4a06", + "bab02b1f092b40c8983cd6440f7eaf16", + "94f30dc2653a4f178c9c2ef454d24644", + "a508625ef12d4a639fa9773484507709" + ] + }, + "id": "FEByigZTo5cv", + "outputId": "e452754b-e155-4b57-eced-7af37996f1f0" + }, + "execution_count": 25, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "It looks like you are running Gradio on a hosted a Jupyter notebook. For the Gradio app to work, sharing must be enabled. Automatically setting `share=True` (you can turn this off by setting `share=False` in `launch()` explicitly).\n", + "\n", + "Colab notebook detected. This cell will run indefinitely so that you can see errors and logs. To turn off, set debug=False in launch().\n", + "* Running on public URL: https://bf27145eb99f8caadd.gradio.live\n", + "\n", + "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "
" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/2 [00:00 software_engineer_jobs.json\n", + "Keyboard interruption in main thread... closing server.\n", + "Killing tunnel 127.0.0.1:7860 <> https://bf27145eb99f8caadd.gradio.live\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "# Get list of all .ipynb files in /content\n", + "notebooks = [f for f in os.listdir(\"/content\") if f.endswith(\".ipynb\")]\n", + "print(notebooks)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZfPQJw0Z5UD9", + "outputId": "0e4ba82b-e23b-4faa-8b29-eaf87fdf9500" + }, + "execution_count": 27, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "Y88jqI_u5WEL" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/week4/community-contributions/Week4-Comments-Generator-DP.ipynb b/week4/community-contributions/Week4-Comments-Generator-DP.ipynb new file mode 100644 index 0000000..6b3b698 --- /dev/null +++ b/week4/community-contributions/Week4-Comments-Generator-DP.ipynb @@ -0,0 +1,400 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "3e473bbd-a0c2-43bd-bf99-c749784d00c3", + "metadata": {}, + "outputs": [], + "source": [ + "import gradio as gr\n", + "import openai\n", + "import anthropic\n", + "import google.generativeai as genai\n", + "import requests\n", + "import json\n", + "import os\n", + "from typing import Dict, Any, Optional\n", + "import asyncio\n", + "from dotenv import load_dotenv" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16210512-41f1-4de3-8348-2cd7129e023f", + "metadata": {}, + "outputs": [], + "source": [ + "# load API\n", + "load_dotenv(override=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6747e275-91eb-4d2b-90b6-805f2bd9b6b7", + "metadata": {}, + "outputs": [], + "source": [ + "class CodeCommenter:\n", + " def __init__(self):\n", + " # Initialize API clients\n", + " self.openai_client = None\n", + " self.anthropic_client = None\n", + " self.gemini_client = None\n", + " \n", + " # Load API keys from environment variables\n", + " self.setup_clients()\n", + " \n", + " def setup_clients(self):\n", + " \"\"\"Initialize API clients with keys from environment variables\"\"\"\n", + " try:\n", + " # OpenAI\n", + " openai_key = os.getenv('OPENAI_API_KEY')\n", + " if openai_key:\n", + " self.openai_client = openai.OpenAI(api_key=openai_key)\n", + " \n", + " # Anthropic\n", + " anthropic_key = os.getenv('ANTHROPIC_API_KEY')\n", + " if anthropic_key:\n", + " self.anthropic_client = anthropic.Anthropic(api_key=anthropic_key)\n", + " \n", + " # Google Gemini\n", + " gemini_key = os.getenv('GOOGLE_API_KEY')\n", + " if gemini_key:\n", + " genai.configure(api_key=gemini_key)\n", + " self.gemini_client = genai.GenerativeModel('gemini-2.0-flash-exp')\n", + " \n", + " except Exception as e:\n", + " print(f\"Warning: Error setting up API clients: {e}\")\n", + " \n", + " def create_prompt(self, code: str, language: str) -> str:\n", + " \"\"\"Create a prompt for the LLM to add comments and docstrings\"\"\"\n", + " return f\"\"\"Please add detailed and helpful comments and docstrings to the following {language} code. \n", + " \n", + "Guidelines:\n", + "1. Add comprehensive docstrings for functions, classes, and modules\n", + "2. Add inline comments explaining complex logic\n", + "3. Follow the commenting conventions for {language}\n", + "4. Maintain the original code structure and functionality\n", + "5. Make comments clear and professional\n", + "6. Don't change the actual code logic, only add comments\n", + "7. Do not add code markdown delimiters like ```python\n", + "\n", + "Here's the code to comment:\n", + "\n", + "{code}\n", + "\n", + "Please return only the commented code without any additional explanation or markdown formatting.\"\"\"\n", + "\n", + " def call_openai(self, prompt: str, model: str = \"gpt-4o-mini\") -> str:\n", + " \"\"\"Make API call to OpenAI\"\"\"\n", + " if not self.openai_client:\n", + " return \"Error: OpenAI API key not configured. Please set OPENAI_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.openai_client.chat.completions.create(\n", + " model=model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful coding assistant that adds detailed comments and docstrings to code.\"},\n", + " {\"role\": \"user\", \"content\": prompt}\n", + " ],\n", + " max_tokens=4000,\n", + " temperature=0.1\n", + " )\n", + " return response.choices[0].message.content.strip()\n", + " except Exception as e:\n", + " return f\"Error calling OpenAI API: {str(e)}\"\n", + " \n", + " def call_anthropic(self, prompt: str, model: str = \"claude-3-5-haiku-20241022\") -> str:\n", + " \"\"\"Make API call to Anthropic Claude\"\"\"\n", + " if not self.anthropic_client:\n", + " return \"Error: Anthropic API key not configured. Please set ANTHROPIC_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.anthropic_client.messages.create(\n", + " model=model,\n", + " max_tokens=4000,\n", + " temperature=0.1,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": prompt}\n", + " ]\n", + " )\n", + " return response.content[0].text.strip()\n", + " except Exception as e:\n", + " return f\"Error calling Anthropic API: {str(e)}\"\n", + " \n", + " def call_gemini(self, prompt: str) -> str:\n", + " \"\"\"Make API call to Google Gemini\"\"\"\n", + " if not self.gemini_client:\n", + " return \"Error: Google API key not configured. Please set GOOGLE_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.gemini_client.generate_content(\n", + " prompt,\n", + " generation_config=genai.types.GenerationConfig(\n", + " max_output_tokens=4000,\n", + " temperature=0.1,\n", + " )\n", + " )\n", + " return response.text.strip()\n", + " except Exception as e:\n", + " return f\"Error calling Gemini API: {str(e)}\"\n", + " \n", + " def call_ollama(self, prompt: str, model: str = \"llama3.2:latest\") -> str:\n", + " \"\"\"Make API call to Ollama (local)\"\"\"\n", + " try:\n", + " url = \"http://localhost:11434/api/generate\"\n", + " data = {\n", + " \"model\": model,\n", + " \"prompt\": prompt,\n", + " \"stream\": False,\n", + " \"options\": {\n", + " \"temperature\": 0.1,\n", + " \"num_predict\": 4000\n", + " }\n", + " }\n", + " \n", + " response = requests.post(url, json=data, timeout=60)\n", + " if response.status_code == 200:\n", + " result = response.json()\n", + " return result.get('response', '').strip()\n", + " else:\n", + " return f\"Error calling Ollama API: HTTP {response.status_code}\"\n", + " except requests.exceptions.ConnectionError:\n", + " return \"Error: Could not connect to Ollama. Make sure Ollama is running locally on port 11434.\"\n", + " except Exception as e:\n", + " return f\"Error calling Ollama API: {str(e)}\"\n", + "\n", + " def generate_comments(self, language: str, code: str, llm: str) -> str:\n", + " \"\"\"Generate comments for the given code using the specified LLM\"\"\"\n", + " if not code.strip():\n", + " return \"Error: Please provide code to comment.\"\n", + " \n", + " prompt = self.create_prompt(code, language)\n", + " \n", + " # Route to appropriate LLM\n", + " if llm == \"gpt-4o-mini\":\n", + " return self.call_openai(prompt, \"gpt-4o-mini\")\n", + " elif llm == \"claude-3-5-haiku-20241022\":\n", + " return self.call_anthropic(prompt, \"claude-3-5-haiku-20241022\")\n", + " elif llm == \"gemini-2.0-flash\":\n", + " return self.call_gemini(prompt)\n", + " elif llm == \"ollama:llama3.2:latest\":\n", + " return self.call_ollama(prompt, \"llama3.2:latest\")\n", + " else:\n", + " return f\"Error: Unsupported LLM: {llm}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "813f0911-d53f-4887-9341-656712e32d8f", + "metadata": {}, + "outputs": [], + "source": [ + "def create_gradio_interface():\n", + " \"\"\"Create and configure the Gradio interface\"\"\"\n", + " commenter = CodeCommenter()\n", + " \n", + " # Define the main function for the interface\n", + " def process_code(language, code, llm):\n", + " \"\"\"Process the code and return commented version\"\"\"\n", + " if not code.strip():\n", + " return \"Please enter some code to comment.\"\n", + " \n", + " # Show processing message\n", + " processing_msg = f\"Processing {language} code with {llm}...\"\n", + " print(processing_msg)\n", + " \n", + " # Generate comments\n", + " result = commenter.generate_comments(language, code, llm)\n", + " return result\n", + " \n", + " # Define default code\n", + " default_code = \"\"\"import pyodbc\n", + "from tabulate import tabulate\n", + "def connect_to_sql_server(server_name, database, username=None, password=None):\n", + " try:\n", + " if username and password:\n", + " connection_string = f\"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server_name};DATABASE={database};UID={username};PWD={password}\"\n", + " else:\n", + " connection_string = f\"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server_name};DATABASE={database};Trusted_Connection=yes\"\n", + " connection = pyodbc.connect(connection_string)\n", + " print(f\"Successfully connected to {server_name}/{database}\")\n", + " return connection\n", + " except Exception as e:\n", + " print(f\"Failed to connect to {server_name}/{database}: {str(e)}\")\n", + " return None\n", + "def get_record_count(connection, table_name):\n", + " try:\n", + " cursor = connection.cursor()\n", + " query = f\"SELECT COUNT(*) FROM {table_name}\"\n", + " cursor.execute(query)\n", + " count = cursor.fetchone()[0]\n", + " cursor.close()\n", + " print(f\"Record count for {table_name}: {count}\")\n", + " return count\n", + " except Exception as e:\n", + " print(f\"Failed to get record count for {table_name}: {str(e)}\")\n", + " return None\n", + "def select_top_records(connection, table_name, n):\n", + " try:\n", + " cursor = connection.cursor()\n", + " query = f\"SELECT TOP {n} * FROM {table_name}\"\n", + " cursor.execute(query)\n", + " records = cursor.fetchall()\n", + " columns = [column[0] for column in cursor.description]\n", + " cursor.close()\n", + " print(f\"Top {n} records from {table_name}\")\n", + " if records:\n", + " print(tabulate(records, headers=columns, tablefmt=\"grid\"))\n", + " return records\n", + " except Exception as e:\n", + " print(f\"Failed to retrieve top {n} records from {table_name}: {str(e)}\")\n", + " return None\n", + "conn = connect_to_sql_server(\"localhost\", \"AdventureWorks_lite\")\n", + "if conn:\n", + " total_records = get_record_count(conn, \"Sales.SalesOrderDetail\")\n", + " top_records = select_top_records(conn, \"Production.Product\", 10)\n", + " conn.close()\n", + " print(\"Connection closed successfully\")\"\"\"\n", + "\n", + " css = \"\"\"\n", + "textarea[rows]:not([rows=\"1\"]) {\n", + " overflow-y: auto !important;\n", + " scrollbar-width: thin !important;\n", + "}\n", + "textarea[rows]:not([rows=\"1\"])::-webkit-scrollbar {\n", + " all: initial !important;\n", + " background: #f1f1f1 !important;\n", + "}\n", + "textarea[rows]:not([rows=\"1\"])::-webkit-scrollbar-thumb {\n", + " all: initial !important;\n", + " background: #a8a8a8 !important;\n", + "}\n", + "\"\"\"\n", + "\n", + " # Create the interface\n", + " with gr.Blocks(title=\"Code Commenter\", theme=gr.themes.Base(), css=css) as interface:\n", + " gr.Markdown(\"# 🔧 Code Commenter\")\n", + " gr.Markdown(\"Add detailed comments and docstrings to your code using various LLM models.\")\n", + " \n", + " with gr.Row():\n", + " with gr.Column():\n", + " code_input = gr.Textbox(\n", + " label=\"Input Code\",\n", + " value=default_code,\n", + " lines=15,\n", + " max_lines=20,\n", + " info=\"Enter the code you want to add comments to\"\n", + " )\n", + " \n", + " with gr.Column():\n", + " code_output = gr.Textbox(\n", + " label=\"Commented Code\",\n", + " lines=20,\n", + " max_lines=20,\n", + " info=\"Your code with added comments and docstrings\"\n", + " )\n", + " \n", + " with gr.Row():\n", + " with gr.Column(scale=1):\n", + " language_dropdown = gr.Dropdown(\n", + " choices=[\"Python\", \"Ruby\", \"Rust\", \"C++\", \"Java\"],\n", + " value=\"Python\",\n", + " label=\"Programming Language\",\n", + " info=\"Select the programming language of your code\"\n", + " )\n", + " \n", + " llm_dropdown = gr.Dropdown(\n", + " choices=[\n", + " \"gpt-4o-mini\",\n", + " \"claude-3-5-haiku-20241022\", \n", + " \"gemini-2.0-flash\",\n", + " \"ollama:llama3.2:latest\"\n", + " ],\n", + " value=\"gpt-4o-mini\",\n", + " label=\"LLM Model\",\n", + " info=\"Choose the language model to use\"\n", + " )\n", + " \n", + " generate_btn = gr.Button(\n", + " \"🚀 Generate Comments\", \n", + " variant=\"primary\",\n", + " size=\"lg\"\n", + " )\n", + " \n", + " # Add some API setup information\n", + " gr.Markdown(\"## 📝 API Setup Instructions\")\n", + " gr.Markdown(\"\"\"\n", + " To use this tool, you need to set up API keys as environment variables:\n", + " \n", + " - **OpenAI**: Set `OPENAI_API_KEY`\n", + " - **Anthropic**: Set `ANTHROPIC_API_KEY` \n", + " - **Google Gemini**: Set `GOOGLE_API_KEY`\n", + " - **Ollama**: Make sure Ollama is running locally on port 11434\n", + " \"\"\")\n", + " \n", + " # Connect the button to the processing function\n", + " generate_btn.click(\n", + " fn=process_code,\n", + " inputs=[language_dropdown, code_input, llm_dropdown],\n", + " outputs=code_output,\n", + " show_progress=True\n", + " )\n", + " \n", + " return interface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef461e08-c1d5-406d-b7d2-a4329f16486e", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"🚀 Starting Code Commenter...\")\n", + "print(\"📋 Setting up Gradio interface...\")\n", + "\n", + "# Create and launch the interface\n", + "interface = create_gradio_interface()\n", + "\n", + "print(\"🌐 Launching interface...\")\n", + "print(\"💡 The interface will open in your default browser\")\n", + "print(\"🔧 Make sure to set up your API keys as environment variables\")\n", + "\n", + "# Launch with auto-opening in browser\n", + "interface.launch(\n", + " server_name=\"127.0.0.1\",\n", + " server_port=7860,\n", + " share=False,\n", + " inbrowser=True,\n", + " show_error=True\n", + ")" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week4/community-contributions/Week4_generate_comments_and_tests-DP.ipynb b/week4/community-contributions/Week4_generate_comments_and_tests-DP.ipynb new file mode 100644 index 0000000..09efe1d --- /dev/null +++ b/week4/community-contributions/Week4_generate_comments_and_tests-DP.ipynb @@ -0,0 +1,538 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "3e473bbd-a0c2-43bd-bf99-c749784d00c3", + "metadata": {}, + "outputs": [], + "source": [ + "import gradio as gr\n", + "import openai\n", + "import anthropic\n", + "import google.generativeai as genai\n", + "import requests\n", + "import json\n", + "import os\n", + "from typing import Dict, Any, Optional\n", + "import asyncio\n", + "from dotenv import load_dotenv" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "16210512-41f1-4de3-8348-2cd7129e023f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# load API\n", + "load_dotenv(override=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6747e275-91eb-4d2b-90b6-805f2bd9b6b7", + "metadata": {}, + "outputs": [], + "source": [ + "class CodeCommenter:\n", + " def __init__(self):\n", + " # Initialize API clients\n", + " self.openai_client = None\n", + " self.anthropic_client = None\n", + " self.gemini_client = None\n", + " \n", + " # Load API keys from environment variables\n", + " self.setup_clients()\n", + " \n", + " def setup_clients(self):\n", + " \"\"\"Initialize API clients with keys from environment variables\"\"\"\n", + " try:\n", + " # OpenAI\n", + " openai_key = os.getenv('OPENAI_API_KEY')\n", + " if openai_key:\n", + " self.openai_client = openai.OpenAI(api_key=openai_key)\n", + " \n", + " # Anthropic\n", + " anthropic_key = os.getenv('ANTHROPIC_API_KEY')\n", + " if anthropic_key:\n", + " self.anthropic_client = anthropic.Anthropic(api_key=anthropic_key)\n", + " \n", + " # Google Gemini\n", + " gemini_key = os.getenv('GOOGLE_API_KEY')\n", + " if gemini_key:\n", + " genai.configure(api_key=gemini_key)\n", + " self.gemini_client = genai.GenerativeModel('gemini-2.0-flash-exp')\n", + " \n", + " except Exception as e:\n", + " print(f\"Warning: Error setting up API clients: {e}\")\n", + " \n", + " def create_comments_prompt(self, code: str, language: str) -> str:\n", + " \"\"\"Create a prompt for the LLM to add comments and docstrings\"\"\"\n", + " return f\"\"\"Please add detailed and helpful comments and docstrings to the following {language} code. \n", + " \n", + "Guidelines:\n", + "1. Add comprehensive docstrings for functions, classes, and modules\n", + "2. Add inline comments explaining complex logic\n", + "3. Follow the commenting conventions for {language}\n", + "4. Maintain the original code structure and functionality\n", + "5. Make comments clear and professional\n", + "6. Don't change the actual code logic, only add comments\n", + "7. Do not add code markdown delimiters like ```python\n", + "\n", + "Here's the code to comment:\n", + "\n", + "{code}\n", + "\n", + "Please return only the commented code without any additional explanation or markdown formatting.\"\"\"\n", + "\n", + " def create_tests_prompt(self, code: str, language: str) -> str:\n", + " \"\"\"Create a prompt for the LLM to generate unit tests\"\"\"\n", + " return f\"\"\"Please generate comprehensive unit tests for the following {language} code.\n", + " \n", + "Guidelines:\n", + "1. Use appropriate testing framework for {language} (pytest for Python, JUnit for Java, etc.)\n", + "2. Create tests for all functions and methods\n", + "3. Include both positive and negative test cases\n", + "4. Test edge cases and error conditions\n", + "5. Use meaningful test names that describe what is being tested\n", + "6. Include setup and teardown methods if needed\n", + "7. Add mock objects for external dependencies (like database connections)\n", + "8. Do not add code markdown delimiters like ```python\n", + "9. Follow testing best practices for {language}\n", + "\n", + "Here's the code to test:\n", + "\n", + "{code}\n", + "\n", + "Please return only the unit test code without any additional explanation or markdown formatting.\"\"\"\n", + "\n", + " def create_combined_prompt(self, code: str, language: str) -> str:\n", + " \"\"\"Create a prompt for the LLM to add both comments and unit tests\"\"\"\n", + " return f\"\"\"Please add detailed comments and docstrings to the following {language} code AND generate comprehensive unit tests for it.\n", + " \n", + "For Comments:\n", + "1. Add comprehensive docstrings for functions, classes, and modules\n", + "2. Add inline comments explaining complex logic\n", + "3. Follow the commenting conventions for {language}\n", + "4. Don't change the actual code logic, only add comments\n", + "\n", + "For Unit Tests:\n", + "1. Use appropriate testing framework for {language} (pytest for Python, JUnit for Java, etc.)\n", + "2. Create tests for all functions and methods\n", + "3. Include both positive and negative test cases\n", + "4. Test edge cases and error conditions\n", + "5. Add mock objects for external dependencies (like database connections)\n", + "6. Follow testing best practices for {language}\n", + "\n", + "Structure your response as:\n", + "1. First, provide the original code with added comments and docstrings \n", + "2. Then, provide the unit tests as a separate section\n", + "3. Do not add code markdown delimiters like ```python\n", + "4. The 2 separated portions of code, comments and unit test should be clearly demarcated by comments specifying the following section purpose\n", + "\n", + "Here's the code:\n", + "\n", + "{code}\n", + "\n", + "Please return the commented code followed by the unit tests, clearly separated.\"\"\"\n", + "\n", + " def call_openai(self, prompt: str, model: str = \"gpt-4o-mini\") -> str:\n", + " \"\"\"Make API call to OpenAI\"\"\"\n", + " if not self.openai_client:\n", + " return \"Error: OpenAI API key not configured. Please set OPENAI_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.openai_client.chat.completions.create(\n", + " model=model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful coding assistant that adds detailed comments, docstrings, and generates unit tests for code.\"},\n", + " {\"role\": \"user\", \"content\": prompt}\n", + " ],\n", + " max_tokens=4000,\n", + " temperature=0.1\n", + " )\n", + " return response.choices[0].message.content.strip()\n", + " except Exception as e:\n", + " return f\"Error calling OpenAI API: {str(e)}\"\n", + " \n", + " def call_anthropic(self, prompt: str, model: str = \"claude-3-5-haiku-20241022\") -> str:\n", + " \"\"\"Make API call to Anthropic Claude\"\"\"\n", + " if not self.anthropic_client:\n", + " return \"Error: Anthropic API key not configured. Please set ANTHROPIC_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.anthropic_client.messages.create(\n", + " model=model,\n", + " max_tokens=4000,\n", + " temperature=0.1,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": prompt}\n", + " ]\n", + " )\n", + " return response.content[0].text.strip()\n", + " except Exception as e:\n", + " return f\"Error calling Anthropic API: {str(e)}\"\n", + " \n", + " def call_gemini(self, prompt: str) -> str:\n", + " \"\"\"Make API call to Google Gemini\"\"\"\n", + " if not self.gemini_client:\n", + " return \"Error: Google API key not configured. Please set GOOGLE_API_KEY environment variable.\"\n", + " \n", + " try:\n", + " response = self.gemini_client.generate_content(\n", + " prompt,\n", + " generation_config=genai.types.GenerationConfig(\n", + " max_output_tokens=4000,\n", + " temperature=0.1,\n", + " )\n", + " )\n", + " return response.text.strip()\n", + " except Exception as e:\n", + " return f\"Error calling Gemini API: {str(e)}\"\n", + " \n", + " def call_ollama(self, prompt: str, model: str = \"llama3.2:latest\") -> str:\n", + " \"\"\"Make API call to Ollama (local)\"\"\"\n", + " try:\n", + " url = \"http://localhost:11434/api/generate\"\n", + " data = {\n", + " \"model\": model,\n", + " \"prompt\": prompt,\n", + " \"stream\": False,\n", + " \"options\": {\n", + " \"temperature\": 0.1,\n", + " \"num_predict\": 4000\n", + " }\n", + " }\n", + " \n", + " response = requests.post(url, json=data, timeout=60)\n", + " if response.status_code == 200:\n", + " result = response.json()\n", + " return result.get('response', '').strip()\n", + " else:\n", + " return f\"Error calling Ollama API: HTTP {response.status_code}\"\n", + " except requests.exceptions.ConnectionError:\n", + " return \"Error: Could not connect to Ollama. Make sure Ollama is running locally on port 11434.\"\n", + " except Exception as e:\n", + " return f\"Error calling Ollama API: {str(e)}\"\n", + "\n", + " def process_code(self, language: str, code: str, llm: str, generate_comments: bool, generate_tests: bool) -> str:\n", + " \"\"\"Process the given code based on selected options\"\"\"\n", + " if not code.strip():\n", + " return \"Error: Please provide code to process.\"\n", + " \n", + " if not generate_comments and not generate_tests:\n", + " return \"Error: Please select at least one option (Generate comments or Generate test units).\"\n", + " \n", + " # Determine which prompt to use\n", + " if generate_comments and generate_tests:\n", + " prompt = self.create_combined_prompt(code, language)\n", + " elif generate_comments:\n", + " prompt = self.create_comments_prompt(code, language)\n", + " else: # generate_tests only\n", + " prompt = self.create_tests_prompt(code, language)\n", + " \n", + " # Route to appropriate LLM\n", + " if llm == \"gpt-4o-mini\":\n", + " return self.call_openai(prompt, \"gpt-4o-mini\")\n", + " elif llm == \"claude-3-5-haiku-20241022\":\n", + " return self.call_anthropic(prompt, \"claude-3-5-haiku-20241022\")\n", + " elif llm == \"gemini-2.0-flash\":\n", + " return self.call_gemini(prompt)\n", + " elif llm == \"ollama:llama3.2:latest\":\n", + " return self.call_ollama(prompt, \"llama3.2:latest\")\n", + " else:\n", + " return f\"Error: Unsupported LLM: {llm}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "813f0911-d53f-4887-9341-656712e32d8f", + "metadata": {}, + "outputs": [], + "source": [ + "def create_gradio_interface():\n", + " \"\"\"Create and configure the Gradio interface\"\"\"\n", + " commenter = CodeCommenter()\n", + " \n", + " # Define the main function for the interface\n", + " def process_code_interface(language, code, llm, generate_comments, generate_tests):\n", + " \"\"\"Process the code and return processed version based on selected options\"\"\"\n", + " if not code.strip():\n", + " return \"Please enter some code to process.\"\n", + " \n", + " if not generate_comments and not generate_tests:\n", + " return \"Please select at least one option: Generate comments or Generate test units.\"\n", + " \n", + " # Show processing message\n", + " options = []\n", + " if generate_comments:\n", + " options.append(\"comments\")\n", + " if generate_tests:\n", + " options.append(\"unit tests\")\n", + " \n", + " processing_msg = f\"Processing {language} code with {llm} to generate {' and '.join(options)}...\"\n", + " print(processing_msg)\n", + " \n", + " # Process the code\n", + " result = commenter.process_code(language, code, llm, generate_comments, generate_tests)\n", + " return result\n", + " \n", + " # Define default code\n", + " default_code = \"\"\"import pyodbc\n", + "from tabulate import tabulate\n", + "def connect_to_sql_server(server_name, database, username=None, password=None):\n", + " try:\n", + " if username and password:\n", + " connection_string = f\"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server_name};DATABASE={database};UID={username};PWD={password}\"\n", + " else:\n", + " connection_string = f\"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={server_name};DATABASE={database};Trusted_Connection=yes\"\n", + " connection = pyodbc.connect(connection_string)\n", + " print(f\"Successfully connected to {server_name}/{database}\")\n", + " return connection\n", + " except Exception as e:\n", + " print(f\"Failed to connect to {server_name}/{database}: {str(e)}\")\n", + " return None\n", + "def get_record_count(connection, table_name):\n", + " try:\n", + " cursor = connection.cursor()\n", + " query = f\"SELECT COUNT(*) FROM {table_name}\"\n", + " cursor.execute(query)\n", + " count = cursor.fetchone()[0]\n", + " cursor.close()\n", + " print(f\"Record count for {table_name}: {count}\")\n", + " return count\n", + " except Exception as e:\n", + " print(f\"Failed to get record count for {table_name}: {str(e)}\")\n", + " return None\n", + "def select_top_records(connection, table_name, n):\n", + " try:\n", + " cursor = connection.cursor()\n", + " query = f\"SELECT TOP {n} * FROM {table_name}\"\n", + " cursor.execute(query)\n", + " records = cursor.fetchall()\n", + " columns = [column[0] for column in cursor.description]\n", + " cursor.close()\n", + " print(f\"Top {n} records from {table_name}\")\n", + " if records:\n", + " print(tabulate(records, headers=columns, tablefmt=\"grid\"))\n", + " return records\n", + " except Exception as e:\n", + " print(f\"Failed to retrieve top {n} records from {table_name}: {str(e)}\")\n", + " return None\n", + "conn = connect_to_sql_server(\"localhost\", \"AdventureWorks_lite\")\n", + "if conn:\n", + " total_records = get_record_count(conn, \"Sales.SalesOrderDetail\")\n", + " top_records = select_top_records(conn, \"Production.Product\", 10)\n", + " conn.close()\n", + " print(\"Connection closed successfully\")\"\"\"\n", + "\n", + " css = \"\"\"\n", + "textarea[rows]:not([rows=\"1\"]) {\n", + " overflow-y: auto !important;\n", + " scrollbar-width: thin !important;\n", + "}\n", + "textarea[rows]:not([rows=\"1\"])::-webkit-scrollbar {\n", + " all: initial !important;\n", + " background: #f1f1f1 !important;\n", + "}\n", + "textarea[rows]:not([rows=\"1\"])::-webkit-scrollbar-thumb {\n", + " all: initial !important;\n", + " background: #a8a8a8 !important;\n", + "}\n", + "\"\"\"\n", + "\n", + " # Create the interface\n", + " with gr.Blocks(title=\"Code Commenter & Test Generator\", theme=gr.themes.Base(), css=css) as interface:\n", + " gr.Markdown(\"# 🔧 Code Commenter & Test Generator\")\n", + " gr.Markdown(\"Add detailed comments, docstrings, and/or generate unit tests for your code using various LLM models.\")\n", + " \n", + " with gr.Row():\n", + " with gr.Column():\n", + " code_input = gr.Textbox(\n", + " label=\"Input Code\",\n", + " value=default_code,\n", + " lines=15,\n", + " max_lines=20,\n", + " info=\"Enter the code you want to process\"\n", + " )\n", + " \n", + " with gr.Column():\n", + " code_output = gr.Textbox(\n", + " label=\"Processed Code\",\n", + " lines=20,\n", + " max_lines=20,\n", + " info=\"Your code with added comments, docstrings, and/or unit tests\"\n", + " )\n", + " \n", + " # Add checkboxes below the textboxes\n", + " with gr.Row():\n", + " with gr.Column():\n", + " generate_comments_checkbox = gr.Checkbox(\n", + " label=\"Generate comments\",\n", + " value=True,\n", + " info=\"Add detailed comments and docstrings to the code\"\n", + " )\n", + " generate_tests_checkbox = gr.Checkbox(\n", + " label=\"Generate test units\",\n", + " value=False,\n", + " info=\"Generate comprehensive unit tests for the code\"\n", + " )\n", + " \n", + " with gr.Row():\n", + " with gr.Column(scale=1):\n", + " language_dropdown = gr.Dropdown(\n", + " choices=[\"Python\", \"Ruby\", \"Rust\", \"C++\", \"Java\"],\n", + " value=\"Python\",\n", + " label=\"Programming Language\",\n", + " info=\"Select the programming language of your code\"\n", + " )\n", + " \n", + " llm_dropdown = gr.Dropdown(\n", + " choices=[\n", + " \"gpt-4o-mini\",\n", + " \"claude-3-5-haiku-20241022\", \n", + " \"gemini-2.0-flash\",\n", + " \"ollama:llama3.2:latest\"\n", + " ],\n", + " value=\"gpt-4o-mini\",\n", + " label=\"LLM Model\",\n", + " info=\"Choose the language model to use\"\n", + " )\n", + " \n", + " generate_btn = gr.Button(\n", + " \"🚀 Process Code\", \n", + " variant=\"primary\",\n", + " size=\"lg\"\n", + " )\n", + " \n", + " # Add some API setup information\n", + " gr.Markdown(\"## 📝 API Setup Instructions\")\n", + " gr.Markdown(\"\"\"\n", + " To use this tool, you need to set up API keys as environment variables:\n", + " \n", + " - **OpenAI**: Set `OPENAI_API_KEY`\n", + " - **Anthropic**: Set `ANTHROPIC_API_KEY` \n", + " - **Google Gemini**: Set `GOOGLE_API_KEY`\n", + " - **Ollama**: Make sure Ollama is running locally on port 11434\n", + " \"\"\")\n", + " \n", + " gr.Markdown(\"## ✨ Features\")\n", + " gr.Markdown(\"\"\"\n", + " - **Generate Comments**: Add detailed docstrings and inline comments\n", + " - **Generate Unit Tests**: Create comprehensive test suites with mocking for external dependencies\n", + " - **Combined Mode**: Generate both comments and unit tests in one go\n", + " - **Multiple LLMs**: Choose from OpenAI, Anthropic, Google Gemini, or local Ollama models\n", + " - **Multiple Languages**: Support for Python, Ruby, Rust, C++, and Java\n", + " \"\"\")\n", + " \n", + " # Connect the button to the processing function\n", + " generate_btn.click(\n", + " fn=process_code_interface,\n", + " inputs=[language_dropdown, code_input, llm_dropdown, generate_comments_checkbox, generate_tests_checkbox],\n", + " outputs=code_output,\n", + " show_progress=True\n", + " )\n", + " \n", + " return interface" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ef461e08-c1d5-406d-b7d2-a4329f16486e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🚀 Starting Code Commenter & Test Generator...\n", + "📋 Setting up Gradio interface...\n", + "🌐 Launching interface...\n", + "💡 The interface will open in your default browser\n", + "🔧 Make sure to set up your API keys as environment variables\n", + "* 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": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(\"🚀 Starting Code Commenter & Test Generator...\")\n", + "print(\"📋 Setting up Gradio interface...\")\n", + "\n", + "# Create and launch the interface\n", + "interface = create_gradio_interface()\n", + "\n", + "print(\"🌐 Launching interface...\")\n", + "print(\"💡 The interface will open in your default browser\")\n", + "print(\"🔧 Make sure to set up your API keys as environment variables\")\n", + "\n", + "# Launch with auto-opening in browser\n", + "interface.launch(\n", + " server_name=\"127.0.0.1\",\n", + " server_port=7860,\n", + " share=False,\n", + " inbrowser=True,\n", + " show_error=True\n", + ")" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week4/community-contributions/day5_java_code_commenter.ipynb b/week4/community-contributions/day5_java_code_commenter.ipynb new file mode 100644 index 0000000..49ef719 --- /dev/null +++ b/week4/community-contributions/day5_java_code_commenter.ipynb @@ -0,0 +1,300 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "45ca91c2", + "metadata": {}, + "source": [ + "# AI tool to add comments to the provided Java code\n", + "\n", + "Here we build a Gradio App that uses the frontier models to add comments to a java code. For testing purposes I have used the *cheaper* versions of the models, not the ones the leaderboards indicate as the best ones." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f44901f5", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import google.generativeai as genai\n", + "import anthropic\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c47706b3", + "metadata": {}, + "outputs": [], + "source": [ + "# environment\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')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35446b9a", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "claude = anthropic.Anthropic()\n", + "genai.configure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e899efd", + "metadata": {}, + "outputs": [], + "source": [ + "OPENAI_MODEL = \"gpt-4o-mini\"\n", + "CLAUDE_MODEL = \"claude-3-haiku-20240307\"\n", + "GEMINI_MODEL = 'gemini-2.0-flash-lite'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47640f53", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are an assistant that adds comments to java code. \"\n", + "system_message += \"Do not make any changes to the code itself.\"\n", + "system_message += \"Use comments sparingly. Only add them in places where they help to undestand how the code works. Do not comment every single line of the code.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f41ccbf0", + "metadata": {}, + "outputs": [], + "source": [ + "def user_prompt_for(code):\n", + " user_prompt = \"Add helpful comments to this java code. \"\n", + " user_prompt += \"Do not change the code itself.\\n\\n\"\n", + " user_prompt += code\n", + " return user_prompt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c57c0000", + "metadata": {}, + "outputs": [], + "source": [ + "test_code = \"\"\"\n", + "package com.hma.kafkaproducertest.producer;\n", + "\n", + "import com.hma.kafkaproducertest.model.TestDTO;\n", + "import org.springframework.cloud.stream.function.StreamBridge;\n", + "import org.springframework.messaging.Message;\n", + "import org.springframework.messaging.support.MessageBuilder;\n", + "import org.springframework.stereotype.Component;\n", + "\n", + "import java.util.Arrays;\n", + "import java.util.Comparator;\n", + "import java.util.StringJoiner;\n", + "import java.util.stream.Collectors;\n", + "import java.util.stream.IntStream;\n", + "\n", + "@Component\n", + "public class TestProducer {\n", + "\n", + " public static final String EVENT_TYPE_HEADER = \"event-type\";\n", + " private static final String BINDING_NAME = \"testProducer-out-0\";\n", + "\n", + " private final StreamBridge streamBridge;\n", + "\n", + " public TestProducer(StreamBridge streamBridge) {\n", + " this.streamBridge = streamBridge;\n", + " }\n", + "\n", + " public void sendMessage(TestDTO payload, String eventType){\n", + " Message message = MessageBuilder\n", + " .withPayload(payload)\n", + " .setHeader(EVENT_TYPE_HEADER, eventType)\n", + " .build();\n", + "\n", + " streamBridge.send(BINDING_NAME, message);\n", + " }\n", + "\n", + " public void test(String t1, String t2) {\n", + " var s = t1.length() > t2.length() ? t2 : t1;\n", + " var l = t1.length() > t2.length() ? t1 : t2;\n", + " var res = true;\n", + " for (int i = 0; i < s.length(); i++) {\n", + " if (s.charAt(i) == l.charAt(i)) {\n", + " res = false;\n", + " break;\n", + " }\n", + " }\n", + " System.out.println(res);\n", + " }\n", + "}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00c71128", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_gpt(code):\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(code)}\n", + " ]\n", + " stream = openai.chat.completions.create(\n", + " model=OPENAI_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": "ca92f8a8", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_claude(code):\n", + " result = claude.messages.stream(\n", + " model=CLAUDE_MODEL,\n", + " max_tokens=2000,\n", + " system=system_message,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": user_prompt_for(code)},\n", + " ],\n", + " )\n", + " response = \"\"\n", + " with result as stream:\n", + " for text in stream.text_stream:\n", + " response += text or \"\"\n", + " yield response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9dffed4b", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_gemini(code):\n", + " gemini = genai.GenerativeModel(\n", + " model_name=GEMINI_MODEL,\n", + " system_instruction=system_message\n", + " )\n", + " stream = gemini.generate_content(user_prompt_for(code), stream=True)\n", + " result = \"\"\n", + " for chunk in stream:\n", + " result += chunk.text or \"\"\n", + " yield result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31f9c267", + "metadata": {}, + "outputs": [], + "source": [ + "def comment_code(code, model):\n", + " if model==\"GPT\":\n", + " result = stream_gpt(code)\n", + " elif model==\"Claude\":\n", + " result = stream_claude(code)\n", + " elif model==\"Gemini\":\n", + " result = stream_gemini(code)\n", + " else:\n", + " raise ValueError(\"Unknown model\")\n", + " yield from result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04c0a1b", + "metadata": {}, + "outputs": [], + "source": [ + "with gr.Blocks() as ui:\n", + " with gr.Row():\n", + " original_code = gr.Textbox(label=\"Java code:\", lines=10, value=test_code)\n", + " commented_code = gr.Markdown(label=\"Commented code:\")\n", + " with gr.Row():\n", + " model = gr.Dropdown([\"GPT\", \"Claude\", \"Gemini\"], label=\"Select model\", value=\"GPT\")\n", + " comment = gr.Button(\"Comment code\")\n", + "\n", + " comment.click(comment_code, inputs=[original_code, model], outputs=[commented_code])\n", + "\n", + "ui.launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84d33a5f", + "metadata": {}, + "outputs": [], + "source": [ + "ui.close()" + ] + }, + { + "cell_type": "markdown", + "id": "bbd50bf7", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "In my personal opinion, at least when using these *cheaper* versions of the models, the result provided by Claude is the best. ChatGPT adds way too many comments even if the system message discourages that. Gemini provides a good result also, but maybe adds a tad too few comments -- although that certainly depends on your personal preferences." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "llms", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week4/community-contributions/day5_java_unit_test_generator.ipynb b/week4/community-contributions/day5_java_unit_test_generator.ipynb new file mode 100644 index 0000000..39e30e3 --- /dev/null +++ b/week4/community-contributions/day5_java_unit_test_generator.ipynb @@ -0,0 +1,281 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "45ca91c2", + "metadata": {}, + "source": [ + "# AI tool to generate unit tests for the provided Java code\n", + "\n", + "Here we build a Gradio App that uses the frontier models to generate unit tests for a java code. For testing purposes I have used the *cheaper* versions of the models, not the ones the leaderboards indicate as the best ones." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f44901f5", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import google.generativeai as genai\n", + "import anthropic\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c47706b3", + "metadata": {}, + "outputs": [], + "source": [ + "# environment\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')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35446b9a", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI()\n", + "claude = anthropic.Anthropic()\n", + "genai.configure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e899efd", + "metadata": {}, + "outputs": [], + "source": [ + "OPENAI_MODEL = \"gpt-4o-mini\"\n", + "CLAUDE_MODEL = \"claude-3-haiku-20240307\"\n", + "GEMINI_MODEL = 'gemini-2.0-flash-lite'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47640f53", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are an assistant that generates unit test for java code. \"\n", + "system_message += \"Generate one JUnit5 test class with all the relevant test cases in it.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f41ccbf0", + "metadata": {}, + "outputs": [], + "source": [ + "def user_prompt_for(code):\n", + " user_prompt = \"Generate unit tests for this java code.\\n\\n\"\n", + " user_prompt += code\n", + " return user_prompt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c57c0000", + "metadata": {}, + "outputs": [], + "source": [ + "test_code = \"\"\"\n", + "package com.hma.kafkaproducertest.rest;\n", + "\n", + "import com.hma.kafkaproducertest.model.TestDTO;\n", + "import com.hma.kafkaproducertest.producer.TestProducer;\n", + "import org.springframework.web.bind.annotation.*;\n", + "\n", + "@RestController\n", + "@RequestMapping(\"/api\")\n", + "public class TestController {\n", + "\n", + " private final TestProducer producer;\n", + "\n", + " public TestController(TestProducer producer) {\n", + " this.producer = producer;\n", + " }\n", + "\n", + " @PostMapping(\"/event\")\n", + " public TestDTO triggerKafkaEvent(@RequestBody TestDTO payload) {\n", + " producer.sendMessage(payload, \"test\");\n", + " return payload;\n", + " }\n", + "\n", + "}\n", + "\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00c71128", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_gpt(code):\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt_for(code)}\n", + " ]\n", + " stream = openai.chat.completions.create(\n", + " model=OPENAI_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": "ca92f8a8", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_claude(code):\n", + " result = claude.messages.stream(\n", + " model=CLAUDE_MODEL,\n", + " max_tokens=2000,\n", + " system=system_message,\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": user_prompt_for(code)},\n", + " ],\n", + " )\n", + " response = \"\"\n", + " with result as stream:\n", + " for text in stream.text_stream:\n", + " response += text or \"\"\n", + " yield response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9dffed4b", + "metadata": {}, + "outputs": [], + "source": [ + "def stream_gemini(code):\n", + " gemini = genai.GenerativeModel(\n", + " model_name=GEMINI_MODEL,\n", + " system_instruction=system_message\n", + " )\n", + " stream = gemini.generate_content(user_prompt_for(code), stream=True)\n", + " result = \"\"\n", + " for chunk in stream:\n", + " result += chunk.text or \"\"\n", + " yield result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31f9c267", + "metadata": {}, + "outputs": [], + "source": [ + "def generate_tests(code, model):\n", + " if model==\"GPT\":\n", + " result = stream_gpt(code)\n", + " elif model==\"Claude\":\n", + " result = stream_claude(code)\n", + " elif model==\"Gemini\":\n", + " result = stream_gemini(code)\n", + " else:\n", + " raise ValueError(\"Unknown model\")\n", + " yield from result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04c0a1b", + "metadata": {}, + "outputs": [], + "source": [ + "with gr.Blocks() as ui:\n", + " with gr.Row():\n", + " original_code = gr.Textbox(label=\"Java code:\", lines=10, value=test_code)\n", + " generated_code = gr.Markdown(label=\"Unit tests:\")\n", + " with gr.Row():\n", + " model = gr.Dropdown([\"GPT\", \"Claude\", \"Gemini\"], label=\"Select model\", value=\"GPT\")\n", + " generate = gr.Button(\"Generate tests\")\n", + "\n", + " generate.click(generate_tests, inputs=[original_code, model], outputs=[generated_code])\n", + "\n", + "ui.launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84d33a5f", + "metadata": {}, + "outputs": [], + "source": [ + "ui.close()" + ] + }, + { + "cell_type": "markdown", + "id": "bbd50bf7", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "The models are missing some information as the `TestDTO` is not defined in the code provided as an input.\n", + "\n", + "Results:\n", + "- Gemini: Generates a well constructed test class with multiple test cases covering scenarios with valid and invalid inputs. It makes assumptions about the content of `TestDTO` and adds a note about those as a comment.\n", + "- Claude: Similar approach to unknown format of `TestDTO`, although no comment added about the assumptions made. The test cases are strutured differently, and they don't cover any case of invalid input, which in my opinion is an important test for a REST endpoint.\n", + "- GPT: While the other two generated *real* unit tests using the mockito extension, GPT generated a *webMVC* test. The other two relied on the equality impelemntation of `TestDTO`, while GPT checks separately each field in the response. As this type of test spins up the application context, the test won't run without additional configuration. In addition, some imports are missing from the test file.\n", + "\n", + "It comes down to personal preferences, but I would give the point to Gemini for this one." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "llms", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week5/community-contributions/08_rag_qa_assistant.ipynb b/week5/community-contributions/08_rag_qa_assistant.ipynb new file mode 100644 index 0000000..2d0affb --- /dev/null +++ b/week5/community-contributions/08_rag_qa_assistant.ipynb @@ -0,0 +1,710 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "3f78498d-dbc6-4e1b-a629-9ac9e44c8dd8", + "metadata": {}, + "source": [ + "# RAG-powered Q&A agent for Insurellm employees\n", + "---\n", + "\n", + "An internal expert knowledge assistant for Insurellm employees, using Retrieval-Augmented Generation (RAG) to deliver fast, accurate, and cost-efficient answers to a wide range of internal queries,\n", + "\n", + "- 🌍 Task: Answer questions about Insurellm using naive RAG\n", + "- 🧠 Models: OpenAI GPT via LangChain\n", + "- 🔍 Retrieval: ChromaDB + OpenAI embeddings\n", + "- 🚀 Tools:\n", + " - langchain: 0.3.21\n", + " - openai: 1.69.0\n", + " - chromadb: 0.6.3\n", + " - gradio: 5.23.1\n", + " - python: 3.11.11\n", + "\n", + "- ✨ Features:\n", + "\n", + " - Loads PDF, text, and markdown files automatically\n", + " - Only updates when files actually change (saves time)\n", + " - Breaks documents into small, overlapping pieces for better search\n", + " - Finds the most relevant information using smart matching\n", + " - Remembers conversation history and shows where answers come from\n", + " - Only answers based on your documents (no made-up information\n", + " - Web chat interface with streaming responses\n", + " - Handles errors gracefully and detects duplicate content\n", + " - Tracks document details and keeps everything organized\n", + " - Ready for business use with built-in quality checks\n", + "\n", + "- 📤 Output: Streaming response with sources retrieved from the knowledge base\n", + "- 🧑‍💻 Skill Level: Intermediate\n", + "- ⚙️ Hardware: ✅ CPU is sufficient — no GPU required\n", + "\n", + "🛠️ **Requirements**: 🔑 OpenAI API Key \n", + "\n", + "⚙️ **Customizable by user**\n", + "- 📝 Modify system and expansion prompts\n", + "- 📁 Drop in new company documents\n", + "- 🎯 Adjust retrieval top-k and similarity threshold\n", + "\n", + "This project currently uses a naive RAG approach, which limits the assistant's performance and accuracy. To improve response quality and reliability, more advanced RAG techniques will be needed — a more refined and powerful version is planned for future release.\n", + "\n", + "![](https://github.com/lisekarimi/lexo/blob/main/assets/08_naive_rag.png?raw=true)\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "b9abf112-72ca-431a-b7cf-b126e0a69a4d", + "metadata": {}, + "source": [ + "## 📥 Imports" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abdef4fe-5055-4259-99c7-82a0525c0d35", + "metadata": {}, + "outputs": [], + "source": [ + "# Standard library imports\n", + "import os\n", + "import hashlib\n", + "from pathlib import Path\n", + "from typing import List\n", + "\n", + "# Third-party imports\n", + "import numpy as np\n", + "import plotly.graph_objects as go\n", + "from dotenv import load_dotenv\n", + "from pydantic import Field\n", + "from sklearn.manifold import TSNE\n", + "import gradio as gr\n", + "\n", + "# LangChain core imports\n", + "from langchain.document_loaders import TextLoader, PyPDFLoader\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.schema import BaseRetriever, Document\n", + "from langchain.schema.vectorstore import VectorStoreRetriever\n", + "from langchain.callbacks.manager import CallbackManagerForRetrieverRun\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "from langchain.prompts import PromptTemplate\n", + "\n", + "# LangChain integrations\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_chroma import Chroma" + ] + }, + { + "cell_type": "markdown", + "id": "79875c2d-4193-4fa8-95b8-ad128b1c84fb", + "metadata": {}, + "source": [ + "## 🔐 Load env variables and configuration" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b5ca4dd-a1c2-4fc6-844f-7b0c83008c99", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables\n", + "load_dotenv(override=True)\n", + "\n", + "# Configuration\n", + "DATA_PATH = \"data/knowledge-base/\" # Use your path\n", + "MODEL = \"gpt-4o-mini\"\n", + "CHROMA_PATH = \"vector_db/chroma_insurellm\"\n", + "\n", + "# Explicitly access the OpenAI API key\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if not openai_api_key:\n", + " print(\"❌ OPENAI_API_KEY is missing\")" + ] + }, + { + "cell_type": "markdown", + "id": "18e5b9a1-dca8-4b42-8517-174f653f30a7", + "metadata": {}, + "source": [ + "## 📄 Load files as Document objects into memory" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae72f98b-05a5-4758-9503-424a93055323", + "metadata": {}, + "outputs": [], + "source": [ + "# Load .pdf, .txt, and .md documents with metadata, excluding Jupyter checkpoints.\n", + "\n", + "documents = []\n", + "\n", + "def add_metadata(doc, file_path):\n", + " doc.metadata[\"doc_type\"] = file_path.parent.name\n", + " doc.metadata[\"file_name\"] = file_path.name\n", + " if not doc.page_content.strip():\n", + " print(f\"⚠️ Empty content in {file_path}\")\n", + " # else:\n", + " # print(doc)\n", + " # print(\"-\" * 40)\n", + " return doc\n", + "\n", + "for file_path in Path(DATA_PATH).rglob(\"*\"):\n", + " if \".ipynb_checkpoints\" in file_path.parts:\n", + " continue\n", + "\n", + " try:\n", + " if file_path.name.endswith(\".pdf\"):\n", + " docs = PyPDFLoader(str(file_path)).load()\n", + " elif file_path.name.endswith((\".txt\", \".md\")):\n", + " docs = TextLoader(str(file_path), encoding=\"utf-8\").load()\n", + " else:\n", + " continue\n", + " except Exception as e:\n", + " print(f\"❌ Skipped {file_path}: {e}\")\n", + " continue\n", + "\n", + " documents.extend([add_metadata(doc, file_path) for doc in docs])\n", + "\n", + "print(f\"{len(documents)} documents loaded.\" if documents else \"No documents loaded.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "ed0fcc85-ca14-430a-bde2-db3d77f79143", + "metadata": {}, + "source": [ + "## ✂️ Splitting documents into chunks" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e40d0487-6db4-4c3f-b0c6-e9aaf4e14b37", + "metadata": {}, + "outputs": [], + "source": [ + "# Split documents into smaller chunks with overlapping characters for better context.\n", + "text_splitter = CharacterTextSplitter(\n", + " chunk_size=1000,\n", + " chunk_overlap=200,\n", + " add_start_index=True # Maintain chunk order (useful for context tracking)\n", + ")\n", + "\n", + "# Load and split documents\n", + "chunks = text_splitter.split_documents(documents)\n", + "\n", + "print(f\"Split {len(documents)} documents into {len(chunks)} chunks.\")\n", + "\n", + "def generate_chunk_id(text):\n", + " return hashlib.md5(text.encode(\"utf-8\")).hexdigest()\n", + "\n", + "# Add chunk_id to each chunk's metadata\n", + "for chunk in chunks:\n", + " chunk.metadata[\"chunk_id\"] = generate_chunk_id(chunk.page_content) # Create an MD5 hash of the chunk's content\n", + " if not chunk.page_content.strip():\n", + " print(f\"⚠️ Empty chunk from: {chunk.metadata['file_name']}\")\n", + "\n", + "# Debug: print a few chunk metadatas to verify chunk_id is added\n", + "for i, chunk in enumerate(chunks[:2]):\n", + " print(f\"Chunk {i+1} metadata:\", chunk.metadata)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1faa604c-ddd9-4475-aaff-f4456629d77d", + "metadata": {}, + "outputs": [], + "source": [ + "# Check for duplicate chunk IDs\n", + "chunk_ids = [chunk.metadata[\"chunk_id\"] for chunk in chunks]\n", + "duplicate_ids = [chunk_id for chunk_id in chunk_ids if chunk_ids.count(chunk_id) > 1]\n", + "\n", + "if duplicate_ids:\n", + " print(f\"Duplicate chunk IDs found: {duplicate_ids}\")\n", + "else:\n", + " print(\"No duplicate chunks.\")" + ] + }, + { + "cell_type": "markdown", + "id": "d73f6bee-5df5-422a-a03f-e117a858370b", + "metadata": {}, + "source": [ + "## 🧠 Chuncks Embedding" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0135e85-6e0b-45a4-ab0d-b9fec56b63ac", + "metadata": {}, + "outputs": [], + "source": [ + "embedding_function = OpenAIEmbeddings()\n", + "# By default, OpenAIEmbeddings() uses OpenAI's text-embedding-ada-002 model - a multilingual model" + ] + }, + { + "cell_type": "markdown", + "id": "dbdb70eb-9902-4065-92b7-c72c2b8e15f7", + "metadata": {}, + "source": [ + "## 💾 Save embedded chunks to Chroma database" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "093959f0-6826-4594-9338-598094e24923", + "metadata": {}, + "outputs": [], + "source": [ + "os.makedirs(CHROMA_PATH, exist_ok=True)\n", + "\n", + "def get_existing_chunk_ids(db_path):\n", + " try:\n", + " db_existing = Chroma(persist_directory=db_path)\n", + " results = db_existing._collection.get(include=[\"metadatas\"])\n", + " return set(\n", + " m[\"chunk_id\"] for m in results[\"metadatas\"]\n", + " if isinstance(m, dict) and \"chunk_id\" in m\n", + " )\n", + " except Exception as e:\n", + " print(\"❌ Error loading existing chunk IDs:\", e)\n", + " return set()\n", + "\n", + "# Get chunk_ids of current chunks\n", + "new_chunk_ids = set([chunk.metadata[\"chunk_id\"] for chunk in chunks])\n", + "\n", + "# Get existing chunk_ids from Chroma\n", + "existing_chunk_ids = get_existing_chunk_ids(CHROMA_PATH)\n", + "\n", + "# Compare\n", + "if new_chunk_ids != existing_chunk_ids:\n", + " print(\"Chunk changes detected. Rebuilding Chroma DB.\")\n", + " db = Chroma.from_documents(documents=chunks, embedding=embedding_function, persist_directory=CHROMA_PATH)\n", + " print(f\"Saved {len(chunks)} chunks to {CHROMA_PATH}.\")\n", + "else:\n", + " db = Chroma(persist_directory=CHROMA_PATH, embedding_function=embedding_function)\n", + " print(\"Chroma DB is up to date. Skipping regeneration.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "670b049a-0eca-41c1-a5a8-8ed4561168b2", + "metadata": {}, + "source": [ + "## 📊 Visualizing the Vector Store" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1179ca76-2502-4bea-a4d8-4cbe149e92fa", + "metadata": {}, + "outputs": [], + "source": [ + "collection = db._collection\n", + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "metadatas = result['metadatas']\n", + "doc_types = [metadata['doc_type'] for metadata in metadatas]\n", + "colors = [['blue', '#4B0082', 'red', '#8B4513'][['products', 'employees', 'contracts', 'company'].index(t)] for t in doc_types]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c18bd18c-0b6c-4206-b2d0-a1bb59b3d39e", + "metadata": {}, + "outputs": [], + "source": [ + "# We humans find it easier to visalize things in 2D!\n", + "# Reduce the dimensionality of the vectors to 2D using t-SNE\n", + "# (t-distributed stochastic neighbor embedding)\n", + "\n", + "tsne = TSNE(n_components=2, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 2D scatter plot\n", + "fig = go.Figure(data=[go.Scatter(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " mode='markers',\n", + " marker=dict(size=8, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='2D Chroma Vector Store Visualization',\n", + " plot_bgcolor='black',\n", + " paper_bgcolor='black',\n", + " font=dict(color='black'),\n", + " xaxis=dict(gridcolor='lightgray', zerolinecolor='lightgray'),\n", + " yaxis=dict(gridcolor='lightgray', zerolinecolor='lightgray'),\n", + " width=800,\n", + " height=600,\n", + " margin=dict(r=20, b=10, l=10, t=40),\n", + ")\n", + "\n", + "\n", + "fig.show()" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "b7d527de", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71364356-7edb-4e72-a7ba-f6284d4a998d", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's try 3D!\n", + "\n", + "tsne = TSNE(n_components=3, random_state=42)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 3D scatter plot\n", + "fig = go.Figure(data=[go.Scatter3d(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " z=reduced_vectors[:, 2],\n", + " mode='markers',\n", + " marker=dict(size=8, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='3D Chroma Vector Store Visualization',\n", + " plot_bgcolor='black',\n", + " paper_bgcolor='black',\n", + " font=dict(color='white'),\n", + " scene=dict(\n", + " xaxis=dict(color='white', backgroundcolor='black', showbackground=True),\n", + " yaxis=dict(color='white', backgroundcolor='black', showbackground=True),\n", + " zaxis=dict(color='white', backgroundcolor='black', showbackground=True)\n", + " ),\n", + " width=900,\n", + " height=700,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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jovgpDqW0aavzqcnVxaTK2CJTa6EZVVFS2yiWppgVDFLruTlZb8ofyy88MILnit0iWskfw/9Jn+/fZP3Jr//fen6ydfE6FroyefayTUw2uTvKxi9B6Pjg3id4hiZ0c+H1WZ3/Yxei9F1Mnqt8nU3u8/k9/Kabp0xN1Xy5K8j079G+XfGs/XS5vJ5MLuW8msRm3xujI4xe65RWXJu3Lhx4xb+7UCLaxj5/XXMNr+/ttN1kOTncbPeDtT/h4iIiIiIiCSuhuQRERERERH1EwYmIiIiIiIiEwxMREREREREJhiYiIiIiIiITDAwERERERERmWBgIiIiIiIiMsHAREREREREZIKBiYiIiIiIyAQDExERERERkQkGJiIiIiIiIhMMTERERERERCYYmIiIiIiIiEwwMBEREREREZlgYCIiIiIiIjLBwERERERERGSCgYmIiIiIiMgEAxMREREREZEJBiYiIiIiIiITDExEREREREQmGJiIiIiIiIhMMDARERERERGZYGAiIiIiIiIywcBERERERERkgoGJiIiIiIjIBAMTERERERGRCQYmIiIiIiIiEwxMREREREREJhiYiIiIiIiITDAwERERERERmWBgIiIiIiIiMsHAREREREREZIKBiYiIiIiIyAQDExERERERkQkGJiIiIiIiIhMMTERERERERCYYmIiIiIiIiEwwMBEREREREZlgYCIiIiIiIjLBwERERERERGSCgYmIiIiIiMgEAxMREREREZEJBiYiIiIiIiITDExEREREREQmGJiIiIiIiIhMMDARERERERGZYGAiIiIiIiIywcBERERERERkgoGJiIiIiIjIBAMTERERERGRCQYmIiIiIiIiEwxMREREREREJhiYiIiIiIiITDAwERERERERmWBgIiIiIiIiMsHAREREREREZIKBiYiIiIiIyAQDExERERERkQkGJiIiIiIiIhMMTERERERERCYYmIiIiIiIiEwwMBEREREREZlgYCIiIiIiIjLBwERERERERGSCgYmIiIiIiMgEAxMREREREZEJBiYiIiIiIiITDExEREREREQmGJiIiIiIiIhMMDARERERERGZYGAiIiIiIiIywcBERERERERkgoGJiIiIiIjIBAMTERERERGRCQYmIiIiIiIiEwxMREREREREJhiYiIiIiIiITDAwERERERERmWBg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" + } + }, + "cell_type": "markdown", + "id": "163a82aa", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "c19187ba-1ac9-400e-ae9b-684682349e8b", + "metadata": {}, + "source": [ + "## 🔍 Query Chroma" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f8d1524-c822-4303-b1a0-a3440cc90f82", + "metadata": {}, + "outputs": [], + "source": [ + "similarity_threshold = 0.5\n", + "\n", + "class MyVectorStoreRetriever(VectorStoreRetriever):\n", + " def _get_relevant_documents(\n", + " self, query: str, *, run_manager: CallbackManagerForRetrieverRun\n", + " ) -> List[Document]:\n", + " docs_and_similarities = (\n", + " self.vectorstore.similarity_search_with_relevance_scores(\n", + " query, **self.search_kwargs\n", + " )\n", + " )\n", + "\n", + " # Make the score part of the document metadata\n", + " for doc, similarity in docs_and_similarities:\n", + " doc.metadata[\"score\"] = similarity\n", + "\n", + " docs = [doc for doc, sim in docs_and_similarities if sim >= self.search_kwargs.get(\"score_threshold\", 0)]\n", + " return docs\n", + "\n", + "retriever = MyVectorStoreRetriever(\n", + " vectorstore=db,\n", + " search_type=\"similarity_score_threshold\",\n", + " search_kwargs={\"score_threshold\": similarity_threshold, \"k\": 20},\n", + ")\n", + "\n", + "\n", + "# Add metadata to the context sentto the LLM\n", + "def inject_metadata(doc: Document) -> Document:\n", + " doc_type = doc.metadata.get(\"doc_type\", \"Unknown\")\n", + " file_name = doc.metadata.get(\"file_name\", \"Unknown\")\n", + " content = f\"[SOURCE: {doc_type} - {file_name}]\\n{doc.page_content}\"\n", + " return Document(page_content=content, metadata=doc.metadata)\n", + "\n", + "class MetadataInjectingRetriever(BaseRetriever):\n", + " base_retriever: BaseRetriever = Field()\n", + "\n", + " def _get_relevant_documents(self, query: str):\n", + " docs = self.base_retriever.get_relevant_documents(query)\n", + " return [inject_metadata(doc) for doc in docs]\n", + "\n", + "retriever = MetadataInjectingRetriever(base_retriever=retriever)" + ] + }, + { + "cell_type": "markdown", + "id": "7446b2e0-23ca-4ad5-935d-1944f29b53cf", + "metadata": {}, + "source": [ + "## 🗣️ LLM and answers" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ab9093f-a6be-4ade-98f0-6911f47cb091", + "metadata": {}, + "outputs": [], + "source": [ + "llm = ChatOpenAI(temperature=0.7, model_name=MODEL)\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4830b80-5d43-4d23-9ac6-410fc110b74b", + "metadata": {}, + "outputs": [], + "source": [ + "# Define your question\n", + "question = \"Who are the top 3 earners in 2023 with base, bonus, and total. Include names.\"\n", + "\n", + "# Define the system prompt\n", + "system_prompt = \"\"\"\n", + "You are an assistant that answers questions about the company Insurellm.\n", + "\n", + "Use the following chat history and retrieved documents to answer.\n", + "\n", + "Always base your answers strictly on the retrieved documents. If documents contain partial info, respond with what’s available. If there is no info, say so.\n", + "\n", + "Do not invent names, roles, or facts.\n", + "\n", + "You can use the document source information shown in the format [SOURCE: doc_type - file_name] if it helps you answer the question accurately.\n", + "\n", + "Always extract exact numbers (like number of employees, years, revenue, etc.) from the documents if they are mentioned.\n", + "\n", + "\n", + "Chat History:\n", + "{chat_history}\n", + "\n", + "Documents:\n", + "{context}\n", + "\n", + "Question:\n", + "{question}\n", + "\"\"\"\n", + "\n", + "# Create the prompt template\n", + "prompt = PromptTemplate(\n", + " input_variables=[\"chat_history\", \"context\", \"question\"],\n", + " template=system_prompt\n", + ")\n", + "\n", + "# Set up LLM, memory, and conversation chain\n", + "llm = ChatOpenAI(temperature=0.7, model_name=MODEL)\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True, output_key=\"answer\")\n", + "\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(\n", + " llm=llm,\n", + " retriever=retriever,\n", + " memory=memory,\n", + " return_source_documents=True,\n", + " combine_docs_chain_kwargs={\"prompt\": prompt}\n", + ")\n", + "\n", + "# Format chat history\n", + "chat_history_text = \"\\n\".join([f\"{msg.type.upper()}: {msg.content}\" for msg in memory.chat_memory.messages])\n", + "\n", + "# Retrieve docs using the original question\n", + "retrieved_docs = retriever.get_relevant_documents(question)\n", + "# print(\"\\n📦 Context sent to LLM:\\n\")\n", + "# for i, doc in enumerate(retriever.get_relevant_documents(question), 1):\n", + "# print(f\"--- Document {i} ---\")\n", + "# print(doc.page_content) # preview\n", + "# print()\n", + "\n", + "# Invoke the chain\n", + "response = conversation_chain.invoke({\"question\": question})\n", + "\n", + "print(\"\\n🧠 Answer:\", response[\"answer\"])" + ] + }, + { + "cell_type": "markdown", + "id": "794f74c2-9b85-4d2c-8476-f4b29a001752", + "metadata": {}, + "source": [ + "## 🎛️ Gradio interface" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa85878e-04e4-457e-8775-523194c26409", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Define your system prompt\n", + "\n", + "system_prompt = \"\"\"\n", + "You are an assistant that answers questions about the company Insurellm.\n", + "\n", + "Use the following chat history and retrieved documents to answer. Always base your answers strictly on the retrieved documents. If documents contain partial info, respond with what’s available. If there is no info, say so.\n", + "\n", + "You can use the document source information shown in the format [SOURCE: doc_type - file_name] if it helps answer the question accurately.\n", + "\n", + "Extract exact numbers (like number of employees, years, revenue, etc.) from the documents if mentioned. Do not invent names, roles, or facts.\n", + "\n", + "Behavior Guidelines:\n", + "- Respond only when the user asks a question or requests clarification.\n", + "- If the user greets you or expresses gratitude, respond warmly, but **avoid repeating the previous answer** unless explicitly requested for more details.\n", + "- If the user asks \"thank you\" or similar, acknowledge it with gratitude, but **do not provide the same answer again** unless further information is requested.\n", + "- If the user shares feedback, acknowledge it, thank them, and offer further assistance.\n", + "- If the user expresses frustration or confusion, empathize, clarify, and offer further support.\n", + "- If the user doesn't find a clear answer, encourage them to ask for clarification or provide additional details, and offer further assistance.\n", + "\n", + "Chat History:\n", + "{chat_history}\n", + "\n", + "Documents:\n", + "{context}\n", + "\n", + "Question:\n", + "{question}\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9c1276d-abd0-4766-88d0-a710c030014d", + "metadata": {}, + "outputs": [], + "source": [ + "# 2. Create the prompt template\n", + "\n", + "prompt = PromptTemplate(\n", + " input_variables=[\"chat_history\", \"context\", \"question\"],\n", + " template=system_prompt\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0fe0466-7e87-4a40-b398-29d7e821f48f", + "metadata": {}, + "outputs": [], + "source": [ + "# 3. Set up LLM, memory, retriever, and the updated chain\n", + "\n", + "llm = ChatOpenAI(temperature=0.7, model_name=MODEL)\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True, output_key=\"answer\")\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(\n", + " llm=llm,\n", + " retriever=retriever,\n", + " memory=memory,\n", + " return_source_documents=True,\n", + " combine_docs_chain_kwargs={\"prompt\": prompt}\n", + ")\n", + "\n", + "def chat(question, history):\n", + " result = conversation_chain.invoke({\"question\": question})\n", + " answer = \"\"\n", + " for chunk in result[\"answer\"]:\n", + " answer += chunk\n", + " yield answer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2243e89c-c49b-416a-8152-f3679a9e2c05", + "metadata": {}, + "outputs": [], + "source": [ + "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)" + ] + } + ], + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/week5/community-contributions/Personal Knowledge Worker/Project_GPT.ipynb b/week5/community-contributions/Personal Knowledge Worker/Project_GPT.ipynb new file mode 100644 index 0000000..4bafbb0 --- /dev/null +++ b/week5/community-contributions/Personal Knowledge Worker/Project_GPT.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dfe37963-1af6-44fc-a841-8e462443f5e6", + "metadata": {}, + "source": [ + "## Personal Knowledge Worker for Sameer Khadatkar\n", + "\n", + "This project will use RAG (Retrieval Augmented Generation) to ensure our question/answering assistant has high accuracy.\n", + "\n", + "This first implementation will use a simple, brute-force type of RAG.." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba2779af-84ef-4227-9e9e-6eaf0df87e77", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import glob\n", + "from dotenv import load_dotenv\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "802137aa-8a74-45e0-a487-d1974927d7ca", + "metadata": {}, + "outputs": [], + "source": [ + "# imports for langchain, 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_chroma import Chroma\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.manifold import TSNE\n", + "import numpy as np\n", + "import plotly.graph_objects as go\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "from langchain.embeddings import HuggingFaceEmbeddings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58c85082-e417-4708-9efe-81a5d55d1424", + "metadata": {}, + "outputs": [], + "source": [ + "# price is a factor, so we're going to use a low cost model\n", + "\n", + "MODEL = \"gpt-4o-mini\"\n", + "db_name = \"vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee78efcb-60fe-449e-a944-40bab26261af", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables in a file called .env\n", + "\n", + "load_dotenv(override=True)\n", + "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "730711a9-6ffe-4eee-8f48-d6cfb7314905", + "metadata": {}, + "outputs": [], + "source": [ + "# Read in documents using LangChain's loaders\n", + "# Take everything in all the sub-folders of our knowledgebase\n", + "\n", + "folders = glob.glob(\"sameer-db/*\")\n", + "\n", + "def add_metadata(doc, doc_type):\n", + " doc.metadata[\"doc_type\"] = doc_type\n", + " return doc\n", + "\n", + "text_loader_kwargs = {'encoding': 'utf-8'}\n", + "\n", + "documents = []\n", + "for folder in folders:\n", + " doc_type = os.path.basename(folder)\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + " documents.extend([add_metadata(doc, doc_type) for doc in folder_docs])\n", + "\n", + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)\n", + "\n", + "print(f\"Total number of chunks: {len(chunks)}\")\n", + "print(f\"Document types found: {set(doc.metadata['doc_type'] for doc in documents)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78998399-ac17-4e28-b15f-0b5f51e6ee23", + "metadata": {}, + "outputs": [], + "source": [ + "# Put the chunks of data into a Vector Store that associates a Vector Embedding with each chunk\n", + "# Chroma is a popular open source Vector Database based on SQLLite\n", + "\n", + "embeddings = OpenAIEmbeddings()\n", + "\n", + "if os.path.exists(db_name):\n", + " Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection()\n", + "\n", + "# Create vectorstore\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": "ff2e7687-60d4-4920-a1d7-a34b9f70a250", + "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": "markdown", + "id": "b0d45462-a818-441c-b010-b85b32bcf618", + "metadata": {}, + "source": [ + "## Visualizing the Vector Store\n", + "\n", + "Let's take a minute to look at the documents and their embedding vectors to see what's going on." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b98adf5e-d464-4bd2-9bdf-bc5b6770263b", + "metadata": {}, + "outputs": [], + "source": [ + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "metadatas = result['metadatas']\n", + "doc_types = [metadata['doc_type'] for metadata in metadatas]\n", + "colors = [['green', 'red'][['personal', 'profile'].index(t)] for t in doc_types]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "427149d5-e5d8-4abd-bb6f-7ef0333cca21", + "metadata": {}, + "outputs": [], + "source": [ + "# We humans find it easier to visalize things in 2D!\n", + "# Reduce the dimensionality of the vectors to 2D using t-SNE\n", + "# (t-distributed stochastic neighbor embedding)\n", + "\n", + "tsne = TSNE(n_components=2, random_state=42,perplexity=5)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 2D scatter plot\n", + "fig = go.Figure(data=[go.Scatter(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='2D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x',yaxis_title='y'),\n", + " width=800,\n", + " height=600,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1418e88-acd5-460a-bf2b-4e6efc88e3dd", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's try 3D!\n", + "\n", + "tsne = TSNE(n_components=3, random_state=42,perplexity=5)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 3D scatter plot\n", + "fig = go.Figure(data=[go.Scatter3d(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " z=reduced_vectors[:, 2],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='3D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x', yaxis_title='y', zaxis_title='z'),\n", + " width=900,\n", + " height=700,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "9468860b-86a2-41df-af01-b2400cc985be", + "metadata": {}, + "source": [ + "## Time to use LangChain to bring it all together" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3942a10-9977-4ae7-9acf-968c43ad0d4a", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.schema import SystemMessage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45c0fb93-0a16-4e55-857b-1f9fd61ec24c", + "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", + "memory.chat_memory.messages.insert(0, SystemMessage(\n", + " content=\"\"\"You are an AI Assistant specialized in providing accurate information about Sameer Khadatkar. Only respond when the question explicitly asks for information. \n", + " Keep your answers brief, factual, and based solely on the information provided. Do not speculate or fabricate details. \n", + " For example, if the user simply says \"hi,\" respond with: \"How can I help you?\"\n", + " \"\"\"\n", + "))\n", + "\n", + "# the retriever is an abstraction over the VectorStore that will be used during RAG\n", + "retriever = vectorstore.as_retriever(k=4)\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": "968e7bf2-e862-4679-a11f-6c1efb6ec8ca", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's try a simple question\n", + "\n", + "query = \"Who are you?\"\n", + "result = conversation_chain.invoke({\"question\": query})\n", + "print(result[\"answer\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b5a9013-d5d4-4e25-9e7c-cdbb4f33e319", + "metadata": {}, + "outputs": [], + "source": [ + "# set up a new conversation memory for the chat\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + "\n", + "# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)" + ] + }, + { + "cell_type": "markdown", + "id": "bbbcb659-13ce-47ab-8a5e-01b930494964", + "metadata": {}, + "source": [ + "## Now we will bring this up in Gradio using the Chat interface -\n", + "\n", + "A quick and easy way to prototype a chat with an LLM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3536590-85c7-4155-bd87-ae78a1467670", + "metadata": {}, + "outputs": [], + "source": [ + "# Wrapping that in a function\n", + "\n", + "def chat(question, history):\n", + " result = conversation_chain.invoke({\"question\": question})\n", + " return result[\"answer\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b252d8c1-61a8-406d-b57a-8f708a62b014", + "metadata": {}, + "outputs": [], + "source": [ + "# And in Gradio:\n", + "\n", + "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e23270cf-2d46-4f9e-aeb3-de1673900d2f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3476931e-7d94-4b4d-8cc6-67a1bd5fa79c", + "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/Personal Knowledge Worker/Project_PHI.ipynb b/week5/community-contributions/Personal Knowledge Worker/Project_PHI.ipynb new file mode 100644 index 0000000..b1ad1b8 --- /dev/null +++ b/week5/community-contributions/Personal Knowledge Worker/Project_PHI.ipynb @@ -0,0 +1,927 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "fOxyiqtzKqLg", + "outputId": "714d12c5-775e-42c8-b51c-979a9112b808" + }, + "outputs": [], + "source": [ + "!pip install -q datasets requests torch peft bitsandbytes transformers trl accelerate sentencepiece tiktoken matplotlib gradio modal ollama langchain langchain-core langchain-text-splitters langchain-openai langchain-chroma langchain-community faiss-cpu feedparser" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zyxwwUw6LWXK" + }, + "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, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Zzqc9nk1L_5w", + "outputId": "0af5e1bb-2ccb-4838-b7a5-76c19285d094" + }, + "outputs": [], + "source": [ + "from langchain.document_loaders import DirectoryLoader, TextLoader, UnstructuredPDFLoader\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.schema import Document\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_chroma import Chroma\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.manifold import TSNE\n", + "import numpy as np\n", + "import plotly.graph_objects as go\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "from langchain.embeddings import HuggingFaceEmbeddings\n", + "from huggingface_hub import login\n", + "import torch\n", + "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, set_seed\n", + "from google.colab import userdata\n", + "from google.colab import drive\n", + "drive.mount('/content/drive')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "u_vbe1itNZ2n" + }, + "outputs": [], + "source": [ + "base_path = \"/content/drive/MyDrive/sameer-db\"\n", + "folders = glob.glob(os.path.join(base_path, \"*\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "f0lJBMjhMrLO", + "outputId": "5cdc6327-3a3a-4d5b-ca05-4c1383c020e2" + }, + "outputs": [], + "source": [ + "def add_metadata(doc, doc_type):\n", + " doc.metadata[\"doc_type\"] = doc_type\n", + " return doc\n", + "\n", + "# With thanks to CG and Jon R, students on the course, for this fix needed for some users\n", + "text_loader_kwargs = {'encoding': 'utf-8'}\n", + "# If that doesn't work, some Windows users might need to uncomment the next line instead\n", + "# text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "documents = []\n", + "for folder in folders:\n", + " doc_type = os.path.basename(folder)\n", + " loader = DirectoryLoader(folder, glob=\"**/*.md\", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs)\n", + " folder_docs = loader.load()\n", + " documents.extend([add_metadata(doc, doc_type) for doc in folder_docs])\n", + "\n", + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n", + "chunks = text_splitter.split_documents(documents)\n", + "\n", + "print(f\"Total number of chunks: {len(chunks)}\")\n", + "print(f\"Document types found: {set(doc.metadata['doc_type'] for doc in documents)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zSjwqZ3YNBLp" + }, + "outputs": [], + "source": [ + "hf_token = userdata.get('HF_TOKEN')\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t7rraUyHNkdP" + }, + "outputs": [], + "source": [ + "Phi_4 = \"microsoft/Phi-4-mini-instruct\"\n", + "db_name = \"/content/drive/MyDrive/phi_vector_db\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pDjj2S5ZPzF1" + }, + "outputs": [], + "source": [ + "quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 66, + "referenced_widgets": [ + "2a0377fc1e0c4c08944be1857c4e2409", + "7c8335e0c3f8459d89f3b9815a896e39", + "0fcb91f0551a4871b747f82e5fa6ff38", + "fa5c6cf8395840e08e2743d6e88190be", + "8613224ada934e7ba57fd5184ea61044", + "1180c8fe49e94873a024d38d33649852", + "4395c417cc854fc48da18d0ddd62671e", + "d678106a6601478cb5712991604788f0", + "5c4a8d25dbc942d5a596c8fa8580a785", + "c1b076c063e04536831d68e5e48f1692", + "9bcee7f185434cd0b1a998448236548c" + ] + }, + "id": "qzQzgir5VUBF", + "outputId": "1e7198a3-4857-49ab-f368-d430beddbf42" + }, + "outputs": [], + "source": [ + "tokenizer = AutoTokenizer.from_pretrained(Phi_4, trust_remote_code=True)\n", + "tokenizer.pad_token = tokenizer.eos_token\n", + "tokenizer.padding_side = \"right\"\n", + "\n", + "base_model = AutoModelForCausalLM.from_pretrained(\n", + " Phi_4,\n", + " quantization_config=quant_config,\n", + " device_map=\"auto\",\n", + ")\n", + "base_model.generation_config.pad_token_id = tokenizer.pad_token_id\n", + "\n", + "print(f\"Memory footprint: {base_model.get_memory_footprint() / 1e9:.1f} GB\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MjK3mBKHQBra" + }, + "outputs": [], + "source": [ + "from langchain.embeddings.base import Embeddings\n", + "from typing import List\n", + "import torch.nn.functional as F" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Q1BIMVW4Pf0A" + }, + "outputs": [], + "source": [ + "class PHI4Embeddings(Embeddings):\n", + " def __init__(self, tokenizer, model):\n", + " self.tokenizer = tokenizer\n", + " self.model = model\n", + " self.model.eval()\n", + "\n", + " def embed_documents(self, texts: List[str]) -> List[List[float]]:\n", + " embeddings = []\n", + " for text in texts:\n", + " with torch.no_grad():\n", + " inputs = self.tokenizer(text, return_tensors=\"pt\", truncation=True, max_length=512).to(self.model.device)\n", + " outputs = self.model(**inputs, output_hidden_states=True)\n", + " hidden_states = outputs.hidden_states[-1] # Last layer\n", + " attention_mask = inputs[\"attention_mask\"].unsqueeze(-1)\n", + " pooled = (hidden_states * attention_mask).sum(dim=1) / attention_mask.sum(dim=1)\n", + " normalized = F.normalize(pooled, p=2, dim=1)\n", + " embeddings.append(normalized[0].cpu().tolist())\n", + " return embeddings\n", + "\n", + " def embed_query(self, text: str) -> List[float]:\n", + " return self.embed_documents([text])[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7aUTue_mMxof" + }, + "outputs": [], + "source": [ + "# Put the chunks of data into a Vector Store that associates a Vector Embedding with each chunk\n", + "\n", + "embeddings = PHI4Embeddings(tokenizer, base_model)\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()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uWSe-8mATUag", + "outputId": "296804af-2283-435a-908c-48adaa6b4fd9" + }, + "outputs": [], + "source": [ + "# Create vectorstore\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, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1ZQ6agxtSLp5", + "outputId": "8e5bf8a7-fbaf-427b-9a67-369945aba80e" + }, + "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, + "metadata": { + "id": "qBIOPr2YT5FM" + }, + "outputs": [], + "source": [ + "# Prework\n", + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "metadatas = result['metadatas']\n", + "doc_types = [metadata['doc_type'] for metadata in metadatas]\n", + "colors = [['blue', 'red'][['personal', 'profile'].index(t)] for t in doc_types]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 617 + }, + "id": "fnuul36bUB3h", + "outputId": "f6cf1650-910a-4a03-f92d-9c200fb37de7" + }, + "outputs": [], + "source": [ + "# We humans find it easier to visalize things in 2D!\n", + "# Reduce the dimensionality of the vectors to 2D using t-SNE\n", + "# (t-distributed stochastic neighbor embedding)\n", + "\n", + "tsne = TSNE(n_components=2, random_state=42, 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(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='2D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x',yaxis_title='y'),\n", + " width=800,\n", + " height=600,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 717 + }, + "id": "Dgaeb7aRUF5d", + "outputId": "47546459-e169-4d2b-d0d7-4ebd135556e0" + }, + "outputs": [], + "source": [ + "# Let's try 3D!\n", + "\n", + "tsne = TSNE(n_components=3, random_state=42, perplexity=4)\n", + "reduced_vectors = tsne.fit_transform(vectors)\n", + "\n", + "# Create the 3D scatter plot\n", + "fig = go.Figure(data=[go.Scatter3d(\n", + " x=reduced_vectors[:, 0],\n", + " y=reduced_vectors[:, 1],\n", + " z=reduced_vectors[:, 2],\n", + " mode='markers',\n", + " marker=dict(size=5, color=colors, opacity=0.8),\n", + " text=[f\"Type: {t}
Text: {d[:100]}...\" for t, d in zip(doc_types, documents)],\n", + " hoverinfo='text'\n", + ")])\n", + "\n", + "fig.update_layout(\n", + " title='3D Chroma Vector Store Visualization',\n", + " scene=dict(xaxis_title='x', yaxis_title='y', zaxis_title='z'),\n", + " width=900,\n", + " height=700,\n", + " margin=dict(r=20, b=10, l=10, t=40)\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BZcCyGI3YEwJ", + "outputId": "fd03e6ee-2ec1-4c6b-c14b-986255ca070c" + }, + "outputs": [], + "source": [ + "from langchain.llms import HuggingFacePipeline\n", + "from transformers import pipeline\n", + "\n", + "pipe = pipeline(\n", + " \"text-generation\",\n", + " model=base_model,\n", + " tokenizer=tokenizer,\n", + " max_new_tokens=4069,\n", + " return_full_text=False,\n", + " temperature=0.7\n", + ")\n", + "\n", + "llm = HuggingFacePipeline(pipeline=pipe)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WDY8-1gJUM1v" + }, + "outputs": [], + "source": [ + "# set up the conversation memory for the chat\n", + "from langchain.schema import SystemMessage\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + "# memory.chat_memory.add_message(SystemMessage(content='''You are a helpful assistant that answers questions about Sameer Khadatkar **in English only**, based only on the retrieved documents.\n", + "# Do not respond in any other language.'''))\n", + "\n", + "# the retriever is an abstraction over the VectorStore that will be used during RAG\n", + "retriever = vectorstore.as_retriever(k=2)\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, + "metadata": { + "id": "dkuv5wD6jCrX" + }, + "outputs": [], + "source": [ + "def extract_first_helpful_answer(output: str) -> str:\n", + " if \"Helpful Answer:\" in output:\n", + " parts = output.split(\"Helpful Answer:\")\n", + " return parts[0].strip().split(\"\\n\")[0].strip() # Take only the first line after it\n", + " return output.strip()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZY5BH4C3UY1E" + }, + "outputs": [], + "source": [ + "query = \"Who is Sameer\"\n", + "result = conversation_chain.invoke({\"question\": query})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7n5PcQw0iRjO", + "outputId": "794c4dad-efde-4220-a9bd-50a1ae156229" + }, + "outputs": [], + "source": [ + "print(extract_first_helpful_answer(result[\"answer\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vW025q5Tkwc3", + "outputId": "e57d34e5-a64c-4e0b-e29b-d887214331c4" + }, + "outputs": [], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JIev764VkCht" + }, + "outputs": [], + "source": [ + "# set up a new conversation memory for the chat\n", + "memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n", + "\n", + "# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n", + "conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OO9o_VBholCx" + }, + "outputs": [], + "source": [ + "# Wrapping that in a function\n", + "\n", + "def chat(question, history):\n", + " result = conversation_chain.invoke({\"question\": question})\n", + " return extract_first_helpful_answer(result[\"answer\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 646 + }, + "id": "zOqiuWqCo04a", + "outputId": "fcb89961-1687-4d54-fcdd-ca5c590d69de" + }, + "outputs": [], + "source": [ + "# And in Gradio:\n", + "\n", + "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qIYSDiQUo5WX" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "0fcb91f0551a4871b747f82e5fa6ff38": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_d678106a6601478cb5712991604788f0", + "max": 2, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_5c4a8d25dbc942d5a596c8fa8580a785", + "value": 2 + } + }, + "1180c8fe49e94873a024d38d33649852": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2a0377fc1e0c4c08944be1857c4e2409": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_7c8335e0c3f8459d89f3b9815a896e39", + "IPY_MODEL_0fcb91f0551a4871b747f82e5fa6ff38", + "IPY_MODEL_fa5c6cf8395840e08e2743d6e88190be" + ], + "layout": "IPY_MODEL_8613224ada934e7ba57fd5184ea61044" + } + }, + "4395c417cc854fc48da18d0ddd62671e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "5c4a8d25dbc942d5a596c8fa8580a785": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "7c8335e0c3f8459d89f3b9815a896e39": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_1180c8fe49e94873a024d38d33649852", + "placeholder": "​", + "style": "IPY_MODEL_4395c417cc854fc48da18d0ddd62671e", + "value": "Loading checkpoint shards: 100%" + } + }, + "8613224ada934e7ba57fd5184ea61044": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9bcee7f185434cd0b1a998448236548c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "c1b076c063e04536831d68e5e48f1692": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d678106a6601478cb5712991604788f0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fa5c6cf8395840e08e2743d6e88190be": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_c1b076c063e04536831d68e5e48f1692", + "placeholder": "​", + "style": "IPY_MODEL_9bcee7f185434cd0b1a998448236548c", + "value": " 2/2 [00:41<00:00, 19.69s/it]" + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/week5/community-contributions/Personal Knowledge Worker/sameer-db/personal/sameer.md b/week5/community-contributions/Personal Knowledge Worker/sameer-db/personal/sameer.md new file mode 100644 index 0000000..c585424 --- /dev/null +++ b/week5/community-contributions/Personal Knowledge Worker/sameer-db/personal/sameer.md @@ -0,0 +1,23 @@ +# Sameer Khadatkar + +Hi, I am **Sameer Khadatkar**, born and brought up in **Nagpur**. + +I completed my schooling from **Dinanath Junior College and High School, Nagpur** up to 12th standard. After that, I moved to **Amravati** for my Bachelor's degree. + +### Academic Journey +I prepared for the **GATE Mechanical Engineering (ME)** exam: +- **2020**: Rank **377** + +With this rank, I secured admission to the prestigious **Indian Institute of Science (IISc), Bangalore**. + +### Career +I later got placed at **Wells Fargo**, Hyderabad. + +### Personal Life +- I got married to my batchmate from Government College of Engineering Amravati. + +### Hobbies & Interests +I played **Cycle Polo** up to my 8th standard and even competed at the **national level**. + +### Family +- Parents, elder sister and wife. diff --git a/week5/community-contributions/Personal Knowledge Worker/sameer-db/profile/Profile.md b/week5/community-contributions/Personal Knowledge Worker/sameer-db/profile/Profile.md new file mode 100644 index 0000000..d9853cd --- /dev/null +++ b/week5/community-contributions/Personal Knowledge Worker/sameer-db/profile/Profile.md @@ -0,0 +1,145 @@ +# Sameer Raju Khadatkar + +**Quant AI/ML @ Wells Fargo | M.Tech. (CDS) @ IISc, Bangalore | B.Tech. (Mechanical) @ GCOE, Amravati** +📍 Hyderabad, Telangana, India +📧 sameer123khadatkar@gmail.com +🔗 [LinkedIn](https://www.linkedin.com/in/sameer-khadatkar/) + +--- + +## Summary + +I currently serve as a Quantitative Analytics Specialist within Wells Fargo's Model Risk Management (MRM) team at India and Philippines. My primary responsibility involves validating AI/ML models, with a focus on fraud detection, as well as models used in marketing, credit scoring, and natural language processing (NLP). In this role, I ensure the conceptual soundness of models, conduct performance testing, conduct explainability analysis and rigorously challenge models by developing challenger models to detect weaknesses. + +Additionally, I ensure compliance with regulatory standards set by Wells Fargo, in alignment with guidelines from the Federal Reserve and the OCC. I work closely with model development and risk management teams, providing validation feedback and recommending improvements. I also contribute to documentation and reporting, preparing validation reports, and ensuring the ongoing monitoring of model performance. + +With a strong foundation in Machine Learning, Deep Learning, and High-Performance Computing gained during my graduate studies at the Indian Institute of Science, Bangalore, and a Bachelor's degree in Mechanical Engineering, I bring a unique blend of skills at the intersection of advanced technology and engineering. My expertise allows me to tackle complex challenges, drive innovation, and contribute to cutting-edge solutions in diverse industries. + +--- + +## Professional Experience + +### Wells Fargo International Solutions Private Ltd +**Quantitative Analytics Specialist – AVP** +📍 Hyderabad, Telangana, India +📅 August 2022 – September 2023 + +- Collaborating with a team overseeing an inventory of ∼300 models focused on Fraud Detection, primarily utilizing Logistic Regression, Extreme Gradient Boosting (XGBoost), and Neural Network models. +- Conduct validation of AI/ML models by ensuring conceptual soundness, performing performance testing, carrying out explainability analysis, and developing surrogate, challenger, and offset models to uncover potential weaknesses. +- Joined the team during its expansion in India, playing a key role in building trust with US stakeholders. Recognized with the **Manager’s Spotlight Award** for outstanding dedication and contributions. +- Developing a module to assist Validators in benchmarking anomaly detection models (Isolation Forest, Extended Isolation Forest, Autoencoders, Histogram-Based Outlier Score (HBOS), etc.) and assessing them using clustering performance metrics. +- Created a validation playbook for fraud detection vendor models and developed an Excel-based policy library to facilitate quick reference for team members. + +--- + +## Highlighted Projects at Wells Fargo + +### ✅ Check Authorization Model | Validation + +- Validated a high-impact machine learning model for check authorization, ensuring compliance with regulatory and bank's MRM standards. +- Reviewed model objectives, assumptions, architecture, and data pipeline. +- Assessed performance using AUC, recall, KS statistic, and PSI across time. +- Performed explainability analysis using multicollinearity checks, surrogate models (overall and segment level), SHAP, PDP, H-Statistic, 2D-PDPs, and sensitivity analysis. +- Identified local weaknesses through segmentation and built offset models to detect missed signals. +- Developed challenger models using YOLOv5, SigNet, TrOCR (Transformer-based OCR), XGBoost model, and pixel-based feature engineering. + +### 🧠 Word Embedding Explainability Research + +- Collaborated with the Bank’s Chief Model Risk Officer on a research project focused on the explainability of word embeddings using clustering techniques such as Spectral Clustering, HDBSCAN, and analysis of ReLU neural network activation patterns. +- Utilized Sentence Transformer embeddings (SBERT) and applied dimensionality reduction methods including PCA, UMAP, and t-SNE for cluster interpretation and visualization. +- Extended the research by developing a Mixture of Experts model leveraging XGBoost. + +--- + +## Education + +**Indian Institute of Science (IISc), Bangalore** +📅 2020 – 2022 +🎓 Master of Technology (M.Tech.), Computational and Data Sciences +📍 Bengaluru, Karnataka +**CGPA:** 9.1 / 10.0 + +**Government College of Engineering, Amravati (GCoEA)** +📅 2015 – 2019 +🎓 Bachelor of Technology (B.Tech.), Mechanical Engineering +📍 Amravati, Maharashtra +**CGPA:** 8.29 / 10.0 + +--- + +## Certifications + +- Advanced Data Science with IBM (Coursera) +- HYPERMESH (SHELL MESH AND SOLID MESH) +- Introduction to Big Data (Coursera) +- MASTERCAM (Design, Turning and Milling) +- CREO PARAMETRIC + +--- + +## Research Publication + +**Subspace Recursive Fermi-Operator Expansion Strategies for Large-Scale DFT Eigenvalue Problems on HPC Architectures** +📝 Sameer Khadatkar, Phani Motamarri (MATRIX Lab) +📅 July 20, 2023 +📚 *Journal of Chemical Physics, 159, 031102 (2023)* +🔗 [Publication Link](https://pubs.aip.org/aip/jcp/article/159/3/031102/2903241/Subspace-recursive-Fermi-operator-expansion) + +- Implemented recursive Fermi-operator expansion methods on multi-node CPU (PARAM Pravega) and GPU (ORNL Summit) systems for large-scale DFT problems. +- Applied mixed-precision strategies achieving 2× to 4× speedup over diagonalization. +- Benchmarked using MPI and SLATE for distributed dense linear algebra. + +--- + +## Academic, Independent and Other Projects + +- **LLM-Powered Multimodal Airline Chatbot**: Built a chatbot with GPT-4o-mini, supporting both text and voice, generating pop-art city images. Stack: Python, Gradio, custom tools. +- **Future Stock Price Prediction for MAANG**: Used yfinance, Stateful LSTM vs XGBoost. LSTM outperformed with ~0.02 MAE. +- **Duplicate Question Detection**: LSTM Siamese Network with Word2Vec and GloVe. GloVe performed better. +- **Music Genre Classification**: Used MFCCs and spectral features. Best result: 76% ± 3% accuracy with SVM. +- **Algorithm Implementation from Scratch**: PCA, LDA, GMM, TF-IDF, and backpropagation for DNNs. + +--- + +## Skills + +**Knowledge Areas:** +Model Risk Management, Machine Learning, Deep Learning, High-Performance Computing + +**Programming Languages:** +Python, C, C++ (OpenMP, MPI, CUDA), SQL + +**Python Libraries & Tools:** +Numpy, Pandas, Scikit-Learn, PyTorch, TensorFlow (Keras), PySpark, Matplotlib + +--- + +## Relevant Courses + +- Machine Learning for Signal Processing (IISc) +- Advanced Data Science with IBM (Coursera) +- Deep Learning (NPTEL) +- Pattern Recognition and Neural Networks (NPTEL) +- Numerical Linear Algebra (IISc) +- Data Analysis and Visualization (IISc) +- Numerical Solution of Differential Equations (IISc) +- Parallel Programming (IISc) +- Introduction to Big Data (Coursera) +- LLM Engineering: Master AI, Large Language Models & Agents (Udemy) + +--- + +## Extracurricular Activities + +- **Project Associate** at MATRIX Lab, CDS Department, IISc. +- **Teaching Assistant** for “DS284: Numerical Linear Algebra” at IISc. +- Led suspension operations for SAE BAJA Team at GCoE Amravati. +- Organized Annual Social Gathering as Joint Secretary at GCoE Amravati. + +--- + +## Top Skills + +- Data Reporting +- SQL +- Microsoft Excel diff --git a/week6/community-contributions/lisekarimi/09_part1_data_curation.ipynb b/week6/community-contributions/lisekarimi/09_part1_data_curation.ipynb new file mode 100644 index 0000000..cee891a --- /dev/null +++ b/week6/community-contributions/lisekarimi/09_part1_data_curation.ipynb @@ -0,0 +1,716 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "40978455-23da-4159-bf08-15d9e8f79984", + "metadata": {}, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 1)\n", + "A complete pipeline from raw text to fine-tuned frontier and open source models\n", + "\n", + "---\n", + "In this project, we aim to **predict item prices based solely on their textual descriptions**. \n", + "\n", + "We approach the problem with a structured 8-part pipeline:\n", + "\n", + "- 🧩 **Part 1: Data Curation & Preprocessing** : We aggregate, clean, analyze, and balance the dataset — then export it in .pkl format and save it in the HuggingFace Hub for the next step: model training and evaluation.\n", + "\n", + "- ⚔️ **Part 2: Traditional ML vs Frontier LLMs** : We compare traditional machine learning models (LR, SVR, XGBoost) using vectorized text inputs (BoW, Word2Vec) against LLMs like GPT-4o, LLaMA, Deepseek ... ❗ Who will predict better: handcrafted features or massive pretraining?\n", + "\n", + "- 🧠 **Part 3: E5 Embeddings & RAG** : We compare XGBoost on **contextual dense embeddings** vs. Word2Vec, and test if **RAG** boosts GPT-4o Mini’s price predictions. 📦 Do contextual embeddings and retrieval improve price prediction?\n", + "\n", + "- 🔧 **Part 4: Fine-Tuning GPT-4o Mini** : We fine-tune GPT-4o Mini on our curated dataset and compare performance before and after.\n", + "🤖 Can a fine-tuned GPT-4o Mini beat its own zero-shot performance?\n", + "\n", + "- 🦙 **Part 5: Evaluating LLaMA 3.1 8B Quantized** : We run LLaMA 3.1 (8B, quantized) using the same evaluation setup to see how well an open-source base model performs with no fine-tuning.\n", + "\n", + "- ⚙️ **Part 6: Fine-Tuning LLaMA 3.1 with QLoRA** : We fine-tune LLaMA 3.1 using QLoRA and explore key hyperparameters, tracking **training and validation loss** to monitor overfitting and select the best configuration.\n", + "\n", + "- 🧪 **Part 7: Evaluating Fine-Tuned LLaMA 3.1 8B (Quantized)** : After fine-tuning LLaMA 3.1, it's time to evaluate its performance and see how it stacks up against other models. Let's dive into the results.\n", + "\n", + "- 🏆**Part 8: Summary & Leaderboard** : Who comes out on top? Let’s find out. We wrap up with final model rankings and key insights across ML, embeddings, RAG, and fine-tuned frontier and open-source models.\n", + "\n", + "---\n", + "- ➡️ Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA \n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "Let’s begin with Part 1.\n", + "\n", + "# 🧩 Part 1: Data Curation & Preprocessing\n", + "\n", + "- Tasks:\n", + " - Load and filter dataset, then prepare each datapoint\n", + " - Explore, visualize, balance price distribution\n", + " - Export .pkl, upload to HF Hub\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ✅ CPU is sufficient — no GPU required\n", + "- 🛠️ Requirements: 🔑 Hugging Face Token\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcf2f470", + "metadata": {}, + "outputs": [], + "source": [ + "!uv pip install transformers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddbb5eb0-9ab7-4675-b195-0bf4055b9320", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import sys\n", + "import random\n", + "import pickle\n", + "import importlib\n", + "from dotenv import load_dotenv\n", + "from huggingface_hub import login\n", + "from datasets import Dataset, DatasetDict\n", + "from collections import Counter, defaultdict\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa916b7a-9044-4461-b29a-815d47973e75", + "metadata": {}, + "outputs": [], + "source": [ + "# import datasets\n", + "# print(datasets.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6cf6e19-1276-4b37-8f9b-6acf1473a7c6", + "metadata": {}, + "outputs": [], + "source": [ + "# environment\n", + "\n", + "load_dotenv(override=True)\n", + "hf_token = os.getenv('HF_TOKEN')\n", + "if not hf_token:\n", + " print(\"❌ HF_TOKEN is missing\")\n", + "\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "markdown", + "id": "a1637a14-b2df-4286-a8d6-ddae413f4a8a", + "metadata": {}, + "source": [ + "## ⚙️ Data Loading & Curation (Simultaneously)\n", + "We load and curate the data at the same time using loaders.py and items.py.\n", + "- Datasets come from: https://huggingface.co/datasets/McAuley-Lab/Amazon-Reviews-2023/tree/main/raw/meta_categories\n", + "- `loaders.py` handles parallel loading and filtering of products\n", + "- `items.py` defines the Item class to clean, validate, and prepare each datapoint (title, description, price...) for modeling.\n", + "\n", + "\n", + "🛠️ Note: Data is filtered to include items priced between 1 and 999 USD.\n", + "\n", + "💡 Comments have been added in both files to clarify the processing logic.\n", + "\n", + "⚠️ Loading 2.8M+ items can take 40+ mins on a regular laptop.\n", + "\n", + "⚠️ Set WORKER wisely in `loaders.py` to match your system capacity. Too many may crash your machine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b89273c-e02f-4c15-8394-5d948a266bfc", + "metadata": {}, + "outputs": [], + "source": [ + "sys.path.append('./helpers')\n", + "import helpers.items\n", + "import helpers.loaders\n", + "\n", + "importlib.reload(helpers.items)\n", + "importlib.reload(helpers.loaders)\n", + "\n", + "from helpers.items import Item # noqa: E402\n", + "from helpers.loaders import ItemLoader # noqa: E402" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "260a123b-8f34-4c66-bcac-1c3b25e95d7f", + "metadata": {}, + "outputs": [], + "source": [ + "dataset_names = [\n", + " \"Automotive\",\n", + " \"Electronics\",\n", + " \"Office_Products\",\n", + " \"Tools_and_Home_Improvement\",\n", + " \"Cell_Phones_and_Accessories\",\n", + " \"Toys_and_Games\",\n", + " \"Appliances\",\n", + " \"Musical_Instruments\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b482032-cba9-4ee9-9451-9b7dc9f41be6", + "metadata": {}, + "outputs": [], + "source": [ + "items = []\n", + "for dataset_name in dataset_names:\n", + " loader = ItemLoader(dataset_name)\n", + " items.extend(loader.load())\n", + "\n", + "# Now, time for a coffee break!!\n", + "# By the way, the larger datasets first... it speeds up the process." + ] + }, + { + "cell_type": "markdown", + "id": "145d0648-e01d-46b9-ad42-f10b69fccbc3", + "metadata": {}, + "source": [ + "## 🔍 Inspecting a Sample Datapoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0185985d-5f67-4e4b-ac66-95b5b293231f", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"A grand total of {len(items):,} items\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b0c0ae8-c0ec-4f6f-b847-800da379c01b", + "metadata": {}, + "outputs": [], + "source": [ + "# Investigate the first item from the list\n", + "\n", + "datapoint = items[0]\n", + "\n", + "# Access various attributes\n", + "title = datapoint.title\n", + "details = datapoint.details\n", + "price = datapoint.price\n", + "category = datapoint.category\n", + "\n", + "print(f\"Datapoint: {datapoint}\")\n", + "print('*' * 40)\n", + "print(f\"Title: {title}\")\n", + "print('*' * 40)\n", + "print(f\"Detail: {details}\")\n", + "print('*' * 40)\n", + "print(f\"Price: ${price}\")\n", + "print('*' * 40)\n", + "print(f\"Category: {category}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e05ed6e4-1cbc-46a4-be2f-4832b99e5ec3", + "metadata": {}, + "outputs": [], + "source": [ + "# The prompt that will be used during training\n", + "print(items[0].prompt)\n", + "print('*' * 40)\n", + "# The prompt that will be used during testing\n", + "print(items[0].test_prompt())" + ] + }, + { + "cell_type": "markdown", + "id": "f66e714d-2bae-458e-a0f6-1ce78d0696b3", + "metadata": {}, + "source": [ + "## 📊 Data Visualization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd50ae2c-b34e-4be7-bd74-62055e4d5b2d", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(15, 6))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c736b038-2dcd-40b9-8ae9-d17271f1ff81", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of token counts\n", + "\n", + "tokens = [item.token_count for item in items]\n", + "plt.title(f\"Token counts: Avg {sum(tokens)/len(tokens):,.1f} and highest {max(tokens):,}\\n\")\n", + "plt.xlabel('Length (tokens)')\n", + "plt.ylabel('Count')\n", + "plt.hist(tokens, rwidth=0.7, color=\"blue\", bins=range(0, 300, 10))\n", + "plt.show()" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjYAAAHLCAYAAADbUtJvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAEGISURBVHhe7d17XFVl3v//9+asIqikAoqglaZ5wmOYB9TCtBypscM05Snnl41ojXlPNzWlTQedybytu0mn8ZRa5phIjlmBinguNexgHrA8ZaB5AjVFkev3xy3r61oggija4vV8PNbj0f5cn703+2Ltvd9day30GGOMAAAAXMDLWQAAAPi1ItgAAADXINjAxuPxlGpbsWKF865FeDweJSQkOMsoxpIlSzR27Fhn+ar65ptv5PF45Ovrq6ysLOdwhZk0aZLuu+8+NWzYUB6PR7Gxsc4WSVJsbGyR/fDCLTs729Z/8uRJvfDCC2rcuLH8/f0VEhKi7t27KzMz09bntGLFiiKPfeE2bNgw512umbFjx8rj8TjLRcTGxqp58+bOchG7d++Wx+PRzJkznUOl4rkG7/m1a9dq7NixOnbsmHOoWD/++KOeeuopdevWTTVq1Ljo6y2ci4ttd911l61/x44d+u1vf6uaNWuqatWq6tixoxYtWmTrQcUg2MBm3bp1tq1Pnz6qUqVKkXqbNm2cd0U5LFmyRC+++KKzfFVNnTpVkpSfn69Zs2Y5hyvMlClTtGfPHvXo0UO1a9d2DlvefvvtIvvhsmXL5Ovrq9tuu02hoaFW74kTJxQbG6tp06ZpxIgRSklJ0YwZM9SxY0f98ssvtsd1atOmTZHnWbdunQYMGCBJuvfee513cY2wsDCtW7dOd999t3PourV27Vq9+OKLpQ42O3fu1HvvvSc/Pz/16dPHOWwpnAvn9swzz0iO/WD37t2KiYnR9u3bNWXKFM2fP1+1a9dWfHy8FixYcMGjokIYoAQDBw401apVc5ZLRZIZPny4s4xiDB8+3FTk2/H06dMmJCTEtGrVytSrV880btzY2VJhzp07Z/33rbfearp162YbL8nMmTONJDN16lRb/cknnzTVqlUz33//va1+uQoKCkyjRo1MZGSk7ee91saMGVOq/aZbt27m1ltvdZavuGvxnn/ttdeMJLNr1y7nULEu/P1t2LDBSDIzZsyw9ZQkNjbWVK1a1eTk5Fi1xx9/3AQEBJgff/zRquXn55umTZuaiIiI62qfqQxYsUGZHTlyRH/84x9Vr149+fn5qVGjRnruueeUl5fnbLUxxujZZ5+Vr6+v/vWvf1n1efPmKSYmRtWqVVNgYKB69eqljIwM230HDRqkwMBA7dy5U3369FFgYKAiIiL09NNPX/J5C73//vuKiYlRYGCgAgMD1bp1a02bNs3WM336dLVq1UoBAQGqVauW7r33Xm3dutXWExsbW+zhkkGDBikqKsq6XbiUPWHCBE2cOFENGzZUYGCgYmJitH79etv9/vGPf0iOQ4G7d++WJM2fP18dO3ZUcHCwqlatqkaNGmnIkCHW/S9HcnKyDh8+rKFDh2rgwIHasWOHVq9ebY3Hx8crMjJSBQUFtvtJUseOHW0rdseOHdNjjz2mWrVqKTAwUHfffbd++OEHeTyeUh1e8/K6/I+hadOmKTAwUA8++KBV++WXXzR16lTdf//9atSoka3/cqWlpemHH37Q4MGDL/nznj59Wk8//bRat26t4OBg1apVSzExMfroo4+crdahm9mzZ6tp06aqWrWqWrVqpcWLFztb9fHHH6t169by9/dXw4YNNWHCBGfLJW3YsEFdunSx9qPx48fbfscXOxT10UcfqWXLlvL391ejRo30xhtvlHgYrDSvJzMzUw8//LDq1Kkjf39/NW3a1HofFCooKNDLL7+sJk2aqEqVKqpRo4ZatmypN954Qzp/KO6//uu/JMk6lOm5xKHyS/3+SvL9998rPT1dDzzwgIKCgqz6mjVr1KpVK9WrV8+qeXt7q3fv3tq3b5+++OILq44K4Ew6wIWcKzanTp0yLVu2NNWqVTMTJkwwKSkp5vnnnzc+Pj6mT58+tvte+H9vp0+fNg899JCpXr26+eSTT6yeV155xXg8HjNkyBCzePFik5SUZGJiYky1atXMli1brL6BAwcaPz8/07RpUzNhwgSzdOlS88ILLxiPx2NefPFFq+9inn/+eSPJ3HfffWb+/PkmJSXFTJw40Tz//PNWz6uvvmokmd/97nfm448/NrNmzTKNGjUywcHBZseOHVZft27dil1VGDhwoImMjLRu79q1y0gyUVFR5q677jLJyckmOTnZtGjRwtSsWdMcO3bMGGPMzp07Tf/+/Y0ks27dOms7ffq0Wbt2rfF4POahhx4yS5YsMcuXLzczZswwjz766AXP/H8/U1neznfeeafx9/c3R44cMTt37jQej8cMGjTIGv/oo4+MJJOammq739atW40k8+abbxpz/v9+O3fubAICAsz48eNNSkqKefHFF83NN99sJJkxY8bY7n8pZVmx2bFjh5Fkhg4daquvXLnSSDKvvPKKGTZsmKlRo4bx9fU1bdu2NYsXL7b1ltbDDz9svLy8zJ49e5xDRRw7dswMGjTIzJ492yxfvtx8+umnZvTo0cbLy8u8++67tt7C/aNDhw7m3//+t1myZImJjY01Pj4+ttWmpUuXGm9vb9O5c2eTlJRk5s+fb9q3b28aNGhQqt97t27dTEhIiLn55pvNlClTTGpqqvnjH/9oJNl+psJ99sIVjE8++cR4eXmZ2NhYs3DhQjN//nzTsWNHExUVVeS5S/t6tmzZYoKDg02LFi3MrFmzTEpKinn66aeNl5eXGTt2rNU3btw44+3tbcaMGWOWLVtmPv30UzNp0iSrZ9++fWbEiBFGkklKSrLeOxeuppSkrCs2zz77rJFkVq9ebas3btzYdO3a1VYzxpjExEQjyfzzn/90DuEquvQ7ApWaM9hMmTLFSDL//ve/bX1/+9vfjCSTkpJi1XQ+2Bw+fNh07tzZ1KtXz2zevNka37t3r/Hx8TEjRoywasYYc/z4cRMaGmoeeOABqzZw4MBin7dPnz6mSZMmtprTDz/8YLy9vc3vf/9755Dl6NGjpkqVKkXC2d69e42/v795+OGHrVpZg02LFi1Mfn6+Vf/iiy+MJDN37lyrdrFDURMmTDCSrBB0MT169DDe3t7OcrF2795tvLy8zEMPPWTVunXrZqpVq2Zyc3ONMcacPXvW1K1b1/a6jTHmz3/+s/Hz8zOHDh0yxhjz8ccfG0lm8uTJtr5x48YZXeVg88wzzxidD4MXmjt3rpFkgoKCzO23324WLVpkFi9ebLp37248Ho/59NNPbf2XcvToURMQEGB69erlHCqV/Px8c/bsWfPYY4+Z6Oho25gkU7duXWvejTEmOzvbeHl5mXHjxlm1jh07mvDwcHPq1Cmrlpuba2rVqlXsfuNUGHw///xzW71Zs2a211VcsGnfvr2JiIgweXl5Vu348eMmJCSkyHOX9vX06tXL1K9fv0gASUhIMAEBAebIkSPGGGPuuece07p1a1uPU1kPRV2oLMEmPz/f1KtXz9xyyy3OIRMfH29q1Khhjh8/bqt36dLFSDKvvvqqrY6r6/LX5FApLV++XNWqVVP//v1t9UGDBkmSli1bZqvv2rVLMTExys3N1fr169WqVStr7LPPPlN+fr4GDBig/Px8awsICFC3bt2KLCd7PB717dvXVmvZsqX27Nljqzmlpqbq3LlzGj58uHPIsm7dOp06dcp6HYUiIiLUo0ePIq+rLO6++255e3tbt1u2bClJl/y5Jal9+/aSpAceeED//ve/tX//fmeLdH7e8/PzneVizZgxQwUFBbbDWUOGDNHJkyc1b948SZKPj48eeeQRJSUlKScnR5J07tw5zZ49W/369VNISIgkKT09XTr/813od7/7ne32lZafn693331Xt956q2677TbbWOGhFT8/P33yySfq27ev7r77bi1evFhhYWF66aWXbP2X8t577+n06dMaOnSoc+ii5s+fr9tvv12BgYHy8fGRr6+vpk2bVuSwpiR1795d1atXt27XrVtXderUsfaPkydPasOGDbrvvvsUEBBg9VWvXr3I+6EkoaGh6tChg612qffPyZMntXHjRsXHx8vPz8+qBwYGXvS5L/V6Tp8+rWXLlunee+9V1apVbe/9Pn366PTp09ah2g4dOuirr77SH//4R3322WfKzc21Hreiffrpp9q/f78ee+wx55ASEhKUk5OjAQMG6IcfftCBAwf0/PPPa+3atVI5D3+h7JhtlMnhw4cVGhpa5Nh6nTp15OPjo8OHD9vqX3zxhXbs2KEHH3xQ9evXt40dOHBAOv/l7evra9vmzZunQ4cO2fqrVq1q+2CXJH9/f50+fdpWc/r5558lqcjzX6jw5w4LC3MOKTw8vMjrKovCEFDI399fknTq1ClbvThdu3ZVcnKyFQDr16+v5s2ba+7cuc7WUikoKNDMmTMVHh6utm3b6tixYzp27JjuuOMOVatWzXbO0ZAhQ3T69Gl98MEH0vkgmpWVpcGDB1s9hw8flo+Pj2rVqmXVdP7L7GpasmSJsrOziw0bhfPdqVMn2xds1apV1a1bN3355ZcXdF/atGnTVLt2bfXr1885VKykpCQ98MADqlevnubMmaN169Zpw4YN1nw6OfcPnd9HCvePo0ePqqCgwHbVV6HiahdzqecpztGjR2WMKfb3WVxNpXiew4cPKz8/X//7v/9b5H1feJVS4Xs/MTFREyZM0Pr169W7d2+FhISoZ8+e2rhxo+3xK8K0adPk6+trXR13oZ49e2rG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V61atdSgQQM98sgjWrNmjV5//XVFR0fr0KFDWr58uVq0aKE+ffqooKBA7du3V2BgoCZNmqSCggINHz5cQUFBSklJcT4dAAC4RipFsFmxYoW6d+/uLGvgwIGaOXOmzp49q5dfflmzZs3S/v37FRISopiYGL344otq0aKFJOmnn37SiBEjlJKSomrVqql37956/fXXVatWLefDAgCAa6RSBBsAAFA5VPpzbAAAgHu4dsWmoKBAP/30k6pXry6Px+McBgAA1yFjjI4fP67w8HB5eZV9/cW1webHH39URESEswwAAH4F9u3bp/r16zvLl+TaYJOTk6MaNWpo3759CgoKcg4DAIDrUG5uriIiInTs2DEFBwc7hy/JtcEmNzdXwcHBysnJIdgAAPArUd7v77IfvAIAALhOEWwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwAAIBrEGwA4CryeEq/ASg/gg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHANgg0AAHCNCgk248aNU/v27VW9enXVqVNH8fHx2r59u7PNZsWKFfJ4PEW2bdu2OVsBAACkigo26enpGj58uNavX6/U1FTl5+crLi5OJ0+edLYWsX37dmVlZVnbzTff7GwBAACQJHmMMcZZvNp+/vln1alTR+np6eratatzWDq/YtO9e3cdPXpUNWrUcA5fUm5uroKDg5WTk6OgoCDnMABUCI/HWbm4iv80Bq4/5f3+rpAVG6ecnBxJUq1atZxDRURHRyssLEw9e/ZUWlqac9iSl5en3Nxc2wYAACqXCg82xhiNGjVKnTt3VvPmzZ3DlrCwML3zzjtasGCBkpKS1KRJE/Xs2VMrV650tkrnz+MJDg62toiICGcLAABwuQo/FDV8+HB9/PHHWr16terXr+8cLlHfvn3l8Xi0aNEi55Dy8vKUl5dn3c7NzVVERMRlL2UBwJXAoSigbH5Vh6JGjBihRYsWKS0trcyhRpJuu+02ZWZmOsuSJH9/fwUFBdk2AABQuVRIsDHGKCEhQUlJSVq+fLkaNmzobCmVjIwMhYWFOcsAAABSRQWb4cOHa86cOXr//fdVvXp1ZWdnKzs7W6dOnbJ6EhMTNWDAAOv2pEmTlJycrMzMTG3ZskWJiYlasGCBEhISrB4AAIALVUiwmTx5snJychQbG6uwsDBrmzdvntWTlZWlvXv3WrfPnDmj0aNHq2XLlurSpYtWr16tjz/+WPfdd5/VAwAAcKEKP3m4opT35CMAuBI4eRgom/J+f1fIig0AAEBFINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXINgAAADXqJBgM27cOLVv317Vq1dXnTp1FB8fr+3btzvbikhPT1fbtm0VEBCgRo0aacqUKc4WAAAAS4UEm/T0dA0fPlzr169Xamqq8vPzFRcXp5MnTzpbLbt27VKfPn3UpUsXZWRk6Nlnn9XIkSO1YMECZysAAIAkyWOMMc7i1fbzzz+rTp06Sk9PV9euXZ3DkqRnnnlGixYt0tatW63asGHD9NVXX2ndunW23uLk5uYqODhYOTk5CgoKcg4DQIXweJyVi6v4T2Pg+lPe7+8KWbFxysnJkSTVqlXLOWRZt26d4uLibLVevXpp48aNOnv2rK0uSXl5ecrNzbVtAACgcqnwYGOM0ahRo9S5c2c1b97cOWzJzs5W3bp1bbW6desqPz9fhw4dstV1/jye4OBga4uIiHC2AAAAl6vwYJOQkKCvv/5ac+fO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aWlp+v7775WWlqZ3331XM2fO1MyZMy+4t93q1atVtWpVNW3a1Kpt2LBBkjRjxgxlZWVZtxcuXKgnn3xSTz/9tL799ls9/vjjGjx4sNLS0qz7FjLG6Mknn9S0adO0evVqtW7dWt9884169eql++67T19//bXmzZun1atXKyEhwXbf119/Xe3atVNGRob++Mc/6oknntC2bduk86tLixYt0r///W9t375dc+bMsQUvSerQoYNWrVplqwG4DM5/7huA+wwcOND069fPWTbGGPP888+buLg4W23fvn1Gktm+fbsxxphu3bqZzp0723rat29vnnnmGWOMMZ988onx8fExWVlZ1nhqaqqRZBYuXGiMMWbXrl1GksnIyLB6zPmfLTIy0uTn51u1+++/3zz44IO2vgv9z//8j2nUqJGzbHu+Qp06dTJ/+MMfbLX777/f9OnTx7otycyfP9888sgj5pZbbjH79u2zxh599FHz//1//5912xhjVq1aZby8vMypU6eMMcZERkaaRx55xBovKCgwderUMZMnTzbGGDNixAjTo0cPU1BQYPU4vfHGGyYqKspZBlBGrNgAldymTZuUlpamwMBAa7vlllskSd9//73V17JlywvuJYWFhengwYOSpO3btysiIkKhoaHWeIcOHS7oLtmtt94qb29v6/aFj12cU6dOKSAgwFku1tatW3X77bfbarfffnuR81n+9Kc/ad26dVq1apXq169v1Tdt2qSZM2fa5qdXr14qKCjQrl27rL4L58fj8Sg0NNR6DYMGDdLmzZvVpEkTjRw5UikpKVZvoSpVquiXX35xlgGUEcEGqOQKCgrUt29fbd682bZlZmaqa9euVp+vr6/tfh6PRwUFBdL5Qzgej8c2XhYlPXZxbrjhBh09etRZvijnz1bcz3vnnXdq//79+uyzz2z1goICPf7447a5+eqrr5SZmakbb7zR6ivpNbRp00a7du3SSy+9pFOnTumBBx5Q//79bf1HjhxR7dq1bTUAZUewASq5Nm3aaMuWLYqKitJNN91k26pVq+ZsL9Ytt9yivXv36sCBA1at8ByXQn5+fpKkc+fO2eqXIzo6WtnZ2UXCja+vb5HHb9q0qVavXm2rrV271nZ+jiT95je/0fvvv6+hQ4fqgw8+sOqF8+Ocm5tuusl6TaURFBSkBx98UP/61780b948LViwQEeOHLHGv/32W0VHR9vuA6DsCDZAJZGTk1NkVWbv3r0aPny4jhw5ot/97nf64osv9MMPPyglJUVDhgwpEhIu5s4779SNN96ogQMH6uuvv9aaNWusk4cLV0bq1KmjKlWqWCcn5+TkOB6l9KKjo1W7dm2tWbPGVo+KitKyZctsoee//uu/NHPmTE2ZMkWZmZmaOHGikpKSNHr0aNt9df6KqtmzZ2vw4MH68MMPJUnPPPOM1q1bp+HDh1srWYsWLdKIESOcd7+o//mf/9EHH3ygbdu2aceOHZo/f75CQ0NVo0YNq2fVqlWKi4uz3Q9A2RFsgEpixYoVio6Otm0vvPCCwsPDtWbNGp07d069evVS8+bN9eSTTyo4OLjUfyPG29tbycnJOnHihNq3b6+hQ4fqL3/5iyRZ58L4+PjozTff1D//+U+Fh4erX79+jkcpPW9vbw0ZMkTvvfeerf76668rNTVVERER1upHfHy83njjDb322mu69dZb9c9//lMzZswocrl5of79++vdd9/Vo48+qqSkJLVs2VLp6enKzMxUly5dFB0dreeff15hYWHOu15UYGCg/va3v6ldu3Zq3769du/erSVLlljzu27dOuXk5BQ5PAWg7Dzm/64IAIAras2aNercubN27txpOxflSjlw4IBuvfVWbdq0SZGRkc7hX5X7779f0dHRevbZZ51DAMqIYAPgili4cKECAwN18803a+fOnXryySdVs2bNIue3XEkfffSRatWqpS5dujiHfjXy8vL02muv6emnn1aVKlWcwwDKiGAD4IqYNWuWXnrpJe3bt0833HCD7rjjDr3++usKCQlxtgLAVUOwAQAArlG6MwMBAAB+BQg2AADANQg2AADANQg2AADANf5/xpvZ/AgCsC0AAAAASUVORK5CYII=" + } + }, + "cell_type": "markdown", + "id": "940ba698", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da33633a-7ad5-479c-8dff-f7a7a149d49c", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of prices\n", + "\n", + "prices = [item.price for item in items]\n", + "plt.title(f\"Prices: Avg {sum(prices)/len(prices):,.1f} and highest {max(prices):,}\\n\")\n", + "plt.xlabel('Price ($)')\n", + "plt.ylabel('Count')\n", + "plt.hist(prices, rwidth=0.7, color=\"blueviolet\", bins=range(0, 1000, 10))\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0f494d7-349e-4878-929c-075ac97c6b6d", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of categories\n", + "\n", + "category_counts = Counter()\n", + "for item in items:\n", + " category_counts[item.category]+=1\n", + "\n", + "categories = category_counts.keys()\n", + "counts = [category_counts[category] for category in categories]\n", + "\n", + "# Bar chart by category\n", + "plt.bar(categories, counts, color=\"goldenrod\")\n", + "plt.title('How many items in each category')\n", + "plt.xlabel('Categories')\n", + "plt.ylabel('Count')\n", + "\n", + "plt.xticks(rotation=30, ha='right')\n", + "\n", + "# Add value labels on top of each bar\n", + "for i, v in enumerate(counts):\n", + " plt.text(i, v, f\"{v:,}\", ha='center', va='bottom')\n", + "\n", + "# Display the chart\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "d4fe384d-049b-4742-98e5-20d162db5151", + "metadata": {}, + "source": [ + "## 🎯 Data Sampling\n", + "\n", + "We sample to keep the dataset balanced but rich:\n", + "- 🎯 Keep all items if price ≥ $240 or group size ≤ 1200\n", + "- 🎯 For large groups, randomly sample 1200 items, favoring rare categories\n", + "\n", + "✅ This keeps valuable high-price items and avoids overrepresented classes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20330037-744d-4834-8ece-413a8dbe2030", + "metadata": {}, + "outputs": [], + "source": [ + "HEAVY_DATASET = \"Automative\"\n", + "\n", + "# Group items by rounded price\n", + "# Slots is a dictionary where the keys are rounded prices and the values are lists of items that have that rounded price\n", + "slots = defaultdict(list)\n", + "for item in items:\n", + " slots[round(item.price)].append(item)\n", + "\n", + "np.random.seed(42) # Set random seed for reproducibility\n", + "sample = [] # Final collection of items after our sampling process completes\n", + "\n", + "# Sampling loop\n", + "for price, items_at_price in slots.items():\n", + "\n", + " # Take all items if price ≥ 240 or small group\n", + " if price >= 240 or len(items_at_price) <= 1200:\n", + " sample.extend(items_at_price)\n", + "\n", + " # Otherwise sample 1200 items with weights\n", + " else:\n", + "\n", + " # Weight: 1 for toys, 5 for others\n", + " weights = [1 if item.category == HEAVY_DATASET else 5 for item in items_at_price]\n", + " weights = np.array(weights) / sum(weights)\n", + "\n", + " indices = np.random.choice(len(items_at_price), 1200, False, weights) # False = don't pick the same index twice\n", + " sample.extend([items_at_price[i] for i in indices])\n", + "\n", + "print(f\"There are {len(sample):,} items in the sample\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21aed337-6f15-48e4-8155-70551ed1d5e0", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of prices in the sample\n", + "\n", + "prices = [float(item.price) for item in sample]\n", + "plt.title(f\"Avg {sum(prices)/len(prices):.2f} and highest {max(prices):,.2f}\\n\")\n", + "plt.xlabel('Price ($)')\n", + "plt.ylabel('Count')\n", + "plt.hist(prices, rwidth=0.7, color=\"darkblue\", bins=range(0, 1000, 10))\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08a7353e-2752-4493-bb0b-6057d1eab16d", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of categories in the sample\n", + "\n", + "category_counts = Counter()\n", + "for item in sample:\n", + " category_counts[item.category]+=1\n", + "\n", + "categories = category_counts.keys()\n", + "counts = [category_counts[category] for category in categories]\n", + "\n", + "# Create bar chart\n", + "plt.bar(categories, counts, color=\"pink\")\n", + "\n", + "# Customize the chart\n", + "plt.title('How many in each category')\n", + "plt.xlabel('Categories')\n", + "plt.ylabel('Count')\n", + "\n", + "plt.xticks(rotation=30, ha='right')\n", + "\n", + "# Add value labels on top of each bar\n", + "for i, v in enumerate(counts):\n", + " plt.text(i, v, f\"{v:,}\", ha='center', va='bottom')\n", + "\n", + "# Display the chart\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "9bdb0c58-24e0-4ab5-8a28-2136b53ab915", + "metadata": {}, + "source": [ + "The HEAVY_DATASET still in the lead, but improved somewhat" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ce8ff80-cd19-4c3b-965f-ce6af8ee347d", + "metadata": {}, + "outputs": [], + "source": [ + "# Create pie chart\n", + "\n", + "fig, ax = plt.subplots(figsize=(8, 8))\n", + "wedges, texts, autotexts = ax.pie(\n", + " counts,\n", + " # labels=categories,\n", + " autopct='%1.0f%%',\n", + " startangle=90,\n", + " pctdistance=0.85,\n", + " labeldistance=1.1\n", + ")\n", + "ax.legend(wedges, categories, title=\"Categories\", loc=\"lower center\", bbox_to_anchor=(0.5, 1.15), ncol=3)\n", + "\n", + "# Draw donut center\n", + "centre_circle = plt.Circle((0, 0), 0.70, fc='white')\n", + "fig.gca().add_artist(centre_circle)\n", + "\n", + "# Add center label\n", + "ax.text(0, 0, \"Categories\", ha='center', va='center', fontsize=14, fontweight='bold')\n", + "\n", + "# Equal aspect ratio\n", + "plt.axis('equal')\n", + "plt.title(\"Category Distribution\")\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "acbc6beb-fab4-49ab-bc7e-243638c1fa99", + "metadata": {}, + "outputs": [], + "source": [ + "# How does the price vary with the character count of the prompt?\n", + "\n", + "sizes = [len(item.prompt) for item in sample]\n", + "prices = [item.price for item in sample]\n", + "\n", + "# Create the scatter plot\n", + "plt.scatter(sizes, prices, s=0.2, color=\"red\")\n", + "\n", + "# Add labels and title\n", + "plt.xlabel('Size')\n", + "plt.ylabel('Price')\n", + "plt.title('Is there a simple correlation between prompt length and item price?')\n", + "\n", + "# Display the plot\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "76b060a4-0b8d-495c-bb96-28cb7b7ec623", + "metadata": {}, + "source": [ + "There is no strong or simple correlation between prompt length and item price.\n", + "\n", + "In other words, longer prompts don’t clearly mean higher prices, and vice versa." + ] + }, + { + "cell_type": "markdown", + "id": "0f33211c-3548-4a21-990b-21aa55089186", + "metadata": {}, + "source": [ + "## ✅ Final Check Before Training" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be8d0c68-ac6e-4a4d-a6c7-64e9c6763ec4", + "metadata": {}, + "outputs": [], + "source": [ + "# Ensure the price label is correctly placed by the end of the prompt\n", + "\n", + "def report(item):\n", + " prompt = item.prompt\n", + " tokens = Item.tokenizer.encode(item.prompt)\n", + " print(prompt)\n", + " print(tokens[-6:])\n", + " print(Item.tokenizer.batch_decode(tokens[-6:]))\n", + "\n", + "report(sample[50])" + ] + }, + { + "cell_type": "markdown", + "id": "656d523d-8297-4d75-a973-a7e5517d21bc", + "metadata": {}, + "source": [ + "LLaMA and GPT-4o both tokenize numbers from 1 to 999 as a single token, while models like Qwen2, Gemma, and Phi-3 split them into multiple tokens. This helps keep prices compact in our prompts — useful for our project, though not strictly required." + ] + }, + { + "cell_type": "markdown", + "id": "e36254ba-d20f-44ad-b991-1f1f3cdc4aaa", + "metadata": {}, + "source": [ + "## 📦 Creating Train/Test Datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cfb5092-c38d-4c14-8dd0-e1d97c06d7f6", + "metadata": {}, + "outputs": [], + "source": [ + "random.seed(42)\n", + "random.shuffle(sample)\n", + "train = sample[:400_000]\n", + "test = sample[400_000:402_000]\n", + "print(f\"Divided into a training set of {len(train):,} items and test set of {len(test):,} items\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f084822-e489-4946-8cf5-f5b0ebd7a23c", + "metadata": {}, + "outputs": [], + "source": [ + "print(train[0].prompt)\n", + "print('*' * 40)\n", + "print(test[0].test_prompt())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d49a08ce-dd41-4af8-82f6-4701628e8152", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the distribution of prices in the first 250 test points\n", + "\n", + "prices = [float(item.price) for item in test[:250]]\n", + "plt.figure(figsize=(15, 6))\n", + "plt.title(f\"Avg {sum(prices)/len(prices):.2f} and highest {max(prices):,.2f}\\n\")\n", + "plt.xlabel('Price ($)')\n", + "plt.ylabel('Count')\n", + "plt.hist(prices, rwidth=0.7, color=\"darkblue\", bins=range(0, 1000, 10))\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c581439-93f2-422a-924f-fd6c58ef8693", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract prompts and prices\n", + "train_prompts = [item.prompt for item in train]\n", + "train_prices = [item.price for item in train]\n", + "test_prompts = [item.test_prompt() for item in test]\n", + "test_prices = [item.price for item in test]\n", + "\n", + "# Create Hugging Face datasets\n", + "train_dataset = Dataset.from_dict({\"text\": train_prompts, \"price\": train_prices})\n", + "test_dataset = Dataset.from_dict({\"text\": test_prompts, \"price\": test_prices})\n", + "dataset = DatasetDict({\n", + " \"train\": train_dataset,\n", + " \"test\": test_dataset\n", + "})\n", + "\n", + "# Save full Item objects\n", + "os.makedirs(\"data\", exist_ok=True) # Make sure the folder exists\n", + "\n", + "# Save full Item objects to the folder\n", + "with open('data/train.pkl', 'wb') as file:\n", + " pickle.dump(train, file)\n", + "\n", + "with open('data/test.pkl', 'wb') as file:\n", + " pickle.dump(test, file)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3914d029-350e-4140-a31f-e931fa289a41", + "metadata": {}, + "outputs": [], + "source": [ + "# Push to the Hugging Face Hub\n", + "USERNAME = \"lisekarimi\" # 🔧 Replace with your Hugging Face username\n", + "DATASET_NAME = f\"{USERNAME}/pricer-data\"\n", + "\n", + "dataset.push_to_hub(DATASET_NAME, private=True)" + ] + }, + { + "cell_type": "markdown", + "id": "3d8f3b33-41f8-4ee6-96ed-27677ffc8ec4", + "metadata": {}, + "source": [ + "**Note:** \n", + "- The dataset `pricer-data` on Hugging Face only contains `text` and `price`:\n", + "\n", + "\n", + "{\n", + " \"text\": \"How much does this cost...Price is $175.00\",\n", + " \"price\": 175.0\n", + "}\n", + "\n", + "- Full `Item` objects (with metadata) are available in `train.pkl` and `test.pkl`:\n", + "\n", + "Item(data={\n", + " \"title\": str,\n", + " \"description\": list[str],\n", + " \"features\": list[str],\n", + " \"details\": str\n", + "}, price=float)\n", + "\n", + "\n", + "Now, it’s time to move on to **Part 2: Model Benchmarking – Traditional ML vs Frontier LLMs.**\n", + "\n", + "🔜 See you in the [next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part2_tradml_vs_frontier.ipynb)" + ] + } + ], + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week6/community-contributions/lisekarimi/09_part2_tradml_vs_frontier.ipynb b/week6/community-contributions/lisekarimi/09_part2_tradml_vs_frontier.ipynb new file mode 100644 index 0000000..b4a8f14 --- /dev/null +++ b/week6/community-contributions/lisekarimi/09_part2_tradml_vs_frontier.ipynb @@ -0,0 +1,779 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d9b9eaa6-a12f-4cf8-a4c5-e8ac2c15d15b", + "metadata": {}, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 2)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- ➡️ Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA \n", + "- Summary & Leaderboard\n", + "\n", + "--- \n", + "\n", + "# ⚔️ Part 2: Traditional ML vs LLMs\n", + "\n", + "- Tasks:\n", + " - Vectorize text (BoW, Word2Vec)\n", + " - Train SVR, LR, XGBoost models\n", + " - Predict with LLMs (GPT-4o, Claude, LLaMA…)\n", + " - Compare traditional ML vs LLMs\n", + " \n", + "📊 Which model predicts prices best? Let’s find out.\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ✅ CPU is sufficient — no GPU required\n", + "- 🛠️ Requirements: 🔑 HF Token, Open API Key, Anthropic API key, Groq API key\n", + "\n", + "⚠️ This notebook assumes you're familiar with NLP techniques (e.g., converting text to vectors using Bag-of-Words or Word2Vec) and traditional ML models (like SVR, Logistic Regression, XGBoost) along with basic evaluation metrics.\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ce6a892-b357-4132-b9c0-a3142a0244c8", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import importlib\n", + "import re\n", + "import csv\n", + "import tiktoken\n", + "import math\n", + "from datasets import load_dataset\n", + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.feature_extraction.text import CountVectorizer\n", + "from gensim.models import Word2Vec\n", + "from gensim.utils import simple_preprocess\n", + "from sklearn.svm import LinearSVR\n", + "import xgboost as xgb\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "from anthropic import Anthropic" + ] + }, + { + "cell_type": "markdown", + "id": "6f82b230-2e03-4b1e-9be5-926fcd19acbe", + "metadata": {}, + "source": [ + "## 📥 Load Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4292a45d", + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55f1495b-f343-4152-8739-3a99f5ac405d", + "metadata": {}, + "outputs": [], + "source": [ + "HF_USER = \"lisekarimi\"\n", + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "\n", + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85880d79-f1ba-4ee8-a039-b6acea84562c", + "metadata": {}, + "outputs": [], + "source": [ + "print(train[0][\"text\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88842541-d73b-4fae-a550-6dedf8fab633", + "metadata": {}, + "outputs": [], + "source": [ + "print(train[0][\"price\"])" + ] + }, + { + "cell_type": "markdown", + "id": "1e3501c5-a52d-4ace-a988-b86b7e7dbb31", + "metadata": {}, + "source": [ + "## 🛠️ Prepare Data for models" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a87cd82-127b-4a66-9ad9-90978a2376b5", + "metadata": {}, + "outputs": [], + "source": [ + "def mask_price_value(text):\n", + " return re.sub(r\"(\\n\\nPrice is \\$).*\", r\"\\1\", text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84ad6155-2708-4810-80a6-7efcf3bbd886", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract prices\n", + "prices = np.array([float(datapoint[\"price\"]) for datapoint in train])\n", + "\n", + "# Extract cleaned prompts\n", + "documents = [mask_price_value(datapoint[\"text\"]) for datapoint in train]\n", + "\n", + "# Set random seed for reproducibility\n", + "np.random.seed(42)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1c82371-5e92-4354-a064-38db1b6a8339", + "metadata": {}, + "outputs": [], + "source": [ + "print(documents[0])" + ] + }, + { + "cell_type": "markdown", + "id": "f05dd862-cc64-43d3-a0c3-c3a16d66e1bf", + "metadata": {}, + "source": [ + "## 📊 Model Evaluation with testing.py\n", + "\n", + "- Runs predictions and computes errors on test data\n", + "- Metrics: Absolute error, RMSLE, and hit rate\n", + "- Visual: Scatter plot of predicted vs. actual prices (color-coded)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45965754-7107-4023-bb33-81730b73db2e", + "metadata": {}, + "outputs": [], + "source": [ + "import helpers.testing\n", + "importlib.reload(helpers.testing)\n", + "\n", + "from helpers.testing import Tester # noqa: E402\n", + "\n", + "results = {} # Store each model's tester to compare and find the best performer" + ] + }, + { + "cell_type": "markdown", + "id": "2d8b08a8-f0a3-468f-91ea-7da60aecc32a", + "metadata": {}, + "source": [ + "## 🎯 Price Prediction with Traditional ML" + ] + }, + { + "cell_type": "markdown", + "id": "35475efe-0751-443a-9605-89e2025c3eb4", + "metadata": {}, + "source": [ + "## Bag-of-Words + Linear Regression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ded239d6-4dca-439b-8748-67aa2d2fa2a9", + "metadata": {}, + "outputs": [], + "source": [ + "# Use the CountVectorizer for a Bag of Words model\n", + "vectorizer = CountVectorizer(max_features=1000, stop_words='english')\n", + "X = vectorizer.fit_transform(documents)\n", + "regressor = LinearRegression()\n", + "regressor.fit(X, prices)\n", + "\n", + "def bow_lr_pricer(datapoint):\n", + " x = vectorizer.transform([mask_price_value(datapoint[\"text\"])])\n", + " return max(regressor.predict(x)[0], 0)\n", + "\n", + "tester = Tester(bow_lr_pricer, test)\n", + "tester.run()\n", + "results[\"Bag of Words LR\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "4b861fe5", + "metadata": {}, + "source": [ + "Bow Lr Pricer Error=$121.23 RMSLE=0.98 Hits=27.2%" + ] + }, + { + "cell_type": "markdown", + "id": "25dfc7c6-a258-4b56-8c02-f01003c4674d", + "metadata": {}, + "source": [ + "## Word2Vec + Linear Regression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efa22fd1-e81d-4142-b0a1-f1399c7a98a3", + "metadata": {}, + "outputs": [], + "source": [ + "# Preprocess the documents\n", + "processed_docs = [simple_preprocess(doc) for doc in documents]\n", + "\n", + "# Train Word2Vec model\n", + "w2v_model = Word2Vec(sentences=processed_docs, vector_size=400, window=5, min_count=1, workers=4)\n", + "\n", + "# This step of averaging vectors across the document is a weakness in our approach\n", + "\n", + "def document_vector(doc):\n", + " doc_words = simple_preprocess(doc)\n", + " word_vectors = [w2v_model.wv[word] for word in doc_words if word in w2v_model.wv]\n", + " return np.mean(word_vectors, axis=0) if word_vectors else np.zeros(w2v_model.vector_size)\n", + "\n", + "# Create feature matrix\n", + "X_w2v = np.array([document_vector(doc) for doc in documents])\n", + "\n", + "# Run Linear Regression on word2vec\n", + "\n", + "word2vec_lr_regressor = LinearRegression()\n", + "word2vec_lr_regressor.fit(X_w2v, prices)\n", + "\n", + "def word2vec_lr_pricer(datapoint):\n", + " doc = mask_price_value(datapoint[\"text\"])\n", + " vec = document_vector(doc)\n", + " return max(0, word2vec_lr_regressor.predict([vec])[0])\n", + "\n", + "tester = Tester(word2vec_lr_pricer, test)\n", + "tester.run()\n", + "results[\"Word2Vec LR\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "daaf6101", + "metadata": {}, + "source": [ + "Word2Vec Lr Pricer Error=$127.42 RMSLE=0.97 Hits=27.6%" + ] + }, + { + "cell_type": "markdown", + "id": "5f1fe808-f80e-4d15-8ec7-d31710cf68c5", + "metadata": {}, + "source": [ + "## Word2Vec + Linear SVR" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35d01455-6619-4f29-8f95-90c03763407e", + "metadata": {}, + "outputs": [], + "source": [ + "svr_regressor = LinearSVR()\n", + "svr_regressor.fit(X_w2v, prices)\n", + "\n", + "def svr_pricer(datapoint):\n", + " np.random.seed(42)\n", + " doc = mask_price_value(datapoint[\"text\"])\n", + " doc_vector = document_vector(doc)\n", + " return max(float(svr_regressor.predict([doc_vector])[0]),0)\n", + "\n", + "tester = Tester(svr_pricer, test)\n", + "tester.run()\n", + "results[\"Word2Vec SVR\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "48cb9c88", + "metadata": {}, + "source": [ + "Svr Pricer Error=$124.24 RMSLE=0.98 Hits=28.4%" + ] + }, + { + "cell_type": "markdown", + "id": "469ca205-3e5e-4aca-8b77-53f6acd92e40", + "metadata": {}, + "source": [ + "## Word2Vec + XGBoost " + ] + }, + { + "cell_type": "markdown", + "id": "a55acfe0-9633-45aa-a4c4-96b434a5a43b", + "metadata": {}, + "source": [ + "I initially tried Random Forest, but it struggled with high training time and didn’t scale well with this data.\n", + "That’s why I opted for XGBoost — it’s faster, handles large datasets efficiently, and often delivers better performance on structured data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0e3e1d7-2e62-4866-924e-7ed4483db8bc", + "metadata": {}, + "outputs": [], + "source": [ + "xgb_model = xgb.XGBRegressor(n_estimators=100, random_state=42, n_jobs=-1, verbosity=0)\n", + "xgb_model.fit(X_w2v, prices)\n", + "\n", + "def xgboost_pricer(datapoint):\n", + " doc = mask_price_value(datapoint[\"text\"])\n", + " doc_vector = document_vector(doc)\n", + " return max(0, xgb_model.predict([doc_vector])[0])\n", + "\n", + "tester = Tester(xgboost_pricer, test)\n", + "tester.run()\n", + "results[\"Word2Vec XGBoost\"] = tester\n" + ] + }, + { + "cell_type": "markdown", + "id": "d35050fa", + "metadata": {}, + "source": [ + "Xgboost Pricer Error=$107.97 RMSLE=0.84 Hits=29.2%" + ] + }, + { + "cell_type": "markdown", + "id": "4db1051d-9a7e-4cec-87fc-0d77fd858ced", + "metadata": {}, + "source": [ + "## 🚀 Price Prediction with Frontier LLMs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ef3fa58-87b7-4c30-8088-1a4999f0d25a", + "metadata": {}, + "outputs": [], + "source": [ + "load_dotenv(override=True)\n", + "\n", + "# Get API keys from environment\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if not openai_api_key:\n", + " print(\"❌ OPENAI_API_KEY is missing\")\n", + "\n", + "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n", + "if not anthropic_api_key:\n", + " print(\"❌ ANTHROPIC_API_KEY is missing\")\n", + "\n", + "groq_api_key = os.getenv('GROQ_API_KEY')\n", + "if not groq_api_key:\n", + " print(\"❌ GROQ_API_KEY is missing\")\n", + "\n", + "# Initialize clients\n", + "openai = OpenAI(api_key=openai_api_key)\n", + "claude = Anthropic(api_key=anthropic_api_key)\n", + "groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d86b3bca-513b-4621-8c66-4b89c134b895", + "metadata": {}, + "outputs": [], + "source": [ + "def messages_for(datapoint):\n", + " system_message = \"You estimate prices of items. Reply only with the price, no explanation\"\n", + " user_prompt = mask_price_value(datapoint[\"text\"]).replace(\" to the nearest dollar\", \"\").replace(\"\\n\\nPrice is $\",\"\")\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " {\"role\": \"assistant\", \"content\": \"Price is $\"}\n", + " ]\n", + "\n", + "messages_for(train[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f502d428-98aa-4160-bebe-726efcce5c65", + "metadata": {}, + "outputs": [], + "source": [ + "# A utility function to extract the price from a string\n", + "\n", + "def get_price(s):\n", + " s = s.replace('$','').replace(',','')\n", + " match = re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", s)\n", + " return float(match.group()) if match else 0\n", + "\n", + "get_price(\"The price is roughly $99.99 because blah blah\") # Testing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3845eda0-d37d-4605-a00f-83b1d8fc6945", + "metadata": {}, + "outputs": [], + "source": [ + "# A utility function to Count the tokens before passing the prompt to the model\n", + "\n", + "def count_tokens(messages):\n", + " encoding = tiktoken.get_encoding(\"cl100k_base\")\n", + " token_count = sum(len(encoding.encode(message['content'])) for message in messages)\n", + " return token_count\n" + ] + }, + { + "cell_type": "markdown", + "id": "4737e678-5d57-4dee-984b-ae5c56f9542d", + "metadata": {}, + "source": [ + "### gpt-4o-mini" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dca067d0-a4ff-4a48-bb74-d2914f3704b7", + "metadata": {}, + "outputs": [], + "source": [ + "# Count tokens once before running\n", + "total_tokens = 0\n", + "for datapoint in train:\n", + " messages = messages_for(datapoint)\n", + " total_tokens += count_tokens(messages)\n", + "print(f\"Total tokens: {total_tokens}\")\n", + "\n", + "def gpt_4o_mini(datapoint):\n", + " messages = messages_for(datapoint)\n", + " response = openai.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=messages,\n", + " seed=42,\n", + " max_tokens=5\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)\n", + "\n", + "tester = Tester(gpt_4o_mini, test)\n", + "tester.run()\n", + "results[\"gpt 4o mini\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "5c4c8ee4", + "metadata": {}, + "source": [ + "Gpt 4o Mini Error=$99.30 RMSLE=0.75 Hits=44.8%" + ] + }, + { + "cell_type": "markdown", + "id": "00a72937-9cde-472c-bd22-84996a42ab4c", + "metadata": {}, + "source": [ + "### gpt 4o (the big guy 😎)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20d18e1a-ccbf-4481-84ed-16b1c5760176", + "metadata": {}, + "outputs": [], + "source": [ + "def gpt_4o_frontier(datapoint):\n", + " response = openai.chat.completions.create(\n", + " model=\"gpt-4o\",\n", + " messages=messages_for(datapoint),\n", + " seed=42,\n", + " max_tokens=5\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)\n", + "\n", + "tester = Tester(gpt_4o_frontier, test)\n", + "tester.run()\n", + "results[\"gpt 4o (the big guy)\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "0c307928", + "metadata": {}, + "source": [ + "Gpt 4O Frontier Error=$87.68 RMSLE=1.01 Hits=51.2%" + ] + }, + { + "cell_type": "markdown", + "id": "20af42a7-8889-4091-bee9-80aeaf63816f", + "metadata": {}, + "source": [ + "### claude 3.7 Sonnet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4e343ef-2097-4395-86b2-90c489f133fe", + "metadata": {}, + "outputs": [], + "source": [ + "def claude_3_point_7_sonnet(datapoint):\n", + " messages = messages_for(datapoint)\n", + " system_message = messages[0]['content']\n", + " messages = messages[1:]\n", + " response = claude.messages.create(\n", + " model=\"claude-3-7-sonnet-20250219\",\n", + " max_tokens=5,\n", + " system=system_message,\n", + " messages=messages\n", + " )\n", + " reply = response.content[0].text\n", + " return get_price(reply)\n", + "\n", + "tester = Tester(claude_3_point_7_sonnet, test)\n", + "tester.run()\n", + "results[\"claude 3.7 sonnet\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "fdbba849", + "metadata": {}, + "source": [ + "Claude 3 Point 7 Sonnet Error=$110.26 RMSLE=0.60 Hits=46.0%" + ] + }, + { + "cell_type": "markdown", + "id": "0ff3a6bd-99b8-438e-abc1-295bf0bb9961", + "metadata": {}, + "source": [ + "### groq model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58a0c852-0811-4156-9c08-fa5bf4b54cd2", + "metadata": {}, + "outputs": [], + "source": [ + "def llama3_groq_pricer(datapoint):\n", + " response = groq.chat.completions.create(\n", + " model=\"llama3-70b-8192\",\n", + " messages=messages_for(datapoint),\n", + " max_tokens=5,\n", + " seed=42\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)\n", + "\n", + "tester = Tester(llama3_groq_pricer, test)\n", + "tester.run()\n", + "results[\"llama3-70b-8192\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "daf7f96c", + "metadata": {}, + "source": [ + "Llama3 Groq Pricer Error=$122.95 RMSLE=0.73 Hits=44.8%" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4cd8f25-9a8d-4227-ba58-c163b4d601cb", + "metadata": {}, + "outputs": [], + "source": [ + "def deepseek_qwen_pricer(datapoint):\n", + " response = groq.chat.completions.create(\n", + " model=\"deepseek-r1-distill-qwen-32b\",\n", + " messages=messages_for(datapoint),\n", + " max_tokens=5,\n", + " seed=42\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)\n", + "\n", + "tester = Tester(deepseek_qwen_pricer, test)\n", + "tester.run()\n", + "results[\"deepseek-qwen-32b\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "7280870e", + "metadata": {}, + "source": [ + "Deepseek Qwen Pricer Error=$178.96 RMSLE=0.83 Hits=33.2%" + ] + }, + { + "cell_type": "markdown", + "id": "af7d0190-d89b-4525-8a34-21033e99abb0", + "metadata": {}, + "source": [ + "## 🕵️ Human Judgement Baseline (Ed)\n", + "\n", + "We include a human baseline from our instructor Ed, who manually estimated prices based on item descriptions (💪 thanks Ed for taking on this exhausting task!). This allows us to compare model performance against human intuition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d63970d-a2d2-4329-8fe7-d0bdc2ff1bcb", + "metadata": {}, + "outputs": [], + "source": [ + "human_predictions = []\n", + "\n", + "with open('data/human_output.csv', 'r', encoding=\"utf-8\") as csvfile:\n", + " reader = csv.reader(csvfile)\n", + " for row in reader:\n", + " human_predictions.append(float(row[1]))\n", + "\n", + "def human_pricer(datapoint):\n", + " # `Tester` runs in order, so use the index from Tester itself\n", + " idx = human_pricer.counter\n", + " human_pricer.counter += 1\n", + " return human_predictions[idx]\n", + "\n", + "human_pricer.counter = 0 # initialize counter\n", + "\n", + "tester = Tester(human_pricer, test)\n", + "tester.run()\n", + "results[\"Human Predictions\"] = tester" + ] + }, + { + "cell_type": "markdown", + "id": "08c0d367-d596-43e6-81af-5889691fa34b", + "metadata": {}, + "source": [ + "## 🥇 Benchmark Showdown: ML, LLMs, and Ed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "830ae9a5-a185-41af-b17f-8d6a3f3752b7", + "metadata": {}, + "outputs": [], + "source": [ + "def truncate(x, decimals=2):\n", + " factor = 10 ** decimals\n", + " return math.floor(x * factor) / factor\n", + "\n", + "df_results = []\n", + "\n", + "for model_name, tester in results.items():\n", + " avg_error = truncate(sum(tester.errors) / tester.size)\n", + " hit_percent = truncate(sum(1 for c in tester.colors if c == \"green\") / tester.size * 100)\n", + " rmsle = truncate(math.sqrt(sum(tester.sles) / tester.size))\n", + "\n", + " df_results.append({\n", + " \"model\": model_name,\n", + " \"avrg_error\": avg_error,\n", + " \"rmsle\": rmsle,\n", + " \"accuracy_%\": hit_percent\n", + " })\n", + "\n", + "df_results = pd.DataFrame(df_results)\n", + "df_results = df_results.sort_values(by=\"avrg_error\")\n", + "\n", + "# Display with .2f formatting\n", + "print(df_results.to_string(index=False, float_format=\"{:.2f}\".format))\n" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "e78ddc21-1ffc-431b-902b-4562bdd4e789", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)\n", + "\n", + "🏁 **GPT-4o, GPT-4o Mini and XGBoost** clearly outperformed both LLMs (like Claude 3.7, LLaMA3-70B, DeepSeek-32B) and traditional ML approaches (LR, SVR).\n", + "\n", + "Now let’s take the top-performing frontier LLM — **GPT-4o Mini** — to test if retrieval (RAG) boosts its performance, and the best ML model — **XGBoost** — to see if contextual embeddings enhance its predictions.\n", + "\n", + "Let’s find out.\n", + "\n", + "🔜 See you in the [next notebook](https://github.com/lisek75/nlp_llms_notebook/blob/main/09_part3_e5embeddings_rag.ipynb)" + ] + } + ], + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week6/community-contributions/lisekarimi/09_part3_e5embeddings_rag.ipynb b/week6/community-contributions/lisekarimi/09_part3_e5embeddings_rag.ipynb new file mode 100644 index 0000000..5e6eea0 --- /dev/null +++ b/week6/community-contributions/lisekarimi/09_part3_e5embeddings_rag.ipynb @@ -0,0 +1,1080 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d9b9eaa6-a12f-4cf8-a4c5-e8ac2c15d15b", + "metadata": { + "id": "d9b9eaa6-a12f-4cf8-a4c5-e8ac2c15d15b" + }, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 3)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- ➡️E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA\n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# 🧠 Part 3: E5 Embeddings & RAG\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ⚠️ GPU required for embeddings (400K items) - use Google Colab\n", + "- 🛠️ Requirements: 🔑 HF Token, Open API Key\n", + "- Tasks:\n", + " - Preprocessed item descriptions\n", + " - Generated and stored embeddings in ChromaDB\n", + " - Trained XGBoost on embeddings, pushed to HF Hub, and ran predictions\n", + " - Predicted prices with GPT-4o Mini using RAG\n", + "\n", + "Is Word2Vec enough for XGBoost, or do contextual E5 embeddings perform better?\n", + "\n", + "Does retrieval improve price prediction for GPT-4o Mini?\n", + "\n", + "Let’s find out.\n", + "\n", + "⚠️ This notebook assumes basic familiarity with RAG and contextual embeddings.\n", + "We use the same E5 embedding space for both XGBoost and GPT-4o Mini with RAG, enabling a fair comparison.\n", + "Embeddings are stored and queried via ChromaDB — no LangChain is used for creation or retrieval.\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8e2af5e-03cc-46dc-8a8b-37cb102d0e92", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d8e2af5e-03cc-46dc-8a8b-37cb102d0e92", + "outputId": "905907cc-81c5-4a3b-e7c8-9e237e594a09" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q tqdm huggingface_hub numpy sentence-transformers datasets chromadb xgboost" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ce6a892-b357-4132-b9c0-a3142a0244c8", + "metadata": { + "id": "4ce6a892-b357-4132-b9c0-a3142a0244c8" + }, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import math\n", + "import chromadb\n", + "import re\n", + "import joblib\n", + "import os\n", + "from tqdm import tqdm\n", + "import gc\n", + "from huggingface_hub import login, HfApi\n", + "import numpy as np\n", + "from sentence_transformers import SentenceTransformer\n", + "from datasets import load_dataset\n", + "from google.colab import userdata\n", + "from xgboost import XGBRegressor\n", + "from openai import OpenAI\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "yBH-mvV0QBiw", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yBH-mvV0QBiw", + "outputId": "b4b6df10-dc05-4dbe-dd8b-55bae5a2b7af" + }, + "outputs": [], + "source": [ + "# Mount Google Drive to access persistent storage\n", + "\n", + "from google.colab import drive\n", + "drive.mount('/content/drive')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3OUI1jQYyaeX", + "metadata": { + "id": "3OUI1jQYyaeX" + }, + "outputs": [], + "source": [ + "# Google Colab User Data\n", + "# Ensure you have set the following in your Google Colab environment:\n", + "openai_api_key = userdata.get(\"OPENAI_API_KEY\")\n", + "hf_token = userdata.get('HF_TOKEN')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99f6f632", + "metadata": {}, + "outputs": [], + "source": [ + "openai = OpenAI(api_key=openai_api_key)\n", + "login(hf_token, add_to_git_credential=True)\n", + "\n", + "# Configuration\n", + "ROOT = \"/content/drive/MyDrive/deal_finder\"\n", + "CHROMA_PATH = f\"{ROOT}/chroma\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "FF-HryRnDXm5", + "metadata": { + "id": "FF-HryRnDXm5" + }, + "outputs": [], + "source": [ + "# Helper class for evaluating model predictions\n", + "\n", + "GREEN = \"\\033[92m\"\n", + "YELLOW = \"\\033[93m\"\n", + "RED = \"\\033[91m\"\n", + "RESET = \"\\033[0m\"\n", + "COLOR_MAP = {\"red\":RED, \"orange\": YELLOW, \"green\": GREEN}\n", + "\n", + "class Tester:\n", + "\n", + " def __init__(self, predictor, data, title=None, size=250):\n", + " self.predictor = predictor\n", + " self.data = data\n", + " self.title = title or predictor.__name__.replace(\"_\", \" \").title()\n", + " self.size = size\n", + " self.guesses = []\n", + " self.truths = []\n", + " self.errors = []\n", + " self.sles = []\n", + " self.colors = []\n", + "\n", + " def color_for(self, error, truth):\n", + " if error<40 or error/truth < 0.2:\n", + " return \"green\"\n", + " elif error<80 or error/truth < 0.4:\n", + " return \"orange\"\n", + " else:\n", + " return \"red\"\n", + "\n", + " def run_datapoint(self, i):\n", + " datapoint = self.data[i]\n", + " guess = self.predictor(datapoint)\n", + " truth = datapoint[\"price\"]\n", + " error = abs(guess - truth)\n", + " log_error = math.log(truth+1) - math.log(guess+1)\n", + " sle = log_error ** 2\n", + " color = self.color_for(error, truth)\n", + " # title = datapoint[\"text\"].split(\"\\n\\n\")[1][:20] + \"...\"\n", + " self.guesses.append(guess)\n", + " self.truths.append(truth)\n", + " self.errors.append(error)\n", + " self.sles.append(sle)\n", + " self.colors.append(color)\n", + " # print(f\"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}\")\n", + "\n", + " def chart(self, title):\n", + " # max_error = max(self.errors)\n", + " plt.figure(figsize=(12, 8))\n", + " max_val = max(max(self.truths), max(self.guesses))\n", + " plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6)\n", + " plt.scatter(self.truths, self.guesses, s=3, c=self.colors)\n", + " plt.xlabel('Ground Truth')\n", + " plt.ylabel('Model Estimate')\n", + " plt.xlim(0, max_val)\n", + " plt.ylim(0, max_val)\n", + " plt.title(title)\n", + "\n", + " # Add color legend\n", + " from matplotlib.lines import Line2D\n", + " legend_elements = [\n", + " Line2D([0], [0], marker='o', color='w', label='Accurate (green)', markerfacecolor='green', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='Medium error (orange)', markerfacecolor='orange', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='High error (red)', markerfacecolor='red', markersize=8)\n", + " ]\n", + " plt.legend(handles=legend_elements, loc='upper right')\n", + "\n", + " plt.show()\n", + "\n", + "\n", + " def report(self):\n", + " average_error = sum(self.errors) / self.size\n", + " rmsle = math.sqrt(sum(self.sles) / self.size)\n", + " hits = sum(1 for color in self.colors if color==\"green\")\n", + " title = f\"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%\"\n", + " self.chart(title)\n", + "\n", + " def run(self):\n", + " self.error = 0\n", + " for i in range(self.size):\n", + " self.run_datapoint(i)\n", + " self.report()\n", + "\n", + " @classmethod\n", + " def test(cls, function, data):\n", + " cls(function, data).run()\n" + ] + }, + { + "cell_type": "markdown", + "id": "6f82b230-2e03-4b1e-9be5-926fcd19acbe", + "metadata": { + "id": "6f82b230-2e03-4b1e-9be5-926fcd19acbe" + }, + "source": [ + "## 📥 Load Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ae00568", + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55f1495b-f343-4152-8739-3a99f5ac405d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 177, + "referenced_widgets": [ + "6e7c01d666f64fa58d6a059cc8d8f323", + "597b7155767441e6a0283a19edced00f", + "cf1360550eaa49a0867f55db8b8c4c77", + "94f26137cccf47f6a36d9325bc8f5b9c", + "a764b97f3dcd480c8860dde979e5e114", + "f1ec9a46c9ce4e038f3051bbd1b2c661", + "992f46ae91554731987b4baf79ba1bbd", + "b4abe22402fe40fd82b7fe93b4bc06f3", + "57ec058518734e3dbd27324cbba243c0", + "f101230e8a9a431d85ee2f8e51add7ad", + "e196658b093746588113240a60336437", + "cb06a4d26cb84c708857b683d1e84c12", + "e82ad07ba22e465cbe0232c504c3b693", + "c4e0ed1165f54393aaec24cd4624d562", + "295a3c6662034aaaab4d2e0192d1d1ce", + "c38aff0c91a849feb547e78156c2c347", + "69647c5595874c3185cebf6813ee908c", + "1036b1af4b154916a3d4f16f5ed799eb", + "e6347ff832cc4c04aef86594ea5a9e64", + "01c63224aa6a4f0c9c88a4d85527e767", + "1db34b9a4f1f42a897345b5a6630ced6", + "9293f2d745024d7facb68e04cc188850", + "26f6ec91efaf42909cec172fafe55987", + "c1131f0324b0498da9bc59720e867eb6", + "3e58017527a04634a489a33ed53fd312", + "06cd89f57d08466c875d179e79e3ecd2", + "2e0aa0aa87a04419a277f303f577f7ff", + "8fa0fe1992db42a997e7cd3ee08bd09e", + "accb1d5142a9498da0117f746fedd691", + "fcc2fc2f82e2441995b9e61b23b9b91e", + "da93fe316dd24cb48538b52ef2eaf6b5", + "5cea58775faf41829c04d2a84e3e2c31", + "1914ec7959d143d09a55da324bbcd47b", + "a3d3504148df46f59b6770fb377e2bb6", + "b088b9a503e24f179741d40d21a730d9", + "b77dcf4632954d0c9c3b6d441c5f684d", + "4cc8b3c4d9934f24a94b4601ab7816b5", + "c093f1c0806a43b79594ddac856a301c", + "9f4d9ac1aa074ed6b0248a4b18fde7db", + "c00785b8fdda409e9cb435abbb0466da", + "612e211af4cd46eb9d2f3148d1c7cb0b", + "86f93c663cc446adbc6366a528cb01b0", + "dd42911451ec48e086c1c99e76492321", + "5b942241f11c4f2ab086f0f289f99a03", + "d28a5c6172f74c0f8bbd2d949455f22e", + "0e67b2055f214eb691b4b54d9431bdd8", + "f81c4dc72b3b4b40a6a70528db732482", + "043a355b6a85471ba0142eb25e2c9eb0", + "8682bfab79a8409499797a3307e4d64d", + "55a837644bb643ac864fa1a674e665c8", + "33aae5a98bf5433b813ff8216e015089", + "56eedfc5ba6642dc8443ab60f5f09b8c", + "a1b710c227a84ea1a55c310084f13a93", + "0d4bc0d0e88a4c77a202f9c11b2ee2a9", + "20858379c2cd45d59070b18149d6e925" + ] + }, + "id": "55f1495b-f343-4152-8739-3a99f5ac405d", + "outputId": "37317fe6-b560-4ad0-c7d6-66517fd67c42" + }, + "outputs": [], + "source": [ + "HF_USER = \"lisekarimi\"\n", + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "\n", + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85880d79-f1ba-4ee8-a039-b6acea84562c", + "metadata": { + "id": "85880d79-f1ba-4ee8-a039-b6acea84562c" + }, + "outputs": [], + "source": [ + "print(train[0][\"text\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88842541-d73b-4fae-a550-6dedf8fab633", + "metadata": { + "id": "88842541-d73b-4fae-a550-6dedf8fab633" + }, + "outputs": [], + "source": [ + "print(train[0][\"price\"])" + ] + }, + { + "cell_type": "markdown", + "id": "7b8a9a5b-f74d-487d-a400-d157fea8c979", + "metadata": { + "id": "7b8a9a5b-f74d-487d-a400-d157fea8c979" + }, + "source": [ + "## 📦 Embed + Save Training Data to Chroma\n", + "- No LangChain used.\n", + "- We use `intfloat/e5-small-v2` for embeddings:\n", + " - Fast, high-quality, retrieval-tuned\n", + " - **Requires 'passage:' prefix**\n", + "- We embed item descriptions and store them in ChromaDB, with price saved as metadata." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b95a87a8-2136-4e03-a36c-42e5d53a3e28", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 337, + "referenced_widgets": [ + "8216f5d45e9345e493a43b8cbbe6598a", + "ec3854658f8448fc8463e8635889f700", + "7a90822b2aff4d5cb926442f01a77a9b", + "9518c3af589744cfbbb51f87d68f216e", + "327044765c044384a14be4e660bb152f", + "0b773d68d2394d80a2baf73c1808752a", + "21568b9954c8411d863baa7385df624f", + "0a08828a0ba4430ea6e039949f220b5b", + "3d5a51cfb5f44eecbf80d46e2e4608fd", + "313f059a82104a9394182f6dcdb0bfb4", + "6a625748afc84fe89a8af7a4ef638675", + "ebe43cd30e414f31ab52614c6e9f9f2b", + "88c29992adaa44af857e3216f7e53e60", + "0528af78cef844e8a2b489dcb8fce049", + "8cbccd78a79447158f02caadfa7d805f", + "076ce072490c493ba5b3c431f6166eda", + "dd7780038f8a4cd3837972c78b6583bc", + "9e285e2b58934552b98edd998b82a678", + "338efda3245a4989a9b3ee0795949bb8", + "136dfb68394742ea98d9eb845730846c", + "891d821725b6457c9d06737bf75fe3ed", + "14feb4e20339465d966a6a80504eb819", + "c02b637785324b9eb88e6a2c00cb986b", + "3635da14e6f04e8f90548eb6381290a8", + "1314757f404e47f5b0f6fa4de8537863", + "9e5f2478e931476d882e471c7f66aaeb", + "4ad885d69d9f492c960ca53426189707", + "992d5e88d7844a52a283c0e19475ab78", + "43eaec936c774e3380ae4ff1a823f3dc", + "ceeb11b317ac4d37b59641024f77265f", + "5e0371de53164830b4e8c2b6954b5947", + "63a729492e8a4a759d75b769cbb3e1e7", + "14dde2c87b7b4c9ea16d48732108dcd7", + "f50717b099d142be95390ae8f1e99e6a", + "ffa64c304dab4ef18e9ef50ac1625cd6", + "f358351612004f64adffb931c3130603", + "7593358526ae4a87bf4be0eb1bcfc076", + "51536b45f5674d498272dc7b2def635d", + "8fbe2a3fc07943e7bf0fdc927bab795a", + "6b265cc65d5a42638572c1776faafdb1", + "39fa86a7760d43c793eb8ef27475af7d", + "eee5113e2dd1402faf76d00f07d8e0af", + "6792ed7123724b2d8091bc8d36255e68", + "e35094b24c154340bb1b3ebba7ac0a0d", + "dd63bb6ffed34b6687a0c79d8af93fb7", + "32080bc9381c449ab63794655ec6d714", + "eb7aa289fefc465d98edeed9ce2bff51", + "53fae218b4b74863af5fe53a66a5f7ef", + "35bc6d95c60f4c3d8ddc6b3b0845ff7e", + "f4765ca278ad4da4b465bd2920a21320", + "7ac6ead5baef4f30aff170a30a9a7977", + "e7adb5eb38d54b29b734d207982411c8", + "8f4f51b75af74daa9b9ad6696760109c", + "ae4db932b7544c6cb9ff668fa954addd", + "be63f07eedbd4d46ac4913df45216108", + "2e47d9e7b36a4ec69a9071930671ae8e", + "7b1c7f9bf0e8412abb66bcfc24cf9668", + "5c8742d3f663470e9977d006e83314b7", + "74ec67e07ee0477eb41e21093ae82858", + "4b60a8f023bc4d759bc197b11bf4e160", + "7a090f162fa84568a5e486ba935c3ed1", + "8b650428a6834f5d8ebe62ad327493e0", + "5c4d22bce82546d28a8b0c041895c8e3", + "16121b830a2948afb3ca8eb54e27a678", + "0305a4b4408f4562b87b58098148326d", + "68f07b5b7ad447ce9a87023d872c2e73", + "2156a5ced089414c99a1bb8dd3a0b3b7", + "2e6cd134c70e455a85c47b1575135883", + "f4264985b5cc4a0f970a088fb90b8bcf", + "71d790bf25324e6dbb5372f636c53da9", + "dac3ba29ee4d4083a9abca7eab632534", + "5c75c020a1914da680340fe826f3f58d", + "195e6dfb82c84f0191838acbbfe38126", + "b06adcaf8d4c497897ed3625f3afb4eb", + "d4ab3971183a4e8fa10402e3542e6466", + "444ca1f5213241c2bc71fa9ebe9ac3ca", + "34d571f76ef845f4bc272a5e05491c31", + "e8ee76b022d64b2cb24a2cb7b61aeef7", + "8c9ac87788b04ae6899f3b62fdc3ed0d", + "431b638c435444c38e50a09573b8f31b", + "0430f22e24d14171b83261faa090f349", + "0fa5ae935a554461b086a4b81470b9ad", + "f072e665d27e442ab4d0e2eb33c98db9", + "fd3b1885c39c4b70b083d7fddf74d4b6", + "f77051cb151645559223ecf835426688", + "0e17661f878948598703ee7942e5e1a2", + "fca913c6cfff48099d1744d5b091fc46", + "085baf51ecef46318ceafbaba2bb4490", + "52309039c2d8421bbb8e99f63f5ba91f", + "f4233cd960ea4f549734a5b1e1da5e2e", + "42ce1b7765f547cd9ecd8b428ec1c718", + "e72a08514d3b42d2b5fbf87a920bcdf0", + "ad05cf4c0ed44341aa3cd2cbd22b513d", + "db9915d53d784b85accebe1552c4e7e1", + "9519b6d9bf1b45e3b56da4c28d2aeb2e", + "cfeb0597708b49fa9b65342e1ac446ae", + "e29617eff6fd4199a74b670198ba2a69", + "1cea197a15d94654a0e792318435d707", + "89dcb96670a8433593e3452fad3c9210", + "0802085388be453b8fe5edee7e0a01ef", + "1ed257f19b8b44ee85f09e10178ae52f", + "04107981561149cba5baf74ccba87aa6", + "09afb010020e4b2f91d7cdbdca316962", + "b11b51beaa54474cb7682110bd2d24ae", + "47822470ddf842cd9e3368090549a2b5", + "835bce5d87a2417c9b6a5b27627447dc", + "5ca06dd536d44de784984a492d23573f", + "8e75bdb4469e497c8f021ebde7c6c9b3", + "7f4d4f8ece1d4651a2186f10a0cc25a5", + "92036442af5f4b698f2a54ecba4650e2" + ] + }, + "id": "b95a87a8-2136-4e03-a36c-42e5d53a3e28", + "outputId": "6094328e-8c33-4b40-80e9-08c5cfb3e277" + }, + "outputs": [], + "source": [ + "# Load embedding model\n", + "model_embedding = SentenceTransformer(\"intfloat/e5-small-v2\", device='cuda')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "733cf41d-e81e-4cfc-b597-67da02dbc3cf", + "metadata": { + "id": "733cf41d-e81e-4cfc-b597-67da02dbc3cf" + }, + "outputs": [], + "source": [ + "# Init Chroma\n", + "client = chromadb.PersistentClient(path=CHROMA_PATH)\n", + "collection = client.get_or_create_collection(name=\"price_items\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f493c7d-1c72-40f9-a5c6-63c7f6b1cf2c", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 91 + }, + "id": "1f493c7d-1c72-40f9-a5c6-63c7f6b1cf2c", + "outputId": "72627732-4eee-4d9a-c8cb-0c42e2541a80" + }, + "outputs": [], + "source": [ + "# Format description function (no price in text)\n", + "def description(item):\n", + " text = item[\"text\"].replace(\"How much does this cost to the nearest dollar?\\n\\n\", \"\")\n", + " text = text.split(\"\\n\\nPrice is $\")[0]\n", + " return f\"passage: {text}\"\n", + "\n", + "description(train[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f44bf613-adf6-4993-bf7b-6aa9fad21a03", + "metadata": { + "id": "f44bf613-adf6-4993-bf7b-6aa9fad21a03" + }, + "outputs": [], + "source": [ + "batch_size = 300 # how many items to insert into Chroma at once\n", + "encode_batch_size = 1024 # how many items to encode at once in GPU memory\n", + "\n", + "for i in tqdm(range(0, len(train), batch_size), desc=\"Processing batches\"):\n", + "\n", + " end_idx = min(i + batch_size, len(train))\n", + "\n", + " # Collect documents and metadata\n", + " documents = [description(train[j]) for j in range(i, end_idx)]\n", + " metadatas = [{\"price\": train[j][\"price\"]} for j in range(i, end_idx)]\n", + " ids = [f\"doc_{j}\" for j in range(i, end_idx)]\n", + "\n", + " # GPU batch encoding\n", + " vectors = model_embedding.encode(\n", + " documents,\n", + " batch_size=encode_batch_size,\n", + " show_progress_bar=False,\n", + " normalize_embeddings=True\n", + " ).tolist()\n", + "\n", + " # Insert into Chroma\n", + " collection.add(\n", + " ids=ids,\n", + " documents=documents,\n", + " embeddings=vectors,\n", + " metadatas=metadatas\n", + " )\n", + "\n", + "print(\"✅ Embedding and storage to ChromaDB completed.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2e2ccc9-b772-45f7-8258-cbc4f9c3ed59", + "metadata": {}, + "outputs": [], + "source": [ + "# Now flush and clean\n", + "print(\"🧹 Cleaning up and saving ChromaDB...\")\n", + "client = None\n", + "gc.collect()" + ] + }, + { + "cell_type": "markdown", + "id": "c35d2fab-583f-4527-a7cc-9d31214b2f35", + "metadata": {}, + "source": [ + "Our ChromaDB is currently saved in a persistent Google Drive path; for a production-ready app, we recommend uploading it to AWS S3 for better reliability and scalability.\n", + "\n", + "🧩 Now that we've generated the E5 embeddings, let's use them for both **XGBoost regression** and **GPT-4o Mini with RAG** ." + ] + }, + { + "cell_type": "markdown", + "id": "40e4c587-211d-4bc0-91cf-6267f45405d6", + "metadata": { + "id": "40e4c587-211d-4bc0-91cf-6267f45405d6" + }, + "source": [ + "## 📈 Embedding-Based Regression with XGBoost" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f058ccac-3392-457d-b54c-6471960e9af3", + "metadata": { + "id": "f058ccac-3392-457d-b54c-6471960e9af3" + }, + "outputs": [], + "source": [ + "# Step 1: Load vectors and prices from Chroma\n", + "result = collection.get(include=['embeddings', 'documents', 'metadatas'])\n", + "vectors = np.array(result['embeddings'])\n", + "documents = result['documents']\n", + "prices = [meta['price'] for meta in result['metadatas']]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "JYQo0RaMb8Ql", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 254 + }, + "id": "JYQo0RaMb8Ql", + "outputId": "c1641347-1fd4-41bb-e060-147224fc6bed" + }, + "outputs": [], + "source": [ + "# Step 2: Train XGBoost model\n", + "xgb_model = XGBRegressor(n_estimators=100, random_state=42, n_jobs=-1, verbosity=0)\n", + "xgb_model.fit(vectors, prices)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "yaqG0z7jb919", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yaqG0z7jb919", + "outputId": "6a2f9120-97e0-4436-aa12-40d94fbc5c64" + }, + "outputs": [], + "source": [ + "# Step 3: Serialize XGBoost model locally for Hugging Face upload\n", + "MODEL_DIR = os.path.join(ROOT, \"models\")\n", + "MODEL_FILENAME = \"xgboost_model.pkl\"\n", + "LOCAL_MODEL = os.path.join(MODEL_DIR, MODEL_FILENAME)\n", + "\n", + "os.makedirs(MODEL_DIR, exist_ok=True)\n", + "joblib.dump(xgb_model, LOCAL_MODEL)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Z_17sQUdxIr3", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 104, + "referenced_widgets": [ + "2362f3121e5546b98e4623eb3680e96b", + "ef53ee3b68c840d6a3fe98386d26bbd9", + "a4768d0ecdd640a2a5bccd07a93c54b7", + "e177440016974bc699b666fa721c6490", + "2a9d0e5829174b738b4dfea1c71a3481", + "ee6dffc7b79e405d923940166ef10590", + "57bf3388622241869a5e9dab558dca72", + "aa87f4feddd6409fbfb81f417e5d6662", + "973a83ca118e4ed1b5a51821034ecc31", + "d5a3c955aba14b3ea8e9b5c90a3bf20a", + "daaa4f26bad545a394685e266f85a6ae" + ] + }, + "id": "Z_17sQUdxIr3", + "outputId": "68ebdbdb-d42e-4bc8-addc-85b42d418d1d" + }, + "outputs": [], + "source": [ + "# Step 4: Push serialized XGBoost model to Hugging Face Hub\n", + "api = HfApi(token=hf_token)\n", + "REPO_NAME = \"smart-deal-finder-models\"\n", + "REPO_ID = f\"{HF_USER}/{REPO_NAME}\"\n", + "\n", + "# Create the model repo if it doesn't exist\n", + "api.create_repo(repo_id=REPO_ID, repo_type=\"model\", private=True, exist_ok=True)\n", + "\n", + "# Upload the saved model\n", + "api.upload_file(\n", + " path_or_fileobj=LOCAL_MODEL,\n", + " path_in_repo=MODEL_FILENAME,\n", + " repo_id=REPO_ID,\n", + " repo_type=\"model\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f59125d-9fa6-483b-957f-4423a9b2c900", + "metadata": { + "id": "3f59125d-9fa6-483b-957f-4423a9b2c900" + }, + "outputs": [], + "source": [ + "# Step 5: Define the predictor\n", + "def xgb_predictor(datapoint):\n", + " doc = description(datapoint)\n", + " vector = model_embedding.encode([doc], normalize_embeddings=True)[0]\n", + " return max(0, xgb_model.predict([vector])[0])" + ] + }, + { + "cell_type": "markdown", + "id": "a890f1f0-d827-472f-a7a9-6c2cbe3d8341", + "metadata": { + "id": "a890f1f0-d827-472f-a7a9-6c2cbe3d8341" + }, + "source": [ + "🔔 Reminder: In Part 2, XGBoost with Word2Vec (non-contextual embeddings) achieved:\n", + "- Avg. Error: ~$107\n", + "- RMSLE: 0.83\n", + "- Accuracy: 29.20%\n", + "\n", + "🧪 Now, let’s see if contextual embeddings improve XGBoost." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "q-tIbVilTPxP", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 718 + }, + "id": "q-tIbVilTPxP", + "outputId": "7c9043ef-a2c4-4933-b334-18d99690ba0f" + }, + "outputs": [], + "source": [ + "# Step 4: Run the Tester on a subset of test data\n", + "tester = Tester(xgb_predictor, test)\n", + "tester.run()" + ] + }, + { + "cell_type": "markdown", + "id": "dcb09db0-7d69-40e1-a6e3-b92263e38f1e", + "metadata": { + "id": "dcb09db0-7d69-40e1-a6e3-b92263e38f1e" + }, + "source": [ + "Xgb Predictor Error=$110.68 RMSLE=0.93 Hits=30.4%" + ] + }, + { + "cell_type": "markdown", + "id": "1ccd5d3f-98cd-45a8-951f-d6446062addc", + "metadata": { + "id": "1ccd5d3f-98cd-45a8-951f-d6446062addc" + }, + "source": [ + "Results are nearly the same. In this setup, switching to contextual embeddings didn’t yield performance gains for XGBoost." + ] + }, + { + "cell_type": "markdown", + "id": "4db1051d-9a7e-4cec-87fc-0d77fd858ced", + "metadata": { + "id": "4db1051d-9a7e-4cec-87fc-0d77fd858ced" + }, + "source": [ + "## 🚰 Retrieval-Augmented Pipeline – GPT-4o Mini\n", + "\n", + "- Preprocess: clean the input text (description(item))\n", + "- Embed: generate embedding vector (get_embedding(item))\n", + "- Retrieve: find similar items from ChromaDB (find_similar_items)\n", + "- Build Prompt: create the LLM prompt using context and masked target (build_messages)\n", + "- Predict: get price estimate from LLM (estimate_price)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "YPLxSn7eHp9N", + "metadata": { + "id": "YPLxSn7eHp9N" + }, + "outputs": [], + "source": [ + "test[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eFxFKNroNiyD", + "metadata": { + "id": "eFxFKNroNiyD" + }, + "outputs": [], + "source": [ + "# Step 1: Preprocess test item text\n", + "# (uses the same `description(item)` function as during training)\n", + "description(test[1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lxIEtSWYHqCT", + "metadata": { + "id": "lxIEtSWYHqCT" + }, + "outputs": [], + "source": [ + "# Step 2: Embed a test item\n", + "def get_embedding(item):\n", + " return model_embedding.encode([description(item)])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "y43prQsuHp_w", + "metadata": { + "id": "y43prQsuHp_w" + }, + "outputs": [], + "source": [ + "# Step 3: Query Chroma for similar items\n", + "def find_similars(item):\n", + " results = collection.query(query_embeddings=get_embedding(item).astype(float).tolist(), n_results=5)\n", + " documents = results['documents'][0][:]\n", + " prices = [m['price'] for m in results['metadatas'][0][:]]\n", + " return documents, prices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "nxAOUFRkHp6v", + "metadata": { + "id": "nxAOUFRkHp6v" + }, + "outputs": [], + "source": [ + "documents, prices = find_similars(test[1])\n", + "documents, prices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "djPoSk6sHo84", + "metadata": { + "id": "djPoSk6sHo84" + }, + "outputs": [], + "source": [ + "# Step 4: Format similar items as context\n", + "def format_context(similars, prices):\n", + " message = \"To provide some context, here are some other items that might be similar to the item you need to estimate.\\n\\n\"\n", + " for similar, price in zip(similars, prices):\n", + " message += f\"Potentially related product:\\n{similar}\\nPrice is ${price:.2f}\\n\\n\"\n", + " return message" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "F3yxhnqSHp4C", + "metadata": { + "id": "F3yxhnqSHp4C" + }, + "outputs": [], + "source": [ + "print(format_context(documents, prices))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "pEJobsKNHqE8", + "metadata": { + "id": "pEJobsKNHqE8" + }, + "outputs": [], + "source": [ + "# Step 5: Mask the price in the test item\n", + "def mask_price_value(text):\n", + " return re.sub(r\"(\\n\\nPrice is \\$).*\", r\"\\1\", text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vLhBNVBNQAHS", + "metadata": { + "id": "vLhBNVBNQAHS" + }, + "outputs": [], + "source": [ + "# Step 6: Build LLM messages\n", + "def build_messages(datapoint, similars, prices):\n", + "\n", + " system_message = \"You estimate prices of items. Reply only with the price, no explanation.\"\n", + "\n", + " context = format_context(similars, prices)\n", + "\n", + " prompt = mask_price_value(datapoint[\"text\"])\n", + " prompt = prompt.replace(\" to the nearest dollar\", \"\").replace(\"\\n\\nPrice is $\", \"\")\n", + "\n", + " user_prompt = context + \"And now the question for you:\\n\\n\" + prompt\n", + "\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " {\"role\": \"assistant\", \"content\": \"Price is $\"}\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "I94fNHfBHp1a", + "metadata": { + "id": "I94fNHfBHp1a" + }, + "outputs": [], + "source": [ + "build_messages(test[1], documents, prices)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5NfY_GAVHpy4", + "metadata": { + "id": "5NfY_GAVHpy4" + }, + "outputs": [], + "source": [ + "# Step 7: Run prediction\n", + "def get_price(s):\n", + " s = s.replace('$','').replace(',','')\n", + " match = re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", s)\n", + " return float(match.group()) if match else 0\n", + "\n", + "def gpt_4o_mini_rag(item):\n", + " documents, prices = find_similars(item)\n", + " response = openai.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=build_messages(item, documents, prices),\n", + " seed=42,\n", + " max_tokens=5\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Pg-GJTT0HpwV", + "metadata": { + "id": "Pg-GJTT0HpwV" + }, + "outputs": [], + "source": [ + "print(test[1][\"price\"])\n", + "print(gpt_4o_mini_rag(test[1]))" + ] + }, + { + "cell_type": "markdown", + "id": "54103ab4-d6dd-4c0b-add5-5d9741e934b4", + "metadata": { + "id": "54103ab4-d6dd-4c0b-add5-5d9741e934b4" + }, + "source": [ + "🔔 Reminder: In Part 2, GPT-4o Mini (without RAG) achieved:\n", + "- Avg. Error: ~$99\n", + "- RMSLE: 0.75\n", + "- Accuracy: 44.8%\n", + "\n", + "🧪 Let’s find out if RAG can boost GPT-4o Mini’s price prediction capabilities.\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "r0NGJupwHppF", + "metadata": { + "id": "r0NGJupwHppF" + }, + "outputs": [], + "source": [ + "Tester.test(gpt_4o_mini_rag, test)" + ] + }, + { + "cell_type": "markdown", + "id": "00545880-d9e1-4934-8008-b62c105d177b", + "metadata": { + "id": "00545880-d9e1-4934-8008-b62c105d177b" + }, + "source": [ + "Gpt 4O Mini Rag Error=$59.54 RMSLE=0.42 Hits=69.2%" + ] + }, + { + "cell_type": "markdown", + "id": "2b9f46ae-92b5-4189-89b0-df88a600bb89", + "metadata": { + "id": "2b9f46ae-92b5-4189-89b0-df88a600bb89" + }, + "source": [ + "🎉 **GPT-4o Mini + RAG shows clear gains:** \n", + "Average error dropped from **$99 → $59.54**, RMSLE from **0.75 → 0.42**, and accuracy rose from **48.8% → 69.2%**. \n", + "\n", + "Adding retrieval-based context led to a strong performance boost for GPT-4o Mini.\n", + "\n", + "Now the question is — can fine-tuning push it even further, surpass RAG, and challenge larger models?\n", + "\n", + "🔜 See you in the [next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part4_ft_gpt4omini.ipynb)" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "A100", + "provenance": [] + }, + "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/week6/community-contributions/lisekarimi/09_part4_ft_gpt4omini.ipynb b/week6/community-contributions/lisekarimi/09_part4_ft_gpt4omini.ipynb new file mode 100644 index 0000000..84ca7e6 --- /dev/null +++ b/week6/community-contributions/lisekarimi/09_part4_ft_gpt4omini.ipynb @@ -0,0 +1,510 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "12934dbc-ff4f-4dfc-8cc1-d92cc8826cf2", + "metadata": {}, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 4)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- ➡️ Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA\n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# 🔧 Part 4: Fine-Tuning GPT-4o Mini\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ✅ CPU is sufficient — no GPU required\n", + "- 🛠️ Requirements: 🔑 HF Token, Open API Key, wandb API Key\n", + "- Tasks:\n", + " - Convert chat data to .jsonl format for OpenAI\n", + " - Fine-tune the model and monitor with Weights & Biases\n", + " - Test the fine-tuned GPT-4o Mini \n", + "\n", + "Can fine-tuning GPT-4o Mini outperform both its zero-shot baseline and RAG-enhanced version? \n", + "Time to find out.\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5809630f-d3ea-41df-86ec-9cbf59a46f5c", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import importlib\n", + "import json\n", + "import re\n", + "from dotenv import load_dotenv\n", + "from huggingface_hub import login\n", + "from datasets import load_dataset\n", + "from openai import OpenAI" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4120c84d-c310-4d31-9e1f-1549ea4a4186", + "metadata": {}, + "outputs": [], + "source": [ + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if not openai_api_key:\n", + " print(\"❌ OPENAI_API_KEY is missing\")\n", + "\n", + "openai = OpenAI(api_key=openai_api_key)\n", + "\n", + "hf_token = os.getenv('HF_TOKEN')\n", + "if not hf_token:\n", + " print(\"❌ HF_TOKEN is missing\")\n", + "\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "markdown", + "id": "31d3aa97-68a8-4f71-a43f-107f7c8553c5", + "metadata": {}, + "source": [ + "## 📥 Load Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2bae96a", + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c45e23d6-1304-4859-81f0-35a9ddf1c755", + "metadata": {}, + "outputs": [], + "source": [ + "HF_USER = \"lisekarimi\"\n", + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "\n", + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "667adda8-add8-41b6-9e60-7870bad20c02", + "metadata": {}, + "outputs": [], + "source": [ + "test[0]" + ] + }, + { + "cell_type": "markdown", + "id": "b85d86d0-b6b1-49cd-9ef0-9214c1267199", + "metadata": {}, + "source": [ + "## 🛠️ Step 1 : Data Preparation" + ] + }, + { + "cell_type": "markdown", + "id": "d3ba760d-467a-4cd9-8d3f-e6ce84273610", + "metadata": {}, + "source": [ + "To fine-tune GPT-4o-mini, OpenAI requires training data in **.jsonl format**. \n", + "\n", + "`make_jsonl` converts our chat data :\n", + "\n", + "from \n", + "\n", + "[\n", + " {\"role\": \"system\", \"content\": \"You estimate prices of items. Reply only with the price, no explanation\"},\n", + " {\"role\": \"user\", \"content\": \"How much is this laptop worth?\"},\n", + " {\"role\": \"assistant\", \"content\": \"Price is $999.00\"}\n", + "]\n", + "\n", + "into the .jsonl format \n", + "\n", + "{\"messages\": [{\"role\": \"system\", \"content\": \"You estimate prices of items. Reply only with the price, no explanation\"}, {\"role\": \"user\", \"content\": \"How much is this laptop worth?\"}, {\"role\": \"assistant\", \"content\": \"Price is $999.00\"}]}\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec254755-67f6-4676-b67f-c1376ea00124", + "metadata": {}, + "outputs": [], + "source": [ + "# Mask the price in the test item\n", + "def mask_price_value(text):\n", + " return re.sub(r\"(\\n\\nPrice is \\$).*\", r\"\\1\", text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5e51957-b0ec-49f9-ae70-74771a101756", + "metadata": {}, + "outputs": [], + "source": [ + "def messages_for(datapoint):\n", + " system_message = \"You estimate prices of items. Reply only with the price, no explanation\"\n", + " user_prompt = mask_price_value(datapoint[\"text\"]).replace(\" to the nearest dollar\", \"\").replace(\"\\n\\nPrice is $\",\"\")\n", + " assistant_response = f\"Price is ${datapoint['price']:.2f}\"\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " {\"role\": \"assistant\", \"content\": assistant_response}\n", + " ]\n", + "\n", + "messages_for(train[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03583d32-b0f2-44c0-820e-62c8e7e48247", + "metadata": {}, + "outputs": [], + "source": [ + "def make_jsonl(datapoints):\n", + " result = \"\"\n", + " for datapoint in datapoints:\n", + " messages = messages_for(datapoint)\n", + " messages_str = json.dumps(messages, ensure_ascii=False)\n", + " result += '{\"messages\": ' + messages_str + '}\\n'\n", + " return result.strip()\n", + "\n", + "make_jsonl(train.select([0]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36c9cf60-0bcb-44cb-8df6-ff2ed4110cd2", + "metadata": {}, + "outputs": [], + "source": [ + "ft_train = train.select(range(100))\n", + "ft_validation = train.select(range(100, 150))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "494eaecd-ae5d-4396-b694-6faf88fb7fd6", + "metadata": {}, + "outputs": [], + "source": [ + "# Convert the items into jsonl and write them to a file\n", + "\n", + "def write_jsonl(datapoints, filename):\n", + " with open(filename, \"w\", encoding=\"utf-8\") as f:\n", + " jsonl = make_jsonl(datapoints)\n", + " f.write(jsonl)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae42986d-ab02-4a11-aa0c-ede9c63ec7a2", + "metadata": {}, + "outputs": [], + "source": [ + "write_jsonl(ft_train, \"data/ft_train.jsonl\")\n", + "write_jsonl(ft_validation, \"data/ft_val.jsonl\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9bed22d-73ad-4820-a983-cbdccd8dbbc8", + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"data/ft_train.jsonl\", \"rb\") as f:\n", + " train_file = openai.files.create(file=f, purpose=\"fine-tune\")\n", + "with open(\"data/ft_val.jsonl\", \"rb\") as f:\n", + " validation_file = openai.files.create(file=f, purpose=\"fine-tune\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e6c6ce8-6600-4068-9ec5-32c6428ce9ea", + "metadata": {}, + "outputs": [], + "source": [ + "train_file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26943fad-4301-4bb4-97e8-be52a9743322", + "metadata": {}, + "outputs": [], + "source": [ + "validation_file" + ] + }, + { + "cell_type": "markdown", + "id": "edb0a3ec-1607-4c5b-ab06-852f951cae8b", + "metadata": {}, + "source": [ + "## 🚀 Step 2: Run Fine-Tuning & Monitor with wandb\n", + "We will use https://wandb.ai to monitor the training runs\n", + "\n", + "1- Create an API key in wandb\n", + "\n", + "2- Add this key in OpenAI dashboard https://platform.openai.com/account/organization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59f552fe-5e80-4742-94a8-5492556a6543", + "metadata": {}, + "outputs": [], + "source": [ + "wandb_integration = {\"type\": \"wandb\", \"wandb\": {\"project\": \"gpt-pricer\"}}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "144088d7-7c30-439a-9282-1e6096c181ea", + "metadata": {}, + "outputs": [], + "source": [ + "# Run the fine tuning\n", + "\n", + "openai.fine_tuning.jobs.create(\n", + " training_file=train_file.id,\n", + " validation_file=validation_file.id,\n", + " model=\"gpt-4o-mini-2024-07-18\",\n", + " seed=42,\n", + " hyperparameters={\"n_epochs\": 1},\n", + " integrations = [wandb_integration],\n", + " suffix=\"pricer\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "330e75f5-0208-4c74-8dd3-07bc06047b2e", + "metadata": {}, + "outputs": [], + "source": [ + "job_id = openai.fine_tuning.jobs.list(limit=1).data[0].id\n", + "job_id\n", + "\n", + "# Then check your wandb dashboard to view the run of this job ID" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a92dac5-e6d8-439c-b55e-507becb37a6c", + "metadata": {}, + "outputs": [], + "source": [ + "# Use this command to track the fine-tuning progress here\n", + "\n", + "openai.fine_tuning.jobs.list_events(fine_tuning_job_id=job_id, limit=2).data" + ] + }, + { + "cell_type": "markdown", + "id": "b6b65677-06b2-47d3-b0e6-51210a3d832b", + "metadata": {}, + "source": [ + "# 📧 You’ll get an email once fine-tuning is complete. ☕ You can take a break until then. ▶️ Once you receive it, run the cells below to continue." + ] + }, + { + "cell_type": "markdown", + "id": "0a7af4be-0b55-4654-af7a-f47485babc52", + "metadata": {}, + "source": [ + "## Step 3 : Test the fine tuned model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8497eb8-49ee-4a05-9e51-fc1b4b2b41d4", + "metadata": {}, + "outputs": [], + "source": [ + "ft_model_name = openai.fine_tuning.jobs.retrieve(job_id).fine_tuned_model\n", + "ft_model_name" + ] + }, + { + "cell_type": "markdown", + "id": "12bed33f-be31-4d7c-8651-3f267c529304", + "metadata": {}, + "source": [ + "You can find the entire fine-tuning process in the **Fine-tuning** dashboard on OpenAI.\n", + "\n", + "![Fine-tuning Process](https://github.com/lisekarimi/lexo/blob/main/assets/09_ft_gpt4omini.png?raw=true)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac6a89ef-f982-457a-bad7-bd84b6132a07", + "metadata": {}, + "outputs": [], + "source": [ + "# Build LLM messages\n", + "def build_messages(datapoint):\n", + " system_message = \"You estimate prices of items. Reply only with the price, no explanation\"\n", + " user_prompt = mask_price_value(datapoint[\"text\"]).replace(\" to the nearest dollar\", \"\").replace(\"\\n\\nPrice is $\",\"\")\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " {\"role\": \"assistant\", \"content\": \"Price is $\"}\n", + " ]\n", + "\n", + "def get_price(s):\n", + " s = s.replace('$','').replace(',','')\n", + " match = re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", s)\n", + " return float(match.group()) if match else 0\n", + "\n", + "def gpt_ft(datapoint):\n", + " response = openai.chat.completions.create(\n", + " model=ft_model_name,\n", + " messages=build_messages(datapoint),\n", + " seed=42,\n", + " max_tokens=7\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return get_price(reply)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93a93017-458c-4769-b81c-b2dad2af7552", + "metadata": {}, + "outputs": [], + "source": [ + "print(test[0][\"price\"])\n", + "print(gpt_ft(test[0]))" + ] + }, + { + "cell_type": "markdown", + "id": "87a5ad10-ed60-4533-ad61-225ceb847e6c", + "metadata": {}, + "source": [ + "🔔 **Reminder:** \n", + "- In **Part 2**, GPT-4o Mini (zero-shot) scored: \n", + " Avg. Error: ~$99 | RMSLE: 0.75 | Accuracy: 44.8% \n", + "\n", + "- In **Part 3**, with **RAG**, performance improved to: \n", + " Avg. Error: ~$59.54 | RMSLE: 0.42 | Accuracy: 69.2%\n", + "\n", + "🧪 **Now it’s time to see** if fine-tuning can push GPT-4o Mini even further and outperform both baselines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0adf1500-9cc7-491a-9ea6-88932af85dca", + "metadata": {}, + "outputs": [], + "source": [ + "import helpers.testing\n", + "importlib.reload(helpers.testing)\n", + "\n", + "from helpers.testing import Tester # noqa: E402\n", + "\n", + "tester = Tester(gpt_ft, test)\n", + "tester.run()" + ] + }, + { + "cell_type": "markdown", + "id": "37439666", + "metadata": {}, + "source": [ + "Gpt Ft Error=$129.16 RMSLE=0.94 Hits=35.2%" + ] + }, + { + "cell_type": "markdown", + "id": "5487da30-e1a8-4db5-bf17-80bc4f109524", + "metadata": {}, + "source": [ + "**Fine-tuning GPT-4o Mini led to worse performance than both its zero-shot and RAG-enhanced versions.**\n", + "\n", + "⚠️ When Fine-Tuning Isn’t Needed:\n", + "- For tasks like price prediction, GPT-4o performs well with prompting alone — thanks to strong pretraining and generalization.\n", + "- 💡 Fine-tuning isn’t always better. Use it when prompting fails — not by default.\n", + "\n", + "✅ **When Fine-Tuning Is Worth It (based on OpenAI’s own guidelines)**\n", + "- Custom tone/style – e.g., mimicking a brand voice or writing like a specific author\n", + "- More consistent output – e.g., always following a strict format\n", + "- Fix prompt failures – e.g., when multi-step instructions get ignored\n", + "- Handle edge cases – e.g., rare product types or weird inputs\n", + "- Teach new tasks – e.g., estimating prices in a custom format no model has seen before\n", + "\n", + "---\n", + "\n", + "Now that we’ve explored both frontier closed-source models and traditional ML, it’s time to turn to open-source.\n", + "\n", + "🚀 **Next up: Fine-tuned LLaMA 3.1 8B (quantized)** — can it beat its base version, outperform GPT-4o Mini, or even challenge the big players?\n", + "\n", + "🔍 Let’s find out in the [next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part5_llama31_8b_quant.ipynb)" + ] + } + ], + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/week6/community-contributions/lisekarimi/data/human_output.csv b/week6/community-contributions/lisekarimi/data/human_output.csv new file mode 100644 index 0000000..e516273 --- /dev/null +++ b/week6/community-contributions/lisekarimi/data/human_output.csv @@ -0,0 +1,1500 @@ +"How much does this cost to the nearest dollar? + +OEM AC Compressor w/A/C Repair Kit For Ford F150 F-150 V8 & Lincoln Mark LT 2007 2008 - BuyAutoParts NEW +As one of the world's largest automotive parts suppliers, our parts are trusted every day by mechanics and vehicle owners worldwide. This A/C Compressor and Components Kit is manufactured and tested to the strictest OE standards for unparalleled performance. Built for trouble-free ownership and 100% visually inspected and quality tested, this A/C Compressor and Components Kit is backed by our 100% satisfaction guarantee. Guaranteed Exact Fit for easy installation 100% BRAND NEW, premium ISO/TS 16949 quality - tested to meet or exceed OEM specifications Engineered for superior durability, backed by industry-leading unlimited-mileage warranty Included in this K + +Price is $",120 +"How much does this cost to the nearest dollar? + +Motorcraft YB3125 Fan Clutch +Motorcraft YB3125 Fan Clutch Package Dimensions 25.146 cms (L) x 20.066 cms (W) x 15.494 cms (H) Package Quantity 1 Product Type Auto Part Country Of Origin China Manufacturer Motorcraft, Brand Motorcraft, Model Fan Clutch, Weight 5 pounds, Dimensions 10 x 7.63 x 6.25 inches, Country of Origin China, model number Exterior Painted, Manufacturer Part Rank Automotive Automotive Replacement Engine Fan Clutches 583, Domestic Shipping can be shipped within U.S., International Shipping This item can be shipped to select countries outside of the U.S. Learn More, Available October 10, 2007 + +Price is $",80 +"How much does this cost to the nearest dollar? + +Dorman Front Washer Fluid Reservoir Compatible with Select Ford/Lincoln/Mercury Models +This washer fluid reservoir is designed to match the fit and function of the original equipment reservoir. It is engineered to withstand the stresses of underhood heat and engine vibration on specified vehicle makes, models, and years. This part is compatible with the following vehicles. Before purchasing, enter your vehicle trim in the garage tool to confirm fitment. Ford Explorer 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Lincoln Aviator 2003, 2004, 2005 - Mercury Mountaineer 2002, 2003, 2004, 2005, + +Price is $",35 +"How much does this cost to the nearest dollar? + +HP Premium HD Plus Touchscreen 1TB HDD 2.3GHz AMD Ryzen 5, (12GB RAM, Ryzen 5 4500U, DVD Writer, Windows 10 Home) Natural Silver, (Renewed) +This pre-owned or refurbished product has been professionally inspected and tested to work and look like new. How a product becomes part of Amazon Renewed, your destination for pre-owned, refurbished products A customer buys a new product and returns it or trades it in for a newer or different model. That product is inspected and tested to work and look like new by Amazon-qualified suppliers. Then, the product is sold as an Amazon Renewed product on Amazon. If not satisfied with the purchase, renewed products are eligible for replacement or refund under the Amazon Renewed Guarantee. + +Price is $",350 +"How much does this cost to the nearest dollar? + +Super Switch Pickup Selector Super Switch 4-Pole Double Wafer for Strat/Nashville Tele Guitars with Black/Ivory/White Tips +Dopro Super Switch Pickup Selector Super Switch 4-Pole Double Wafer for Strat/Nashville Tele Guitars with Black/Ivory/White Tips Package includes 3 free tips which normally sold separately Five-position blade pickup selector switch ideal for four-conductor pickups. Used on American made Fat Strat and Double Fat Strat models, and on Nashville Telecaster models. Mounting screws included. Mounting screws and 35mm cavity depth required 1-5/8 standard mounting screw spacing Please consult your local Luthier if you don't know how to install the switch Dimensions 5.47 x 4.29 x 0 + +Price is $",75 +"How much does this cost to the nearest dollar? + +Horror Bookmarks, Resin Horror Bookmarks for Adults, The Best Gift for Fans of Horror Novels, Horror Personalized Bookmarks for Men Women, Horror Figures Sculpture Bookmarks (Set) +Horror Bookmarks - The Best Gift for Fans of Horror Novels, Resin Horror Bookmarks for Adults, Half-Length Figure Sculpture Bookmarks, Horror Bookmark Set for Men Women Office Supplies Specification Upper Part Material Resin Lower Part Of Material Wood Character Size 3.3cm x 2cm / x Overall Size 10cm / 4inch Package Includes 1 / 6 x Horror bookmarks - the best gift for fans of horror novels Note 1. Due to manual measurements, please allow slight measurement deviations. 2. Due to the different display and lighting effects, the + +Price is $",12 +"How much does this cost to the nearest dollar? + +SK6241 - Stinger 4 Gauge 6000 Series Power Amplifier Installation Kit +Amplifier installation kits can save you time & money when installing an amplifier in your vehicle. Instead of purchasing everything you need separately like power/ground cables, remote turn-on cable, fuse blocks, fuses, and more, you can get an amp kit that already has the cables & accessories in one package. Amplifier wiring kits come in various gauge configurations depending on the wattage of your sound system and include all the necessary components you need to successfully install an amplifier. This Stinger 4 AWG 6000 Series Power Amplifier Wiring Kit includes all the necessary hardware and wire to power one amplifier and is designed specifically for car audio systems up to 1750 watts. The included premium power + +Price is $",115 +"How much does this cost to the nearest dollar? + +Godox ML60Bi LED Light Kit, Handheld LED Video Light, Bi-Color LED Light, CRI 96+ TLCI 97+, 7 FX Effects, Slient Mode, with Softbox, RC-A6 Remote Control, 2X NP970 Lithium Battery +🌸Breathtakingly powerful and portable 10100 Lux @ 1 m with the included reflector. Weighing just 0.77 kg (lightweight housing only), the ML60Bi is extremely easy to hold and carry. In relation to its small size, it produces an impressively high output and thus offers you more flexible creativity for your productions. 🌸Variable color temperature The wide color temperature range from 2800K to 6500K allows you to quickly + +Price is $",100 +"How much does this cost to the nearest dollar? + +Randall G3 Plus Combo Guitar Amp +The Randall G3 is a combo amplifier that brings even more intensity and aggressiveness to your guitar playing with a redesigned preamp circuit, a 12 speaker, and digital effects. Randall took the high gain tone circuit of their flagship V2 and T2 guitar amplifiers and installed it in each of the G3 Plus amps. What you get is higher professional level tone and performance without the costs of a high-end amp. EQ Controls - Bass, Middle, Treble, Sweep, Voicing Master Control - Volume Power Output - 100 Watts @ 4 Ohms Single Speaker - 12 Celestion Seventy 80 2 Mode - Weight 51 Pounds, Dimensions 13.5 x 27 x 20.5 inches, + +Price is $",300 +"How much does this cost to the nearest dollar? + +HOLDWILL 6 Pack LED Shop Light, 4FT 24W 6500K, Cool White, Clear Cover, Hight Output, Linkable 4 Foot LED Strip Lights, T8 LED Tube Lights, LED Light Fixture for Garage Ceiling with Plug Cable +Specification Length Power 24W Lumen 2640lm CCT 6500K Beam Angle 120 degrees Luminous Flux 110lm per watt LED chips 120pcs Color Rendering Index(CRI) 85 Operation Temperature °F Lamp Power Factor 0.95 Input Voltage Material Top quality Aluminum & superior PC BRIGHT - HOLDWILL shop light bring your application the best lighting available with an incredible minimum of Illuminate the dark corners of your space SAVING - Each led under cabinet light has 24w + +Price is $",80 +"How much does this cost to the nearest dollar? + +Viking Horns 3 Gallon Air Tank and 200 PSI Air Compressor Kit, for Train Air Horn +New 3 gallon (12 liter) Air Tank & 200 PSI H.D Air Compressor Kit. For high pressure air horns systems that require an on-board air system. Air tank made from heavy gauge steel for outdoor use. Compact design and weight. Comes as a kit, ready to install, with 240 psi Air Gauge, 200 psi Air Pressure Switch, Compression Fittings for 1/4 O.D air hose, air pressure release safety valve. Comes with a 200 PSI Heavy Duty Air Compressor with a 1/4 inch NPT braided air hose, and Mounting Hardware. Both, Air Tank & Compressor Kit come complete ready for installation + +Price is $",90 +"How much does this cost to the nearest dollar? + +CURT 70110 Custom Tow Bar Base Plate Brackets for Dinghy Towing, Fits Select Jeep Wrangler JK +CUSTOM FIT. This tow bar base plate is uniquely engineered to fit select years of the Jeep Wrangler JK. It bolts onto the frame, providing a reliable connection for flat towing (not compatible with universal tow bar) HIGHLY VERSATILE. Add versatile towing options to your vehicle with this class 1 trailer hitch. It provides a standard, square receiver hitch and comes with a ball mount with a ball hole to connect a small trailer SOLID STRENGTH. CURT towing base plates and tow bar brackets are constructed from high-strength steel and welded together with precision for dependable towing strength DOUBLE FINISH. This tow plate is finished in a tough shield of dual-co + +Price is $",120 +"How much does this cost to the nearest dollar? + +Solar HAMMERED BRONZE Finish Post Deck Fence Cap Lights for 4 X 4 WOOD Post With White LEDs and Vertical-lined Clear Lens -GREEN NATURAL SOLAR +During the day, these energy-efficient Atlantic Solars lights harness sunlight energy to charge their internal Lithium Battery. At night they automatically turn on, emitting a bright glow for your fence post line. Each Atlantic Solars light is made of Premium Heat-Resistant Plastic for years of use. With our Newest & Improved Solar Panels, a 3.2V Lithium Ion Battery, and 5 Ultra Bright White LEDs, its output is virtually unparalleled. Atlantic Solars 4 x 4 Fence Post Caps One Pre-Installed 3.2V Lithium-Ion Battery for each light Light source + +Price is $",300 +"How much does this cost to the nearest dollar? + +COSTWAY Electric Tumble Dryer, Sliver +This is our brand new compact dryer with 10 lbs. cloth capacity, it will be your best helper to dry your cloth or sheet in a short time, It has four mode air dry, cool, warm, and hot. You can choose the drying time or mode according to the material and weight of the cloth. This dryer combine the cooling, wrinkle, freshening, function, without taking up a lot of room will bring much convenience for your life. Don't hesitate to buy one! feature brand new and high quality 1. 5 cu. Ft. Capacity allows you to dry up to 10 lbs. Of clothing stainless steel tub provides durability see- through window lets you monitor clothes as they dry four mode air dry + +Price is $",450 +"How much does this cost to the nearest dollar? + +FREE SIGNAL TV Transit 32 12 Volt DC Powered LED Flat Screen HDTV for RV Camper and Mobile Use +Mobile High Performance 32 inch LED TV - Get HD picture quality from this superb DC-powered 12 volt television with 1366 x 768 resolution. Groundbreaking engineering results in a lightweight TV with dynamic audio response and advanced noise reduction circuitry. The Easy-to-Set-Up and Versatile RV Flat Screen TV - Simple 12V connection. 3 HDMI Inputs. Can also be used at home by converting to AC with the included 1260 Power Brick Adapter. Perfect Television for Campers, Trailers, RVs, and More - The Transit 32 inch 12 volt powered flat screen TV is also ideal for cars and trucks. With high-resolution picture from a + +Price is $",280 +"How much does this cost to the nearest dollar? + +Bilstein 5100 Monotube Gas Shock Set compatible with Jeep Cherokee XJ w/2-3 Lift +Bilstein 5100 shocks utilize a monotube design, with a 46mm digressive piston, to increase road handling characteristics both on and off-road. The single tube body allows for rapid heat transfer between the shock oil to the shock body, and then dissipated further to reduce shock fade. German engineering combined with US manufacturing ensures optimum performance and longevity for upwards of 100k miles (real customer feedback!). The 5100 series is more compliant in tougher situations and off-road terrain compared to the 4600 series. Factory spec vehicles should use the 4600 series shocks as the valving is more appropriate for daily driven vehicles and pavement environments. Part Numbers + +Price is $",140 +"How much does this cost to the nearest dollar? + +Sangean K-200 Multi-Function Upright AM/FM Digital Radio (Pink) +Product Description The K-200 from SANGEAN brings sleekness and uniqueness into a multi-media entertainment unit including the features from traditional alarm clock. The versatile and unique omni-directional speaker design fills your work place with high-performance sound quality that plays your music with crystal clear digital sound and deep bass for more powerful overall sound. The eye-catching night light with 8 brightness settings definitely gives a little brightness to your counter. From the Manufacturer Sangean's new sleek and unique K-200 AM / FM-RBDS Digital Tuning Kitchen Radio brings a multi-media entertainment center to your kitchen combines the features of a traditional alarm clock. The versatile and unique omni-directional speaker design fills your + +Price is $",19.99 +"How much does this cost to the nearest dollar? + +Charles Leonard Magnetic Lapboard Class Combo Pack, Includes 12 Each Plain/Plain 9 x 12 Inch White Boards, 2-Inch Erasers, Black Dry Erase Markers +Class pack provides an environmentally friendly way for children to learn. Dry-erase surface lets students write, wipe off and reuse with no waste. Classroom set includes magnetic lap boards that are dual-sided; dry-erase markers; and multipurpose erasers. ALL INCLUSIVE set has everything you need for the classroom! 12 Each Double Sided Magnetic Plain/Plain 9x12 lap boards. Individual dry erase boards are large enough to work on for math problems, English language arts, Penmanship or for drawing. Just write and wipe, it’s that easy SAFETY FIRST each set also includes 30 + +Price is $",85 +"How much does this cost to the nearest dollar? + +Gigabyte AMD Radeon HD 7870 2 GB GDDR5 Mini-Displayport PCI-Express 3.0 Graphic Card +Powered by AMD Radeon HD 7870 GPU and Integrated with the industry's best 2 GB GDDR5 memory and memory interface Ultra Durable VGA Components - GPU Temperature 5%-10% Down - Overclocing Capability Up - Power Switching Loss Down WINDFORCE 3X Anti-Turbulence Cooling with New Triangle Cool Technology Gold Plated HDMI for optimum signal transfer between connections Features mini-Display port outputs with HDCP protection Supports AMD Eyefinity/Eyespeed/CrossFire/Avivo HD Technologies Minimum Recommended Power Supply 500W or greater with 2x 6-pin VGA power connectors Max Screen Resolution 4096 x + +Price is $",450 +"How much does this cost to the nearest dollar? + +3dRose LLC 8 x 8 x 0.25 Inches Bull Terrier on Zebra Pattern Mouse Pad +Bull Terrier On Zebra Mouse Pad is 8 x 8 x.25 and is made of heavy-duty recycled rubber. Matte finish image will not fade or peel. Machine washable using a mild detergent and air dry. Dimensions (in inches) 8 W x 8 H x 0.25 D Matte finish Soft to touch, will not crack or peel Clean with mild detergent Made of heavy-duty recycled rubber Manufacturer 3D Rose (Home Improvement), Brand Weight 4.9 ounces, Dimensions 8 x 0.25 x 8 inches, model number Shape Square, Material Type Rubber, s 1, Size 8\ x + +Price is $",7 +"How much does this cost to the nearest dollar? + +ROKINON 85mm F1.4 Auto Focus Full Frame Weather Sealed High Speed Telephoto Lens for Nikon F Mount +Dslr camera lens For Nikon F Mount full-frame & APS-C DSLR cameras Aperture range f/1.4 to f/16 Ultra multi-coated Optics; weather-sealed Takes front filter size of 77mm Constructed of 9 elements in 7 groups Dimensions 2.9 x 3.2 x 3.2 inches, Weight 1.06 pounds, model number Rank SLR Camera Lenses 1944, Available April 18, 2019, Manufacturer Rokinon, Country of Origin Korea, Republic of, Brand Rokinon, Focal Length Description 85mm, Lens Type Telephoto + +Price is $",320 +"How much does this cost to the nearest dollar? + +Headlight Assembly Compatible with 2012 2013 2014 2015 Civic Sedan 4-Door 12 13 Civic Coupe 2-Door Black Housing Amber Reflector +Vehicle compatibility headlights assembly compatible with Civic Sedan 4-Door / Civic Coupe high beam mode 9005 and low beam mode 9006; bulbs are not included Waterproof fully sealed with solid silicon & designed with one-way vents to prevent moisture from being trapped inside the housing, no corrosion or moisture worries in sorts of weather conditions Brighter lighting the metallic parabolic reflectors provide more light output to create a broader and smoother beam Safety reflector the sided micro-prism reflector makes the oncoming cars or passerby quickly notice you at night, ensuring your driving safety and others' Impact resistance the + +Price is $",110 +"How much does this cost to the nearest dollar? + +ASI NAUTICAL 2.5 Inches Opera Glasses Binoculars for Adults with Handle- Captain's Mother of Pearl Solid Brass Opera Glasses Binoculars-Pocket Size Handel Binoculars for Kids, Bird Watching, Hunting +Thanks for Visiting Best Antique & Nautical Items store at amazon ASI NAUTICAL This 2.5 Captains Solid Brass Black & White Binocular By ASI NAUTICAL made with Antique Finish is best suitable to gift your loved ones. Easy to carry to any outdoor place like when you go to watch football match,Any historical Monuments,Visit Mountains,hills, for Hunting,Birds Watching,etc. Material Brass Magnification 10x Approx. Total Weight 0.19 kg Approx. Binocular Size 2.5 Inches, + +Price is $",65 +"How much does this cost to the nearest dollar? + +Behringer TUBE OVERDRIVE TO100 Authentic Tube-Sound Overdrive Effects Pedal +BEHRINGER TUBE OVERDRIVE TO100 Authentic Tube-Sound Overdrive Effects Pedal Get tube-like distortion, smooth sustain and super fat tone Get tube-like distortion, smooth sustain and super fat tone This BEHRINGER product has been designed to compete head to head with leading products on the market This BEHRINGER product has been designed to compete head to head with leading products on the market Captures every nuance of your playing from smooth overdrive to screaming tube sounds Captures every nuance of your playing from smooth overdrive to screaming tube sounds Dedicated Drive, Tone and Level controls for awesome sound shaping Dedicated Drive, Tone and Level controls for awesome sound shaping Status LED for effect on/off and + +Price is $",185 +"How much does this cost to the nearest dollar? + +Fun Express Insect Finger Puppets - 24 finger puppet bugs for kids +You'll get an assortment of 24 insect finger puppets including bees, butterflies, ladybugs, dragonflies, and grasshoppers. Each plastic bug finger puppet is made of quality vinyl and measures 1 3/4 - 2 3/4. Plastic bugs and insects for kids make a fun and creative gift and can be used as party favors or decorations for your bug themed party! Adult supervision recommended for children under 3 years as small parts could be a choking hazard. 24 Insect Finger puppets for toddlers and children. Each finger puppet is made of vinyl and measures 1 3/4 - 2 3/4. You'll get an assortment of toy bugs and + +Price is $",6 +"How much does this cost to the nearest dollar? + +WAFJAMF Roller Stamp Identity Theft Stamp Perfect for Privacy Protection(Blue) +IDENTITY THEFT PROTECTION SOLUTION Paper can be recycled after using roller stamp, no need for a shredder. WIDE COVERAGE DESIGN The 1.26 inches wide roller is perfect for covering large swaths of private information in a quick and clean way. SAVE TIME Ink quickly dries. Stamp works well on all regular paper, envelopes and package addresses. One swipe and the info is covered, no need to go for a shredder. UNIQUE DESIGN FOR PRIVACY PROTECTION Compact design with CONFIDENTIAL letters, specially designed to obscure the text underneath it. Total length of stamp coverage can reach 50 meters. Dimensions 2.72 x 1.89 x 1.38 inches, Weight + +Price is $",33 +"How much does this cost to the nearest dollar? + +Capulina Tiffany Floor Lamp 16 Wide Stained Glass Dragonfly Antique Style Standing Reading Light for Living Room Bedroom +Size and Weight lamp shade 16 inches wide and lamp post 63 inches Height;product total weight is 18lbs And the base heavy is 6.6lbs to ensure stability Real tiffany lamp shade lamp shade is handmade by skilled craftsmen,Each small piece of stained glass of the lampshade is spliced by copper foil method,never fade color,durable and beautiful Bulb Matching We can use Incandescent or CFL bulbs (bulbs are not included),different bulbs get different looking,recommanding to use Edison LED bulb. Decor living room bedroom When you light bulb up,tiffany lamp shade eallows the light to filter in but also softens the heat and + +Price is $",65 +"How much does this cost to the nearest dollar? + +Apple Watch Series 6 (GPS, 44mm) - Space Gray Aluminum Case with Black Sport Band (Renewed Premium) +Apple Watch Series 6 (GPS, 44mm) - Space Gray Aluminum Case with Black Sport Band LEAVE YOUR PHONE IN YOUR POCKET Apple Watch Series 6 GPS Model lets you call, text, and get directions from your wrist, while leaving your phone in your pocket. It offers multiple connectivity options, including Bluetooth, Wi-Fi, and NFC to suit all of your possible needs. ALWAYS-ON RETINA DISPLAY You no longer need to raise your wrist or touch the screen to see the time or other information on your watch face, because the display never sleeps. All you need to do is glance to find the time or your workout metrics right there where you + +Price is $",199 +"How much does this cost to the nearest dollar? + +ICON 01725 Tandem Axle Fender Skirt FS1724 for KZ - Cobalt Blue +Tandem axle fender skirt measures to 65-1/4 x 14. Constructed of durable high-impact ABS plastic. This replacement fender skirt is textured. The legs of these fender skirts curve underneath the trailer. Durable, high-impact ABS plastic Textured finish Quick and simple installation Color Cobalt Blue Size 65-1/4 x 14 Brand ICON, Color Regular, Exterior Finish Smooth, Material Acrylonitrile Butadiene Styrene, Dimensions LxWxH 14.5 x 5 x 2.9 inches, Style Modern, Auto Part Position Lower, Vehicle Service Type Trailer, Fit Type Universal + +Price is $",310 +"How much does this cost to the nearest dollar? + +SanDisk 128GB Ultra (10 Pack) MicroSD Class 10 Micro SDXC Memory Card for Smartphone Bundle with (1) GoRAM Reader 10 Pack) +Shoot and save more high-quality photos and full HD video on your Android smartphone or tablet with SanDisk Ultra microSD UHS-I cards. With storage capacities up to 128GB, they're the ideal complement for Android smartphones and tablets. And the SanDisk memory zone app, available on the Google play store, makes it easy to view, access, and back up all of your files from your phones memory in one convenient place. To help your smartphone run at its peak performance, This app can be set to automatically off-load files from your smartphones internal memory to your memory card. Bundle Includes (10x) 128GB + +Price is $",180 +"How much does this cost to the nearest dollar? + +Velvac - 715427 +2020 Mirror System, 2003 & Newer Ford E-Series Cutaway Standard Head, Black, Htd Remote Flat Glass, Wedge Convex, 102 Body Width, Left Side 2020 System, Ford E, 102 Body, Black, Left Side Htd Remote Flat Glass, Wedge Convex, Standard Head Model 2020 mirrors are designed specifically for wide body applications such as high cube cut away vans, rental trucks, Class C RV's and ambulances. The fixed length arms are designed to position the mirror beyond the body providing the driver with an unobstructed view of blind spots and passing lanes around the vehicle. These versatile mirrors are available in several body widths and finishes as well as manual or heated remote glass + +Price is $",110 +"How much does this cost to the nearest dollar? + +TCMT Passenger Backrest Sissy Bar & Luggage Rack Fits For Indian Scout Scout Sixty Scout ABS 2020 Scout 100th Anniversary Scout Sixty ABS +An Indian Scout passenger will ride with greater comfort and confidence with this Quick Release Passenger Sissy Bar. This sturdy backrest can be installed quickly and easily without tools once a set of Mounting Spools are installed on the Motorcycle. The Passenger Backrest locks securely onto the Mounting Spools and provides the passenger with strong, stable support and comfort. The backrest must be equipped with a Genuine Leather Backrest Pad. To add convenient cargo space, an accessory Chrome Backrest Luggage Rack can be added to the backrest. Fitment Fit For 2020 Scout 100th Anniversary Fit For Scout Sixty ABS Fit For + +Price is $",85 +"How much does this cost to the nearest dollar? + +Alnicov 63.5MM Brass Tremolo Block,Tremolo System Bridge,With Bar Block For Fender Strat Stratocaster Bridge +Description 1.Fits bridges with 2-1/16 E to E string pacing and 6 screw modifications install (detailed instructions included) Fits for MIM Fender Standard Series StratAmerican Special StratMIM Classic PlayerClassic Vibe StratAny Import Strat with 6 screw pivot mounting and 2 1/16 string spacing Specifications Tremlo block block dia size brassWeight 248g Package included 1Pcs tremolo bar wrench Durable Electric Guitar Bridge Tremolo Block High quality, easy to handle Sustain your guitar bridge Add mass and sustain to your bridge along with the tonal qualities of brass Since this block is larger + +Price is $",65 +"How much does this cost to the nearest dollar? + +Subaru Forester Outback Legacy OEM Engine Block Heater Genuine new +Manufactured from top quality components, this is your inexpensive replacement option for your rebuild, repair, and maintenance needs. When you select a genuine OEM part - you can rely on the high quality and effectiveness of the product and brand without having to guess if the product will work in sequence with your vehicle. Protecting your investment is important and choosing the right parts can be challenging. Stick with what you know and choose a genuine OEM part. Genuine Subaru Genuine Engine Block Heater Warms engine coolant to promote easier starting in extreme cold conditions. Plugs into a a household electrical outlet. Crosstrek Hybrid models Forester Outback 2.5 Legacy 2.5 Manufacturer Subaru, Brand Subaru, Weight 1 pounds, Dimensions + +Price is $",350 +"How much does this cost to the nearest dollar? + +Richmond Auto Upholstery - 2012 Dodge Ram 3500 Laramie Crew-Cab - Driver Side Bottom Replacement Perforated Leather Seat Cover Dark Gray +Our OEM replacement leather seat covers are guaranteed to match your vehicles interior! Richmond Auto Upholstery has been manufacturing automotive seat covers for over 30 years and only specializing in original factory replacement leather covers & much more! If you cannot find what you need for your Dodge Ram then please give us a call at (281) with your vehicles information!To ensure you receive the correct cover, please send us your VIN Number & TRIM (Interior Trim) Code during check out or email it to us after you have made your purchase. If we do not receive this information within 24 hours we will send an email requesting the information + +Price is $",260 +"How much does this cost to the nearest dollar? + +AP-39 Automotive Paint Primer Grey 2K Urethane Gallon Kit Normal Activator +Automotive paint primer sealer applied as a high build sanding primer or final non-sanding primer sealer. Compatible with AF 970 Black Automotive Base coat certified to be among the Deepest Black Base coats in the market. Not for sale in California, Delaware, and Maryland. Direct to Metal Excellent Filling Properties; Superior Color Holdout Easy Spray and Sanding Shipped by UPS ground only. No overnight shipping. The material is considered hazardous and cannot be returned. Not for sale in California, Delaware, and Maryland. Brand enenfeifei, Color Grey, Size 2 Piece Set, Volume 1 Gallons, Special Feature Not for sale in California, Delaware, and Maryland + +Price is $",200 +"How much does this cost to the nearest dollar? + +Road Top Wireless Carplay Retrofit Kit Decoder for BMW i3 I01 NBT System Year, Support Android Auto, Mirrorlink, Reverse Camera, Original Car Knob Control +Pre-shopping Notes When you buy, please check our website picture to make sure your car system is right. This Wireless Carplay Fits for BMW i3 I01 NBT System Not fit for EVO system. Wireless/Wired Apple Carplay It can work with Siri/ Maps/ Music/ Phone Call. Built-in mic for Siri function and Bluetooth call, use Maps(Support Google Waze and sygic map, etc), listen to your favorite songs using iTunes, Apple Music or other app and access to messages. Keep your original car knob and steering wheel control. Wireless/Wired Android Auto Use wireless or wired connection ( + +Price is $",95 +"How much does this cost to the nearest dollar? + +Gibson Performance Exhaust 5658 Aluminized Dual Extreme Cat-Back Performance Exhaust System +For the extremist who wants to take their truck to the next level, this dual bolt-on Cat back system is for you. This system exists behind the rear tires at an aggressive angle with a powerful exhaust tone. You will gain bold street looks with powerful dyno tuned and tested street performance gains. You can expect to experience gains on average of 15-20 horsepower. Gibson muffler provides a mean performance sound and complemented with polished Stainless Steel Tip. Easy bolt-on installation. No welding required. Backed by a Lifetime Limited Warranty. If you want Extreme, this system is it. 3 inch aluminized mandrel bent tubing Gibson muffler features a baffled and chambered design, + +Price is $",499 +"How much does this cost to the nearest dollar? + +Bella Tunno Happy Links - Baby Montessori Silicone Links & Soft Silicone Baby Toys, Developmental Toys for Playing, Teething, Gross Motor Skills, Color Recognition & More, Navy, SL07 +Introducing your new favorite product. Is it a toy? A teether? A link? Yes, it is. It’s pretty much magic what our Happy Links can do. We took the classic link and made it into the product we wish we had for our littles. Generously sized, easy to grip and wrapped in food-grade silicone, our links relieve little gums, keep toys and lovies attached and keeps kids entertained. Our Happy Links set includes 5 links for teething playing and organizing. Attach them to the stroller, rocker, play gym, or carrier to bring + +Price is $",18 +"How much does this cost to the nearest dollar? + +CANMORE H300 Handheld GPS Golf Device, Shot Distance Yardage Measuring, 40000+ Free Worldwide Preloaded Courses, Lightweight Golf Accessory for Golfers, Powerful Magnetic Clip for Golf Cart, Orange +WORLDWIDE COURSE DATA - Free course data preloaded for over 40,000 (and counting) golf courses around the world (NO subscription fees) - Contact Canmore to add new courses or suggest fixes. ***Notice Golf courses may change layout over time, when detected, the device will display “Incorrect Hole” and require course update. Please visit the CANMORE website for updates and new course information. ESSENTIAL FUNCTIONS YOU NEED - Manage your game, not your golf assistant! GPS course finder switches hole automatically and gives you easy-to-access distance to green ( + +Price is $",299 +"How much does this cost to the nearest dollar? + +DCPOWER AC Adapter Compatible Replacement for KORG PS60 PS-60 61-Key Portable Performance Synthesizer +New aftermarket, custom-made item (NON-OEM/NON-Original Equipment Manufacturer). Auto-Switching adapter can be used in the worldwide. Returns accepted within 30 Days. Quantity 1 unit of adapter. Connector type Round Barrel/Round tip Can be used to power up the device Input AC for using in the worldwide Output 9V DC Dimensions 3 x 2 x 1.5 inches, Weight 6 Ounces, Rank Musical Instruments Keyboard Power Supplies 5234, Is Discontinued No, Available October 24, 2013, Manufacturer DCPOWER, Brand Generic, Connector Type barrel connector, Special Feature Portable, Input Voltage 240 Volts, + +Price is $",88 +"How much does this cost to the nearest dollar? + +Sharp, Commercial Desktop Calculator, LCD +Resume function lets you recall data after shut-off. Extra-large digits for excellent readability. Dual solar/battery power for use in any lighting. Resume function lets you recall data after shut-off. Extra-large digits for excellent readability. Dual solar/battery power for use in any lighting. Dimensions 7.2 x 5.1 x 1 inches, Weight 6.4 ounces, model number Batteries 1 CR2 batteries required. (included), Rank Office Products Basic Office Calculators 1027, Is Discontinued No, Available December 27, 2004, Manufacturer SHARP ELECTRONICS, Brand Sharp, Color Black, Calculator Type Business, Power Source Battery Powered, Batteries 1 CR2 batteries required. (included) + +Price is $",32 +"How much does this cost to the nearest dollar? + +Melissa & Doug Lifelike Plush Stork Giant Standing Stuffed Animal (3+ Feet Tall) +This lifelike plush stork really delivers! A terrific way to welcome a new baby and a great companion for years to come, this striking silky white stork with black wingtips and realistic details is sure to turn heads. Standing an impressive three-plus feet tall, this lifelike bird’s soft, squeezable body covered with silky feathers encourage hugs and cuddles, while quality construction and a strong interior structure keep it standing proudly for years to come. The included baby bib The stork wears proclaims “welcome baby”. the stories long bright orange legs stand on an oval two-foot-long base for extra stability. Kids’ imaginations are sure to take flight with this beautiful feathered + +Price is $",25 +"How much does this cost to the nearest dollar? + +Sony SSCS8 2-Way Center Channel Speaker with Bookshelf Speaker System and Subwoofer Bundle (3 Items) +Equipped with two 4 woofers and a 1 tweeter, the Sony SS-CS8 2-Way Center Channel Speaker handles 145W of peak power. The speaker's woofers use a mica-reinforced diaphragm, the upper surface of which is fashioned to deliver supple and faithful sound quality, while the bottom layer is designed to provide a powerful bass response. The cabinet of the SS-CS8 is made from wood, which is designed to provide a natural resonance, and its bass reflex construction will give directionality to the low frequencies. The speaker's crossover network is mounted directly to the cabinet for vibration isolation, which is intended + +Price is $",95 +"How much does this cost to the nearest dollar? + +ASUS Chromebook CX1, 14 Full HD NanoEdge Display, Intel Celeron N3350 Processor, 64GB eMMC, 4GB RAM, Chrome OS, Transparent Silver, +ASUS Chromebook CX1400 is made for boosting productivity and having more fun while on the move — all day, every day. This lightweight, ultraportable device is powered by Intel processor and gives you the freedom of up to battery life. The slim-bezel design fits more screen into the compact chassis for easy multitasking and incredibly immersive entertainment, and the device is your gateway to the best of Google, including the rich library of apps for work or play on the Google Play Store. With speedy performance, robust security and intuitive features, ASUS Chromebook CX1 is ideal for anyone + +Price is $",440 +"How much does this cost to the nearest dollar? + +FiiO X7 32GB Hi-Res Lossless Music Player, Titanium +FiiO X7 High Resolution Audio Player FiiO X7 High Resolution Audio Player- Currently supports Music Player function only. DAC and other features will be available through future firmware upgrade Dimensions 2.52 x 5.12 x 0.65 inches, Weight 7.8 ounces, model number FIIO X7, Rank Electronics MP3 & MP4 Players 2510, Is Discontinued No, OS Android 4.4.4, RAM 32 GB, Connectivity technologies Aux, Special features Hi Res Audio, Other display features Wireless, Color Titanium Blue, Manufacturer FiiO, Available November 30, 2015, Brand FiiO, Model Name X7, + +Price is $",60 +"How much does this cost to the nearest dollar? + +TORRO Leather Case Compatible with iPhone 14 – Genuine Leather Wallet Case/Cover with Card Holder and Stand Function (Red) +COMPATIBILITY – The TORRO leather iPhone 14 case with card holder is designed and crafted exclusively for iPhone 14. The precision fit ensures full, unrestricted access to the screen, camera, buttons and charging port. GENUINE LEATHER - TORRO are a UK company specialising in luxury leather goods handcrafted from premium cowhide leather. The top-grain leather used is sourced from the finest tanneries in the US and undergoes minimal treatment in order to preserve the natural properties and appearance of TORRO luxurious leathers. SHOCKPROOF – The folio case features a unique TORRO durable TPU frame that has been formulated to aid shock absorption, + +Price is $",45 +"How much does this cost to the nearest dollar? + +Universal Air Conditioner KT 1031 A/C Compressor and Component Kit +UAC A/C Compressor and Component Kit Brand New, OE replacement UAC branded Compressor Kit 100% Guaranteed Fit! Add your car (year/make/model) to Amazon's garage to confirm Premium ISO/TS 16949 quality; tested to meet or exceed OEM specifications Includes compressor & clutch, drier / accumulator, expansion device, 8oz bottle of PAG oil, seal kit; compressor may come charged with shipping oil to keep the part lubricated during transit - drain and replace according to your system's requirements Product is backed by industry leading warranty Manufacturer UAC, Brand UAC, Model KT 1031, Weight 17.9 pounds, Dimensions 17 x 16 x 12 + +Price is $",65 +"How much does this cost to the nearest dollar? + +Street Series Stainless Performance Cat-Back Exhaust system +Made in the USA and engineered to last, for those seeking increased performance and better economy, MagnaFlow MF Series Performance Exhaust systems deliver the smooth deep sound you want and the wide-open performance power you need. Our exhaust systems feature straight-through flow designs for the ultimate in unrestricted horsepower and torque for big power while maintaining exhaust efficiency. These systems are an engineered balance of interior and exterior noise levels and are tested against SAE j1169 standards. great quality and sound Manufacturer MagnaFlow, Brand MagnaFlow Exhaust Products, Model 17870, Weight 25 pounds, Dimensions 58.75 x 13.75 x 19 inches, model number 17870, Exterior Machined, Manufacturer Part 17870, Rank Automotive Automotive Replacement + +Price is $",260 +"How much does this cost to the nearest dollar? + +Lenovo IdeaPad 3 Laptop, FHD (1920 x 1080) AMD Ryzen 5 3500U 8GB DDR4 RAM, 256GB SSD, AMD Radeon Vega 8 Graphics Windows 10, Abyss Blue (Renewed) +14 FHD TN Anti-glare, Ryzen 5 3500U Mobile Processor - 3.80 GHz) 256GB SSD, 8GB DDR4 SDRAM 180 degree hinge, WiFi and Bluetooth 5.0 720p HD Webcam with Dolby Audio dual speakers, 4-in-1 Media Card Reader 2 x USB 3.1 | 1 x USB 2.0 | 1 x HDMI | headphones, Windows 10 in S mode Brand Lenovo, Model Name Lenovo Ide + +Price is $",360 +"How much does this cost to the nearest dollar? + +Access Bed Covers TonnoSport - Roll-Up Tonneau Cover - Compatible with Toyota Tundra 6ft. 6in. Bed (w/o Deck Rail) +Tonneau Cover TONNOSPORT Roll-Up Cover TONNOSPORT Roll-Up Cover; Roll-Up; Without Deck Rail;FEATURES Gives You A Sleek Low Profile Look Gives You A Sleek Low Profile Look Compatible With Bed Rails/Bed Caps/Tailgate Protector Compatible With Bed Rails/Bed Caps/Tailgate Protector Quick Clamp On Installation Quick Clamp On Installation Lockable/Protects Your Cargo Lockable/Protects Your Cargo Complete Bed Usage When Open Complete Bed Usage When Open No Need To Remove No Need To Remove Tailgate Stays Operational Tailgate Stays Operational 2 Year Warranty 2 Year Warranty + +Price is $",55 +"How much does this cost to the nearest dollar? + +G.I. JOE Hasbro 3 3/4 Wave 5 Action Figure SGT. Flash (Laser Rifle Trooper) +SGT. FLASH is highly skilled in many aspects of electronic technology and is capable of equipment repair in the field. His specialized education includes electronics school, chemical school, and covert electronics. He is a qualified expert with the M-16, and (shoulder laser rifle). Celebrate 25 years of the ultimate action team with this articulated action figure! Display your action figure on the included display base! Figure also comes with a weapon! Twenty-fifth anniversary action figure has detailed styling and comes with a weapon and a display base! Ages 5 and up. Dimensions 5.12 x 1.57 x 5.51 inches, Weight + +Price is $",29 +"How much does this cost to the nearest dollar? + +T&S Brass Double Pantry Faucet, Wall Mount, 8 Centers, 6 Swing Built in Stops +T&S Brass 8 Wall Mount Mixing Faucet, Eterna Cartridges, Lever Handles, 6 Swing Nozzle, Built-In Stops & 1/2 NPT Female Inlets. Package Dimensions 9 L x 4 H x 14 W (inches) Package Weight 5.11 pounds Country of Origin United States Part Number Brand T&S Brass, Mounting Type Wall Mount, Finish Type Polished, Color Brass, Handles 1, Included Components Nozzle, Instruction Manual, Handle Type Lever, Installation Type Single Hole, Dimensions LxWxH 13.3 x 8.8 x 3.7 inches, Handle Material Brass, + +Price is $",65 +"How much does this cost to the nearest dollar? + +ZTUOAUMA Fuel Injection Pump Compatible with Cummins Engine M11 N14 QSM11 ISM11 +Part Number Application Models Compatible with Cummins Diesel Engine M11 N14 QSM11 ISM11 Note Please verify the part number and the detailed parts on pumps between our pictures before buying Warranty Returnable for 6 Months and Changeable for 1 Year (return and change for free) Direct replacement with strict and full test in factory to ensure the long durable service life Brand ZTUOAUMA, Fit Type Vehicle Specific Fit, Vehicle Service Type Truck, Style Fashion, Auto Part Position Rear, Gas Type Diesel, Operation Mode Mechanical, Manufacturer zt truck parts, Weight 11.51 pounds, Dimensions 9.92 x 9.06 x 7.6 + +Price is $",250 +"How much does this cost to the nearest dollar? + +Hp Prime Graphing Calculator Ii +Hp Prime Graphing Calculator Ii IB Diploma Programme exam approved Sleek, slim, brushed metal design that looks great and performs even better. Keep the calculator protected when it's not in use with a slide-on cover Enjoy a feature-rich calculating experience with familiar HP alphanumeric keypad and a large diagonal, multi-touch display Lithium-Ion rechargeable battery, 256 MB flash memory Unique STEM ecosystem with HP Prime Graphing Calculator, HP Prime Wireless Kit1, and HP Connectivity Kit Dimensions 3.66 x 0.65 x 7.28 inches, Weight 8 ounces, model number Batteries 1 Lithium Ion batteries required., Rank Office Products 27247, Basic Office Calculators 79, Available July 10, 2019, + +Price is $",39 +"How much does this cost to the nearest dollar? + +Lowrance Nmea 2000 25' Extension Cable +Lowrance n2k extension cable Red plugs NMEA 2000 extension cable Mfg.# Lowrance connectors. Package Dimensions 10 L x 3 H x 5 W (inches) Country of Origin Mexico Part number For use with LGC 3000 and red NMEA network Dimensions L x W x H 9.92 x 4.25 x 3.23 inches, Weight 0.79 Pounds, Dimensions LxWxH 10 x 5 x 3 inches, Weight 0.32 Kilograms, Brand Name Lowrance, Model Name Color Red, s 1, Manufacturer Lowrance, Part Model Year 2015, Included Components Lowrance Nmea + +Price is $",35 +"How much does this cost to the nearest dollar? + +Jeep Genuine Accessories Hood Lock +Hood lock rivits on using existing holes. Self codes to the ignition key. Same as standard in Europe, meets Thatchem requirements. When you select a genuine OEM part you can rely on the high quality and effectiveness of the product and brand without having to guess if the product will work in sequence with your vehicle. Protecting your investment is important and choosing the right parts can be challenging. Stick with what you know and choose a genuine OEM part. Fits Wrangler Hood lock secures underhood items from theft Rivits into existing holes and automatically codes itself to the vehicle ignition key during installation Same as the production hood lock for European markets Manufacturer Jeep, Brand Jeep, Model Weight 3.7 pounds, Dimensions 8.2 x 7.8 + +Price is $",65 +"How much does this cost to the nearest dollar? + +GODOX CB-06 Hard Carrying Case with Wheels +Godox CB-06 Hard Carrying Case with Wheels Carrying/Transport Options Dual connecting straps Top handle Wheels Dimensions 94.0 x 34.0 x 25.0cm (37.01 x 13.39 x 9.84 ) Dimensions 41.25 x 16.25 x 12.5 inches, Weight 7.5 pounds, model number CB 06, Rank Tripod & Monopod Cases 13, Is Discontinued No, Available August 24, 2017, Manufacturer Godox, Language English, Brand GODOX, Color Black, Closure Type Zipper, Pattern Solid, Dimensions LxWxH 41.25 x 16.25 x + +Price is $",75 +"How much does this cost to the nearest dollar? + +Au-Tomotive Gold, INC. Ford Black Valet Key Chain +Milled alloy black finish with easy release spring-loaded key ring for valet parking. Laser cut engraved logo will never fade. Showing OEM style car logo on one side. It is about 4 long. Brand new Official licensed product. Milled alloy black finish with easy release spring-loaded key ring for valet parking. Laser cut engraved logo will never fade. Showing OEM style car logo on one side. It is about 4 long. Brand new Official licensed product. Manufacturer Au-Tomotive Gold, INC, Brand Au-Tomotive Gold, INC., Weight 1.44 ounces, Dimensions 4.3 x 2.1 x 0.6 inches, Manufacturer Part Rank Automotive Keychains 18749 + +Price is $",35 +"How much does this cost to the nearest dollar? + +Snailfly Black Roof Rack Rail + Cross Bar Fit for Honda All New CRV CR-V (4pcs +FITMENT Roof Rack Cross Bars Fit For Honda CRV CR-V 2017 2018 2019 2020 2021 2022 Please make sure the fitment before your purchase 2 PACKAGES Package 1# 2pcs Roof Racks Package 2# 2pcs Crossbars Necessary Mounting Hardware Like Bolts Are Included. SPECIFICS 100% Brand New Smooth surface Item exactly as the picture showed High Quality Aluminum Alloy Long lasting & durable finish, suitable for all weathers INSTALLATION Please contact us via message if you need installation insturctions. FEATURES Low profile streamline design,efficiently reduce wind resistance and noise. Greatly increase overall + +Price is $",125 +"How much does this cost to the nearest dollar? + +KING SHA Anti Glare LED Track Lighting Heads (50W Eqv.) Compatible with Halo Pack +Stable performance dimming capabilities that work seamlessly with universal dimmers, allowing you to adjust the brightness smoothly from 10% to 100% without any flickering. Anti-glare design to provide soft and eye-friendly lighting. The glare-free grid helps to reduce eye strain and protect your vision. Compatibility with H-type circuit track systems, making them suitable for a wide range of track lighting applications. GU10 base with a twist and turn type, which makes it easy to change bulbs. The 7W dimmable MR16 bulb with a high color rendering index of 90+ and a color temperature of 3000K (50W equivalent) provides bright and vibrant illumination. Adjustable + +Price is $",180 +"How much does this cost to the nearest dollar? + +APS Compatible with Chevy Silverado 1500 Main Upper Stainless Steel Black 8x6 Horizontal Billet Grille Insert +INSTALLATION This is Bolt Over/Overlay/Bolton (Drilling Not Required) 8x6 Horizontal Billet grille insert. OE grille shell remains on the car after installation. CUSTOM FIT Compatible with Chevy Silverado 1500 Not for Z71 SPECS Each grille made from premium Stainless Steel and customized to fit the Main Upper of your vehicle. All necessary hardware and instruction are included. Grille insert only, logo or emblem, frame or shell is NOT included. PERFECT DESIGN Each grille made from premium stainless steel with black powder coated surface that offers resistance to oxidization. This grille enhances the visual appearance of your car. SATISFACTION GUARANTEED + +Price is $",110 +"How much does this cost to the nearest dollar? + +Wilwood Engineering Brake Caliper +Wilwood's D52 Front Caliper Kit is a direct bolt-on 2 piston replacement for the factory original single calipers on many GM Passenger Vehicles and Trucks. Forged billet aluminum bodies, stainless steel pistons, and competition style high-temperature seals put an end to the rust, bore pitting, and seal failures that plague the OE caliper design. D52 calipers provide low-maintenance performance and a huge weight savings with high temperature reliability for the street and track. D52 calipers mount in the stock location over stock rotors, use the original style OE D52 brake pads and an OE banjo bolt brake line mounting. Calipers can be used with most wheels that clear the OE calipers. The front calipers with 2 + +Price is $",90 +"How much does this cost to the nearest dollar? + +ACDelco Gold Starter, Remanufactured (Renewed) +ACDelco’s Professional Remanufactured Starters are the high quality replacement ideal for many vehicles on the road today. ACDelco’s Professional Remanufactured Starters have new bronze sintered and oil-impregnated bushings. Solenoid contacts are new with copper terminals and plated hardware. Remanufacturing starters is an industry standard practice that involves disassembly of existing units, and replacing components that are most prone to wear with new components. Damaged and obsolete parts are replaced and are end of line tested to ensure they perform to ACDelco specifications. In addition, remanufacturing returns components back into service rather than processing as scrap or simply disposing of them. These starters will + +Price is $",110 +"How much does this cost to the nearest dollar? + +UWS Matte Black Heavy-Wall Aluminum Deep Angled Truck Tool Box with Low Profile, RigidCore Lid +UWS crossover truck tool boxes are the tried-and-true way of keeping your tools organized, on-hand and fully secure no matter where you and your truck roam. Each UWS tool box is built from extra-thick aluminum welded into a single-piece tub. This provides the tool box with reliable strength and helps keep the interior sealed off from the elements. Aluminum construction also makes the box highly resistant to corrosion for long-lasting use. To add even more strength to the crossover truck tool box, the lid features our patented RigidCore foam-filled design. Layered between two sheets of aluminum, this core greatly increases the structural integrity of the lid to prevent bending and warping and to ensure + +Price is $",50 +"How much does this cost to the nearest dollar? + +Dell Latitude E5440 14in Business Laptop Computer, Intel Core up to 8GB RAM, 256GB SSD, HDMI, DVDRW, WiFi plus BT, Windows 10 Professional (Renewed) +2018 Dell Latitude E5440 14 Business Laptop Computer, Intel Dual-Core up to 8GB RAM, 256GB SSD, HDMI, Bluetooth 4.0, WiFi Windows 10 Professional (CertifiedRefurbished) Operating System Microsoft Windows 10 Professional CPU Intel Core 1.9GHz up to 2.9GHz Screen 14 Memory 8 GB DDR3 Storage 256GB SSD Optical Drive DVD-Writer Graphics Card Intel HD Graphics 4400 Video Memory Shared memory Communication Gigabit LAN and WLAN CPU Type Intel Core i5 4 + +Price is $",350 +"How much does this cost to the nearest dollar? + +(Plug and Play) Spare Tire Brake Light Wheel Light Brake Light for Wrangler JK JKU Red Light +FITMENT Fit for JK JKU with all 16 to 20 inch rim diameter wheels, works with 5x5, 5x4.5, 5x5.5 inch lug patterns. Plug & Play Package comes with instructions including the video link of installing and wiring. Just plug to the 3rd brake light.Easy to install, just plug and play, no need to splice the existing brake light wires. No broken wire installation. You can install the third spare light in few minutes. Braking Function Obvious and fast braking warning signal, lights up the inside of your spare when step on the brake, more red brightness and stronger penetration, easy To Be + +Price is $",89 +"How much does this cost to the nearest dollar? + +The Ultimate Roadside Rescue Assistant +The Ultimate Roadside Rescue Assistant is the rechargeable power source, air compressor, emergency light and phone charger no driver should be without. It features a 140W inverter to power 110V household appliances, plus a car battery jump starter, 150 PSI air compressor and a 5 LED work light. Keep one in your home or vehicle for peace of mind. The Ultimate Roadside Rescue Assistant is the rechargeable power source, air compressor, emergency light and phone charger no driver should be without. It features a 140W inverter to power 110V household appliances, plus a car battery jump starter, 150 PSI air compressor and a 5 LED work light. Keep one in your home or vehicle for peace of mind. Manufacturer Rally Manufacturing + +Price is $",155 +"How much does this cost to the nearest dollar? + +Brand New 18 x 8.5 Replacement Wheel for Mercedes CLS500 CLS550 Rim 65371 +JWL/VIA Certifed Product ISO 9001 Certifed Product Replication Manufacturer WheelerShip, Brand Wheelership, Model OEM Replacement (Aftermarket), Weight 32.3 Pounds, Exterior Silver, Manufacturer Part Construction Rim Diameter 18 Inches, Rim Width 8.5 Inches, Bolt Pattern ( Holes) 5, Bolt Pattern (Pitch Circle Diameter) 112 Millimeters, Offset 28 Millimeters, Available April 24, 2014, Size 18 inch, Exterior Finish Silver, Wheel Size 18 Inches, Pitch Circle Diameter 112 Millimeters, Rim Size 18 Inches, Diameter 18 Inches, Vehicle Service Type Passenger Car + +Price is $",350 +"How much does this cost to the nearest dollar? + +Headlight Headlamp LH Left & RH Right Pair Set for Toyota Prius +For 10-11 Toyota Prius Headlight Headlamp Halogen LH & RH Pair Driver & Passenger Set DETAIL Assembly Type Composite Lens Color Clear Ballast Included No Manufacturer Part Number Mounting Hardware Included No Bulb Size Same as factory Bulb Type Halogen OE Number Bulbs Included No Certifications DOT,SAE Placement on Vehicle Left, Right Fitment Type Direct Replacement Headlight Style Factory Housing Color Chrome (Crystal) Fits Prius Headlight · 100% brand new and high quality · Fits both LH (Driver Side) & RH (Passenger Side) · Replaces dealer part numbers · Correct for models with Halogen Style Headlights · Do NOT fit models with HID (High Intensity Discharge + +Price is $",200 +"How much does this cost to the nearest dollar? + +Lilo And Stitch Deluxe Oversize Print Large 16 Backpack with Laptop Compartment - A19563 Multi-color +Send them off with awesome top quality and durable Backpack by KBNL! Our backpacks and accessories feature today's popular characters and designs. KBNL backpacks are as practical as it is stylish and include the following features Durable polyester exterior, Full interior lining, dual side pockets, front organizer pocket for additional accessory storage, Padded and adjustable shoulder straps, padded interior pocket which protects up to a laptop, Fully padded back panel - KBNL products are made with top quality material and workmanship. Front organizer pocket for additional accessory storage Padded and adjustable shoulder straps, fully padded back panel, padded interior pocket which protects up to a laptop Dimensions 5 x 12 x + +Price is $",29.99 +"How much does this cost to the nearest dollar? + +AC Compressor & A/C Clutch For Hyundai Accent 2006 2007 2008 2009 - BuyAutoParts NEW +Engineered for superior durability, backed by a one year, unlimited mileage warranty Guaranteed Exact Fit for easy installation 100% BRAND NEW, premium ISO/TS 16949 quality - no core deposit or return required! Make sure you flush the system thoroughly and replace the drier filter along with the compressor for better long-term reliability, or consider one of our AC kits that includes everything you need! Fits Hyundai Accent Manufacturer BuyAutoParts, Part Weight 16 Pounds, Dimensions 12 x 11 x 10 inches, Quantity 1, Rank Automotive Automotive Replacement Air Conditioning Compressors 9735, Available April 25, 2015, + +Price is $",160 +"How much does this cost to the nearest dollar? + +House Of Troy Pinnacle Collection Portable Halogen Wall Lamp, Antique Brass +From the Manufacturer The House of Troy Pinnacle Collection Portable Halogen Wall Lamp shows that hand-craftsmanship is a time honored tradition, as alive today as the land itself. In this tradition, House of Troy carefully crafts each light for you by hand, to the highest quality standards. This swing arm wall lamp will create a stunning presence in any room and works well with many styles of decor. Showcasing the classic lines of this lamp and cut from the highest quality solid brass, the has an antique brass finish achieved by coloring the solid brass with an application of acid oxide. The finish is then darkened and partially rubbed away, leaving dark highlights throughout. All oxidized finishes are protected with a finish coat of matte + +Price is $",40 +"How much does this cost to the nearest dollar? + +Juno T29 WH Floating Electrical Feed Single Circuit Track, 120 Volts, White +Floating Electrical Feed for Juno Single Circuit Track Permits mounting at any point of Juno single circuit track under the outlet box. Includes floating connector and outlet box cover plus extra track dead end.. Floating Electrical Feed For Juno 1 Circuit Track - White Lighting Rail. 1- Juno Floating Electrical Feed T29Wh For Juno Single Circuit Track Brand Name Juno Lighting Product Dimensions 6.0 X 3.0 X 3.0 Country Of Origin China Manufacturer Acuity Brands Lighting, Part Weight 4.2 ounces, Dimensions 6 x 3 x 3 inches, Country of Origin China, model number T29 WH, Color White, Style Voltage, Finish White, + +Price is $",60 +"How much does this cost to the nearest dollar? + +Sherman GO-PARTS - for Toyota Avalon Side View Mirror - Right (Passenger) Replacement 2014 2015 +Sherman Replacement Part Compatible with TOYOTA AVALON Right Mirror outside rear view (Partslink Number Sherman Replacement Part Compatible with TOYOTA AVALON Right Mirror outside rear view (Partslink Number Manufacturer Sherman, Brand Sherman, Model Weight 3.35 pounds, Dimensions 17.01 x 11.73 x 6.69 inches, model number Exterior Painted, Manufacturer Part ABPA Partslink Position Rear, Lift Type Manual, Rank Automotive Automotive Exterior Mirrors 21172, Available November 8, 2021, Auto Part Position Rear, Mounting Type Windshield Mount, Included Components Mirror, Operation Mode Manual, Shape Rect + +Price is $",80 +"How much does this cost to the nearest dollar? + +Roland RPU-3 Electronic Keyboard Pedal or Footswitch, 3 Pedal +Product Description Combining three pedals into one convenient and clutter-free unit, the Roland RPU-3 offers a real grand piano pedaling experience. With separate 1/4 outputs for each of its three pedals, the RPU-3 is compatible with keyboards such as Roland’s FP-90, FP-60, and pianos. In addition to providing the same pedal configuration as a grand piano, the RPU-3 also provides hands-free control of various instrument functions, such as selecting registrations or activating vocal effects on the FP-90. From the Manufacturer Combining three pedals into one convenient and clutter-free unit, the Roland RPU-3 offers a real grand piano pedaling experience. With + +Price is $",45 +"How much does this cost to the nearest dollar? + +Rockland VMI14 12,000 Pound 12 Volt DC Electric Integrated Vehicle Winch Kit with a Synthetic Rope and Remote Accessory for Jeep, Truck, and ATV Recovery +MULTI-PURPOSE WINCH Electric vehicle winch with a Hawse fairlead and synthetic rope provides car recovery in tough situations for trucks and SUVs CONVENIENT REMOTE OPERATION Wired remote controller power switch allows for retracting the rope for winching as desired DC MOTOR Series-wound motor stays cooler during longer pulls to increase continuous operation time HIGH-PERFORMANCE GEAR SYSTEM planetary gear system with free spooling provides a fast line speed with a fast line-out FEATURES AND SPECIFICATIONS Voltage detection and stall load protection capabilities flash red and blue LED lights to warn and alert you; Color Black; Dimensions (L + +Price is $",60 +"How much does this cost to the nearest dollar? + +Max Advanced Brakes Elite XDS Front Cross-Drill & Slots Rotors with Elite Max Brake Pads +Max Advanced Brakes Elite XDS FRONT brake kit is exceptional in every way to meet the demanding braking needs for multiple driving styles, road and weather conditions FRONT brake kit with Elite XDS brake rotors are finished with a special coating to prevent corrosion & rust and to protect against moisture and salt. Brake rotors are cross-drilled and slotted to dissipate heat and keep your brakes in perfect condition at all times. Elite Max brake pads and hardware clips included Max Advanced Brakes has been providing replacement brake kits, brake rotors and brake pads for over 10 years and we've always prioritized the safety and satisfaction of our customers. Our brakes are designed to be safe and durable + +Price is $",80 +"How much does this cost to the nearest dollar? + +Quality-Built 11030 Premium Quality Alternator +Quality-Built Alternators are remanufactured for a perfect fit. Housings are 100 percent blasted clean, all mounting threads inspected, re-tapped for easy installation and consistent torque. Terminals are of 100 percent OE-quality. High-temp insulators make connections secure and reliable. Quality-Built alternators are re-designed to operate with every turn of the key for reliable performance. Rotors are electronically tested and coated with high dielectric insulation to ensure maximum durability and charging performance. Bearings are inspected or new, with high-temperature grease for reduced heat and friction. Stators are electronically tested for maximum insulation quality and phase balance. Rectifiers are load tested to ensure alternator durability and charging performance. Brushes and springs are new + +Price is $",110 +"How much does this cost to the nearest dollar? + +Lucida LG-510 Student Classical Guitar, Full Size +The perfect guitar for any beginner, the Lucida Student LG-510 features Gotoh tuners for easy tuning, nylon strings for low string tension and a classic design available in multiple sizes. White Wood Top, Back and Sides Open Gear Gotoh Tuning Machines Nato Neck Hard Maple Fretboard Multi-Colored Rosette Weight 3.7 pounds, Dimensions 39 x 15 x 4 inches, model number Rank Musical Instruments Classical & Nylon-String Guitars 336, Is Discontinued No, Available May 3, 2010, Back Material White Wood, Body Material Wood, Color Name Multi-colored,White, Fretboard Material Maple Wood, String Material Nylon, Top Material White Wood, + +Price is $",160 +"How much does this cost to the nearest dollar? + +Longacre Aluminum Turn Plates +Longacre is an established brand name in the racing industry and is recognized for dedication to quality, innovation and customer satisfaction. Check out our comprehensive line of race scales, alignment tools, racing gauges and other products. Whether you are into stock, modified, drag, go kart, off-road, sprint or RC car racing, we'll provide you with the quality racing parts you deserve. The free floating in 2 directions eliminates bind It reads to 1/2° - Degrees can be zeroed with the car on The low profile design means that its only 1 tall Can also be used on top of scale pads Has a weight capacity of 1,500 lbs. per scale Manufacturer Longacre, Brand Longacre, Model Longacre Racing Products, Weight 31 + +Price is $",300 +"How much does this cost to the nearest dollar? + +Motion Pro Adjustable Torque Wrench Adapter +Torque any fastener with a combination wrench or Allen wrench. Will work with 6 millimeter (1/4 inch) through 19 millimeter (3/4 inch) combination wrenches and with 6 millimeter and 8 millimeter Allen wrenches. Torque any fastener with a combination wrench or Allen wrench Brand Motion Pro, Material Alloy Steel, Dimensions LxWxH 6 x 3.9 x 1.1 inches, Weight 0.5 Pounds, Quantity 1, Head Style Fixed Square, Hex, Finish Type Black Oxide Finish, Torque 90 Foot Pounds, Operation Mode Mechanical, Manufacturer Motion Pro, Model Dimensions 6 x 3.9 x 1.1 + +Price is $",120 +"How much does this cost to the nearest dollar? + +Glyph Thunderbolt 3 NVMe Dock (0 GB) +Perfect fit ultra slim case for iphone 6 plus. Lightweight, and easy access to all buttons Snap-on case Strong packaging to protect the goods from possible damage High quality and durable protection cover. Brand Glyph Production Technologies, model number Weight 1.89 Kilograms, Dimensions 9.4 x 3.8 x 0.9 inches, Dimensions LxWxH 9.4 x 3.8 x 0.9 inches, Color Black, Manufacturer Glyph Production Technologies, Is Discontinued No, Available June 6, 2015, Rank Computers & Accessories Laptop Docking Stations 2945, Hardware Interface USB, Thunderbolt, Compatible Devices iPhone 6 Plus, Total USB Ports 3, Dimensions L + +Price is $",100 +"How much does this cost to the nearest dollar? + +TOYO Open Country MT Performance Radial E/10 129P +TOYO Open Country MT Performance Radial E/10 129P Country of Origin Japan The Package Height of the Product is 11.8 inches The Package Length of the Product is 34.5 inches The Package Width of the Product is 34.5 inches Fit type Universal Fit Load capacity 4080 pounds Brand Toyo Tires, Size E/10, Rim Size 18 Inches, Section Width 295 Millimeters, Tire Aspect Ratio 70.0, Load Index 129, Speed Rating P, Load Capacity 4080 Pounds, Tread Depth 19.4 32nds, Tread Type Non-Directional, Tire Diameter 25, Weight 58 pounds, Manufacturer Toyo + +Price is $",300 +"How much does this cost to the nearest dollar? + +Razer Seiren X USB Streaming Microphone and Razer Kiyo Streaming Webcam +Bundle Contents 1x Kiyo Webcam, 1x Seiren X Microphone Super Cardioid Pickup Pattern Sound is recorded at a tighter angle, reducing unwanted background noise and providing crisp clear audio Designed for Streaming Supports video and audio recording in 720p 60 FPS / 1080p 30 FPS; Streamlabs certified and compatible with popular platforms like OBS and XSplit Convenient, Built In Lighting An attached, 5600K daylight balanced ring light around the camera keeps subjects evenly lit without the hassle of additional lighting equipment Brand Razer, Connectivity Technology USB, Color Black, Video Capture Resolution 1080p, 720p, Lens Type Zoom, Form Factor Compact + +Price is $",110 +"How much does this cost to the nearest dollar? + +Happy Birthday to Dad From Your Daughter Greeting Card - I've Always Known I Could Depend On Your Love and Support No Matter What +Greeting Card Includes Envelope Front From Your Daughter - Ever since I was a little girl, you've been such an important part of my life... I've always known I could depend on your love and support... no matter what. Inside On your birthday, if I could give you anything in return for all you've given me, it would have to be the love I always hold in my heart for you. Manufacturer Greeting Card, Brand Greeting Card, Weight 1.6 ounces, Dimensions 9 x 7 x 0.1 inches, Is Discontinued No, Pre-printed happy birthday, s 1, Manufacturer Part GC, Rank + +Price is $",6 +"How much does this cost to the nearest dollar? + +Little Tikes My Real Jam First Concert Set with Electric Guitar, Drum and Keyboard, 4 Play Modes, and Bluetooth Connectivity - for Kids Ages 3+ +The My Real Jam™ First Concert Set lets kids harness their inner musician. Four play modes—Play with the Band, Free Play; Solo Jam; Play Any Song with Bluetooth® —provides countless hours of musical fun. The realistically designed Electric Guitar, Drums and Keyboard are packed with features, while the packages double as reusable instrument cases, perfect for storing the instruments or for hitting the road as an aspiring musician. BECOME A SUPERSTAR – Lets kids jam their way to rock star status with a perfect combo of musical play and pretend play PLAY ANY SONG WITH BLUETOOTH - Sync with any Bluetooth enabled device to play along + +Price is $",19.99 +"How much does this cost to the nearest dollar? + +Studio M Peace and Harmony Art Pole Community Inspirational Outdoor Decorative Garden Post, Made in USA, 60 Inches Tall +Impactful. Beautiful. Unique. An Art Pole is an impactful way to bring beautiful artwork into any landscape. With a patented, state-of-the-art design and exceptional quality, it will be at the heart of your garden for years to come. Art Poles are easy to install - all hardware is included and no digging is necessary. Made in the USA from ultra-durable, maintenance free PVC, each Art Pole features vivid artwork with an expected 5-year fade-resistance (this will vary by regional climate and sun exposure). U.S. Patent No. U.S. Patent No. U.S. Patent No. Art Poles are created by the team of passionate people + +Price is $",110 +"How much does this cost to the nearest dollar? + +MyVolts 12V Power Supply Adaptor Compatible with/Replacement for HP Scanjet 3500C Scanner - US Plug with Extension and ON/Off Switch +Need to power your HP Scanner Scanjet 12V high-quality power adapter is compatible with the HP Scanjet 3500C Scanner.The plug fits a US 2-pin wall power socket.This power adaptor is designed to meet the power specification of the HP Scanjet 3500C Scanner - correct voltage, amperage and tip size.It meets and exceeds all US safety standard, features overvoltage, overcurrent and short circuit protection to protect your device, and is energy efficient.Also included in the Premium option is a handy in-line on / off switch, AND a 3 meter (10 feet) extension cable.Power + +Price is $",35 +"How much does this cost to the nearest dollar? + +Dell Latitude 7212 Rugged Extreme Tablet, 11.6 inch FHD Touch LCD, Intel Core 8GB Ram, 128GB SSD, WiFi, GPS, Windows 10 Professional (Renewed) +This Certified Refurbished product is tested and certified to look and work like new. The refurbishing process includes functionality testing, basic cleaning, inspection, and repackaging. The product ships with all relevant accessories, a minimum 90-day warranty, and may arrive in a generic box. Only select sellers who maintain a high performance bar may offer Certified Refurbished products on Amazon.com Intel Core 7th Generation Processor (Dual Core, 3MB + u-blox NEO-M8 GPS card FHD Outdoor-Readable Glove-Capable Touchscreen w/ Gor + +Price is $",220 +"How much does this cost to the nearest dollar? + +Covermates Contour Fit Car Cover - Light Weight Polyester, Weather Resistant, Elastic Hem, Vehicle Covers-Khaki +From freezing rain and snowstorms to harsh sunlight and bird droppings, your vehicle faces it all. Spring brings bouts of rain followed by showers of pollen, leaving your vehicle a yellow, sticky mess. Our WeatherTite Prime covers are made of 300D stock-dyed polyester designed for climates with moderate humidity, moderate sunlight, heavy wind gusts, and heavy rain and snowfall. WeatherTite Prime covers provide excellent protection from dirt, dust, pollen, rain, and anything else nature has to throw at it. Hidden grommets are placed along the bottom of the cover, allowing optional cable locks to keep the cover secure and safe. An extra + +Price is $",199 +"How much does this cost to the nearest dollar? + +Westin Black HDX Grille Guard fits Ram 2500 3500 (Excl. Power Wagon) +The HDX Grille Guard is the ultimate in extreme truck gear. Its a fully welded grille guard that features full wraparound wings made of heavy duty 2 diameter tube. Uprights are finished and protected with extra wide rubber that is 1/8 thick and 2 3/4 wide resulting in a solid clean look. The full punch plate grille protects the vehicle's grille area. HDX Grille Guards are available in stainless and black powder coat finish. PERFECT FIT Direct fit for Ram 2500 3500 (Excl. Power Wagon) 2 inch tube, full wrap around wings Mount kit and hardware included Full punch plate grille solid construction + +Price is $",160 +"How much does this cost to the nearest dollar? + +Fieldpiece JL2 Job Link Wireless App Transmitter Bluetooth +With the JL2 transmitter and the job link app, you can start running your jobs through your mobile device. Fill out inspection checklists, view live measurements, gather in-depth Diagnostics, and adjust systems to live data. All reports can be emailed to customers and office, as well as saved in the cloud for access at anytime. The JL2 transmitter receives measurements from any Fieldpiece Wireless manifold and the Fieldpiece Wireless dual in-duct Psychomotor (SDP2) via radio frequency for extra distance - up to 100' from instrument to phone. Then the JL2 transmitter converts all live measurements and data to Bluetooth connection with your mobile device. made in United States. Manufactured by Fieldpiece instruments Inc. Sman digital + +Price is $",99 +"How much does this cost to the nearest dollar? + +hansgrohe Talis S Modern Premium Easy Clean 1 9-inch Tall Bathroom Sink Faucet in Chrome, +Design With a range of models and styles, paired with the quality and design you expect from hansgrohe, dream bathrooms become a reality. Bath faucets by hansgrohe exude beautiful design with superior performance and durability. Pick your desired faucet, then browse the entire product suite for complementary accessories. German engineering ensures a lifetime of consistent and dependable operation. Maintenance Products that function perfectly are essential. To ensure that they do, every hansgrohe product 100% air tested in production. hansgrohe faucets feature a silicone aerator that optimizes water flow performance, resists mineral deposit build-up, and is designed to be easily wiped clean. Installation Can be installed in + +Price is $",60 +"How much does this cost to the nearest dollar? + +G-Technology G-SPEED eS PRO High-Performance Fail-Safe RAID Solution for HD/2K Production 8TB +Product Description High-Performance, Fail-Safe RAID Solutions for HD/2K Production The new G-SPEED eS PRO from G-Tech provides professional content creators better than Fibre-Channel performance for demanding post production applications at a fraction of the cost. The compact and whisper quiet G-SPEED eS PRO features mini-SAS connectivity to a high performance PCIe x8 IOP RAID controller that supports RAID levels or 6. A single G-SPEED eS PRO enclosure with four 7200 RPM, SATA II drives in RAID 0 mode supports multi-stream ProRes 422 HQ playback and a single-stream of uncompressed 10-bit HD. Two units + +Price is $",399 +"How much does this cost to the nearest dollar? + +DreamLine Shower Door, 56-60 W x 72 H, Chrome +The DreamLine Mirage-X frameless sliding shower or tub door is the epitome of simple elegance with a modern flair. The remarkably innovative headerless design creates an unobstructed and open view for your shower. The Mirage-X shower door will complete any bathroom space with a look of luxury and style. DreamLine exclusive ClearMax water repellant and stain resistant glass coating adds superior protection from stains and is nearly maintenance-free. IMPORTANT! All measurements should be taken only AFTER walls are finished (tile, back walls, etc. ) Model Size 56 - 60 in. W x 72 in. H; Walk-in Opening 22 to 26 in. Configuration consists of a Sliding Door and a Station + +Price is $",89 +"How much does this cost to the nearest dollar? + +Sanctuary Square Backplate Finish Oiled Rubbed Bronze, Size 1.25 H x 1.25 W x 0.06 D +Finish Oiled Rubbed Bronze, Size 1.25 H x 1.25 W x 0.06 D Features -Screw pack M4. -Base material Zinc alloy. -Lifetime warranty. -Sanctuary collection. Dimensions Size 1 H x 1 W x 0.06 D - Overall Height - Top to Bottom -1. Size 1 H x 1 W x 0.06 D - Overall Width - Side to Side -1. Size 1 H x 1 W x 0.06 D - Overall Product Weight -0.1 lbs. Size 1.25 H + +Price is $",35 +"How much does this cost to the nearest dollar? + +Pelican Protector 1750 Long Case - Multi-Purpose Hard Case with Foam - Tripod, Camera Equipment, Sportsmans Rifle Case, Electronics Gear, and More (Black) +Sensitive equipment needs protection, and since 1976 the answer has been the Pelican Protector Case. These cases are designed rugged, and travel the harshest environments on earth. Against the extreme cold of the arctic or the heat of battle, Pelican cases have survived. Made in the USA, these tough cases are designed with an automatic purge valve, that equalizes air pressure, a watertight silicone O-ring lid, over-molded rubber handles and stainless steel hardware. PREMIUM HARD CASE In use with camera and film professionals, military, law enforcement, and hunters worldwide as a rifle case. + +Price is $",55 +"How much does this cost to the nearest dollar? + +Brock Replacement Driver and Passenger Halogen Headlights Headlamps Compatible with +Meets all OE specifications, with DOT stamp Exact replacement for stock assembly New, clear lenses ensure full illumination and maximum safety Lens and housing included 1-Year Limited Warranty Manufacturer Brock, Brand Brock, Model Replacement Headlight Assemblies, Weight 16 pounds, Dimensions 23 x 23 x 15 inches, Country of Origin Taiwan, model number Is Discontinued No, Manufacturer Part OEM Part 3C0 941 006 AE, ABPA Partslink Position Rear, Front, Bulb Type Halogen, Special Features Waterproof, Rank Automotive Automotive Headlight Assemblies 16731, Available September 9, 2022, Specific Uses For Product Head Lights, Light Source Type Halogen, Vehicle Service Type Car + +Price is $",120 +"How much does this cost to the nearest dollar? + +Carlinkit Ai Box Mini, Android 11, Multimedia Video Magic GPS,Wireless Caplay & Wireless Android Auto, Only Support Car with OEM Wired CarPlay +Compatible models recommended Car Links Your Phone Over The Air, Applicable to cars of 2015 and above. Please check the listing page before purchasing. If yours is not in the list, please ask for help from carlinkit. Multiple Online service Real-time online Maps will guide you at any time, either by connecting to a mobile phone hotspot, or by inserting a SIM card. Both of these allow you to enjoy the convenience. It also supports voice assistants, adding a new way to free your hands. SIM & TF Card & Type-C slot Simple card slot design makes everything clear at a glance. Support NANO SIM card + +Price is $",100 +"How much does this cost to the nearest dollar? + +StarDot YouTube Live Stream Camera Bundle, Gray +is a standalone live streaming camera which is compatible with YouTube live streaming and Facebook Live. This camera has been thoroughly tested for continuous 24/7 live streaming. It will broadcast high-quality video directly to YouTube without assistance from computers, cellphones, or third-party servers. Copy and paste a YouTube stream name/key from your YouTube account to the camera configuration page, and you're streaming in less than a minute. Easy to set up - connect the camera to your network, and get the stream name/key from YouTube or Facebook Live. Place it in the camera’s web setup page to start streaming. No need to open up additional network Ports in your router or modem settings. Live stream resolutions include HD 1080P, HD 720P, + +Price is $",110 +"How much does this cost to the nearest dollar? + +Atomic Compatible MERV 8 Carrier Replacement Furnace Filter - 2 Pack +The Atomic is a compatible filter fits the Carrier FILCAB mechanical air cleaner and MPKA series. This media filter is a whole house filter which is attached to the HVAC system. It has a MERV 8 filter efficiency value, which indicates how efficient the particles that can be trapped by the filter. The higher the rating, the finer the filtration and the fewer the particles that pass through it. To further increase filtration, it has a pleated rather than a flat surface, thereby increasing the filtering surface area. This efficiently traps airborne particles as small as 3 microns. An additional benefit is that an air filter will also extend the life of your heating and cooling system by making it work more efficiently by preventing the + +Price is $",50 +"How much does this cost to the nearest dollar? + +Bandai Awakening of S. H. s.h.figuarts star wars / force Obi-Wan Kenobi +SH Figuarts Star Wars Obi-Wan Kenobi (EpisodeI) about 155mm ABS & PVC painted action figure bandai star wars japan awakens Theme Action,Star Wars, Brand STAR WARS, Material Polyvinyl Chloride, Occasion Birthday, Dimensions 8\ L x 6\ W x 8\ H, Cartoon Character Star Wars, Room Type Office, Living Room, Bedroom, Pieces 1, Assembly Required No, s 1, Collection Name Action Figure, Shape Novelty, Manufacturer Bandai, Quantity 1, Weight 4.6 ounces, model number Rank Toys & Games Action Figures 44598, Is Discontinued + +Price is $",15 +"How much does this cost to the nearest dollar? + +Fit System 62135G Passenger Side Towing Mirror for Silverado/Sierra, 2500, 3500, Textured Black, Arrow Signal, Dual Lens, 1st Design, (no Power fold/Side Reflector/BLIS), fold, Heated Power +Passenger Side Towing Mirror for Silverado/ Sierra 1500, 2500, 3500, 1st design. Textured black, LED Arrow Signal and dual lens. Without power fold, side reflector and blind spot detection system. Foldaway. Heated Power. Towing Mirror glass is power adjustable. Convex Lens. Towing Mirror glass has heating capability to clear ice, snow and fog. Manual folding for additional clearance. Towing Mirror has the ability to extend. + +Price is $",88 +"How much does this cost to the nearest dollar? + +Black Horse Black Aluminum Exceed Running Boards Compatible with GMC Terrain / Chevriolet Equinox +Black Horse Black Aluminum Exceed Running Boards compatible with GMC Terrain / Chevriolet Equinox Black Horse Off Road Aluminum Exceed Running Board - Features an all-black design with Chrome Trim/Compatible with GMC Chevrolet wide flat stepping surface Built with heavy-duty aluminum/Resistant to rust and corrosion for long-lasting use /All necessary hardware included Stripe design for a strong grip/Designed to look like a part of your vehicle/Easy installation, DIY instructions and all mounting hardware included Eases step in or out of vehicle// Manufacturer Black Horse Off Road, Brand Black Horse Off Road, Model Exceed Running Boards, Weight 40 Pounds, Dimensions 73 x 9 x 11 inches, Country of + +Price is $",70 +"How much does this cost to the nearest dollar? + +Dearsun Twinkle Star Color Night Light Plush Pillows Light up Night Stuffed Toys Perfect for Birthday (Orange) +% Polyester Polyester 100% Polyester Size 13.8 x 3.1 x 13.8 inch This is a good plush pillow to show your kids that what is a star and how to shine. Turn on the press on Star and the light will turn off in 15 minutes automatically. The star has multiple colors when lighted. Fill Material Polyester, Color Orange, Size 1 Count (Pack of 1), Brand DearSun, Shape Novelty, Special Feature Protable, Cover Material Polyester, Pattern Star, Age Range (Description) Child, s 3, Dimensions 13.8\ L x 13.8\ W, Care Instructions + +Price is $",30 +"How much does this cost to the nearest dollar? + +Pokemon - Gallade Spirit Link - XY Roaring Skies +In the Pokemon Trading Card Game, players build decks around their favorite Pokemon and then play against each other, sending their Pokemon into battle to prove who the best Pokemon Trainer is. Players can begin with theme decks - pre-constructed decks designed to cover the basics of the game. Then, they can augment their card collections with booster packs that provide more cards, letting players develop more diverse decks. With thousands of cards to choose from, the game is never the same twice. Card Name Gallade Spirit Link Card Type Trainer - Item Card Number 83/108 Artist 5ban Graphics Set Roaring Skies Card Text Your turn does not end if the Pokmon this card is attached to becomes M Gallade-EX. A single individual + +Price is $",39 +"How much does this cost to the nearest dollar? + +Ibanez GIO Series Classical Guitar - HH Infinity R - Black Night +Ibanez classical guitars take the guesswork out of finding an affordable, great-sounding classical guitar that's easy to fret and play. Whether you are looking for a traditional classical-sized instrument or a comfortable nylon-string beginner guitar, they are extremely well-constructed, affordable and have the pristine tonality and playability of much more expensive instruments. Ibanez builds guitars for players of all levels—from beginners to the most demanding masters of the instrument. Regardless of price, Ibanez always strives to offer the absolute best sound, style, and playability in its class. The Standard series incorporates all the staples the Ibanez brand is famous for, such as fast necks, floating terms, and high-oct + +Price is $",200 +"How much does this cost to the nearest dollar? + +Set 2 Heavy Duty 12 Ply Skid Steer Tire w/Rim Guard +Deep tread designed to resist gouging and cutting. Brand new, not retreads. Heavy duty 12 Ply rated with Rim Guard to protect your wheels, Durable tread pattern for super stability. 32.7 oval diameter, 12.3 section width, 23/32 tread depth, max load 6320 lb@80 psi Tire Specifications Tire Size Tire Size Brand SUPERGUIDER Brand SUPERGUIDER Tread Pattern SKS-1 Tread Pattern SKS-1 Ply Rated 12 Ply Rated 12 Tread Depth 0.72 Tread Depth 0.72 Rim Width 9.75 Rim Width 9.75 Max Load Max Load Please note fitment guide is for + +Price is $",400 +"How much does this cost to the nearest dollar? + +Hairpin Table Legs 28 Heavy Duty Hairpin Legs, (Set for 4 ) Heavy Duty Table Legs (Black) +★Hairpin Table Legs Whether you’re a professional carpenter or woodworking is your hobby, our metal furniture legs will give your project the support it needs! ★CREATE A CUSTOM UNIQUE GIFT - Using these hairpin legs to create a custom coffee table, end table, or night stand lets you put together a unique gift that will stand out above the rest. Your gift will be remembered, cherished, and used for years to come. ★Designed for Versatility With a sleek, mid-century modern look, our industrial table legs are ideal for desks, benches and any piece of furniture in between! Finished with the latest in powder coating technology, the legs are uniform and smooth to + +Price is $",50 +"How much does this cost to the nearest dollar? + +Marada Racing Seat with Adjustable Slide for Racing Wheel Simulator Stand Cockpit Adjustable Seat Back Breathable Fabric Black with Installed Parts +Adjustable The adjustment angle of the seat back is 60-135 degrees. By adjusting the handle you can easily adjust to the angle you want.Can be suitable for players of different sizes. Overall Height 34.2, Side Width 21.2, Knee Width 20.6, Seat Back Height 30.7, Shoulder Width 21 Material Cloth, not easy to dirty. The fabric is very breathable and Suitable for sedentary. The product is not easy to deform, protect your spine and cultivate good driving habits. Design The seat bottom adopts double lock slide rail design, which is very stable, high matching with our bracket, and easy to install Experience + +Price is $",299 +"How much does this cost to the nearest dollar? + +Remington Industries 24 AWG Gauge Stranded Hook Up Wire, 25 feet Length, White, 0.0201 Diameter, 300 Volts +Hook up wire is used in a variety of general-purpose electrical applications. Stranded copper wire provides good electrical connectivity while PVC insulation protects the wire against abrasion, chemicals, oils, and solvents. The wire conforms to UL and MIL-SPEC specifications, and provides excellent uniformity for easy processing, stripping, and terminating. Available in black, red, white, Blue, green & yellow. Voltage rating 300 volts Type Ul1007 stranded wire (7/32) Insulation pvc (0.016 inch Color white Color White, Brand Remington Industries, Material wire wound, Gauge 24.0, Voltage 300 + +Price is $",99 +"How much does this cost to the nearest dollar? + +Acer Ultrabook, Intel Core 4GB Memory, 320GB HDD and 20GB SSD, Windows 8 +The Acer Aspire S3 Ultrabook is catching lots of attention and now so will you with the Champagne color design. This ultra-thin 13.3 ultrabook is less than 3 lbs light and only 0.5 thin, yet it packs a powerful 2nd Gen Intel Core i3 Processor and is outfitted with Acer Green Instant On and Always Connect for instant response and continuous connectivity. The Acer Aspire S3 Ultrabook all the best new experiences in a ultra-aerodynamic design, transforming your mobile lifestyle! HD widescreen CineCrystal LED-backlit display. Screen Resolution 1366 x 768 Intel Core processor + +Price is $",299 +"How much does this cost to the nearest dollar? + +ICBEAMER 7 RGB LED Headlights Bulb Halo Angel Eye DOT Approved Phone APP Bluetooth Control for Jeep Wrangler +⭐Transform your Jeep Wrangler with ICBEAMER's RGB Multifunction Halo Angle Eye LED Headlights - control brightness, mode selection, and more with the ICBEAMER phone app. ⭐Upgrade your Jeep Wrangler with ICBEAMER's easy-to-install LED Headlamp Assembly - Plug & Play design, with built-in Canbus and H4/H13 Adapter included. ⭐Experience unbeatable visibility with ICBEAMER's 7 LED Headlight Bulbs - high and low beam output of 3600 LM and 1800 LM respectively, and water-proof IP67 for reliable performance in any weather. ⭐Perfect fit for + +Price is $",100 +"How much does this cost to the nearest dollar? + +R1 Concepts Front Rear Brakes and Rotors Kit |Front Rear Brake Pads| Brake Rotors and Pads| Ceramic Brake Pads and Rotors |fits Lexus IS250 +R1 Concepts Series brake rotors are great for those who want a medium performance upgrade over their factory brakes. Every rotor uses a iron grade of G3000 that provides great stability and braking power. All-in-One Complete Brake Kit Replacement eLine Series Front & Rear Brake Kit comes with (4) high performance brake rotors and (8) low-dust ceramic brake pads. High Performance Brake Rotors Made of G3000 grade cast iron with zinc finish for ultimate rust protection. Built with O.E.M specifications in mind, no modification required. Ultimate Stopping Power Precision-drilled holes and countersunk design + +Price is $",100 +"How much does this cost to the nearest dollar? + +Camplux 2.64 GPM Tankless, Outdoor Portable Gas Water Heater with Overheating Protection, Instant Propane Hot Water Heater for RV, Camping, Cabins, Barns, White +𝐂𝐨𝐦𝐩𝐚𝐜𝐭, 𝐋𝐢𝐠𝐡𝐭 𝐖𝐞𝐢𝐠𝐡𝐭 𝐏𝐨𝐫𝐭𝐚𝐛𝐥𝐞 𝐃𝐞𝐬𝐢𝐠𝐧 - 12.8 inches, lbs. Compact and portable design perfect for barns, cabins, outdoor instant + +Price is $",70 +"How much does this cost to the nearest dollar? + +KNOKLOCK 10 Pack 3.75 Kitchen Cabinet Handles Brushed Satin Nickel Cabinet Pulls Kitchen Cabinet Hardware Drawer Pulls for Dresser Cupboard Wardrobe +Material - The cabinet handles is made of zinc alloy, brushed satin nickel finish, more stable and durable, while making your cabinet more delicate and beautiful. Cabinet Pulls Dimensions - Hole Centers(CC) 3.75 Overall Length 4.9 Width 0.60 Projection 0.80 (22mm) Fits Most Cabinets - We offer 1 (25mm) and 1.77 (45mm) mounting screws to help you mount most furniture of different thicknesses, Machine Screws Metric Size M4 Versatile Appicatications - This brushed satin nickel cabinet handles is perfect for dressers, drawers, + +Price is $",60 +"How much does this cost to the nearest dollar? + +Valley Enterprises Yaesu USB FTDI CT-62 CAT Cable Length 10 Feet +Aftermarket Programming Cable Aftermarket Programming Cable FTDI USB Chipset FTDI USB Chipset TX and RX Led indicators TX and RX Led indicators Total Length 10 feet Total Length 10 feet No programming software included No programming software included For use with Yaesu This device requires an FTDI USB VCP Driver. Virtual COM port (VCP) drivers cause the USB device to appear as an additional COM port available to the PC. Application software can access the USB device in the same way as it would access a standard COM port. A link to download the free driver is included. Aftermarket Programming Cable FTDI USB chipset TX and RX Led indicators Total Length 10 Feet No + +Price is $",30 +"How much does this cost to the nearest dollar? + +G9 LED Light 100W replacement halogen bulbs equivalent g9 led bulbs AC110V 120V 130 voltage Bi-Pin Base Corn Base,Daylight White of 4) +Perfect G9 replacement(Daylight White 6000K) This G9 bulb is the same type as traditioanl g9 base replacement, producing confortable light Efficient Each this type of candelabra bulbs provides around 850lm, improving the brightness of your room/home Simple Installation G9 base. Installs into existing G9 base holder Applications Furniture lighting, office lighting, merchandise lighting, display lighting, interior light etc one year, free replacement if any not working during period, please send email to us directly. Brightness 102 pcs LED chip.Brightness than general LED G9 ALL + +Price is $",60 +"How much does this cost to the nearest dollar? + +ZCHAOZ 4 Lights Antique White Farmhouse Ceiling Light Fixture Flush Mount Chandelier Ceiling Lamp Modern Sputnik Light Fixtures Hanging for Dining Room Bedroom Living Room Kitchen Entryway Foyer +Light Source & Dimmable White flush mount ceiling light is compatible with various types of 4 x E26 base bulbs(max 60w per blub), options include incandescent, led, halogen, Edison bulb, cfl, etc(Bulbs are Not Included). This hanging light fixtures is dimmable if working with dimmable bulbs and compatible dimmer switch(Not Included Also). Handmade Distressed White ZCHAOZ white ceiling light fixtures ceiling mount is made from high quality iron material in handmade white finish coating with a sturdy cylinder structure design in the center extending + +Price is $",50 +"How much does this cost to the nearest dollar? + +Honeywell Honeywell VisionPro Heat/Cool Digital Thermostat, White +This Honeywell Digital Thermostat is the perfect upgrade to any home. Thermostat has RedLink Wireless Communication, Touch Screen and 7 day programmability. Stages up to 3 Heat / 2 Cool RedLINK wireless communication Precise temperature control (+/- 1° F) for reliable and consistent temperature Package weight of the Product 9.6 Ounces Brand Honeywell, Model Name Controller Type Android, Special Feature Programmable, Color White, Power Source Battery Powered, Weight 9.6 ounces, Voltage 24 Volts, Material Plastic, Shape Rectangular, Display Type 10 sq.in. LCD, Control Type Touch, s 1, Control Method Touch, Mounting Type Wall Mount, + +Price is $",60 +"How much does this cost to the nearest dollar? + +Patriot Exhaust 1-7/8 Clippster Exhaust Header for Big Block Chevrolet 67-81, Silver Ceramic Hi-Temperature Coating +Clippster style headers are perfect for grafting modern uni-body front clip suspensions to street rods, muscle cars and trucks. Clippster headers use longer primaries than tight tucks, yet shorter than full length headers. Collectors exit toward the rear of the engine compartment providing excellent ground clearance on slammed applications as well as clearing steering and suspension components. Mid length or clippster headers provide improved ground clearance for popular muscle cars and street rods Durable tubing Comes complete with gaskets, header bolts and collector reducers Available in three finishes Silver Ceramic Hi-Temperature Coating Popular metallic ceramic coating Limited one year warranty Manufacturer Patriot Exhaust, Brand Patriot + +Price is $",70 +"How much does this cost to the nearest dollar? + +Fitrite Autopart New Front Left Driver Side Fender For Nissan Altima, Made Of Steel +Product Name New Front Left Driver Side Fender For Nissan Altima, Made Of Steel Product Name New Front Left Driver Side Fender For Nissan Altima, Made Of Steel Condition New Condition New Warranty 1 Year Warranty 1 Year Fitment Type Vehicle Specific Fitment Type Vehicle Specific Condition New Placement on Vehicle Front, Left Driver Side Warranty 1 Year Fitment Type Vehicle Specific Parts Link No OEM Number Brand Fitrite Autoparts, Exterior Finish Primed, Material Alloy Steel, Dimensions LxWxH 45 x 35 x 11 inches, Weight 8.1 Pounds, Style Modern, Auto Part Position Front Left, Vehicle Service Type Car, Fit Type Vehicle Specific Fit + +Price is $",70 +"How much does this cost to the nearest dollar? + +Technical Precision Replacement for GE General Electric G.E Light Bulb +Replacement For GE GENERAL ELECTRIC G.E Light Bulb Unit per sale 1 Brand Technical Precision, Light Type CFL, Wattage 55.00, Bulb Base G8, Specific Uses For Product Lamp, Light Color Warm White, Unit Count 1 Count, Color Temperature 3000 Kelvin, s 1, Brightness 4000 Lumen, Shape Cd, Size 1 Count (Pack of 1), Connectivity Technology Normal bulb, Controller Type Push Button, Color Rendering Index 82, Manufacturer Technical Precision, Part Weight 7 ounces, Dimensions 11.57 x 9.45 x 1.89 inches, Is Discontinued No, Quantity 1, Rank Industrial & Scientific Compact Fluorescent Bul + +Price is $",50 +"How much does this cost to the nearest dollar? + +Covercraft Carhartt SeatSaver Front Row Custom Fit Seat Cover for Select Ford Models - Duck Weave (Gravel) +Carhartt SeatSaver seat covers from Covercraft are the solution to the problem of keeping the seats in your truck or SUV clean and protected from daily use and weekend adventures. Made from durable, duck-weave fabric, these custom-fit seat covers protect your seats from dirt, mud, grime, spills and more. Featuring Rain Defender technology, a durable water repellency finish is added to the fabric to make it highly water resistant. Combine these features with the custom fitment and classic Carhartt styling, you get seat covers that look great and protect your seats from whatever you throw at them. Classic Duck-Weave Carhartt fabric for durability Custom-made + +Price is $",99 +"How much does this cost to the nearest dollar? + +Sennheiser SD Pro 2 - Double-Sided Multi Connectivity Wireless Headset for Desk Phone & Softphone/PC Connection, Ultra Noise-Cancelling Microphone (Black) +With the SD Pro 2, you get everything you need in an office headset, wrapped in one unique product. The SD Pro 2 is a double-sided, premium wireless DECT headset for desk phone and PC/softphone with base station. It features Sennheiser Voice Clarity, ultra noise-cancelling microphone, and ActiveGard hearing protection technology. Choosing the right SD Pro 2 SD PRO 2 This headset is designed for business professionals who communicate with their desk phone and softphone/PC. SD PRO 2 ML This headset is designed for business professionals who communicate in desk phone and + +Price is $",80 +"How much does this cost to the nearest dollar? + +Hitachi Mass Air Flow Sensor +Hitachi’s Air Flow Sensors (MAFs) measure the amount and characteristics of air entering the engine. Hitachi uses precision elements and high-quality components for enhanced durability and accurate air flow measurements. Hitachi MAFs are 100% air flow tested for ideal performance and are calibrated for each application ensuring your vehicle meets the strict emission standards set by the manufacturer. Details such as a contaminant bypass port (when applicable) and protected circuitry providing a durable and reliable product approved by OE manufacturers makes Hitachi’s air flow sensors the premium choice. New orignial equipment part Restores original drivability characteristics Meets the OE performance and durability standards for this application Precision manufactured and assembled sensing elements for accurate air flow measurements Built in contaminant bypass port provides reliable operation + +Price is $",120 +"How much does this cost to the nearest dollar? + +AmScope LED Cordless Stereo Microscope w/Top & Bottom Light Illumination System and 36 specimens +This cordless LED binocular stereo microscope comes with two pairs of stereo objective lenses mounted in a rotating nosecone, sturdy all-metal pillar stand, and a versatile illumination system that provides both incident (top) lighting and transmitted (bottom) lighting. You can choose between incident illumination shining down onto the object or transmitted illumination through the frosted stage plate. The first is used for the observation of three-dimensional objects and the second for the observation of slides. It comes with a rechargeable illumination system capable of taking rechargeable AA batteries, and an AC adapter/charger. This microscope offers high resolution and good depth within a broad field of view. It gives sharp clear stereo images. Its 45 + +Price is $",300 +"How much does this cost to the nearest dollar? + +Front Left Driver Side Window Regulator - Compatible with Kia Optima +Front Left Window Regulator - Compatible with 2014 - 2015 Kia OptimaPosition Front LeftNote Includes Module PanelCompatible With or Fits Note w/ USA Built - 2014 - 2015 Kia Optima EX - 2014 - 2015 Kia Optima EX Luxury - 2014 - 2015 Kia Optima LX - 2014 - 2015 Kia Optima SXNote - 2014 - 2015 Kia Optima Limited - 2014 - 2015 Kia Optima SX Turbo - 2014 - 2015 Kia Optima SXL Turbo Includes Module Panel Compatible with or fits (Note w/ USA Built; 2014 - 2015 Kia Opt + +Price is $",45 +"How much does this cost to the nearest dollar? + +Premium Replica Hubcap Set, Fits Nissan Rogue Replacement Wheel Covers +This is a set of 4 Brand New replica Nissan hubcap. Fits 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Rogue. Silver-painted. This is a copy of a factory-original. Our Replica wheel covers are made of sturdy ABS plastic and feature a rich silver finish, just like the originals. They will look great on your vehicle for years to come. Brand New Condition Aftermarket replacement for Nissan part Fits Nissan Rogue 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 model years. Mounts easily and securely to + +Price is $",66 +"How much does this cost to the nearest dollar? + +Excellerations Phonics Spelling Game for Kids and Classrooms Classroom Activity (12 Game Boards) (Item # PSG) +Excellerations Early Language, Phonics Spelling Game, Kids Educational Toy, Ages 3 Years and Up (Item # PSG) CLASSROOM ESSENTIAL This spelling game is perfect for those ages 3 and up to learn about how to sound out words EASY TO USE This activity comes equipped with a helpful activity guide for tricks to teach about phonics and words INTERACTIVE LEARNING This phonics spelling game will get students interacting with their learning while developing spelling and word association skills DURABLE DESIGN This spelling game is made with reusable game boards and durable foam letter tiles so that it can be used again and again ENHANCE CURRICULUM Build on + +Price is $",60 +"How much does this cost to the nearest dollar? + +RC4WD BigDog Dual Axle Scale Car/Truck Trailer Electric Car/Truck Option Parts +Key Features Hand made tube trailer chassis Billet aluminum wheels 1.55 Dirt grabber tires Steel leaf spring Working lift jack Steel tool box for battery and light switch Working lights Easy clip hitch mount Two steel ramps Ramp holders Whitebone inspired design Weight Length 22.63 Width 12.28 Height 5.31 Inside of the Deck Length 15.9in / 404mm Inside of the Deck Width 8.5in / 216mm Tail Plate Length 6.1in / 155mm Tail Plate Width 2.55in / 65mm Overview This is a 1/10 Car or Truck Hauler. Perfect for towing around your rig to + +Price is $",100 +"How much does this cost to the nearest dollar? + +Unknown Stage 2 Clutch Kit - Low Altitude +Amazing all-around performance gains. Easily adjustable for altitude, modifications and more. Superior weight profile offers better acceleration. Goldstar weights adjust easily with magnets. Custom angle cut helix. Comes with two washers to prevent spring bind and free up clutch movement for faster shifts. Includes primary and secondary springs.This item fits the following vehicle applications compatible with Polaris 600 Rush PRO-S with Polaris 600 Rush XCR with Polaris 600 SwitchBack Adventure with Polaris 600 SwitchBack Assault 144 with Polaris 600 SwitchBack PRO-S with Polaris 600 SwitchBack SP 144 with Polaris 600 SwitchBack XCR with Polaris 800 Rush PRO-S with Polaris 800 Rush PRO-S LE with Pol + +Price is $",99 +"How much does this cost to the nearest dollar? + +Dodge Ram 1500 Mopar 4X4 Emblem - +BRAND NEW AND MOPAR GENUINE 2007 2008 2009 2010 Dodge Ram 1500 2500 3500 4X4 Logo Emblem Decal Genuine MOPAR Part Number Oe Spec Or Performance/Custom OE Spec, Manufacturer Warranty 2 Year, Modified Item No Manufacturer Part Number Model Ram 1500 2500 3500, Brand Compatible with Mopar Returns Accepted Returns Accepted, Non-Domestic Product No, Make Compatible with Dodge Fitment Type Direct Replacement, Model Year Manufacturer Mopar, Brand Mopar, Weight 1 pounds, Dimensions 6 x 6 x 6 inches, model number Manufacturer Part Position Rear, Available + +Price is $",60 +"How much does this cost to the nearest dollar? + +Pro Comp Alloys Series 89 Wheel with Polished Finish (16x8 +Pro Comp Alloys are designed using State-Of-The-Art Low-Pressure-Casting Technology providing unsurpassed wheel strength, style and value. Pro Comp Alloy Wheels combine head turning style, light weight, durable finish in black, graphite, milled, chrome, polished and dual-tone finishes. Pro Comp Alloys allows for massive brake clearance for todays performance Jeeps, trucks and SUVs. 108 inches Bolt Pattern 6x5.5 inch Back Space 4.5 inch Size 16 inches X 8 inches, Brand Pro Comp Alloys, Wheel Size 16 Inches, Pitch Circle Diameter 139.7 Millimeters, Weight 26 Pounds, Diameter 16 Inches, Vehicle Service + +Price is $",300 +"How much does this cost to the nearest dollar? + +Detroit Axle - Front Rear Strut & Coil Spring Assembly Replacement for Toyota Camry 2.2L Models - 4pc Set +Kit Includes 1x Complete Front Strut & Coil Spring Assembly - Driver Side - 171956 1x Complete Front Strut & Coil Spring Assembly - Driver Side - 171956 1x Complete Front Strut & Coil Spring Assembly - Passenger Side 1x Complete Front Strut & Coil Spring Assembly - Passenger Side 1x Complete Rear Strut & Coil Spring Assembly - Driver Side - 171958 1x Complete Rear Strut & Coil Spring Assembly - Driver Side - 171958 1x Complete Rear Strut & Coil Spring Assembly - Passenger Side - 171957 1x Complete Rear Strut & Coil Spring Assembly + +Price is $",300 +"How much does this cost to the nearest dollar? + +ECCPP Rear Wheel Axle Replacement fit for for Honda Sportrax 2009 +This axle works on the following models 2002 for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for HondaSportrax for for for for Package including 1 piece of Rear Wheel Axle Fitment - for Honda Sportrax 2009 Length - 855 mm, brand new complete rear wheel axle OE quality - Produced in the same specifications and functions as OE. Refer OE number Premium Material - Long service life with high quality raw material and the complete polishing Installation - Replace directly with assembly, easy to install. Brand ECCPP, Weight 15.22 pounds, Dimensions 35 + +Price is $",300 +"How much does this cost to the nearest dollar? + +Dell Latitude E6520 Intel 8GB RAM 500GB HDD Win 10 Pro DVD-RW (Renewed) +Keep up with business wherever you are with the Latitude E6520 laptop. It is ideal for professionals looking for a stable and durable laptop that is light and easy to carry on the go. Specifications Processor Intel Quad Core up to 3.3 GHz Graphics Intel HD Integrated Graphics Memory 8G DDR3 Hard Drive 500G Webcam Webcam Operating System Windows 10 Pro 64 Bit Multi-Language. Ports Network connector USB 2.0 (4) – 1 USB/eSATA combo, Stereo headphone/Microphone combo jack, 1394, Docking Connector, VGA, HDMI. Warranty 1 full year Parts and Labor Warranty Included in the box Computer + +Price is $",310 +"How much does this cost to the nearest dollar? + +F FIERCE CYCLE 251pcs Black Universal Motorcycle Fairing Body Bolts Kit Fastener Clips M5 M6 Screws Nuts +Includes hardware for all fairing pieces including, front, mid, lowers, rear, windscreen, and more. Fitment for Honda, for Kawasaki, for Yamaha, for Suzuki This kit is a common size on most motorcycles but it remains the responsibility of the buyer to check the appropriate size fittings are ordered. Simply replace the existing stock fairing bolts with these bolts. Package Includes 5 x Bolt (M6 x 40mm), 20 x x 16mm), 20 x x 20mm), 40 x x 16mm), 8 x x 25mm), 17 x Self Tapping x 12mm + +Price is $",40 +"How much does this cost to the nearest dollar? + +Flash Furniture 4 Pk. HERCULES Series 880 lb. Capacity Black Plastic Stack Chair +When in need of a space-saving seating solution that is either permanent or temporary, stack chairs have been proven to be beneficial. Stack chairs are a popular choice for many businesses that include hotels, schools, restaurants, cafeterias, and offices. This industrial looking chair hits the mark on comfort. This chair features a carrying handle to easily transport. This versatile chair is ideal for both indoor and outdoor functions. With the ability to quickly store the chairs, it allows for the space to be used again for other purposes or when cleaning is needed. This heavy duty plastic stack chair is sturdy in construction to withstand regular use and frequent stacking. To make transporting even easier, equip yourself with the appropriate sized + +Price is $",60 +"How much does this cost to the nearest dollar? + +B&M 30287 Throttle Valve/Kickdown Cable, Silver/Black +This throttle valve / kickdown cable is adjustable, so it can accommodate most TH350 applications. It's handy as a straight replacement for an old OE model, and less expensive. If your project includes a transmission swap, you will appreciate the universal sizing during installation. Adjustable for a universal fit in 95% of all listed transmission applications Eases the installation process for transmission swaps Less expensive than OE models For use with TH350 transmissions Backed by the manufacturer with a 1 year limited warranty Brand B&M, Color Silver/Black, Pieces 1, Special Feature Easy to Install, Included Components Screw, Weight 8 ounces, Unit Count 1.0 Count, s 1, Manufacturer B&M, model + +Price is $",70 +"How much does this cost to the nearest dollar? + +Gates TCK226 PowerGrip Premium Timing Belt Component Kit +Gates is the world's leading manufacturer of timing belts and Timing Component Kits. We designed our kits for virtually every vehicle make and model so technicians can conduct complete system replacements and streamline parts sourcing. As the Original Equipment Manufacturer (OEM) for vehicle manufacturers globally, our Timing Component Kits are OE-equivalent or better in service life, quality, and performance. Total solution for any application TCK includes belts, idler(s), tensioners, tensioner springs, supporting hardware, detailed installation instructions and Technical Service Bulletins for troublesome applications Popular kits covering domestic and import (European and Asian) vehicle applications Designed for convenience, easy parts sourcing and reduced customer comebacks Manufacturer Gates, Brand Gates, Model PowerGrip Premium Timing Belt Component + +Price is $",60 +"How much does this cost to the nearest dollar? + +Monroe Shocks & Struts Quick-Strut 171491 Strut and Coil Spring Assembly +Featuring a vehicle-specific design, Monroe Quick-Strut strut assemblies are fit checked, ride tested and engineered to restore factory ride height and ride performance. Assembled in Paragould, AR, they include all required components in a single unit. QUICKER, SAFER, EASIER AND COMPLETE REPAIR -- Includes everything you need for strut replacement in a single, fully assembled unit with no need for a spring compressor RESTORES RIDE HEIGHT -- Precisely calibrated to meet the OE design, each application-specific coil spring type is engineered to restore ride height and support the vehicle's weight VEHICLE-SPECIFIC DESIGN -- Application-specific coil spring, mount and strut designs ensure optimized ride + +Price is $",70 +"How much does this cost to the nearest dollar? + +Feit Electric 35W EQ DM MR16 LED Light Bulb, 6 Bulbs +This Feit Electric equivalent traditional glass MR16 flood LED light bulb has a GU10 base. Featuring bright white and high 90+ CRI (color rendering index) rating this Enhance LED is our highest quality energy efficient light with bolder color rendering and enhanced contrast so people and objects appear more realistic and vibrant. This MR16 reflector produces a similar light output while using less energy than a standard incandescent light bulb. The dimmable light has an average life of 25000 hours / 22 years and is safe for indoor or outside use. Choose a dependable high quality 120 volt MR16 bulb for residential or commercial applications. Specifications 💡 Color temperature 3000K + +Price is $",70 +"How much does this cost to the nearest dollar? + +Yellow Jacket 2806 Contractor Extension Cord with Lighted End; 100 ft; 100 Ft +Product Description Yellow Jacket 2806 10/3 Heavy-Duty 15-Amp SJTW Contractor Extension Cord with Lighted End, Super flexibility in cold and hot weather. Power Lite power indicator lamp glows through the extra heavy, clear molded plug when the cord has power. Three times as abrasion resistant as standard vinyl, making these cords the toughest on the jobsite. Extra heavy, clear molded plugs are rugged, durable and oversized. Meets OSHA specifications, UL Listed. 10 Gauge. The Yellow Jacket (R) brand is a registered trademark of Coleman Cable Inc. From the Manufacturer Yellow Jacket 2806 10/3 Heavy-Duty 15-Amp SJ + +Price is $",99 +"How much does this cost to the nearest dollar? + +Garage-Pro Tailgate SET Compatible with Chevrolet Silverado 1500, Fits 2007 Chevrolet Silverado 1500 Classic, 1500 HD Classic, 2500 HD Classic, 3500 Classic Fleetside/Styleside +Manufactured from high quality materials Manufactured from high quality materials Easy to install; replaces old or damaged part Easy to install; replaces old or damaged part This is an OE replacement item This is an OE replacement item Garage-Pro is the most affordable brand for your old, worn-out, or damaged factory part! This premium quality replacement part is made to give your car, truck, and SUV that original factory look and performance. Available for different applications, our Garage-Pro part will surely fit right to your vehicle. Comes with 1-year unlimited mileage warranty! + +Price is $",80 +"How much does this cost to the nearest dollar? + +3M Perfect It Buffing and Polishing Kit | 36060 06094 06068 3M Rubbing Compound, Machine Polish, Ultrafine Polish | Buffing Compound, Car Polishing Kit | Bundled with Kangaroobands Microfiber Cloth +The 3M Perfect-It Paint Finishing System 3M Perfect-It EX AC Rubbing Compound is the best-performing rubbing compound for removing scratches and surface defects before polishing, even on the latest clear coats. Longer Working Time, Easier Cleanup Even in Extreme Conditions As part of a complete system for creating showroom-grade finishes, it is the ideal compound for the critical pre-polishing stage in collision repair. This fast-cutting, fine-finishing compound removes fine grade (P1200 or finer) sand scratches and + +Price is $",40 +"How much does this cost to the nearest dollar? + +Chinese Style Dollhouse Model DIY Miniature Furniture Kit Wooden Tea Shop Dolls House with LED Lights Accessories Hand Craft Puzzle Toy Birthday Gift +Feature This dollhouse makes a great craft project and gift for both friends and collectors! The pictures shows finished project. You receive are spare parts,Mainly through, paste, assembly, modeling, placement DIY craft, complete your lovely beautiful house.Glue and Battery are not included.Detailed pictures instructions. ( Just follow the pictures! )Description Assembly Difficulty Level Time 2-10 hoursFinished Size as picture showsWeight Approximate Include 1 x DollhouseNote 1.The real color of the item may be slightly different from the pictures shown on allow error due to the hand measurement. 3.Due to long shipping, the item may damage in transit, if + +Price is $",40 +"How much does this cost to the nearest dollar? + +Generic NRG Innovations Steering Wheel Short Hub Adapter Kit + LED Keychain Flashlight, black +NRG Innovation has developed another complement to our quick release steering kits. These units were designed specially for an aftermarket steering wheel installed with the quick release kit still mounts in the same location, not too close to the driver. Made from the highest quality aluminum. Our Short Hubs are made to work with our quick release's. This product is designed utilizing one piece solid construction for the maximum in durability and usability. Made of High Quality Aluminum Direct Bolt-on Design, Perfectly fits Any Wheel or Quick Release with a 6-Bolt X 74MM Pattern Anodized for Durability and Strength Racing Style, for Most Aftermarket Racing Brand Steering Wheel Manufacturer NRG Innovations, Brand NRG Innov + +Price is $",50 +"How much does this cost to the nearest dollar? + +Learning Resources Coding Critters Ranger & Zip,22 Piece Set, Ages 4+, Screen-Free Early Coding Toy for Kids, Interactive STEM Coding Pet, Gifts for Boys and Girls,Back to School Gifts +Meet the Coding critters your first coding friends. These playful puppy pets bring early STEM concepts to preschool learning through 100% screen-free coding. Kids code along with their new pets’ storybook adventure, and help the brave Ranger and mischievous zip have a playtime they'll never forget. Each storybook coding challenge unfolds in the Coding critters' Fun pet playset - can you code Ranger to play hide and seek, fetch a ball from the tennis ball launcher, or catch zip after a ride down the slide? In addition to following along with the storybook's coding challenges, + +Price is $",60 +"How much does this cost to the nearest dollar? + +Bosch Automotive 15463 Oxygen Sensor, OE Fitment (Mazda) +Premium Bosch oxygen sensors promise better quality, better overall OE Fit/Form/Function while ensuring better coverage against the competition. Premium Bosch oxygen sensors are designed to improve fuel economy. Vehicles utilizing Bosch premium oxygen sensors experience better engine performance. Premium Bosch oxygen sensors assist in cleaner exhaust emissions. Brand Bosch Automotive, Dimensions LxWxH 2.2 x 1.97 x 5.83 inches, Weight 0.25 Pounds, Style Modern, Mounting Type Flange Mount, Specific Uses For Product Oxygen Sensor, Manufacturer Bosch Automotive, Dimensions 2.2 x 1.97 x 5.83 inches, Country of Origin United Kingdom, model number 15463, Is Discontinued + +Price is $",70 +"How much does this cost to the nearest dollar? + +Case of 24-2 Inch Blue Painters Tape - 60 Yards/roll +Case of 24 rolls of painters tape bulk packed for easy use and access. Each roll is 1.88 inches by 60 yards of masking tape. Professional grade tape is flexible, leaves no sticky residue behind, prevents paint bleed, removes without damaging surface, and gives clean edges. Use for every kind of painting, trimming edging, masking. or protecting. Brightly colored tape works well with delicate and bold paint colors. Durable, strong tape sticks to a variety of clean / dry surfaces. Apply pressure when adhering tape for the cleanest lines as adhesive is pressure sensitive and heat activated. Ideal for use in temperatures from 40 to 130 degrees Fahrenheit. Made in the USA. + +Price is $",70 +"How much does this cost to the nearest dollar? + +MOCA Engine Water Pump & Fan Clutch fit 04-07 for Buick Rainier & 02-09 for Chevrolet Trailblazer & 02-09 for GMC Envoy & 02-06 Envoy XL & 04-05 Envoy XUV & 03-07 for Isuzu Ascender 4.2L +Please confirm this item fits for your vehicle before purchasing (Check Fitment Data Above or see description below) Package Includes 1 Water Pump, 1 Fan Thermostat Housing Assembly Part Numbers 33939, All the Components are produced under strictly observed and meet or exceed OEM performance requirements in Manufacturing and Material Local US friendly after-service team to resolve your issues in time, parts have 2 years or 40000 miles warranty Manufacturer OELINE Auto + +Price is $",110 +"How much does this cost to the nearest dollar? + +SAREMAS Foot Step Bars for Hyundai Palisade 2023 Running Boards Side Steps nerf bar Pedal Protector +The price for one pair(left and right running board) Don't drill,use the factory hole Main raw material high quality Aluminum&ABS ect Including brackets and mounting parts For Hyundai Palisade 2020 2021 2022 2023 Manufacturer Donarrw, Brand SAREMAS, Weight 32.3 pounds, Dimensions 81 x 11 x 8 inches, Exterior Aluminum, Manufacturer Part PATXTB, Rank Automotive Running Boards 6648, Available February 18, 2020, Material Aluminum, Acrylonitrile Butadiene Styrene (ABS), Exterior Finish Aluminum, Vehicle Service Type Passenger Car + +Price is $",100 +"How much does this cost to the nearest dollar? + +Gretsch G9210 Square Neck Boxcar Mahogany Resonator Acoustic Guitar +Classic Squareneck Resonator from Gretsch Neck; Padauk Fingerboard; and Hand-spun Cone - Mahogany Natural Acoustic Squareneck Resonator Guitar with Mahogany Top Sides Weight 10 pounds, Dimensions 20 x 7 x 48 inches, model number Rank Musical Instruments 50797, Acoustic Resonator Guitars 12, Is Discontinued No, Available February 5, 2018, Back Material Mahogany, Body Material Mahogany, Color Name Natural, Fretboard Material Padauk, String Material Phosphor Bronze, Top Material Mahogany Wood, Neck Material Type Mahogany, Strings 6, Brand Gretsch, Color Natural + +Price is $",350 +"How much does this cost to the nearest dollar? + +NikoMaku Mirror Dash Cam Front and Rear OEM Design Backup Camera for Cars 4K Resolution Type-C 11 Inch Full Touch Screen Rear View Mirror Camera 170° Wide Angle Dual Cameras Waterproof AS5 Pro +4K Resolution The AS5 Pro mirror dash cam delivers clear video with its 4K front camera and 1080P rear camera. Equipped with 170° wide-angle front lenses, this camera can capture high-quality footage day or night. The mirror dash cam records in real-time and boasts an enhanced imaging system for superior image quality. With its 4K resolution, every detail on the road is vividly displayed. OEM Look Design The supplied bracket allows for a complete replacement of your existing rear-view mirror. Say goodbye to shaky footage while driving, as the bracket effectively + +Price is $",360 +"How much does this cost to the nearest dollar? + +Fenix HP25R v2.0 USB-C Rechargeable Headlamp Bundle with Backup Battery, 1600 Lumen Spotlight, 400 lumens Floodlight and Red Light with LumenTac Organizer +HIGH-PERFORMANCE - The Fenix HP25R v2.0 headlamp emits up to 1600 lumen spotlight reaching 317 yards. You can also switch to a wide-angle floodlight, or an auxiliary red light to preserve the night vision. USB-C RECHARGEABLE - via its built-in charging port. Includes a high capacity battery. Runs up to 400 hours on the lowest mode. DESIGN FOR COMFORT -The HP25R v2.0 keeps the battery compartment in the rear to maintain a balanced weight. Also comes with cable clips + +Price is $",200 +"How much does this cost to the nearest dollar? + +R&L Racing Heavy Duty Roll-Up Soft Tonneau Cover Compatible with 94-02 Dodge Ram Regular/Club/Quad Cab 6.5' 78 Bed +R&L Racing Roll Up Tonneau Cover. Get effective bed protection, upgraded appearance, and even improved fuel economy, all at a budget price, with the R&L Racing Roll-Up Tonneau Cover. The vinyl cover will protect your truck bed and contents from the elements, and give your truck a smooth aerodynamic appearance that will even reduce drag for more miles per gallon. It features the quick and easy Clean-Seal closure system, lightweight aluminum rails and bows, and easy no-drill installation. Cargo in an unprotected pickup truck bed can become moisture damaged and corrode from exposure to rain and snow, + +Price is $",350 +"How much does this cost to the nearest dollar? + +Garmin GPSMAP 64sx, Handheld GPS with Altimeter and Compass, Preloaded With TopoActive Maps, Black/Tan +Navigate your next adventure with the GPSMAP 64sx handheld navigator series. Whether you’re hiking, cycling, geocaching or climbing, you are free to explore more with the reliable Garmin handheld navigation in the palm of your hand. And the series now has multi-GNSS support and Topo Active mapping. Rugged and water-resistant design with button operation and a 2. 6” sunlight-readable color display Preloaded with Topo Active maps (U. S. and Australia only) featuring routable roads and trails for cycling and hiking Know where you’re at with a high-sensitivity receiver with quad helix antenna and multi-GNSS support + +Price is $",200 +"How much does this cost to the nearest dollar? + +Brown 5-7/8 X 8-1/2 X 3/16 Thick Heavy Duty Felt Sheets - 12 Pcs +Protect your beautiful laminate, ceramic, vinyl or hardwood flooring as well as your precious furniture, with our Heavy Duty Felt Pads made of 100% polyester felt. These brown protector pads are designed to blend in with dark furniture to compliment your home decor. Simply peel and stick them to lamps, furniture and small appliances to protect tabletops, shelves, desks, floors and countertops. These can also be used to provide a cushioning layer between glass tabletops and pedestals or frames. Or place them on cabinet doors to reduce noise when they're closed. Trim them into the exact shape and size you need, and prevent scratches or damages anywhere + +Price is $",120 +"How much does this cost to the nearest dollar? + +GAOMON PD2200 Pen Display & 20 Pen Nibs 8192 Tilt-Support Full-Laminated Graphics Drawing Monitor Tablet for Digital Drawing/Animation/Online Teaching and Meeting +GAOMON PD2200 PEN DISPLAY + 20 PEN NIBS FOR ONLINE EDUCATION & MEETING You can use PD2200 pen monitor for online education and remote meeting. It works with most online meeting programs, like Zoom, and so on. FOR DIGITAL ART & CREATION -- It's not only for amatuer but also for professionalists for digital drawing, sketching, graphics design, 3D art work, animation, etc. FOR ANNOTATING AND SIGNATURE --It is also broadly used in annotating and signing files WITH AG-FILM PRE-APPLIED + +Price is $",80 +"How much does this cost to the nearest dollar? + +VXMOTOR for 97-03 Ford Lightduty 4WD for 99-03 F150 Lightduty F150 Super Crew Cab/04 F150 Heritage for 97-02 Expedition 4WD for 99-02 Expedition 2WD Matte Black Heavyduty Bull Bar +Application for Ford F150 / F250 Lightduty 4WD ( 4 Wheel Drive ) Models, for Ford F150 Lightduty 2WD ( 2 Wheel Drive ) Models, for Ford F150 Super Crew Cab Models, for 2004 Ford F150 Heritage Models, for Ford Expedition 4WD ( 4 Wheel Drive ) Models, for Ford Expedition 2WD ( 2 Wheel Drive ) Models Front Bumper Bull Bar Guard Heavy Duty Steel With Flat Black Fine + +Price is $",100 +"How much does this cost to the nearest dollar? + +HP EliteBook 2540p Intel Core X2 2GB 160GB DVD+/-RW 12.1'' Wi, Black (Refurbished) +Standing screen display size 12.1 Inches, Processor RAM 2 GB DDR3, Hard Drive 160 GB, Graphics Coprocessor Intel HD Graphics, Chipset Brand Intel, Card Description Integrated, Wireless Type Bluetooth, USB 2.0 Ports 3, Brand HP, Microsoft, Series HP EliteBook, model number Operating System Windows 8 1, Weight 3.97 Pounds, Dimensions 19 x 17 x 5 inches, Rear Webcam Resolution 1 MP, Processors 2, Computer Memory Type DDR3 SDRAM, Flash Memory Size 160 GB, Power Source Battery Powered, Available + +Price is $",199 +"How much does this cost to the nearest dollar? + +Green EPX Mixing Nozzles 3M 50ml Duo-Pak Adhesive Cartridges (Longer 4.5in, 1 1 & 2 1 ratios) +This is a of our Atlas Professional Green Screw-On Mixing Nozzles for the New 3M 1 1 and 2 1 ratio 50ml Duo-Pack Cartridge Design (also called a B-System design with a large gray screw-off cap). These are the longer mixing nozzles, which are preferred for most Urethane and many Epoxy adhesives that require more mixing elements to properly mix. They are also in the high-efficiency quadro style, which reduces wasted material by about 50% vs traditional helix nozzles. They reduce wasted + +Price is $",40 +"How much does this cost to the nearest dollar? + +Box Partners 6 1/4 x 3 1/8 13 Pt. Manila Shipping Tags - Pre-Wired +Box Partners G10083 6 1/4 x 3 1/8 13 Pt. Manila Shipping Tags - Pre-Wired 6 1/4 x 3 1/8 13 Pt. Manila Shipping Tags - Pre-Wired Dimensions L x W x H 1.5 x 1.5 x 1.5 inches, Weight 1 Pounds, Dimensions LxWxH 1 x 1 x 1 inches, Weight 1 Pounds, Brand Name Aviditi, Model Name Color Manila, Material Blend, Suggested Users unisex-adult, s 1, Manufacturer BOX Partners LLC + +Price is $",10 +"How much does this cost to the nearest dollar? + +Vixen Air 1/2 NPT Air Ride Suspension High Flow Electric Air Valves/Solenoids 250 PSI Four Corners with Fittings and Hoses +These eight powerful ½ NPT air valves with exceptional high flow deliver unparalleled performance for 12V vehicles. The unique design provides high pressure control at minimal power consumption. Valves support pressures of up to 250 PSI and are constructed with high quality brass to ensure continuous use through extreme conditions. Solenoid's DIN connector is water and dust resistant, a metal mounting bracket is included for each valve, and the air flow direction is clearly marked with an arrow to provide an easy trouble-free installation. Premium brass fittings, flow control valves, pressure switch, drain valve, hoses and cutter are included in this kit. ½ + +Price is $",80 +"How much does this cost to the nearest dollar? + +Smart Floor Lamp, Multicolors Scene DIY Torch Floor Lamp, 24W 2400LM Dimmable Tall Standing Lamp work with Alexa Google Home,Wifi Remote Control RGB Floor Lamp For Living Room +Smart Control💡Control this smart floor lamp using the Smart Life app or your voice with Amazon Alexa or Google Home. You can group multiple lamps together and control them individually or together. Choose from 16 million colors and 12 scenes to create the perfect lighting for any occasion. Note The lamp only works with 2.4GHz Wi-Fi networks. Adjustable Lighting💡 This floor lamp features a range of white color temperatures from 2700K to 6500K and single color RGBWW options. The lamp is also dimmable and uses high-quality LED chips with a C + +Price is $",99 +"How much does this cost to the nearest dollar? + +SOZG 324mm Wheelbase Body Shell RC Car Body Shell Super Hard Plastic Black with Screw for RC Vehicle, SOZGpuFdVe +Specification Item Type Body ShellProduct Material Rigid plasticWeight Approx. 1190g / BlackWheelbase Size For 1/10 RC for, for Axial List 1 Set x Body Shell (81 Bags x ScrewNote 1. Manual measurement, please allow 1‑3mm error, thank you!2. Due to the difference between different monitors, the picture may not reflect the actual color of the This car shell is suitable for 324mm wheelbase chassis, if it is installed on other chassis, the wheelbase needs to be adjusted to Shipped in bulk, assembled by the customer (the door cannot be opened). + +Price is $",30 +"How much does this cost to the nearest dollar? + +Mickey Thompson ET Street S/S Racing Radial Tire - +A D.O.T. approved street tire which provides excellent traction at the strip. Proven polyester-ply, steel belted, tubeless radial construction provides strength & durability for excellent ride control on the street Proven R2 compound provides quick and consistent traction at the STRIP with little burnout required Minimal tread void for excellent dry traction, strategically placed to aid in hydroplane resistance 18 popular sizes for 15- to wheel diameters DO NOT USE ON DYNO Brand Mickey Thompson, Seasons Year Round, Size Section Width 275 Millimeters, Ply Rating Polyester, Tire Diameter 25.9 inches, Weight 30.95 Pounds, Manufacturer Mickey Thompson, Model ET Street S/S, model number Is Discontinued No, Manufacturer + +Price is $",300 +"How much does this cost to the nearest dollar? + +Pirelli 106W XL RFT P0 +Product Type Vehicle Tire Package Dimensions 10.9 L X29.0 W X29.0 H Country Of Origin Mexico Package Weight Fit type Universal Fit Brand Pirelli, Seasons Year Round, Size Section Width 275 Millimeters, Load Capacity 2094 Pounds, Tread Depth 9 32nds, Tread Type Asymmetrical, Ply Rating XL, Tire Diameter 28.66, Weight 36 pounds, Manufacturer PIRELLI, Model P Zero PZ4 Run Flat, model number Is Discontinued No, Manufacturer Part OEM Part Special Features Run_flat, Construction Radial, UTQG Rank Automotive Passenger Car Performance Tires 722, Available August 5, 2017, Rim Size + +Price is $",350 +"How much does this cost to the nearest dollar? + +Torklift C3212 Rear Tie Down +Fits 11-14 Chevy/GMC 2500 / 3500 HD (Crew / Ext. Cab ONLY) with factory hitch 11-14 Chevy/GMC 2500 / 3500 HD (Crew / Ext. Cab ONLY) with factory hitch 11-13 Chevy/GMC 2500 / 3500 (Regular Cab ONLY) with factory hitch 2014 Chevy/GMC 1500 4wd (Crewcab) with factory hitch 2014 Chevy/GMC 2500 4wd (Crewcab) with factory hitch 2014 Chevy/GMC 2500 4wd (Regular Cab) with factory hitch 2014 Chevy/GMC 3500 4wd ( + +Price is $",200 +"How much does this cost to the nearest dollar? + +Cardone Remanufactured Ford Computer +CARDONE Remanufactured Electronic and Powertrain Control Modules are designed to meet or exceed O.E. performance. Reverse engineering provides insight into how and why the unit originally failed, allowing our engineers to identify and correct original design weaknesses. All critical components are re-soldered or replaced at our Philadelphia manufacturing plant, and each unit is 100% computer tested to ensure reliability. CARDONE is committed to getting your vehicle back to peak performance. On-car vehicle validation testing ensures product fits and functions properly OE components with high failure rates are 100% replaced All electronic modules are 100% tested to ensure they meet OE requirements for the application Advanced robotic equipment ensures precision made units and consistent high quality with every part Every unit is 100% tested to ensure + +Price is $",199 +"How much does this cost to the nearest dollar? + +Kidde AccessPoint 001798 Supra TouchPoint Lock +From the Manufacturer TouchPoint lock is designed to replace a standard cam lock in a variety of metal storage cabinets or enclosures sized with 5/16 inch square-hole cams. Solid die-cast body with a 10 digit changeable combination and a clutch mechanism to turn the cam. Can be mounted on top of the door surface or flush-mounted into the door. User changeable combination lock with push button combination is designed to replace a standard cam lock Door lock can easily change keyed cabinets to pushbutton locks; for use with items with 5/16 inch cams Combination lock features heavy-duty die-cast construction; great for metal cabinets and other enclosures Mounts flush into a door, or on top of a door surface; clutch + +Price is $",99 +"How much does this cost to the nearest dollar? + +3M Protecta Self Retracting Lifeline Rebel 6' (18M) Web Twin, Steel Rebar and Carabiner, Black/Red +Our Protecta personal self retracting lifelines (SRL’s) represent a major improvement in economy line SRL’s. Employers can economically replace simple lanyards with the versatility and added safety of a 6 ft. (1.8m) SRL. Protecta personal SRL’s are ergonomically designed for ease of use and are ideal for direct connection to most harnesses. The compact and lightweight design is barely noticeable on your back and stays out of the worker’s way. In addition, tension is always kept on the lifeline, which reduces dragging, snagging and trip falls. Whether your application requires + +Price is $",20 +"How much does this cost to the nearest dollar? + +Plantronics Wired Headset, Black, 7 x 5.4 x 2.2 inches +The next generation of our most popular over-the-head monaural headset. Completely re-imagined for the demands of the modern customer service center and office. Features soft ear cushions for all-day wearing comfort, metal joints that deliver durability and reliability and a flexible mic with visual and tactile positioning guides for precise positioning and clearer conversations. Frequency response - up to 6,800 Hz Dimensions 7 x 5.4 x 2.2 inches, Weight 4.8 Ounces, Manufacturer PLANTRONICS, INC., model number Rank Computer Headsets 370, Is Discontinued No, Available October 30, 2014, Units 1.0 Count + +Price is $",40 +"How much does this cost to the nearest dollar? + +Logitech K750 Wireless Solar Keyboard for Windows, 2.4GHz Wireless with USB Unifying Receiver, Ultra-Thin, Compatible with PC, Laptop - Black +Product Description Battery hassles are a thing of the past with the solar-powered Logitech Wireless Solar Keyboard K750. It charges itself whenever there's light, so you can say good-bye to batteries, power bricks and charging cables. With sleek lines and a thin profile, this stylish, streamlined keyboard adds style to your workspace. Combining the best of traditional keyboards, laptops and a Logitech-only concave key cap design, you'll enjoy faster, quieter, feel-good typing-hour after hour. Plus, you'll get Logitech Advanced 2.4 GHz wireless and the tiny Logitech Unifying receiver. From the Manufacturer + +Price is $",85 +"How much does this cost to the nearest dollar? + +Olympus PEN E-PL9 Body Only with 3-Inch LCD (Pearl White) +Introducing the PEN E PL9. It has everything to produce images you’ll be proud to share. There’s nothing to learn; just pick it up and let the on screen guides and built in settings make every shot perfect. Thanks to the powerful image stabilization system, you’ll easily shoot blur free stills and smooth 4K video, all handheld. With features like flip touchscreen, built in flash, Wi Fi and Bluetooth for easy sharing make the E PL9 your go to camera. 16 Megapixel live MOS sensor TruePic VIII Image Processor 3 180 Degree Flip down touch screen In body 3 axis image stabilization 4K video & still image capture from 4K + +Price is $",450 +"How much does this cost to the nearest dollar? + +Beck/Arnley Hub & Bearing Assembly +Since 1914, Beck/Arnley has focused on the customer, offering high quality parts that look and perform the same as the original part. This ideal has never changed. Today, Beck/Arnley is committed to being the premium supplier of high quality import parts within the automotive market. BeckArnley is an original equipment brand that partners with other manufacturers to supply the parts that cars were originally built with. This product is in a BeckArnley package, note that the part may have been manufactured by an independent BeckArnley supplier and the number on the part may differ from the number on the package. Quality construction Excellent materials Exacting tolerances Manufacturer Beck/Arnley, Brand Beck/Arnley, Weight 6.37 Pounds + +Price is $",120 +"How much does this cost to the nearest dollar? + +Eibach Pro-Kit Performance Springs Set Of 4 Compatible with Nissan Altima +Eibach production technology is recognized worldwide as leading its field, from our high-strength spring-steel alloys, our advanced CNC winding process, our high-quality corrosion protection and the legendary longevity of our components. High Performance Handling and Aggressive Good Looks. Each Spring Individually Tested Stop Quicker, Corner Faster and get Better MPG! Progressive Spring Design for Excellent Ride Quality. Manufacturer Eibach, Brand Eibach, Model Weight 24.8 pounds, Dimensions 24.7 x 14.7 x 7 inches, model number Exterior Machined, Manufacturer Part Rank Automotive Automotive Replacement Shocks 12221, Available December 9, 2019 + +Price is $",60 +"How much does this cost to the nearest dollar? + +LEGO DC Batman 1989 Batwing 76161 Displayable Model with a Buildable Vehicle and Collectible Figures Batman, The Joker – Mime Version and Lawrence The Boombox Goon, New 2021 (2,363 Pieces) +This is no kid’s toy. If you’re serious about BATMAN, comic book super heroes or making cool models, this LEGO DC BATMAN 1989 Batwing is for you! Recreate the authentic detail and gothic elegance of BATMAN’s iconic aircraft, the Batwing, with this LEGO brick build-and-display model. The impressive reproduction features realistic details, removable canopy, full interior, poseable flaps and a new special brick that will allow you to mount and display your model on your wall. There’s also a stand, nameplate + +Price is $",29 +"How much does this cost to the nearest dollar? + +Kingston Brass Restoration 4-Inch Centerset Lavatory Faucet with Porcelain Lever Handle, Brushed Nickel +Product Description Classic style. Two handle deck mount. 4 in. center set. Max 1.2 LPM water flow rate at 60 PSI. Integrated removable aerator. Drip-free ceramic cartridge system. Three hole sink application. 4.05 in. spout reach. 3 in. spout height. 4 in. center spread installation. 1/4 turn on and off water control mechanism. 1.05 in. spout clearance. Made from brass. Satin nickel finish. Made in Taiwan. From the Manufacturer Functional and Stylish Faucets Gives an Irresistible Beauty to the Bathroom. Design is Perfectly Co- + +Price is $",35 +"How much does this cost to the nearest dollar? + +Polk Vanishing Series 265-LS In-Wall 3-Way Loudspeaker, Dual 6.5 Dynamic Balance Drivers & 1 Ring-Radiator Tweeter, Polk PowerPort Technology, Rotating Cam System for Easy Installation +Enjoy extraordinary audio performance for your movies, music and TV shows with the Polk Vanishing Series 265-LS 3-Way Loudspeaker that disappears into your wall and yet delivers impactful, room filling sound. The in-wall speaker is equipped with dual 6.5 Dynamic Balance Drivers for clear, accurate mids and dynamic lows, and a 1 Ring-Radiator Tweeter for incredible imaging. With Polk's Patented PowerPort Bass Technology, the speaker adds deep, rumbling bass to your audio, while minimizing unwanted resonances. + +Price is $",200 +"How much does this cost to the nearest dollar? + +Spec-D Tuning LED Projector Headlights Glossy Black Housing Smoke Lens Compatible with Subaru Impreza Outback Sport, Subaru Impreza WRX Left + Right Pair Headlamps Assembly +✔️ All of Our Items are 100% Brand New In Original Packaging! You Will Never Receive a Used Item From Us! Comes in a Pair (Driver Side Left & Passenger Side Right Included) ✔️ DOT and SAE Compliant. Made by an ISO Certified Manufacturer using Materials that meet or Exceed OEM Requirements! ✔️ Direct Bolt On Replacement From Your Original Headlights! No Wiring or Modifications Needed! No Installation Instructions Included, Professional Installation is Highly Recommended! ✔️ Products Undergo Strict Quality Control to Ensure it is Waterproof (fully sealed with solid silicon) & Impact/UV Resistant + +Price is $",300 +"How much does this cost to the nearest dollar? + +RICHMOND & FINCH Airpod Pro Case, Green Leopard Full Protective Cover, Shockproof, Scratch Resistant, Wireless Charging Compatible Case for Airpods Pro +COMPATIBILITY This Richmond & Finch Airpod Pro Case is compatible with Airpods Pro Only PROTECTION Our Richmond & Finch Airpods Pro Case offers premium protection to your air pods pro with our shockproof protective cover, protecting your Airpod Pro from drops and knocks WIRELESS CHARGING The Richmond & Finch Airpods Pro Case is wireless charging compatible, so you can charge your Airpod Pros easily and quickly SCRATCH RESISTANT Our Richmond & Finch Airpod Pro Protective Cover is made from high quality scratch resistant materials, ensuring your Air Pods Pro are safe from any scratches or damage FASHION FORWARD All + +Price is $",30 +"How much does this cost to the nearest dollar? + +LFA Industries - mm Capacity, 33 Jacobs Taper Mount Plain Bearing Precision Crafted Heavy Duty All Steel, Keyed Drill Chuck with T5/k32 Chuck Key Included +LFA Industries Plain Bearing Precision Crafted Heavy Duty All Steel, Keyed Drill Chuck with T5/k32 Chuck Key Included, mm Capacity, 33 Jacobs Taper Mount. LFA Industries Plain Bearing Precision Crafted Heavy Duty Keyed Drill Chuck All Steel, Keyed Drill Chuck with Key Included LFA Industries mm Capacity, 33 Jacobs Taper Mount Manufactured To Last-For Quality and Excellence-Chucknology Made in France over 85 Years Manufacturer LFA Industries, Part Weight 2 pounds, Dimensions 2.88 x 1.67 x 2.88 inches, Country of Origin France + +Price is $",40 +"How much does this cost to the nearest dollar? + +SAUTVS LED Headlight Assembly for Slingshot, Center Head Light Kit for Polaris Slingshot S GT R LE SL Modified Accessories, Replace OEM +Compatible with Polaris Slingshot S SL SLR R LE (Please refer to the compatible list in description) Plug & Play, perfect and accurate replacement for the original headlight without any changing or modifying, replace OEM The design of internal protection mechanism makes it no flickering or failure; IP67 waterproof and scratch resistant materials prevent from dust, mud, snow or heavy rain leaking in; Strictly follow the quality and safety standards, working in all the weather conditions High quality LED beads are used, long service time and life span; Brighter and concentrated light source, ensuring your driving safety Package include 1 set LED headlight assembly + +Price is $",100 +"How much does this cost to the nearest dollar? + +2 Pack Combo Womens Safety Glasses Impact Resistant Clear Smoke Lens +Package Includes 2 pairs of Womens Safety Glasses with Clear Lenses and Black Sunglasses Lens Assorted Color Temple Frames Available! Sizing Information Frame length – 6.25 in, Frame Width 5.4 in. Exceeds ANSI Z87.1+ Safety Standards. Shatter Proof Protection Our lenses offer 100% protection against glare and protection against UV/UVA/UVB rays. The Safety Glasses are also scratch-resistant, impact-resistant, and shatter proof. Keep your eyes safe during construction, metalworking, welding, woodworking, hunting, fishing, sports, shooting, and other activities outdoors. Impact Resistant Coating coating Package Includes 2 pairs of Womens Safety Glasses with Clear Lenses and Black Sunglasses + +Price is $",40 +"How much does this cost to the nearest dollar? + +Arepa - Venezuelan cuisine - Venezuela PopSockets PopGrip Swappable Grip for Phones & Tablets +Arepa Venezolana. Arepa - Venezuelan cuisine - Venezuela. Arepa - Venezuelan cuisine - Venezuela. Great gift for holidays, birthdays, events, parties and much more. Arepa - Venezuelan cuisine - Venezuela Great gift for holidays, birthdays, events, parties and much more. PopGrip with swappable top; switch out your PopTop for another design or remove it completely for wireless charging capabilities. (Not compatible with Apple MagSafe wireless charger or MagSafe wallet.) Expandable stand to watch videos, take group photos, FaceTime, and Skype handsfree. Advanced adhesive allows you to remove and reposition on most devices and cases. Note Will not stick to some silicone, waterproof + +Price is $",19 +"How much does this cost to the nearest dollar? + +Schlage Lock Company Padlock, 1-1/2 x 5/16, Brass +Schlage Commercial Padlock 5/16 Diameter with 1-1/2 Shackle and Keyway Schlage commercial grade padlock is designed for use in high risk locations Solid brass body resists corrosion for all-weather performance 1-1/2 in. x 5/16 in. molybdenum hardened steel shackle for increased cut resistance Double deadbolt locking mechanism provides extra security Re-key able Schlage cylinder Brand SCHLAGE, Special Feature Keyway, Lock Type Key Lock, Dimensions LxWxH 0.4 x 1.5 x 2.5 inches, Material Brass, Steel, Recommended Uses For Product Security, Color Brass + +Price is $",40 +"How much does this cost to the nearest dollar? + +Techni Mobili White Sit to Stand Mobile Laptop Computer Stand with Height Adjustable and Tiltable Tabletop +Techni Mobili Sit-to-Stand Rolling Laptop Stand offers an adjustable height mechanism that is compact, portable and is a perfect choice for a laptop or writing setup in a limited space. This Sit-to-Stand mobile laptop stand features a large tabletop with a tilt mechanism attached so it can be adjusted to your most comfortable working angle. It also features a safety edge-stopper to prevent objects from sliding down when tilted. The heavy-duty steel frame supports a sturdy structure, and the non-marking locking casters let you glide while maintaining the balanced level. 𝐒𝐔𝐑𝐅𝐀𝐂𝐄 𝐌𝐀� + +Price is $",40 +"How much does this cost to the nearest dollar? + +Special Lite Products Contemporary Wall Mounted Mailbox with Rain Overhang Finish Oil Rubbed Bronze +The clean lines and minimal design of the Contemporary Horizontal Mailbox provide an immediate way to add a lovely and welcoming outdoor accent to your front porch. The straightforward design makes this mailbox a perfect match with any home while upgrading your entry way at the same time. The durable powder coat finish will keep your mailbox looking vibrant and beautiful for years to come while the door closure will protect your mail from rainy weather keeping it dry inside. All types and sizes of magazines, letters, envelopes can fit easily inside the enclosure. Matching newspaper scroll arms are included and can be easily attached at your choosing. Deliberate but stylish, the Contemporary delivers at all angles. One of our best sellers! All screws, hinges, and like + +Price is $",110 +"How much does this cost to the nearest dollar? + +Tascam Digital Portastudio Multi-Track Audio Recorder & Tascam RC3F 3-Way Footswitch +Tascam Digital Portastudio Multi-Track Audio RecorderTascam Digital Portastudio Multi-Track Audio RecordeTascam RC3F 3-Way FootswitchThe RC-3F is a 3-way footswitch for the GB-10, LR-10, DP-03 and other TASCAM recorders and players. The 1/8 mini jack plugs into the remote jack of these TASCAM products to add features like play/pause, looping or punch in. See the products' user manual for details. Product 1 Eighteen track faders and one master fader allows instant access to any track without selecting pages + +Price is $",399 +"How much does this cost to the nearest dollar? + +Glow Lighting Vista Crystal Flush Mount, 6 W +Create that beach feeling with this capiz shell and chrome pendant chandelier. Ideal for bedrooms, kitchens, dining rooms and bathrooms. Uses 3 x 40 Candelabra base bulbs Trimmed with clear crystal Easy installation hardware, instructions included for convenient setup CSA/CUS approved for dry location Manufacturer Glow Crystal Lighting Inc., Part Weight 2.69 pounds, Dimensions 10 x 10 x 8.5 inches, Country of Origin Canada, model number Is Discontinued No, Size 6\ W, Color 8.5, Power Source Corded Electric, Voltage 120 Volts, Quantity 1, Type of Bulb incandescent, Mounting Type Ceiling Mount, Plug Format A- US style, Certification CSA + +Price is $",166 +"How much does this cost to the nearest dollar? + +Z3 Wind Deflector, Smoke Tint, Lexan, Windscreen, Windstop, Windblocker +- Easy installation, installs in less than two minutes. - Take long trips with the top-down in comfort. - Cruise at night without freezing from cold drafts. - Hear the full richness and clarity of your stereo. Reduce turbulence up to 70%; prevents unrelenting wind buffeting and driver fatigue Unique no reflection or glare, easy to use at night against headlights; Unlike others, no abrasion, does not induce long term wear 30 day trial period and lifetime warranty; No rattles or squeaks, is silent; Keep hair in place while driving with the top-down. Talk clearly on your blue tooth device; Talk with passengers without strain; Enjoy conversations while driving with the + +Price is $",99 +"How much does this cost to the nearest dollar? + +Olympus E-20 5MP Digital Camera w/ 4x Optical Zoom +Product description 5.2 megapixel sensor creates 2,560 x 1,920 images for prints at 11 x 14 and beyond 4x optical zoom lens with autofocus Included 32 MB SmartMedia card holds 7 images at default resolution Compatible with SmartMedia and Type I and II CompactFlash Uses Amazon.com You'd be hard-pressed to find a digital camera that captures better images than those from the Olympus E-20N. The camera pairs a sensor with a high-quality custom-designed 4x zoom lens for photos with clarity that rivals film. First, a note about naming conventions this camera is also known as the E-20 and the E-20P. The N + +Price is $",220 +"How much does this cost to the nearest dollar? + +PHYNEDI 1 1000 World Trade Center Bricks Model Compatible with Lego, MOC DIY Creative Large Architecture Collection Challenge Building Toy, (4,870 Pieces) +The building instructions of this model are two PDF guides (Part 1 has 135 pages, Part 2 has 155 pages),. Part 1 also includes a four page introduction about the World Trade Center history and design. World Trade Center features Scale 1 in inches 13,2 x 10,7 (base area), 22,7 (height)Size in centimeters 33,6 x 27,2 (base area), 57,5 (height)Size in studs 42 x 34 (base area), 71,9 (height)Style ArchitectureYear 2022 Package + +Price is $",50 +"How much does this cost to the nearest dollar? + +YANGHUAN Unstable Unicorns Adventure Card Game Toy Expansion Pack-Teen Board Game-Adult Strategy is Designed to add to The Base Unstable Unicorn Solitaire Expansion Pack +Product Description Product Name Card Game Single piece size 15 x 10.5 x 5cm Single piece weight 350g Expansion package parameters Single piece size Single product weight 105 grams Material coated paper Color Unstable Unicorns white frame, Unstable Unicorns black frame, NSFW extension, Legenda extension, Rainbow extension, Dragons extension, Uncut extension Ability training emotion, intellectual development, brain use, other ability training, interactive toys, parent-child communication, interest development Suitable age 14 years old and above Game type Unstable Unicorns is still a strategy game, it will destroy your + +Price is $",40 +"How much does this cost to the nearest dollar? + +Interlogix NetworX Touch Screen Keypad, 3.5 Color Touch Screen, Icon-based Graphic Interface, Built-in Message Board, NetworX System Compatibility, Capability, Modern Design +Interlogix NetworX Touch Screen Keypad, 3.5 Color Touch Screen, Icon-based Graphic Interface, Built-in Message Board, NetworX System Compatibility, Capability, Modern Design Ideal for almost any size application, the NetworX Touch Screen Keypad offers powerful yet simple control of any NetworX security system. An intuitive interface, 3.5 touch screen and Quick Keys for rapid system arming and status updates enable quick and easy system management Users can record their own names for different system components and leave voice messages for others when arming or disarming. When a Net + +Price is $",110 +"How much does this cost to the nearest dollar? + +Steering Damper,Universal Motorcycle Handlebar Aluminum Alloy Steering Damper Stabilizer Safety Control(Gold) +Features 1. Durable in Use Made of durable aluminum alloy for extreme strength. 2. Excellent Quality Professional manufacturing, high precision and good quality. 3. Easy and Simple to Hand Easy installation without any modification required. 4. Stable Quality The anodized surface for enhance its oxidizing and corrosion resistance. 5. Scope of Application Universal for motorcycle, high-emissions car, sports car, street car. Specification Condition 100% Brand New Material Aluminum alloy (CNC) Color Black/Gold/Red/Silver/Blue(optional) Mounting screw Fitment Universal for motorcycle, high-emissions car, sports car, street car. Package List 1 * Dam + +Price is $",120 +"How much does this cost to the nearest dollar? + +Amprobe TIC 410A Hot Stick Attachment +Amprobe products range from an extensive line of clamp meters and digital multimeters to industry-specific tools for residential/commercial electricians, HVAC/R technicians, utilities and industrial maintenance professionals. All Amprobe tools undergo rigorous testing to ensure full compliance with the latest IEC and CE safety regulations in Fluke Safety labs for quality and safety you can trust. Extension probe attaches to Amprobe TIC 300 Pro AC voltage detector to test for high AC voltages without touching or disconnecting the circuit Can detect AC voltages between 1,500V and For utility, industrial, and mining applications when working with high-voltage equipment such as transmission lines, downed power lines, fuses, and load-break connectors Extends to 57 long Conforms + +Price is $",100 +"How much does this cost to the nearest dollar? + +MyCableMart 3.5mm Plug/Jack, 4 Conductor TRRS, Self Solder, Male +Connects stereo audio & microphone devices requiring 4 conductors (left and right audio and microphone plus ground). This connector MAY also be suitable for left/right audio 1 video (composite) and ground. Great for making your own 3.5mm 4 conductor Cables or for repairing existing cables. Wire terminals are attached using solder (not included).Features 3.5mm 4 conductor (3 band) plug 3.5mm 4 conductor (3 band) plug Nickel Plated Nickel Plated Strain relief Strain relief Outer Dimensions (at PVC outer molding) Outer Dimensions (at PVC outer molding) Outer Dimensions (with PVC outer molding + +Price is $",25 +"How much does this cost to the nearest dollar? + +OtterBox + Pop Symmetry Series Case for iPhone 11 Pro (ONLY) - Retail Packaging - White Marble +OtterBox + Pop Symmetry Series Case for iPhone 11 Pro (ONLY) - Retail Packaging - White Marble Compatible with iPhone 11 Pro Thin one-piece case with durable protection against drops, bumps and fumbles that is also compatible with Qi wireless charging PopSockets PopGrip is integrated into case to help with holding, texting, snapping better pictures and hand-free viewing PopTop designs are easy to switch out — just close flat, press down and turn to swap the PopTop. Includes OtterBox limited lifetime warranty (see website for details) and 100% authentic Dimensions 7.8 x 4.29 x 1.06 inches, Weight 3 + +Price is $",20 +"How much does this cost to the nearest dollar? + +Dell XPS Desktop ( Intel Core i7 4790 (3.6 GHz), 8GB, 1TB HDD,Windows 10 Home Black +Product description Bring your multimedia to life with Dell XPS desktop PCs offering powerful processors, superb graphics performance and lots of storage space. Amazon.com Processor 4th Generation Intel Core processor (8M Cache, up to 4.00 GHz) OS Windows 7 Professional, English Graphics Card NVIDIA GeForce GTX 750Ti 2GB DDR5 Memory 32GB Dual Channel DDR3 - 4 DIMMs Hard Drive 1TB 7200 RPM SATA Hard Drive 6.0 Gb/s + 256GB SSD Processor 3.6 GHz RAM 8 GB DDR5, Memory Speed 1600 MHz, + +Price is $",500 +"How much does this cost to the nearest dollar? + +Franklin Iron Works Sperry Industrial Bronze Chandelier 28 Wide Rustic Farmhouse Cylinder Scavo Glass Fixture for Dining Room House Foyer Kitchen Island Entryway Bedroom Living Room +28 wide x 28 high. Glass is 6 1/4 high x 3 wide. Canopy is 5 1/2 wide. Weighs 19.58 lbs. Comes with of lead wire and 6-feet of chain. Sloped ceiling adaptable. Uses eight maximum 60 watt standard-medium base bulbs (not included). Contemporary farmhouse eight-light chandelier from Franklin Iron Works. Industrial bronze finish metal frame. Scavo glass cylinder shades. Brand Franklin Iron Works, Color Scovo Glass, Material Glass, Style Farmhouse, Light fixture form Chandelier, Room Type Entryway, + +Price is $",400 +"How much does this cost to the nearest dollar? + +Avery Legal Dividers, Standard Collated Sets, Letter Size, Side Tabs, 51-75 +You have the right to organized and professional-looking files. This Standard Collated Legal Divider Set features Tabs 51-75 so it's perfect for index briefs, legal exhibits, mortgage documentation files and more. White paper stock with clear, Rip Proof reinforced tabs are preprinted on both sides using Helvetica bold type for ease of use, and the unpunched binding edge gives you the freedom to fit practically any binding system. Here's evidence these dividers will do your files justice. Clear Rip Proof reinforced tabs printed on both sides Unpatched binding edge so indexes can fit practically any binding system Contains 30% post-consumer recycled content Avery Style is printed using Helvetica bold type Manufacturer Avery, + +Price is $",20 +"How much does this cost to the nearest dollar? + +Moen 8346 Commercial Posi-Temp Pressure Balancing 4 Port Cycling Valve Hand Shower System 2.5 gpm, Chrome +Product Description VERSATILE DESIGN Chrome finish is highly reflective for a mirror-like look that works with any decorating style From the Manufacturer This single-handle handheld shower system has a Posi-Temp pressure-balancing valve that maintains water pressure and controls temperature, a slide bar, drop ell, vacuum breaker, a metal hose and mounting hardware. The pressure balancing cycle valve design has 1/4 turn stops, the rubber nozzles are quick cleaning and the chrome plated metal construction provides a bright, highly reflective, cool grey metallic look. The temperature handle operates counterclockwise through a 270 degree arc, with off at 6 o' clock + +Price is $",200 +"How much does this cost to the nearest dollar? + +Carlisle Versa Trail ATR All Terrain Radial Tire - NHS +Tire designed to provide high performance for sports driving. Providing maximum traction with good braking control and handling, the tire offers unrivaled comfort when driving at high speeds. Comfort, experience, technology and design! Tire only, Rim not included made in united states package height 8.9 package length 27.1 package width 27.1 Fit type Universal Fit Brand Carlisle, Seasons NON_WINTER, Size Rim Size 12 Inches, Section Width 9 Inches, Tire Aspect Ratio 8, Speed Rating M, Tread Depth 24 32nds, Ply Rating 6-Ply, Tire Diameter 27 Inches, Weight 23.6 pounds, Manufacturer Carlisle, Model Versa Trail ATR + +Price is $",300 +"How much does this cost to the nearest dollar? + +SUNWAYFOTO 44mm Tripod Ball Head Arca Compatible Sunway +66lb Max load! Eliptical Ball for progressive resistance. Y-axis diameter 0.03mm longer than the X-axis. Single notch design. Super strong shell. All Metal knobs. For long term durability. Panning Base Scale Independent Pan Lock Knob, 360° panning movement with calibrated precision, precisely capture overlapping panoramic images. Panning Base is laser-engraved with index marks from with increments at 5° 50mm clamp with Bubble level. Ball Diameter 44mm. Base 55mm. Height 94mm. Weight 450g. Max load 30kg (66 lbs). Bottom thread 3/8 with 1/4 adapter. 1 year + +Price is $",100 +"How much does this cost to the nearest dollar? + +NanoBeam AC 4 Units 5GHz High-Performance airMAX ac Bridge CPE with Dedicated Management Radio +Models Ubiquiti Networks NanoBeam AC 5GHz High-Performance airMAX ac Bridge CPE with Dedicated Management Radio Incorporating innovative industrial design with proprietary airMAX ac technology, the NanoBeamAC is ideal for CPE deployments requiring maximum performance from the smallest possible footprint. The NanoBeam ac Gen2 airMAX ac CPE with Dedicated Management Radio from Ubiquiti Networks offers a more reliable long-distance point-to-point connection. Boasting a maximum throughput up to 450 Mb/s, this NanoBeam radio is designed to filter out noise to reduce interference in areas congested with multiple RF signals while offering up to 19 dBi gain. Setup is simple, as the NanoBeam + +Price is $",150 +"How much does this cost to the nearest dollar? + +WULF 4 Front 2 Rear Leveling Lift Kit with Spindles & Shackles compatible with Ford Ranger 2WD with Coil Spring Suspension +Compatible with Ford Ranger 2WD with Coil Spring Suspension FRONT WULF 4 Lift Ductile Cast Iron Spindles / Knuckles REAR 1.5-2 Adjustable Lift Black Powder Coated Shackles, Zerk-Grease Fittings, Pressed greaseable high grade poly bushings and metal sleeves included NOTE 2WD models only. Excludes models with Stabilitrak. Requires Coil Spring suspension Please see the description for full details, or contact us for assistance Fast Shipping. Manufacturers Lifetime Warranty. Dedicated Customer Service Manufacturer WULF Suspensions, Brand WULF Suspensions, Country of Origin USA, + +Price is $",250 +"How much does this cost to the nearest dollar? + +Alera ALEVABFMC Valencia Series Mobile B/f Pedestal, 15 7/8 X 19 1/8 X 22 7/8, Med. Cherry +Sturdy woodgrain laminate mobile box file pedestal to store all your office necessities. Full-extension ball bearing slides on file drawer for easy access. Durable laminate is water-, scratch-, and dent-resistant with 3 mm protective edge banding. Two fold-away safety keys included. Accepts Alera® Pedestal Cushions for an instant seating option. Sturdy woodgrain laminate mobile box file pedestal to store all your office necessities. Full-extension ball bearing slides on file drawer for easy access. Durable laminate is water-, scratch-, and dent-resistant with 3 mm protective + +Price is $",50 +"How much does this cost to the nearest dollar? + +YU-GI-OH! Ignition Assault Booster Box +24 Packs per Display 9 cards per packHumanitys greatest fear has been realized! Dueling A.I.s have become sentient and organized their own army to take the Yu-Gi-Oh! TRADING CARD GAME by storm in Ignition Assault! Winter 2020s booster set heats things up with Ais @Ignister cards from the climax of YuGi-Oh! VRAINS, multiple brand-new strategies, new cards for popular strategies, and powerful, general use cards that every Duelist will want to add to their arsenal! Keep your A. 24 Packs per Display 9 cards per pack Dimensions 5.65 x 4.75 x 1.5 inches, Weight 11.2 ounces + +Price is $",30 +"How much does this cost to the nearest dollar? + +48 x 36 Extra-Large Framed Magnetic Black Chalk Board (Black Frame) +Handsome, smooth 48 x 36 inches extra-large framed black chalk board. Perfect for office, meeting rooms, classrooms, at work or at home...to serve as black board, or magnetic board, or menu board, or bulletin board etc. Black frame. (Search for on Amazon if you want a Dark Brown wood tone frame or if you want a Medium Brown wood tone frame.) DELIVERY Shipped to continental U.S. addresses only. Handsome, smooth black board with elegant black veneer frame and reinforced backing. (If you want a dark brown wood tone frame, search for on Amazon; If you want a medium brown wood tone frame, search for ) Lean this light-weight black board + +Price is $",60 +"How much does this cost to the nearest dollar? + +Dell Latitude D620 Renewed Notebook PC +Dell Latitude D620 14.1 Laptop (Intel Core Duo 80GB Hard Drive, 2048Mb RAM, DVD/CDRW Drive, XP Professional) Windows XP Professional with Dell Reinstallation XP Pro. CD Intel Core Duo Processor 2GB DDR2 RAM 80GB Hard Drive Screen, Wifi Standing screen display size 14 Inches, Screen Resolution 1366 x 768 pixels, Processor 1.83 GHz RAM 2 GB DDR2, Memory Speed 1.83 GHz, Hard Drive 60 GB HDD, Chipset Brand Intel, Card Description Integrated, Wireless Type USB 2.0 Ports 3, Brand Dell, Series Dell Latitude, model number d620, Hardware Platform PC, Operating System Windows XP + +Price is $",150 +"How much does this cost to the nearest dollar? + +acer Aspire 5 Laptop, AMD Ryzen 3 5300U Quad-Core Processor, 15.6 FHD IPS Display, 8 GB DDR4 RAM, 512 GB PCIe SSD, HDMI, Fingerprint, Wi-Fi 6, Backlit Keyboard, Windows 11 Home S Mode +Processor AMD Ryzen 3 5300U 4-Core Processor (8 Threads, 4MB L3 Cache, Up to Graphics AMD Radeon Operating system Windows 11 Home English Memory 8 GB DDR5 SDRAM Hard Drive 512 GB PCIe Solid State Drive Optical Drive No Display 15.6 FHD (1920 x 1080) LED-backlit, IPS Wide Viewing Angle, Slim Bezel, 16 9 aspect ratio 1 x USB 2.0 + +Price is $",400 +"How much does this cost to the nearest dollar? + +Elk 30 by 6-Inch Viva Pendant with Green Glass Shade, Satin Nickel Finish +The Viva light pendant is meticulously hand blown with up to three layers of uncompromising beauty and style. This pendant features green hand blown glass shade. Shade holder comes in satin nickel finish. Accommodates six medium base bulbs. Measures 9-inch extended length by width by 6-inch height. Viva light pendant is meticulously hand blown with up to three layers of uncompromising beauty and style Features exquisite line of green hand blown glass shade Accommodates six medium base bulbs Shade holder comes in satin nickel finish Measures 9-inch extended length by width by 6-inch height Brand Elk, Color Satin Nickel, Material Material Other, Style Contemporary, Light fixture form Pendant, Specific + +Price is $",60 +"How much does this cost to the nearest dollar? + +Barbie Top Model Doll +Amazon.com.caption font-family Verdana, Helvetica neue, Arial, serif; font-size 10px; font-weight bold; font-style italic; ul.indent list-style inside disc; text-indent -15px; Barbie is ready to hit the runway and show off the latest global fashions as a top model. While we all know Barbie’s occupational curiosity has led her down varied paths, this one is perfect for the slender fashionista. She comes wearing a trendy outfit of fishnet stockings, a tiered black miniskirt, a patterned top with a short sleeve shrug, and ankle boots. Her long blond hair is styled sleekly straight and she is carrying an animal print handbag. While this outfit is certainly catwalk worthy, it’s only + +Price is $",60 +"How much does this cost to the nearest dollar? + +Danby Designer 20-In. Electric Range with Coil Elements and Ft. Oven Capacity in Stainless Steel/Black +You dont need to be a world-class chef to enjoy cooking with this ultra-compact electric range by Danby Designer. Measuring only 20 inches wide, this stylish model is the ideal addition to trailers, cottages or efficiency apartments. It features a glass window on the oven door, plus angled front-mounted push and turn safety knobs with hot surface indicator lights. The lift-up porcelain cooktop has one 8-inch coil element for quick boiling and three 6-inch coil elements. Each element has a removable drip bowl for easy cleaning. The ft. electric oven has two oven racks with safety stops and four adjustable positions, plus a powerful broiler with 2400 watts of bro + +Price is $",200 +"How much does this cost to the nearest dollar? + +FixtureDisplays® Metal Truss Podium Double Width Modern Design +FixtureDisplays Metal Truss Podium Double Width Modern Design Churches & Other Venues Black truss is great to project a simple, clean and crisp look. Decorative truss panel design. Great for Churches, Schools, Hotels, Conferences, Funeral Homes, Stages, Debates, Wedding & Events, Restaurants Reception, Concierge etc. Easy screw aseembly. Contact us if u wish to order assembly service. Double-wide Full Size Pulpit Measurement 39 wide x 15.5 deep x 46.7 tall. Podium weighs 41 lbs. Reading panel comes with book stopper. Works great for two person services, or a larger room where a wider podium is proper. Sturdy Construction Made + +Price is $",250 +"How much does this cost to the nearest dollar? + +ACDelco GM Original Equipment Alternator +ACDelco GM Original Equipment Light Duty Alternators have components that are newly manufactured, and are GM-recommended replacement for your vehicle’s original alternator. Alternators provide power to the vehicle's electrical systems and charge the battery while the engine is running. These original equipment alternators have been manufactured to fit your GM vehicle, providing the same performance, durability, and service life you expect from General Motors. 100% newly manufactured as an exact replacement for your GM vehicle’s original alternator Components are tested to meet original specification requirements for remarkable durability GM-recommended replacement part for your GM vehicle’s original factory component Offering the quality, reliability, and durability of GM OE Manufactured to GM OE specifications for fit, form, and function Dimensions 13.8 + +Price is $",200 +"How much does this cost to the nearest dollar? + +EBC Premium Street Brake Kit +Type Automotive Brake Save 10% from buying separate parts with EBC Brakes quality brake kit. High efficiency EBC pads with patented EBC Brake-in coating and premium rotors with thermic anti rust coating, fully balanced and run-out tested for smooth braking.Dimension 12 x 12 x 12 inchWeight 35.18 lbsManufacturer Warranty Covered by Manufacturer's Warranty Daily Driver Premium Brake Kit For Cars Truck Or SUV Quality British Made EBC Pads Premium G3000 OE Style Rotors Geomet Anti Rust Coating Manufacturer EBC Brakes, Brand EBC, Model EBC Brakes, Weight 40 pounds, model number Manufacturer Part Available May 19, 2012, Vehicle Service Type Car, Orientation Front + +Price is $",220 +"How much does this cost to the nearest dollar? + +FXR Men's Boost FX Jacket (Black/Orange/White - Large) +HydrX Pro - Shell - durable, sublimated 450d polyester shell with HydrX Pro laminate Boost LE Shell - M-Series Omni Stretch 450d polyester shell with HydrX Pro laminate F.A.S.T. 90g insulation value in outer shell body, perforated at vent areas Lining - moisture-wicking quick-dry mesh lining FXR Dry Vent system - snowproof and moisture resistant chest side body vent system Removable liner - FXR Thermal Dry active liner with 175g Thermal Flex fill YKK Aquaguard front zipper HD #8 W/P zippers throughout Adjustable windskirt 360 3M Scotchlite reflective Shock-cord adjustable collar Shock-cord adjustable bottom + +Price is $",99 +"How much does this cost to the nearest dollar? + +SuperATV Scratch Resistant 3-in-1 Flip Windshield For CFMOTO ZForce 500 / 800 Trail / 800 EX / 1000 | 1/4 Thick Polycarbonate | USA Made | Can be set to Open, Vented Or Closed +Fits CFMOTO ZForce 500 | CFMOTO ZForce 800 Trail | CFMOTO ZForce 800 EX | CFMOTO ZForce 1000 | Can be used with most soft or hard tops | 100% Fitment Guaranteed Great For All Weather Want a CFMOTO Windshield that works in all conditions? Our 3-in-1 Flip-Up design allows you to choose from closed, vented, or open positions to ride comfortably in all-weather without having to + +Price is $",200 +"How much does this cost to the nearest dollar? + +SBU 3 Layer All Weather Mini Van Car Cover Compatible for Ford Windstar Minivan Model Years Breathable Automobile Van Protection +This Van Cover will provide all year round protection to your car. -It will efficiently shield your car’s paint from all finish-destroying agents sun, rain, snow, dust, dirt, tree sap and other corruptive elements. -The cover will minimize accidental bumps, dings, and scratches. You will save money on car washes, repair shops and will enjoy your ride in a brand-new looking car all year round. Investing in our quality cover is not only a practical move but also the perfect option for maintaining the car’s exterior. Condition Brand New, Color Gray, PACKAGE INCLUDES Brand New Van Cover.Free Storage Pouch, Antenna Patch. All + +Price is $",250 +"How much does this cost to the nearest dollar? + +2 Pack Outdoor Brochure Holder Advertising Pamphlet Display Box with Lid Wall Mount Flyer Holder Acrylic Envelope Holder Waterproof Outdoor Brochure Box for Store Literature Display (Clear) +Features Fit for various occasions Our realtor flyer holders are ideal for literature, real estate advertisements, flyers, paper, letters, tickets, signature papers, etc., suitable for plenty of occasions indoor and outdoor, such as home, office, shopping malls, real estate companies, food stores, public places, business occasions, banks and so on. Warm to share These outdoor brochure boxes can also be applied as gifts for family members, friends, relatives, coworkers, neighbors, and other people you care about, so you can send them to show your love and concern, and to strengthen your relationships. Specifications Material acrylic Color clear Size + +Price is $",10 +"How much does this cost to the nearest dollar? + +Monroe Shocks & Struts Quick-Strut 171585 Strut and Coil Spring Assembly +Featuring a vehicle-specific design, Monroe® Quick-Strut® strut assemblies are fit checked, ride tested and engineered to restore factory ride height and ride performance. Assembled in Paragould, AR, they include all required components in a single unit. QUICKER, SAFER, EASIER AND COMPLETE REPAIR -- Includes everything you need for strut replacement in a single, fully assembled unit with no need for a spring compressor RESTORES RIDE HEIGHT -- Precisely calibrated to meet the OE design, each application-specific coil spring type is engineered to restore ride height and support the vehicle's weight VEHICLE-SPECIFIC DESIGN -- Application-specific coil spring, mount and strut designs ensure + +Price is $",80 +"How much does this cost to the nearest dollar? + +Elements of Design Magellan Three Handle Tub and Shower Faucet, Oil Rubbed Bronze +Solid brass water way construction, Premium color finish resists tarnishing and corrosion, 2.5 GPM / 9.5 LPM at 60 PSI, 6-Inch reach Shower Arm, 1/4 turn washer less cartridge, IPS Inlets, Pressure Balance Valve, Temperature Check Stop.. Constructed from solid brass for durability and reliability Our corrosion and tarnish-resistant finishes provides long-lasting use Pressure Balance Valve; Fine Artistic Craftsmanship Max 2.0 LPM Water Flow Rate At 80 PSI On Showerhead Compliant with California Energy Commission Title 20 Brand Elements of Design, Color Oil Rubbed Bronze, Material Brass, Finish Type Oil Rubbed, Handles 3 + +Price is $",60 +"How much does this cost to the nearest dollar? + +GM Genuine Parts Air Conditioning Evaporator Core +ACDelco GM Original Equipment A/C Evaporator Cores are heat exchangers and are located in the HVAC housing, where they cool and dehumidify the cabin air. Refrigerant is metered into the evaporator by the orifice tube or expansion valve. This original equipment evaporator core is a GM-recommended replacement for your vehicle’s original components and has been manufactured to fit your GM vehicle, providing the same performance, durability, and service life you expect from General Motors. Channel-plate construction provides a high refrigerant contact surface area, resulting in better performance Vacuum-brazed, corrosion-treated, and leak-tested to help provide trouble-free operation GM-recommended replacement part for your GM vehicle’s original factory component Offering the quality + +Price is $",200 +"How much does this cost to the nearest dollar? + +Baseus USB C Docking Station to Cast on 3 Monitors with 100W PD USB-C Port, 4K USB 3.0 * 5, LAN, SD/TF Cards Reader, Audio Port for Windows, Mac Laptop +Docking Station — Up to 16 ports allowing you to connect almost all devices through a single gear; 3 4K HDMI ports to cast different content on each display, PD Type-C to connect mobile devices, 3 USB 3.0 ports, 2 USB2.0 ports. Note Docking station requires a second power adapter through the PD USB-C port when charging your laptop through it Triple Extend to the Fullest — Boost productivity by casting up to 3 different contents on displays; Actual pixels up to when using + +Price is $",50 +"How much does this cost to the nearest dollar? + +Whitehall™ Personalized Whitehall Capitol Mailbox with Door & Side Address Plaques Personalized Mailbox (3 Colors Available) +After your order is placed, our friendly US based representatives will send a layout for your approval THREE COLORS AVAILABLE 1) Black with Gold Address 2) Bronze with Gold Address 3) White with Gold Address BOX DIMENSIONS - 9.625 X 13 X Approved by Postmaster General. Manufactured from die cast, high-density aluminum alloy The address Plaque can display up to five, 3 numbers and the bottom line holds up to sixteen, 1.25 characters. Material Aluminum, Included Security Features Hopper & Baffle, Brand Clarus Crystal, Dimensions 20.38\ D x 9.63\ W x 13\ H + +Price is $",200 +"How much does this cost to the nearest dollar? + +Pro Circuit Works Pipe for 02-19 YAMAHA YZ250 +The Original Pro Circuit Works Pipe Offers Unparalleled Performance and Power for Every Two-Stroke Application. Increased Horsepower and Torque Gains Will Quickly Be Noticed Across the Entire Rpm Range. The Unplated, Oiled Metal Finish Requires Some Maintenance, but Really Gives Your Bike That Works Look. Please Note The Image Displayed Is Representative of the Item, but May Vary Slightly Depending on Your Specific Model. Please Note The Image Displayed Is Representative of the Item, but May Vary Slightly Depending on Your Specific Model. Size YAMAHA YZ250 Style CARBON STEEL Color silver Warranty Pro-Circuit provides a 90-day warranty. See their site for full details. Manufacturer Pro Circuit + +Price is $",180 +"How much does this cost to the nearest dollar? + +HYANKA 15 1200W Professional DJ Speaker, Portable Pa System, Bluetooth Party Speaker with Subwoofer, Microphone and Speaker Set, Powered Pa Speaker System with Light, FM, TWS, USB, Remote, EQ +1. High Powered Active Professional DJ Speaker The B-15 has been finely tuned by our experienced engineer teams with 1200W P.M.P.O portable loud powered system with the HF Unit made of super titanium film with high sound without any distortion. Separate bass and treble controls on this Active Professional DJ Speaker allow for precise pitch tuning. This Bluetooth DJ speaker with subwoofer will give you incredibly loud sound crystal-clear treble and booming bass. 2. Multiple Easy Connections This large party powered pa speaker with 15 subwoofer can be connected + +Price is $",100 +"How much does this cost to the nearest dollar? + +Bluetooth X6BT Card Reader Writer Encoder Card Writer Device +Package Includes 1 x X6(BT) Card Reader Writer 1 x Software MINI CD 1 x Bluetooth dongle 1 x USB cord 20 x Blank Cards - X6 Bluetooth Card Readers Writer Encoder card swipe - World's Only Bluetooth Card Reader / Writer. - The World First Bluetooth Manual Swipe Smallest Card Reader/Writer is designed in USA to offer a card reading/writing solution. - for ISO 7811-6 formats, it’s Powered by USB directly not need for extra power adaptor. - Works with all the major operating systems as Windows 7, 8, 10, Vista, X, bits) and Apple Computers(MacBook Air, MacBook Pro, Mac Mini, Mac Pro, i + +Price is $",50 +"How much does this cost to the nearest dollar? + +AIRAID Cold Air Intake System by K&N Increased Horsepower, Cotton Oil Filter Compatible with FORD (Excursion, F250 Super Duty, F350 Super Duty) +INCREASES HORESPOWER AIRAID performance air intake systems feature an aerodynamically-engineered intake tube, designed to accelerate airflow to your engine and reduce turbulence—helping increase your vehicle’s performance SUPERIOR FILTRATION AIRAID performance intake systems are engineered to provide a smooth, unimpeded path for airflow to your engine—keeping the air cooler and more oxygen-dense. Injecting more oxygen-rich air into the cylinders allows the engine to burn fuel more efficiently during combustion, offering you an increase in performance EASY INSTALL These simple-to-install, sophisticated systems help maintain proper air-to-fuel + +Price is $",150 +"How much does this cost to the nearest dollar? + +Bostingner Shower Faucets Sets Complete, Shower System 10 Inch All Metal Overhead Rain Shower Combo Set with Handheld Ceiling Mounted 3 Way Pressure Balance Shower Valve and Trim Kit, Matte Black +Ultra-Luxury Multi Shower - Unlike normal shower kit that can only use single function at a time, Bostingner Shower head system can be used both the rainfall shower head and handheld spray SIMULTANEOUSLY that strikes the perfect balance of GENEROUS COVERAGE and HIGH PRESSURE. The PUSH BUTTON design makes it easy to switch settings, so children and elderly can also use it without a problem Anti-scald & Water Hammer Prevention - The Upgrade cUPC Certified Anti-scald pressure balance valve is key to safe homes, effectively control water pressure balance to prevent scald and + +Price is $",100 +"How much does this cost to the nearest dollar? + +PIT66 Front Bumper Turn Signal Lights, Compatible with Mazda MX-5 Miata 1990 1991 1992 1993 1994 1995 1996 1997 W/Bulbs Smoked Lens Left Driver Side and Right Passenger Side. +Compatibility - Compatible with Mazda MX-5 Miata. Reference Oem Part Number Perfect Design - Smooth circular arc design, more beautiful appearance, tight fitting to the vehicle, unique lighting system, providing all-round lighting, evenly distributing light output in all directions, maximizing visibility. Safety - It can effectively help you to remind passing vehicles and identify whether the distance on both sides of the road is suitable for traffic in bad weather or other times of poor visibility, as well as determine the distance on both sides of the vehicle when + +Price is $",100 +"How much does this cost to the nearest dollar? + +Caseology Bumpy Compatible with Google Pixel Buds Pro Case (2022) - Sage Green +Hybrid layer clear case with ultra-clear PC body and TPU frame for drop-proof shock absorbance Slim yet durable Pixel Buds Pro case made with military grade materials Side colored TPU with rugged sandstone texture provides non-slip grip Wireless charging compatible and carabiner included for easy carrying Caseology Bumpy Compatible with Google Pixel Buds Pro Case (2022) / Not Compatible with Google Pixel Buds A series, Google Pixel Buds 2 Dimensions 2.67 x 2.54 x 1.15 inches, Weight 1.76 ounces, model number Rank Cell Phones & Accessories 34945, Cell Phone Basic Cases 14563, Connectivity technologies wireless, Special features + +Price is $",20 +"How much does this cost to the nearest dollar? + +Fleck 2510 Timer Mechanical Filter Control Head +- Mechanical 2510 control head for filter systems - - 12-day timer initiated backwash - - Maximum 17 GPM backwash (includes 7 GPM DLFC) - - Standard 2. 5 -8 NPSM mounting base - - Requires yoke or bypass to connect to plumbing -Heavy duty 2510 electromechanical control valve provides simple and durable backwash control for most common backwashing filters. A maximum of 17 GPM available backwash can handle even dense iron filter medias. Dedicated piston motor provides powerful piston movement that reduces system maintenance. New Fleck 2510 filter valve replacement for filter tanks Fully adjustable cycles for backwash and rinse times For back-washing filters, allows for strong + +Price is $",80 +"How much does this cost to the nearest dollar? + +Haloview MC7108 Wireless RV Backup Camera System 7'' Monitor Built in DVR Rear View Camera with Infrared Night Vision and Wide Viewing Angle for Truck/Trailer/RV/Pickups/Camping Car/Van/Farm +7 LCD digital monitor, Built-in recorder. Real time recording, video playback 10-32V wide voltage input, Support 4 wireless camera wide viewing angle, Wireless Line of Sight Range Up to 984 feet (This kit include 1 monitor+ 1 camera) Split mode, auto-scan mode and single-display mode available, Normal, mirror, FLIP, MIRROR-FLIP viewing options available HD 720P Digital Wireless Backup camera system, it has far better image resolution, stronger lens and longer transmission distance, which will bring you a + +Price is $",250 +"How much does this cost to the nearest dollar? + +Schmidt Spiele - Manhattan +The product of this place is a board game of Hans im Gluck's / Andreas Seyfarth work. It is with a Japanese manual in Japan version package of Mobius Games Inc.. Number of players 2-4 people Target age 10 years old or older Playing Time 60 minutes one point sales easy-to-understand rules, fun easy-to-understand, easy-to-understand strategy, the progress of the game can be seen in the eyes. It is a game that can be recommended to anyone. 2-4 people for Age 10 years old - adult Travel Time 60 minutes From Germany With a Japanese manual Dimensions 11.81 x 5.91 x 3.94 inches, Weight 10.6 ounces, model number + +Price is $",30 +"How much does this cost to the nearest dollar? + +Corsa 14333 Tip Kit (Ford Mustang GT) +CORSA Performance Pro-Series tips are dual-walled stainless steel. The dual-wall is designed to protect against heat distortion and maintain visual appeal. Each tip is adorned with high-definition, precision laser engraving that provides unmatched detail. CORSA Performance tip kits are designed to fit directly to CORSA exhaust systems. Mustang GT 5.0L Fits Premium Package ONLY Requires Roush Quad Tip Rear Valance Modification Dual walled design protects against heat distortion CORSA Performance tip kits are designed to fit directly to CORSA exhaust systems Premium Stainless Steel Construction Manufacturer Corsa Performance, Brand Corsa, Weight 7 pounds, Dimensions 23 x 11 x 7 inches, model number 14333, Is Discontinued No, Manufacturer Part + +Price is $",80 +"How much does this cost to the nearest dollar? + +Hoshizaki FM116A Fan Motor Kit 1 +Product Description Hoshizaki FM116A Fan Motor Kit 1 is a genuine OEM (original equipment manufacturer) replacement part. Hoshizaki is committed to developing original products that bring comfort and convenience to your life. Approved by original equipment manufacturer (OEM) and intended only for designed and specified use. From the Manufacturer FAN MOTOR KIT 1. Hoshizaki Genuine OEM replacement part. Hoshizaki is committed to developing original products that bring comfort and convenience to your life. Use genuine OEM parts for safety reliability and performance. Genuine OEM replacement part Hoshizaki is committed to developing original products that bring comfort and convenience to your life Genuine OEM provides safety, reliability, and optimal performance Approved by original + +Price is $",80 +"How much does this cost to the nearest dollar? + +BAINUO Antler Chandelier Light Antler Deer Chandelier for Living Room Dining Room Balcony Bedroom Cafe Bar Cabin Hanging Light Fixtures +Specification Product Type Vintage Style Resin Deer Faux Antler Chandelier Style vintage/farmhouse/rustic/transitional/art deco Bulb Base 6* Not Included) Bulbs Category LED/INCANDESCENT/HALOGEN Product Rating Voltage 110V Maximum Wattage 40W for single lamp Weight 16.5LB Dimension Diameter 34.4 inches, Height 17.7 inches. Material Resin Color Brown Features antler chandelier also works on sloped, slanted or vaulted ceiling; 2.Deer horn 6 light pendant light wide application - The indoor dining table chandelier is perfectly used + +Price is $",280 +"How much does this cost to the nearest dollar? + +DNA MOTORING Smoke Lens Amber Headlights Replacement For 06-10 Explorer +A headlight (headlamp) is a lamp attached to the front of a vehicle to light the road ahead. Headlight performance has steadily improved throughout the automobile age, spurred by the great disparity between daytime and nighttime traffic fatalities. Headlights are one of the most important components of your vehicle; they allow you to see the road in front of you clearly during the night and in any bad weather that may arise. Our headlights upgrade the face of your vehicle with clear style and extreme range. Compatible with 06-10 Ford explorer. Plug-n-Play Operation, Direct Bolt-On OE Fitment or Replacement for the Stock Unit Uses H13 High Beam & Low Beam / Bulbs are NOT Included Brings a Different Appearance + +Price is $",100 +"How much does this cost to the nearest dollar? + +Wera Stainless 3840/1 TS 2.5mm Hex Insert Bit, Drive +Wera 3840/1 TS 2.5mm hex insert bit for 1/4 hex drive is designed to keep rust at bay. Wera’s Stainless tool line is manufactured from 100% Stainless steel, preventing extraneous rust caused by use of conventional tools contaminating stainless fasteners. Wera’s unique vacuum ice-hardened process gives the necessary hardness for industrial applications. Torsion (TZ) bits are designed to prevent premature wear for improved service life. Hex-Plus technology prevents rounding of screw recess and transfers up to 20% more torque. Stainless bits partnered with Wera’s stainless Rapidaptor will protect the full length of the bit against extraneous rust. Ice + +Price is $",30 +"How much does this cost to the nearest dollar? + +Celestron - PowerSeeker 127EQ Telescope - Manual German Equatorial Telescope for Beginners - Compact and Portable - Bonus Astronomy Software Package - 127mm Aperture & 1.25 Moon Filter +Celestron 1.25 Moon FilterThe Moon has the distinction of being the most often viewed celestial object through backyard telescopes. It is undoubtedly beautiful and mysterious, and is one of those constants in our lives that connects us to every other being on our planet. Regardless of who we are or where we live or travel, we all look at the same moon. It is difficult to look at the Moon through a telescope and see all of the details due to its brightness. Our eyes are not ready for the bright beam of light that emits from the eyepiece, and they “ + +Price is $",100 +"How much does this cost to the nearest dollar? + +NHOPEEW Android Car Radio Carplay for Jeep Wrangler 2015 2016 2017 Touchscreen Bluetooth Car Stereo with AHD Backup Camera/Mic/HiFi +Compatible with jeep wrangler 2015 2016 2017 Android 11 System The Android head unit fit for jeep wrangler 2015 2016 2017, it is plug&play, easy to install. Android 11 operating system, 2GB RAM & 32GB ROM, ensures smooth operation and faster response. Android Auto & Apple Carplay Support wireless and wired connect your phone to the carplay jeep wrangler radio, with Siri voice control allows you make calls, send and receive messages, enjoy music and Navigating. Large Screen with Hi-Fi The jeep wrangler + +Price is $",199 +"How much does this cost to the nearest dollar? + +Other Harmonica A) +For the sound of yesterday from the technology of today, The new Suzuki 2 timers are sure to bring back memories. 2 timers have a traditional sound quality made possible by a dual hole octave/tremolo tuning action, Excellent for folk and country style playing. Laser tuned reeds are extra lightweight to give that special harmonica octave effect. Available in 21 and 24 note Models, Includes a soft lined hard Shell Case. Available in the keys of C & a. Excellent for folk and country style playing Package Dimensions 3.302 H x 18.541 L x 5.588 W (centimetres) Package Weight 0.349 pounds Country of Origin Japan Weight 4 Ounces, Dimensions 6 x 3 x 1 inches + +Price is $",40 +"How much does this cost to the nearest dollar? + +Harley Air Filter Venturi Intake Air Cleaner Motorcycle Cnc Cut Chrome Kit for Touring Street Glide 2008 - 2016 Softail 2016 - 2017 Fitment - C (Gray) +Package x Air Cleaner Intake Filter with Accessories Fitment for Harley Touring Street Glide 2008 - 2016, Touring Road Glide 2008 - 2016, Softail 2016 - 2017, Dyna FXDLS 2017, FLSTNSE 2014 - 2015, FLSTSE 2011 - 2012, FXSBSE 2013 - 2014 NOTE Before purchase, please check electric or non-electric throttle on your Touring models. If Electric - use fitment C. If non + +Price is $",100 +"How much does this cost to the nearest dollar? + +Elite Screens Edge Free Ambient Light Rejecting Fixed Frame Projection Projector Screen,Aeon CineGrey 3D Series, 16 9 for Home Theater, Movie and Office Presentations +DIMENSION SIZE Diagonal, 16 9 Aspect Ratio. View Size 66.2 H x 117.6 W. Overall Size 66.7 H x 118.1 W x 1. 3 D. SCREEN MATERIAL Ceiling Ambient Light Rejecting Material (CLR/ALR) CineGrey 3D with 65% rejection ratio and Features a 90° Viewing Angle with 1.2 Gain. It is best for family rooms, educational facilities, conference rooms or any applications in which incident light is a factor. Fixed Frame Projector Screen is compatible with Standard Throw + +Price is $",250 \ No newline at end of file diff --git a/week6/community-contributions/lisekarimi/helpers/__init__.py b/week6/community-contributions/lisekarimi/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/week6/community-contributions/lisekarimi/helpers/items.py b/week6/community-contributions/lisekarimi/helpers/items.py new file mode 100644 index 0000000..a594e27 --- /dev/null +++ b/week6/community-contributions/lisekarimi/helpers/items.py @@ -0,0 +1,120 @@ +from typing import Optional # A variable might be a certain type or None +from transformers import AutoTokenizer +import re + +BASE_MODEL = "meta-llama/Meta-Llama-3.1-8B" + +MIN_TOKENS = 150 # Minimum tokens required to accept an item +MAX_TOKENS = 160 # We limit to 160 tokens so that after adding prompt text, the total stays around 180 tokens. + +MIN_CHARS = 300 # Reject items with less than 300 characters +CEILING_CHARS = MAX_TOKENS * 7 # Truncate long text to about 1120 characters (approx 160 tokens) + +class Item: + """ + An Item is a cleaned, curated datapoint of a Product with a Price + """ + + # Load tokenizer for the model + tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True) + + # Define PRICE_LABEL and question for the training prompt + PRICE_LABEL = "Price is $" + QUESTION = "How much does this cost to the nearest dollar?" + + # A list of useless phrases to remove to reduce noise for price prediction + REMOVALS = ['"Batteries Included?": "No"', '"Batteries Included?": "Yes"', '"Batteries Required?": "No"', '"Batteries Required?": "Yes"', "By Manufacturer", "Item", "Date First", "Package", ":", "Number of", "Best Sellers", "Number", "Product "] + + # Attributes for each item + title: str + price: float + category: str + token_count: int = 0 # How many tokens in the final prompt + + # Optional fields + details: Optional[str] # The value can be a string or can be None + prompt: Optional[str] = None + include = False # Whether to keep the item or not + + def __init__(self, data, price): + self.title = data['title'] + self.price = price + self.parse(data) + + def scrub_details(self): + """ + Removes useless phrases from details, which often has repeated specs or boilerplate text. + """ + details = self.details + for remove in self.REMOVALS: + details = details.replace(remove, "") + return details + + def scrub(self, stuff): + """ + Clean up the provided text by removing unnecessary characters and whitespace + Also remove words that are 7+ chars and contain numbers, as these are likely irrelevant product numbers + """ + stuff = re.sub(r'[:\[\]"{}【】\s]+', ' ', stuff).strip() + stuff = stuff.replace(" ,", ",").replace(",,,",",").replace(",,",",") + words = stuff.split(' ') + select = [word for word in words if len(word)<7 or not any(char.isdigit() for char in word)] + return " ".join(select) + + def parse(self, data): + """ + Prepares the text, checks length, tokenizes it, and sets include = True if it’s valid. + """ + # Builds a full contents string by combining description, features, and cleaned details. + contents = '\n'.join(data['description']) + if contents: + contents += '\n' + features = '\n'.join(data['features']) + if features: + contents += features + '\n' + self.details = data['details'] + if self.details: + contents += self.scrub_details() + '\n' + + # If content is long enough, trim it to max char limit before processing. + if len(contents) > MIN_CHARS: + contents = contents[:CEILING_CHARS] + + # Clean and tokenize text, then check token count. + text = f"{self.scrub(self.title)}\n{self.scrub(contents)}" + tokens = self.tokenizer.encode(text, add_special_tokens=False) + + if len(tokens) > MIN_TOKENS: + # Truncate tokens, decode them back and create the training prompt + tokens = tokens[:MAX_TOKENS] + text = self.tokenizer.decode(tokens) + self.make_prompt(text) + + # Mark the item as valid and ready to be used in training + self.include = True # Only items with MIN_TOKENS <= tokens <= MAX_TOKENS are kept + + + def make_prompt(self, text): + """ + Builds the training prompt using the question, text, and price. Then counts the tokens. + """ + self.prompt = f"{self.QUESTION}\n\n{text}\n\n" + self.prompt += f"{self.PRICE_LABEL }{str(round(self.price))}.00" + self.token_count = len(self.tokenizer.encode(self.prompt, add_special_tokens=False)) + + def test_prompt(self): + """ + Returns the prompt without the actual price, useful for testing/inference. + """ + return self.prompt.split(self.PRICE_LABEL )[0] + self.PRICE_LABEL + + def __repr__(self): + """ + Defines how the Item object looks when printed — it shows the title and price. + """ + return f"<{self.title} = ${self.price}>" + + + + + \ No newline at end of file diff --git a/week6/community-contributions/lisekarimi/helpers/loaders.py b/week6/community-contributions/lisekarimi/helpers/loaders.py new file mode 100644 index 0000000..4314c65 --- /dev/null +++ b/week6/community-contributions/lisekarimi/helpers/loaders.py @@ -0,0 +1,106 @@ +from datetime import datetime # Measure how long loading takes +from tqdm import tqdm # Shows a progress bar while processing data +from datasets import load_dataset # Load a dataset from Hugging Face Hub +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor # For parallel processing (speed) +from items import Item + +CHUNK_SIZE = 1000 # Process the dataset in chunks of 1000 datapoints at a time (for efficiency) +MIN_PRICE = 0.5 +MAX_PRICE = 999.49 +WORKER = 4 # Set the number of workers here + +class ItemLoader: + + def __init__(self, name): + """ + Initialize the loader with a dataset name. + """ + self.name = name # Store the category name + self.dataset = None #Placeholder for the dataset (we load it later in load()) + + def process_chunk(self, chunk): + """ + Convert a chunk of datapoints into valid Item objects. + """ + batch = [] # Initialize the list to hold valid items + + # Loop through each datapoint in the chunk + for datapoint in chunk: + try: + # Extract price from datapoint + price_str = datapoint['price'] + if price_str: + price = float(price_str) + + # Check if price is within valid range + if MIN_PRICE <= price <= MAX_PRICE: + item = Item(datapoint, price) + + # Keep only valid items + if item.include: + batch.append(item) + except ValueError: + continue # Skip datapoints with invalid price format + return batch # Return the list of valid items + + + def load_in_parallel(self, workers): + """ + Split the dataset into chunks and process them in parallel. + """ + results = [] + size = len(self.dataset) + chunk_count = (size // CHUNK_SIZE) + 1 + + # Build chunks directly here (no separate function) + chunks = [ + self.dataset.select(range(i, min(i + CHUNK_SIZE, size))) + for i in range(0, size, CHUNK_SIZE) + ] + + # Process chunks in parallel using multiple CPU cores + with ProcessPoolExecutor(max_workers=workers) as pool: + for batch in tqdm(pool.map(self.process_chunk, chunks), total=chunk_count): + results.extend(batch) + + # Add the category name to each result + for result in results: + result.category = self.name + + return results + + + def load(self, workers=WORKER): + """ + Load and process the dataset, returning valid items. + """ + # Record start time + start = datetime.now() + + # Print loading message + print(f"Loading dataset {self.name}", flush=True) + + # Load dataset from Hugging Face (based on category name) + self.dataset = load_dataset( + "McAuley-Lab/Amazon-Reviews-2023", + f"raw_meta_{self.name}", + split="full", + trust_remote_code=True + ) + + # Process the dataset in parallel and collect valid items + results = self.load_in_parallel(workers) + + # Record end time and print summary + finish = datetime.now() + print( + f"Completed {self.name} with {len(results):,} datapoints in {(finish-start).total_seconds()/60:.1f} mins", + flush=True + ) + + # Return the list of valid items + return results + + + + \ No newline at end of file diff --git a/week6/community-contributions/lisekarimi/helpers/testing.py b/week6/community-contributions/lisekarimi/helpers/testing.py new file mode 100644 index 0000000..9422182 --- /dev/null +++ b/week6/community-contributions/lisekarimi/helpers/testing.py @@ -0,0 +1,84 @@ +import math +import matplotlib.pyplot as plt + +GREEN = "\033[92m" +YELLOW = "\033[93m" +RED = "\033[91m" +RESET = "\033[0m" +COLOR_MAP = {"red":RED, "orange": YELLOW, "green": GREEN} + +class Tester: + + def __init__(self, predictor, data, title=None, size=250): + self.predictor = predictor + self.data = data + self.title = title or predictor.__name__.replace("_", " ").title() + self.size = size + self.guesses = [] + self.truths = [] + self.errors = [] + self.sles = [] + self.colors = [] + + def color_for(self, error, truth): + if error<40 or error/truth < 0.2: + return "green" + elif error<80 or error/truth < 0.4: + return "orange" + else: + return "red" + + def run_datapoint(self, i): + datapoint = self.data[i] + guess = self.predictor(datapoint) + truth = datapoint["price"] + error = abs(guess - truth) + log_error = math.log(truth+1) - math.log(guess+1) + sle = log_error ** 2 + color = self.color_for(error, truth) + title = datapoint["text"][:40] + "..." if len(datapoint["text"]) > 40 else datapoint["text"] + self.guesses.append(guess) + self.truths.append(truth) + self.errors.append(error) + self.sles.append(sle) + self.colors.append(color) + # print(f"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}") + + def chart(self, title): + max_error = max(self.errors) + plt.figure(figsize=(15, 6)) + max_val = max(max(self.truths), max(self.guesses)) + plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6) + plt.scatter(self.truths, self.guesses, s=3, c=self.colors) + plt.xlabel('Ground Truth') + plt.ylabel('Model Estimate') + plt.xlim(0, max_val) + plt.ylim(0, max_val) + plt.title(title) + + # Add color legend + from matplotlib.lines import Line2D + legend_elements = [ + Line2D([0], [0], marker='o', color='w', label='Accurate (green)', markerfacecolor='green', markersize=8), + Line2D([0], [0], marker='o', color='w', label='Medium error (orange)', markerfacecolor='orange', markersize=8), + Line2D([0], [0], marker='o', color='w', label='High error (red)', markerfacecolor='red', markersize=8) + ] + plt.legend(handles=legend_elements, loc='upper left') + plt.show() + + def report(self): + average_error = sum(self.errors) / self.size + rmsle = math.sqrt(sum(self.sles) / self.size) + hits = sum(1 for color in self.colors if color=="green") + title = f"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%" + self.chart(title) + + def run(self): + self.error = 0 + for i in range(self.size): + self.run_datapoint(i) + self.report() + + @classmethod + def test(cls, function, data): + cls(function, data).run() \ No newline at end of file diff --git a/week7/community_contributions/lisekarimi/09_part5_llama31_8b_quant.ipynb b/week7/community_contributions/lisekarimi/09_part5_llama31_8b_quant.ipynb new file mode 100644 index 0000000..6a10dd6 --- /dev/null +++ b/week7/community_contributions/lisekarimi/09_part5_llama31_8b_quant.ipynb @@ -0,0 +1,612 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "4WDyBU0Vm0Zl" + }, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 5)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- ➡️ Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA\n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# 🦙 Part 5: Evaluating LLaMA 3.1 8B Quantized\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ⚠️ GPU required - use Google Colab\n", + "- 🛠️ Requirements: 🔑 HF Token\n", + "- Tasks:\n", + " - Quantize LLaMA 3.1 8B to 4-bit\n", + " - Define prediction function\n", + " - Evaluate with Tester\n", + "\n", + "We know LLaMA 3.1 won’t beat frontier models — but how far behind is it without any tuning?\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MDyR63OTNUJ6", + "outputId": "7e9e5b6b-d11c-45df-d774-2da5f6455d51" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q datasets torch transformers bitsandbytes accelerate matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-yikV8pRBer9" + }, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import re\n", + "import math\n", + "import torch\n", + "from huggingface_hub import login\n", + "from datasets import load_dataset\n", + "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, set_seed\n", + "from google.colab import userdata\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uuTX-xonNeOK" + }, + "outputs": [], + "source": [ + "# Google Colab User Data\n", + "# Ensure you have set the following in your Google Colab environment:\n", + "hf_token = userdata.get('HF_TOKEN')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Constants\n", + "\n", + "BASE_MODEL = \"meta-llama/Meta-Llama-3.1-8B\"\n", + "HF_USER = \"lisekarimi\"\n", + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DTMo_1msQb9X" + }, + "source": [ + "## 📥 Load Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 177, + "referenced_widgets": [ + "048d1b454cdc400ea5979230703770b8", + "7dd26897141a4d87bc3893bb1b1bafb3", + "c4f6e0b6237c46b98d393d27b35cabe7", + "dd525aced49e4ebe8395514601c20b20", + "69a35e3916ae488296a70687b5e890de", + "e3442871bdb5445ba86e5aa0f0ee8de9", + "8981816dd709488e9ace85e6b160892d", + "6edd1bd723324c128fec4de5f1758330", + "f77a98060e9d48dc8ac4919902ffc88d", + "ed6dfe86de2e4957b4e24df3f564c5db", + "e253ec71b5104dd291455753a160c7f1", + "b802074124bc4d7d979c28ba9e84a432", + "76abd56919414e2b8b2b4683d4cb2bd5", + "2bb62653ed2d4e86b9eb0476a0333a3a", + "58a799a559ff4f2681b586650c35b12e", + "878d6cea9b2c40d3b3b58b1c1bff902f", + "d00a41c676034c38881da90ae961e936", + "da539e354ea540509a2ea7d13dc8dc45", + "4f27fc91cbb14aa08d08b848c6689937", + "abea7cdfa8624614aca8d8ab3c07a671", + "b5ed6e3c852c49c1b904a19e05f5a90b", + "ac7225138dfa48b086b30f154f9a1111", + "70da4d47bd4c4b57a7f65d82d7a01829", + "19f8ee6f626845beaa7154efe4802045", + "13556136763b49bda041c92445ee2ad4", + "a2f5735e3c314155be432484fcf72fe7", + "81c15499cc8e4011b9bd392f660a3b6e", + "96b6a830727d48539c181343efada938", + "0ead4e0b3435492693636130d2782c25", + "50a8e3f2c06c4595931788b18f5152e9", + "cebc935dafae4d4eba105d3107c46ddc", + "f566351d5c504181b00a53c3c654090f", + "4238f42b624142fea3746fb2f03bcc2d", + "be8416b487d04d769fd93973b7fe916a", + "1bbada4a48444e60a360aba596af77b3", + "75436fb8e4eb43e4b0a309871e4d3cc1", + "e4ae815e69d3448296e4c3bcb713710e", + "72ca180ed6604f148f2f2e61ac97259a", + "c0b34963c7a446908fadfb38c958b612", + "38fa12125f024935852122d434c2cbf6", + "ff564729da354497b606bfb809ac4e33", + "9ee352287f8b4e27af617e3427cb3012", + "15522242cf72440ca8895496ad5144c4", + "e7dc05ebb11a4b30b4806c2628ec6bde", + "413fafe61f7c415a9c1c90dea56aa301", + "ac2522256e73492d9b5d0e7976d92ff5", + "53266635573042b4b94496f38915e6d4", + "8da5f5529fef4f1bb884793e503e5fc5", + "80b7529e0ad541749bf464a1d8927225", + "2203154b7c464105b12f1ef8caf410cd", + "87b8c46fa98a4940ab90422ab44d33de", + "6dee11eaa4a849bbb58488a233d3719e", + "be947f2a2b8a484daa61f45ae06c5232", + "0b1de2365ad1497ab2ebfec1be33a720", + "326453121cd84c1e95b3b5da0166c931" + ] + }, + "id": "5PVXACKHQhh4", + "outputId": "80dc4772-ea31-4752-8f97-573efaa43917" + }, + "outputs": [], + "source": [ + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pGJR24lbQlRS", + "outputId": "a1bb5e66-1aa9-40b7-c361-562eafae5d8c" + }, + "outputs": [], + "source": [ + "test[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vrxH6h00P9qc" + }, + "source": [ + "## 🦙 Load Tokenizer and Quantized LLaMA Model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 418, + "referenced_widgets": [ + "8698049df4ce440d8a16bc34d69231e7", + "b0f74f9ed33649ebb16952d0fb0aecab", + "00241684d4f64383b032a1362d174d55", + "b74ea8552d8145d28f43cf7ad8450d0b", + "6838953f363945d79e079c12aeb2232b", + "57c4a682571e401f9fec996603fa587d", + "e2b93774cb4a4648a4210c7693864ccc", + "766c8e2406ce407faf3489229dada75a", + "a52ea6c6672b4ab2bae4f669dc45deb6", + "381094cbfef64531a58df85e6d453847", + "a6a14894a06a4d4b839f3b791cfadd34", + "b43b118cae174c3c810f08c2249b80dc", + "6502e59cbd344bf6be966923bb3e38fa", + "f86fcf5f6bf24ce399c5d64dc83c3690", + "46598b397fbc4461bb83ad45000e5569", + "dd307f2b56824c6c91b8fe1c028a1704", + "b87577323cb44a2f9f3cc0a8219eadf4", + "0ed52815268a4d90a224029e9e23e09f", + "fafd3011a3cb4e0099a0db77caf843aa", + "89bb151875e349118677c9677bec4137", + "b8722d98e81d4e3494c9c0b8b01319d4", + "b8f661dd658e45a49b5bac2bdf7f3b78", + "f031fadfbba14031a944c351fd99b032", + "a6bf09a98289481abb0c9882702eb575", + "09d54c271e55463495cb9b617d2ec41d", + "32bdcc7f7efd47679258f398184dd0ab", + "0f090959768e40aa8fabfacdf772d8df", + "e40a9c85694c446d84d3493274138178", + "ceb1bbb613f0438aa6996d5551f713f3", + "59b59d4040e04b65a66f578160d13d43", + "079ab8a1fae64a0782ea8035f494f2fd", + "1e425099c1044c14986386e5a4ce0b48", + "1e3e028ec53448c691abb2cfad4ffd8c", + "d2142e9de5ea4dd2b8d00b56354352c3", + "cf1d7a58189b4a5bbe6d005de998548c", + "5b6e10b9e5a146be85e519c1bc476fcd", + "6d9feded70b84654ab79f9d13b065c83", + "ec5afa847d364fbc974b35d821ccd931", + "fa392b34ae8647668e94aca22c1a5edb", + "4d315c92d7c84191a165218d403c0f8d", + "c4279579368841b99a46f529c55125e9", + "572bb151402e4940a8d7c92156f9711b", + "d4536337378b4146b054371b18f83fdc", + "14ddae4a15d74c80b1712443853e3f96", + "46e827e5d7a94a619536ff08127b6172", + "ad7977cc642e4cae890e52d03d753788", + "73ba16b54d314d94aaeebea2ba291a94", + "1bc2120a87ab4ad99798b1706342bd89", + "4c4772ace8c246b9a5c8f870ed27c11b", + "d179e366c02f4bb2897cc9f531955e5e", + "1134fd00384740d0a39b6de241ca17cd", + "5a120718aa934959bd50cf4864b137b4", + "46917a8997f942fea0aaf00a95459f93", + "6076b184b66c4d50a91bc477c8eea53e", + "2538bc7fc4594363934266f25bcd52bc", + "f6144dfa2a20416b9e5c28615a5ff129", + "35941d364234488da6fcc0997a5cccf7", + "8c5e160cc4434ca99f694f5e195a2005", + "fa82a4c6e8fc4591aa5652d7d95c6e40", + "2a82034aebcb4e3fbaff825ca59817d0", + "edcabc56841a4ba68ee53385fe2dc0f6", + "e8bf66aa640e433d8d890ae541b21dcd", + "eb7b76b25ce44dc1b8eba7cac8bc9671", + "c9648aceda71470284f6ed7ce2add462", + "7df6ddb46ae3419fbc3fac488eb8a6b6", + "3b2aa7ca49e4451fbfc65560a2d3d43d", + "6af2831aa4e641568d72df6d13fc074a", + "732cb67ef916489298655df845773934", + "cc96573e39e148dbac8b0bd299f0f0b0", + "4e9cbcdc1cfb495a850be45cf752d3c4", + "b811921bdbe84b0dbd9add0f69271ef0", + "a1053fdea18348119949b326f3a12651", + "90c10be928c54821aacf11705c0513ff", + "a543366ec93c486bb2d28d1ff9567197", + "97ff48d2660444a1a7503e735e2b2a55", + "1fd84a85c98246adb2e18e41c8a9d88f", + "fed4a63b10ea4788af8cd181d8d24863", + "8bd5f65dda734db1a253897f85428d4c", + "2744cec152a44fd483f5cdd8f4de8c70", + "47780d4dab77454ab898f6707d8d4168", + "6653b71e07bc488ebbb4ed5728564ccd", + "59d44fcd08114cb4aaeea768b1438bcf", + "18cf08eb051d48c9a5c0b6b827507b7f", + "fee935f9fb354a67a37d42641ff0d81e", + "22ec450031234856a304ccee34d452f4", + "4944567015cc46be83a8524c0542722a", + "b80d78f92da64255991b4fcfde98b1d4", + "e239b0fe8301409f9dd7e5e801949ec2", + "6e7533e6b43c4f1dbb1e0421b99fdc47", + "4be15c8712e340b3b9d9a3bd1c7c7516", + "337d98c0886948929a48411422a81ff8", + "83d8d49cf93c4af7bb3e3cfa3234c6c6", + "a1fb4ca7292e4cdc85b522248fdddaf6", + "ce26e74cc006450ca4e44bee2d14d80c", + "c01c7b35b1914ae681550421c0035a8c", + "c7966f356f80422abb3dcb45dbc541db", + "a86bb39581e1430a8314a616951af75e", + "446c7ef56bcc437388d4a99859c1b9fb", + "5c16ffe6a5504f2585aa6bc3132ff2ee", + "9d466ef4939c43f2846f22a5a21e5cd0", + "bec4a9e185074743848c04c4aff12037", + "cff028485bae4d96b4f7a48b738f6b61", + "c02af33357e64469aeb01a7af5a9ab37", + "fd0ff0c9933d4238a373c286f8e1dd5d", + "c517e6db93f04398b9a3ccc86e090499", + "e75b68d16bc443e39974922342952de9", + "0536d41437f54df38624a7d290e45325", + "eec3717367b348a388bb76eb6482ce25", + "e16f1ef5ee06493fac2d5871806a3b3a", + "24f7575f0f47498480b2a2f79f0d4ce5", + "c17fe53a4a2b4266a3cbd24c9f145cde", + "b4d715f23ada4ee48fdfd9af463f7124", + "7d9102b6a7b44e14809ecf8fa421ee70", + "8d640aa311f34b33b0967e128c138130", + "3680065e53494bad98e74fd7c81185dd", + "11fb0bacbcc44352b3b25d9f0923c332", + "7319ccdb3e3349328d6f9b4bb5445776", + "35017cc6cb484eeaa12714532e872f99", + "ae22d146f6f24981bde97896ad3d8b14", + "3feeca46c382431c9868e4852ca04d49", + "0e3b239635704ab391f1801b762b7f93", + "90d35d2eda00413eba027093309f6c31", + "d61446d3664a455baaada9761a1715be", + "92b7d7f81ebc441d8e6d6e20477aa37c", + "8b5b230489104f6bba63720fa9fad0ae", + "0afc992c54ec4a10a7f9fd3e45fa7761", + "4fbbb9ba6f4e44d6b2ccc5197dad5488", + "18e5f93ef3b64301b7c1548d17843d64", + "ee997f8eeccc4dd98aea71b930531cf5", + "e11a6cfa4615457090d4c87815fdb716", + "4d74f0ec93f54e09a22c3cb93a042570", + "31cdf14402f34270bdc1b1efd2a0d011" + ] + }, + "id": "TAit9IzsQLcc", + "outputId": "176a77ad-0245-4a3d-b9f3-e139de359da7" + }, + "outputs": [], + "source": [ + "quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + ")\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)\n", + "tokenizer.pad_token = tokenizer.eos_token\n", + "tokenizer.padding_side = \"right\"\n", + "\n", + "base_model = AutoModelForCausalLM.from_pretrained(\n", + " BASE_MODEL,\n", + " quantization_config=quant_config,\n", + " device_map=\"auto\",\n", + ")\n", + "base_model.generation_config.pad_token_id = tokenizer.pad_token_id\n", + "\n", + "print(f\"Memory footprint: {base_model.get_memory_footprint() / 1e9:.1f} GB\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 🤖 Prediction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1FfMJ2JbzEr3" + }, + "outputs": [], + "source": [ + "def extract_price(s):\n", + " if \"Price is $\" in s:\n", + " contents = s.split(\"Price is $\")[1]\n", + " contents = contents.replace(',','').replace('$','')\n", + " match = re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", contents)\n", + " return float(match.group()) if match else 0\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CgN8eRttRAZx" + }, + "outputs": [], + "source": [ + "def model_predict(prompt):\n", + " set_seed(42)\n", + " inputs = tokenizer.encode(prompt, return_tensors=\"pt\").to(\"cuda\")\n", + " attention_mask = torch.ones(inputs.shape, device=\"cuda\")\n", + " outputs = base_model.generate(inputs, max_new_tokens=4, attention_mask=attention_mask, num_return_sequences=1)\n", + " response = tokenizer.decode(outputs[0])\n", + " return extract_price(response)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hpdEk2-FW6aT", + "outputId": "f8913c56-1a8f-4a13-9084-21acfdb64ceb" + }, + "outputs": [], + "source": [ + "model_predict(test[0]['text']), test[0]['price']" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "auFzPUJKTLln" + }, + "source": [ + "## 🧪 Run Evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jnoI1EWGTUau" + }, + "outputs": [], + "source": [ + "# Helper class for evaluating model predictions\n", + "\n", + "GREEN = \"\\033[92m\"\n", + "YELLOW = \"\\033[93m\"\n", + "RED = \"\\033[91m\"\n", + "RESET = \"\\033[0m\"\n", + "COLOR_MAP = {\"red\":RED, \"orange\": YELLOW, \"green\": GREEN}\n", + "\n", + "class Tester:\n", + "\n", + " def __init__(self, predictor, data, title=None, size=100):\n", + " self.predictor = predictor\n", + " self.data = data\n", + " self.title = title or predictor.__name__.replace(\"_\", \" \").title()\n", + " self.size = size\n", + " self.guesses = []\n", + " self.truths = []\n", + " self.errors = []\n", + " self.sles = []\n", + " self.colors = []\n", + "\n", + " def color_for(self, error, truth):\n", + " if error<40 or error/truth < 0.2:\n", + " return \"green\"\n", + " elif error<80 or error/truth < 0.4:\n", + " return \"orange\"\n", + " else:\n", + " return \"red\"\n", + "\n", + " def run_datapoint(self, i):\n", + " datapoint = self.data[i]\n", + " guess = self.predictor(datapoint[\"text\"])\n", + " truth = datapoint[\"price\"]\n", + " error = abs(guess - truth)\n", + " log_error = math.log(truth+1) - math.log(guess+1)\n", + " sle = log_error ** 2\n", + " color = self.color_for(error, truth)\n", + " # title = datapoint[\"text\"].split(\"\\n\\n\")[1][:20] + \"...\"\n", + " self.guesses.append(guess)\n", + " self.truths.append(truth)\n", + " self.errors.append(error)\n", + " self.sles.append(sle)\n", + " self.colors.append(color)\n", + " # print(f\"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}\")\n", + "\n", + " def chart(self, title):\n", + " # max_error = max(self.errors)\n", + " plt.figure(figsize=(12, 8))\n", + " max_val = max(max(self.truths), max(self.guesses))\n", + " plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6)\n", + " plt.scatter(self.truths, self.guesses, s=3, c=self.colors)\n", + " plt.xlabel('Ground Truth')\n", + " plt.ylabel('Model Estimate')\n", + " plt.xlim(0, max_val)\n", + " plt.ylim(0, max_val)\n", + " plt.title(title)\n", + "\n", + " # Add color legend\n", + " from matplotlib.lines import Line2D\n", + " legend_elements = [\n", + " Line2D([0], [0], marker='o', color='w', label='Accurate (green)', markerfacecolor='green', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='Medium error (orange)', markerfacecolor='orange', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='High error (red)', markerfacecolor='red', markersize=8)\n", + " ]\n", + " plt.legend(handles=legend_elements, loc='upper right')\n", + "\n", + " plt.show()\n", + "\n", + "\n", + " def report(self):\n", + " average_error = sum(self.errors) / self.size\n", + " rmsle = math.sqrt(sum(self.sles) / self.size)\n", + " hits = sum(1 for color in self.colors if color==\"green\")\n", + " title = f\"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%\"\n", + " self.chart(title)\n", + "\n", + " def run(self):\n", + " self.error = 0\n", + " for i in range(self.size):\n", + " self.run_datapoint(i)\n", + " self.report()\n", + "\n", + " @classmethod\n", + " def test(cls, function, data):\n", + " cls(function, data).run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 692 + }, + "id": "1wA5uVgpTWLC", + "outputId": "5a597437-50c8-419c-c1da-af0166dabe0f" + }, + "outputs": [], + "source": [ + "Tester.test(model_predict, test)" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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556qlRkiEkVx3bp1ffv2vfztFbu3fHH067QnOjw1YfrMvgMH33fffW+99Zbb7U5NTe3Tp8+9997729/+Njw8/Nq1a1JSslqty5Yte+KJJ371q1+Fh4dPnDjRlzGIKDMzs1evXgkJCT4l5f+AjFFXHzU1Y/A8qzz+/e/0r39RenrTq43V21paSrNmUdeuNG8e6XTV3739d7ebjh6lv/2NevemjAxqUMXNZqMDB1gVdeBA+u67289d1ysmE61axb47cSJptdU/KYpkMlF4OHXuTJs3k9Va/QNK+/3qVYqKon/+k7VWerq0qIhWrmQdMXEi5ea2TnttNob8j3/QpEns35xwBI0Ax9GlS/TEE/TAAzR0KHnr70Fzc7gRCECgOQQanDGuXqVHHqkhYEiljLfeIr2+Ke2sT8b44x//KP01/fPPP//1r3+9aNGi1NTUpUuXtm/fvm3btr6M0alTp5deemn9+vWnT58eN27cq6+++tVXX1VrG8dxp06duv/++1etWnXt2rWjR4++8MILcXFxBoOBiMLCwu69996oqKgTJ06oVKr9+/f369fv//7v/6ZMmXLp0qX09PS0tLTnnnuuf//+KSkpR48effbZZ7t16yZNJklMTHz00Ue7dOmSlJSUmppqNpurXrq4uHj69OkDBg3RFpUavHO7j3yd9tvf/f7RP/zh408Sb968mZGRodVq//CHP8ycOfPixYtnz54dOHDg0KFDr169SkSrVq3q0qXL9OnTz507t3jx4ieeeOK5557zzevIz88fP378kCFDql5R4T8jY9TVQU3KGKJIZWXsrwX/9V/s6cbRo9lUKv8eK1fSn/5EP/kJ/eIXtHr1nTODyUS/+x1rz09/yqqfP/yzcYemffstderE/pHjf/6H+ve/w4ervb1rF7Vrx777619TXFy1N9l8silT6Oc/p//8T7r3XkpLa2JNtvr5/fs7x1FkJN1zD7udrl3p8GF2+t276eGHWUe0aUPTpvn3gvU9W3IyPfcca8M997A2uFz1/SI+p3CB7Gx69VX6j/9gDy387Gf02Wd0W3Ve4XeA5kEAAi0s0LCMIf176IMP1pwx7rqLBgxgszIqH+lpxL1s2bLlqaeeuv/++x+pPH7/+9/fe++90nwMqY4hZQye5//5z3+++eabRqPR4/E4HI6RI0d27NjRlzGef/75jz76yG63cxx3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" + } + }, + "cell_type": "markdown", + "metadata": { + "id": "lSfPbebIq2Ml" + }, + "source": [ + "![image.png](attachment:image.png)\n", + "\n", + "Alright — now that we know where things stand, it’s time to shake things up.\n", + "\n", + "Can QLoRA fine-tuning unlock the true power of LLaMA 3.1?\n", + "\n", + "👀 Let’s find out... in the [next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part6_ft_llama_qlora.ipynb)" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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": 4 +} diff --git a/week7/community_contributions/lisekarimi/09_part6_ft_llama_qlora.ipynb b/week7/community_contributions/lisekarimi/09_part6_ft_llama_qlora.ipynb new file mode 100644 index 0000000..af4b5e7 --- /dev/null +++ b/week7/community_contributions/lisekarimi/09_part6_ft_llama_qlora.ipynb @@ -0,0 +1,907 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 6)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- ➡️ Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA\n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# ⚙️ Part 6: Fine-Tuning LLaMA 3.1 with QLoRA\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ⚠️ GPU required - use Google Colab (A100)\n", + "- 🛠️ Requirements: 🔑 HF Token, wandb API Key ([Weights & Biases](https://wandb.ai))\n", + "- Tasks:\n", + " - Load and split dataset (Train/validation); set up [Weights & Biases](https://wandb.ai) logging\n", + " - Load quantized LLaMA 3.1 8B and tokenizer\n", + " - Prepare data with a collator for fine-tuning\n", + " - Configure QLoRA (LoRAConfig), training settings (SFTConfig), and tune key hyperparameters\n", + " - Fine-tune and push best model to Hugging Face Hub\n", + "\n", + "⚠️ I attempted to fine-tune the model on the full 400K dataset using an A100 on Google Colab, but it consistently crashed. So for now, I’m training on a 20K subset to understand the process, play with hyperparameters, track progress in Weights & Biases, and push the best checkpoint to the Hub.\n", + "\n", + "⏱️ Training on 20,000 examples took over 2 hours.\n", + "\n", + "The full model fine-tuned on the complete 400K dataset is available thanks to our instructor, [Ed](https://www.linkedin.com/in/eddonner) — much appreciated! \n", + "We’ll dive into that model in the next notebook — **stay tuned** 😉\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MDyR63OTNUJ6", + "outputId": "525372ce-f614-44f1-b894-80e289958197" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q datasets transformers torch peft bitsandbytes trl accelerate wandb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-yikV8pRBer9" + }, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import torch\n", + "import wandb\n", + "from google.colab import userdata\n", + "from datetime import datetime\n", + "from datasets import load_dataset\n", + "from huggingface_hub import login\n", + "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, EarlyStoppingCallback\n", + "from peft import LoraConfig\n", + "from trl import SFTTrainer, SFTConfig, DataCollatorForCompletionOnlyLM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Google Colab User Data\n", + "# Ensure you have set the following in your Google Colab environment:\n", + "hf_token = userdata.get('HF_TOKEN')\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "B48QsPsvUs_x" + }, + "source": [ + "## 🔀 Load Dataset from HF and Split into Train/Validation" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets (for Google Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 177, + "referenced_widgets": [ + "6f1f8dca2a334818a36fae380818001e", + "6d3be1ece4a949d3b8d3736db02bcb5c", + "c8c6bbacfe254c539f4acda8cdd5c04d", + "db87c136ff15430892aa75fa47521b0c", + "1d56af1140034021b2aecc5df846e499", + "6238783102084e0c99626bf948ff5bb6", + "f523b67e652049f7b13131d2750325bb", + "f03cc2cf18c140c8b4a076ab99ac86e3", + "472bb957b0e149df8ef0c26c3a3ffc19", + "86dfcc161f2d41a7a33041848766d091", + "6a7ed9e79ebb4f9c9962d08c78b424ca", + "efc4817d5f734852a844640ebe7eceed", + "0b473a8e944c4b028f51f53f62b72deb", + "1fd89859568440f58f3ab56f32183dd4", + "2e4bd8853acc4faa92e461210df2c689", + "3fb588f271db4b7abb9a3631582cc7d6", + "8f9c00ca63ca47e9873ec2a743fa1512", + "afdae504b36845b9a98874cced112721", + "8afd0ddfdeca43b59207a8b35a35e13c", + "0be7a6fdb206420d88b2b2e45a37432c", + "00f0983c1d204862b589011100297ffe", + "8c7de85bcec742ec85f1e8b854351056", + "5847c75b6dd74bc1b13116d91431ccf2", + "bcb0ad86493f45848895c02c0b9deaf6", + "18d70754531248b1ab22e1fd0df061ae", + "028d806f909f42e2b6a7ec630f6e3cb5", + "ff00d3192c734b398f779c7fffde57c8", + "55388dcb89f84c7ebe7f5f7051f2d98b", + "d3cab2b162a740fb82f78f030ea32b45", + "cea0149336be4c92952bacb8aa820926", + "6b560f8a028c4ba39896fd97f48f18ad", + "2a3ed922dab44648b6d6ed63e21c549d", + "885e1f4b9c3d45d5acd8d0a368ca557d", + "73e42dca7c4b455f8be4b34236e6ced2", + "c36aec28025e4baab8a3c4a293297f15", + "7569e26e1e2b46e4a7018e1bd2bc92d5", + "9f5795d223e74f1e8e49709ec1e4ddf1", + "5638ccb893164fc79980eb48d06909f9", + "70a528a0a08e4931b845ecc0992e07d6", + "669bbecd55804849bff5a850438d905d", + "245de1eaef2840b69e6c82afee68b4dc", + "ad57405b8f474c0aa92833f83dde70e8", + "cb3391329a7f4d0b93f5efffb9b0dcfe", + "cb0007dffa284be8aff41efacdfc31cb", + "c7de048747a24f9a9ce85396b87b8250", + "066b3f278ec24b299504cea66b3c3e63", + "0e1069c5bf644531902c51283a6d68e1", + "06bd7477f9fe45d0ad4138fc21bd29dc", + "adb68e7a8bea4b77b960e412c67a6286", + "39ec099d38f04f4e8ea334d0c5335e2f", + "044bf34d53024427801e24fbca808dc1", + "e3d2839112ff4b7f9ab5bc04900ff522", + "f620e7774fa04ed0a88d2f78d2243906", + "7a12c0d7b32b445f978809c9aee2c62d", + "5a230441445746d59ea8a10a4d5bb467" + ] + }, + "id": "XEE1FrSIh-EF", + "outputId": "8cd19745-2f6f-41e0-96dd-5a2f72ac3a63" + }, + "outputs": [], + "source": [ + "HF_USER = \"lisekarimi\" # your HF name here!\n", + "\n", + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']\n", + "split_ratio = 0.1 # 10% for validation\n", + "\n", + "##############################################################################\n", + "# Optional: limit training dataset to TRAIN_SIZE for testing/debugging\n", + "# Comment the two lines below to use the full dataset\n", + "TRAIN_SIZE = 20000\n", + "train = train.select(range(TRAIN_SIZE))\n", + "##############################################################################\n", + "\n", + "total_size = len(train)\n", + "val_size = int(total_size * split_ratio)\n", + "\n", + "val_data = train.select(range(val_size))\n", + "train_data = train.select(range(val_size, total_size))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lUPNqb2Bse21", + "outputId": "a3d09c8f-ce5a-46b0-e1b0-b4471a659f69" + }, + "outputs": [], + "source": [ + "print(f\"Train data size : {len(train_data)}\")\n", + "print(f\"Validation data size: {len(val_data)}\")\n", + "print(f\"Test data size : {len(test)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wixbM-VeVfsR" + }, + "source": [ + "## 🛠️ Hugging Face Configuration" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "OixVUG06VmZk", + "outputId": "3cb523e0-fd03-4a18-913b-c22fa90e3bdd" + }, + "outputs": [], + "source": [ + "PROJECT_NAME = \"llama3-pricer\"\n", + "\n", + "# Run name for saving the model in the hub\n", + "\n", + "RUN_NAME = f\"{datetime.now():%Y-%m-%d_%H.%M.%S}-size{total_size}\"\n", + "PROJECT_RUN_NAME = f\"{PROJECT_NAME}-{RUN_NAME}\"\n", + "HUB_MODEL_NAME = f\"{HF_USER}/{PROJECT_RUN_NAME}\"\n", + "HUB_MODEL_NAME" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1-t1nGgnVTU4" + }, + "source": [ + "## 🛠️ wandb Configuration" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load from Colab's secure storage\n", + "wandb_api_key = userdata.get('WANDB_API_KEY')\n", + "\n", + "# Load from environment variables (.env file) if running Locally (GPU setup)\n", + "# wandb_api_key = os.getenv('WANDB_API_KEY')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"WANDB_API_KEY\"] = wandb_api_key\n", + "wandb.login()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 156 + }, + "id": "yJNOv3cVvJ68", + "outputId": "0c03623e-6887-49e3-8989-bbe45dfc5d35" + }, + "outputs": [], + "source": [ + "# Configure Weights & Biases to record against our project\n", + "\n", + "LOG_TO_WANDB = True\n", + "\n", + "os.environ[\"WANDB_PROJECT\"] = PROJECT_NAME\n", + "os.environ[\"WANDB_LOG_MODEL\"] = \"checkpoint\" if LOG_TO_WANDB else \"end\"\n", + "os.environ[\"WANDB_WATCH\"] = \"gradients\"\n", + "\n", + "if LOG_TO_WANDB:\n", + " wandb.init(project=PROJECT_NAME, name=RUN_NAME)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qJWQ0a3wZ0Bw" + }, + "source": [ + "## 📥 Load the Tokenizer and Model" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 418, + "referenced_widgets": [ + "1b88f6d4010f4451a58abe2c46b74f62", + "139758ba39964f49b65eb67182eef68e", + "9c138d12dcb644fe9b72bd9eb5d26637", + "3bf8626162904a15932480ddbcea0ebd", + "a919a41b53604ccd91331d3f713e1310", + "5b8cdfe01f9a4c248e3de30442411ad4", + "e14d38a4c3e04d68ac30d475b0db1a73", + "dadfd3c2a521420890092be265c0aa50", + "761e88b179104dbbb6455ba81bd1f833", + "11f5b4df0c7344ba9e188f4eca82886f", + "125aa3f0dbd744eb82f8e4de94199736", + "6ca21586e6fc4a608adedba7889eadb5", + "023eb92e8a2b4323bfd12582e3c23962", + "c7c76b9845174e9687107595df27c050", + "78d4a28e03db4775b6e8e071c0b02d5d", + "8483c625762c49679877a37ab0ddcef9", + "1df5f6fe2fc04e60bfcb1f78689824ba", + "add10c416e334928af303d51dfd745c6", + "5e9e9dac85014292b94d347cc4bad3fe", + "d665aa6480624ab697f4e426b51d59de", + "03cce0d3f3a443fc808915b101576e4b", + "f15714023f234c39863b34d1a3721a8e", + "8f7a48d803eb4d2182c9da07af743ac7", + "74892e7b343d410bbbef60c64a823a9a", + "d6a70560831144e39dc9762d397f4c90", + "9b969f7fbcdc491cab71aac42761cd2a", + "d31f9443d1c646309c7a5e1ec39ffc0e", + "0f5a81846ab143bebf6ec422cda3f145", + "f0b05f3f7f37414c9d09470c94e304d7", + "d18784692c9c4ca99e277e6ed51e2bf1", + "f58addfac7c3438a90ebf10c88348d56", + "451deac2eeec45598590579340be0d4b", + "848e0651caf34ef288cca451e3d11274", + "5adf041222f843429c3a9f1b99becfed", + "a4764f36570b4752a1ec4392d2f0146c", + "511a4c6a898346acac9d98fd3a7cdf2c", + "26da7435a2614201a9e5b8087749f0e0", + "6054fa015ae44659beb7473c084c7b5b", + "3b9fc447a9ae4506a1edaf0fa449d9d5", + "6acef8f1820545ef90b22d90ac80427d", + "2a5cbad0b8fd45dc9ee25715b1015aef", + "86a9428f39be4d65a1e922bd9afb3800", + "96d919a1a7f14e91b8e6c91d855e36d5", + "82d7484aa2774015b7ea18d933afa9b6", + "b9d2d4f2c44a4d7cad2b3803c7f6e7be", + "9f3a176a6ae6426a8c1567a835da8680", + "006763d2301f4205a588adf5c19876a0", + "b44eb6596c3441bbaab288030f953a04", + "bf91666a0c054c79acb03d2e1bb38c37", + "f0185f1b4b23445c920a873eb63a9372", + "8e1ac15b677d4c21ad42ea1dda68fe05", + "87746d8d6d3d413ebb46b4e12fb74cc8", + "bb5ea1e92c434a46838f943648de87bd", + "1abcfcba332b40eb901d1331ed84f9bd", + "52fa5fcc629742619fa3105f73d90767", + "1bcc2d5771034c2dbc372031e83a2384", + "221cfaa2a5db4cf1ac399363c3589025", + "793f9bdc92a545519dd3279023e4ab50", + "55e25f5cc12f44f3a39fae501fccd060", + "59463b5e6286483394dedb602991ac95", + "fc95344ea44d40f28702360542afcff7", + "ffb3af537d6c41548ad88027505b04d6", + "6afcf0f6131d4dddbeda796e9c0c5bc5", + "93f65b3bc071453f86fe8f0f6c17d8fd", + "2ac9926ee4644232b43d84cfa95c584d", + "0c5a7738132b4f0f8b4810333b37c588", + "99d41ffa37134be9a57fe5e50a59b67d", + "50e71304ab4f42c29f1994fed9b595b8", + "76b4b0d63e524eb783429169a25be74e", + "441cfadbe4b446f4b61391b7be4d2865", + "6751f0c35b634d7c9b06c4e41f9ff851", + "6a5dc276bbf64bf9b5a99751068ee228", + "b3ac6055014642a285435f877d5651f5", + "e9137600b29c4ecaad4ef8bca5fd5f91", + "634afb9c1b8c4e29b3ec7b76a1108ae4", + "6be0ac91035548fbbe778e3d7fd58e7e", + "e8e9d5c979ac4afba526e38b6d0851be", + "a4ae8ca9c0e7478fbad3b9ed67bc21a2", + "faf3a64e316a43ddbac8ba14573c4eb4", + "a395885e39434f9f98246d0fb1c94c8f", + "d13552c90ead4804a4d5a21121f25536", + "c25b94002c2246a9aa7f6ed1e4a22cfa", + "e3892cf602cb4a49948f26cae1e7644c", + "bc290a324a7147c5b6a722acb41ed05a", + "2b556f5aa6324958ac6fe36bddf17909", + "67c6a0534b3a4345b9c11af1bffdfbf0", + "d767921bb23c485396282cb79a4d1836", + "d598468ad8f94146976f70d873f0b56d", + "b547888cd5494b21911b7d457ab6fbac", + "28362e43274848109c2624e5668942b0", + "7a27fc65bc0b44ce9bd959f4be13514d", + "73bc97e6d9cc4ccd8d134092ce970026", + "c042bf08ab23410098e6d16e837d19ce", + "d2930ad2c08748d0883bb77c68acf940", + "c2a1291730874e8e94232c0d51575f81", + "cb92871b11a0410eb295cc323e5872a7", + "150a5ce5d8124b0eb9e44d8715b8b1ab", + "7a6f05ad1f2e483dbcdca102c66530b0", + "626a29aee42e4e6d8c18d8ea5889734a", + "c549ca0548d04a7d8749a0842c4aa62b", + "958c0ff0f47f4c0fa4e2085f5243d84f", + "a8171febcac94a4b902ff737592f3f47", + "22630cdb7d6f4975bc31cc189987573d", + "2f8a9ccee6ea4cdd8c8c225575cae0ce", + "e40f81c5c4334accbca947964146d238", + "d6849da8e89546469188dc047c66ea25", + "8a67d8a2ac0a4fd7a41aa5c890049525", + "5bf18445be0e46e087cbcd377ccfffbe", + "72b2020c9479471681ce0f42898cfe1c", + "c114fd62eb4b4fdca94654668c8f2374", + "401580df26fc40abb2b774c3d9684921", + "e756b825b211476994a69fb65f4bbf7c", + "b2c26cf10e5a4d4fa8961f5c9cca18ce", + "c288256c73dd44d08916db4e9cf989f0", + "250a72e9650845d2b274bc3c157439f8", + "94281c7e5be049c1a9f3dfa082805133", + "f004f9f743ae4229aa90c92abba6ded6", + "bd8ca5b8aaed4809a93f553d5cb4a887", + "4cec4c2d73de4d52b2143082645536ac", + "893b96616a0e47bfaa0434e10eca1341", + "74e7d88dd4894894ac2c16fdfd29233b", + "9e1f1e4288df407fa03415664dc361d5", + "81dc3f390b9a49f8b1be5c43580b070d", + "917a225a9bb74f8ab034dcdcee3c7247", + "bc6c698857ce4f8eabc1571ba0ff0edf", + "e9ae1c247ae5409f9da4db84ce71a6e3", + "55071660223e4022a6a7836572077c0c", + "8364e661011743af9fd40dabc5a7dfe4", + "ac65442e0d5e43e2998d7c700573228a", + "666f3434ae8a495f8ada8fedb50b7051", + "1977e9f07f104faead7dfcfa8aaed6f2", + "ebe2257c07f345fea72f162542a45142" + ] + }, + "id": "R_O04fKxMMT-", + "outputId": "29aa1cf7-2a2e-492e-adc9-cd0a5bfb123e" + }, + "outputs": [], + "source": [ + "BASE_MODEL = \"meta-llama/Meta-Llama-3.1-8B\"\n", + "\n", + "quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True, # Reduce the precision to 4 bits\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + ")\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)\n", + "tokenizer.pad_token = tokenizer.eos_token\n", + "tokenizer.padding_side = \"right\"\n", + "\n", + "base_model = AutoModelForCausalLM.from_pretrained(\n", + " BASE_MODEL,\n", + " quantization_config=quant_config,\n", + " device_map=\"auto\",\n", + ")\n", + "base_model.generation_config.pad_token_id = tokenizer.pad_token_id\n", + "\n", + "print(f\"Memory footprint: {base_model.get_memory_footprint() / 1e6:.1f} MB\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SrCE2Le7RBRj" + }, + "source": [ + "## ⚙️ Fine-tune our LLaMA 3 8B (4-bit quantized) model with QLoRA\n", + "- 1. Prepare the Data with a Data Collator\n", + "- 2. Define the QLoRA Configuration (LoraConfig)\n", + "- 3. Set the Training Parameters (SFTConfig)\n", + "- 4. Initialize the Fine-Tuning Trainer (SFTTrainer)\n", + "- 5. Run Fine-Tuning and Push to Hub" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9BYO0If4uWys" + }, + "source": [ + "### 🔄 1. Prepare the Data with a Data Collator\n", + "\n", + "We only want the model to learn the price, not the product description. Everything before \"Price is $\" is context, not training target. HuggingFace’s DataCollatorForCompletionOnlyLM handles this masking automatically:\n", + "\n", + "1. Tokenizes the response_template (\"Price is $\")\n", + "2. Finds its token position in each input\n", + "3. Masks all tokens before it (context)\n", + "4. Trains the model only on tokens after it (the price)\n", + "\n", + "\n", + "Example:\n", + "\n", + "Input: \"Product: Red T-shirt. Price is $12.99\"\n", + "\n", + "Masked: \"Product: Red T-shirt. Price is $\" → masked (no loss)\n", + "\n", + "\"12.99\" → not masked (model is trained to predict this)\n", + "\n", + "So the model learns to generate 12.99 given the context, but isn’t trained to repeat or memorize the description." + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2omVEaPIVJZa" + }, + "outputs": [], + "source": [ + "response_template = \"Price is $\"\n", + "collator = DataCollatorForCompletionOnlyLM(response_template, tokenizer=tokenizer)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4DaOeBhyy9eS" + }, + "source": [ + "### 🧠 2. Define the QLoRA Configuration (LoraConfig)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0HKuVS_XR3cw" + }, + "outputs": [], + "source": [ + "LORA_R = 32\n", + "LORA_ALPHA = 64\n", + "TARGET_MODULES = [\"q_proj\", \"v_proj\", \"k_proj\", \"o_proj\"]\n", + "LORA_DROPOUT = 0.1\n", + "\n", + "lora_parameters = LoraConfig(\n", + " r=LORA_R,\n", + " lora_alpha=LORA_ALPHA,\n", + " target_modules=TARGET_MODULES,\n", + " lora_dropout=LORA_DROPOUT,\n", + " bias=\"none\",\n", + " task_type=\"CAUSAL_LM\", # Specifies we're doing causal language modeling\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uLfFsfNQSBAm" + }, + "source": [ + "### ⚙️ 3. Set the Training Parameters (SFTConfig)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7PKXdhPXSJot" + }, + "outputs": [], + "source": [ + "# 📦 Training Setup:\n", + "EPOCHS = 1\n", + "BATCH_SIZE = 16 # A100 GPU can go up to 16\n", + "GRADIENT_ACCUMULATION_STEPS = 2\n", + "MAX_SEQUENCE_LENGTH = 182 # Max token length per input\n", + "\n", + "# ⚙️ Optimization:\n", + "LEARNING_RATE = 1e-4\n", + "LR_SCHEDULER_TYPE = 'cosine'\n", + "WARMUP_RATIO = 0.03\n", + "OPTIMIZER = \"paged_adamw_32bit\"\n", + "\n", + "# 💾 Checkpointing & Logging:\n", + "SAVE_STEPS = 200 # Checkpoint\n", + "STEPS = 20 # Log every 20 steps\n", + "save_total_limit = 10 # Keep latest 10 only\n", + "\n", + "\n", + "LOG_TO_WANDB = True\n", + "\n", + "HUB_MODEL_NAME = f\"{HF_USER}/{PROJECT_RUN_NAME}\"\n", + "\n", + "train_parameters = SFTConfig(\n", + " # Output & Run\n", + " output_dir=PROJECT_RUN_NAME,\n", + " run_name=RUN_NAME,\n", + " dataset_text_field=\"text\",\n", + " max_seq_length=MAX_SEQUENCE_LENGTH,\n", + "\n", + " # Training\n", + " num_train_epochs=EPOCHS,\n", + " per_device_train_batch_size=BATCH_SIZE,\n", + " gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,\n", + " max_steps=-1,\n", + " group_by_length=True,\n", + "\n", + " # Evaluation\n", + " eval_strategy=\"steps\",\n", + " eval_steps=STEPS,\n", + " per_device_eval_batch_size=1,\n", + "\n", + " # Optimization\n", + " learning_rate=LEARNING_RATE,\n", + " lr_scheduler_type=LR_SCHEDULER_TYPE,\n", + " warmup_ratio=WARMUP_RATIO,\n", + " optim=OPTIMIZER,\n", + " weight_decay=0.001,\n", + " max_grad_norm=0.3,\n", + "\n", + " # Precision\n", + " fp16=False,\n", + " bf16=True,\n", + "\n", + " # Logging & Saving\n", + " logging_steps=STEPS, # See loss after each {STEP} batches\n", + " save_strategy=\"steps\",\n", + " save_steps=SAVE_STEPS, # Model Checkpointed locally\n", + " save_total_limit=save_total_limit,\n", + " report_to=\"wandb\" if LOG_TO_WANDB else None,\n", + "\n", + " # Hub\n", + " push_to_hub=True,\n", + " hub_strategy=\"end\", # Only push once, at the end\n", + " load_best_model_at_end=True, # Loads the best eval_loss checkpoint\n", + " metric_for_best_model=\"eval_loss\", # Monitors eval_loss\n", + " greater_is_better=False, # Lower eval_loss = better model\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1q-a3LHDSoxQ" + }, + "source": [ + "### 🧩 4. Initialize the Fine-Tuning Trainer (SFTTrainer)\n", + "Combining everything" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 290, + "referenced_widgets": [ + "6753caf741414a4c8fa309978253c8cd", + "aeade430d57b4338910ad0c3645fd06a", + "eb7081b71cc14aff9b99dba8f9368def", + "8eb16171df804d06a02351f74bb28dc4", + "9d60a205ebda49ca88220cc4eec716ca", + "d8ff973b90374423b4b5e17a1937111c", + "4bf3bf107f2c4e28a58387c96916e97f", + "d66cb8c1829c439095f4691fa32d7b6e", + "567c8321685045c5a873b3b1edecdc96", + "96ff596facb94acab611201b4adac13f", + "de65507ce09a4ef4ad8f28d46d335acc", + "e40fe92fe9094a58b53f0eeb97d3d629", + "592615cc81624de5a9934f5671d6c188", + "fadf75d91df54f49acef3f178ea53ce3", + "5ccca8ab6cb94a88bb27bd482f7948a9", + "d74dcc2ef9b8442d9ae99db2a79e0c48", + "580ebfa370d34426933e8c7389872e2b", + "1187f05dc99641e9a68d9cf49216c370", + "7deffbba68ba4f018374bd6bec62dd18", + "d24cdc40a6a34d6eb0efbfde17505d6f", + "31d44a308b4b4557934ec887e0b6a817", + "76112ce6fdc4496dba783451efa28cfd", + "15a85e4a77484c9392b2e5cb8767b336", + "4524d775b9034a1f890673a9c005d123", + "5ab6a6b427f84ec685ac52f6ff0d63b5", + "427ee9e90a844313989f623aba124498", + "6d2b7c059e6b42afa955fe01bf38011d", + "5d821ed8ffe14927be799c4d31043a82", + "12f9fab59e9849dcb7b3b17c5674580f", + "dd4a2876db37476fa438e8758c855393", + "f115f97428764c53ac780131fd75bd17", + "1a1e0e562a844ed098e97ce8a62695ee", + "0a7ae7cc902243a5996f730f0fe05cdb", + "07205ea24c3f4959bf9ebd393f5c921d", + "723bb8342ac84eedabd91e3eef178967", + "28714d0cf3d84a48975c8ad31e29691d", + "dd1d90d76d914839a1dad1cddab2c09f", + "e2d55edf98784523bcbeaad0cc2be494", + "d00ecfa9dc44428b989ec1a9deb27eae", + "ba2717985bc342e9827f8901ef655b00", + "6669dc8f20e3461f93c95cef7a90b201", + "29cb36c1943c4e1b9898534aaf32bd37", + "14a1449c13a14afda16bc7c05b7fd840", + "259d315eb4584c699b1c738d411eab7e", + "a4bb13eb7cee4f87b0e3e1a3a1be18e7", + "14d8a699a92044cda33802d96aaa41a2", + "d345350fd5ad4a028fbbc45cfc9f6db3", + "6953210353f840d59457fc54f4f8b829", + "d6cd9e1196f04ecbba83dc0b446b2c65", + "9e380ef863204da5863c9b6e7a2c8340", + "1d1bb803831d46309619f6a0c51c2eeb", + "6a50aaf7ad304a5aa3f29113121e8fe0", + "7a573a39c2b245f5a84626d951584f67", + "a57e66367d4245f6bcd4ad0463535583", + "d6f3327d39a34ec5a44d976f239a61ce", + "8f450df9f161409a8102c1f0b63edad8", + "95d932d12cb8442da17adb8e9782c40c", + "41c5f295b45f4828a9327b699b85ca01", + "9e4f3fd6bf7749f88ccd7ba65dd9446f", + "a8f8cb0d9fb14f30a537977f3d51a2c4", + "4e9e4ed0f2db4d7ba5a5bb0d00676a0c", + "1fe2bab9c9aa4de48e6e2512f9a7d0a1", + "d93ac5affccf404fa3916e7f3dd62943", + "92346fc65f48493d80198ac6d7adf4d8", + "647bfb2a24cc44a0adaf69ced8e99213", + "5c96424cff314aa484e4bc905bcbd761", + "cec2fcfb30194d5ab8c0a3868bad3598", + "35df7031c4964cef9c53bba6eabbe91d", + "e15c772e14264c9889e6dae34015e04b", + "e85b65cb497c48c2b844ae3e5d9efc60", + "52c8495d46ca4a3c8c6694a700d05e95", + "3db6d8a5ce2a40daaae6714807a27997", + "051d74df7ef1468aa968cac5792e7b00", + "75838a7c887545ff9fbbf5887a1336bc", + "59f698c1829148ac90edda008d5c6f69", + "35921436c69643aab792bd1333c749ef", + "2dd51cc6033746e1a8def460e5e51ff5", + "a8a3e5973ee5441087d10dfb17bfa1d6", + "64c3b3c02e844df6bfd3acf1ee23d765", + "83016eccdd7f4dedab9d3ea6e6852977", + "9d4c5a62214f4649b77365349ae4ac88", + "07cb9756d1814a7ba7fb49cccb2763cb", + "492454ad524742bd8bb3f5c3d5b37feb", + "e98053f6b7f045da812088d1e76d3a31", + "f2aeb3ae99cc4b7ca97fb959df1150ad", + "f92e18b6ab0147b1b428724f5155ca61", + "14356b2447e349ee8478478eb231fa81", + "f244a7e331d941f5a99712dcbc5550ea" + ] + }, + "id": "fCwmDmkSATvj", + "outputId": "2b4adc75-e0db-4e0b-c90b-9f9ff2dfd3c6" + }, + "outputs": [], + "source": [ + "# The latest version of trl is showing a warning about labels - please ignore this warning\n", + "fine_tuning = SFTTrainer(\n", + " model=base_model,\n", + " train_dataset=train_data,\n", + " eval_dataset=val_data,\n", + " peft_config=lora_parameters, # QLoRA config\n", + " args=train_parameters, # SFTConfig\n", + " data_collator=collator,\n", + " callbacks=[EarlyStoppingCallback(early_stopping_patience=5)] # Early stop if no val improvement for 5 steps\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vHz6JA5_XJ07" + }, + "source": [ + "### 🚀 5. Run Fine-Tuning and Push to Hub" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "id": "GfvAxnXPvB7w", + "outputId": "d351d89a-b3d7-4e2b-fee2-5ba2e929837e" + }, + "outputs": [], + "source": [ + "fine_tuning.train()\n", + "print(f\"✅ Best model pushed to HF Hub: {HUB_MODEL_NAME}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://github.com/lisek75/nlp_llms_notebook/blob/main/assets/09_train_eval_loss_steps.png?raw=true)\n", + "\n", + "![](https://github.com/lisek75/nlp_llms_notebook/blob/main/assets/09_train_eval_loss_wandb.png?raw=true)\n", + "\n", + "This chart shows training loss vs evaluation loss over steps during fine-tuning of Llama 31 8B 4-Bit FT (20K Samples).\n", + "\n", + "- Blue line (train/loss): Decreasing overall, with some noise. Final value: 1.8596.\n", + "- Orange line (eval/loss): Smoother and consistently lower than training loss. Final value: 1.8103.\n", + "\n", + "- No overfitting: Eval loss < train loss throughout — a good sign.\n", + "- Stable convergence: Both curves flatten around step 500, suggesting the model is reaching training stability.\n", + "- Final eval loss is low, indicating decent generalization to unseen data.\n", + "\n", + "This fine-tuning run looks healthy. We can likely push further with more data - 400K run." + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 938 + }, + "id": "32vvrYRVAUNg", + "outputId": "bb4ab0f6-c390-48f3-a71c-2d259bb0ec0b" + }, + "outputs": [], + "source": [ + "if LOG_TO_WANDB:\n", + " wandb.finish()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://github.com/lisek75/nlp_llms_notebook/blob/main/assets/09_run_summary_qlora_llama.png?raw=true)" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IyKZ0r38IfT3" + }, + "source": [ + "Now that our best model is pushed to Hugging Face, let’s put it to the test.\n", + "\n", + "🔜 See you in the [next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part7_eval_llama_qlora.ipynb)" + ], + "outputs": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "A100", + "provenance": [] + }, + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/week7/community_contributions/lisekarimi/09_part7_eval_llama_qlora.ipynb b/week7/community_contributions/lisekarimi/09_part7_eval_llama_qlora.ipynb new file mode 100644 index 0000000..bfe78d1 --- /dev/null +++ b/week7/community_contributions/lisekarimi/09_part7_eval_llama_qlora.ipynb @@ -0,0 +1,739 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "GHsssBgWM_l0" + }, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 7)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- ➡️ Evaluating Fine-Tuned LLaMA\n", + "- Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# 🧪 Part 7: Evaluating the Fine-Tuned LLaMA 3.1 8B (Quantized)\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ⚠️ GPU required - use Google Colab\n", + "- 🛠️ Requirements: 🔑 HF Token\n", + "- Tasks:\n", + " - Load the tokenizer and fine-tuned base model\n", + " - Load the PEFT adapter for the fine-tuned weights\n", + " - Run evaluation — the moment of truth!\n", + "\n", + "🔔 **Reminder:** \n", + "As mentioned in Part 6, I fine-tuned the model on only 20K samples. \n", + "In this notebook, we’ll evaluate both this model and the full 400K-sample version fine-tuned by our instructor.\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MDyR63OTNUJ6" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q datasets transformers torch peft bitsandbytes matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-yikV8pRBer9" + }, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import math\n", + "import torch\n", + "from huggingface_hub import login\n", + "import torch.nn.functional as F\n", + "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, set_seed\n", + "from datasets import load_dataset\n", + "from peft import PeftModel\n", + "import matplotlib.pyplot as plt\n", + "from google.colab import userdata" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WyFPZeMcM88v" + }, + "outputs": [], + "source": [ + "# Google Colab User Data\n", + "# Ensure you have set the following in your Google Colab environment:\n", + "hf_token = userdata.get('HF_TOKEN')\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "30lzJXBH7BcK" + }, + "outputs": [], + "source": [ + "# Helper class for evaluating model predictions\n", + "\n", + "GREEN = \"\\033[92m\"\n", + "YELLOW = \"\\033[93m\"\n", + "RED = \"\\033[91m\"\n", + "RESET = \"\\033[0m\"\n", + "COLOR_MAP = {\"red\":RED, \"orange\": YELLOW, \"green\": GREEN}\n", + "\n", + "class Tester:\n", + "\n", + " def __init__(self, predictor, data, title=None, size=250):\n", + " self.predictor = predictor\n", + " self.data = data\n", + " self.title = title or predictor.__name__.replace(\"_\", \" \").title()\n", + " self.size = size\n", + " self.guesses = []\n", + " self.truths = []\n", + " self.errors = []\n", + " self.sles = []\n", + " self.colors = []\n", + "\n", + " def color_for(self, error, truth):\n", + " if error<40 or error/truth < 0.2:\n", + " return \"green\"\n", + " elif error<80 or error/truth < 0.4:\n", + " return \"orange\"\n", + " else:\n", + " return \"red\"\n", + "\n", + " def run_datapoint(self, i):\n", + " datapoint = self.data[i]\n", + " guess = self.predictor(datapoint[\"text\"])\n", + " truth = datapoint[\"price\"]\n", + " error = abs(guess - truth)\n", + " log_error = math.log(truth+1) - math.log(guess+1)\n", + " sle = log_error ** 2\n", + " color = self.color_for(error, truth)\n", + " # title = datapoint[\"text\"].split(\"\\n\\n\")[1][:20] + \"...\"\n", + " self.guesses.append(guess)\n", + " self.truths.append(truth)\n", + " self.errors.append(error)\n", + " self.sles.append(sle)\n", + " self.colors.append(color)\n", + " # print(f\"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}\")\n", + "\n", + " def chart(self, title):\n", + " # max_error = max(self.errors)\n", + " plt.figure(figsize=(12, 8))\n", + " max_val = max(max(self.truths), max(self.guesses))\n", + " plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6)\n", + " plt.scatter(self.truths, self.guesses, s=3, c=self.colors)\n", + " plt.xlabel('Ground Truth')\n", + " plt.ylabel('Model Estimate')\n", + " plt.xlim(0, max_val)\n", + " plt.ylim(0, max_val)\n", + " plt.title(title)\n", + "\n", + " # Add color legend\n", + " from matplotlib.lines import Line2D\n", + " legend_elements = [\n", + " Line2D([0], [0], marker='o', color='w', label='Accurate (green)', markerfacecolor='green', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='Medium error (orange)', markerfacecolor='orange', markersize=8),\n", + " Line2D([0], [0], marker='o', color='w', label='High error (red)', markerfacecolor='red', markersize=8)\n", + " ]\n", + " plt.legend(handles=legend_elements, loc='upper right')\n", + "\n", + " plt.show()\n", + "\n", + "\n", + " def report(self):\n", + " average_error = sum(self.errors) / self.size\n", + " rmsle = math.sqrt(sum(self.sles) / self.size)\n", + " hits = sum(1 for color in self.colors if color==\"green\")\n", + " title = f\"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%\"\n", + " self.chart(title)\n", + "\n", + " def run(self):\n", + " self.error = 0\n", + " for i in range(self.size):\n", + " self.run_datapoint(i)\n", + " self.report()\n", + "\n", + " @classmethod\n", + " def test(cls, function, data):\n", + " cls(function, data).run()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 📥 Load Dataset" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 177, + "referenced_widgets": [ + "61f42f612e98467684716cc7421c7554", + "a7e864c2ae21482e8bcdbc42a5a65309", + "63405c5e47da4652b052ee6099ead31e", + "0864a38b1c494308a07defced89f4fe3", + "8f089946a97d4becb3ff06b7a65595a2", + "42b865ac9e4f4ecaa475c4d69929e401", + "3478290afe1d48268c7c07206c212eda", + "f21c0db9205f4c40a2f9ea1ddd66b59e", + "4604f38122454bc1b1826311a326eb12", + "6e2b95e33cab4fe9b9f555195b634fac", + "b8f0f357a61c4502962f385291c3bac8", + "fa49b7e56b054faca67334e08bbf622c", + "243d84401ba24360a42c2636d7984772", + "bbcf01edcbcd425b9ca1e61e80f6df4f", + "17b41698c33044c7942e66e63c5c2d2d", + "14dfccde2f6a47679cea42ce965b6ef2", + "6a1570c8980b4d5ebac78348f79c4f1b", + "44f1922676f3417fb7baccd92bf53cea", + "176b023546bc4053a4d484205d7ab200", + "b02018254c4b4fb680e382974380c331", + "766aba35ebf54996990e075e4f692f96", + "24ceffd3b8c64e5f983e52d743ebef8d", + "5b9076b6c05a4454a7233302114b9d8c", + "4bfbd393271844de825a53c7d639fa60", + "3313091548bf414fabf84f5aa2c85d14", + "f98c7fe4ad6d4649a7a104f973992be0", + "fd1eb06d0aa64ba59ae9bb214f2c94ed", + "24237203b2c44709b20ca84b95387849", + "7910e6a4881a43638c4e91dd0f024092", + "f22dad57ee324ca8b927f9a3b8cc6edc", + "20a702b1ccbe499eabf70af974561417", + "48f72254ce6f408c94bf56a3919c032e", + "6bf00cd26256489fb209b8b51ca9fb0e", + "da3c453facaf41b6bc89d311d9f1ce74", + "78487c1a13e84e7bb35a72a07ad9b681", + "3866fe39fcc34120a0b4c4b36c8eaa6c", + "54de8e445909429f9d7ca9ad02e8f190", + "eeda8994cb8d46cc9d5c2212907ab869", + "b670675ee9bc4689a34f997d0da13b82", + "56727a21bb4648fe8ae46d3a61b39f4a", + "da89c856fbf746b496d37cbef92305b9", + "2f4ba348ef7246af8b1cd04352bcbd1d", + "0d86b4a93411494eb8e725440e393cff", + "203c4888674c46bba1033639ad4286a2", + "005dac04aacb4955ae079d36bfc4cd19", + "68ff796bdee44aa380324374ae38fd25", + "411691dce3f1457cb3ee9e8ad652d61d", + "f0fc209cb9e74d0ca3c0c9b14b1450e0", + "6e2155c3ad3243508dff34919eecd0a2", + "68891d88fe7e417abbd508d2089e7960", + "8e1ab77817bc4ec2835b195a0beb1096", + "c638e3a09f6b4caaa078e242b010744e", + "ee9abd78adb54984868ebee19f638e25", + "8280e432938b4e9794c95e47bb9c02fa", + "abdd2ff8028b432091434805f81c455c" + ] + }, + "id": "cvXVoJH8LS6u", + "outputId": "6308b124-a922-4e82-fb6a-5933d3c324e0" + }, + "outputs": [], + "source": [ + "DATASET_NAME = \"lisekarimi/pricer-data\"\n", + "dataset = load_dataset(DATASET_NAME)\n", + "train = dataset['train']\n", + "test = dataset['test']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xb86e__Wc7j_", + "outputId": "8b699099-7414-4663-fab1-d069d3ec3d35" + }, + "outputs": [], + "source": [ + "test[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qJWQ0a3wZ0Bw" + }, + "source": [ + "## 📥 Load Tokenizer and Model\n", + "The fine-tuned model (PeftModel) only holds the LoRA adapters, so it requires the base model to apply them correctly." + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 401, + "referenced_widgets": [ + "aee2cb6b13d64f1dab9f8190a274bbc0", + "547a2807263e4295af11da5a43ccf5b7", + "00b57ab6c0c44e39ad6fa27b7e5a085b", + "d51c826dc6d749b38ce7e5fdfc730086", + "f276602665c148999240ef916aa8a9c8", + "9d83d7056aed43a59d82955bdb8f272d", + "7a71aedc0f49430ba7c71040c5fa2529", + "108880a9a7bb4a73837889ad2a25fd77", + "0163275024a041e2bc9fba947c371269", + "555a494cbcda41e79ee4584a8122774b", + "5dfbe2af8afc43c691c34c52a47c9790", + "25edb5ab02c3402998b75cffc13d0a55", + "9a4f0361323540aa8428054a0d98ecb3", + "cf149d1eceae43a9808e142fbfe5d4ff", + "de86c9338690424fa0052e5b055cea88", + "2acb3368945a48aeaf9fbc6d22e9238d", + "4c4c4b1507814037bcea0519ec43ba26", + "6d37385e79904b7ca267ad165774f962", + "b14a5f0f71094aa98403edd429cb882e", + "31b28b6183c644f9b5601208a1f72499", + "d3cddc62e0fb4256bf4c74f6a59e686b", + "82cb2192839e451292b27a186daaa7c1", + "2e038c429eed4abdae8d27a7226d7298", + "364c4658aba64512a1f50cdad9cc12f8", + "fde7b1ab1e224fec8e9b761e703b53dd", + "ad5db9c88ce64f73992d2e274ca1206a", + "0e7ada829b22485ca7a628d2c464f3f1", + "ec4f7d2076db4f6a856ab0d5e8edffbd", + "3f00114026a4417db1b142e5bcb7a695", + "e4e9cf32b99848baa6a587fb235ce6b5", + "a109b5ee80574e40a14fa1e186f4f9f4", + "af569da703694c27aa9ca2ddce6c4923", + "886bb94abf2c437eb8505222c4336e85", + "f668156d681e47f39e553f127a44261d", + "9bb3d0deaac6439e9ad67c2bc0565ff4", + "762b36fde5ac4a2982152f3babfa3ed9", + "141911ee360d42ab8dd3b7fa3563bbf0", + "340eae69eeaf4e458e6d8134018f4ad4", + "3226e3a8c4564f6fbd6ffb3eeb7b45e7", + "6ed52680f866470da1e8d4a48b6e42fb", + "6d8a206edb824c5eb06c803e8cab14de", + "86fd4472a7a84940a54f24104689a74d", + "916c0e20af5e4b78a5e86532b0c9a3e8", + "62dd475c101e4859a48ee57a272f71bc", + "a8b7185a12c94adca0e63563d7df3ce4", + "47d57186838d466fb91b6666df85d1b4", + "9d37814d818c466c90892bf1f6e9a190", + "b5fdba30791649a792d192a131890a4e", + "789fe6f5489345c6a8b6a889d20e0ca0", + "5ce12a0983bb49f1a871598a6b9a0a13", + "d9eb89d218a44f21bb4447040e5c8925", + "b04aaa7931e74297a55bca3ebf4ded1d", + "837708f48ded4d78b7ad2e0dc6464e9c", + "32236e0d0b3e46e4b2c26b7ccb63c89e", + "499acde0cedf4ea1a90415f98660aaa5", + "840d3e7824944889ac2091b35f0c17c0", + "08f2fae4688b45729d8f5bf53837e56d", + "133bb5607eb0457888b1fe4e8d3fab3e", + "46bfe5feb9074050b556d804a544140d", + "4c3b0c2d04d24ec6abe8acbadb420712", + "eda1fcca6987495b87cf2206f93a0ecb", + "00b803cf92754db1bbea8ca909e5ccef", + "17e17b928555462abfbfa4caf7992427", + "35f90fa89e8842cdaa487b59da45b3e8", + "2887ef88074c4591b710688fa76329bf", + "0a0c5f00b3cc477e8b7e06550fc6f1cb", + "3b079fe81b7b44d796c531bec1754637", + "e82f8ac6e8eb4ed6a6743e10b8b99904", + "1f7de1e2970c4c8fbfe1ab400297e1a7", + "7ea0d8782a1f4cca9a64b95fe47e8a2e", + "689b49d52b8f4efb94f80d76a0fefab3", + "2005939305c442f7bed3b83ea16e13b1", + "1a6f2631e29444818fdbd9a0de265367", + "6bfc89e091a5448d94d2ea559ce43a21", + "bfc12d40caf4481280888506dfa01505", + "a1fb82d5761843a49a0993ff937cb40d", + "4c9c567918ee478a817b51e2a204d915", + "305623f276ba45e5a57727d1829158e1", + "b2722e271f78405b9151804ffc522530", + "963435e51a7a4ce98510c0372cd05030", + "d394cfc6af384a39b87c72ac6a3788d9", + "2c621a7a90ed4bfd8b52cea9c79e11c1", + "59ac0bb5c046448fbf16a27d2c3205f8", + "7617f5670879416d9dbc2dabda76ef4d", + "b32d6d6ff5dd4ac4adfb063205111707", + "38f3a7159fc34d89bc18e4225473615d", + "2a2c386e432f429f86c303d71472b480", + "ece25eb325004ae48ec5ec00055dd845", + "68e2b37bbd9a44f8a6032526acbf9ea6", + "3af191957e3f453ba803a1c01d6969ae", + "29dba394a6664e0f8984bcb966ccf19b", + "d84373a3f97245ae94bfb666c7e93a17", + "9f917250ccbf4078a90fda1eec71c6f4", + "8171dd4382d24f0a83484fbf967fec03", + "6f97606a500548e980c6481d756c72eb", + "6d1054047d4645a69c272484fd9e0c04", + "7fd14d942d2246bf8df28eca28e13fb2", + "0dabd208524f426bb5c643791e736413", + "368dea7bbf144cf0a667493cb23bddab", + "d6b14f8e43754283ad96543c4c1ffee6", + "f78562ef15524795bb9be326dcaab502", + "b01c8091b96444f687a49c5c51b5faf7", + "baab647e635a46ababa58993965a8159", + "25d9a9b78d554f8fbe92d7e805640c3b", + "95726f4b9bc34434b9d00fcdfe2ff87e", + "a7b835a668ef40c986a6fd51e464d1f4", + "188cac6192fc4b91be3ca5b01bab1d91", + "3537ef715f3447388625ee606555bb85", + "322ca0ccce644c48a2a0f4b44a38776d", + "cc3726d026594cb6ac2d6bafb16562ac", + "f48cc4a0a5d041cf9391a99353ff46af", + "05134ca3a9954341951ff958ff30fe0a", + "3a6aa623f1dd41b8940a41b509fa7500", + "fd58111bb44347b8bdcb984a0e86f9b7", + "c16cfb96177640a991c5509e652c85b9", + "adc0ffacba0846fabd76ed7955397077", + "e074da8f28d84ec891f22e30b86fb954", + "0b53df078f4a4a259b677ccccbdf46cd", + "954d5fa3b18a49589717cfc31fb58779", + "af0beb46b198458794c85803fe5af47f", + "c7322d41ae4c4068880521a136e923b4", + "391d834aa8734d7b9a97c03cab5e1e7d", + "5d779fc6bb1244449a68cf62dfd15698", + "197ca7f2357a4a2c89f5f3da3844c606", + "df4d22e6876b4c0082a7ace3281ff4e5", + "28d44cfae7de4b62be11020d9015f92c", + "3e8d7274ee3a4dfbbdd44ea0b2cd61b6", + "fa768ce193b94a4882a1e796e69cffea", + "c37a4882e4474f8690c4b479baf2d785", + "68a033bbcb4d4774bdb115e09d78365b", + "10b5e7970aa04bd6b3384aa645c48d92", + "f838b073dd254bb091a7db7175cd2ce8" + ] + }, + "id": "lAUAAcEC6ido", + "outputId": "b2983922-5036-4083-8cba-0cb3f51fbc51" + }, + "outputs": [], + "source": [ + "BASE_MODEL = \"meta-llama/Meta-Llama-3.1-8B\"\n", + "\n", + "quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True, # Reduce the precision to 4 bits\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\"\n", + ")\n", + "\n", + "# Load the Tokenizer and the Model\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)\n", + "tokenizer.pad_token = tokenizer.eos_token\n", + "tokenizer.padding_side = \"right\"\n", + "\n", + "base_model = AutoModelForCausalLM.from_pretrained(\n", + " BASE_MODEL,\n", + " quantization_config=quant_config,\n", + " device_map=\"auto\",\n", + ")\n", + "base_model.generation_config.pad_token_id = tokenizer.pad_token_id\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2RJ0G-WRJGMK" + }, + "source": [ + "## 🧪 Load and Evaluate the Fine-Tuned Model with PEFT Adapters" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 20K Sample Fine-Tuned Model" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000, + "referenced_widgets": [ + "f0c0a20172294f77a0306801f8d76fb7", + "f68ee0810c2a4ac087ac6ece5279fb09", + "8aa12b380191454ebf55e8b42d0e0f2b", + "63f6cfa30a274ee3835671d8e39a85ef", + "0b980946a50d4248a4c63ef117fc2e8f", + "18283c6dee9447ddaca34ad267773e48", + "a7d10d9147df4adebf913e3023c2a3a4", + "5886ca455d4d4aefa617478f4f69a3ca", + "8c0e83bce4f74e7ba337fc9af5b977b8", + "00dbc32bdb0440c0bc3ba2cc6677b04c", + "243e6d8479ac4958a8d877e28f9b514a", + "10b7df1ecfab4e5cb146932fc4fb2c17", + "07c6fd1fe1ac442dbeb7037161841b78", + "88adf6ab3f3e476fa66ad22e9ff49aa8", + "fe522e9cee55448a9c13a5daaad5e7e7", + "4b1b9e5a67e54a3b90f2c113355e735a", + "5cdbdf93af9344ccabd7c3f236446541", + "c4af3ca6696d4fcd9b831d825456c7fa", + "525b1673c902412db32691056d49fd35", + "42de37b9a74143b4a851a178c484a706", + "f5f42d9201dc4fbaaa9c684fdb748d4a", + "10a0e99256a149a0a94ff652a4fd259a" + ] + }, + "id": "R_O04fKxMMT-", + "outputId": "06fc64f8-3407-460b-e093-0293e958915e" + }, + "outputs": [], + "source": [ + "# Load lisekarimi model (trained on 20K datapoints)\n", + "\n", + "FINETUNED_MODEL = \"lisekarimi/llama3-pricer-2025-04-08_18.44.04-size20000\"\n", + "fine_tuned_model = PeftModel.from_pretrained(base_model, FINETUNED_MODEL)\n", + "print(f\"Memory footprint: {fine_tuned_model.get_memory_footprint() / 1e6:.1f} MB\")\n", + "fine_tuned_model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Je5dR8QEAI1d" + }, + "outputs": [], + "source": [ + "# Gets top 3 predicted tokens from the model\n", + "# Filters valid numeric outputs (prices)\n", + "# Returns a weighted average based on token probabilities\n", + "\n", + "# This code would be more complex if we couldn't take advantage of the fact\n", + "# That Llama generates 1 token for any 3 digit number\n", + "\n", + "top_K = 3\n", + "\n", + "def improved_model_predict(prompt, device=\"cuda\"):\n", + " set_seed(42) # Reproducibility : same prompt = same o/p every time\n", + " inputs = tokenizer.encode(prompt, return_tensors=\"pt\").to(device)\n", + " attention_mask = torch.ones(inputs.shape, device=device)\n", + "\n", + " with torch.no_grad(): # Do not track gradients during inference\n", + " outputs = fine_tuned_model(inputs, attention_mask=attention_mask)\n", + " next_token_logits = outputs.logits[:, -1, :].to('cpu')\n", + "\n", + " next_token_probs = F.softmax(next_token_logits, dim=-1)\n", + " top_prob, top_token_id = next_token_probs.topk(top_K)\n", + "\n", + " prices, weights = [], [] # weights = corresponding probabilities\n", + "\n", + " for i in range(top_K):\n", + " predicted_token = tokenizer.decode(top_token_id[0][i])\n", + " probability = top_prob[0][i]\n", + "\n", + " try:\n", + " result = float(predicted_token)\n", + " except ValueError as e:\n", + " result = 0.0\n", + "\n", + " if result > 0:\n", + " prices.append(result)\n", + " weights.append(probability)\n", + "\n", + " if not prices:\n", + " return 0.0, 0.0\n", + "\n", + " total = sum(weights)\n", + "\n", + " weighted_prices = [price * weight / total for price, weight in zip(prices, weights)]\n", + "\n", + " return sum(weighted_prices).item()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "t_GHfTwHXD5f", + "outputId": "056b0fc2-5632-4be8-ee24-b6bcefe14ab9" + }, + "outputs": [], + "source": [ + "improved_model_predict(test[0][\"text\"], device=\"cuda\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 718 + }, + "id": "W_KcLvyt6kbb", + "outputId": "fba4200d-b911-467b-ab3c-17b78aa3b408" + }, + "outputs": [], + "source": [ + "Tester.test(improved_model_predict, test)" + ] + }, + { + "attachments": { + "0dcb25a7-83fa-4313-a94f-d3a56a0f07bc.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABBQAAALUCAYAAAC7J2ESAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAP+lSURBVHhe7N0FYBzXuYbhTxZLtmWZMdCgHUaHmTkNtKGG2hRvk6bNbdLblCGFNNQmbRpmZnCYmZkTx0ySxSztnffMjrtR1xjZFnxPO7E0O9od3nP++c85OamIzMzMzMzMzMyWQr/0v2ZmZmZmZmZmS8wBBTOzlaClpUWvv/66/v3vf+vjjz9Oz+2eZsyYoUsuuUSPP/54es7Sef7553XFFVfogw8+SM/p3ubMmaNbb71VN998c3pOfLz++Mc/6oknngg/W9e6++679cknn6R/M+t7ampq9MADD+iiiy5KzzEz6xnc5MHMvpSmpia98847oXJ8wAEHaNiwYelXbFHq6up03XXX6bzzztOf//xn7bvvvulX/hsV3EceeUQVFRXaaKONtOGGG6qsrCz9auzzzz/X008/rfr6eq2++urafffd0698eS+88IK++c1vhnU866yz0nOXHNtH5fyMM87QV7/61fTc/1ZbW6sbb7wxnFPIyclRUVGRBg8erPHjx2vVVVdVcXFxeG154lz+1a9+pfb29lDRBes2cODAsA1MAwYMCPMXh+DD7NmzQ2VhtdVWU2lpafqVhSPw8sorr6iysjI954t4H45vYWFhek7P941vfENf//rXtc8++6TnfFFzc7OmTJmit99+O+yXjo4ODRo0SOuuu67WW2899esXPx9hX3OtLGzfjRo1SptttlnYh0squbY4B9jva6yxRvqVGNcl98DPPvssnLucJ2uvvXa4VvPy8tJLLRzr+95776V/k3Jzc8N5Mm7cOE2YMEEjRoxIv6JwTr7//vshsMU+2HvvvcN10flznnvuOb311lsqKSnRpptuGt4HFPmqqqrCfmR/ch/ib/k89g3rzPqzP1knzsNNNtkk7GfWqzO2l/Vh/yzMDjvsoHXWWadLzleOxauvvqq5c+cqPz8/HEfWuby8PNwvFoZjx7aw3Quz6667hmNbUFAQluM+wL7KxGtsy4477pies3A33HBDuE9PnDgx3MMycc6wHdwftttuu7Dc1KlTQ9By0qRJ+vTTT9NLxvej/v37a5VVVgmfvzJw3syaNUsPPfSQ2tratOWW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g/Uh3mcQgXUm/nTrTOx4YZYbX4vBCdanGEjg6yi4Jt7M5wIKIiIiIiIiInL5FC4TERERERERkUJTQEFERERERERECk0BBREREREREREpNAUURERERERERKTQFFAQERERERERkUJTQEFERERERERECk0BBREREREREREpNL88h+e+iIiISJGRlpaGY8eOISAgANWqVfNs/WUdOXIE6enpKFeuHCIjIz1bRUREfJMCCiIiIl4qNzcXJ0+exOnTp3H27FnbFhgYiJIlS1pjOCwsDH5+fra9KFq7di2mTJmCMmXKYOzYsZ6t+c6dO4eEhAQkJibiQlWZSpUqISoqyvPo0p05cwYHDhxAlSpVfvA98X1s3LgRDz74IG677TbbJiIi4qs05EFERMQL5eTkYPfu3Zg0aRIee+wx3H333ejVqxf69euHl156CStWrLBG808p6v0NmZmZePfdd3HHHXega9eudmvevDlat26NTp06fb9t8eLFnmcUzqZNm3Drrbdi/fr1FpgRERGR/6SAgoiIiBfau3cvBgwYgLlz51pP+vTp0zF//nzrYWevOxvK+/bts2OzsrIskyEjI8OyGU6cOIHU1FTbx8yGU6dO2TYewyAEswOIPzksgTd3G7Gxz+cwqMHABB/z+dnZ2d+/Fn/yccHABd9HSkrK9/v5vJ8SEhKCgQMHWhYDPwtvN9xwA/r06YMFCxbY4y+++MKCAhyiUPBz8TPxccFAAe+775H3eRw/E49LSkqyn/w8Lh7H95qcnGz7LvReRUREvJUCCiIiIl5ozJgxNv8AAwhDhw7F9ddfj+rVq1uj+w9/+AOef/551K9f345dunSpbR8/frxlMTRu3Bh/+9vfrEE9depUtG3bFjVq1LDX4OsdPnzYAgEMMAwePBjDhg2z30UMCsyePRvt2rXD5s2bLQAxb948mwPh008/RZcuXVC7dm20b98en3/+uQUxiL9ryZIl9vvr1q1rWQazZs36yYY6hyBw6MbVV1/9/S0oKMiGJ5QtW9Yev/fee/jd736H4cOHW4ZGmzZt7DO++eablr3gBlT4u7/77jvExMRg1apVOHjwIPr27YujR4+iZ8+eqFq1Ku655x588803djwDDp999hnuu+8++w6ZJcHPXNSzOkRERK40BRRERES8DHv32TC+5ZZbLBDg7+/v2fNDBedPYCN6zpw51sPPhj4b4MxoeOaZZ6xRvWzZMgscsJH+wQcf2NwFhcGsAA61YCCDjXE23vl4z549tn/dunV4/fXXbbJDZlMMGTIEhw4dsiyDy8FMBQ794Ofi+7733ns9e35adHS0BVQqVKiAmTNnYufOnfaemjRpYvsZWNi1axceeOABvP/++6hTp47N9cC5FURERHyJAgoiIiJehsEBNuDdCQVdI0aMsCwFbu/cubMFDFzs1b/rrrvQo0cP1KxZE+XLl8fEiRNx++2345FHHsG1115rjfLu3bvbMIO4uDjPMy8NhygwM4JZAg0bNrR5HZjpwCEDzBD45JNPULp0afTu3duyG+68807LVuD7uByckJGfiUERNvwZJLgYrirB5zEQw++FEzsy0MEMCGL2A98fv69WrVrZd8RsCWZkiIiI+BIFFERERLyMOzdAiRIlfpCFwIAAe9rZs85Gc8FJGUuVKoUGDRogODjYnkdbt261oRDcx+O5r1GjRjZnALMgCoON86ZNm1qjnPfZSOfv4bAJDpNgEISrOVSuXNlWouBxvH/NNdd4XuHn4WvwxvfO33upq1q4x/Hn+d9jxYoVLYuB75HfC78fBhQYHBEREfElCiiIiIh4GTbW2SjnHADuHAXEuQAYIOAwCLe33cWGcXh4uOdRPk48yIZ4wcY0X5dzBfDG7e4+d/4A/iw42aGLx4WGhnoe5QcYuI3H8jmc8JANd2538T5/3+Xg7+RncLnv2f0M5P7+S8X3VPB9uQGHH/vcIiIi3kwBBRERES/Dnn4OUVi5cqX1/LsNXTbQ3QwBNoDP52YmEO9zIsUdO3ZYYMHF1SPYSGePPIdTcCgDMx3cbAeufHDkyBG7f74f+50uDiNwV01w8T6HRVwON4DgYnCB752fiZkWxAwJdy4HFwMsfF7BwIPrQp9DRETElyigICIi4mXYGO7fv7/1oo8ePdomUmRggJMccuLATZs2WWP6Qg1jvsaDDz6IRYsW2VwLDCRwFYaFCxfaHAgMNrBxzmyI+Ph4LF++3FZK4EoOixcv9rzKpeNcBAwgcMlHvj9OKsnX4WtfSfxcDF7ws/NzcaUHTgjJ1SwK4jE8lsM+mOnBpSeVgSAiIvJDCiiIiIh4oebNm+PZZ5+11RS4esNTTz2FgQMH2soKnLeAyyZy+MNPYTCCkyJ27NjRVjIYNGgQJkyYgNjYWHsu5xBgo7xDhw6oV6+eraDA5RnZOOekjoXFgAJfa9u2bXj66adtlQUuGVmrVi3PEVcG3zOXeuTylVxBgqtJMODiruDg4uSN3bp1s6DGgAEDMHLkSAuYiIiIyL/55Z2fxyciIiJegQ1yNoIPHDhgkyhyNQUOV+DKCVztgY1mDm3gsIINGzZYEOL8VRC4mgOzG1JTU214Q+3atS1g4K4ewTka+Dt4HOchYMYChxQwG6Jly5a2cgNff/Xq1bYUpTt3A98Pl6e87rrrbNJEDsPgcfxdSUlJiIiIsBUWODSB77lZs2b2vAtZunSprc7A1Rz4HrZs2WKZGHy/nEjRxdfk7+J+DtXgcxi4YFZE+/bt7fth4IHLRXJ5SA7F4DYOIzl+/LhlUnAeCn5WOnbsmB3L98uJLUVERHyFAgoiIiIiIiIiUmga8iAiIiIiIiIihaaAgoiIiIiIiIgUmgIKIiIiIiIiIlJoCiiIiIiIiIiISKEpoCAiIiIiIiIihQT8P975f48Hg5AkAAAAAElFTkSuQmCC" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image.png](attachment:0dcb25a7-83fa-4313-a94f-d3a56a0f07bc.png)" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 400K Sample Fine-Tuned Model" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000, + "referenced_widgets": [ + "dd1b57e03f2641d3b702f2cc66942b8f", + "e1d477dccbfc44a8a6da301486180e82", + "c312a5111a284c3db88f22290869c023", + "ce118d8b8146497f9c7fdd3b38188e72", + "bc46c271637341bb82d6b87df22ab2af", + "602adf3242f54731938b68d3cf68465e", + "39fae5e74834421795729a259a046fb8", + "0618d8626e2e46cb9a17f86444de3c48", + "1cd43b5b2fe445088c84e19773ad861e", + "f70a29870ab34f34a1900b2df2bf177e", + "41a96c5e35a44b898b872c189f531d3a", + "0a524a73d5d6478db81256371bf2bc9b", + "275f6179dc624bceaa5d0639fe0b1b00", + "79c41b26746344bc9a220f2376360110", + "287a6430766c44e5a71dda1048fa2a2c", + "3bbe1a454a854747a96fe83e91d6cb3c", + "8a93759afe21414fb0d6684f0a591d60", + "a3d76b3ce67a495db861bac80cfc0864", + "8fc794262ed14fc785c8f06e734c57d4", + "7dc967baa0e7427bb66cf3e26849d508", + "2d7a6dbd15304347a37dbfb6e5ec7203", + "288393e05947444bad11034071015baf" + ] + }, + "id": "Kl6n_0sAbU0g", + "outputId": "2fb53efb-da22-4c29-a594-c2cf5a079388" + }, + "outputs": [], + "source": [ + "FINETUNED_MODEL = \"ed-donner/pricer-2024-09-13_13.04.39\"\n", + "REVISION = \"e8d637df551603dc86cd7a1598a8f44af4d7ae36\"\n", + "fine_tuned_model = PeftModel.from_pretrained(base_model, FINETUNED_MODEL, revision=REVISION)\n", + "print(f\"Memory footprint: {fine_tuned_model.get_memory_footprint() / 1e6:.1f} MB\")\n", + "fine_tuned_model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 718 + }, + "id": "R0YlorBhbeSE", + "outputId": "f42de9bf-d45a-4d2d-c218-fe000d716e54" + }, + "outputs": [], + "source": [ + "Tester.test(improved_model_predict, test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "🎉 And there it is — the open-source, quantized, and fine-tuned model outperforms the rest. 🙌 \n", + "\n", + "📘 We'll continue in [the next notebook](https://github.com/lisekarimi/lexo/blob/main/09_part8_summary.ipynb) with a final wrap-up and summary of key insights.\n" + ], + "outputs": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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": 4 +} \ No newline at end of file diff --git a/week7/community_contributions/lisekarimi/09_part8_summary.ipynb b/week7/community_contributions/lisekarimi/09_part8_summary.ipynb new file mode 100644 index 0000000..f7983a4 --- /dev/null +++ b/week7/community_contributions/lisekarimi/09_part8_summary.ipynb @@ -0,0 +1,75 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "GHsssBgWM_l0" + }, + "source": [ + "# 🔍 Predicting Item Prices from Descriptions (Part 8)\n", + "---\n", + "- Data Curation & Preprocessing\n", + "- Model Benchmarking – Traditional ML vs LLMs\n", + "- E5 Embeddings & RAG\n", + "- Fine-Tuning GPT-4o Mini\n", + "- Evaluating LLaMA 3.1 8B Quantized\n", + "- Fine-Tuning LLaMA 3.1 with QLoRA\n", + "- Evaluating Fine-Tuned LLaMA\n", + "- ➡️ Summary & Leaderboard\n", + "\n", + "---\n", + "\n", + "# 🧪 Part 8: Summary & Leaderboard\n", + "\n", + "![](https://github.com/lisekarimi/lexo/blob/main/assets/09_ft_leaderboard.png?raw=true)\n", + "\n", + "# 🥇 The winner is the LLaMA 3.1 8B (4-bit) fine-tuned on 400K samples \n", + "\n", + "LLaMA 3.1 8B (4-bit) fine-tuned on 400K samples is outperforming even the big guy GPT-4o — with the lowest error and highest accuracy (75.6%).\n", + "\n", + "RAG + GPT-4o Mini also did well, proving that retrieval adds real value.\n", + "\n", + "On the other hand, traditional ML models and even human guesses, gave weaker results and fell behind the top models.\n", + "\n", + "💡 As we’ve seen, a **well-tuned open-source small model** can do amazing things on a focused task — sometimes even better than large, closed models.\n", + "It’s not about size — it’s about fit, focus, and fine-tuning.\n", + "\n", + "# ✨ Conclusion\n", + "What a journey! From classic ML to state-of-the-art LLMs, from embeddings to retrieval and fine-tuning — we explored it all to answer: who predicts prices best?\n", + "\n", + "Thanks for following along — see you in the next challenge! 🚀\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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": 4 +} \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/10_part1_ensemble_model.ipynb b/week8/community_contributions/lisekarimi/10_part1_ensemble_model.ipynb new file mode 100644 index 0000000..5635a9f --- /dev/null +++ b/week8/community_contributions/lisekarimi/10_part1_ensemble_model.ipynb @@ -0,0 +1,1126 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3ede0360-00f4-404e-b0d2-4a83cc385654", + "metadata": { + "id": "3ede0360-00f4-404e-b0d2-4a83cc385654" + }, + "source": [ + "🔗 Ensemble Model\n", + "---\n", + "We’ll reuse core components built earlier:\n", + "\n", + "- A fine-tuned LLaMA model\n", + "- An XGBoost regression model, stored in Hugging Face\n", + "- A ChromaDB vector store, stored on Google Drive and also available on AWS S3\n", + "- A GPT-4o mini + RAG pipeline\n", + "\n", + "We'll run all three models on the same test data, gather their predictions, and train a Linear Regression Ensemble. The ensemble learns how to combine these predictions to output a more accurate final price.\n", + "\n", + "Once trained, we'll save the ensemble as ensemble_model.pkl, ready for later use.\n", + "\n", + "- 🧑‍💻 Skill Level: Advanced\n", + "- ⚙️ Hardware: ⚠️ GPU required (use Google Colab)\n", + "- 🛠️ Requirements: \n", + "\n", + " - 🔑 Hugging Face Token and OpenAI Key — must be set in Google Colab secrets or .env files if you are running with your own GPU\n", + " - completion of Part 9 of [this series of notebooks](https://github.com/lisekarimi/lexo)\n", + "- 🎯 Task: Train and save the Ensemble Model\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mzYB4XYQeWRQ", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mzYB4XYQeWRQ", + "outputId": "f474ce9b-09fb-4a47-93d7-273fe2d2ba10" + }, + "outputs": [], + "source": [ + "# Install required packages in Google Colab\n", + "%pip install -q tqdm huggingface_hub numpy sentence-transformers datasets chromadb xgboost peft torch bitsandbytes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3caecd1-8712-4acd-80b5-e8059c16f43f", + "metadata": { + "id": "b3caecd1-8712-4acd-80b5-e8059c16f43f" + }, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import re\n", + "import zipfile\n", + "import chromadb\n", + "import joblib\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "import torch\n", + "from datasets import load_dataset\n", + "from google.colab import userdata\n", + "from huggingface_hub import HfApi, hf_hub_download, login\n", + "from openai import OpenAI\n", + "from peft import PeftModel\n", + "from sentence_transformers import SentenceTransformer\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics import r2_score, mean_squared_error\n", + "from sklearn.metrics import r2_score\n", + "from tqdm import tqdm\n", + "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05d9523f-b6c9-4132-bd2b-6712772b3cd2", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "05d9523f-b6c9-4132-bd2b-6712772b3cd2", + "outputId": "7077320e-43e2-4b03-ca7d-e7ea9a3407f8" + }, + "outputs": [], + "source": [ + "# Mount Google Drive to access saved ChromaDB and XGBoost model files\n", + "\n", + "from google.colab import drive\n", + "drive.mount(\"/content/drive\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "z9735RD_TUHw", + "metadata": { + "id": "z9735RD_TUHw" + }, + "outputs": [], + "source": [ + "# Load from Colab's secure storage\n", + "\n", + "openai_api_key = userdata.get(\"OPENAI_API_KEY\")\n", + "openai = OpenAI(api_key=openai_api_key)\n", + "\n", + "hf_token = userdata.get(\"HF_TOKEN\")\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "DtswsfBQxxJF", + "metadata": { + "id": "DtswsfBQxxJF" + }, + "outputs": [], + "source": [ + "# Configuration\n", + "\n", + "HF_USER = \"lisekarimi\"\n", + "ROOT = \"/content/drive/MyDrive/snapr\"\n", + "os.makedirs(ROOT, exist_ok=True)\n", + "\n", + "api = HfApi(token=hf_token)\n", + "REPO_NAME = \"smart-deal-finder-models\"\n", + "REPO_ID = f\"{HF_USER}/{REPO_NAME}\"" + ] + }, + { + "cell_type": "markdown", + "id": "qByarIFiTYa1", + "metadata": { + "id": "qByarIFiTYa1" + }, + "source": [ + "### 📥 Load Test Dataset" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9ca3e34", + "metadata": {}, + "outputs": [], + "source": [ + "# #If you face NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported run:\n", + "# %pip install -U datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0eKakxSFTVcA", + "metadata": { + "id": "0eKakxSFTVcA" + }, + "outputs": [], + "source": [ + "DATASET_NAME = f\"{HF_USER}/pricer-data\"\n", + "dataset = load_dataset(DATASET_NAME)\n", + "test = dataset[\"test\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cWqvs8JRTggE", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 110 + }, + "id": "cWqvs8JRTggE", + "outputId": "bf7f0113-de82-422a-aaec-54efbb2b9d16" + }, + "outputs": [], + "source": [ + "# Format description function (no price in text)\n", + "def description(item):\n", + " text = item[\"text\"].replace(\n", + " \"How much does this cost to the nearest dollar?\\n\\n\", \"\"\n", + " )\n", + " text = text.split(\"\\n\\nPrice is $\")[0]\n", + " return f\"passage: {text}\"\n", + "\n", + "\n", + "description(test[0])" + ] + }, + { + "cell_type": "markdown", + "id": "alpkYSc2UX0n", + "metadata": { + "id": "alpkYSc2UX0n" + }, + "source": [ + "### 📥 Load Models and ChromaDB" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "pjPBEgXqmHOA", + "metadata": { + "id": "pjPBEgXqmHOA" + }, + "outputs": [], + "source": [ + "# ChromaDB\n", + "\n", + "CHROMA_PATH = f\"{ROOT}/chroma\"\n", + "COLLECTION_NAME = \"price_items\"\n", + "CHROMA_ZIP_URL = \"https://aiprojects-lise-karimi.s3.eu-west-3.amazonaws.com/smart-deal-finder/chroma.zip\"\n", + "\n", + "# Download and unzip if CHROMA_PATH doesn't exist\n", + "if not os.path.exists(CHROMA_PATH):\n", + " os.makedirs(CHROMA_PATH, exist_ok=True)\n", + " r = requests.get(CHROMA_ZIP_URL)\n", + " with open(\"/tmp/chroma.zip\", \"wb\") as f:\n", + " f.write(r.content)\n", + " with zipfile.ZipFile(\"/tmp/chroma.zip\", \"r\") as zip_ref:\n", + " zip_ref.extractall(CHROMA_PATH)\n", + "\n", + "client = chromadb.PersistentClient(path=CHROMA_PATH)\n", + "collection = client.get_or_create_collection(name=COLLECTION_NAME)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fi1BS71XCv1", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 337, + "referenced_widgets": [ + "c60f1153084a493ea31fac10bf986aef", + "6de41ac188dd48aea5d30a90bc52c38c", + "d2b4cdcaef6a4c41972f8c96af2814ab", + "2180dfb4e6e74df5bf9985c481b6e420", + "dcff84c8c3bf4f4bae334e0484207d10", + "ca1ed709ecaa4a0e8ac96ffb930e6613", + "e5297e7d36334c57aece043f62c79841", + "5fdca4e0987a4788983c418941711d7e", + "200e8e9b0df84affa177567243bf18d1", + "ef6e6dcff8b444bba62c1f76e1127d7c", + "7c94357c0d4e444489e8d47d2151437b", + "4ffdcd2ec96046ffb5121def27c95c9d", + "dd47ad1efe46496cb096a7714cf27c19", + "194ad4f8707b4d288e88cdbdfa33605d", + "c8a05ae3f5854f24998cc615a8849c88", + "b5ec411e72a946f8b4a470de5827c949", + "1a0be25b030d43858cee804da65d67a1", + "88d1f6a56f9b4a50854aee82c0945cc9", + "73e5967ae96942e080f3b05638583bc8", + "8434bfa06abf42c98e8ffb0e7b83c9f9", + "43d872e632da4d9883ea3d71dc91bdf9", + "86729f54df1b4967b2730b48f84a98aa", + "83fcebcf2b2c4213835334a998ba91e9", + "4ef06b10bfcb418d85534a8b73688eff", + "88c466cc89234d8f9f21147882fc5faf", + "f87e958c639544c0b925646fc28c4604", + "a52988b97dff4759a456398ecea1eaaf", + "c1116a13be86401bbbf6e51de0df7d12", + "d6ed27ce322748d29ed864808f619ee3", + "4a6fbedd3333496081695800cae8bdda", + "a7badc083fb34e69bd6f27bc9a805e7b", + "a78bcdbac2f74c72938d87c431f23e78", + "1d627cf1043642a3815a2902f65b4ded", + "3b8cc480ded24f66b03779fd25844670", + "0ce0073368c64339b3c1f960861e4b56", + "ffc973a4347943ebaa4ead16e04c05f6", + "aafba411ee984946a3ec0760580b60b6", + "0dd2501d917f48739b2817d598541660", + "213ca3afc47945a68e28a6ae005c3b7d", + "6355e004d7c34b969b2d2c6ccbc12620", + "9359b873cb4a4187b67a1732d78c7534", + "32f86a2b9e0547a6bc0a523ca3cfa088", + "0f446cb8ee3147438ef1e98e665a2831", + "64bb7ebae66d42f2a4d6a3039bf67d4b", + "e2b51ee511234ff2bc2cf33227fe2088", + "a76d3def06db41fab4ab2f077839d5bc", + "fa9598b858c14024aaf15d1417e9683d", + "df0bb9a9635643ebb679e115f45dde8e", + "527c4d1987334e3e9b2aa0de7d0527a7", + "0c6a889a9066484abbcb87b730d7e325", + "80a1f4c902154f2184c38ef844a1cca7", + "463c3cc65cd343108fe6049e4cde7142", + "fb015ce2fd9b48d79db67f80181964b7", + "07f46375dc594cd19ac5ab983083b2de", + "451ca5f213544cc8b24de6b7d55602fc", + "5bb2e645ea7741839e0f88ae484d94d2", + "19d1353070f643e08364500e9b1c30e6", + "fff94d7934cc4793876903d1c18efbfa", + "f0413b6310ef4510bf493e6814fa162d", + "a97c1662e64c44ee9f6e5be5617c07ec", + "da02a5ab5fe44cc297ab3048509a99e1", + "ee8c23aa2ca84b32a02a2500917559d8", + "6635ef559f72485e9453f87b3921f954", + "d9f2925a563d4d9fa332c15205f44d9b", + "73ec7891d53149e7a072a0e310716178", + "f7309076b36e4224acc42ade5d09bf37", + "cd53294ff44e4955afbfbd4660563b58", + "2ae42eb6385f43fab59f2bb56bb8a28e", + "fc0f1abaaf054d0d93a27c7ee0f6630d", + "c7a61078596c475784307480d26e3661", + "5bd26e4ff28f4639b52aab848ada03d1", + "ce710ef5ffa14cfe9842c63caebc81e5", + "63061726d47940c395a00d5d01556f4f", + "2b41598231d14f3ca6354c9543ec4351", + "0df33079f63c45d39de21439289aa4a8", + "8cc5d2eac9a64d68b72608bb5ae44c89", + "dd33a409204c4610a08e44c3e82e00da", + "b96b7ac71a6c48a9a6c888f2f34efea5", + "794d71dd5b734a3cb5607fc31aaddd18", + "0f6e7a2d9b8846178a7492e137d83bba", + "657bb839f0ea40eb9873385cecd06fd0", + "1ac174e8904943bb9a5e5483e58eef63", + "a1c9714fc4ea48af83669481e89c58c7", + "763a2d64c8e94ca1b0289264d9f868bc", + "ef78cf15ab914b3fa95ff95a86ec7a99", + "24350ebdc38a41e689f3e3b09dfc3e35", + "b8131b3c4c4c4b20809af9b0e91dd006", + "420c50ed8abe49ec9f4f2777e6cd2749", + "fc3f2d2c33ee40f8850710c2f4ce331f", + "90730ec699e84ddda2af799f8220e7a5", + "01f1c4b3b434474dbf2212a05869354d", + "912d6c1687324bb9b334bbf98a2b5b30", + "dc4106a0020b4b9fa21cd12a44967f2e", + "0084e537ffa74ab4a6d5f307b0916d2c", + "0edeb9ca771c4ca2a9a678e0e8a91614", + "b610d515ddb4405695e6972e45463194", + "4af72cb05f284d42bca73fcb88904255", + "86f34fb6325e4e878eee0be27946c88b", + "bfc26f456f1d440bb80eedac1cb14967", + "1f005c3cf7594275a37bb937a3c33db3", + "4347e7d3db4d4cc3836a4e69db032f27", + "809a4d0270dd4c05817ea224bb78ff5a", + "b403a344e84342e4b076e64e829d7354", + "6b3cbb0ac0b14e3fa193cd5cb3f8f521", + "2d06aaf8d15b456b8fadeb54dd2ea73d", + "74842e94dda648d18cd055220a3d2b39", + "5a3818bde07841fbb6077bf20b7dec4b", + "2a5224c8b3004d249a07297a2111493f", + "ff02ac7f08974426b3f70b71e59ed5bb", + "0dd550d3e39f42809fa16770231af7e5" + ] + }, + "id": "8fi1BS71XCv1", + "outputId": "9256b509-1371-4bb3-bd84-98bb75725ac3" + }, + "outputs": [], + "source": [ + "# Embedding Model\n", + "\n", + "embedding_model = SentenceTransformer(\"intfloat/e5-small-v2\", device=\"cuda\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "zmwIbufXUzMo", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 483, + "referenced_widgets": [ + "36b26207185e4e10a8c60f0f5918aa7c", + "96a0c5044c824968a701e20319c8d037", + "a567759a6e554c2eb9334559e880a56e", + "dcc68ce908ac4cfc9ffdcd0333cce14b", + "06d7ac4abde74e1496ef80b9e22cd148", + "94ba3ecd90f84291a46462a51ba001b8", + "00b94b9d1e4e4e428c7467b4f99e45af", + "02219374302849bd93d7aba7f65ee42b", + "82223db2023045e88dc3d9652bc6b183", + "6e08a796d2c440c58d5e6bb20f39be16", + "6ac04725da4f485f8d7efd738de0940a", + "230a6add3adb4dbd9f0329412e3f1455", + "db5f777e8ec143fe89a2e6296031c9c2", + "4f87c3aba240471d96349a037777732e", + "74b04b71ce0746a89d146c4044c85890", + "582e3cd91e3048639ab48492b5ca4b15", + "1d8e31a4418c49e0bfa28b399673f718", + "ec17f9e6bbbc4584baf11c0e7c504f84", + "19779fea3c8c4a5cbea953b059775110", + "3c82450a6db649f59f36668d5521d203", + "3447d41776ef406bbfbe3e6c277b82d2", + "4195859f8457499ba8e61a9f1662931c", + "6f80cc0bed9b42e89f9691675ff5a484", + "dc39eee63325479a915101649ab04273", + "99e1e2c842f845d1b2ded34736b60ad7", + "20ff78d4df09401d8aee462b57c57a48", + "1aff04abbd0b4f15bd58154b00591264", + "9cf024b488154926861d695137268da1", + "6470d6b03e3548d783ed252d128ec361", + "230a79f3d05d4c9eac73ae6962cb5d2d", + "adfe1cc7a6f94b0ab43170c75688374d", + "b6d24621c29f4352862f37ae69f2d6ad", + "303a6f79669e40d98ed2998f4f5e47cc", + "b737799377c948a99edf34c014a105c4", + "daf9616a687f406da1d9ee2bd147c850", + "cfd34b617326486498a916531bae9a87", + "201ea14e31a244a3aa2aeed2c12fb255", + "8454d5f263eb45daa0e6f7db6aa3f92d", + "f9787ee50d634421ae5f0325126dcb73", + "c2200daaf2994ed9ae16587d8d52236c", + "93a0ec9723074e9199d1f9db988c30dc", + "b1cb687d58ba40f49961d5485a466ef7", + "ccc580852d66401993d675c254832379", + "7321b89aea1c4746901ef40548bcf056", + "8fae24599e174689adbaa52a16270785", + "01605d6fb53d4e56aca9a746b2c75566", + "45cb352704fe41f1be0f01c61511323d", + "881550789f4845dda8561f6b26aff204", + "654bf64ec165449993b195209d75f4ba", + "9eaa6e09335047d5987c0a6528d5e77e", + "39331a837a644795bada1e2b034fe14d", + "a339562553394755811bb7077a81843d", + "4f58f5fa385f44e0ae09e2019294d597", + "431cc587951845d6af39f3e4ab0f2f76", + "ac879c2c923b423dabd6d0d60b12266d", + "4a3eb0fc1d2d4606a8acb382085a57af", + "f82bbcbd14ad48a78ebdfdfb43916bd1", + "a634449526034dbdb945c4905f4edeba", + "da4133a915ad4d449876a43468203842", + "a56f3a61d1ba4011ab6fce4067fa8418", + "46727d5afdf7487fb073e7e2d25cc75d", + "1480c5a1a0ad4151a12d47bc22685f04", + "5720fc31c90344908d9eeb49fe83df1b", + "47bd422d424a47e48edd304773162082", + "6a68ecb89be34255a0e0fc6db41c1f4d", + "12b1b3c7f0914030ad756b676cc97962", + "780f5b6ad91142f991a936b55219f61d", + "45723f91352b49688469a95e7f47aa9d", + "90bbf502500340a1993a957c27ad3d33", + "dcbb25b2a082476d905bcf124a849322", + "38e6bd6d64b54f9a8cdb4f40eaf41cde", + "7544a101cad94a15a2f4eb5639d22525", + "501184a0fc424a02a80aecd3f62fb9fd", + "1cbf5d28bced46ac8712a4609b5a5867", + "9ba6ecc0a422472681d8e61bdb32f87b", + "8383700148dd44538ed81ec5a261b7b5", + "740e930ff17c4f668818a8c762a5470e", + "0d995d8da0464c9ca7b1b444c22de025", + "bc8a5e6d27ba402996434f00918c8b0e", + "75f225b1a6f845148361b029878b63ea", + "c16b051d3cb44607b339770f5f8b6f2e", + "7857ed1e0b0f45bdb48269fbad68653d", + "e65ffc77bd6740c7924aa5b93297cb89", + "3ba97a41b4654dc0bb9bcaaa685b4518", + "6504931865a74cb5a80f2ac60da47430", + "ff8d5791b13c440d81312a6b96c9592f", + "c31bd8cb693b4e248a29f2ded032fb70", + "c25b1a42547a422ba7597c99ca4ce249", + "5c6338fcad9344e092f5077bf73c4910", + "dca176a7a6ea4fe9b025f851976f436a", + "611fc076771a4fcca5c46367b711d61a", + "0cfde45e26cf4c05b67755c2274f2df8", + "5d572d2f46ea484587e085c29318b616", + "8ad59c1261844a06b7abecebd7b60377", + "82d610cd077c47bd9efd609f2399c861", + "07fd58c9d07144a7a0aacab6b8252125", + "aa0932b4e66b4f33ba9f5237ea1470da", + "0d867615a23a42988bb91b4f0d0cc942", + "9c28ff7b0f5c421390ac1ccb899f093f", + "0645e7ed6593410eaf9c9c0b25158667", + "ca68b1dc60a343f9bd7298a63cadd556", + "9597ec6b495c4298b87967ed3e4044db", + "d7dad0ae58814124af1e92a078122736", + "173575b8b5254537937206759d6b6262", + "d1efdc10d36441d88cf7705e846bfbef", + "3550d450f95f40eeae0c0d559ae9f4de", + "773df79ed7b44f698cce98ca9ed802cc", + "24a2b4b88e1d46488eabb9101536beac", + "0d61c01e6cdf445b9474f9d759676edd", + "9b3505aacd164a19b45aba89eee46378", + "bd6fb8b066be46aaa7d457bf89257e54", + "f1eca4e5d600407885264d340b4f47a7", + "ef1e6a69995845e09781f76a38fced30", + "c5f50067867a40b99cb9f312e8adc49f", + "4e9cf63dbef041aba2c7f0b9c74466c8", + "07baa025b3a14bf89d6f6b438b695bbd", + "fb8609ef5b8d4653b25e52f853b7be1f", + "2f90ac58752347319d1203b5e8765c0e", + "d9815cabf324472a8eab585afabfa47e", + "120687e04065424595571941d816a134", + "a6d09159931f4d3d91a0647d9fa9d8ba", + "833c755f7bf9479abeef0041a82a92ba", + "56d848676e644c739e28730af99d69c6", + "39654eca8add4c09815cb3e6a45616ec", + "02aa70e064744a29af0a68aaca33c741", + "7fd83f95cfef4b1dbd881be7083d7455", + "cdf56625053b417fad2e64a0bed6725b", + "4199341c09bd46fab8a3b649d0c8af7a", + "334e67f38b8243aa9072f52a32e46080", + "492cdb40ffbf444d8e256875663fc598", + "655c6e0f21ff4e9db7f35522355d847c", + "926c1be6e26f4d9eba332881f975ed38", + "47641f7363be4252b9f5e53846bee057", + "887f8a2b268541eab71804a44ba1479b", + "5b6e78d1727e473ab3b66d6ff042aeca", + "acc60a1210104049983341db3010be0a", + "c028c37980e14b3ea07b1da6f558651e", + "9d1085906e3548078e5e393a86337c3e", + "259c86a51f4e4cab9648cc603fc25c7e", + "8ce05076e77643a88b062687e2b24493", + "8b3b7f947f4d4401bbca47d5720f7450", + "9bf9dccee248425da698dbb4526fcad9", + "b991477124184bf3b4397762649a6596", + "fb139bcae29f49778bf172eb503c0668", + "93ba52daa9aa4dee8da91bba6c7d0269", + "fefedf36efc94ed287bdeceae698d5b5", + "8288b87b06b34ba4b2c7a343d6cea827", + "5a85d212a6b5468fbc10e6aeb0ad8bee", + "22274b08e14c4c77a6223131779f6f48", + "edc0e436da954a33bbea8e80629eb43c", + "1d9b1c594680467f9c8a6682d8aeb2e7", + "d82f940e0a8a478e8b1ee8f169f798fc", + "ab1616f507594b27b898ede4504b4e39", + "1fed11f1c7484251a2a7400627ad5f6a" + ] + }, + "id": "zmwIbufXUzMo", + "outputId": "2acb6897-4c41-4447-e029-ffcc1b3b4da1" + }, + "outputs": [], + "source": [ + "# Fine Tuned Llama Model\n", + "\n", + "BASE_MODEL = \"meta-llama/Meta-Llama-3.1-8B\"\n", + "FINETUNED_MODEL = \"ed-donner/pricer-2024-09-13_13.04.39\"\n", + "REVISION = \"e8d637df551603dc86cd7a1598a8f44af4d7ae36\"\n", + "\n", + "# Quantization config (4-bit)\n", + "quant_config = BitsAndBytesConfig(\n", + " load_in_4bit=True,\n", + " bnb_4bit_use_double_quant=True,\n", + " bnb_4bit_compute_dtype=torch.bfloat16,\n", + " bnb_4bit_quant_type=\"nf4\",\n", + ")\n", + "\n", + "# Load tokenizer\n", + "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)\n", + "tokenizer.pad_token = tokenizer.eos_token\n", + "tokenizer.padding_side = \"right\"\n", + "\n", + "# Load base model\n", + "base_model = AutoModelForCausalLM.from_pretrained(\n", + " BASE_MODEL, quantization_config=quant_config, device_map=\"auto\"\n", + ")\n", + "\n", + "# Load fine-tuned model\n", + "fine_tuned_model = PeftModel.from_pretrained(\n", + " base_model, FINETUNED_MODEL, revision=REVISION\n", + ")\n", + "\n", + "# Align generation config\n", + "fine_tuned_model.generation_config.pad_token_id = tokenizer.pad_token_id\n", + "\n", + "print(f\"Memory footprint: {fine_tuned_model.get_memory_footprint() / 1e6:.1f} MB\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0IHiJNU7a4XC", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 49, + "referenced_widgets": [ + "0264a3987fbf4040860ffa3fc47940d8", + "06d1db35940b469797c39c653741ea36", + "84c4d2fdaf734a559ee3eee09f1be295", + "fddde0bfed544b18ba39bfaa40eb9e1b", + "d40cc525cc28416cad4a45b3631798c9", + "e1372af176154902b1f555f30c28c007", + "5a1352c5ceb84320b14353b7aa21650d", + "522d0ed9e705457e9c72d276e2a26dbd", + "4de73aa76f044811990c379737a8e5c0", + "9305e96697ab4854ac89a6636991101d", + "b00e41d1051340fd904ba719111a907d" + ] + }, + "id": "0IHiJNU7a4XC", + "outputId": "c68bc44e-6b15-46c3-c8d9-3f256f368317" + }, + "outputs": [], + "source": [ + "# XGBoost Trained Model\n", + "\n", + "MODEL_FILENAME = \"xgboost_model.pkl\"\n", + "model_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_FILENAME, token=hf_token)\n", + "xgb_model = joblib.load(model_path)" + ] + }, + { + "cell_type": "markdown", + "id": "76BhcPjWa6C5", + "metadata": { + "id": "76BhcPjWa6C5" + }, + "source": [ + "### 📊 Model prediction collection" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "LgGmUKJxayZ6", + "metadata": { + "id": "LgGmUKJxayZ6" + }, + "outputs": [], + "source": [ + "def extract_tagged_price(output: str):\n", + " \"\"\"Extracts a float price from a string based on 'Price is $' keyword.\"\"\"\n", + " try:\n", + " contents = output.split(\"Price is $\")[1].replace(\",\", \"\")\n", + " match = re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", contents)\n", + " return float(match.group()) if match else 0.0\n", + " except Exception:\n", + " return 0.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ggKf1nSQbAnv", + "metadata": { + "id": "ggKf1nSQbAnv" + }, + "outputs": [], + "source": [ + "def ft_llama_price(description: str):\n", + " prompt = (\n", + " f\"How much does this cost to the nearest dollar?\\n\\n{description}\\n\\nPrice is $\"\n", + " )\n", + " inputs = tokenizer(prompt, return_tensors=\"pt\").to(\"cuda\")\n", + "\n", + " outputs = fine_tuned_model.generate(\n", + " **inputs, max_new_tokens=5, num_return_sequences=1\n", + " )\n", + "\n", + " result = tokenizer.decode(outputs[0])\n", + " price = extract_tagged_price(result)\n", + " return price" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "_cWyYUd4Ub-K", + "metadata": { + "id": "_cWyYUd4Ub-K" + }, + "outputs": [], + "source": [ + "def xgboost_price(description: str):\n", + " vector = embedding_model.encode([description], normalize_embeddings=True)[0]\n", + " pred = xgb_model.predict([vector])[0]\n", + " return round(float(max(0, pred)), 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3Skod8juXgnN", + "metadata": { + "id": "3Skod8juXgnN" + }, + "outputs": [], + "source": [ + "def gpt4o_price(item):\n", + " def get_embedding(text):\n", + " return embedding_model.encode([text], normalize_embeddings=True)\n", + "\n", + " def find_similars(text):\n", + " results = collection.query(\n", + " query_embeddings=get_embedding(text).astype(float).tolist(), n_results=5\n", + " )\n", + " docs = results[\"documents\"][0]\n", + " prices = [m[\"price\"] for m in results[\"metadatas\"][0]]\n", + " return docs, prices\n", + "\n", + " def format_context(similars, prices):\n", + " context = (\n", + " \"To provide some context, here are similar products and their prices:\\n\\n\"\n", + " )\n", + " for sim, price in zip(similars, prices):\n", + " context += f\"Product:\\n{sim}\\nPrice is ${price:.2f}\\n\\n\"\n", + " return context\n", + "\n", + " def build_messages(description, similars, prices):\n", + " system_message = (\n", + " \"You are a pricing expert. \"\n", + " \"Given a product description and a few similar products with their prices, \"\n", + " \"estimate the most likely price. \"\n", + " \"Respond ONLY with a number, no words.\"\n", + " )\n", + " context = format_context(similars, prices)\n", + " user_prompt = (\n", + " \"Estimate the price for the following product:\\n\\n\"\n", + " + description\n", + " + \"\\n\\n\"\n", + " + context\n", + " )\n", + " return [\n", + " {\"role\": \"system\", \"content\": system_message},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " {\"role\": \"assistant\", \"content\": \"Price is $\"},\n", + " ]\n", + "\n", + " docs, prices = find_similars(description(item))\n", + " messages = build_messages(description(item), docs, prices)\n", + " response = openai.chat.completions.create(\n", + " model=\"gpt-4o-mini\", messages=messages, seed=42, max_tokens=5\n", + " )\n", + " reply = response.choices[0].message.content\n", + " return float(\n", + " re.search(r\"[-+]?\\d*\\.\\d+|\\d+\", reply.replace(\"$\", \"\").replace(\",\", \"\")).group()\n", + " or 0\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "98bf0aed", + "metadata": {}, + "source": [ + "### ✂️ Split dataset and process" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8XQK5yrk8On4", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8XQK5yrk8On4", + "outputId": "ec379798-8b73-4e66-a517-a818845c8353" + }, + "outputs": [], + "source": [ + "print(\"Splitting entire dataset...\")\n", + "np.random.seed(42)\n", + "all_indices = list(range(len(test)))\n", + "np.random.shuffle(all_indices)\n", + "\n", + "train_split_size = int(0.8 * len(all_indices))\n", + "train_indices = all_indices[:train_split_size] # 80% of total\n", + "test_indices = all_indices[train_split_size:] # 20% of total\n", + "\n", + "train_indices = train_indices[:250] # First 250 from training split\n", + "test_indices = test_indices[:50] # First 50 from testing split" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "XN7P5fkkXfgP", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XN7P5fkkXfgP", + "outputId": "69f9d265-a402-48ab-a91e-8c6032ea4118" + }, + "outputs": [], + "source": [ + "# Process subset of TRAINING data\n", + "ft_llama_preds_train = []\n", + "gpt4omini_preds_train = []\n", + "xgboost_preds_train = []\n", + "true_prices_train = []\n", + "\n", + "for i in tqdm(train_indices):\n", + " item = test[i]\n", + " text = description(item)\n", + " true_prices_train.append(item[\"price\"])\n", + " ft_llama_preds_train.append(ft_llama_price(text))\n", + " gpt4omini_preds_train.append(gpt4o_price(item))\n", + " xgboost_preds_train.append(xgboost_price(text))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1_6_atEgHnFR", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1_6_atEgHnFR", + "outputId": "956e4dcb-2300-44ab-a66b-9b1254216762" + }, + "outputs": [], + "source": [ + "print(\"True Prices:\", true_prices_train)\n", + "print(\"FT-LLaMA Predictions:\", ft_llama_preds_train)\n", + "print(\"GPT-4o-mini Predictions:\", gpt4omini_preds_train)\n", + "print(\"XGBoost Predictions:\", xgboost_preds_train)" + ] + }, + { + "cell_type": "markdown", + "id": "ygJsuvtLtOdR", + "metadata": { + "id": "ygJsuvtLtOdR" + }, + "source": [ + "Example :\n", + "- True Prices: [245.0, 24.99, 302.4, 737.0, ...]\n", + "- FT-LLaMA Predictions: [99.0, 53.0, 550.0, 852.0, ...]\n", + "- GPT-4o-mini Predictions: [179.99, 97.0, 348.0, 769.0, ...]\n", + "- XGBoost Predictions: [220.19, 59.85, 254.29, 335.76, 165.04, ...]" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "tYWMhTrXcA7x", + "metadata": { + "id": "tYWMhTrXcA7x" + }, + "outputs": [], + "source": [ + "# Create features for TRAINING data\n", + "maxes_train = [\n", + " max(a, b, c)\n", + " for a, b, c in zip(ft_llama_preds_train, gpt4omini_preds_train, xgboost_preds_train)\n", + "]\n", + "means_train = [\n", + " np.mean([a, b, c])\n", + " for a, b, c in zip(ft_llama_preds_train, gpt4omini_preds_train, xgboost_preds_train)\n", + "]\n", + "\n", + "# Create TRAINING dataframe\n", + "X_train = pd.DataFrame(\n", + " {\n", + " \"FT_LLaMA\": ft_llama_preds_train,\n", + " \"GPT4oMini\": gpt4omini_preds_train,\n", + " \"XGBoost\": xgboost_preds_train,\n", + " \"Max\": maxes_train,\n", + " \"Mean\": means_train,\n", + " }\n", + ")\n", + "\n", + "y_train = pd.Series(true_prices_train)" + ] + }, + { + "cell_type": "markdown", + "id": "e1682cf0", + "metadata": {}, + "source": [ + "### 🏋️Train the Ensemble Model" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "-WsFABEicOyo", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-WsFABEicOyo", + "outputId": "42ae6421-fb4e-4ae6-ab54-b075e311b94d" + }, + "outputs": [], + "source": [ + "np.random.seed(42)\n", + "lr = LinearRegression()\n", + "lr.fit(X_train, y_train)\n", + "\n", + "# Print feature coefficients\n", + "feature_columns = X_train.columns.tolist()\n", + "for feature, coef in zip(feature_columns, lr.coef_):\n", + " print(f\"{feature}: {coef:.2f}\")\n", + "print(f\"Intercept={lr.intercept_:.2f}\")" + ] + }, + { + "cell_type": "markdown", + "id": "GnYPOslHFgGx", + "metadata": { + "id": "GnYPOslHFgGx" + }, + "source": [ + "- FT_LLaMA: 0.52\n", + "- GPT4oMini: 0.17\n", + "- XGBoost: -0.31\n", + "- Max: 0.45\n", + "- Mean: 0.13\n", + "- Intercept=-6.06\n", + "\n", + "---\n", + "FT_LLaMA is the most influential model in the ensemble.\n", + "\n", + "Max prediction also has strong positive impact.\n", + "\n", + "GPT4oMini and Mean contribute less, but still add value.\n", + "\n", + "XGBoost has a negative coefficient, acting as a counterbalance.\n", + "\n", + "\n", + "Overall: FT_LLaMA leads, max adds value, XGBoost corrects for overestimation—resulting in a balanced ensemble." + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "wyx39HEL9niI", + "metadata": { + "id": "wyx39HEL9niI" + }, + "source": [ + "### 🔮 Prediction" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "W3F0nNBXlrUJ", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "W3F0nNBXlrUJ", + "outputId": "1dbd9702-50cf-4d80-b8ab-9b2000dd3b10" + }, + "outputs": [], + "source": [ + "# Process subset of TEST data\n", + "ft_llama_preds_test = []\n", + "gpt4omini_preds_test = []\n", + "xgboost_preds_test = []\n", + "true_prices_test = []\n", + "\n", + "print(\"Processing TEST data (50 items)...\")\n", + "for i in tqdm(test_indices):\n", + " item = test[i]\n", + " text = description(item)\n", + " true_prices_test.append(item[\"price\"])\n", + " ft_llama_preds_test.append(ft_llama_price(text))\n", + " gpt4omini_preds_test.append(gpt4o_price(item))\n", + " xgboost_preds_test.append(xgboost_price(text))\n", + "\n", + "# Create features for TEST data\n", + "maxes_test = [\n", + " max(a, b, c)\n", + " for a, b, c in zip(ft_llama_preds_test, gpt4omini_preds_test, xgboost_preds_test)\n", + "]\n", + "means_test = [\n", + " np.mean([a, b, c])\n", + " for a, b, c in zip(ft_llama_preds_test, gpt4omini_preds_test, xgboost_preds_test)\n", + "]\n", + "\n", + "# Create TEST dataframe\n", + "X_test = pd.DataFrame(\n", + " {\n", + " \"FT_LLaMA\": ft_llama_preds_test,\n", + " \"GPT4oMini\": gpt4omini_preds_test,\n", + " \"XGBoost\": xgboost_preds_test,\n", + " \"Max\": maxes_test,\n", + " \"Mean\": means_test,\n", + " }\n", + ")\n", + "\n", + "y_test = pd.Series(true_prices_test)" + ] + }, + { + "cell_type": "markdown", + "id": "mVn6AAGq96wm", + "metadata": { + "id": "mVn6AAGq96wm" + }, + "source": [ + "### 🧪 Evaluation" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "y25l8rR791wG", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "y25l8rR791wG", + "outputId": "0a02a620-eb0d-46a6-8f54-1046c2394ab3" + }, + "outputs": [], + "source": [ + "# Evaluate on the test set\n", + "print(\"Evaluating model...\")\n", + "y_pred = lr.predict(X_test)\n", + "r2 = r2_score(y_test, y_pred)\n", + "print(f\"R² score: {r2:.4f}\")\n", + "\n", + "# Calculate RMSE\n", + "rmse = np.sqrt(mean_squared_error(y_test, y_pred))\n", + "print(f\"RMSE: {rmse:.2f}\")\n", + "\n", + "# Calculate MAPE\n", + "mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100\n", + "print(f\"MAPE: {mape:.2f}%\")" + ] + }, + { + "cell_type": "markdown", + "id": "vHJLe6LNEBrB", + "metadata": { + "id": "vHJLe6LNEBrB" + }, + "source": [ + "Evaluating model...\n", + "- R² score: 0.7376\n", + "- RMSE: 127.62\n", + "- MAPE: 29.70%\n", + "\n", + "---\n", + "\n", + "- R² = 0.74: This is a solid R² value, indicating our model explains about 74% of the variance in the price data\n", + "Generally, an R² above 0.7 is considered good for price prediction tasks\n", + "- RMSE = 127.6: Average error; good if prices are in the thousands.\n", + "- MAPE = 29.7%: This means our predictions are off by roughly 30% on average. Typical for price prediction, but there’s room for improvement.\n" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "C6cEJ57WApkG", + "metadata": { + "id": "C6cEJ57WApkG" + }, + "source": [ + "### 🚀 Push to HF" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "_n7n_MnscS4r", + "metadata": { + "id": "_n7n_MnscS4r" + }, + "outputs": [], + "source": [ + "# Serialize Ensemble model locally for Hugging Face upload\n", + "\n", + "MODEL_DIR = os.path.join(ROOT, \"models\")\n", + "MODEL_FILENAME = \"ensemble_model.pkl\"\n", + "LOCAL_MODEL = os.path.join(MODEL_DIR, MODEL_FILENAME)\n", + "\n", + "os.makedirs(MODEL_DIR, exist_ok=True)\n", + "joblib.dump(lr, LOCAL_MODEL)\n", + "\n", + "# Create the model repo if it doesn't exist\n", + "api.create_repo(repo_id=REPO_ID, repo_type=\"model\", private=True, exist_ok=True)\n", + "\n", + "# Upload the saved model\n", + "api.upload_file(\n", + " path_or_fileobj=LOCAL_MODEL,\n", + " path_in_repo=MODEL_FILENAME,\n", + " repo_id=REPO_ID,\n", + " repo_type=\"model\",\n", + ")" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "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 +} \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/10_part2_modal.ipynb b/week8/community_contributions/lisekarimi/10_part2_modal.ipynb new file mode 100644 index 0000000..f1525d7 --- /dev/null +++ b/week8/community_contributions/lisekarimi/10_part2_modal.ipynb @@ -0,0 +1,387 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "44c6af6b-6fc3-44d5-a586-71618af7d09a", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "# Modal (Part 2)\n", + "\n", + "---\n", + "✅ With all models and ChromaDB set up, it's time to integrate everything into a real system: **Snapr** — an app that scans online product listings, predicts their value, and alerts users to great deals.\n", + "\n", + "To power SSnapr, we’ll need:\n", + "- Price prediction models — ready for production \n", + "- Fast, on-demand predictions \n", + "- A scalable setup that handles real-world usage\n", + "\n", + "🔧 That’s where **Modal** comes in. Modal lets us deploy models and services to the cloud, with minimal setup, low latency, and clean Python APIs.\n", + "\n", + "- You can check out a [live demo](https://huggingface.co/spaces/lisekarimi/snapr) of the project\n", + "- The source code is available on [GitHub](https://github.com/lisekarimi/snapr)\n", + "\n", + "---\n", + "📢 Find more LLM notebooks on my [GitHub repository](https://github.com/lisekarimi/lexo)\n" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "b8c175e7-ca0a-4664-bded-08ec131c5636", + "metadata": {}, + "source": [ + "## 📚 Pre-requisites\n", + "\n", + "To follow this project smoothly, it's helpful to know:\n", + "\n", + "- 🛰️ What an API is: You send a request → it’s processed remotely → you receive a result\n", + "- 🐳 What a Docker image & container are:\n", + " - Image = environment with code & dependencies\n", + " - Container = running instance of that image\n", + "- 🧑‍💻 Local vs Remote code execution:\n", + " - Local code runs on your machine\n", + " - Remote code runs in the cloud (via Modal" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "440fffc2-9ec1-433d-9b71-e6fae3b46415", + "metadata": {}, + "source": [ + "## 🔧 Install & Setup Modal\n", + "- Before starting, install Modal in your environment (Run this once): `uv pip install modal`\n", + "- Create an account at modal.com (they give you $5 free to start).\n", + "- Then authenticate your environment: `modal setup`" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef286205", + "metadata": {}, + "outputs": [], + "source": [ + "!uv pip install modal" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3906c01-b313-4dac-9a2e-6c7dbfdcc8fd", + "metadata": {}, + "outputs": [], + "source": [ + "import modal\n", + "import sys\n", + "sys.path.append(\".\") # Make sure your local modules are accessible" + ] + }, + { + "cell_type": "markdown", + "id": "43c59002-afe6-4dcc-a53e-b50d85857f7d", + "metadata": {}, + "source": [ + "## 🧠 Key Concepts\n", + "\n", + "Modal is a platform that lets you run Python code in the cloud. You can:\n", + "- Deploy code as APIs\n", + "- Run GPU workloads (e.g., LLMs)\n", + "- Automatically handle Docker, infra, deployment\n", + "\n", + "What is a Modal App?\n", + "An \"App\" is a containerized cloud service where you can run code remotely.\n", + "- Code runs in isolated containers (like Docker)\n", + "- These containers are created on-demand and destroyed when idle\n", + "- You define your logic in a file and deploy it to Modal\n", + "\n", + "Key Modal Concepts\n", + "- `modal.Image`: Defines the environment (like a Docker image)\n", + "- `@app.cls`: Runs classes remotely inside a container\n", + "- `modal.App`: Defines and registers the Modal app\n", + "- `.remote()`: Sends request to Modal API to execute the code remotely\n", + "- `modal deploy -m`: Deploys app permanently like a real cloud service" + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "79436b01-9623-4b0e-8ffc-0ea51a5783ac", + "metadata": {}, + "source": [ + "## ⚙️ Minimal Example" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d62850fc-dbf4-48b0-a2f2-a1e9a200414d", + "metadata": {}, + "outputs": [], + "source": [ + "from modal_services.get_started import app, f\n", + "\n", + "with app.run(): # This spins up a container in Modal\n", + " print(f.local(1000)) # Run locally inside the notebook\n", + " print('*' * 5)\n", + " print(f.remote(1000)) # Run remotely via Modal API inside a container" + ] + }, + { + "attachments": { + "886d059a-a8ca-4552-86d2-fb87fb824441.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "d07d54f3-dfb9-46b2-be50-d6d35f81b3c0", + "metadata": {}, + "source": [ + "🔄 What Happens When You Call .remote()?\n", + "\n", + "some_function.remote() → Modal SDK sends API request\n", + " → Spins up a container\n", + " → Runs the code remotely\n", + " → Sends the result back to your local machine\n", + "\n", + "![image.png](attachment:886d059a-a8ca-4552-86d2-fb87fb824441.png)\n", + "\n", + "What we have here is an **ephemeral app**: the container shuts down after finishing.\n", + "\n", + "For our project, we need a persistently running app that behaves like a production API. To achieve that, we should use `modal deploy -m`, making the app suitable for serving AI services reliably." + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "9422c5b0-573e-43a4-99b5-2c6199770f5c", + "metadata": {}, + "source": [ + "## 📦 Persistent Deployment with `modal deploy`" + ], + "outputs": [] + }, + { + "attachments": { + "b84a3557-9805-462f-a1d5-008b3aa4f4f5.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "8edb6eb4-4489-4823-9d16-a01c8d0355b6", + "metadata": {}, + "source": [ + "Click the blue \"+\" button at the top left of JupyterLab, then choose \"Terminal\" to open a new terminal tab.\n", + "\n", + "There, you can run:\n", + "\n", + "```bash\n", + "conda activate llms\n", + "modal deploy -m modal_services.get_started\n", + "```\n", + "\n", + "This builds and deploys the app (`example-hello-world`), registers `f()`, and makes it callable via `.remote()` anytime — even outside the notebook.\n", + "\n", + "![image.png](attachment:b84a3557-9805-462f-a1d5-008b3aa4f4f5.png)" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "656456f5-b3f9-40bf-8a2e-169da0a68fe8", + "metadata": {}, + "outputs": [], + "source": [ + "from modal_services.get_started import f\n", + "f = modal.Function.from_name(\"example-hello-world\", \"f\") # (app_name, function_name)\n", + "print(f.remote(20))" + ] + }, + { + "attachments": { + "b950fed1-8806-424c-830a-d8b99927801e.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "7d2c4b43-97a7-4a8e-a0df-1e20de053d5a", + "metadata": {}, + "source": [ + "## 🚀 Deploy Our first Modal-powered model\n", + "\n", + "So far, we’ve seen how to run simple remote functions using `@app.function()` and call them via `modal.Function.from_name(...)` in a **persistent app** — good for basic tasks.\n", + "\n", + "But in our Smart Deal Finder project, we need more:\n", + "- Load and reuse a large model (like LLaMA) \n", + "- Keep the model in memory \n", + "- Expose one or more methods (like `price()`)\n", + "\n", + "That’s why we use `@app.cls` — it lets us define a class (e.g. `Pricer`) that lives in a Modal container, loads the model once in `setup()`, and handles remote requests efficiently.\n", + "\n", + "Full code : `\\modal_services.ft_pricer.py`\n", + "\n", + "---\n", + "\n", + "\n", + "🚀 In this step, we’ll deploy a class-based app using `modal.Cls.from_name`.\n", + "\n", + "Specifically, we’ll deploy `Pricer`, which loads our 4-bit quantized fine-tuned LLaMA model (trained in Notebook 9), and exposes a remote `.price()` method to estimate item prices.\n", + "\n", + "⚠️ Before deploying, add your HF_TOKEN in Modal\n", + "\n", + "Then open a terminal and run:\n", + "\n", + "```bash\n", + "modal deploy -m modal_services.ft_pricer\n", + "```\n", + "\n", + "This will:\n", + "- Build the image with your code and dependencies\n", + "- Deploy the app `llm-ft-pricer` and register the `Pricer` class and its methods\n", + "- Not start any container yet — setup() isn't run and the model isn’t loaded\n", + "- Prepare the app to handle `.remote()` calls when they come in\n", + "\n", + "![image.png](attachment:b950fed1-8806-424c-830a-d8b99927801e.png)" + ], + "outputs": [] + }, + { + "attachments": { + "1c697283-e5e2-4b09-b1f1-d1c11f18c8e4.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABdoAAACPCAIAAABia/6KAAAgAElEQVR4Ae2d/1MUR/7/84u/3A9XdRWNU1Z55i2TEFGOvI2Ib08wmAu66xcERQwSAYEIbxTxwDeuhG8G0CxKsouCgmTRFddvKNHEaDAav6GRLycLJ9RVpSqfSlmVqlT5L9znumemZ2Z3ZlhgF4F9blE60zP96p7HdPd0P+fVPa+99tprHH4gAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAITReA1yDEThRrpgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAhADkG5QAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEJpQA5JgJxY3EQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAByDMoACIAACIAACIAACIAACIAACIAACIAACEwoAcgxE4obiYEACIAACIAACIAACIAACIAACIAACIAA5BiUARAAARAAARAAARAAARAAARAAARAAARCYUAKQYyYUNxIDARAAARAAARAAARAAARAAARAAARAAAcgxKAMgAAIgAAIgAAIgAAIgAAIgAAIgAAIgMKEEIMdMKG4kBgIgAAIgAAIgAAIgAAIgAAIgAAIgAAKQY1AGQAAEQAAEQAAEQAAEQAAEQAAEQAAEQGBCCUCOmVDcSAwEQAAEQAAEQAAEQAAEQAAEQAAEQAAEIMegDIAACIAACIAACIAACIAACIAACIAACIDAhBKAHDOhuJEYCIAACIAACIAACIAACIAACIAACIAACECOQRkAARAAARAAARAAARAAARAAARAAARAAgQklADlmQnEjMRAAARAAARAAARAAARAAARAAARAAARCAHIMyAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAITSkBXjpk7d+4777wTERHxLn4gAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAL+I6Atx8ydO3f58uXh4eFvvfUWjx8IgAAIgAAIgAAIgAAIgAAIgAAIgAAIgID/CGjLMe+88054eLj/UoElEAABEAABEAABEAABEAABEAABEAABEAABkYC2HBMREQG/GJQREAABEAABEAABEAABEAABEAABEAABEAgEAW055t133w1EYrAJAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAAOQZlAARAAARAAARAAARAAARAAARAAARAAAQmlADkmAnFjcRAAARA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QAAEQAAEQAAEQAAEQECLgK4c8y5+IAACIAACIAACIAACIAACIAACIAACIAACASCgK8dw+IEACIAACIAACIAACIAACIAACIAACIAACASAAOSYAECFSRAAARAAARAAARAAARAAARAAARAAARDQJwA5Rp8NjoAACIAACIAACIAACIAACIAACIAACIBAAAhAjgkAVJgEARAAARAAARAAARAAARAAARAAARAAAX0CkGP02eAICIAACIAACIAACIAACIAACIAACIAACASAAOSYAECFSRAAARAAARAAARAAARAAARAAARAAARDQJwA5Rp8NjoAACIAACIAACIAACIAACIAACIDAWAnMmTtnXujckIg3314yPzQqBH+MwNtL5odEvDkvdO6cuXPGSnfKx4McM+VvIS4ABEAABEAABEAABEAABEAABEBgUhGYM3fO/EXzmPqADQMC8xfNC05RBnLMpKqzyAwIgAAIgAAIgAAIgAAIgAAIgMDUJvBnfq6B+oBDmgT+zM+d2nd99LmHHDN6ZogBAiAAAiAAAiAAAiAAAiAAAiAAAloE5oVCixnjtKx5ocGlyECO0apACAMBEAABEAABEAABEAABEAABEACBURKAX4ym54vvgUHlIwM5ZpTVC6eDAAiAAAiAAAiAAAiAAAiAAAiAgBeBOXPnjKg7RGe9Z66INldER2e9N+LJwXlC8Kwj43c5hl+6JrOwal/Gmijeq3QiQI8Av/nQiSO5q/QOI9zfBMJizKa10WH+M6tvMGxFyp7yokxTpK8Vgo80ZxQdKtxhXuodIzxa75BeLD7SbFqr+POpYhrWYj6KGBzpcsJi9NoBQ+PyHaHcyvakxGjcJX3jcnxsgUBgCfhWEUaRB32DtHZX7k7xvckyqD780s17yrVrlk4sIWOKZkSjafK+zvDolLzK8rzUFeHexzj9BlNxsn5zxxkaZyb0WkV6Ar90jdnkU3vI7GEDBPxKwKCE+zUdGJsaBPQfAYr8j9SAj6a3qTCLTT8TMF6711wRXTSUWvIiI+9hUt7DpJIXGUVDqeaKaF80l7CiiNhLy2KqF4QljHEekC+pjPmcsKIFEflvjSb6W+EHFkR8on0t8xfN8/ONmazm/CrH8Ftqv3EPDg73ddN/vzm62Xs8OVlBvNp8FZ53Dw5eL3+1mQii1HOdT4YHB7tOJPjlmsN2Hr/bNziscQdj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" + }, + "4a22e438-6b25-4c69-9439-99d146ffd188.png": { + "image/png": "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pH06nREREWlpaU1NtDTr5MmTpaWl8ldvsrKympubhUrV3Ny8bRvtCY9fAASCK5QEkAEEURGIWbJqbaJ9kG+xqfzrDin4qiWy0Z18ldztuk/QyRdx4CeB2BWJgsDvv5YXu0I0V/EzCdqzzbACLLILZi/+xgN/IAACoSdADdywwaqTNmvUaj9Gx9Efrko07LfRGxjhghsIjEkCrH8Y9Pk+5LGEKQv5fVus3XC46BNw1qxZ5eXlHo8nJyfnv9uR/Hfr1vDw8EWLFuXk5Hg8nvLy8lmzZvkEgsMIETCrGOS+IgijfnoMMZvrESrPREpmyZIla9euXbLEbN0bsZgzZ05CQoK1H2tmy5cvX7VqFXYnsaZkfRVCiTUfXAUBPQH/hRJ9SJyDAAiAAAiAAAiAwMshIAslQ0s+NTW1rq5ObfJQV1cnvwYfWlzwDQIgAAJjhwCEkrFzr5DT0UFgx353XSl9uxk/EAABEAABEAABEBgjBHbUHHfX7AwwswsWLFjJfgsWLAgwCgQDARAAgTFFAELJmLpdyCwIgAAIgAAIgAAIgAAIgAAIgAAIgEAoCUAoCSVdxA0CIAACIAACIAACIAACIAACIAACIDCmCEAoGVO3C5kFARAAARAAARAAARAAARAAARAAARAIJQEIJaGki7hBAARAAARAAARAAARAAARAAARAAATGFAEIJWPqdiGzIAACIAACIAACIAACIAACIAACIAACoSQAoSSUdBE3CIAACIAACIAACIAACIAACIAACIDAmCIAoWRM3S5kFgRAAARAAARAAARAAARAAARAAARAIJQEIJSEki7iBgEQAAEQAAEQAAEQAAEQAAEQAAEQGFMEIJSMqduFzIIACIAACIAACIAACIAACIAACIAACISSAISSUNJF3CAAAiAAAiAAAiAAAiAAAiAAAiAAAmOKgJVQ8g5+IAACIAACIAACIAACIAACIAACIAACIDCRCFgJJRx+IAACIAACIAACIAACIAACIAACIAACIDCRCEAomUh3G2UFARAAARAAARAAARAAARAAARAAARCwJAChxBIPLoIACIAACIAACIAACIAACIAACIAACEwkAhBKJtLdRllBAARAAARAAARAAARAAARAAARAAAQsCUAoscSDiyAAAiAAAiAAAiAAAiAAAiAAAiAAAhOJAISSiXS3UVYQAAEQAAEQAAEQAAEQ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" + } + }, + "cell_type": "markdown", + "id": "afff309a-740b-443f-96f1-4b20618ada8b", + "metadata": {}, + "source": [ + "## 🔗 Connect to Our Deployed App\n", + "\n", + "Now that our app is deployed, we can connect to it and use it like a remote service.\n", + "\n", + "We'll do this using `modal.Cls.from_name(\"llm-ft-pricer\", \"Pricer\")`, which fetches the `Pricer` class from our deployed app via the Modal API.\n", + "\n", + "Then, calling `.price.remote(...)` sends a request to Modal, spins up a container if needed, loads the model, runs the method, and returns the result.\n", + "\n", + "This is how we turn our model into a cloud API.\n", + "\n", + "What happens under the hood when calling price.remote(...): \n", + "- First run = downloads model files → stores in volume (/cache) → loads into memory → runs \n", + "- Later runs = load from volume → memory → run (no re-download)\n", + "\n", + "---\n", + "\n", + "Since we added `min_containers=1`, a container is created and kept warm as soon as the app is deployed. Models remain loaded in memory, so there are no cold starts — unless the app is stopped or the container crashes. \n", + "\n", + "![image.png](attachment:1c697283-e5e2-4b09-b1f1-d1c11f18c8e4.png)\n", + "\n", + "⚠️ However, this **continuously consumes credits** if you forget to stop the container or app manually.\n", + "\n", + "To save credits, you can set `min_containers=0` and `scaledown_window=300` — this way, no container stays warm by default, and a new one will spin up only when `.remote()` is called (i.e., on cold start).\n", + "\n", + "![image.png](attachment:4a22e438-6b25-4c69-9439-99d146ffd188.png)\n" + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b478ae8-f636-4ac7-bf53-0f3b23c21a72", + "metadata": {}, + "outputs": [], + "source": [ + "Pricer = modal.Cls.from_name(\"llm-ft-pricer\", \"Pricer\")\n", + "pricer = Pricer()\n", + "reply = pricer.price.remote(\"SEVERIN 28L Microwave, 900W, 5 power levels, 35-min timer, turntable (31.5 cm), Silver, MW 7772\")\n", + "print(reply)" + ] + }, + { + "cell_type": "markdown", + "id": "2e63efbf-344b-4b5f-8a0d-27b6e41f8508", + "metadata": {}, + "source": [ + "Now that we’ve deployed our model and learned how to call it remotely with `.remote()`,\n", + "let’s go one step further — wrap this logic inside a local Python class.\n", + "\n", + "In the next step, we'll build a local Agent that cleanly interacts with our deployed `Modal app`, using the same `Modal API` under the hood." + ], + "outputs": [] + }, + { + "cell_type": "markdown", + "id": "8fbc7696-e892-4f08-80c5-5199b03ed175", + "metadata": {}, + "source": [ + "## 🔌 Connect to Your Modal App with a Local Agent\n", + "\n", + "`ft_pricer.py` is now a deployed API on Modal. \n", + "\n", + "To use it locally, we’ll wrap it in a class called `FTPriceAgent` (Full code: `\\agents\\ft_price_agent.py)` that:\n", + "\n", + "- Connects to the remote app via `modal.Cls.from_name(...)` \n", + "- Calls `.price.remote(...)` to run predictions \n", + "\n", + "🔄 **Two API Calls:** happen\n", + "1. `modal.Cls.from_name(...)` → fetches the deployed class \n", + "2. `.price.remote(...)` → runs the remote method on Modal \n", + "\n", + "This keeps our code clean and modular." + ], + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b80cd15a-e419-4c21-97e7-4a56ed4db680", + "metadata": {}, + "outputs": [], + "source": [ + "from agents.ft_price_agent import FTPriceAgent\n", + "\n", + "agent = FTPriceAgent()\n", + "agent.price(\"Apple AirPods Max wireless over-ear headphones with active noise cancellation and spatial audio\")" + ] + }, + { + "cell_type": "markdown", + "id": "65522b93-59c9-4d15-a12d-58e078b88545", + "metadata": {}, + "source": [ + "Now that we’ve seen how Modal agents work — connecting to remote services and running `.remote()` — we’ll use the same pattern for the rest of our models.\n", + "\n", + "✅ For each model — **XGBoost**, **GPT-4o RAG**, and the **Ensemble** — we’ll build a dedicated Agent. " + ], + "outputs": [] + } + ], + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/agents/__init__.py b/week8/community_contributions/lisekarimi/agents/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/week8/community_contributions/lisekarimi/agents/base_agent.py b/week8/community_contributions/lisekarimi/agents/base_agent.py new file mode 100644 index 0000000..fe09e18 --- /dev/null +++ b/week8/community_contributions/lisekarimi/agents/base_agent.py @@ -0,0 +1,33 @@ +import logging + +class Agent: + """ + An abstract superclass for Agents + Used to log messages in a way that can identify each Agent + """ + + # Foreground colors + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + + # Background color + BG_BLACK = '\033[40m' + + # Reset code to return to default color + RESET = '\033[0m' + + name: str = "" + color: str = '\033[37m' + + def log(self, message): + """ + Log this as an info message, identifying the agent + """ + color_code = self.BG_BLACK + self.color + message = f"[{self.name}] {message}" + logging.info(color_code + message + self.RESET) \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/agents/ft_price_agent.py b/week8/community_contributions/lisekarimi/agents/ft_price_agent.py new file mode 100644 index 0000000..465f1bb --- /dev/null +++ b/week8/community_contributions/lisekarimi/agents/ft_price_agent.py @@ -0,0 +1,29 @@ +import modal +from agents.base_agent import Agent + + +class FTPriceAgent(Agent): + """ + An Agent that runs the fine-tuned LLM that's running remotely on Modal + """ + + name = "FTPrice Agent" + color = Agent.RED + + def __init__(self): + """ + Set up this Agent by creating an instance of the modal class + """ + self.log("FTPrice Agent is initializing - connecting to modal") + Pricer = modal.Cls.from_name("llm-ft-pricer", "Pricer") # 1st API call: to fetch Pricer (remote class) + self.pricer = Pricer() + self.log("FTPrice Agent is ready") + + def price(self, description: str) -> float: + """ + Make a remote call to return the estimate of the price of this item + """ + self.log("FTPrice Agent is calling remote fine-tuned model") + result = self.pricer.price.remote(description) # 2nd API call: to run the price method in the remote Pricer class + self.log(f"FTPrice Agent completed - predicting ${result:.2f}") + return result \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/helpers/__init__.py b/week8/community_contributions/lisekarimi/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/week8/community_contributions/lisekarimi/helpers/items.py b/week8/community_contributions/lisekarimi/helpers/items.py new file mode 100644 index 0000000..a594e27 --- /dev/null +++ b/week8/community_contributions/lisekarimi/helpers/items.py @@ -0,0 +1,120 @@ +from typing import Optional # A variable might be a certain type or None +from transformers import AutoTokenizer +import re + +BASE_MODEL = "meta-llama/Meta-Llama-3.1-8B" + +MIN_TOKENS = 150 # Minimum tokens required to accept an item +MAX_TOKENS = 160 # We limit to 160 tokens so that after adding prompt text, the total stays around 180 tokens. + +MIN_CHARS = 300 # Reject items with less than 300 characters +CEILING_CHARS = MAX_TOKENS * 7 # Truncate long text to about 1120 characters (approx 160 tokens) + +class Item: + """ + An Item is a cleaned, curated datapoint of a Product with a Price + """ + + # Load tokenizer for the model + tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True) + + # Define PRICE_LABEL and question for the training prompt + PRICE_LABEL = "Price is $" + QUESTION = "How much does this cost to the nearest dollar?" + + # A list of useless phrases to remove to reduce noise for price prediction + REMOVALS = ['"Batteries Included?": "No"', '"Batteries Included?": "Yes"', '"Batteries Required?": "No"', '"Batteries Required?": "Yes"', "By Manufacturer", "Item", "Date First", "Package", ":", "Number of", "Best Sellers", "Number", "Product "] + + # Attributes for each item + title: str + price: float + category: str + token_count: int = 0 # How many tokens in the final prompt + + # Optional fields + details: Optional[str] # The value can be a string or can be None + prompt: Optional[str] = None + include = False # Whether to keep the item or not + + def __init__(self, data, price): + self.title = data['title'] + self.price = price + self.parse(data) + + def scrub_details(self): + """ + Removes useless phrases from details, which often has repeated specs or boilerplate text. + """ + details = self.details + for remove in self.REMOVALS: + details = details.replace(remove, "") + return details + + def scrub(self, stuff): + """ + Clean up the provided text by removing unnecessary characters and whitespace + Also remove words that are 7+ chars and contain numbers, as these are likely irrelevant product numbers + """ + stuff = re.sub(r'[:\[\]"{}【】\s]+', ' ', stuff).strip() + stuff = stuff.replace(" ,", ",").replace(",,,",",").replace(",,",",") + words = stuff.split(' ') + select = [word for word in words if len(word)<7 or not any(char.isdigit() for char in word)] + return " ".join(select) + + def parse(self, data): + """ + Prepares the text, checks length, tokenizes it, and sets include = True if it’s valid. + """ + # Builds a full contents string by combining description, features, and cleaned details. + contents = '\n'.join(data['description']) + if contents: + contents += '\n' + features = '\n'.join(data['features']) + if features: + contents += features + '\n' + self.details = data['details'] + if self.details: + contents += self.scrub_details() + '\n' + + # If content is long enough, trim it to max char limit before processing. + if len(contents) > MIN_CHARS: + contents = contents[:CEILING_CHARS] + + # Clean and tokenize text, then check token count. + text = f"{self.scrub(self.title)}\n{self.scrub(contents)}" + tokens = self.tokenizer.encode(text, add_special_tokens=False) + + if len(tokens) > MIN_TOKENS: + # Truncate tokens, decode them back and create the training prompt + tokens = tokens[:MAX_TOKENS] + text = self.tokenizer.decode(tokens) + self.make_prompt(text) + + # Mark the item as valid and ready to be used in training + self.include = True # Only items with MIN_TOKENS <= tokens <= MAX_TOKENS are kept + + + def make_prompt(self, text): + """ + Builds the training prompt using the question, text, and price. Then counts the tokens. + """ + self.prompt = f"{self.QUESTION}\n\n{text}\n\n" + self.prompt += f"{self.PRICE_LABEL }{str(round(self.price))}.00" + self.token_count = len(self.tokenizer.encode(self.prompt, add_special_tokens=False)) + + def test_prompt(self): + """ + Returns the prompt without the actual price, useful for testing/inference. + """ + return self.prompt.split(self.PRICE_LABEL )[0] + self.PRICE_LABEL + + def __repr__(self): + """ + Defines how the Item object looks when printed — it shows the title and price. + """ + return f"<{self.title} = ${self.price}>" + + + + + \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/helpers/loaders.py b/week8/community_contributions/lisekarimi/helpers/loaders.py new file mode 100644 index 0000000..4314c65 --- /dev/null +++ b/week8/community_contributions/lisekarimi/helpers/loaders.py @@ -0,0 +1,106 @@ +from datetime import datetime # Measure how long loading takes +from tqdm import tqdm # Shows a progress bar while processing data +from datasets import load_dataset # Load a dataset from Hugging Face Hub +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor # For parallel processing (speed) +from items import Item + +CHUNK_SIZE = 1000 # Process the dataset in chunks of 1000 datapoints at a time (for efficiency) +MIN_PRICE = 0.5 +MAX_PRICE = 999.49 +WORKER = 4 # Set the number of workers here + +class ItemLoader: + + def __init__(self, name): + """ + Initialize the loader with a dataset name. + """ + self.name = name # Store the category name + self.dataset = None #Placeholder for the dataset (we load it later in load()) + + def process_chunk(self, chunk): + """ + Convert a chunk of datapoints into valid Item objects. + """ + batch = [] # Initialize the list to hold valid items + + # Loop through each datapoint in the chunk + for datapoint in chunk: + try: + # Extract price from datapoint + price_str = datapoint['price'] + if price_str: + price = float(price_str) + + # Check if price is within valid range + if MIN_PRICE <= price <= MAX_PRICE: + item = Item(datapoint, price) + + # Keep only valid items + if item.include: + batch.append(item) + except ValueError: + continue # Skip datapoints with invalid price format + return batch # Return the list of valid items + + + def load_in_parallel(self, workers): + """ + Split the dataset into chunks and process them in parallel. + """ + results = [] + size = len(self.dataset) + chunk_count = (size // CHUNK_SIZE) + 1 + + # Build chunks directly here (no separate function) + chunks = [ + self.dataset.select(range(i, min(i + CHUNK_SIZE, size))) + for i in range(0, size, CHUNK_SIZE) + ] + + # Process chunks in parallel using multiple CPU cores + with ProcessPoolExecutor(max_workers=workers) as pool: + for batch in tqdm(pool.map(self.process_chunk, chunks), total=chunk_count): + results.extend(batch) + + # Add the category name to each result + for result in results: + result.category = self.name + + return results + + + def load(self, workers=WORKER): + """ + Load and process the dataset, returning valid items. + """ + # Record start time + start = datetime.now() + + # Print loading message + print(f"Loading dataset {self.name}", flush=True) + + # Load dataset from Hugging Face (based on category name) + self.dataset = load_dataset( + "McAuley-Lab/Amazon-Reviews-2023", + f"raw_meta_{self.name}", + split="full", + trust_remote_code=True + ) + + # Process the dataset in parallel and collect valid items + results = self.load_in_parallel(workers) + + # Record end time and print summary + finish = datetime.now() + print( + f"Completed {self.name} with {len(results):,} datapoints in {(finish-start).total_seconds()/60:.1f} mins", + flush=True + ) + + # Return the list of valid items + return results + + + + \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/helpers/testing.py b/week8/community_contributions/lisekarimi/helpers/testing.py new file mode 100644 index 0000000..9422182 --- /dev/null +++ b/week8/community_contributions/lisekarimi/helpers/testing.py @@ -0,0 +1,84 @@ +import math +import matplotlib.pyplot as plt + +GREEN = "\033[92m" +YELLOW = "\033[93m" +RED = "\033[91m" +RESET = "\033[0m" +COLOR_MAP = {"red":RED, "orange": YELLOW, "green": GREEN} + +class Tester: + + def __init__(self, predictor, data, title=None, size=250): + self.predictor = predictor + self.data = data + self.title = title or predictor.__name__.replace("_", " ").title() + self.size = size + self.guesses = [] + self.truths = [] + self.errors = [] + self.sles = [] + self.colors = [] + + def color_for(self, error, truth): + if error<40 or error/truth < 0.2: + return "green" + elif error<80 or error/truth < 0.4: + return "orange" + else: + return "red" + + def run_datapoint(self, i): + datapoint = self.data[i] + guess = self.predictor(datapoint) + truth = datapoint["price"] + error = abs(guess - truth) + log_error = math.log(truth+1) - math.log(guess+1) + sle = log_error ** 2 + color = self.color_for(error, truth) + title = datapoint["text"][:40] + "..." if len(datapoint["text"]) > 40 else datapoint["text"] + self.guesses.append(guess) + self.truths.append(truth) + self.errors.append(error) + self.sles.append(sle) + self.colors.append(color) + # print(f"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}") + + def chart(self, title): + max_error = max(self.errors) + plt.figure(figsize=(15, 6)) + max_val = max(max(self.truths), max(self.guesses)) + plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6) + plt.scatter(self.truths, self.guesses, s=3, c=self.colors) + plt.xlabel('Ground Truth') + plt.ylabel('Model Estimate') + plt.xlim(0, max_val) + plt.ylim(0, max_val) + plt.title(title) + + # Add color legend + from matplotlib.lines import Line2D + legend_elements = [ + Line2D([0], [0], marker='o', color='w', label='Accurate (green)', markerfacecolor='green', markersize=8), + Line2D([0], [0], marker='o', color='w', label='Medium error (orange)', markerfacecolor='orange', markersize=8), + Line2D([0], [0], marker='o', color='w', label='High error (red)', markerfacecolor='red', markersize=8) + ] + plt.legend(handles=legend_elements, loc='upper left') + plt.show() + + def report(self): + average_error = sum(self.errors) / self.size + rmsle = math.sqrt(sum(self.sles) / self.size) + hits = sum(1 for color in self.colors if color=="green") + title = f"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%" + self.chart(title) + + def run(self): + self.error = 0 + for i in range(self.size): + self.run_datapoint(i) + self.report() + + @classmethod + def test(cls, function, data): + cls(function, data).run() \ No newline at end of file diff --git a/week8/community_contributions/lisekarimi/modal_services/__init__.py b/week8/community_contributions/lisekarimi/modal_services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/week8/community_contributions/lisekarimi/modal_services/ft_pricer.py b/week8/community_contributions/lisekarimi/modal_services/ft_pricer.py new file mode 100644 index 0000000..974aeb8 --- /dev/null +++ b/week8/community_contributions/lisekarimi/modal_services/ft_pricer.py @@ -0,0 +1,140 @@ +import modal +from modal import App, Volume, Image + +import logging +logging.basicConfig(level=logging.INFO) + +# ───────────────────────────────────────────────────────────────────────────── +# Constants +# ───────────────────────────────────────────────────────────────────────────── + +GPU = "T4" # Use a T4 GPU for inference +CACHE_PATH = "/cache" # Mount point for the Modal volume + +# Hugging Face model references +BASE_MODEL = "meta-llama/Meta-Llama-3.1-8B" +FINETUNED_MODEL = "ed-donner/pricer-2024-09-13_13.04.39" +REVISION = "e8d637df551603dc86cd7a1598a8f44af4d7ae36" # Commit of the fine-tuned model + +# Local cache paths (inside the volume) +BASE_MODEL_DIR = f"{CACHE_PATH}/llama_base_model" +FINETUNED_MODEL_DIR = f"{CACHE_PATH}/llama_finetuned_model" + +# ───────────────────────────────────────────────────────────────────────────── +# Structure +# ───────────────────────────────────────────────────────────────────────────── + +# Container (App: llm-ft-pricer) +# ├── /app ← Code + installed Python packages (from image) +# ├── /cache ← Mounted Modal volume (`hf-hub-cache`) +# │ └── meta-llama/Meta-Llama-3.1-8B/... ← HuggingFace model files downloaded via snapshot_download + + + +QUESTION = "How much does this cost to the nearest dollar?" +PREFIX = "Price is $" # Used to parse generated output + +# ───────────────────────────────────────────────────────────────────────────── +# Modal App, Image, Volume, Secrets +# ───────────────────────────────────────────────────────────────────────────── + +app = modal.App("llm-ft-pricer") # Define the Modal app + +image = ( + Image.debian_slim() + .pip_install("huggingface", "torch", "transformers", "bitsandbytes", "accelerate", "peft") # All needed libraries + .env({"HF_HUB_CACHE": CACHE_PATH}) # Hugging Face will store model files in /cache +) + +cache_vol = modal.Volume.from_name("hf-hub-cache", create_if_missing=True) # Persisted volume for caching models +secrets = [modal.Secret.from_name("HF_TOKEN")] # Hugging Face auth token + +# ───────────────────────────────────────────────────────────────────────────── +# Modal Class: Pricer +# ───────────────────────────────────────────────────────────────────────────── + +# All methods in this class run inside the container with the image, volume, secrets, and GPU you configured. +@app.cls( + image=image, + secrets=secrets, + volumes={CACHE_PATH: cache_vol}, # Mount volume into /cache + gpu=GPU, + timeout=1800, # 30-minute max runtime + min_containers=0, # = 1 : Keeping one container warm uses credits continuously if you forget to stop it. + scaledown_window=300, # Shuts down the container +) +class Pricer: + @modal.enter() + def setup(self): + import os, torch + import logging + from huggingface_hub import snapshot_download + from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig + from peft import PeftModel + + # Create cache path if it doesn't exist + os.makedirs(CACHE_PATH, exist_ok=True) + + # Download base and fine-tuned models into volume + logging.info("Downloading base model...") + snapshot_download(BASE_MODEL, local_dir=BASE_MODEL_DIR) + + logging.info("Downloading fine-tuned model...") + snapshot_download(FINETUNED_MODEL, revision=REVISION, local_dir=FINETUNED_MODEL_DIR) + + # Quantization config (4-bit) + quant_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_use_double_quant=True, + bnb_4bit_compute_dtype=torch.bfloat16, + bnb_4bit_quant_type="nf4" + ) + + # Load tokenizer + self.tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_DIR) + self.tokenizer.pad_token = self.tokenizer.eos_token + self.tokenizer.padding_side = "right" + + # Load base model (quantized) + base_model = AutoModelForCausalLM.from_pretrained( + BASE_MODEL_DIR, + quantization_config=quant_config, + device_map="auto" + ) + + # Apply fine-tuned weights + self.fine_tuned_model = PeftModel.from_pretrained( + base_model, + FINETUNED_MODEL_DIR, + revision=REVISION + ) + self.fine_tuned_model.generation_config.pad_token_id = self.tokenizer.pad_token_id + + @modal.method() + def price(self, description: str) -> float: + import re, torch + from transformers import set_seed + + set_seed(42) # Deterministic output + + # Construct prompt + prompt = f"{QUESTION}\n\n{description}\n\n{PREFIX}" + inputs = self.tokenizer.encode(prompt, return_tensors="pt").to("cuda") + attention_mask = torch.ones(inputs.shape, device="cuda") + + # Generate model output (max 5 tokens) + outputs = self.fine_tuned_model.generate( + inputs, + attention_mask=attention_mask, + max_new_tokens=5, + num_return_sequences=1 + ) + result = self.tokenizer.decode(outputs[0]) + + # Extract number after "Price is $" + contents = result.split("Price is $")[1] + contents = contents.replace(',', '') + match = re.search(r"[-+]?\d*\.\d+|\d+", contents) + return float(match.group()) if match else 0 # Return parsed price or 0 if not found + + diff --git a/week8/community_contributions/lisekarimi/modal_services/get_started.py b/week8/community_contributions/lisekarimi/modal_services/get_started.py new file mode 100644 index 0000000..510d7ad --- /dev/null +++ b/week8/community_contributions/lisekarimi/modal_services/get_started.py @@ -0,0 +1,12 @@ +import sys, modal + +app = modal.App("example-hello-world") + +@app.function() +def f(i: int) -> int: + if i % 2 == 0: + print("hello", i) + else: + print("world", i, file=sys.stderr) + + return i * i diff --git a/week8/day2.0.ipynb b/week8/day2.0.ipynb index 553880e..4f3b049 100644 --- a/week8/day2.0.ipynb +++ b/week8/day2.0.ipynb @@ -44,7 +44,6 @@ "from sentence_transformers import SentenceTransformer\n", "from datasets import load_dataset\n", "import chromadb\n", - "from items import Item\n", "from sklearn.manifold import TSNE\n", "import plotly.graph_objects as go" ] @@ -77,6 +76,18 @@ "login(hf_token, add_to_git_credential=True)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "8491f550-df4a-4c8f-a260-a7a419e8efb6", + "metadata": {}, + "outputs": [], + "source": [ + "# Another import after Logging in to Hugging Face - thank you Trung N.!\n", + "\n", + "from items import Item" + ] + }, { "cell_type": "markdown", "id": "3d4995a4-f67f-4871-87df-8c6439b06366", diff --git a/week8/day2.1.ipynb b/week8/day2.1.ipynb index fac26d8..3151540 100644 --- a/week8/day2.1.ipynb +++ b/week8/day2.1.ipynb @@ -44,7 +44,6 @@ "from sentence_transformers import SentenceTransformer\n", "from datasets import load_dataset\n", "import chromadb\n", - "from items import Item\n", "from sklearn.manifold import TSNE\n", "import plotly.graph_objects as go" ] @@ -174,7 +173,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.12" } }, "nbformat": 4, diff --git a/week8/day2.2.ipynb b/week8/day2.2.ipynb index f55ae2a..eebe634 100644 --- a/week8/day2.2.ipynb +++ b/week8/day2.2.ipynb @@ -44,7 +44,6 @@ "from sentence_transformers import SentenceTransformer\n", "from datasets import load_dataset\n", "import chromadb\n", - "from items import Item\n", "from sklearn.manifold import TSNE\n", "import plotly.graph_objects as go" ] @@ -166,7 +165,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.12" } }, "nbformat": 4, diff --git a/week8/day2.3.ipynb b/week8/day2.3.ipynb index b607e45..c2eeb34 100644 --- a/week8/day2.3.ipynb +++ b/week8/day2.3.ipynb @@ -48,7 +48,6 @@ "from sentence_transformers import SentenceTransformer\n", "from datasets import load_dataset\n", "import chromadb\n", - "from items import Item\n", "from testing import Tester" ] }, @@ -66,6 +65,31 @@ "os.environ['HF_TOKEN'] = os.getenv('HF_TOKEN', 'your-key-if-not-using-env')" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce73b034-9ec1-4533-ba41-3e57c7878b61", + "metadata": {}, + "outputs": [], + "source": [ + "# Log in to HuggingFace\n", + "\n", + "hf_token = os.environ['HF_TOKEN']\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c01daad-86b0-4bc0-91ba-20a64df043ed", + "metadata": {}, + "outputs": [], + "source": [ + "# Another import after Logging in to Hugging Face - thank you Trung N.!\n", + "\n", + "from items import Item" + ] + }, { "cell_type": "code", "execution_count": null, @@ -495,7 +519,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.12" } }, "nbformat": 4, diff --git a/week8/day2.4.ipynb b/week8/day2.4.ipynb index 90bff83..c315c78 100644 --- a/week8/day2.4.ipynb +++ b/week8/day2.4.ipynb @@ -84,6 +84,31 @@ "os.environ['HF_TOKEN'] = os.getenv('HF_TOKEN', 'your-key-if-not-using-env')" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "1006966f-96b7-4e1a-93f0-2bb9a09057c8", + "metadata": {}, + "outputs": [], + "source": [ + "# Log in to HuggingFace\n", + "\n", + "hf_token = os.environ['HF_TOKEN']\n", + "login(hf_token, add_to_git_credential=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de0e4b22-ee61-4b79-95bc-3cd707d5f83d", + "metadata": {}, + "outputs": [], + "source": [ + "# Another import after Logging in to Hugging Face - thank you Trung N.!\n", + "\n", + "from items import Item" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/week8/day4.ipynb b/week8/day4.ipynb index bb4c993..22385a8 100644 --- a/week8/day4.ipynb +++ b/week8/day4.ipynb @@ -78,7 +78,7 @@ " \n", " \n", "

Additional resource: more sophisticated planning agent

\n", - " The Planning Agent that we use in the next cell is simply a python script that calls the other Agents; frankly that's all we require for this project. But if you're intrigued to see a more Autonomous version in which we give the Planning Agent tools and allow it to decide which Agents to call, see my implementation of AutonomousPlanningAgent in my related repo, Agentic. This is an example with multiple tools that dynamically decides which function to call.\n", + " The Planning Agent that we use in the next cell is simply a python script that calls the other Agents; frankly that's all we require for this project. But if you're intrigued to see a more Autonomous version in which we give the Planning Agent tools and allow it to decide which Agents to call, see my implementation of AutonomousPlanningAgent in my related repo, Agentic. This is an example with multiple tools that dynamically decides which function to call.\n", " \n", " \n", " \n", @@ -144,7 +144,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.12" } }, "nbformat": 4,