kerols77 commited on
Commit
49c3811
·
verified ·
1 Parent(s): ac720d8

Upload 8 files

Browse files
Datasets/Final used Datasets/disease_food_nutrition_mapping.csv ADDED
The diff for this file is too large to render. See raw diff
 
Datasets/Final used Datasets/food_dataset_with_nutriition.csv ADDED
The diff for this file is too large to render. See raw diff
 
Dockerfile ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official lightweight Python image.
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies required by some Python packages.
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ git \
8
+ wget \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Set the working directory inside the container.
12
+ WORKDIR /app
13
+
14
+ # Copy the requirements file and install the Python dependencies.
15
+ # This helps leverage Docker's layer caching when dependencies don’t change.
16
+ COPY requirements.txt .
17
+ RUN pip install --upgrade pip && pip install -r requirements.txt
18
+
19
+ # Copy your entire project into the container.
20
+ COPY . .
21
+
22
+ # Set an environment variable for the port; your code defaults to port 7860.
23
+ ENV PORT=7860
24
+
25
+ # Expose the port (Hugging Face Spaces will map this externally).
26
+ EXPOSE 7860
27
+
28
+ # Define the command to run your Flask app.
29
+ # Make sure the file name below matches the name of your main Python file.
30
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,621 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ import pandas as pd
3
+ from transformers import pipeline
4
+ import os
5
+ import re
6
+ import json
7
+ import requests
8
+ import random
9
+ from difflib import get_close_matches
10
+ from textblob import TextBlob
11
+ from nltk.tokenize import word_tokenize, sent_tokenize
12
+ import nltk
13
+ import ast
14
+ from urllib.parse import quote
15
+
16
+ def force_download_nltk():
17
+ needed_packages = ['punkt']
18
+ for package in needed_packages:
19
+ try:
20
+ nltk.data.find(f'tokenizers/{package}')
21
+ except LookupError:
22
+ print(f"Downloading NLTK package: {package}")
23
+ nltk.download(package)
24
+ force_download_nltk()
25
+
26
+ domain_words = {
27
+ "carb", "carbs", "carbo", "carbohydrate", "carbohydrates",
28
+ "fat", "fats", "protein", "proteins", "fiber", "cholesterol",
29
+ "calcium", "iron", "magnesium", "potassium", "sodium", "vitamin", "vitamin c",
30
+ "calories", "calorie"
31
+ }
32
+
33
+ def smart_correct_spelling(text, domain_set):
34
+ tokens = word_tokenize(text)
35
+ corrected_tokens = []
36
+ for token in tokens:
37
+ if token.isalpha() and token.lower() not in domain_set:
38
+ corrected_word = str(TextBlob(token).correct())
39
+ corrected_tokens.append(corrected_word)
40
+ else:
41
+ corrected_tokens.append(token)
42
+ return " ".join(corrected_tokens)
43
+
44
+ qa_pipeline = pipeline("question-answering", model="distilbert-base-cased-distilled-squad")
45
+ classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
46
+ summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
47
+
48
+ def summarize_input(text):
49
+ summary = summarizer(text, max_length=130, min_length=30, do_sample=False)
50
+ return summary[0]['summary_text']
51
+
52
+ df = pd.read_csv(r"Datasets\Final used Datasets\food_dataset_with_nutriition.csv")
53
+ print(f"Starting with {len(df)} recipes in dataset")
54
+ nutrition_columns = ["calories", "Total fats", "Carbohydrate", "Fiber", "Protein",
55
+ "Cholesterol", "Calcium", "Iron", "Magnesium", "Potassium", "Sodium", "Vitamin C"]
56
+ for col in nutrition_columns:
57
+ df[col] = pd.to_numeric(df[col], errors='coerce')
58
+
59
+ disease_df = pd.read_csv(r"Datasets\Final used Datasets\disease_food_nutrition_mapping.csv")
60
+ disease_df["Disease"] = disease_df["Disease"].str.lower()
61
+
62
+ try:
63
+ with open(r"docs\common_misspellings.json", "r") as file:
64
+ common_misspellings = json.load(file)
65
+ except FileNotFoundError:
66
+ common_misspellings = {"suger": "sugar", "milc": "milk"}
67
+ with open(r"docs\common_misspellings.json", "w") as file:
68
+ json.dump(common_misspellings, file, indent=2)
69
+
70
+ try:
71
+ with open(r"docs\common_ingredients.json", "r") as file:
72
+ common_ingredients = json.load(file)
73
+ except FileNotFoundError:
74
+ common_ingredients = ["sugar", "salt", "flour", "milk", "eggs", "butter", "oil", "water"]
75
+ with open(r"docs\common_ingredients.json", "w") as file:
76
+ json.dump(common_ingredients, file, indent=2)
77
+
78
+ def create_ingredient_dictionary(dataframe, common_ingredients_list):
79
+ all_ingredients = []
80
+ all_ingredients.extend(common_ingredients_list)
81
+ all_ingredients.extend(set(common_misspellings.values()))
82
+ for ingredients_list in dataframe['ingredients']:
83
+ parts = re.split(r',|\sand\s|\sor\s|;', str(ingredients_list))
84
+ for part in parts:
85
+ clean_part = re.sub(
86
+ r'\d+[\s/]*(oz|ounce|cup|tbsp|tsp|tablespoon|teaspoon|pound|lb|g|ml|l|pinch|dash)\b\.?',
87
+ '', part)
88
+ clean_part = re.sub(
89
+ r'\b(fresh|freshly|chopped|minced|diced|sliced|grated|ground|powdered|crushed|toasted|roasted)\b',
90
+ '', clean_part)
91
+ clean_part = re.sub(r'\(.*?\)', '', clean_part)
92
+ clean_part = clean_part.strip()
93
+ subparts = re.split(r'\sand\s|\sor\s', clean_part)
94
+ for subpart in subparts:
95
+ cleaned_subpart = subpart.strip().lower()
96
+ if cleaned_subpart and len(cleaned_subpart) > 2:
97
+ all_ingredients.append(cleaned_subpart)
98
+ unique_ingredients = list(set(all_ingredients))
99
+ unique_ingredients.sort(key=len, reverse=True)
100
+ return unique_ingredients
101
+ food_dictionary = create_ingredient_dictionary(df, common_ingredients)
102
+
103
+ def identify_food_ingredient(text, ingredient_dict, misspellings_dict):
104
+ cleaned = re.sub(
105
+ r'\d+[\s/]*(oz|ounce|cup|tbsp|tsp|tablespoon|teaspoon|pound|lb|g|ml|l|pinch|dash)\b\.?',
106
+ '', text)
107
+ cleaned = re.sub(
108
+ r'\b(fresh|freshly|chopped|minced|diced|sliced|grated|ground|powdered|crushed|toasted|roasted)\b',
109
+ '', cleaned)
110
+ cleaned = re.sub(r'\(.*?\)', '', cleaned)
111
+ cleaned = cleaned.strip().lower()
112
+ if cleaned in misspellings_dict:
113
+ return misspellings_dict[cleaned]
114
+ if cleaned in ingredient_dict:
115
+ return cleaned
116
+ words = cleaned.split()
117
+ for word in words:
118
+ if word in ingredient_dict:
119
+ return word
120
+ if word in misspellings_dict:
121
+ return misspellings_dict[word]
122
+ close_matches = get_close_matches(cleaned, ingredient_dict, n=3, cutoff=0.8)
123
+ if close_matches:
124
+ return close_matches[0]
125
+ for dict_ingredient in ingredient_dict:
126
+ if dict_ingredient in cleaned:
127
+ return dict_ingredient
128
+ close_matches = get_close_matches(cleaned, ingredient_dict, n=3, cutoff=0.6)
129
+ if close_matches:
130
+ return close_matches[0]
131
+ return None
132
+
133
+ def correct_food_ingredient(ingredient, ingredient_dict, misspellings_dict):
134
+ cleaned = re.sub(
135
+ r'\d+[\s/]*(oz|ounce|cup|tbsp|tsp|tablespoon|teaspoon|pound|lb|g|ml|l|pinch|dash)\b\.?',
136
+ '', ingredient)
137
+ cleaned = re.sub(
138
+ r'\b(fresh|freshly|chopped|minced|diced|sliced|grated|ground|powdered|crushed|toasted|roasted)\b',
139
+ '', cleaned)
140
+ cleaned = re.sub(r'\(.*?\)', '', cleaned)
141
+ cleaned = cleaned.strip().lower()
142
+ if cleaned in misspellings_dict:
143
+ return misspellings_dict[cleaned]
144
+ if cleaned in ingredient_dict:
145
+ return cleaned
146
+ close_matches = get_close_matches(cleaned, ingredient_dict, n=3, cutoff=0.8)
147
+ if close_matches:
148
+ return close_matches[0]
149
+ close_matches = get_close_matches(cleaned, ingredient_dict, n=3, cutoff=0.6)
150
+ if close_matches:
151
+ return close_matches[0]
152
+ for dict_ingredient in ingredient_dict:
153
+ if cleaned in dict_ingredient or dict_ingredient in cleaned:
154
+ return dict_ingredient
155
+ return cleaned
156
+
157
+ def add_misspelling(misspelled, correct):
158
+ try:
159
+ with open(r"docs\common_misspellings.json", "r") as file:
160
+ misspellings = json.load(file)
161
+ misspellings[misspelled.lower()] = correct.lower()
162
+ with open(r"docs\common_misspellings.json", "w") as file:
163
+ json.dump(misspellings, file, indent=2, sort_keys=True)
164
+ return True
165
+ except Exception:
166
+ return False
167
+
168
+ def extract_unwanted_ingredients(input_text):
169
+ question = "What ingredients should be excluded?"
170
+ result = qa_pipeline(question=question, context=input_text)
171
+ raw_answer = result['answer']
172
+ potential_ingredients = []
173
+ for part in raw_answer.split(','):
174
+ for subpart in part.split(' and '):
175
+ for item in subpart.split(' or '):
176
+ clean_item = item.strip()
177
+ if clean_item:
178
+ potential_ingredients.append(clean_item)
179
+ valid_ingredients = []
180
+ for item in potential_ingredients:
181
+ corrected = identify_food_ingredient(item, food_dictionary, common_misspellings)
182
+ if corrected:
183
+ valid_ingredients.append(corrected)
184
+ return valid_ingredients if valid_ingredients else [raw_answer]
185
+
186
+ def classify_clause(clause):
187
+ candidate_labels = ["include", "exclude"]
188
+ result = classifier(clause, candidate_labels, hypothesis_template="This clause means the ingredient should be {}.")
189
+ return result["labels"][0].lower()
190
+
191
+ def extract_ingredients_from_clause(clause, ingredient_dict, misspellings_dict):
192
+ found = []
193
+ for ingredient in ingredient_dict:
194
+ if ingredient.lower() in clause.lower():
195
+ normalized = identify_food_ingredient(ingredient, ingredient_dict, misspellings_dict)
196
+ if normalized:
197
+ found.append(normalized)
198
+ return list(set(found))
199
+
200
+ def classify_ingredients_in_query(query, ingredient_dict, misspellings_dict):
201
+ include_ingredients = []
202
+ exclude_ingredients = []
203
+
204
+ nutrition_terms = ['calories', 'calorie', 'fat', 'fats', 'carb', 'carbs', 'protein',
205
+ 'fiber', 'cholesterol', 'calcium', 'iron', 'magnesium',
206
+ 'potassium', 'sodium', 'vitamin']
207
+ modified_query = query
208
+ for term in nutrition_terms:
209
+ pattern = re.compile(r'(low|high)\s+' + term, re.IGNORECASE)
210
+ modified_query = pattern.sub('', modified_query)
211
+ clauses = re.split(r'\bbut\b|,', modified_query, flags=re.IGNORECASE)
212
+ for clause in clauses:
213
+ clause = clause.strip()
214
+ if not clause:
215
+ continue
216
+ intent = classify_clause(clause)
217
+ ingredients_found = extract_ingredients_from_clause(clause, ingredient_dict, misspellings_dict)
218
+ if intent == "include":
219
+ include_ingredients.extend(ingredients_found)
220
+ elif intent == "exclude":
221
+ exclude_ingredients.extend(ingredients_found)
222
+ return list(set(include_ingredients)), list(set(exclude_ingredients))
223
+
224
+ def extract_nutrition_from_clause(clause, nutrition_dict, misspellings_dict):
225
+ found = []
226
+ clause_lower = clause.lower()
227
+ sorted_terms = sorted(nutrition_dict, key=lambda x: -len(x))
228
+ for term in sorted_terms:
229
+ pattern = r'\b' + re.escape(term.lower()) + r'\b'
230
+ if re.search(pattern, clause_lower):
231
+ found.append(term.lower())
232
+ return list(set(found))
233
+
234
+ def classify_nutrition_in_query(query, nutrition_dict, misspellings_dict):
235
+ include_nutrition = []
236
+ exclude_nutrition = []
237
+ clauses = re.split(r'\band\b|,|but', query, flags=re.IGNORECASE)
238
+ overall_intent = "exclude" if re.search(r'sensitivity|allergy|exclude', query, flags=re.IGNORECASE) else "include"
239
+ for clause in clauses:
240
+ clause = clause.strip()
241
+ if not clause:
242
+ continue
243
+ intent = "include" if "i want" in clause.lower() else overall_intent
244
+ numbers = re.findall(r'\d+(?:\.\d+)?', clause)
245
+ threshold = float(numbers[0]) if numbers else None
246
+ if re.search(r'\b(high|over|above|more than|exceeding)\b', clause, flags=re.IGNORECASE):
247
+ modifier = "high"
248
+ elif re.search(r'\b(low|under|less than|below)\b', clause, flags=re.IGNORECASE):
249
+ modifier = "low"
250
+ else:
251
+ modifier = "high" if intent == "exclude" else "low"
252
+ terms_found = extract_nutrition_from_clause(clause, nutrition_dict, misspellings_dict)
253
+ for term in terms_found:
254
+ norm_term = nutrition_terms_dictionary.get(term, term)
255
+ condition = (modifier, norm_term, threshold) if threshold is not None else (modifier, norm_term)
256
+ if intent == "include":
257
+ include_nutrition.append(condition)
258
+ elif intent == "exclude":
259
+ exclude_nutrition.append(condition)
260
+ return list(set(include_nutrition)), list(set(exclude_nutrition))
261
+
262
+ nutrition_terms_dictionary = {
263
+ "calorie": "calories",
264
+ "calories": "calories",
265
+ "fat": "Total fats",
266
+ "fats": "Total fats",
267
+ "total fat": "Total fats",
268
+ "total fats": "Total fats",
269
+ "carb": "Carbohydrate",
270
+ "carbs": "Carbohydrate",
271
+ "carbo": "Carbohydrate",
272
+ "carbohydrate": "Carbohydrate",
273
+ "carbohydrates": "Carbohydrate",
274
+ "fiber": "Fiber",
275
+ "protein": "Protein",
276
+ "proteins": "Protein",
277
+ "cholesterol": "Cholesterol",
278
+ "calcium": "Calcium",
279
+ "iron": "Iron",
280
+ "magnesium": "Magnesium",
281
+ "potassium": "Potassium",
282
+ "sodium": "Sodium",
283
+ "vitamin c": "Vitamin C"
284
+ }
285
+
286
+ fixed_thresholds = {
287
+ "calories": 700,
288
+ "Total fats": 60,
289
+ "Carbohydrate": 120,
290
+ "Fiber": 10,
291
+ "Protein": 30,
292
+ "Cholesterol": 100,
293
+ "Calcium": 300,
294
+ "Iron": 5,
295
+ "Magnesium": 100,
296
+ "Potassium": 300,
297
+ "Sodium": 400,
298
+ "Vitamin C": 50
299
+ }
300
+
301
+ def filter_by_nutrition_condition(df, condition):
302
+ if isinstance(condition, tuple):
303
+ if len(condition) == 3:
304
+ direction, nutrition_term, threshold = condition
305
+ elif len(condition) == 2:
306
+ direction, nutrition_term = condition
307
+ threshold = fixed_thresholds.get(nutrition_term)
308
+ else:
309
+ return df
310
+ column = nutrition_term
311
+ if column is None or threshold is None:
312
+ return df
313
+ if direction == "low":
314
+ return df[df[column] < threshold]
315
+ elif direction == "high":
316
+ return df[df[column] >= threshold]
317
+ return df
318
+
319
+ def score_recipe_ingredients(recipe_ingredients, include_list):
320
+ recipe_lower = recipe_ingredients.lower()
321
+ match_count = sum(
322
+ 1 for ingredient in include_list
323
+ if ingredient.lower() in recipe_lower
324
+ )
325
+ return match_count
326
+
327
+ def filter_and_rank_recipes(df, include_list, exclude_list, include_nutrition, exclude_nutrition):
328
+ filtered_df = df.copy()
329
+ print(f"Starting with {len(filtered_df)} recipes for filtering")
330
+ if include_list:
331
+ filtered_df['ingredient_match_count'] = filtered_df['ingredients'].apply(
332
+ lambda x: score_recipe_ingredients(str(x), include_list)
333
+ )
334
+ filtered_df = filtered_df[filtered_df['ingredient_match_count'] >= 2]
335
+ print(f"After requiring at least 2 included ingredients: {len(filtered_df)} recipes remain")
336
+ for ingredient in exclude_list:
337
+ before_count = len(filtered_df)
338
+ filtered_df = filtered_df[
339
+ ~filtered_df['ingredients']
340
+ .str.lower()
341
+ .fillna('')
342
+ .str.contains(re.escape(ingredient.lower()))
343
+ ]
344
+ print(f"After excluding '{ingredient}': {len(filtered_df)} recipes remain (removed {before_count - len(filtered_df)})")
345
+ for i, cond in enumerate(include_nutrition):
346
+ before_count = len(filtered_df)
347
+ filtered_df = filter_by_nutrition_condition(filtered_df, cond)
348
+ after_count = len(filtered_df)
349
+ print(f"After applying nutrition condition {i+1} (include) '{cond}': {after_count} recipes remain (removed {before_count - after_count})")
350
+ for i, cond in enumerate(exclude_nutrition):
351
+ before_count = len(filtered_df)
352
+ temp_df = filter_by_nutrition_condition(df.copy(), cond)
353
+ filtered_df = filtered_df[~filtered_df.index.isin(temp_df.index)]
354
+ after_count = len(filtered_df)
355
+ print(f"After applying nutrition condition {i+1} (exclude) '{cond}': {after_count} recipes remain (removed {before_count - after_count})")
356
+ if filtered_df.empty:
357
+ print("\nNo recipes match all criteria. Implementing fallback approach...")
358
+ fallback_df = df.copy()
359
+ if include_list:
360
+ fallback_df['ingredient_match_count'] = fallback_df['ingredients'].apply(
361
+ lambda x: score_recipe_ingredients(str(x), include_list)
362
+ )
363
+ fallback_df = fallback_df[fallback_df['ingredient_match_count'] >= 1]
364
+ else:
365
+ fallback_df['ingredient_match_count'] = 1
366
+ for ingredient in exclude_list:
367
+ fallback_df = fallback_df[
368
+ ~fallback_df['ingredients']
369
+ .str.lower()
370
+ .fillna('')
371
+ .str.contains(re.escape(ingredient.lower()))
372
+ ]
373
+ if fallback_df.empty:
374
+ fallback_df = df.sample(min(5, len(df)))
375
+ fallback_df['ingredient_match_count'] = 0
376
+ print("No matches found. Showing random recipes as a fallback")
377
+ filtered_df = fallback_df
378
+ if 'ingredient_match_count' not in filtered_df.columns:
379
+ filtered_df['ingredient_match_count'] = 0
380
+ filtered_df = filtered_df.sort_values('ingredient_match_count', ascending=False)
381
+ return filtered_df
382
+
383
+ def get_disease_recommendations(user_text, disease_mapping_df):
384
+ user_text_lower = user_text.lower()
385
+ matches = disease_mapping_df[disease_mapping_df['Disease'].apply(lambda d: d in user_text_lower)]
386
+ if not matches.empty:
387
+ disease_info = matches.iloc[0]
388
+ def safe_parse_list(x):
389
+ if isinstance(x, str):
390
+ try:
391
+ return ast.literal_eval(x)
392
+ except:
393
+ return [item.strip() for item in x.split(',') if item.strip()]
394
+ return x
395
+ best_foods = safe_parse_list(disease_info.get("Best_Foods", "[]"))
396
+ worst_foods = safe_parse_list(disease_info.get("Worst_Foods", "[]"))
397
+ best_nutrition = safe_parse_list(disease_info.get("Best_Nutrition", "[]"))
398
+ worst_nutrition = safe_parse_list(disease_info.get("Worst_Nutrition", "[]"))
399
+ recommendations = {
400
+ "Disease": disease_info['Disease'],
401
+ "Best_Foods": best_foods,
402
+ "Worst_Foods": worst_foods,
403
+ "Best_Nutrition": best_nutrition,
404
+ "Worst_Nutrition": worst_nutrition
405
+ }
406
+ return recommendations
407
+ return None
408
+
409
+ def get_recipe_output(recipe_row):
410
+ recipe_name = recipe_row['title']
411
+ ner_info = recipe_row.get('NER', '')
412
+ try:
413
+ ner_list = json.loads(ner_info)
414
+ ner_str = ", ".join(ner_list)
415
+ except Exception:
416
+ ner_str = ner_info
417
+ nutrition_details = {col: float(recipe_row[col]) for col in nutrition_columns}
418
+ result = {
419
+ "Meal name": recipe_name,
420
+ "NER": ner_str,
421
+ "Nutrition details": nutrition_details
422
+ }
423
+ print(f"Meal name: {recipe_name}")
424
+ print(f"NER: {ner_str}")
425
+ print(f"Nutrition details: {nutrition_details}")
426
+ return result
427
+
428
+ def process_long_query(query):
429
+ if len(query.split()) > 500:
430
+ print("Long input detected. Summarizing...")
431
+ query = summarize_input(query)
432
+ print(f"Processed Query: \"{query}\"")
433
+ corrected = smart_correct_spelling(query, domain_words)
434
+ sentences = sent_tokenize(corrected)
435
+ aggregated_include = []
436
+ aggregated_exclude = []
437
+ aggregated_include_nutrition = []
438
+ aggregated_exclude_nutrition = []
439
+ for sentence in sentences:
440
+ inc, exc = classify_ingredients_in_query(sentence, food_dictionary, common_misspellings)
441
+ aggregated_include.extend(inc)
442
+ aggregated_exclude.extend(exc)
443
+ inc_nut, exc_nut = classify_nutrition_in_query(sentence, list(nutrition_terms_dictionary.keys()), common_misspellings)
444
+ aggregated_include_nutrition.extend(inc_nut)
445
+ aggregated_exclude_nutrition.extend(exc_nut)
446
+ return corrected, list(set(aggregated_include)), list(set(aggregated_exclude)), \
447
+ list(set(aggregated_include_nutrition)), list(set(aggregated_exclude_nutrition))
448
+
449
+ def send_to_api(meal_data, parent_id):
450
+ try:
451
+ api_endpoint = "http://54.242.19.19:3000/api/ResturantMenu/add"
452
+ meal_id = random.randint(1000, 9999)
453
+ meal_name = meal_data.get("Meal name", "No meal name available")
454
+ ner_info = meal_data.get("NER", "")
455
+ images_public = "https://kero.beshoy.me/recipe_images/"
456
+ image_path = True
457
+ image_url = ""
458
+ if image_path:
459
+ try:
460
+ image_url = images_public + quote(meal_name, safe="") + ".jpg"
461
+ print(f"Successfully uploaded image to the server for {meal_name}: {image_url}")
462
+ except Exception as cl_err:
463
+ print(f"Error uploading to the server: {cl_err}")
464
+ if not image_url:
465
+ image_url = "https://picsum.photos/200"
466
+ payload = {
467
+ "id": str(meal_id),
468
+ "name": meal_name,
469
+ "description": ner_info,
470
+ "photo": image_url,
471
+ "parentId": parent_id
472
+ }
473
+ print(f"\nSending payload to API: {payload}")
474
+ response = requests.post(api_endpoint, json=payload)
475
+ print(f"API Response for meal {meal_name}: {response.status_code}")
476
+
477
+ try:
478
+ return response.json()
479
+ except Exception:
480
+ return {"error": response.text}
481
+ except Exception as e:
482
+ print(f"Error sending meal to API: {e}")
483
+ return {"error": str(e)}
484
+
485
+ app = Flask(__name__)
486
+ @app.route('/process', methods=['POST'])
487
+ def process():
488
+ try:
489
+
490
+ input_text = ""
491
+ parent_id = ""
492
+
493
+ if request.is_json:
494
+
495
+ data = request.json
496
+ input_text = data.get("description", "")
497
+ parent_id = data.get("parentId", "")
498
+
499
+ if not input_text:
500
+ return jsonify({"error": "Missing description in request"}), 400
501
+ if not parent_id:
502
+ return jsonify({"error": "Missing parentId in request"}), 400
503
+
504
+ else:
505
+
506
+ input_text_json = request.form
507
+ input_text = input_text_json.get("description", "")
508
+ parent_id = input_text_json.get("parentId", "")
509
+
510
+ if not input_text:
511
+ return jsonify({"error": "Missing description in request"}), 400
512
+ if not parent_id:
513
+ return jsonify({"error": "Missing parentId in request"}), 400
514
+
515
+ print("WARNING: Using raw data format. Please consider using JSON format.")
516
+
517
+ raw_input_text = input_text
518
+ processed_input, user_include, user_exclude, user_include_nutrition, user_exclude_nutrition = process_long_query(raw_input_text)
519
+
520
+ include_list, exclude_list = [], []
521
+ include_nutrition, exclude_nutrition = [], []
522
+
523
+ disease_recs = get_disease_recommendations(processed_input, disease_df)
524
+
525
+ if disease_recs:
526
+ print("\nDisease-related Recommendations Detected:")
527
+ print(f"Disease: {disease_recs['Disease']}")
528
+ print(f"Best Foods: {disease_recs['Best_Foods']}")
529
+ print(f"Worst Foods: {disease_recs['Worst_Foods']}")
530
+ print(f"Best Nutrition: {disease_recs['Best_Nutrition']}")
531
+ print(f"Worst Nutrition: {disease_recs['Worst_Nutrition']}")
532
+
533
+ include_list.extend(disease_recs["Best_Foods"])
534
+ exclude_list.extend(disease_recs["Worst_Foods"])
535
+
536
+ def parse_nutrition_condition(nutrition_phrase):
537
+ parts = nutrition_phrase.strip().split()
538
+ if len(parts) == 2:
539
+ direction = parts[0].lower()
540
+ nutrient = parts[1].lower()
541
+ mapped_nutrient = nutrition_terms_dictionary.get(nutrient, nutrient)
542
+ return (direction, mapped_nutrient)
543
+ return None
544
+
545
+ for bn in disease_recs["Best_Nutrition"]:
546
+ cond = parse_nutrition_condition(bn)
547
+ if cond:
548
+ include_nutrition.append(cond)
549
+ for wn in disease_recs["Worst_Nutrition"]:
550
+ cond = parse_nutrition_condition(wn)
551
+ if cond:
552
+ exclude_nutrition.append(cond)
553
+
554
+ include_list.extend(user_include)
555
+ exclude_list.extend(user_exclude)
556
+ include_nutrition.extend(user_include_nutrition)
557
+ exclude_nutrition.extend(user_exclude_nutrition)
558
+
559
+ include_list = list(set(include_list))
560
+ exclude_list = list(set(exclude_list))
561
+ include_nutrition = list(set(include_nutrition))
562
+ exclude_nutrition = list(set(exclude_nutrition))
563
+
564
+ print("\nFinal Lists After Combining Disease + User Query:")
565
+ print(f"Ingredients to include: {include_list}")
566
+ print(f"Ingredients to exclude: {exclude_list}")
567
+ print(f"Nutrition conditions to include: {include_nutrition}")
568
+ print(f"Nutrition conditions to exclude: {exclude_nutrition}")
569
+
570
+ corrected_include = [correct_food_ingredient(ingredient, food_dictionary, common_misspellings) for ingredient in include_list]
571
+ corrected_exclude = [correct_food_ingredient(ingredient, food_dictionary, common_misspellings) for ingredient in exclude_list]
572
+
573
+ include_list = list(set(corrected_include))
574
+ exclude_list = list(set(corrected_exclude))
575
+ filtered_df = filter_and_rank_recipes(
576
+ df,
577
+ include_list,
578
+ exclude_list,
579
+ include_nutrition,
580
+ exclude_nutrition
581
+ )
582
+
583
+ final_output = {}
584
+ api_responses = []
585
+
586
+ if not filtered_df.empty:
587
+ filtered_df = filtered_df.sample(frac=1)
588
+ meal_count = min(6, len(filtered_df))
589
+
590
+ for i in range(meal_count):
591
+ if i == 0:
592
+ print("\nRecommended Meal:")
593
+ meal_data = get_recipe_output(filtered_df.iloc[i])
594
+ final_output["Recommended Meal"] = meal_data
595
+ else:
596
+ print(f"\nOption {i}:")
597
+ meal_data = get_recipe_output(filtered_df.iloc[i])
598
+ final_output[f"Option {i}"] = meal_data
599
+
600
+ api_response = send_to_api(meal_data, parent_id)
601
+ api_responses.append(api_response)
602
+ else:
603
+ error_message = f"No recipes found that match your criteria.\nIngredients to include: {', '.join(include_list)}\nIngredients to exclude: {', '.join(exclude_list)}\nNutrition Include: {', '.join(str(cond) for cond in include_nutrition)}\nNutrition Exclude: {', '.join(str(cond) for cond in exclude_nutrition)}."
604
+ print(error_message)
605
+ final_output["Message"] = error_message
606
+ return jsonify({"error": error_message}), 404
607
+
608
+ return jsonify({
609
+ "original_response": final_output,
610
+ "api_responses": api_responses,
611
+ "message": f"Successfully processed {len(api_responses)} meals"
612
+ })
613
+
614
+ except Exception as e:
615
+ print(f"Error processing request: {str(e)}")
616
+ return jsonify({"error": f"Internal server error: {str(e)}"}), 500
617
+
618
+
619
+ if __name__ == '__main__':
620
+ port = int(os.environ.get("PORT", 7860))
621
+ app.run(host="0.0.0.0", port=port, debug=False)
docs/common_ingredients.json ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ "sugar", "salt", "flour", "milk", "eggs", "butter", "oil", "water", "garlic", "onion",
3
+ "tomato", "cheese", "chicken", "beef", "pork", "rice", "pasta", "potato", "carrot", "celery",
4
+ "pepper", "cinnamon", "vanilla", "chocolate", "nuts", "almonds", "peanuts", "wheat", "gluten", "soy",
5
+ "corn", "fish", "shellfish", "shrimp", "crab", "lobster", "coconut", "banana", "apple", "orange",
6
+ "lemon", "lime", "strawberry", "blueberry", "raspberry", "blackberry", "honey", "maple syrup", "mustard", "ketchup",
7
+ "mayonnaise", "vinegar", "wine", "beer", "basil", "oregano", "thyme", "rosemary", "parsley", "cilantro",
8
+ "mint", "cumin", "paprika", "ginger", "turmeric", "avocado", "broccoli", "cauliflower", "spinach", "kale",
9
+ "lettuce", "cucumber", "zucchini", "eggplant", "mushroom", "bacon", "ham", "sausage", "turkey", "lamb",
10
+ "tofu", "beans", "lentils", "chickpeas", "quinoa", "oats", "barley", "yogurt", "cream", "cream cheese",
11
+ "sour cream", "cheddar", "mozzarella", "parmesan", "olive oil", "vegetable oil", "canola oil", "coconut oil",
12
+ "sesame oil", "baking powder", "baking soda", "yeast", "brown sugar", "powdered sugar", "confectioners sugar",
13
+ "cane sugar", "granulated sugar", "molasses", "agave", "stevia", "honey", "corn syrup", "almond milk",
14
+ "soy milk", "oat milk", "coconut milk", "cashew milk", "heavy cream", "half and half", "buttermilk",
15
+ "condensed milk", "evaporated milk", "whole milk", "skim milk", "ricotta", "cottage cheese", "blue cheese",
16
+ "goat cheese", "feta", "brie", "camembert", "gruyere", "manchego", "gouda", "provolone", "swiss cheese",
17
+ "pecans", "walnuts", "pistachios", "cashews", "hazelnuts", "macadamia nuts", "peanut butter", "almond butter",
18
+ "cashew butter", "tahini", "sunflower seeds", "pumpkin seeds", "chia seeds", "flax seeds", "sesame seeds",
19
+ "poppy seeds", "hemp seeds", "pine nuts", "white rice", "brown rice", "jasmine rice", "basmati rice",
20
+ "arborio rice", "wild rice", "sushi rice", "wheat flour", "all-purpose flour", "bread flour", "cake flour",
21
+ "pastry flour", "whole wheat flour", "almond flour", "coconut flour", "rice flour", "semolina", "cornmeal",
22
+ "corn flour", "tapioca flour", "potato starch", "cornstarch", "arrowroot", "black pepper", "white pepper",
23
+ "cayenne pepper", "red pepper flakes", "chili powder", "curry powder", "cardamom", "cloves", "nutmeg",
24
+ "allspice", "star anise", "bay leaf", "saffron", "fennel", "coriander", "mustard seeds", "anise",
25
+ "tarragon", "dill", "chives", "sage", "marjoram", "lemongrass", "black beans", "kidney beans", "pinto beans",
26
+ "navy beans", "lima beans", "fava beans", "green beans", "chickpeas", "split peas", "black-eyed peas",
27
+ "edamame", "mung beans", "red lentils", "green lentils", "brown lentils", "yellow lentils", "white potatoes",
28
+ "red potatoes", "sweet potatoes", "russet potatoes", "fingerling potatoes", "yukon gold potatoes", "yams",
29
+ "cabbage", "red cabbage", "napa cabbage", "brussels sprouts", "bok choy", "asparagus", "artichoke",
30
+ "bell pepper", "red bell pepper", "green bell pepper", "yellow bell pepper", "jalapeno", "habanero",
31
+ "serrano", "poblano", "chipotle", "cherry tomatoes", "roma tomatoes", "grape tomatoes", "heirloom tomatoes",
32
+ "sun-dried tomatoes", "tomato paste", "tomato sauce", "tomato puree", "ketchup", "salsa", "red onion",
33
+ "white onion", "yellow onion", "green onion", "scallion", "shallot", "leek", "chive", "pumpkin",
34
+ "butternut squash", "acorn squash", "spaghetti squash", "delicata squash", "kabocha squash", "radish",
35
+ "daikon", "turnip", "rutabaga", "beet", "fennel bulb", "jicama", "okra", "corn", "baby corn", "hominy",
36
+ "apple cider vinegar", "balsamic vinegar", "red wine vinegar", "white wine vinegar", "rice vinegar",
37
+ "malt vinegar", "sherry vinegar", "champagne vinegar", "distilled vinegar", "white vinegar", "red wine",
38
+ "white wine", "rose wine", "champagne", "prosecco", "vodka", "rum", "whiskey", "bourbon", "tequila",
39
+ "brandy", "cognac", "gin", "vermouth", "sake", "ale", "lager", "stout", "porter", "pilsner",
40
+ "wheat beer", "cider", "coffee", "espresso", "instant coffee", "green tea", "black tea", "herbal tea",
41
+ "chai tea", "matcha", "cocoa powder", "dark chocolate", "milk chocolate", "white chocolate", "chocolate chips",
42
+ "candy", "caramel", "toffee", "marshmallow", "gelatin", "agar agar", "sprinkles", "food coloring",
43
+ "vanilla extract", "almond extract", "lemon extract", "mint extract", "orange extract", "rum extract",
44
+ "peppermint extract", "coconut extract", "maple extract", "rose water", "orange flower water", "miso",
45
+ "soy sauce", "tamari", "hoisin sauce", "oyster sauce", "fish sauce", "teriyaki sauce", "sriracha",
46
+ "tabasco", "worcestershire sauce", "hot sauce", "barbecue sauce", "pizza sauce", "pesto", "hummus",
47
+ "guacamole", "salsa", "relish", "pickle", "sauerkraut", "kimchi", "olives", "capers", "anchovies",
48
+ "peaches", "pears", "plums", "cherries", "apricots", "nectarines", "grapes", "watermelon", "cantaloupe",
49
+ "honeydew", "kiwi", "pomegranate", "mango", "papaya", "pineapple", "passion fruit", "dragon fruit",
50
+ "raisins", "dried cranberries", "dried apricots", "dried dates", "dried figs", "prunes", "grapefruit",
51
+ "cranberries", "gooseberries", "currants", "fig", "durian", "lychee", "star fruit", "persimmon",
52
+ "ground beef", "ground turkey", "ground chicken", "ground pork", "ground lamb", "steak", "filet mignon",
53
+ "sirloin", "ribeye", "flank steak", "skirt steak", "brisket", "short ribs", "pork chops", "pork tenderloin",
54
+ "pork belly", "ham hock", "chicken breast", "chicken thigh", "chicken wing", "chicken leg", "whole chicken",
55
+ "turkey breast", "turkey leg", "duck", "duck breast", "goose", "lamb chop", "leg of lamb", "rack of lamb",
56
+ "veal", "liver", "foie gras", "tuna", "salmon", "cod", "haddock", "tilapia", "sea bass", "trout",
57
+ "halibut", "mackerel", "sardines", "herring", "anchovy", "catfish", "mahi mahi", "swordfish", "squid",
58
+ "octopus", "clams", "mussels", "oysters", "scallops", "crayfish", "langoustine", "eel", "caviar",
59
+ "roe", "seaweed", "nori", "kombu", "wakame", "dulse", "hijiki", "macaroni", "spaghetti", "fettuccine",
60
+ "linguine", "penne", "rigatoni", "farfalle", "orzo", "lasagna", "tortellini", "ravioli", "gnocchi",
61
+ "couscous", "bulgur", "farro", "polenta", "grits", "croissant", "baguette", "brioche", "sourdough",
62
+ "rye bread", "pumpernickel", "naan", "pita", "focaccia", "ciabatta", "breadcrumbs", "panko", "crackers",
63
+ "matzo", "tortilla", "phyllo dough", "puff pastry", "pie crust", "graham cracker", "wonton wrapper",
64
+ "dumpling wrapper", "egg roll wrapper", "rice paper", "udon", "soba", "ramen", "rice noodles", "egg noodles",
65
+ "glass noodles", "vermicelli", "fusilli", "rotini", "risotto", "shortening", "lard", "suet", "ghee",
66
+ "margarine", "mayonnaise", "miracle whip", "gravy", "croutons", "stuffing", "nougat", "zwieback", "custard",
67
+ "pudding", "jam", "jelly", "marmalade", "preserves", "compote", "curd", "chutney"
68
+ ]
docs/common_misspellings.json ADDED
@@ -0,0 +1,454 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added sugar or corn syrup": "corn syrup",
3
+ "advocado": "avocado",
4
+ "advocados": "avocado",
5
+ "almond mylk": "almond milk",
6
+ "almonds": "almond",
7
+ "and": "candy",
8
+ "armour lower salt bacon": "\"3 slices armour lower salt bacon\"",
9
+ "aspargus": "asparagus",
10
+ "aubergine": "eggplant",
11
+ "avacado": "avocado",
12
+ "avacados": "avocado",
13
+ "avocados": "avocado",
14
+ "baby pearl tapioca": "\" baby pearl tapioca\"",
15
+ "baccon": "bacon",
16
+ "bacn": "bacon",
17
+ "baking potatoes": "5 baking potatoes\"",
18
+ "bakon": "bacon",
19
+ "bannana": "banana",
20
+ "bannanas": "banana",
21
+ "basil": "basil",
22
+ "bazil": "basil",
23
+ "beaf": "beef",
24
+ "because": "beans",
25
+ "beef": "beef",
26
+ "beens": "beans",
27
+ "beff": "beef",
28
+ "bewries": "berries",
29
+ "bewwies": "berries",
30
+ "bicarbonate of soda": "baking soda",
31
+ "blak pepper": "black pepper",
32
+ "blu berries": "blueberries",
33
+ "bluberries": "blueberries",
34
+ "blue beries": "blueberries",
35
+ "blueberreis": "blueberries",
36
+ "blueberrys": "blueberries",
37
+ "blueburys": "blueberries",
38
+ "boc choi": "bok choy",
39
+ "bokchoy": "bok choy",
40
+ "boneless rump": "[\"1 1/ boneless rump\"",
41
+ "bowtie macaroni": "\"bowtie macaroni\"]",
42
+ "bracoli": "broccoli",
43
+ "bread": "bread",
44
+ "bred": "bread",
45
+ "brockley": "broccoli",
46
+ "brocli": "broccoli",
47
+ "brocoli": "broccoli",
48
+ "brocolli": "broccoli",
49
+ "brok": "broccoli",
50
+ "bromato": "tomato",
51
+ "brown suger": "brown sugar",
52
+ "brownie mix": "\"1 pkg. brownie mix\"",
53
+ "brussel sprouts": "brussels sprouts",
54
+ "brussell sprouts": "brussels sprouts",
55
+ "brussels": "mussels",
56
+ "budr": "butter",
57
+ "bulgur wheat": "\"1 c. bulgur wheat\"",
58
+ "buter": "butter",
59
+ "butr": "butter",
60
+ "cabij": "cabbage",
61
+ "cacoa": "cocoa",
62
+ "calorie": "calories",
63
+ "camomile": "chamomile",
64
+ "canned soup": "canned tomato soup\"",
65
+ "capsicm": "capsicum",
66
+ "capsikcum": "capsicum",
67
+ "carb": "crab",
68
+ "carbs": "capers",
69
+ "carot": "carrot",
70
+ "carrats": "carrot",
71
+ "carrit": "carrot",
72
+ "carrott": "carrot",
73
+ "carrts": "carrot",
74
+ "carumom": "cardamom",
75
+ "caulflower": "cauliflower",
76
+ "cayane": "cayenne",
77
+ "cayanne": "cayenne",
78
+ "cayene": "cayenne",
79
+ "cellary": "celery",
80
+ "cellery": "celery",
81
+ "center": "\"centers",
82
+ "chalot": "shallot",
83
+ "chas": "cheese",
84
+ "chciken": "chicken",
85
+ "chease": "cheese",
86
+ "chedar": "cheddar",
87
+ "chedar cheese": "cheddar cheese",
88
+ "cheeze": "cheese",
89
+ "chekin": "chicken",
90
+ "cheries": "cherries",
91
+ "cherys": "cherries",
92
+ "ches": "cheese",
93
+ "chese": "cheese",
94
+ "chesee": "cheese",
95
+ "chestnuts": "chestnut",
96
+ "chi peas": "chickpeas",
97
+ "chic pea": "chickpea",
98
+ "chic peas": "chickpeas",
99
+ "chicken drummettes": "\"chicken drummettes\"",
100
+ "chicken livers": "[\"chicken livers\"",
101
+ "chiili": "chili",
102
+ "chiken": "chicken",
103
+ "chili peppers": "chili pepper",
104
+ "chilli": "chili",
105
+ "chilli flakes": "chili flakes",
106
+ "chilli pepper": "chili pepper",
107
+ "chipolte": "chipotle",
108
+ "chipotlay": "chipotle",
109
+ "chives": "chive",
110
+ "chli flakes": "chili flakes",
111
+ "choclate": "chocolate",
112
+ "choclit": "chocolate",
113
+ "chocolat": "chocolate",
114
+ "chocolote": "chocolate",
115
+ "choklit": "chocolate",
116
+ "chokolate": "chocolate",
117
+ "chpd": "chopped",
118
+ "cider vinegar": "\" cider vinegar\"",
119
+ "cinammon": "cinnamon",
120
+ "cinamon": "cinnamon",
121
+ "cinimin": "cinnamon",
122
+ "cinimon": "cinnamon",
123
+ "cinnamin": "cinnamon",
124
+ "cinquetfoil": "cinquefoil",
125
+ "clery": "celery",
126
+ "cocnut": "coconut",
127
+ "coconut milk": "coconut milk",
128
+ "coconut millk": "coconut milk",
129
+ "cocunut": "coconut",
130
+ "cofee": "coffee",
131
+ "coffe": "coffee",
132
+ "cokies": "cookies",
133
+ "coliflower": "cauliflower",
134
+ "collander": "colander",
135
+ "confectionary sugar": "confectioners sugar",
136
+ "cooking oil": "\"cooking oil",
137
+ "cornflaur": "cornflour",
138
+ "corriander": "coriander",
139
+ "cream of mushroom soup": "cream of mushroom soup\"",
140
+ "crem": "cream",
141
+ "crisp": "\"crisp",
142
+ "crutons": "croutons",
143
+ "cucomber": "cucumber",
144
+ "cucumba": "cucumber",
145
+ "cucumbr": "cucumber",
146
+ "cucumbra": "cucumber",
147
+ "cumcumber": "cucumber",
148
+ "cummin": "cumin",
149
+ "curied": "curry",
150
+ "currents": "currants",
151
+ "cyanne": "cayenne",
152
+ "dijon mustard": "\"dijon mustard\"",
153
+ "dill": "dill",
154
+ "doctor": "octopus",
155
+ "doritos chips": "\"doritos chips\"",
156
+ "dry mustard": "dry mustard\"",
157
+ "egg": "eggs",
158
+ "egges": "eggs",
159
+ "egggs": "eggs",
160
+ "eggplnt": "eggplant",
161
+ "egs": "eggs",
162
+ "egz": "eggs",
163
+ "exra-virgin olive oil": "extra virgin olive oil",
164
+ "exrtra virgin olive oil": "extra virgin olive oil",
165
+ "fat": "fat\"",
166
+ "fats": "oats",
167
+ "fenel": "fennel",
168
+ "fennle": "fennel",
169
+ "fettucine noodles": "[\"fettucine noodles \"",
170
+ "finna": "fennel",
171
+ "flor": "flour",
172
+ "flore": "flour",
173
+ "flounder": "\"flounder",
174
+ "flour": "flour",
175
+ "flower": "flour",
176
+ "flowers with": "\"flower",
177
+ "fresh ground black pepper": "black pepper",
178
+ "fresh mushrooms": "mushrooms",
179
+ "frozen italian style vegetables": "frozen oriental-style vegetables\"",
180
+ "galic": "garlic",
181
+ "garlick": "garlic",
182
+ "garlicy": "garlic",
183
+ "garlik": "garlic",
184
+ "garllic": "garlic",
185
+ "gelatine": "gelatin",
186
+ "geletin": "gelatin",
187
+ "gellatine": "gelatin",
188
+ "ginjer": "ginger",
189
+ "gnocci": "gnocchi",
190
+ "gralic": "garlic",
191
+ "green beens": "green beans",
192
+ "green chile enchilada sauce": "\"1 can green enchilada sauce\"",
193
+ "green chillies": "green chilies\"",
194
+ "green pepper": "green peppers",
195
+ "ground beef": "beef",
196
+ "ground meat": "meat\"",
197
+ "hareesa": "harissa",
198
+ "hazel nuts": "hazelnuts",
199
+ "hazlenuts": "hazelnuts",
200
+ "hebs": "herbs",
201
+ "herbes": "herbs",
202
+ "herbz": "herbs",
203
+ "high": "thighs",
204
+ "hony": "honey",
205
+ "hut": "halibut",
206
+ "jalepano": "jalapeno",
207
+ "jalepeno": "jalapeno",
208
+ "jalepino": "jalapeno",
209
+ "jalopeno": "jalapeno",
210
+ "japapeno": "jalapeno",
211
+ "kale": "kale",
212
+ "katsup": "ketchup",
213
+ "ketcup": "ketchup",
214
+ "ketshup": "ketchup",
215
+ "ketsup": "ketchup",
216
+ "ladyfingers": "\"ladyfingers\"]",
217
+ "large red": "\"1 large red",
218
+ "leafy greens": "collard greens \"",
219
+ "lemmon": "lemon",
220
+ "lemmonds": "lemon",
221
+ "lemmons": "lemon",
222
+ "lentills": "lentils",
223
+ "less than 700 calories per serving": "calories",
224
+ "lettuice": "lettuce",
225
+ "lettus": "lettuce",
226
+ "letuce": "lettuce",
227
+ "lime": "lime",
228
+ "lime jell-o": "[\" lime jello\"",
229
+ "lime juice": "lime juice\"",
230
+ "limes": "lime",
231
+ "loin end pork": "[\"4 to loin end pork\"",
232
+ "long grain white rice": "\"2 c. long grain white rice\"",
233
+ "low": "orange flower water",
234
+ "lower than 20 g of fiber": "lower than of fiber",
235
+ "magarine": "margarine",
236
+ "magerine": "margarine",
237
+ "majarine": "margarine",
238
+ "manderine": "mandarin",
239
+ "mapel": "maple",
240
+ "mapple": "maple",
241
+ "margerine": "margarine",
242
+ "marj": "marjoram",
243
+ "marjaram": "marjoram",
244
+ "marjoram": "marjoram",
245
+ "marjorem": "marjoram",
246
+ "mayo": "mayonnaise",
247
+ "mayonaise": "mayonnaise",
248
+ "mayonaisse": "mayonnaise",
249
+ "mayonase": "mayonnaise",
250
+ "mayonese": "mayonnaise",
251
+ "mayonez": "mayonnaise",
252
+ "menth": "mint",
253
+ "miilk": "milk",
254
+ "milc": "milk",
255
+ "milks": "milk",
256
+ "mixed pickling spice": "\" mixed pickling spices\"]",
257
+ "mlik": "milk",
258
+ "mlik products": "milk",
259
+ "molk": "milk",
260
+ "mollases": "molasses",
261
+ "mollasses": "molasses",
262
+ "morton tender quick meat cure": "\"3 tbsp. morton tender quick meat cure\"]",
263
+ "mozarella": "mozzarella",
264
+ "mozzarela": "mozzarella",
265
+ "mozzerella": "mozzarella",
266
+ "mozzorella": "mozzarella",
267
+ "mushram": "mushroom",
268
+ "mushroms": "mushrooms",
269
+ "mushroomz": "mushrooms",
270
+ "mushrums": "mushrooms",
271
+ "must": "mustard",
272
+ "musterd": "mustard",
273
+ "my": "\"1 single serving size envelope instant creamy chicken soup mix\"",
274
+ "notmeg": "nutmeg",
275
+ "nut meg": "nutmeg",
276
+ "nutmag": "nutmeg",
277
+ "ocra": "okra",
278
+ "oil products": "oil",
279
+ "oile": "oil",
280
+ "olif oil": "olive oil",
281
+ "oliv oil": "olive oil",
282
+ "oliveoil": "olive oil",
283
+ "ollives": "olives",
284
+ "onin": "onion",
285
+ "onino": "onion",
286
+ "oninon": "onion",
287
+ "onions": "onions\"",
288
+ "onnion": "onion",
289
+ "onoin": "onion",
290
+ "oranje": "orange",
291
+ "oreg": "oregano",
292
+ "oriental chili sesame oil": "\"1/ oriental chili sesame oil\"",
293
+ "origano": "oregano",
294
+ "oring": "orange",
295
+ "orinj": "orange",
296
+ "over": "liver",
297
+ "oyl": "oil",
298
+ "panchetta": "pancetta",
299
+ "papreka": "paprika",
300
+ "paprica": "paprika",
301
+ "parley flakes": "parsley flakes\"",
302
+ "parmasean": "parmesan",
303
+ "parmazan": "parmesan",
304
+ "parmejan": "parmesan",
305
+ "parmesan cheese": "parmesan cheese\"",
306
+ "parmezon": "parmesan",
307
+ "parsely": "parsley",
308
+ "parsley": "parsley",
309
+ "parsli": "parsley",
310
+ "parsly": "parsley",
311
+ "patato": "potato",
312
+ "patatos": "potato",
313
+ "peans": "peas",
314
+ "pecan halves": "\"pecan halves\"]",
315
+ "peer": "pear",
316
+ "penut": "peanut",
317
+ "penut butter": "peanut butter",
318
+ "peper": "pepper",
319
+ "pepers": "peppers",
320
+ "peppr": "pepper",
321
+ "pettitoes": "pig's feet",
322
+ "pickels": "pickles",
323
+ "pimienta": "pimiento",
324
+ "pinaple": "pineapple",
325
+ "pineaple": "pineapple",
326
+ "plain yogurt": "plain yogurt\"",
327
+ "potatoe": "potato",
328
+ "potatoes": "potatoes\"",
329
+ "potatos": "potato",
330
+ "powderd sugar": "powdered sugar",
331
+ "processed meats": "unprocessed bran\"",
332
+ "raisens": "raisins",
333
+ "raisin": "raisin",
334
+ "rasberries": "raspberries",
335
+ "rasberry": "raspberry",
336
+ "rasins": "raisins",
337
+ "red chili pepper": "\"1 red chili pepper\"",
338
+ "regular fritos": "regular salt\"",
339
+ "resins": "raisins",
340
+ "rhubarbe": "rhubarb",
341
+ "rhubard": "rhubarb",
342
+ "rise": "rice",
343
+ "ro-tel tomatoes": "1 can ro-tel tomatoes",
344
+ "ruis": "rice",
345
+ "russet potatoe": "russet potato",
346
+ "s potatoes": "sweet potatoes",
347
+ "saffran": "saffron",
348
+ "saffrin": "saffron",
349
+ "saffrum": "saffron",
350
+ "safron": "saffron",
351
+ "said": "squid",
352
+ "salad dressing": "salad dressing\"",
353
+ "salad dressing mix": "salad dressing \"",
354
+ "sallt": "salt",
355
+ "sammon": "salmon",
356
+ "samon": "salmon",
357
+ "sault": "salt",
358
+ "saurkraut": "sauerkraut",
359
+ "sausge": "sausage",
360
+ "scallions": "scallion",
361
+ "seame seeds": "sesame seeds",
362
+ "seshuan pepper": "sichuan pepper",
363
+ "shalott": "shallot",
364
+ "shampinon": "mushroom",
365
+ "shampinyons": "mushrooms",
366
+ "sigar": "sugar",
367
+ "sinamon": "cinnamon",
368
+ "sirrup": "syrup",
369
+ "sirup": "syrup",
370
+ "sodium": "medium\"",
371
+ "soja": "soy",
372
+ "sojakeim": "soybeans",
373
+ "solt": "salt",
374
+ "sowmilk": "soy milk",
375
+ "soy sce": "soy sauce",
376
+ "soysauce": "soy sauce",
377
+ "spageti": "spaghetti",
378
+ "spagetti": "spaghetti",
379
+ "spaggeti": "spaghetti",
380
+ "spaghetii": "spaghetti",
381
+ "spinach": "spinach",
382
+ "spinage": "spinach",
383
+ "spinich": "spinach",
384
+ "squach": "squash",
385
+ "sqwash": "squash",
386
+ "stek": "steak",
387
+ "stew meat": "stew meat\"",
388
+ "strawberies": "strawberries",
389
+ "strawberrys": "strawberries",
390
+ "strawbery": "strawberry",
391
+ "strwberries": "strawberries",
392
+ "suagr": "sugar",
393
+ "subgr": "sugar",
394
+ "suger": "sugar",
395
+ "sugr": "sugar",
396
+ "sugur": "sugar",
397
+ "sunflowr seeds": "sunflower seeds",
398
+ "sweatner": "sweetener",
399
+ "sweet potatoe": "sweet potato",
400
+ "sweet potatos": "sweet potatoes",
401
+ "sweet relish": "\"sweet relish\"",
402
+ "termaric": "turmeric",
403
+ "termerick": "turmeric",
404
+ "termuric": "turmeric",
405
+ "that": "wheat",
406
+ "thim": "thyme",
407
+ "tomaotes": "tomatoes",
408
+ "tomatoe": "tomato",
409
+ "tomatoe paste": "tomato paste",
410
+ "tomatoe sauce": "tomato sauce",
411
+ "tomatos": "tomato",
412
+ "tomoatoes": "tomatoes",
413
+ "tomotoes": "tomato",
414
+ "tortilla chips": "tortilla chips\"",
415
+ "tumeric": "turmeric",
416
+ "tuna": "tuna",
417
+ "turkey burger": "turkey breast",
418
+ "turmeric": "turmeric",
419
+ "tyme": "thyme",
420
+ "under": "\"flounder",
421
+ "vagetable oil": "vegetable oil",
422
+ "vainilla": "vanilla",
423
+ "vanella": "vanilla",
424
+ "vanil": "vanilla",
425
+ "vanila": "vanilla",
426
+ "vanillin": "vanilla",
427
+ "vegitable oil": "vegetable oil",
428
+ "velveeta cheese": "velveeta cheese\"",
429
+ "venegar": "vinegar",
430
+ "vinager": "vinegar",
431
+ "vinaigre": "vinegar",
432
+ "vinega": "vinegar",
433
+ "vinger": "vinegar",
434
+ "vinigar": "vinegar",
435
+ "vinnegar": "vinegar",
436
+ "wall nuts": "walnuts",
437
+ "wallnut": "walnut",
438
+ "wallnuts": "walnuts",
439
+ "worscestershire": "worcestershire",
440
+ "worsestershire": "worcestershire",
441
+ "worstersire": "worcestershire",
442
+ "wostershire": "worcestershire",
443
+ "yeest": "yeast",
444
+ "yellow pepper": "yellow pepper\"",
445
+ "yogert": "yogurt",
446
+ "yoghourt": "yogurt",
447
+ "yoghurt": "yogurt",
448
+ "yohurt": "yogurt",
449
+ "youghurt": "yogurt",
450
+ "yougurt": "yogurt",
451
+ "zuccini": "zucchini",
452
+ "zucini": "zucchini",
453
+ "zukini": "zucchini"
454
+ }
docs/common_nutrition.json ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Flask==3.1.0
2
+ pandas==2.2.3
3
+ transformers==4.29.2
4
+ torch==2.6.0
5
+ torchaudio==2.6.0
6
+ torchvision==0.21.0
7
+ requests==2.32.3
8
+ textblob==0.17.1
9
+ tokenizers==0.13.3
10
+ nltk==3.8.1
11
+ asttokens==3.0.0
12
+ urllib3==2.3.0