Files changed (10) hide show
  1. .env-template +0 -2
  2. .gitignore +0 -3
  3. .streamlit/config.toml +0 -5
  4. README.md +3 -21
  5. __pycache__/app.cpython-311.pyc +0 -0
  6. app.py +0 -113
  7. edamam.txt +0 -1
  8. index.py +0 -200
  9. key.txt +0 -1
  10. requirements.txt +0 -47
.env-template DELETED
@@ -1,2 +0,0 @@
1
- OPENAI_API_KEY =
2
- EDAMAM_API_KEY =
 
 
 
.gitignore DELETED
@@ -1,3 +0,0 @@
1
- captured_images/
2
- .venv
3
- .env
 
 
 
 
.streamlit/config.toml DELETED
@@ -1,5 +0,0 @@
1
- [theme]
2
- base="light"
3
- primaryColor="#115210"
4
- secondaryBackgroundColor="#aad4a3"
5
- textColor="#000000"
 
 
 
 
 
 
README.md CHANGED
@@ -1,25 +1,7 @@
1
  ---
2
  license: apache-2.0
3
  ---
4
- ## Inspiration
5
- The inspiration stemmed from a passion for promoting health and wellness through food. We were driven by the desire to address the prevalent lack of accessible and easy-to-understand nutritional information. It's a common struggle for people to decide what they can make with the ingredients that they have at home, oftentimes letting groceries they bought earlier in the week or month go bad in favor of the convenience of ordering food to their doorstep. With our app, we aid in minimizing food waste by giving people tasty and easy options to finish up what's left in the fridge, not letting a penny or ingredient go to waste. For many of us college students, leaving the comfort of home-cooked meals and having to sustain ourselves has left us making unhealthy and often not financially smart food decisions rather than cooking, so as to "save ourselves the hassle." But had we had an app like RecipeBud, we're sure that more students like us could see themselves buying groceries and cooking at home. Not only does this save us the extra buck, but contributes to a healthier lifestyle.
6
 
7
- Furthermore, our team is formed of immigrants or children of immigrants. We are no stranger to the real struggles that come with learning another language and trying to place the names for common ingredients that come so naturally to us in our mother tongue, which is even tougher to spell out. Thus, our image-recognition software transcends and overcomes linguistic boundaries such as these so that we all may be able to participate in the universal language that is a comforting home-cooked meal.
8
-
9
- ## What it does
10
- RecipeBud is a culinary game-changer, seamlessly melding image recognition with nutritional insights. This innovative web application lets users snap ingredient pics, swiftly identifying them and delivering a spectrum of recipes with comprehensive nutritional profiles. Serving as a personalized nutritionist, it guides users in making informed meal decisions. Offering a diverse array of recipes while highlighting nutritional benefits, RecipdBud champions a healthier lifestyle for a more vibrant, inclusive community.
11
-
12
- ## How we built it
13
- We engineered our web app using Python and Streamlit, skillfully combining OpenAI's cutting-edge GPT-3.5 model with Microsoft's Resnet-50 model from Hugging Face. Furthermore, we made use of Edamam's comprehensive Food Nutritional Database API to ensure nutritional accuracy. Along with this, we harnessed the power of OpenCV for efficient image capture. Our app seamlessly marries AI-generated responses with accurate food image recognition, providing users with an enriched and insightful culinary experience
14
-
15
- ## Challenges we ran into
16
- Integrating two Language Models was challenging. We hosted a Microsoft image-recognition model locally alongside accessing OpenAI's API, which was challenging: while the local model had quick responses, constantly making API requests was expensive in terms of time. Streamlining this timing discrepancy was challenging. OpenAI's token limit sometimes resulted in incomplete outputs, making testing difficult. However, to be able to explore this field of engineering over the course of one weekend in the depth that we did was ultimately extremely rewarding despite the difficulties we faced. Additionally, as first-time users of Streamlit, navigating it initially was tricky. While Streamlit simplifies many aspects, customizations that may seem simple, like just changing the color of a button, posed complexities, as Streamlit does not support applying custom CSS styles to its element using external CSS files. However, the interface that resulted was elegant and extremely easy to interact with, which would not have been possible without Streamlit's functionalities and features.
17
-
18
- ## Accomplishments that we're proud of
19
- We take pride in having successfully developed a functional application that significantly contributes to users' journey towards a healthier, more nutritious lifestyle. This reinforces our commitment to making a positive impact on their well-being. In this day and age, due to advertising and toxic media, many people's relationships with food are becoming more and more negative and destructive. Furthermore, this age of fast food and cheap, low-quality foodstuffs has drastically affected our population's overall health. We know that RecipeBud will be of help to people who want to take steps in the right direction, one recipe at a time.
20
-
21
- ## What we learned
22
- Developing RecipeBud has been a tremendous learning experience. We gained valuable insights into effectively integrating multiple large language models into a cohesive application. Navigating the intricacies of OpenAI's API, as well as hosting a machine-learning model locally considering model's bias and weight storage, and managing its responses taught us important lessons in error handling and optimization. Additionally, our foray into Streamlit exposed us to the potential and challenges of rapidly building a user-friendly interface. We now have a better understanding of the nuances of balancing simplicity with customization in app development. Overall, RecipeBud has been a rich source of knowledge, preparing us for even more ambitious projects in the future.
23
-
24
- ## What's next for RecipeBud
25
- Our journey doesn't end here; in fact, it's just the beginning. We're diving into the future, brainstorming innovative ideas to take this app to the next level. One crucial aspect we're focusing on is enhancing accessibility for non-English speakers, ensuring our platform caters to a broader audience. Additionally, we're exploring automation features like seamless image capture and intuitive tools for comparing nutritional visuals across various recipes. We also hope to incorporate audio interaction, and for recipes to be played back for users to listen to as they are cooking for a more hands-free, immersive experience. These advancements aim to empower users, making informed, health-conscious choices effortlessly and effectively. Food is a universal language, as we've said before. It brings people together. We hope to also train our own model with data on recipes from around the world specific to less represented cuisines so that a person from one corner of the world can have a taste of the other side of an ocean or spanning across many continents, from the comfort of their own kitchen.
 
1
  ---
2
  license: apache-2.0
3
  ---
 
 
4
 
5
+ #Danish
6
+ #Lakpa
7
+ #Lydia
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
__pycache__/app.cpython-311.pyc DELETED
Binary file (3.37 kB)
 
app.py DELETED
@@ -1,113 +0,0 @@
1
- # This is the main logic file that contains hugging face model interaction
2
-
3
- # This model is for detecting food in the image.
4
- # Use a pipeline as a high-level helper
5
- from transformers import pipeline
6
- import os
7
- import openai
8
- import requests
9
- import json
10
- from openai import OpenAI
11
- openai.organization = "org-5Z0c3Uk1VG7t3TsczN6M4FCi"
12
- #openai.api_key = os.getenv("OPENAI_API_KEY")
13
- openai.api_key_path ="./key.txt"
14
-
15
- def askGPT(prompt="what can I make with potato?"):
16
-
17
- client = OpenAI(
18
- base_url='http://localhost:11434/v1/',
19
-
20
- # required but ignored
21
- api_key='ollama',
22
- )
23
-
24
- chat_completion = client.chat.completions.create(
25
- messages=[
26
- {
27
- 'role': 'user',
28
- 'content': prompt,
29
- }
30
- ],
31
- model='llama3',
32
- )
33
-
34
- result = chat_completion.choices[0].message.content
35
- #print(chat_completion.choices[0].message.content)
36
- return result
37
-
38
- '''def askGPT(prompt="what can I make with potato?"):
39
- response = openai.ChatCompletion.create(
40
- model="gpt-3.5-turbo",
41
- messages=[
42
- {
43
- "role": "system",
44
- "content":prompt
45
- },
46
- {
47
- "role": "user",
48
- "content": ""
49
- } ],
50
- temperature=1,
51
- max_tokens=256,
52
- top_p=1,
53
- frequency_penalty=0,
54
- presence_penalty=0
55
- )
56
- result = response["choices"][0]["message"]["content"]
57
- return result'''
58
-
59
- def classifyImage(image):
60
- pipe = pipeline("image-classification", model="microsoft/resnet-50")
61
- result = pipe(image)
62
- return result[0]['label']
63
-
64
- def analyze_nutrition(ingredients):
65
- # Edamam API endpoint for nutrition analysis
66
- endpoint = "https://api.edamam.com/api/nutrition-data"
67
- # Edamam API application ID and key
68
- app_id = "26722303"
69
- app_key = "44f19a04e17d83e91706e4047804e690"
70
- processed_ingredients = set()
71
- food_dict= {}
72
-
73
- for ingredient in ingredients:
74
- if ingredient in processed_ingredients:
75
- continue
76
- # Parameters for the API request
77
- params = {
78
- "app_id": app_id,
79
- "app_key": app_key,
80
- "ingr": ingredient
81
- }
82
- try:
83
- # Send a GET request to the API
84
- response = requests.get(endpoint, params=params)
85
-
86
- # Check if the request was successful
87
- if response.status_code == 200:
88
- # Parse the JSON response
89
- data = response.json()
90
-
91
- food_dict[ingredient] = {
92
- 'Calories': str(data['calories']) + "kcal",
93
- 'Calories from Protein': str(data['totalNutrientsKCal']['PROCNT_KCAL']['quantity']) + "kcal",
94
- 'Calories from Fat': str(data['totalNutrientsKCal']['FAT_KCAL']['quantity']) + "kcal",
95
- 'Calories from Carbohydrates': str(data['totalNutrientsKCal']['CHOCDF_KCAL']['quantity']) + "kcal",
96
- 'Grams in Protein': str(data['totalNutrients']['PROCNT']['quantity']) + "g",
97
- 'Grams in Carbohydrates': str(data['totalNutrients']['CHOCDF']['quantity']) +"g"
98
- }
99
-
100
- processed_ingredients.add(ingredient)
101
- else:
102
- print("Error for", ingredient, ":", response.status_code)
103
-
104
- except requests.exceptions.RequestException as e:
105
- print("Error for", ingredient, ":", e)
106
- return food_dict
107
-
108
-
109
- # Example ingredients list
110
- # ingredients = ["Orange per 100 grams", "Apple per 100 grams", "Banana per 100 grams"]
111
-
112
- # # # Analyze nutrition for all ingredients
113
- # print(analyze_nutrition(ingredients))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
edamam.txt DELETED
@@ -1 +0,0 @@
1
- 44f19a04e17d83e91706e4047804e690
 
 
index.py DELETED
@@ -1,200 +0,0 @@
1
- import streamlit as st
2
- import cv2
3
- import os
4
- from app import *
5
- import pprint
6
-
7
- # Create a folder to save captured images
8
- if not os.path.exists("captured_images"):
9
- os.makedirs("captured_images")
10
-
11
- background_style = """
12
- <style>
13
- [data-testid="stAppViewContainer"] {
14
- background-image: url('https://i.ibb.co/HpYr6qg/Untitled-design-2.png');
15
- background-size: cover;
16
- background-repeat: no-repeat;
17
- background-attachment: fixed;
18
- }
19
- </style>
20
- """
21
- st.markdown(background_style, unsafe_allow_html=True)
22
-
23
- # Initialize the session state
24
- session_state = st.session_state
25
- if 'ingredientsList' not in session_state:
26
- session_state['ingredientsList'] = ["apple", "orange", "orange"]
27
- # xyz = ["apple", "yerba mate", "orange", "orange"]
28
-
29
- def main():
30
- # Create two columns
31
- col1, col2 = st.columns([1, 5])
32
-
33
- # In the first column, display the title
34
- with col1:
35
- logo = st.image("https://d112y698adiu2z.cloudfront.net/photos/production/software_thumbnail_photos/002/589/585/datas/medium.png", width=150)
36
-
37
-
38
-
39
- # In the second column, display the logo image
40
- with col2:
41
- st.title('RecipeBud')
42
-
43
- st.sidebar.header('Ingredients & Nutrition')
44
- # List of items
45
- #items = ['Item 1', 'Item 2', 'Item 3']
46
-
47
- #list to of Ingredients camptured
48
- #ingredientsList =["apple", "orange", "mango"] #list()
49
-
50
- # Create a VideoCapture object to access the webcam
51
- cap = cv2.VideoCapture(0)
52
-
53
- # Set the video frame width and height (optional)
54
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 800)
55
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 400)
56
-
57
- # Check if the webcam is opened correctly
58
- if not cap.isOpened():
59
- st.error("Error: Unable to access the webcam.")
60
- return
61
-
62
- # Display a placeholder for the video stream
63
- video_placeholder = st.empty()
64
-
65
- # Apply custom CSS for the button
66
- st.markdown(
67
- """
68
- <style>
69
- .stButton>button {
70
- background-color: #4CAF50; /* Green */
71
- color: white;
72
- border: none;
73
- border-radius: 5px;
74
- }
75
- </style>
76
- """,
77
- unsafe_allow_html=True
78
- )
79
-
80
- # Button to capture image
81
- if st.button("Capture Image"):
82
- image_path = capture_image()
83
- classification = classifyImage(image_path)
84
- #session_state['ingredientsList'].append(classification)
85
-
86
- # Button to indicate done
87
- #done_button = st.sidebar.button('Done')
88
-
89
- # Display the captured ingredients
90
- # st.write("Captured Ingredients:", session_state['ingredientsList'])
91
-
92
- button_clicked = st.sidebar.button('Done')
93
-
94
- # Display recipes if "Done" is clicked
95
- while not button_clicked:
96
- # Read a frame from the webcam
97
- ret, frame = cap.read()
98
-
99
- if not ret:
100
- st.error("Error: Unable to read frame from the webcam.")
101
- break
102
-
103
- # Display the frame in the Streamlit app
104
- video_placeholder.image(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), channels="RGB", use_column_width=True)
105
- if button_clicked:
106
- nutrition_values = analyze_nutrition(nutrients(session_state['ingredientsList']))
107
- cap.release()
108
- if session_state['ingredientsList']:
109
- session_state['ingredientsList'].pop()
110
- #st.write("Updated Ingredients List:", session_state['ingredientsList'])
111
-
112
- # displayRecipes(session_state['ingredientsList'])
113
- # Define content for each item
114
- content = {}
115
- for ingredient in nutrition_values:
116
- # content[ingredient] = askGPT(f"Give me your estimate the calories, grams of protein, grams of sugar, grams of fat, and grams of carbohydrates per 100g of {ingredient} as a list")
117
- content[ingredient] = nutrition_values[ingredient]
118
-
119
- # Display expanders for each item
120
- # for ingredient in session_state['ingredientsList']:
121
- # with st.sidebar.expander(ingredient):
122
- # st.write(content[ingredient])
123
- # displayRecipes(session_state['ingredientsList'])
124
-
125
- for ingredient in content:
126
- with st.sidebar.expander(ingredient):
127
- ingred = str(content[ingredient])
128
- st.write(ingred[1:len(ingred)-1].replace("'", "").replace(',', '\n\n'))
129
- displayRecipes(session_state['ingredientsList'])
130
-
131
-
132
-
133
- def displayRecipes(ingredientsList):
134
- items = []
135
- #now we are gonna send the ingredient list to ask gpt
136
- prompt = f"I have following Ingredients :{','.join(ingredientsList)}. What can I make with these \
137
- Ingredients? Give me A list of detailed recipes with measurements containing these ingredients with Nutrition Facts (calories, grams of sugar, grams of protein, grams of fats, grams of carbohydrates) per serving based on the widely accepted nutritional value of each of these ingredients. Rank the list from \
138
- highest nutritional value to lowest. Give me results in \
139
- following format and do not deviate from this format:\
140
- ['Recipe Title', 'Calories per serving']."
141
- #prompt = f"You are going to act as a nutritional expert who has a lot of knowledge about food. I have the following ingredients: {','.join(ingredientsList)}. What can I make with these ingredients? Give me a list of names of recipes, maximum five."
142
- LLMResult = askGPT(prompt)
143
- lystOfRecipes = LLMResult.split('\n\n')
144
- # print(lystOfRecipes)
145
- count = 0
146
- for recipe in range(1,len(lystOfRecipes)-1):
147
- count += 1
148
- items.append({"title": lystOfRecipes[recipe].split(":")[0], "content": ""})
149
- if count == 4:
150
- break
151
- # Display the items with =expanding boxes
152
- for item in items:
153
- #for side bar's item
154
- #with st.sidebar.expander(item):
155
- #st.write("man-holding-banana.jpeg")
156
- #main page items
157
- with st.expander(item["title"]):
158
- st.write(askGPT(f"Give me a detailed recipe for a dish called {item['title']} containing all of the following ingredients: {','.join(ingredientsList)}. Make sure your response is easy to follow and comprehensive."))
159
-
160
-
161
- def capture_image():
162
- # Create a VideoCapture object to access the webcam
163
- cap = cv2.VideoCapture(0)
164
-
165
- # Set the video frame width and height (optional)
166
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 800)
167
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 400)
168
-
169
- # Check if the webcam is opened correctly
170
- if not cap.isOpened():
171
- st.error("Error: Unable to access the webcam.")
172
- return
173
-
174
- # Read a frame from the webcam
175
- ret, frame = cap.read()
176
-
177
- if not ret:
178
- st.error("Error: Unable to read frame from the webcam.")
179
- return
180
-
181
- # Save the frame as an image
182
- image_path = f"captured_images/captured_image_{len(os.listdir('captured_images')) + 1}.jpg"
183
- cv2.imwrite(image_path, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
184
- st.success(f"Image captured and saved as {image_path}")
185
-
186
- # Release the VideoCapture and close the OpenCV window
187
- cap.release()
188
-
189
- return image_path
190
-
191
-
192
- def nutrients(ingredients):
193
- formatted_list = []
194
- for ingredient in ingredients:
195
- formatted_list.append(ingredient + " per 100 grams")
196
- return formatted_list
197
-
198
-
199
- if __name__ == '__main__':
200
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
key.txt DELETED
@@ -1 +0,0 @@
1
- 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
 
 
requirements.txt DELETED
@@ -1,47 +0,0 @@
1
- async-generator==1.10
2
- attrs==21.4.0
3
- certifi==2022.6.15
4
- cffi==1.15.0
5
- charset-normalizer==3.1.0
6
- cryptography==36.0.1
7
- distlib==0.3.4
8
- filelock==3.7.0
9
- fsspec==2023.9.1
10
- h11==0.13.0
11
- huggingface-hub==0.17.1
12
- idna==3.3
13
- numpy==1.22.3
14
- outcome==1.1.0
15
- packaging==23.0
16
- pandas==1.4.1
17
- pbr==5.9.0
18
- platformdirs==2.5.2
19
- pycparser==2.21
20
- pyOpenSSL==21.0.0
21
- python-dateutil==2.8.2
22
- python-dotenv
23
- pytz==2022.1
24
- PyYAML==6.0
25
- regex==2023.8.8
26
- requests==2.28.2
27
- safetensors==0.3.3
28
- scipy==1.9.3
29
- selenium==4.1.0
30
- six==1.16.0
31
- snakeviz==2.1.1
32
- sniffio==1.2.0
33
- sortedcontainers==2.4.0
34
- stevedore==3.5.0
35
- thread6==0.2.0
36
- tokenizers==0.13.3
37
- tornado==6.2
38
- tqdm==4.65.0
39
- transformers==4.33.2
40
- trio==0.19.0
41
- trio-websocket==0.9.2
42
- typing_extensions==4.5.0
43
- urllib3==1.26.8
44
- virtualenv==20.14.1
45
- virtualenv-clone==0.5.7
46
- virtualenvwrapper==4.8.4
47
- wsproto==1.0.0