Spaces:
Runtime error
Runtime error
Commit ·
1cb59e8
0
Parent(s):
Price Comparison Agent Huggingface Spaces
Browse files- .DS_Store +0 -0
- .gitattributes +35 -0
- Dockerfile +21 -0
- LICENSE +21 -0
- README.md +138 -0
- app.py +125 -0
- requirements.txt +6 -0
- src/__init__.py +0 -0
- src/__pycache__/__init__.cpython-310.pyc +0 -0
- src/__pycache__/agents.cpython-310.pyc +0 -0
- src/__pycache__/config.cpython-310.pyc +0 -0
- src/__pycache__/crew.cpython-310.pyc +0 -0
- src/__pycache__/tasks.cpython-310.pyc +0 -0
- src/__pycache__/tools.cpython-310.pyc +0 -0
- src/agents.py +52 -0
- src/config.py +23 -0
- src/crew.py +14 -0
- src/streamlit_app.py +125 -0
- src/tasks.py +34 -0
- src/tools.py +5 -0
- test.ipynb +284 -0
.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
curl \
|
| 8 |
+
software-properties-common \
|
| 9 |
+
git \
|
| 10 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
+
|
| 12 |
+
COPY requirements.txt ./
|
| 13 |
+
COPY src/ ./src/
|
| 14 |
+
|
| 15 |
+
RUN pip3 install -r requirements.txt
|
| 16 |
+
|
| 17 |
+
EXPOSE 8501
|
| 18 |
+
|
| 19 |
+
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 20 |
+
|
| 21 |
+
ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 J.Kanishkha
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🛍️ **Price Comparison Agent** 🚀 using CrewAI and Cerebras 🤖
|
| 2 |
+
|
| 3 |
+
Welcome to the **Price Comparison Agent** project! 🎉 This tool automatically compares prices for your favorite products across various e-commerce platforms. Powered by **CrewAI** for orchestration, **Cerebras LLM** for high-performance language processing, and cutting-edge scraping tools, it gives you insights like never before! 💡
|
| 4 |
+
|
| 5 |
+
## 📚 Table of Contents
|
| 6 |
+
- [🌟 Overview](#overview)
|
| 7 |
+
- [🛠️ Technologies](#technologies)
|
| 8 |
+
- [📂 Project Structure](#project-structure)
|
| 9 |
+
- [⚙️ Installation](#installation)
|
| 10 |
+
- [🔑 Setup Environment Variables](#setup-environment-variables)
|
| 11 |
+
- [🚀 Usage](#usage)
|
| 12 |
+
- [🚧 Future Improvements](#future-improvements)
|
| 13 |
+
- [📝 License](#license)
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## 🌟 Overview
|
| 18 |
+
This project automates the **price comparison** process using an orchestrated system of agents and tasks built on **CrewAI**! 🎯 The agents work together to:
|
| 19 |
+
1. **Collect pricing data** 🛒 from various e-commerce platforms.
|
| 20 |
+
2. **Clean** 🧹 the data for consistency and accuracy.
|
| 21 |
+
3. **Compare prices** 💲 to find the best deal.
|
| 22 |
+
4. **Generate a detailed report** 📊 with actionable insights.
|
| 23 |
+
|
| 24 |
+
### 🎯 Agents:
|
| 25 |
+
- **Search Agent:** Scours the web for price data on your selected product.
|
| 26 |
+
- **Data Cleaner:** Scrubs the collected data to ensure it’s clean and ready for analysis.
|
| 27 |
+
- **Price Comparison Expert:** Identifies the lowest price and price-to-value ratio.
|
| 28 |
+
- **Reporting Agent:** Summarizes all findings into a professional market insights report.
|
| 29 |
+
|
| 30 |
+
### 🧰 Tools:
|
| 31 |
+
- **SerperDevTool:** For scraping e-commerce platforms and gathering product details 🔍.
|
| 32 |
+
- **ScrapeWebsiteTool:** For extracting additional data from specific product pages 🌐.
|
| 33 |
+
|
| 34 |
+
### ⚡ Cerebras LLM:
|
| 35 |
+
Powering our agents with state-of-the-art **language understanding** to generate insights! 🤖
|
| 36 |
+
|
| 37 |
+
---
|
| 38 |
+
|
| 39 |
+
## 🛠️ Technologies
|
| 40 |
+
Here’s what makes the magic happen 🔮:
|
| 41 |
+
- **CrewAI** 🧑💼: Orchestrating agents for intelligent automation.
|
| 42 |
+
- **Cerebras LLM** 🧠: High-performance language model for processing and reporting.
|
| 43 |
+
- **Streamlit** 🌐: Interactive web app for displaying results.
|
| 44 |
+
- **SerperDevTool & ScrapeWebsiteTool** 🔧: Web scraping tools to collect data.
|
| 45 |
+
- **Python** 🐍: The backbone of this project.
|
| 46 |
+
|
| 47 |
+
---
|
| 48 |
+
|
| 49 |
+
## Demo
|
| 50 |
+
|
| 51 |
+

|
| 52 |
+

|
| 53 |
+
|
| 54 |
+
## 📂 Project Structure
|
| 55 |
+
Here’s the folder breakdown 🗂️:
|
| 56 |
+
```bash
|
| 57 |
+
Price-Comparison-Agent/
|
| 58 |
+
│
|
| 59 |
+
├── src/
|
| 60 |
+
│ ├── agents.py
|
| 61 |
+
│ ├── config.py
|
| 62 |
+
│ ├── crew.py
|
| 63 |
+
│ ├── task.py
|
| 64 |
+
│ ├── tools.py
|
| 65 |
+
│
|
| 66 |
+
├── app.py
|
| 67 |
+
├── .env
|
| 68 |
+
├── requirements.txt
|
| 69 |
+
└── README.md
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## ⚙️ Installation
|
| 75 |
+
|
| 76 |
+
Ready to get started? 🏁 Follow these simple steps to install and run the project:
|
| 77 |
+
|
| 78 |
+
1. **Clone the Repository:**
|
| 79 |
+
```bash
|
| 80 |
+
git clone https://github.com/Jkanishkha0305/Price-Comparison-Agent.git
|
| 81 |
+
cd Price-Comparison-Agent
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
2. **Install Dependencies:**
|
| 85 |
+
Set up a virtual environment and install the required Python packages:
|
| 86 |
+
```bash
|
| 87 |
+
python3 -m venv venv
|
| 88 |
+
source venv/bin/activate
|
| 89 |
+
pip install -r requirements.txt
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
3. **Setup Environment Variables:**
|
| 93 |
+
Create a .env file in the root directory. Add your API keys:
|
| 94 |
+
```bash
|
| 95 |
+
CEREBRAS_API_KEY=your_cerebras_api_key
|
| 96 |
+
SERPER_API_KEY=your_serper_api_key
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
4. **Install Dependencies:**
|
| 100 |
+
Fire up the app using Streamlit:
|
| 101 |
+
```bash
|
| 102 |
+
streamlit run app.py
|
| 103 |
+
```
|
| 104 |
+
Go to http://localhost:8501 in your browser to start interacting with the tool! 🌐
|
| 105 |
+
|
| 106 |
+
## 🚀 Usage
|
| 107 |
+
|
| 108 |
+
Once you’re running the Streamlit app, simply:
|
| 109 |
+
|
| 110 |
+
1. **Enter Product Name** 🏷️ (e.g., “Sony WH-1000XM5”).
|
| 111 |
+
2. **Enter Country** 🌍 (e.g., “United States”).
|
| 112 |
+
3. Click **"Compare Prices"** 💸.
|
| 113 |
+
|
| 114 |
+
The app will:
|
| 115 |
+
- **Search for prices** across major platforms 🛍️.
|
| 116 |
+
- **Clean and standardize the data** 🧼.
|
| 117 |
+
- **Compare the lowest prices** and show you the best deals 📊.
|
| 118 |
+
- **Generate a detailed report** with pricing trends and recommendations 📑.
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
## 🚧 Future Improvements
|
| 122 |
+
|
| 123 |
+
Let’s make this tool even better! Here’s what we plan to add next:
|
| 124 |
+
|
| 125 |
+
- **🌎 Multi-country Support**: Compare prices across different regions.
|
| 126 |
+
- **🛍️ More Platforms**: Expand to include even more e-commerce platforms.
|
| 127 |
+
- **🔄 Real-time Updates**: Keep prices up-to-date in real time.
|
| 128 |
+
- **📱 Price Alerts**: Notify users when a product’s price drops below a certain threshold.
|
| 129 |
+
|
| 130 |
+
## Teammates
|
| 131 |
+
1. **Kanishkha Jaisankar**
|
| 132 |
+
2. **Nirbhaya Reddy Gopavaram**
|
| 133 |
+
3. **Nitharshan Coimbatore Venkatesan**
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
## 📝 License
|
| 137 |
+
|
| 138 |
+
This project is licensed under the MIT License. See the LICENSE file for details. ⚖️
|
app.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import sys
|
| 3 |
+
import os
|
| 4 |
+
import json
|
| 5 |
+
from src.config import cerebras_llm
|
| 6 |
+
from src.crew import create_crew # Assuming you have a function that creates the crew setup
|
| 7 |
+
|
| 8 |
+
# Ensure the src folder is part of the Python path
|
| 9 |
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')))
|
| 10 |
+
|
| 11 |
+
# Function to run the entire crew
|
| 12 |
+
def run_crew(product_name, country, model_name):
|
| 13 |
+
# Create the crew with agents and tasks
|
| 14 |
+
event_management_crew = create_crew(product_name, country, model_name)
|
| 15 |
+
|
| 16 |
+
# Format the input for the crew
|
| 17 |
+
event_details = {'product': product_name, 'country': country, 'model': model_name}
|
| 18 |
+
|
| 19 |
+
# Execute Crew (this will run all the tasks)
|
| 20 |
+
event_analysis = event_management_crew.kickoff(inputs=event_details)
|
| 21 |
+
|
| 22 |
+
return event_analysis
|
| 23 |
+
|
| 24 |
+
# Function to clean the output and remove unwanted fields
|
| 25 |
+
def clean_output(output):
|
| 26 |
+
if isinstance(output, dict):
|
| 27 |
+
output = json.dumps(output, indent=4)
|
| 28 |
+
output = output.replace('"pydantic":null,', '')
|
| 29 |
+
output = output.replace('"json_dict":null,', '')
|
| 30 |
+
output = output.replace('"tasks_output":[]', '')
|
| 31 |
+
output = output.replace('"token_usage":', '')
|
| 32 |
+
return output
|
| 33 |
+
return output
|
| 34 |
+
|
| 35 |
+
# Streamlit Page Config
|
| 36 |
+
st.set_page_config(page_title="AI Price Comparator", page_icon="🛒", layout="wide")
|
| 37 |
+
|
| 38 |
+
# Initialize session states for history and reports
|
| 39 |
+
if 'history' not in st.session_state:
|
| 40 |
+
st.session_state.history = []
|
| 41 |
+
if 'reports' not in st.session_state:
|
| 42 |
+
st.session_state.reports = {}
|
| 43 |
+
|
| 44 |
+
# Sidebar for API Key Uploads, History, and Model Selection
|
| 45 |
+
with st.sidebar:
|
| 46 |
+
st.header("🔑 **API Keys**")
|
| 47 |
+
cerebras_api_key = st.text_input("🧠 Cerebras API Key", type="password")
|
| 48 |
+
serper_api_key = st.text_input("🔍 Serper API Key", type="password")
|
| 49 |
+
|
| 50 |
+
# Model Selection
|
| 51 |
+
# Sidebar Model Selection
|
| 52 |
+
st.header("🧠 **Select Model**")
|
| 53 |
+
model_name = st.selectbox(
|
| 54 |
+
"Choose a Model",
|
| 55 |
+
["cerebras/llama-3.1-8b", "cerebras/llama-3.3-70b", "cerebras/deepseek-r1-distill-llama-70b"]
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# History Tab
|
| 59 |
+
st.header("📜 **Search History**")
|
| 60 |
+
if st.session_state.history:
|
| 61 |
+
for idx, search in enumerate(st.session_state.history):
|
| 62 |
+
if st.button(f"🔎 {search['product_name']} in {search['country']}", key=f"search_{idx}"):
|
| 63 |
+
st.session_state.selected_search = search # Store selected search
|
| 64 |
+
st.rerun()
|
| 65 |
+
else:
|
| 66 |
+
st.write("No previous searches yet.")
|
| 67 |
+
|
| 68 |
+
# **Main UI**
|
| 69 |
+
st.markdown("## 🚀 **Welcome to the Price Comparison Tool!** 🛒")
|
| 70 |
+
st.write("Enter the product details below to compare prices across multiple platforms. 📉")
|
| 71 |
+
|
| 72 |
+
# **Inputs for product and country (always visible)**
|
| 73 |
+
selected_search = st.session_state.get('selected_search', {})
|
| 74 |
+
|
| 75 |
+
product_name = st.text_input(
|
| 76 |
+
"💡 **Product Name**",
|
| 77 |
+
selected_search.get('product_name', "Sony WH-1000XM5")
|
| 78 |
+
)
|
| 79 |
+
country = st.text_input(
|
| 80 |
+
"🌍 **Country**",
|
| 81 |
+
selected_search.get('country', "United States")
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
# **Button to compare prices**
|
| 85 |
+
if st.button("🔍 **Compare Prices**", help="Click to analyze prices and get a detailed comparison"):
|
| 86 |
+
if product_name and country:
|
| 87 |
+
st.write(f"🛒 **Analyzing prices for** **{product_name}** in **{country}**... 📈")
|
| 88 |
+
|
| 89 |
+
# Run the crew and get the results
|
| 90 |
+
event_analysis = run_crew(product_name, country, model_name)
|
| 91 |
+
|
| 92 |
+
# Clean the output and display the results
|
| 93 |
+
cleaned_output = clean_output(event_analysis)
|
| 94 |
+
|
| 95 |
+
st.subheader("📊 **Price Comparison Report**")
|
| 96 |
+
st.markdown(cleaned_output)
|
| 97 |
+
|
| 98 |
+
# Store the search and report
|
| 99 |
+
search_key = f"{product_name}_{country}"
|
| 100 |
+
search_data = {'product_name': product_name, 'country': country, 'model_name': model_name}
|
| 101 |
+
|
| 102 |
+
if search_data not in st.session_state.history:
|
| 103 |
+
st.session_state.history.append(search_data)
|
| 104 |
+
|
| 105 |
+
st.session_state.reports[search_key] = cleaned_output # Save the report
|
| 106 |
+
|
| 107 |
+
# Clear selected search after displaying results
|
| 108 |
+
st.session_state.selected_search = {'product_name': product_name, 'country': country}
|
| 109 |
+
else:
|
| 110 |
+
st.error("❌ Please enter both product name and country.")
|
| 111 |
+
|
| 112 |
+
# **Display saved report if a past search is selected**
|
| 113 |
+
search_key = f"{product_name}_{country}"
|
| 114 |
+
if search_key in st.session_state.reports:
|
| 115 |
+
st.subheader("📊 **Saved Price Comparison Report**")
|
| 116 |
+
st.markdown(st.session_state.reports[search_key])
|
| 117 |
+
|
| 118 |
+
# **Download Button for the Report**
|
| 119 |
+
# report_json = st.session_state.reports[search_key].encode('utf-8')
|
| 120 |
+
# st.download_button(
|
| 121 |
+
# label="📥 Download Report",
|
| 122 |
+
# data=report_json,
|
| 123 |
+
# file_name=f"{search_key}.json",
|
| 124 |
+
# mime="application/json"
|
| 125 |
+
# )
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
crewai
|
| 2 |
+
streamlit
|
| 3 |
+
langchain-core
|
| 4 |
+
langchain
|
| 5 |
+
langchain-cerebras
|
| 6 |
+
|
src/__init__.py
ADDED
|
File without changes
|
src/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (150 Bytes). View file
|
|
|
src/__pycache__/agents.cpython-310.pyc
ADDED
|
Binary file (1.98 kB). View file
|
|
|
src/__pycache__/config.cpython-310.pyc
ADDED
|
Binary file (675 Bytes). View file
|
|
|
src/__pycache__/crew.cpython-310.pyc
ADDED
|
Binary file (604 Bytes). View file
|
|
|
src/__pycache__/tasks.cpython-310.pyc
ADDED
|
Binary file (2.11 kB). View file
|
|
|
src/__pycache__/tools.cpython-310.pyc
ADDED
|
Binary file (267 Bytes). View file
|
|
|
src/agents.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Agent
|
| 2 |
+
from src.config import cerebras_llm
|
| 3 |
+
from src.tools import search_tool, scrape_tool
|
| 4 |
+
|
| 5 |
+
def create_agents(product_name, country, model_name):
|
| 6 |
+
search = Agent(
|
| 7 |
+
role="E-Commerce Market Research Analyst",
|
| 8 |
+
goal=f"Provide up-to-date market analysis of {product_name} from e-commerce platforms in {country}. Model: {model_name}",
|
| 9 |
+
backstory="An expert analyst with a keen eye for market trends",
|
| 10 |
+
tools=[search_tool, scrape_tool],
|
| 11 |
+
verbose=True,
|
| 12 |
+
llm=cerebras_llm
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
data_cleaner = Agent(
|
| 16 |
+
role="Data Cleaning Specialist",
|
| 17 |
+
goal=f"Ensure all price values for {product_name} are accurate, properly formatted, and free of inconsistencies.",
|
| 18 |
+
backstory=(
|
| 19 |
+
"An experienced data analyst with a strong background in data preprocessing, "
|
| 20 |
+
"error detection, and price standardization. With expertise in handling messy datasets, "
|
| 21 |
+
"you identify and clean incorrect, missing, or inconsistent price values, ensuring the data is reliable for further analysis."
|
| 22 |
+
),
|
| 23 |
+
tools=[],
|
| 24 |
+
verbose=True,
|
| 25 |
+
llm=cerebras_llm
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
comparison = Agent(
|
| 29 |
+
role="Price Comparison Expert",
|
| 30 |
+
goal=f"Analyze and compare {product_name} prices to identify the lowest price available.",
|
| 31 |
+
backstory=(
|
| 32 |
+
"A meticulous price analyst with expertise in comparing product prices across different sources. "
|
| 33 |
+
"You efficiently process pricing data, highlight discrepancies, and determine the best deal for consumers."
|
| 34 |
+
),
|
| 35 |
+
tools=[],
|
| 36 |
+
verbose=True,
|
| 37 |
+
llm=cerebras_llm
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
reporting_agent = Agent(
|
| 41 |
+
role="Market Insights Reporter",
|
| 42 |
+
goal=f"Generate a comprehensive report summarizing price trends, differences, and the best available deals for {product_name}.",
|
| 43 |
+
backstory=(
|
| 44 |
+
"A skilled data journalist with experience in analyzing pricing trends and market fluctuations. "
|
| 45 |
+
"You transform raw pricing data into insightful reports, providing actionable insights on cost-effective options."
|
| 46 |
+
),
|
| 47 |
+
tools=[],
|
| 48 |
+
verbose=True,
|
| 49 |
+
llm=cerebras_llm
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
return search, data_cleaner, comparison, reporting_agent
|
src/config.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from crewai import LLM
|
| 4 |
+
|
| 5 |
+
load_dotenv()
|
| 6 |
+
|
| 7 |
+
# Load API keys from environment variables
|
| 8 |
+
CEREBRAS_API_KEY = os.getenv("CEREBRAS_API_KEY")
|
| 9 |
+
SERPER_API_KEY = os.getenv("SERPER_API_KEY")
|
| 10 |
+
|
| 11 |
+
if not CEREBRAS_API_KEY:
|
| 12 |
+
raise ValueError("Missing Cerebras API Key! Set CEREBRAS_API_KEY in environment variables.")
|
| 13 |
+
|
| 14 |
+
if not SERPER_API_KEY:
|
| 15 |
+
raise ValueError("Missing Serper API Key! Set SERPER_API_KEY in environment variables.")
|
| 16 |
+
|
| 17 |
+
cerebras_llm = LLM(
|
| 18 |
+
model="cerebras/llama-3.3-70b",
|
| 19 |
+
temperature=0.7,
|
| 20 |
+
max_tokens=18192,
|
| 21 |
+
api_key=CEREBRAS_API_KEY,
|
| 22 |
+
base_url="https://api.cerebras.ai/v1",
|
| 23 |
+
)
|
src/crew.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from src.tasks import create_tasks
|
| 2 |
+
from crewai import Crew
|
| 3 |
+
|
| 4 |
+
def create_crew(product_name, country, model_name):
|
| 5 |
+
# Create agents and tasks using the create_tasks function
|
| 6 |
+
search, data_cleaner, comparison, reporting_agent, search_task, cleaning_task, comparison_task, reporting_task = create_tasks(product_name, country, model_name)
|
| 7 |
+
|
| 8 |
+
# Define the crew (agents and tasks)
|
| 9 |
+
event_management_crew = Crew(
|
| 10 |
+
agents=[search, data_cleaner, comparison, reporting_agent],
|
| 11 |
+
tasks=[search_task, cleaning_task, comparison_task, reporting_task],
|
| 12 |
+
verbose=True,
|
| 13 |
+
)
|
| 14 |
+
return event_management_crew
|
src/streamlit_app.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import sys
|
| 3 |
+
import os
|
| 4 |
+
import json
|
| 5 |
+
from src.config import cerebras_llm
|
| 6 |
+
from src.crew import create_crew # Assuming you have a function that creates the crew setup
|
| 7 |
+
|
| 8 |
+
# Ensure the src folder is part of the Python path
|
| 9 |
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')))
|
| 10 |
+
|
| 11 |
+
# Function to run the entire crew
|
| 12 |
+
def run_crew(product_name, country, model_name):
|
| 13 |
+
# Create the crew with agents and tasks
|
| 14 |
+
event_management_crew = create_crew(product_name, country, model_name)
|
| 15 |
+
|
| 16 |
+
# Format the input for the crew
|
| 17 |
+
event_details = {'product': product_name, 'country': country, 'model': model_name}
|
| 18 |
+
|
| 19 |
+
# Execute Crew (this will run all the tasks)
|
| 20 |
+
event_analysis = event_management_crew.kickoff(inputs=event_details)
|
| 21 |
+
|
| 22 |
+
return event_analysis
|
| 23 |
+
|
| 24 |
+
# Function to clean the output and remove unwanted fields
|
| 25 |
+
def clean_output(output):
|
| 26 |
+
if isinstance(output, dict):
|
| 27 |
+
output = json.dumps(output, indent=4)
|
| 28 |
+
output = output.replace('"pydantic":null,', '')
|
| 29 |
+
output = output.replace('"json_dict":null,', '')
|
| 30 |
+
output = output.replace('"tasks_output":[]', '')
|
| 31 |
+
output = output.replace('"token_usage":', '')
|
| 32 |
+
return output
|
| 33 |
+
return output
|
| 34 |
+
|
| 35 |
+
# Streamlit Page Config
|
| 36 |
+
st.set_page_config(page_title="AI Price Comparator", page_icon="🛒", layout="wide")
|
| 37 |
+
|
| 38 |
+
# Initialize session states for history and reports
|
| 39 |
+
if 'history' not in st.session_state:
|
| 40 |
+
st.session_state.history = []
|
| 41 |
+
if 'reports' not in st.session_state:
|
| 42 |
+
st.session_state.reports = {}
|
| 43 |
+
|
| 44 |
+
# Sidebar for API Key Uploads, History, and Model Selection
|
| 45 |
+
with st.sidebar:
|
| 46 |
+
st.header("🔑 **API Keys**")
|
| 47 |
+
cerebras_api_key = st.text_input("🧠 Cerebras API Key", type="password")
|
| 48 |
+
serper_api_key = st.text_input("🔍 Serper API Key", type="password")
|
| 49 |
+
|
| 50 |
+
# Model Selection
|
| 51 |
+
# Sidebar Model Selection
|
| 52 |
+
st.header("🧠 **Select Model**")
|
| 53 |
+
model_name = st.selectbox(
|
| 54 |
+
"Choose a Model",
|
| 55 |
+
["cerebras/llama-3.1-8b", "cerebras/llama-3.3-70b", "cerebras/deepseek-r1-distill-llama-70b"]
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# History Tab
|
| 59 |
+
st.header("📜 **Search History**")
|
| 60 |
+
if st.session_state.history:
|
| 61 |
+
for idx, search in enumerate(st.session_state.history):
|
| 62 |
+
if st.button(f"🔎 {search['product_name']} in {search['country']}", key=f"search_{idx}"):
|
| 63 |
+
st.session_state.selected_search = search # Store selected search
|
| 64 |
+
st.rerun()
|
| 65 |
+
else:
|
| 66 |
+
st.write("No previous searches yet.")
|
| 67 |
+
|
| 68 |
+
# **Main UI**
|
| 69 |
+
st.markdown("## 🚀 **Welcome to the Price Comparison Tool!** 🛒")
|
| 70 |
+
st.write("Enter the product details below to compare prices across multiple platforms. 📉")
|
| 71 |
+
|
| 72 |
+
# **Inputs for product and country (always visible)**
|
| 73 |
+
selected_search = st.session_state.get('selected_search', {})
|
| 74 |
+
|
| 75 |
+
product_name = st.text_input(
|
| 76 |
+
"💡 **Product Name**",
|
| 77 |
+
selected_search.get('product_name', "Sony WH-1000XM5")
|
| 78 |
+
)
|
| 79 |
+
country = st.text_input(
|
| 80 |
+
"🌍 **Country**",
|
| 81 |
+
selected_search.get('country', "United States")
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
# **Button to compare prices**
|
| 85 |
+
if st.button("🔍 **Compare Prices**", help="Click to analyze prices and get a detailed comparison"):
|
| 86 |
+
if product_name and country:
|
| 87 |
+
st.write(f"🛒 **Analyzing prices for** **{product_name}** in **{country}**... 📈")
|
| 88 |
+
|
| 89 |
+
# Run the crew and get the results
|
| 90 |
+
event_analysis = run_crew(product_name, country, model_name)
|
| 91 |
+
|
| 92 |
+
# Clean the output and display the results
|
| 93 |
+
cleaned_output = clean_output(event_analysis)
|
| 94 |
+
|
| 95 |
+
st.subheader("📊 **Price Comparison Report**")
|
| 96 |
+
st.markdown(cleaned_output)
|
| 97 |
+
|
| 98 |
+
# Store the search and report
|
| 99 |
+
search_key = f"{product_name}_{country}"
|
| 100 |
+
search_data = {'product_name': product_name, 'country': country, 'model_name': model_name}
|
| 101 |
+
|
| 102 |
+
if search_data not in st.session_state.history:
|
| 103 |
+
st.session_state.history.append(search_data)
|
| 104 |
+
|
| 105 |
+
st.session_state.reports[search_key] = cleaned_output # Save the report
|
| 106 |
+
|
| 107 |
+
# Clear selected search after displaying results
|
| 108 |
+
st.session_state.selected_search = {'product_name': product_name, 'country': country}
|
| 109 |
+
else:
|
| 110 |
+
st.error("❌ Please enter both product name and country.")
|
| 111 |
+
|
| 112 |
+
# **Display saved report if a past search is selected**
|
| 113 |
+
search_key = f"{product_name}_{country}"
|
| 114 |
+
if search_key in st.session_state.reports:
|
| 115 |
+
st.subheader("📊 **Saved Price Comparison Report**")
|
| 116 |
+
st.markdown(st.session_state.reports[search_key])
|
| 117 |
+
|
| 118 |
+
# **Download Button for the Report**
|
| 119 |
+
# report_json = st.session_state.reports[search_key].encode('utf-8')
|
| 120 |
+
# st.download_button(
|
| 121 |
+
# label="📥 Download Report",
|
| 122 |
+
# data=report_json,
|
| 123 |
+
# file_name=f"{search_key}.json",
|
| 124 |
+
# mime="application/json"
|
| 125 |
+
# )
|
src/tasks.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Task
|
| 2 |
+
from src.agents import create_agents
|
| 3 |
+
|
| 4 |
+
def create_tasks(product_name, country, model_name):
|
| 5 |
+
# Get the agents
|
| 6 |
+
search, data_cleaner, comparison, reporting_agent = create_agents(product_name, country, model_name)
|
| 7 |
+
|
| 8 |
+
# Task definitions
|
| 9 |
+
search_task = Task(
|
| 10 |
+
description=f"Collect current pricing data for {product_name} from at least 3 major e-commerce platforms in {country}. Include product name, model, specifications, price, and any ongoing promotions or discounts.",
|
| 11 |
+
expected_output=f"A structured dataset containing {product_name} information and pricing from multiple sources, with complete pricing details.",
|
| 12 |
+
agent=search
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
cleaning_task = Task(
|
| 16 |
+
description=f"Process the raw pricing data for {product_name} to standardize formats, handle currency conversions, remove outliers, and identify any inconsistencies or errors in the collected price information.",
|
| 17 |
+
expected_output=f"A cleaned dataset with uniformly formatted prices for {product_name}, standardized currencies, and annotations for any identified anomalies or special pricing conditions.",
|
| 18 |
+
agent=data_cleaner
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
comparison_task = Task(
|
| 22 |
+
description=f"Analyze the cleaned pricing data to identify the lowest available price for {product_name}, calculate price differences between retailers, and determine price-to-value ratios based on product specifications.",
|
| 23 |
+
expected_output=f"A comparative analysis showing price rankings for {product_name}, percentage differences between retailers, and identification of the best value options across different price points.",
|
| 24 |
+
agent=comparison
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
reporting_task = Task(
|
| 28 |
+
description=f"Create a comprehensive market insights report based on the {product_name} pricing analysis, highlighting best deals, pricing trends, and actionable recommendations for price-conscious consumers.",
|
| 29 |
+
expected_output=f"A detailed report for {product_name} with executive summary, visualizations of price comparisons, identification of pricing patterns, and specific recommendations for optimal purchasing decisions.",
|
| 30 |
+
agent=reporting_agent
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
# Return both agents and tasks
|
| 34 |
+
return search, data_cleaner, comparison, reporting_agent, search_task, cleaning_task, comparison_task, reporting_task
|
src/tools.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai_tools import ScrapeWebsiteTool, SerperDevTool
|
| 2 |
+
|
| 3 |
+
# Initialize tools
|
| 4 |
+
search_tool = SerperDevTool()
|
| 5 |
+
scrape_tool = ScrapeWebsiteTool()
|
test.ipynb
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 1,
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"outputs": [
|
| 8 |
+
{
|
| 9 |
+
"name": "stderr",
|
| 10 |
+
"output_type": "stream",
|
| 11 |
+
"text": [
|
| 12 |
+
"/opt/anaconda3/envs/agents/lib/python3.10/site-packages/pydantic/_internal/_config.py:295: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.10/migration/\n",
|
| 13 |
+
" warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning)\n",
|
| 14 |
+
"/opt/anaconda3/envs/agents/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py:502: UserWarning: <built-in function callable> is not a Python type (it may be an instance of an object), Pydantic will allow any object with no validation since we cannot even enforce that the input is an instance of the given type. To get rid of this error wrap the type with `pydantic.SkipValidation`.\n",
|
| 15 |
+
" warn(\n",
|
| 16 |
+
"/opt/anaconda3/envs/agents/lib/python3.10/site-packages/crewai_tools/tools/scrapegraph_scrape_tool/scrapegraph_scrape_tool.py:34: PydanticDeprecatedSince20: Pydantic V1 style `@validator` validators are deprecated. You should migrate to Pydantic V2 style `@field_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.10/migration/\n",
|
| 17 |
+
" @validator(\"website_url\")\n",
|
| 18 |
+
"/opt/anaconda3/envs/agents/lib/python3.10/site-packages/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py:26: PydanticDeprecatedSince20: Pydantic V1 style `@validator` validators are deprecated. You should migrate to Pydantic V2 style `@field_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.10/migration/\n",
|
| 19 |
+
" @validator(\"website_url\")\n",
|
| 20 |
+
"/opt/anaconda3/envs/agents/lib/python3.10/site-packages/crewai_tools/tools/vision_tool/vision_tool.py:15: PydanticDeprecatedSince20: Pydantic V1 style `@validator` validators are deprecated. You should migrate to Pydantic V2 style `@field_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.10/migration/\n",
|
| 21 |
+
" @validator(\"image_path_url\")\n"
|
| 22 |
+
]
|
| 23 |
+
}
|
| 24 |
+
],
|
| 25 |
+
"source": [
|
| 26 |
+
"import os\n",
|
| 27 |
+
"from crewai import Agent, Crew, Task, LLM, Process\n",
|
| 28 |
+
"from crewai_tools import ScrapeWebsiteTool, SerperDevTool\n",
|
| 29 |
+
"from dotenv import load_dotenv"
|
| 30 |
+
]
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"cell_type": "code",
|
| 34 |
+
"execution_count": 2,
|
| 35 |
+
"metadata": {},
|
| 36 |
+
"outputs": [],
|
| 37 |
+
"source": [
|
| 38 |
+
"load_dotenv()\n",
|
| 39 |
+
"CEREBRAS_API_KEY = os.getenv(\"CEREBRAS_API_KEY\")\n",
|
| 40 |
+
"SERPER_API_KEY = os.getenv(\"SERPER_API_KEY\")"
|
| 41 |
+
]
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
"cell_type": "code",
|
| 45 |
+
"execution_count": 3,
|
| 46 |
+
"metadata": {},
|
| 47 |
+
"outputs": [],
|
| 48 |
+
"source": [
|
| 49 |
+
"if not CEREBRAS_API_KEY:\n",
|
| 50 |
+
" raise ValueError(\"Missing Cerebras API Key! Set CEREBRAS_API_KEY in environment variables.\")\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"if not SERPER_API_KEY:\n",
|
| 53 |
+
" raise ValueError(\"Missing Serper API Key! Set SERPER_API_KEY in environment variables.\")"
|
| 54 |
+
]
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"cell_type": "code",
|
| 58 |
+
"execution_count": 4,
|
| 59 |
+
"metadata": {},
|
| 60 |
+
"outputs": [],
|
| 61 |
+
"source": [
|
| 62 |
+
"cerebras_llm = LLM(\n",
|
| 63 |
+
" model=\"cerebras/llama-3.3-70b\",\n",
|
| 64 |
+
" temperature=0.7,\n",
|
| 65 |
+
" max_tokens=8192,\n",
|
| 66 |
+
" api_key=CEREBRAS_API_KEY,\n",
|
| 67 |
+
" base_url=\"https://api.cerebras.ai/v1\",\n",
|
| 68 |
+
")"
|
| 69 |
+
]
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"cell_type": "markdown",
|
| 73 |
+
"metadata": {},
|
| 74 |
+
"source": [
|
| 75 |
+
"### Tools"
|
| 76 |
+
]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"cell_type": "code",
|
| 80 |
+
"execution_count": 5,
|
| 81 |
+
"metadata": {},
|
| 82 |
+
"outputs": [],
|
| 83 |
+
"source": [
|
| 84 |
+
"search_tool = SerperDevTool()\n",
|
| 85 |
+
"scrape_tool = ScrapeWebsiteTool()"
|
| 86 |
+
]
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"cell_type": "markdown",
|
| 90 |
+
"metadata": {},
|
| 91 |
+
"source": [
|
| 92 |
+
"### Agents"
|
| 93 |
+
]
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"cell_type": "code",
|
| 97 |
+
"execution_count": 19,
|
| 98 |
+
"metadata": {},
|
| 99 |
+
"outputs": [],
|
| 100 |
+
"source": [
|
| 101 |
+
"search = Agent(\n",
|
| 102 |
+
" role=\"E-Commerce Market Research Analyst\",\n",
|
| 103 |
+
" goal=f\"Provide up-to-date market analysis of {product_name} from E-commerce Industry\",\n",
|
| 104 |
+
" backstory=\"An expert analyst with a keen eye for market trends\",\n",
|
| 105 |
+
" tools=[search_tool, scrape_tool],\n",
|
| 106 |
+
" verbose=True,\n",
|
| 107 |
+
" llm=cerebras_llm\n",
|
| 108 |
+
" )\n",
|
| 109 |
+
"\n",
|
| 110 |
+
"data_cleaner = Agent(\n",
|
| 111 |
+
" role=\"Data Cleaning Specialist\",\n",
|
| 112 |
+
" goal=f\"Ensure all price values for {product_name} are accurate, properly formatted, and free of inconsistencies.\",\n",
|
| 113 |
+
" backstory=(\n",
|
| 114 |
+
" \"An experienced data analyst with a strong background in data preprocessing, \"\n",
|
| 115 |
+
" \"error detection, and price standardization. With expertise in handling messy datasets, \"\n",
|
| 116 |
+
" \"you identify and clean incorrect, missing, or inconsistent price values, ensuring the data is reliable for further analysis.\"\n",
|
| 117 |
+
" ),\n",
|
| 118 |
+
" tools=[],\n",
|
| 119 |
+
" verbose=True,\n",
|
| 120 |
+
" llm=cerebras_llm\n",
|
| 121 |
+
")\n",
|
| 122 |
+
"\n",
|
| 123 |
+
"comparison = Agent(\n",
|
| 124 |
+
" role=\"Price Comparison Expert\",\n",
|
| 125 |
+
" goal=f\"Analyze and compare {product_name} prices to identify the lowest price available.\",\n",
|
| 126 |
+
" backstory=(\n",
|
| 127 |
+
" \"A meticulous price analyst with expertise in comparing product prices across different sources. \"\n",
|
| 128 |
+
" \"You efficiently process pricing data, highlight discrepancies, and determine the best deal for consumers.\"\n",
|
| 129 |
+
" ),\n",
|
| 130 |
+
" tools=[],\n",
|
| 131 |
+
" verbose=True,\n",
|
| 132 |
+
" llm=cerebras_llm\n",
|
| 133 |
+
")\n",
|
| 134 |
+
"\n",
|
| 135 |
+
"reporting_agent = Agent(\n",
|
| 136 |
+
" role=\"Market Insights Reporter\",\n",
|
| 137 |
+
" goal=f\"Generate a comprehensive report summarizing price trends, differences, and the best available deals for {product_name}.\",\n",
|
| 138 |
+
" backstory=(\n",
|
| 139 |
+
" \"A skilled data journalist with experience in analyzing pricing trends and market fluctuations. \"\n",
|
| 140 |
+
" \"You transform raw pricing data into insightful reports, providing actionable insights on cost-effective options.\"\n",
|
| 141 |
+
" ),\n",
|
| 142 |
+
" tools=[],\n",
|
| 143 |
+
" verbose=True,\n",
|
| 144 |
+
" llm=cerebras_llm\n",
|
| 145 |
+
")"
|
| 146 |
+
]
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"cell_type": "markdown",
|
| 150 |
+
"metadata": {},
|
| 151 |
+
"source": [
|
| 152 |
+
"### Tasks "
|
| 153 |
+
]
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"cell_type": "code",
|
| 157 |
+
"execution_count": 20,
|
| 158 |
+
"metadata": {},
|
| 159 |
+
"outputs": [],
|
| 160 |
+
"source": [
|
| 161 |
+
"search_task = Task(\n",
|
| 162 |
+
" description=f\"Collect current pricing data for {product_name} from at least 3 major e-commerce platforms. Include product name, model, specifications, price, and any ongoing promotions or discounts.\",\n",
|
| 163 |
+
" expected_output=f\"A structured dataset containing {product_name} information and pricing from multiple sources, with complete pricing details.\",\n",
|
| 164 |
+
" agent=search\n",
|
| 165 |
+
")\n",
|
| 166 |
+
"\n",
|
| 167 |
+
"cleaning_task = Task(\n",
|
| 168 |
+
" description=f\"Process the raw pricing data for {product_name} to standardize formats, handle currency conversions, remove outliers, and identify any inconsistencies or errors in the collected price information.\",\n",
|
| 169 |
+
" expected_output=f\"A cleaned dataset with uniformly formatted prices for {product_name}, standardized currencies, and annotations for any identified anomalies or special pricing conditions.\",\n",
|
| 170 |
+
" agent=data_cleaner\n",
|
| 171 |
+
")\n",
|
| 172 |
+
"\n",
|
| 173 |
+
"comparison_task = Task(\n",
|
| 174 |
+
" description=f\"Analyze the cleaned pricing data to identify the lowest available price for {product_name}, calculate price differences between retailers, and determine price-to-value ratios based on product specifications.\",\n",
|
| 175 |
+
" expected_output=f\"A comparative analysis showing price rankings for {product_name}, percentage differences between retailers, and identification of the best value options across different price points.\",\n",
|
| 176 |
+
" agent=comparison\n",
|
| 177 |
+
")\n",
|
| 178 |
+
"\n",
|
| 179 |
+
"reporting_task = Task(\n",
|
| 180 |
+
" description=f\"Create a comprehensive market insights report based on the {product_name} pricing analysis, highlighting best deals, pricing trends, and actionable recommendations for price-conscious consumers.\",\n",
|
| 181 |
+
" expected_output=f\"A detailed report for {product_name} with executive summary, visualizations of price comparisons, identification of pricing patterns, and specific recommendations for optimal purchasing decisions.\",\n",
|
| 182 |
+
" agent=reporting_agent\n",
|
| 183 |
+
")"
|
| 184 |
+
]
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"cell_type": "code",
|
| 188 |
+
"execution_count": 21,
|
| 189 |
+
"metadata": {},
|
| 190 |
+
"outputs": [
|
| 191 |
+
{
|
| 192 |
+
"name": "stderr",
|
| 193 |
+
"output_type": "stream",
|
| 194 |
+
"text": [
|
| 195 |
+
"2025-02-25 03:19:07,616 - 8480639040 - __init__.py-__init__:537 - WARNING: Overriding of current TracerProvider is not allowed\n"
|
| 196 |
+
]
|
| 197 |
+
}
|
| 198 |
+
],
|
| 199 |
+
"source": [
|
| 200 |
+
"product_price_crew = Crew(\n",
|
| 201 |
+
" agents=[search, data_cleaner, comparison, reporting_agent],\n",
|
| 202 |
+
" tasks=[search_task, cleaning_task, comparison_task, reporting_task], \n",
|
| 203 |
+
" verbose=True,\n",
|
| 204 |
+
" process=Process.sequential,\n",
|
| 205 |
+
")"
|
| 206 |
+
]
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"cell_type": "code",
|
| 210 |
+
"execution_count": 25,
|
| 211 |
+
"metadata": {},
|
| 212 |
+
"outputs": [],
|
| 213 |
+
"source": [
|
| 214 |
+
"product_name = \"Sony WH-1000XM5\"\n",
|
| 215 |
+
"country = \"United States\"\n",
|
| 216 |
+
"# format = {'product': product_name, 'country': country}\n",
|
| 217 |
+
"format = {'product': product_name}"
|
| 218 |
+
]
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"cell_type": "code",
|
| 222 |
+
"execution_count": 23,
|
| 223 |
+
"metadata": {},
|
| 224 |
+
"outputs": [],
|
| 225 |
+
"source": [
|
| 226 |
+
"product_name = \"Lenovo Earbuds LP40\"\n",
|
| 227 |
+
"country = \"United States\"\n",
|
| 228 |
+
"format = {'product': product_name, 'country': country}"
|
| 229 |
+
]
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"cell_type": "code",
|
| 233 |
+
"execution_count": 1,
|
| 234 |
+
"metadata": {},
|
| 235 |
+
"outputs": [
|
| 236 |
+
{
|
| 237 |
+
"ename": "NameError",
|
| 238 |
+
"evalue": "name 'product_price_crew' is not defined",
|
| 239 |
+
"output_type": "error",
|
| 240 |
+
"traceback": [
|
| 241 |
+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 242 |
+
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
| 243 |
+
"Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Execute Crew\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m event_analysis \u001b[38;5;241m=\u001b[39m \u001b[43mproduct_price_crew\u001b[49m\u001b[38;5;241m.\u001b[39mkickoff(inputs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mformat\u001b[39m)\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# Print the final report\u001b[39;00m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28mprint\u001b[39m(event_analysis)\n",
|
| 244 |
+
"\u001b[0;31mNameError\u001b[0m: name 'product_price_crew' is not defined"
|
| 245 |
+
]
|
| 246 |
+
}
|
| 247 |
+
],
|
| 248 |
+
"source": [
|
| 249 |
+
"# Execute Crew\n",
|
| 250 |
+
"event_analysis = product_price_crew.kickoff(inputs=format)\n",
|
| 251 |
+
"# Print the final report\n",
|
| 252 |
+
"print(event_analysis)"
|
| 253 |
+
]
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"cell_type": "code",
|
| 257 |
+
"execution_count": null,
|
| 258 |
+
"metadata": {},
|
| 259 |
+
"outputs": [],
|
| 260 |
+
"source": []
|
| 261 |
+
}
|
| 262 |
+
],
|
| 263 |
+
"metadata": {
|
| 264 |
+
"kernelspec": {
|
| 265 |
+
"display_name": "agents",
|
| 266 |
+
"language": "python",
|
| 267 |
+
"name": "python3"
|
| 268 |
+
},
|
| 269 |
+
"language_info": {
|
| 270 |
+
"codemirror_mode": {
|
| 271 |
+
"name": "ipython",
|
| 272 |
+
"version": 3
|
| 273 |
+
},
|
| 274 |
+
"file_extension": ".py",
|
| 275 |
+
"mimetype": "text/x-python",
|
| 276 |
+
"name": "python",
|
| 277 |
+
"nbconvert_exporter": "python",
|
| 278 |
+
"pygments_lexer": "ipython3",
|
| 279 |
+
"version": "3.10.16"
|
| 280 |
+
}
|
| 281 |
+
},
|
| 282 |
+
"nbformat": 4,
|
| 283 |
+
"nbformat_minor": 2
|
| 284 |
+
}
|