mirror of
https://github.com/Sosokker/Packaged-Food-Explorer.git
synced 2025-12-20 13:44:04 +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
|
return False
|
||||||
|
|
||||||
def nutrient_score_intl(self):
|
def nutrient_score_intl(self):
|
||||||
# define the nutrient score factors
|
|
||||||
nutrient_factors = {'fat': 9, 'saturated_fat': 10, 'trans_fat': 10, 'cholesterol': 5,
|
nutrient_factors = {'fat': 9, 'saturated_fat': 10, 'trans_fat': 10, 'cholesterol': 5,
|
||||||
'sodium': 6, 'carbohydrates': 7, 'sugars': 6, 'fiber': 5,
|
'sodium': 6, 'carbohydrates': 7, 'sugars': 6, 'fiber': 5,
|
||||||
'proteins': 5, 'vitamin_a': 15, 'vitamin_c': 15, 'calcium': 10,
|
'proteins': 5, 'vitamin_a': 15, 'vitamin_c': 15, 'calcium': 10,
|
||||||
'iron': 10}
|
'iron': 10}
|
||||||
|
|
||||||
# calculate the nutrient score for each nutrient
|
|
||||||
nutrient_scores = {}
|
nutrient_scores = {}
|
||||||
for nutrient, factor in nutrient_factors.items():
|
for nutrient, factor in nutrient_factors.items():
|
||||||
value = getattr(self, nutrient+'_100g')
|
value = getattr(self, nutrient+'_100g')
|
||||||
@ -97,11 +95,11 @@ class foodItem():
|
|||||||
return total_score
|
return total_score
|
||||||
|
|
||||||
def _get_daily_requirement(self, nutrient):
|
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,
|
daily_requirement = {'fat': 70, 'saturated_fat': 20, 'trans_fat': 2, 'cholesterol': 300,
|
||||||
'sodium': 2000, 'carbohydrates': 260, 'sugars': 90, 'fiber': 38,
|
'sodium': 2000, 'carbohydrates': 260, 'sugars': 90, 'fiber': 38,
|
||||||
'proteins': 50, 'vitamin_a': 900, 'vitamin_c': 90, 'calcium': 1000,
|
'proteins': 50, 'vitamin_a': 900, 'vitamin_c': 90, 'calcium': 1000,
|
||||||
'iron': 18}
|
'iron': 18}
|
||||||
|
|
||||||
# for nutrients without a daily requirement, return None
|
# for nutrients without a daily requirement, return None
|
||||||
return daily_requirement.get(nutrient, None)
|
return daily_requirement.get(nutrient, None)
|
||||||
|
|
||||||
@ -112,3 +110,6 @@ class foodItem():
|
|||||||
product = cls(row)
|
product = cls(row)
|
||||||
products.append(product)
|
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