234 lines
8.6 KiB
Python
234 lines
8.6 KiB
Python
from flask import Flask, request, render_template_string, redirect, url_for
|
|
import os
|
|
import psycopg2
|
|
|
|
app = Flask(__name__)
|
|
|
|
# Retrieve database connection settings from environment variables.
|
|
db_host = os.environ.get("DB_HOST", "postgres_db")
|
|
db_name = os.environ.get("POSTGRES_DB", "sampledb")
|
|
db_user = os.environ.get("POSTGRES_USER", "user")
|
|
db_password = os.environ.get("POSTGRES_PASSWORD", "password")
|
|
|
|
# Function to get the database connection.
|
|
def get_db_connection():
|
|
conn = psycopg2.connect(
|
|
host=db_host,
|
|
database=db_name,
|
|
user=db_user,
|
|
password=db_password
|
|
)
|
|
return conn
|
|
|
|
# Initialize the database and create the shopping list table if it doesn't exist.
|
|
def init_db():
|
|
conn = get_db_connection()
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS shopping_list (
|
|
id SERIAL PRIMARY KEY,
|
|
item VARCHAR(255) NOT NULL UNIQUE,
|
|
category VARCHAR(100) NOT NULL
|
|
);
|
|
""")
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
|
|
# Function to categorize items intelligently.
|
|
def categorize_item(item_name):
|
|
item_name = item_name.lower()
|
|
|
|
categories = {
|
|
'fruits': ['apple', 'banana', 'orange', 'grape', 'pear'],
|
|
'vegetables': ['carrot', 'broccoli', 'lettuce', 'spinach'],
|
|
'dairy': ['milk', 'cheese', 'yogurt', 'butter'],
|
|
'beverages': ['coffee', 'tea', 'water', 'juice'],
|
|
'snacks': ['chips', 'cookies', 'chocolate', 'nuts'],
|
|
'others': []
|
|
}
|
|
|
|
# Check each category and see if the item belongs.
|
|
for category, items in categories.items():
|
|
if any(item in item_name for item in items):
|
|
return category
|
|
|
|
# Default category if no match is found
|
|
return 'others'
|
|
|
|
@app.route("/", methods=["GET", "POST"])
|
|
def index():
|
|
if request.method == "POST":
|
|
item = request.form.get("item")
|
|
if item:
|
|
# Check if item already exists in the database to avoid duplicates.
|
|
conn = get_db_connection()
|
|
cur = conn.cursor()
|
|
cur.execute("SELECT * FROM shopping_list WHERE item = %s", (item,))
|
|
existing_item = cur.fetchone()
|
|
|
|
if not existing_item: # Only insert if item doesn't exist already.
|
|
category = categorize_item(item)
|
|
cur.execute("INSERT INTO shopping_list (item, category) VALUES (%s, %s)", (item, category))
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
|
|
conn = get_db_connection()
|
|
cur = conn.cursor()
|
|
cur.execute("SELECT * FROM shopping_list;")
|
|
items = cur.fetchall()
|
|
cur.close()
|
|
conn.close()
|
|
|
|
# Group items by category for display purposes.
|
|
categorized_items = {}
|
|
for item in items:
|
|
if item[2] not in categorized_items:
|
|
categorized_items[item[2]] = []
|
|
categorized_items[item[2]].append(item[1])
|
|
|
|
return render_template_string("""
|
|
<html>
|
|
<head>
|
|
<title>Smart Shopping List</title>
|
|
<style>
|
|
body {
|
|
font-family: 'Arial', sans-serif;
|
|
background: linear-gradient(135deg, #ff6e7f, #bfe9ff);
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
color: #fff;
|
|
}
|
|
h1 {
|
|
font-size: 3em;
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 5px;
|
|
}
|
|
.container {
|
|
width: 100%;
|
|
max-width: 800px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 15px;
|
|
padding: 30px;
|
|
box-shadow: 0 4px 40px rgba(0, 0, 0, 0.2);
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
form {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-bottom: 40px;
|
|
}
|
|
input[type="text"] {
|
|
padding: 15px;
|
|
width: 70%;
|
|
border: none;
|
|
border-radius: 10px;
|
|
font-size: 1.2em;
|
|
outline: none;
|
|
margin-right: 15px;
|
|
background: #fff;
|
|
color: #333;
|
|
transition: all 0.3s ease-in-out;
|
|
}
|
|
input[type="text"]:focus {
|
|
transform: scale(1.05);
|
|
border: 2px solid #ff6e7f;
|
|
}
|
|
button {
|
|
padding: 15px 30px;
|
|
background-color: #ff6e7f;
|
|
border: none;
|
|
border-radius: 10px;
|
|
color: #fff;
|
|
font-size: 1.2em;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease-in-out;
|
|
}
|
|
button:hover {
|
|
background-color: #ff3b4d;
|
|
transform: scale(1.05);
|
|
}
|
|
ul {
|
|
list-style-type: none;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
}
|
|
li {
|
|
background: #ffffff;
|
|
color: #333;
|
|
padding: 15px;
|
|
font-size: 1.5em;
|
|
border-radius: 10px;
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
li:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
}
|
|
.category {
|
|
font-size: 1.8em;
|
|
margin-bottom: 20px;
|
|
text-align: center;
|
|
}
|
|
.remove {
|
|
background-color: #ff3b4d;
|
|
padding: 8px;
|
|
border-radius: 5px;
|
|
color: white;
|
|
cursor: pointer;
|
|
}
|
|
.remove:hover {
|
|
background-color: #ff1f2d;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>Smart Shopping List</h1>
|
|
<form method="post">
|
|
<input type="text" name="item" placeholder="What do you need to buy?" required>
|
|
<button type="submit">Add Item</button>
|
|
</form>
|
|
{% for category, items in categorized_items.items() %}
|
|
<div class="category">{{ category|capitalize }}</div>
|
|
<ul>
|
|
{% for item in items %}
|
|
<li>
|
|
{{ item }}
|
|
<a href="{{ url_for('remove_item', item_name=item) }}" class="remove">Remove</a>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% endfor %}
|
|
</div>
|
|
</body>
|
|
</html>
|
|
""", categorized_items=categorized_items)
|
|
|
|
# Route to remove an item from the shopping list.
|
|
@app.route("/remove/<item_name>")
|
|
def remove_item(item_name):
|
|
conn = get_db_connection()
|
|
cur = conn.cursor()
|
|
cur.execute("DELETE FROM shopping_list WHERE item = %s", (item_name,))
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
return redirect(url_for('index'))
|
|
|
|
if __name__ == "__main__":
|
|
init_db() # Initialize the database and table
|
|
app.run(host='0.0.0.0', port=5000)
|