87 lines
2.7 KiB
Python

import os
import streamlit as st
import pandas as pd
import plotly.express as px
from utils import is_valid_url
from database import Database
from dotenv import load_dotenv
from scraper import scrape_product
load_dotenv()
st.set_page_config(page_title="Price Tracker", page_icon="📊", layout="wide")
with st.spinner("Loading database..."):
db = Database(os.getenv("POSTGRES_URL"))
# Set up sidebar
with st.sidebar:
st.title("Add New Product")
product_url = st.text_input("Product URL")
add_button = st.button("Add Product")
if add_button:
if not product_url:
st.error("Please enter a product URL")
elif not is_valid_url(product_url):
st.error("Please enter a valid URL")
else:
db.add_product(product_url)
with st.spinner("Added product to database. Scraping product data..."):
product_data = scrape_product(product_url)
db.add_price(product_data)
st.success("Product is now being tracked!")
# Main content
st.title("Price Tracker Dashboard")
st.markdown("## Tracked Products")
# Get all products and their price histories
products = db.get_all_products()
# Create a card for each product
for product in products:
price_history = db.get_price_history(product.url)
if price_history:
# Create DataFrame for plotting
df = pd.DataFrame(
[
{"timestamp": ph.timestamp, "price": ph.price, "name": ph.name}
for ph in price_history
]
)
# Create a card-like container for each product
with st.expander(df["name"][0], expanded=False):
st.markdown("---")
col1, col2 = st.columns([1, 3])
with col1:
if price_history[0].main_image_url:
st.image(price_history[0].main_image_url, width=200)
st.metric(
label="Current Price",
value=f"{price_history[0].price} {price_history[0].currency}",
)
with col2:
# Create price history plot
fig = px.line(
df,
x="timestamp",
y="price",
title=None,
)
fig.update_layout(
xaxis_title=None,
yaxis_title="Price ($)",
showlegend=False,
margin=dict(l=0, r=0, t=0, b=0),
height=300,
)
fig.update_xaxes(tickformat="%Y-%m-%d %H:%M", tickangle=45)
fig.update_yaxes(tickprefix="$", tickformat=".2f")
st.plotly_chart(fig, use_container_width=True)