mirror of
https://github.com/Sosokker/Packaged-Food-Explorer.git
synced 2025-12-18 20:54:05 +01:00
Use sqlite as a main tool to manage data/Add GUI
This commit is contained in:
parent
83b136eba1
commit
d9ed761037
13
Essential/FoodSearch.py
Normal file
13
Essential/FoodSearch.py
Normal file
@ -0,0 +1,13 @@
|
||||
import sqlite3
|
||||
|
||||
class FoodSearch:
|
||||
def __init__(self, db_path):
|
||||
self.conn = sqlite3.connect(db_path)
|
||||
self.cursor = self.conn.cursor()
|
||||
|
||||
def search(self, user_input) -> list:
|
||||
query = f"SELECT * FROM food_data WHERE product_name LIKE '%{user_input}%'"
|
||||
self.cursor.execute(query)
|
||||
results = self.cursor.fetchall()
|
||||
|
||||
return results
|
||||
BIN
Essential/__pycache__/FoodSearch.cpython-311.pyc
Normal file
BIN
Essential/__pycache__/FoodSearch.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Essential/__pycache__/foodItem.cpython-311.pyc
Normal file
BIN
Essential/__pycache__/foodItem.cpython-311.pyc
Normal file
Binary file not shown.
83
Essential/foodDatabase.py
Normal file
83
Essential/foodDatabase.py
Normal file
@ -0,0 +1,83 @@
|
||||
import sqlite3
|
||||
|
||||
conn = sqlite3.connect('food.db')
|
||||
c = conn.cursor()
|
||||
|
||||
# create table
|
||||
c.execute('''CREATE TABLE food
|
||||
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
product_name TEXT,
|
||||
brands TEXT,
|
||||
brands_tags TEXT,
|
||||
categories TEXT,
|
||||
categories_tags TEXT,
|
||||
categories_en TEXT,
|
||||
origins TEXT,
|
||||
origins_tags TEXT,
|
||||
origins_en TEXT,
|
||||
countries TEXT,
|
||||
countries_tags TEXT,
|
||||
countries_en TEXT,
|
||||
image_url TEXT,
|
||||
image_ingredients_url TEXT,
|
||||
image_nutrition_url TEXT,
|
||||
energy_kcal_100g REAL,
|
||||
fat_100g REAL,
|
||||
saturated_fat_100g REAL,
|
||||
unsaturated_fat_100g REAL,
|
||||
omega_3_fat_100g REAL,
|
||||
omega_6_fat_100g REAL,
|
||||
omega_9_fat_100g REAL,
|
||||
trans_fat_100g REAL,
|
||||
cholesterol_100g REAL,
|
||||
carbohydrates_100g REAL,
|
||||
sugars_100g REAL,
|
||||
sucrose_100g REAL,
|
||||
glucose_100g REAL,
|
||||
fructose_100g REAL,
|
||||
lactose_100g REAL,
|
||||
maltose_100g REAL,
|
||||
fiber_100g REAL,
|
||||
soluble_fiber_100g REAL,
|
||||
insoluble_fiber_100g REAL,
|
||||
proteins_100g REAL,
|
||||
salt_100g REAL,
|
||||
added_salt_100g REAL,
|
||||
sodium_100g REAL,
|
||||
alcohol_100g REAL,
|
||||
vitamin_a_100g REAL,
|
||||
beta_carotene_100g REAL,
|
||||
vitamin_d_100g REAL,
|
||||
vitamin_e_100g REAL,
|
||||
vitamin_k_100g REAL,
|
||||
vitamin_c_100g REAL,
|
||||
vitamin_b1_100g REAL,
|
||||
vitamin_b2_100g REAL,
|
||||
vitamin_pp_100g REAL,
|
||||
vitamin_b6_100g REAL,
|
||||
vitamin_b9_100g REAL,
|
||||
vitamin_b12_100g REAL,
|
||||
bicarbonate_100g REAL,
|
||||
potassium_100g REAL,
|
||||
chloride_100g REAL,
|
||||
calcium_100g REAL,
|
||||
phosphorus_100g REAL,
|
||||
iron_100g REAL,
|
||||
magnesium_100g REAL,
|
||||
zinc_100g REAL,
|
||||
copper_100g REAL,
|
||||
manganese_100g REAL,
|
||||
fluoride_100g REAL,
|
||||
selenium_100g REAL,
|
||||
chromium_100g REAL,
|
||||
molybdenum_100g REAL,
|
||||
iodine_100g REAL,
|
||||
caffeine_100g REAL,
|
||||
carbon_footprint_100g REAL,
|
||||
carbon_footprint_from_meat_or_fish_100g REAL,
|
||||
cocoa_100g REAL)''')
|
||||
|
||||
# commit changes and close connection
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@ -78,13 +78,11 @@ class foodItem():
|
||||
return False
|
||||
|
||||
def nutrient_score_intl(self):
|
||||
# define the nutrient score factors
|
||||
nutrient_factors = {'fat': 9, 'saturated_fat': 10, 'trans_fat': 10, 'cholesterol': 5,
|
||||
'sodium': 6, 'carbohydrates': 7, 'sugars': 6, 'fiber': 5,
|
||||
'proteins': 5, 'vitamin_a': 15, 'vitamin_c': 15, 'calcium': 10,
|
||||
'iron': 10}
|
||||
|
||||
# calculate the nutrient score for each nutrient
|
||||
nutrient_scores = {}
|
||||
for nutrient, factor in nutrient_factors.items():
|
||||
value = getattr(self, nutrient+'_100g')
|
||||
@ -97,11 +95,11 @@ class foodItem():
|
||||
return total_score
|
||||
|
||||
def _get_daily_requirement(self, nutrient):
|
||||
# define the daily requirement for each nutrient
|
||||
daily_requirement = {'fat': 70, 'saturated_fat': 20, 'trans_fat': 2, 'cholesterol': 300,
|
||||
'sodium': 2000, 'carbohydrates': 260, 'sugars': 90, 'fiber': 38,
|
||||
'proteins': 50, 'vitamin_a': 900, 'vitamin_c': 90, 'calcium': 1000,
|
||||
'iron': 18}
|
||||
|
||||
# for nutrients without a daily requirement, return None
|
||||
return daily_requirement.get(nutrient, None)
|
||||
|
||||
@ -111,4 +109,7 @@ class foodItem():
|
||||
for i, row in df.iterrows():
|
||||
product = cls(row)
|
||||
products.append(product)
|
||||
return products
|
||||
return products
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.product_name
|
||||
24
Essential/prepare_db.py
Normal file
24
Essential/prepare_db.py
Normal file
@ -0,0 +1,24 @@
|
||||
import sqlite3
|
||||
import pandas as pd
|
||||
import re
|
||||
|
||||
thai_df = pd.read_csv('thai_data.csv')
|
||||
us_df = pd.read_csv('us_data.csv')
|
||||
japan_df = pd.read_csv('japan_data.csv')
|
||||
|
||||
conn = sqlite3.connect('food_data.db')
|
||||
|
||||
thai_df = thai_df[~thai_df.product_name.str.contains('to be deleted', na=False, flags=re.IGNORECASE)]
|
||||
japan_df = japan_df[~japan_df.product_name.str.contains('to be deleted', na=False, flags=re.IGNORECASE)]
|
||||
us_df = us_df[~us_df.product_name.str.contains('to be deleted', na=False, flags=re.IGNORECASE)]
|
||||
|
||||
thai_df = thai_df.dropna(subset=['product_name'])
|
||||
japan_df = japan_df.dropna(subset=['product_name'])
|
||||
us_df = us_df.dropna(subset=['product_name'])
|
||||
|
||||
thai_df.to_sql('thai_food', conn, if_exists='replace', index=False)
|
||||
us_df.to_sql('us_food', conn, if_exists='replace', index=False)
|
||||
japan_df.to_sql('japan_food', conn, if_exists='replace', index=False)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
97
app.py
Normal file
97
app.py
Normal file
@ -0,0 +1,97 @@
|
||||
import tkinter as tk
|
||||
import requests
|
||||
import io
|
||||
from PIL import Image, ImageTk
|
||||
from Essential.FoodSearch import FoodSearch
|
||||
|
||||
|
||||
class App:
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self.food_search = FoodSearch('food_data.db')
|
||||
|
||||
self.search_var = tk.StringVar()
|
||||
self.search_var.trace('w', self.search_callback)
|
||||
|
||||
self.search_entry = tk.Entry(self.master, textvariable=self.search_var)
|
||||
self.search_entry.grid(row=0, column=0, padx=10, pady=10)
|
||||
|
||||
self.search_button = tk.Button(self.master, text="Search", command=self.search)
|
||||
self.search_button.grid(row=1, column=0, padx=10, pady=10)
|
||||
|
||||
self.results_frame = tk.Frame(self.master)
|
||||
self.results_frame.grid(row=2, column=0, padx=10, pady=10, sticky="nsew")
|
||||
|
||||
self.scrollbar = tk.Scrollbar(self.results_frame)
|
||||
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
|
||||
self.results_listbox = tk.Listbox(self.results_frame, yscrollcommand=self.scrollbar.set)
|
||||
self.results_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
|
||||
self.scrollbar.config(command=self.results_listbox.yview)
|
||||
|
||||
self.selected_item = None
|
||||
|
||||
self.image_frame = tk.Frame(self.master, bg='white')
|
||||
self.image_frame.grid(row=0, column=2, rowspan=3, padx=10, pady=10, sticky="nsew")
|
||||
|
||||
self.master.columnconfigure(0, weight=1)
|
||||
self.master.columnconfigure(1, weight=0)
|
||||
self.master.columnconfigure(2, weight=1)
|
||||
self.master.rowconfigure(2, weight=1)
|
||||
|
||||
def search_callback(self, *args):
|
||||
pass
|
||||
|
||||
def search(self):
|
||||
results = self.food_search.search(self.search_var.get())
|
||||
self.update_results(results)
|
||||
|
||||
def update_results(self, results):
|
||||
self.results_listbox.delete(0, tk.END)
|
||||
for result in results:
|
||||
self.results_listbox.insert(tk.END, result[1])
|
||||
|
||||
def clear_results(self):
|
||||
self.results_listbox.delete(0, tk.END)
|
||||
|
||||
def on_item_selected(self, event):
|
||||
widget = event.widget
|
||||
selection = widget.curselection()
|
||||
if selection:
|
||||
index = selection[0]
|
||||
value = widget.get(index)
|
||||
self.selected_item = value
|
||||
self.show_image(self.selected_item)
|
||||
|
||||
def show_image(self, item):
|
||||
image_url = None
|
||||
for result in self.food_search.search(self.search_var.get()):
|
||||
if result[1] == item:
|
||||
image_url = result[13]
|
||||
break
|
||||
|
||||
if not image_url:
|
||||
return
|
||||
|
||||
response = requests.get(image_url)
|
||||
img_data = response.content
|
||||
img = Image.open(io.BytesIO(img_data))
|
||||
img = img.resize((300, 300), Image.ANTIALIAS)
|
||||
img_tk = ImageTk.PhotoImage(img)
|
||||
|
||||
# remove old image label widget
|
||||
for widget in self.image_frame.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
self.image_frame.configure(bg='white')
|
||||
label = tk.Label(self.image_frame, image=img_tk, bg='white')
|
||||
label.image = img_tk
|
||||
label.pack(fill=tk.BOTH, expand=True)
|
||||
root = tk.Tk()
|
||||
app = App(root)
|
||||
root.geometry("800x400")
|
||||
root.title('Food Search')
|
||||
app.results_listbox.bind('<<ListboxSelect>>', app.on_item_selected)
|
||||
|
||||
root.mainloop()
|
||||
Loading…
Reference in New Issue
Block a user