Use sqlite as a main tool to manage data/Add GUI

This commit is contained in:
sosokker 2023-05-02 14:21:10 +07:00 committed by GitHub
parent 83b136eba1
commit d9ed761037
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 222 additions and 4 deletions

13
Essential/FoodSearch.py Normal file
View 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

Binary file not shown.

Binary file not shown.

83
Essential/foodDatabase.py Normal file
View 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()

View File

@ -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
View 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
View 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()