Browse Source

More troubleshooting and setup tips, and some improvements to flagship Week 8 project

pull/5/head
Edward Donner 7 months ago
parent
commit
0a64893188
  1. 11
      README.md
  2. 9
      week1/day1.ipynb
  3. 170
      week1/troubleshooting.ipynb
  4. 4
      week6/day4.ipynb
  5. 22
      week8/day1.ipynb
  6. 15
      week8/deal_agent_framework.py
  7. 10
      week8/keep_warm.py
  8. 144
      week8/memory.json
  9. 45
      week8/price_is_right_final.py
  10. 4
      week8/pricer_service2.py

11
README.md

@ -72,7 +72,7 @@ cd C:\Users\YourUsername\Documents\Projects
5. **Set up the environment:** 5. **Set up the environment:**
- Open Anaconda Prompt (search for it in the Start menu) - Open Anaconda Prompt (search for it in the Start menu)
- Navigate to the cloned repository folder using `cd path\to\repo` - Navigate to the cloned repository folder using `cd path\to\repo` (replace `path\to\repo` with the actual path to the llm_engineering directory, your locally cloned version of the repo)
- Create the environment: `conda env create -f environment.yml` - Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed - Wait for a few minutes for all packages to be installed
- Activate the environment: `conda activate llms` - Activate the environment: `conda activate llms`
@ -81,7 +81,7 @@ You should see `(llms)` in your prompt, which indicates you've activated your ne
6. **Start Jupyter Lab:** 6. **Start Jupyter Lab:**
- In the Anaconda Prompt, type: `jupyter lab` - In the Anaconda Prompt, from within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`. ...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`.
@ -117,7 +117,7 @@ cd ~/Documents/Projects
5. **Set up the environment:** 5. **Set up the environment:**
- Open Terminal - Open Terminal
- Navigate to the cloned repository folder using `cd path/to/repo` - Navigate to the cloned repository folder using `cd path/to/repo` (replace `path/to/repo` with the actual path to the llm_engineering directory, your locally cloned version of the repo)
- Create the environment: `conda env create -f environment.yml` - Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed - Wait for a few minutes for all packages to be installed
- Activate the environment: `conda activate llms` - Activate the environment: `conda activate llms`
@ -126,7 +126,7 @@ You should see `(llms)` in your prompt, which indicates you've activated your ne
6. **Start Jupyter Lab:** 6. **Start Jupyter Lab:**
- In Terminal, type: `jupyter lab` - In Terminal, from within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`. ...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`.
@ -227,6 +227,7 @@ GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx HF_TOKEN=xxxx
``` ```
Double check there are no spaces before or after the `=` sign, and no spaces at the end of the key.
3. Go to File > Save As. In the "Save as type" dropdown, select All Files. In the "File name" field, type ".env". Choose the root of the project folder (the folder called `llm_engineering`) and click Save. 3. Go to File > Save As. In the "Save as type" dropdown, select All Files. In the "File name" field, type ".env". Choose the root of the project folder (the folder called `llm_engineering`) and click Save.
@ -240,6 +241,8 @@ HF_TOKEN=xxxx
cd /path/to/your/project cd /path/to/your/project
(in other words, change to the directory like `/Users/your_name/Projects/llm_engineering`, or wherever you have cloned llm_engineering).
3. Create the .env file with 3. Create the .env file with
nano .env nano .env

9
week1/day1.ipynb

@ -9,6 +9,8 @@
"\n", "\n",
"Let's build a useful LLM solution - in a matter of minutes.\n", "Let's build a useful LLM solution - in a matter of minutes.\n",
"\n", "\n",
"By the end of this course, you will have built an autonomous Agentic AI solution with 7 agents that collaborate to solve a business problem. All in good time! We will start with something smaller...\n",
"\n",
"Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n", "Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n",
"\n", "\n",
"Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n", "Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n",
@ -24,6 +26,10 @@
"If you have any problems at all, please do reach out. \n", "If you have any problems at all, please do reach out. \n",
"I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect.\n", "I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect.\n",
"\n", "\n",
"## More troubleshooting\n",
"\n",
"Please see the [troubleshooting](troubleshooting.ipynb) notebook in this folder for more ideas!\n",
"\n",
"## Business value of these exercises\n", "## Business value of these exercises\n",
"\n", "\n",
"A final thought. While I've designed these notebooks to be educational, I've also tried to make them enjoyable. We'll do fun things like have LLMs tell jokes and argue with each other. But fundamentally, my goal is to teach skills you can apply in business. I'll explain business implications as we go, and it's worth keeping this in mind: as you build experience with models and techniques, think of ways you could put this into action at work today. Please do contact me if you'd like to discuss more or if you have ideas to bounce off me." "A final thought. While I've designed these notebooks to be educational, I've also tried to make them enjoyable. We'll do fun things like have LLMs tell jokes and argue with each other. But fundamentally, my goal is to teach skills you can apply in business. I'll explain business implications as we go, and it's worth keeping this in mind: as you build experience with models and techniques, think of ways you could put this into action at work today. Please do contact me if you'd like to discuss more or if you have ideas to bounce off me."
@ -64,7 +70,8 @@
"- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n", "- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n",
"- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n", "- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n",
"4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n", "4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n",
"5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n", "5. See the [troubleshooting](troubleshooting.ipynb) notebook in this folder for more instructions\n",
"6. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n",
"\n", "\n",
"Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point." "Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point."
] ]

170
week1/troubleshooting.ipynb

@ -0,0 +1,170 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "2a793b1d-a0a9-404c-ada6-58937227cfce",
"metadata": {},
"source": [
"# Oh dear!\n",
"\n",
"If you've got here, then you're still having problems setting up your environment. I'm so sorry! Hang in there and we should have you up and running in no time.\n",
"\n",
"Setting up a Data Science environment can be challenging because there's a lot going on under the hood. But we will get there.\n",
"\n",
"And please remember - I'm standing by to help out. Message me or email ed@edwarddonner.com and I'll get on the case.\n"
]
},
{
"cell_type": "markdown",
"id": "f5190688-205a-46d1-a0dc-9136a42ad0db",
"metadata": {},
"source": [
"# Step 1\n",
"\n",
"Try running the next cell (click in the cell under this one and hit shift+return).\n",
"\n",
"If this doesn't work, then you're not running in an \"activated\" environment. Please check back in the [README](../README.md) for setting up the Anaconda (or virtualenv) environment and activating it, before running `jupyter lab`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6c78b7d9-1eea-412d-8751-3de20c0f6e2f",
"metadata": {},
"outputs": [],
"source": [
"# This should run with no output - no import errors:\n",
"\n",
"from openai import OpenAI"
]
},
{
"cell_type": "markdown",
"id": "0ba9420d-3bf0-4e08-abac-f2fbf0e9c7f1",
"metadata": {},
"source": [
"# Step 2\n",
"\n",
"Now let's check that your API key is correct set up in your `.env` file.\n",
"Try running the next cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ee8e613-5a6e-4d1f-96ef-91132da545c8",
"metadata": {},
"outputs": [],
"source": [
"# This should print your API key to the output\n",
"\n",
"import os\n",
"from dotenv import load_dotenv\n",
"load_dotenv()\n",
"print(\"My key is\", os.getenv(\"OPENAI_API_KEY\"))"
]
},
{
"cell_type": "markdown",
"id": "f403e515-0e7d-4be4-bb79-5a102dbd6c94",
"metadata": {},
"source": [
"## It should print something like:\n",
"\n",
"`My key is sk-proj-blahblahblah`\n",
"\n",
"If it didn't print a key, then it's not able to find a file called `.env` in the `llm_engineering` folder. \n",
"Double check those steps in the instructions. Is it possible that `.env` is actually called `.env.txt`? In Windows, you may need to change a setting in the File Explorer to ensure that file extensions are showing. Or you will see them if you type `dir` in the `llm_engineering` directory.\n",
"\n",
"Worst case, if you're not able to get this part to work, it's not a big deal. You'll just have to paste your key into the Jupyter Notebook (see below for an example), and be sure to remove it before you share the Notebook with anybody else."
]
},
{
"cell_type": "markdown",
"id": "42afad1f-b0bf-4882-b469-7709060fee3a",
"metadata": {},
"source": [
"# Step 3\n",
"\n",
"Now run the below code and you will hopefully see that GPT can handle basic arithmetic!!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cccb58e7-6626-4033-9dc1-e7e3ff742f6b",
"metadata": {},
"outputs": [],
"source": [
"from openai import OpenAI\n",
"\n",
"my_api_key = \"REPLACE THIS TEXT WITH YOUR OPENAI API KEY WITHIN THE QUOTE MARKS - it should start sk-proj-\"\n",
"\n",
"openai = OpenAI(api_key=my_api_key)\n",
"completion = openai.chat.completions.create(\n",
" model='gpt-4o-mini',\n",
" messages=[{\"role\":\"user\", \"content\": \"What's 2+2?\"}],\n",
")\n",
"print(completion.choices[0].message.content)"
]
},
{
"cell_type": "markdown",
"id": "81046a77-c359-4388-929f-ffc8ad5cb93c",
"metadata": {},
"source": [
"# If this didn't work\n",
"\n",
"Then there's something up with your API key!\n",
"\n",
"First check this webpage to make sure you have a positive credit balance.\n",
"OpenAI requires that you have a positive credit balance and it has minimums. Contact me if this is a problem - I can likely share a key with a small limit.\n",
"\n",
"https://platform.openai.com/settings/organization/billing/overview\n",
"\n",
"Also try creating a new key (button on the top right) here:\n",
"\n",
"https://platform.openai.com/api-keys\n",
"\n",
"And note that sometimes OpenAI seems to take a few minutes to give you access after you try.\n",
"\n",
"## If all else fails:\n",
"\n",
"(1) Try pasting your error into ChatGPT or Claude! It's amazing how often they can figure things out\n",
"\n",
"(2) Contact me! ed@edwarddonner.com\n",
"\n",
"Thanks so much.."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42165c99-ec20-460b-b94d-ea1da25b2a0a",
"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.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

4
week6/day4.ipynb

@ -145,7 +145,7 @@
"# Write the test set to a CSV\n", "# Write the test set to a CSV\n",
"\n", "\n",
"import csv\n", "import csv\n",
"with open('human_input.csv', 'w') as csvfile:\n", "with open('human_input.csv', 'w', encoding=\"utf-8\") as csvfile:\n",
" writer = csv.writer(csvfile)\n", " writer = csv.writer(csvfile)\n",
" for t in test[:250]:\n", " for t in test[:250]:\n",
" writer.writerow([t.test_prompt(), 0])" " writer.writerow([t.test_prompt(), 0])"
@ -161,7 +161,7 @@
"# Read it back in\n", "# Read it back in\n",
"\n", "\n",
"human_predictions = []\n", "human_predictions = []\n",
"with open('human_output.csv', 'r') as csvfile:\n", "with open('human_output.csv', 'r', encoding=\"utf-8\") as csvfile:\n",
" reader = csv.reader(csvfile)\n", " reader = csv.reader(csvfile)\n",
" for row in reader:\n", " for row in reader:\n",
" human_predictions.append(float(row[1]))" " human_predictions.append(float(row[1]))"

22
week8/day1.ipynb

@ -11,7 +11,7 @@
"\n", "\n",
"We'll move at a faster pace than usual, particularly as you're becoming proficient LLM engineers.\n", "We'll move at a faster pace than usual, particularly as you're becoming proficient LLM engineers.\n",
"\n", "\n",
"One quick admin thing: I've added a number of packages to the environment.yml file during September. To make sure you have the latest repo with the latest code, it's worth doing this from the `llm_engineering` project folder:\n", "One quick admin thing: I've added a number of packages to the environment.yml file during Sep and Oct. To make sure you have the latest repo with the latest code, it's worth doing this from the `llm_engineering` project folder:\n",
"\n", "\n",
"```\n", "```\n",
"git pull\n", "git pull\n",
@ -206,6 +206,26 @@
"print(reply)" "print(reply)"
] ]
}, },
{
"cell_type": "markdown",
"id": "9c1b1451-6249-4462-bf2d-5937c059926c",
"metadata": {},
"source": [
"# Optional: Keeping Modal warm\n",
"\n",
"## A way to improve the speed of the Modal pricer service\n",
"\n",
"A student mentioned to me that he was concerned by how slow Modal seems to be. The reason is that Modal puts our service to sleep if we don't use it, and then it takes 2.5 minutes to spin back up.\n",
"\n",
"I've added a utility called `keep_warm.py` that will keep our Modal warm by pinging it every 30 seconds.\n",
"\n",
"To use the utliity, bring up a new Terminal (Mac) or Anaconda prompt (Windows), ensure the environment is activated with `conda activate llms\\\n",
"\n",
"Then run: `python keep_warm.py` from within the week8 drectory.\n",
"\n",
"Remember to press ctrl+C or exit the window when you no longer need Modal running.\n"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "3754cfdd-ae28-47c8-91f2-6e060e2c91b3", "id": "3754cfdd-ae28-47c8-91f2-6e060e2c91b3",

15
week8/deal_agent_framework.py

@ -41,13 +41,17 @@ class DealAgentFramework:
def __init__(self): def __init__(self):
init_logging() init_logging()
self.log("Initializing Agent Framework")
load_dotenv() load_dotenv()
client = chromadb.PersistentClient(path=self.DB) client = chromadb.PersistentClient(path=self.DB)
self.memory = self.read_memory() self.memory = self.read_memory()
self.collection = client.get_or_create_collection('products') self.collection = client.get_or_create_collection('products')
self.planner = PlanningAgent(self.collection) self.planner = None
self.log("Agent Framework is ready")
def init_agents_as_needed(self):
if not self.planner:
self.log("Initializing Agent Framework")
self.planner = PlanningAgent(self.collection)
self.log("Agent Framework is ready")
def read_memory(self) -> List[Opportunity]: def read_memory(self) -> List[Opportunity]:
if os.path.exists(self.MEMORY_FILENAME): if os.path.exists(self.MEMORY_FILENAME):
@ -66,14 +70,15 @@ class DealAgentFramework:
text = BG_BLUE + WHITE + "[Agent Framework] " + message + RESET text = BG_BLUE + WHITE + "[Agent Framework] " + message + RESET
logging.info(text) logging.info(text)
def run(self) -> Optional[Opportunity]: def run(self) -> List[Opportunity]:
self.init_agents_as_needed()
logging.info("Kicking off Planning Agent") logging.info("Kicking off Planning Agent")
result = self.planner.plan(memory=self.memory) result = self.planner.plan(memory=self.memory)
logging.info(f"Planning Agent has completed and returned: {result}") logging.info(f"Planning Agent has completed and returned: {result}")
if result: if result:
self.memory.append(result) self.memory.append(result)
self.write_memory() self.write_memory()
return result return self.memory
@classmethod @classmethod
def get_plot_data(cls, max_datapoints=10000): def get_plot_data(cls, max_datapoints=10000):

10
week8/keep_warm.py

@ -0,0 +1,10 @@
import time
import modal
from datetime import datetime
Pricer = modal.Cls.lookup("pricer-service", "Pricer")
pricer = Pricer()
while True:
reply = pricer.wake_up.remote()
print(f"{datetime.now()}: {reply}")
time.sleep(30)

144
week8/memory.json

@ -16,149 +16,5 @@
}, },
"estimate": 930.8824204895075, "estimate": 930.8824204895075,
"discount": 225.88242048950747 "discount": 225.88242048950747
},
{
"deal": {
"product_description": "The Certified Refurbished Acer Nitro V laptop boasts a powerful 13th Generation Intel Core i5 processor, perfect for gaming and multitasking. With its 15.6-inch 1080p IPS display and NVIDIA GeForce RTX 4050 GPU, expect stunning visuals and smooth performance for all your gaming needs. It comes with 8GB RAM and a 512GB SSD, ensuring fast load times and ample storage. This model is backed by a 2-year warranty from Allstate, ensuring reliable performance for years to come.",
"price": 560.0,
"url": "https://www.dealnews.com/products/Acer/Nitro-V-13-th-Gen-i5-15-6-Laptop-w-NVIDIA-Ge-Force-RTX-4050/480447.html?iref=rss-c39"
},
"estimate": 925.1468647365509,
"discount": 365.1468647365509
},
{
"deal": {
"product_description": "This EcoFlow DELTA 2 (950) Portable Power Station is designed to meet all your mobile energy needs. With a capacity of 1024Wh, it features six AC outlets and multiple USB ports, allowing you to charge various devices simultaneously. The included 800W alternator charger ensures quick recharging, making it an ideal power solution for camping trips or emergency situations. Its Wi-Fi and Bluetooth capabilities provide easy control and monitoring.",
"price": 699.0,
"url": "https://www.dealnews.com/Eco-Flow-DELTA-2-950-Portable-Power-Station-800-W-Alternator-Charger-for-699-free-shipping/21671420.html?iref=rss-c142"
},
"estimate": 869.9627492224658,
"discount": 170.96274922246585
},
{
"deal": {
"product_description": "This 12V 280Ah LiFePO4 battery offers advanced lithium iron phosphate technology, providing lightweight yet robust power storage for a variety of applications including solar, RV, and marine use. Its long cycle life ensures you can rely on it for consistent performance over time. With built-in BMS (Battery Management System) for safe operation and efficiency, this battery is designed for those who prioritize both reliability and energy efficiency.",
"price": 400.0,
"url": "https://www.dealnews.com/12-V-280-Ah-Li-Fe-PO4-Battery-for-400-free-shipping/21676885.html?iref=rss-c142"
},
"estimate": 744.6978640830646,
"discount": 344.6978640830646
},
{
"deal": {
"product_description": "This certified refurbished Apple iPhone 14 features 128GB of storage, providing ample space for apps, photos, and videos. Known for its performance, the iPhone 14 includes advanced camera capabilities and a long-lasting battery, setting standards in smartphone technology. The device comes with a one-year warranty from Allstate, ensuring reliability and support for customers. This refurbished option is an excellent choice for users looking for quality at a lower price point.",
"price": 425.0,
"url": "https://www.dealnews.com/products/Apple/Refurb-Unlocked-Apple-iPhone-14-128-GB-Phone-Excellent-Cond/472441.html?iref=rss-c142"
},
"estimate": 667.340418267145,
"discount": 242.34041826714497
},
{
"deal": {
"product_description": "The iRobot Roomba j7+ is a highly efficient WiFi self-emptying robot vacuum designed to make cleaning effortless. With advanced smart mapping technology, it can identify and avoid obstacles, ensuring a thorough cleaning of your home. This model offers a self-emptying base, eliminating the need for manual bag changes. A runtime of 90 minutes allows it to cover large areas, making it ideal for busy households.",
"price": 250.0,
"url": "https://www.dealnews.com/products/iRobot/iRobot-Roomba-j7-Wi-Fi-Self-Emptying-Robot-Vacuum/293669.html?iref=rss-f1912"
},
"estimate": 621.4089582478217,
"discount": 371.4089582478217
},
{
"deal": {
"product_description": "The certified refurbished iRobot Roomba 692 is a smart cleaning device that simplifies household upkeep. This vacuum operates with three-stage cleaning technology and has a compatibility feature with smart assistants such as Alexa and Google Home. It is designed for efficient cleaning across hard floors and carpets, providing a 90-minute runtime per charge. This model comes with a 2-year warranty from Allstate, ensuring peace of mind along with top-notch functionality for your cleaning needs.",
"price": 120.0,
"url": "https://www.dealnews.com/products/iRobot/iRobot-Roomba-692-Robot-Vacuum/143125.html?iref=rss-f1912"
},
"estimate": 304.1034980572389,
"discount": 184.10349805723888
},
{
"deal": {
"product_description": "The Certified Refurb Acer Swift Edge Ryzen 7 Laptop features an advanced AMD Ryzen 7 7735U 8-core processor, offering exceptional performance for both work and play. It is equipped with a 16GB RAM and a spacious 1TB SSD, ensuring smooth multitasking and ample storage for your files. The 16-inch display boasts a stunning 3840x2400 resolution, making it ideal for streaming and content creation. This laptop is certified refurbished, meaning it comes backed by a 2-year warranty for peace of mind.",
"price": 760.0,
"url": "https://www.dealnews.com/Certified-Refurb-Acer-Swift-Edge-Ryzen-7-16-Laptop-for-760-free-shipping/21682096.html?iref=rss-c39"
},
"estimate": 985.5902213719573,
"discount": 225.59022137195734
},
{
"deal": {
"product_description": "The Klipsch T5 II True Wireless ANC Earphones offer a high-fidelity audio experience combined with active noise-canceling technology. These earbuds come with six sizes of patented, color-coded oval ear tips to ensure a comfortable fit for all users. The device is equipped with a two-mic hybrid design, enhancing call quality while reducing background noise. With intuitive head gesture controls, you can easily manage your audio playback without needing to reach for your device.",
"price": 68.0,
"url": "https://www.dealnews.com/products/Klipsch/Klipsch-T5-II-True-Wireless-ANC-Earphones/482823.html?iref=rss-c142"
},
"estimate": 309.56921733594834,
"discount": 241.56921733594834
},
{
"deal": {
"product_description": "The Certified Refurbished Acer Aspire 3 laptop boasts a powerful 6th-generation AMD Ryzen 5 processor and a spacious 15.6-inch touchscreen display with full HD resolution. It is equipped with 16GB of RAM and a 1TB SSD, providing ample storage and fast performance. This model comes with Windows 11 Home and is backed by a two-year warranty.",
"price": 288.0,
"url": "https://www.dealnews.com/products/Acer/Acer-Aspire-3-6-th-Gen-Ryzen-5-15-6-Touchscreen-Laptop/476367.html?iref=rss-c39"
},
"estimate": 558.5214284656016,
"discount": 270.5214284656016
},
{
"deal": {
"product_description": "The Eufy eufyCam S330 (eufyCam 3) 4-Camera kit comes equipped with advanced security features, making it a top choice for home monitoring. Each camera offers high-resolution 4K video and includes an integrated solar panel for continuous powering, thus eliminating the need for frequent recharges. The system utilizes artificial intelligence for facial recognition, effectively distinguishing between family and strangers. Furthermore, it includes a 1TB hard drive for expandable local storage, ensuring that you have ample room to save recorded footage without additional fees.",
"price": 650.0,
"url": "https://www.dealnews.com/products/Eufy/eufy-Cam-S330-eufy-Cam-3-4-Camera-Kit-1-TB-HDD/464094.html?iref=rss-c196"
},
"estimate": 901.053559336033,
"discount": 251.053559336033
},
{
"deal": {
"product_description": "The Shark IQ Robot Vacuum is designed to simplify your cleaning routine with its 60-day capacity base, which allows it to store more dirt before needing to be emptied. It comes equipped with advanced navigation technology to efficiently clean your floors while avoiding obstacles. This self-emptying feature not only saves you time but also ensures your home remains clean with minimal effort on your part. It's a perfect solution for busy households looking for convenience.",
"price": 267.0,
"url": "https://www.dealnews.com/Shark-IQ-Robot-Vacuum-w-60-Day-Capacity-Base-for-267-free-shipping/21668563.html?iref=rss-f1912"
},
"estimate": 495.68476864134675,
"discount": 228.68476864134675
},
{
"deal": {
"product_description": "The Dell Inspiron 15 Laptop is equipped with a 12th Generation Intel Core i5 processor and a 15.6-inch touchscreen display, providing a dynamic computing experience for work and entertainment. With 8GB of RAM and a 512GB SSD, it offers sufficient memory for multitasking and fast boot-up times. This laptop runs Windows 11 Home in S Mode, enhancing its performance for everyday tasks. Its sleek design and robust features make it a practical choice for students and professionals alike.",
"price": 350.0,
"url": "https://www.dealnews.com/products/Dell/Dell-Inspiron-15-12-th-Gen-i5-15-6-Touchscreen-Laptop-w-512-GB-SSD/479057.html?iref=rss-c39"
},
"estimate": 577.1076076116793,
"discount": 227.10760761167933
},
{
"deal": {
"product_description": "The EcoFlow DELTA 2 (950) Portable Power Station is designed for convenience and reliability, boasting a 1024Wh capacity that can power multiple devices simultaneously. It features six AC outlets, two USB-A, and two USB-C ports, making it versatile for outdoor adventures, emergencies, or everyday use. With both Wi-Fi and Bluetooth connectivity, you can monitor the status of your power station right from your smartphone. This bundle also comes with an 800W alternator charger, ensuring that you have everything you need to stay powered up wherever you go.",
"price": 699.0,
"url": "https://www.dealnews.com/Eco-Flow-DELTA-2-950-Portable-Power-Station-800-W-Alternator-Charger-for-699-free-shipping/21673983.html?iref=rss-c142"
},
"estimate": 963.8626028683989,
"discount": 264.8626028683989
},
{
"deal": {
"product_description": "The Certified Refurb iRobot Roomba i4 EVO WiFi Robot Vacuum combines smart technology with powerful cleaning capabilities. This robot vacuum is designed to navigate effortlessly through your home, providing thorough cleaning on multiple surfaces. With WiFi connectivity, users can control the vacuum remotely via a smartphone app. The three-stage cleaning system ensures a deep clean, making it a perfect addition for busy households.",
"price": 130.0,
"url": "https://www.dealnews.com/products/iRobot/iRobot-Roomba-i4-EVO-Wi-Fi-Robot-Vacuum/431157.html?iref=rss-f1912"
},
"estimate": 341.23175777017946,
"discount": 211.23175777017946
},
{
"deal": {
"product_description": "The ZimaBoard 832 Single Board Server is a versatile and compact solution for home or office use, equipped with robust processing power suitable for a variety of applications, including media streaming and file servers. It is designed for ease of use, with capabilities for expansion and customization. Its lightweight and energy-efficient design makes it an ideal selection for developers and tech enthusiasts seeking a reliable platform for programming and digital projects.",
"price": 140.0,
"url": "https://www.dealnews.com/Zima-Board-832-Single-Board-Server-for-140-free-shipping/21676871.html?iref=rss-c39"
},
"estimate": 292.84135797094723,
"discount": 152.84135797094723
},
{
"deal": {
"product_description": "The EcoFlow DELTA 2 (950) Portable Power Station is a robust solution for all your electrical needs while on the go. With a 1024Wh capacity, this power station is versatile enough to charge multiple devices simultaneously, thanks to its six AC outlets. Additionally, it features two USB-A and two USB-C ports, enabling you to charge laptops, phones, and other electronics quickly. Bundled with an 800W Alternator Charger, it's designed to ensure you have power, wherever your adventures may lead you.",
"price": 699.0,
"url": "https://www.dealnews.com/Eco-Flow-DELTA-2-950-Portable-Power-Station-800-W-Alternator-Charger-for-699-free-shipping/21676798.html?iref=rss-c142"
},
"estimate": 870.8927901823207,
"discount": 171.8927901823207
} }
] ]

45
week8/price_is_right_final.py

@ -42,6 +42,11 @@ class App:
def __init__(self): def __init__(self):
self.agent_framework = None self.agent_framework = None
def get_agent_framework(self):
if not self.agent_framework:
self.agent_framework = DealAgentFramework()
return self.agent_framework
def run(self): def run(self):
with gr.Blocks(title="The Price is Right", fill_width=True) as ui: with gr.Blocks(title="The Price is Right", fill_width=True) as ui:
@ -51,16 +56,17 @@ class App:
return [[opp.deal.product_description, f"${opp.deal.price:.2f}", f"${opp.estimate:.2f}", f"${opp.discount:.2f}", opp.deal.url] for opp in opps] return [[opp.deal.product_description, f"${opp.deal.price:.2f}", f"${opp.estimate:.2f}", f"${opp.discount:.2f}", opp.deal.url] for opp in opps]
def update_output(log_data, log_queue, result_queue): def update_output(log_data, log_queue, result_queue):
initial_result = table_for(self.get_agent_framework().memory)
final_result = None final_result = None
while True: while True:
try: try:
message = log_queue.get_nowait() message = log_queue.get_nowait()
log_data.append(reformat(message)) log_data.append(reformat(message))
yield log_data, html_for(log_data), final_result yield log_data, html_for(log_data), final_result or initial_result
except queue.Empty: except queue.Empty:
try: try:
final_result = result_queue.get_nowait() final_result = result_queue.get_nowait()
yield log_data, html_for(log_data), final_result yield log_data, html_for(log_data), final_result or initial_result
except queue.Empty: except queue.Empty:
if final_result is not None: if final_result is not None:
break break
@ -100,28 +106,18 @@ class App:
return fig return fig
def start():
self.agent_framework = DealAgentFramework()
self.agent_framework.run()
opportunities = self.agent_framework.memory
table = table_for(opportunities)
return table
def do_run(): def do_run():
if not self.agent_framework: new_opportunities = self.get_agent_framework().run()
self.agent_framework = DealAgentFramework()
self.agent_framework.run()
new_opportunities = self.agent_framework.memory
table = table_for(new_opportunities) table = table_for(new_opportunities)
return table return table
def do_with_logging(function, initial_log_data): def run_with_logging(initial_log_data):
log_queue = queue.Queue() log_queue = queue.Queue()
result_queue = queue.Queue() result_queue = queue.Queue()
setup_logging(log_queue) setup_logging(log_queue)
def worker(): def worker():
result = function() result = do_run()
result_queue.put(result) result_queue.put(result)
thread = threading.Thread(target=worker) thread = threading.Thread(target=worker)
@ -130,19 +126,11 @@ class App:
for log_data, output, final_result in update_output(initial_log_data, log_queue, result_queue): for log_data, output, final_result in update_output(initial_log_data, log_queue, result_queue):
yield log_data, output, final_result yield log_data, output, final_result
def start_with_logging(initial_log_data):
for log_data, output, final_result in do_with_logging(start, initial_log_data):
yield log_data, output, final_result
def run_with_logging(initial_log_data):
for log_data, output, final_result in do_with_logging(do_run, initial_log_data):
yield log_data, output, final_result
def do_select(selected_index: gr.SelectData): def do_select(selected_index: gr.SelectData):
opportunities = self.agent_framework.memory opportunities = self.get_agent_framework().memory
row = selected_index.index[0] row = selected_index.index[0]
opportunity = opportunities[row] opportunity = opportunities[row]
self.agent_framework.planner.messenger.alert(opportunity) self.get_agent_framework().planner.messenger.alert(opportunity)
with gr.Row(): with gr.Row():
gr.Markdown('<div style="text-align: center;font-size:24px"><strong>The Price is Right</strong> - Autonomous Agent Framework that hunts for deals</div>') gr.Markdown('<div style="text-align: center;font-size:24px"><strong>The Price is Right</strong> - Autonomous Agent Framework that hunts for deals</div>')
@ -155,7 +143,7 @@ class App:
column_widths=[6, 1, 1, 1, 3], column_widths=[6, 1, 1, 1, 3],
row_count=10, row_count=10,
col_count=5, col_count=5,
height=400, max_height=400,
) )
with gr.Row(): with gr.Row():
with gr.Column(scale=1): with gr.Column(scale=1):
@ -163,14 +151,11 @@ class App:
with gr.Column(scale=1): with gr.Column(scale=1):
plot = gr.Plot(value=get_plot(), show_label=False) plot = gr.Plot(value=get_plot(), show_label=False)
ui.load(start_with_logging, inputs=[log_data], outputs=[log_data, logs, opportunities_dataframe]) ui.load(run_with_logging, inputs=[log_data], outputs=[log_data, logs, opportunities_dataframe])
timer = gr.Timer(value=300, active=True) timer = gr.Timer(value=300, active=True)
timer.tick(run_with_logging, inputs=[log_data], outputs=[log_data, logs, opportunities_dataframe]) timer.tick(run_with_logging, inputs=[log_data], outputs=[log_data, logs, opportunities_dataframe])
# timer2 = gr.Timer(value=5, active=True)
# timer2.tick(get_plot, inputs=[], outputs=[plot, timer2])
opportunities_dataframe.select(do_select) opportunities_dataframe.select(do_select)
ui.launch(share=False, inbrowser=True) ui.launch(share=False, inbrowser=True)

4
week8/pricer_service2.py

@ -82,3 +82,7 @@ class Pricer:
match = re.search(r"[-+]?\d*\.\d+|\d+", contents) match = re.search(r"[-+]?\d*\.\d+|\d+", contents)
return float(match.group()) if match else 0 return float(match.group()) if match else 0
@modal.method()
def wake_up(self) -> str:
return "ok"

Loading…
Cancel
Save