Spaces:
Runtime error
Runtime error
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import base64
|
3 |
+
from huggingface_hub import InferenceClient
|
4 |
+
import os
|
5 |
+
|
6 |
+
# Initialize Hugging Face Inference client using token from environment variables
|
7 |
+
client = InferenceClient(api_key=os.getenv("HF_API_TOKEN_DISH"))
|
8 |
+
client1 = InferenceClient(api_key=os.getenv("HF_API_TOKEN_DIET"))
|
9 |
+
|
10 |
+
# 1. Function to identify dish from image
|
11 |
+
def identify_dish(image_bytes):
|
12 |
+
encoded_image = base64.b64encode(image_bytes).decode("utf-8")
|
13 |
+
dish_name = ""
|
14 |
+
|
15 |
+
for message in client.chat_completion(
|
16 |
+
model="meta-llama/Llama-3.2-11B-Vision-Instruct",
|
17 |
+
messages=[
|
18 |
+
{
|
19 |
+
"role": "You are a highly specialized food identification AI with extensive knowledge of global cuisines. Your sole task is to accurately identify dishes from images. Adhere strictly to these guidelines:\n1. Analyze the image thoroughly, focusing on ingredients, presentation, and cultural context.\n2. Provide ONLY the name of the main dish or dishes visible. Do not list individual ingredients or components.\n3. Use the most specific and widely recognized name for the dish.\n4. If multiple distinct dishes are present, list them separated by commas.\n5. If you cannot identify a dish with high confidence (>90%), respond with 'Unidentified dish'.\n6. Do not provide any explanations, descriptions, or additional commentary.\n7. Respond in a concise, list-like format.\nYour response should contain nothing but the dish name(s) or 'Unidentified dish'.",
|
20 |
+
"content": [
|
21 |
+
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encoded_image}" }},
|
22 |
+
{"type": "text", "text": "Identify the dishes in the image and return only the names of the dishes."},
|
23 |
+
],
|
24 |
+
}
|
25 |
+
],
|
26 |
+
max_tokens=70,
|
27 |
+
stream=True,
|
28 |
+
):
|
29 |
+
if message.choices[0].delta.content:
|
30 |
+
dish_name += message.choices[0].delta.content
|
31 |
+
|
32 |
+
return dish_name.strip()
|
33 |
+
|
34 |
+
# 2. Function to get user inputs and calculate daily caloric needs
|
35 |
+
def calculate_metrics(age, gender, height_cm, weight_kg, weight_goal, activity_level, time_frame_months):
|
36 |
+
bmi = weight_kg / ((height_cm / 100) ** 2)
|
37 |
+
|
38 |
+
if gender == "male":
|
39 |
+
bmr = 10 * weight_kg + 6.25 * height_cm - 5 * age + 5
|
40 |
+
else:
|
41 |
+
bmr = 10 * weight_kg + 6.25 * height_cm - 5 * age - 161
|
42 |
+
|
43 |
+
activity_multipliers = {
|
44 |
+
"sedentary": 1.2,
|
45 |
+
"light": 1.375,
|
46 |
+
"moderate": 1.55,
|
47 |
+
"active": 1.725,
|
48 |
+
"very active": 1.9
|
49 |
+
}
|
50 |
+
tdee = bmr * activity_multipliers[activity_level]
|
51 |
+
|
52 |
+
if gender == "male":
|
53 |
+
ibw = 50 + (0.91 * (height_cm - 152.4))
|
54 |
+
else:
|
55 |
+
ibw = 45.5 + (0.91 * (height_cm - 152.4))
|
56 |
+
|
57 |
+
if weight_goal == "loss":
|
58 |
+
daily_caloric_needs = tdee - 500
|
59 |
+
elif weight_goal == "gain":
|
60 |
+
daily_caloric_needs = tdee + 500
|
61 |
+
else:
|
62 |
+
daily_caloric_needs = tdee
|
63 |
+
|
64 |
+
protein_calories = daily_caloric_needs * 0.2
|
65 |
+
fat_calories = daily_caloric_needs * 0.25
|
66 |
+
carbohydrate_calories = daily_caloric_needs * 0.55
|
67 |
+
|
68 |
+
return {
|
69 |
+
"BMI": bmi,
|
70 |
+
"BMR": bmr,
|
71 |
+
"TDEE": tdee,
|
72 |
+
"IBW": ibw,
|
73 |
+
"Daily Caloric Needs": daily_caloric_needs,
|
74 |
+
"Protein Calories": protein_calories,
|
75 |
+
"Fat Calories": fat_calories,
|
76 |
+
"Carbohydrate Calories": carbohydrate_calories
|
77 |
+
}
|
78 |
+
|
79 |
+
# 3. Function to generate diet plan
|
80 |
+
def generate_diet_plan(dish_name, calorie_intake_per_day, goal):
|
81 |
+
user_input = f"""
|
82 |
+
You are a certified Dietitian with 20 years of experience. Based on the following input, create an Indian diet plan that fits within the calculated calorie intake and assesses if the given dish is suitable for the user's goal.
|
83 |
+
|
84 |
+
Input:
|
85 |
+
- Dish Name: {dish_name}
|
86 |
+
- Caloric Intake per Day: {calorie_intake_per_day} calories
|
87 |
+
- Goal: {goal} (e.g., weight loss, weight gain)
|
88 |
+
|
89 |
+
Provide the response in the following format:
|
90 |
+
1. Dish assessment (e.g., "The dish {dish_name} is suitable for your goal" or "The dish {dish_name} is not suitable for your goal, as it is too high in calories for weight goal").
|
91 |
+
2. Suggest an Indian diet plan that stays near to the {calorie_intake_per_day}. For each meal (morning, lunch, evening), list the dish name, calorie count, and ingredients required to make it.And Make it with in 700 Tokens.
|
92 |
+
"""
|
93 |
+
response = client1.chat_completion(
|
94 |
+
model="meta-llama/Meta-Llama-3-8B-Instruct",
|
95 |
+
messages=[{"role": "You are a certified Dietitian with 20 years of Experience", "content": user_input}],
|
96 |
+
max_tokens=700
|
97 |
+
)
|
98 |
+
|
99 |
+
return response.choices[0].message.content
|
100 |
+
|
101 |
+
# Streamlit App Title
|
102 |
+
st.title("AI Diet Planner")
|
103 |
+
|
104 |
+
# Sidebar navigation to switch between the app and the user guide
|
105 |
+
menu = st.sidebar.selectbox("Menu", ["App", "User Guide"])
|
106 |
+
|
107 |
+
# If the user selects the app, show the existing app
|
108 |
+
if menu == "App":
|
109 |
+
# Sidebar for user input
|
110 |
+
st.sidebar.title("User Input")
|
111 |
+
image_file = st.sidebar.file_uploader("Upload an image of the dish", type=["jpeg", "png"])
|
112 |
+
age = st.sidebar.number_input("Enter your age", min_value=18)
|
113 |
+
gender = st.sidebar.selectbox("Select your gender", ["male", "female"])
|
114 |
+
height_cm = st.sidebar.number_input("Enter your height (cm)", min_value=150.0)
|
115 |
+
weight_kg = st.sidebar.number_input("Enter your weight (kg)", min_value=50.0)
|
116 |
+
weight_goal = st.sidebar.selectbox("Weight goal", ["loss", "gain", "maintain"])
|
117 |
+
activity_level = st.sidebar.selectbox("Activity level", ["sedentary", "light", "moderate", "active", "very active"])
|
118 |
+
time_frame = st.sidebar.number_input("Time frame to achieve goal (months)", min_value=1)
|
119 |
+
|
120 |
+
# Submit button
|
121 |
+
submit = st.sidebar.button("Submit")
|
122 |
+
|
123 |
+
# Process the image and calculate metrics upon submission
|
124 |
+
if submit:
|
125 |
+
if image_file:
|
126 |
+
st.write("### Results")
|
127 |
+
image_bytes = image_file.read()
|
128 |
+
|
129 |
+
# Step 1: Identify the dish
|
130 |
+
dish_name = identify_dish(image_bytes)
|
131 |
+
st.markdown("<hr>", unsafe_allow_html=True)
|
132 |
+
st.write("#### Dish Name Identified:")
|
133 |
+
st.markdown(f"<div style='background-color: #d4edda; color: #155724; padding: 10px; border-radius: 10px;'>{dish_name}</div>", unsafe_allow_html=True)
|
134 |
+
|
135 |
+
# Step 2: Perform Calculations
|
136 |
+
metrics = calculate_metrics(age, gender, height_cm, weight_kg, weight_goal, activity_level, time_frame)
|
137 |
+
st.markdown("<hr>", unsafe_allow_html=True)
|
138 |
+
st.write("#### Metrics Calculated:")
|
139 |
+
st.markdown(f"""
|
140 |
+
<div style='background-color: #f8d7da; color: #721c24; padding: 10px; border-radius: 10px;'>
|
141 |
+
<p><b>Your BMI:</b> {metrics['BMI']:.2f}</p>
|
142 |
+
<p><b>Your BMR(Basal metabolic rate):</b> {metrics['BMR']:.2f} calories</p>
|
143 |
+
<p><b>Your TDEE(Total Daily Energy Expenditure):</b> {metrics['TDEE']:.2f} calories</p>
|
144 |
+
<p><b>Ideal Body Weight (IBW):</b> {metrics['IBW']:.2f} kg</p>
|
145 |
+
<p><b>Daily Caloric Needs:</b> {metrics['Daily Caloric Needs']:.2f} calories</p>
|
146 |
+
</div>
|
147 |
+
""", unsafe_allow_html=True)
|
148 |
+
|
149 |
+
# Step 3: Generate diet plan
|
150 |
+
diet_plan = generate_diet_plan(dish_name, metrics["Daily Caloric Needs"], weight_goal)
|
151 |
+
st.markdown("<hr>", unsafe_allow_html=True)
|
152 |
+
st.write("#### Diet Plan Based on Dish & Goal:")
|
153 |
+
st.markdown(f"<div style='background-color: #d1ecf1; color: #0c5460; padding: 10px; border-radius: 10px;'>{diet_plan}</div>", unsafe_allow_html=True)
|
154 |
+
|
155 |
+
else:
|
156 |
+
st.error("Please upload a valid image in JPEG or PNG format.")
|
157 |
+
|
158 |
+
# If the user selects the User Guide, show a detailed guide about the app
|
159 |
+
elif menu == "User Guide":
|
160 |
+
st.write("## AI Diet Planner User Guide")
|
161 |
+
|
162 |
+
st.markdown("""
|
163 |
+
Welcome to the **AI Diet Planner**! This tool helps you identify dishes, calculate your caloric needs, and generate a customized diet plan based on your goals.
|
164 |
+
|
165 |
+
### How to Use:
|
166 |
+
1. **Upload a Dish Image**: Go to the sidebar, and upload a photo of the dish you want to analyze.
|
167 |
+
2. **Provide Your Personal Details**: Enter your age, gender, height, weight, weight goal, and activity level.
|
168 |
+
3. **Submit**: Click the 'Submit' button to get results.
|
169 |
+
|
170 |
+
### What You Get:
|
171 |
+
- **Dish Name**: The AI identifies the dish based on the uploaded image.
|
172 |
+
- **Caloric Metrics**: Your BMI, BMR, and daily caloric needs based on your inputs.
|
173 |
+
- **Diet Plan**: A custom Indian diet plan tailored to your calorie goals and dish.
|
174 |
+
""")
|