Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""app.py.ipynb
|
3 |
+
|
4 |
+
Automatically generated by Colab.
|
5 |
+
|
6 |
+
Original file is located at
|
7 |
+
https://colab.research.google.com/drive/1AO89EnPiFQ-JnEpNKwsABc0bj5or_Upn
|
8 |
+
"""
|
9 |
+
|
10 |
+
import pandas as pd
|
11 |
+
import numpy as np
|
12 |
+
from sklearn.ensemble import RandomForestClassifier
|
13 |
+
from sklearn.preprocessing import LabelEncoder
|
14 |
+
from sklearn.model_selection import train_test_split, GridSearchCV
|
15 |
+
import gradio as gr
|
16 |
+
import warnings
|
17 |
+
warnings.filterwarnings('ignore')
|
18 |
+
|
19 |
+
# Step 1: Generate dataset and train model
|
20 |
+
np.random.seed(42)
|
21 |
+
moods = ['happy', 'stressed', 'bored', 'sad', 'excited', 'tired', 'anxious', 'content', 'nostalgic', 'hungry']
|
22 |
+
snacks = [
|
23 |
+
'fruit', 'chocolate', 'chips', 'popcorn', 'ice cream', 'pretzels', 'cookies', 'candy',
|
24 |
+
'yogurt', 'granola bar', 'crackers', 'veggies', 'cheese',
|
25 |
+
'chin chin', 'kuli kuli', 'plantain chips', 'puff puff', 'akara', 'coconut candy',
|
26 |
+
'kokoro', 'dodo ikire', 'roasted groundnuts', 'suya', 'boli', 'kilishi',
|
27 |
+
'buns', 'doughnuts', 'meat pie', 'egg rolls'
|
28 |
+
]
|
29 |
+
times_of_day = ['morning', 'afternoon', 'evening', 'midnight']
|
30 |
+
|
31 |
+
# Snack groups
|
32 |
+
snack_groups = {
|
33 |
+
'nigerian_fried': ['chin chin', 'puff puff', 'akara', 'buns', 'doughnuts', 'meat pie', 'egg rolls'],
|
34 |
+
'nigerian_savory': ['suya', 'kuli kuli', 'plantain chips', 'boli', 'kilishi', 'roasted groundnuts'],
|
35 |
+
'nigerian_sweet': ['coconut candy', 'dodo ikire', 'chocolate', 'candy', 'cookies', 'ice cream'],
|
36 |
+
'savory_snacks': ['chips', 'popcorn', 'pretzels', 'crackers', 'kokoro'],
|
37 |
+
'healthy_light': ['fruit', 'yogurt', 'veggies', 'granola bar', 'cheese']
|
38 |
+
}
|
39 |
+
snack_to_group = {snack: group for group, snacks in snack_groups.items() for snack in snacks}
|
40 |
+
group_list = list(snack_groups.keys())
|
41 |
+
|
42 |
+
# Mood-time-snack group affinities
|
43 |
+
mood_time_group_probs = {
|
44 |
+
'happy': {
|
45 |
+
'morning': {'nigerian_fried': 0.75, 'nigerian_sweet': 0.2, 'healthy_light': 0.05},
|
46 |
+
'afternoon': {'nigerian_fried': 0.75, 'nigerian_sweet': 0.2, 'healthy_light': 0.05},
|
47 |
+
'evening': {'nigerian_sweet': 0.75, 'healthy_light': 0.2, 'savory_snacks': 0.05},
|
48 |
+
'midnight': {'nigerian_sweet': 0.75, 'nigerian_savory': 0.2, 'savory_snacks': 0.05}
|
49 |
+
},
|
50 |
+
'stressed': {
|
51 |
+
'morning': {'nigerian_sweet': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
52 |
+
'afternoon': {'nigerian_sweet': 0.75, 'nigerian_fried': 0.2, 'savory_snacks': 0.05},
|
53 |
+
'evening': {'nigerian_sweet': 0.75, 'savory_snacks': 0.2, 'nigerian_savory': 0.05},
|
54 |
+
'midnight': {'nigerian_sweet': 0.75, 'nigerian_savory': 0.2, 'savory_snacks': 0.05}
|
55 |
+
},
|
56 |
+
'bored': {
|
57 |
+
'morning': {'savory_snacks': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
58 |
+
'afternoon': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05},
|
59 |
+
'evening': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05},
|
60 |
+
'midnight': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05}
|
61 |
+
},
|
62 |
+
'sad': {
|
63 |
+
'morning': {'nigerian_sweet': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
64 |
+
'afternoon': {'nigerian_sweet': 0.75, 'healthy_light': 0.2, 'nigerian_fried': 0.05},
|
65 |
+
'evening': {'nigerian_sweet': 0.75, 'healthy_light': 0.2, 'savory_snacks': 0.05},
|
66 |
+
'midnight': {'nigerian_sweet': 0.75, 'healthy_light': 0.2, 'nigerian_savory': 0.05}
|
67 |
+
},
|
68 |
+
'excited': {
|
69 |
+
'morning': {'nigerian_fried': 0.75, 'nigerian_sweet': 0.2, 'healthy_light': 0.05},
|
70 |
+
'afternoon': {'nigerian_fried': 0.75, 'nigerian_savory': 0.2, 'nigerian_sweet': 0.05},
|
71 |
+
'evening': {'nigerian_sweet': 0.75, 'nigerian_savory': 0.2, 'savory_snacks': 0.05},
|
72 |
+
'midnight': {'nigerian_savory': 0.75, 'nigerian_sweet': 0.2, 'savory_snacks': 0.05}
|
73 |
+
},
|
74 |
+
'tired': {
|
75 |
+
'morning': {'healthy_light': 0.75, 'nigerian_fried': 0.2, 'nigerian_sweet': 0.05},
|
76 |
+
'afternoon': {'healthy_light': 0.75, 'nigerian_fried': 0.2, 'savory_snacks': 0.05},
|
77 |
+
'evening': {'healthy_light': 0.75, 'nigerian_sweet': 0.2, 'savory_snacks': 0.05},
|
78 |
+
'midnight': {'healthy_light': 0.75, 'nigerian_savory': 0.2, 'nigerian_sweet': 0.05}
|
79 |
+
},
|
80 |
+
'anxious': {
|
81 |
+
'morning': {'savory_snacks': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
82 |
+
'afternoon': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05},
|
83 |
+
'evening': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05},
|
84 |
+
'midnight': {'savory_snacks': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05}
|
85 |
+
},
|
86 |
+
'content': {
|
87 |
+
'morning': {'healthy_light': 0.75, 'nigerian_fried': 0.2, 'nigerian_sweet': 0.05},
|
88 |
+
'afternoon': {'nigerian_savory': 0.75, 'healthy_light': 0.2, 'nigerian_fried': 0.05},
|
89 |
+
'evening': {'healthy_light': 0.75, 'nigerian_sweet': 0.2, 'savory_snacks': 0.05},
|
90 |
+
'midnight': {'healthy_light': 0.75, 'nigerian_savory': 0.2, 'nigerian_sweet': 0.05}
|
91 |
+
},
|
92 |
+
'nostalgic': {
|
93 |
+
'morning': {'nigerian_sweet': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
94 |
+
'afternoon': {'nigerian_sweet': 0.75, 'nigerian_fried': 0.2, 'healthy_light': 0.05},
|
95 |
+
'evening': {'nigerian_sweet': 0.75, 'healthy_light': 0.2, 'savory_snacks': 0.05},
|
96 |
+
'midnight': {'nigerian_sweet': 0.75, 'nigerian_savory': 0.2, 'healthy_light': 0.05}
|
97 |
+
},
|
98 |
+
'hungry': {
|
99 |
+
'morning': {'nigerian_fried': 0.75, 'savory_snacks': 0.2, 'healthy_light': 0.05},
|
100 |
+
'afternoon': {'nigerian_savory': 0.75, 'nigerian_fried': 0.2, 'savory_snacks': 0.05},
|
101 |
+
'evening': {'nigerian_savory': 0.75, 'savory_snacks': 0.2, 'nigerian_sweet': 0.05},
|
102 |
+
'midnight': {'nigerian_savory': 0.75, 'savory_snacks': 0.2, 'nigerian_sweet': 0.05}
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
# Generate 1800 samples
|
107 |
+
n_samples = 1800
|
108 |
+
data = {'mood': [], 'time_of_day': [], 'hunger_level': [], 'sentiment': [], 'snack': [], 'snack_group': []}
|
109 |
+
|
110 |
+
for _ in range(n_samples):
|
111 |
+
mood = np.random.choice(moods, p=[0.15, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.05])
|
112 |
+
time = np.random.choice(times_of_day)
|
113 |
+
hunger_level = 1.0 if mood == 'hungry' else np.random.uniform(0, 0.8)
|
114 |
+
sentiment = round(np.random.uniform(-1, 1), 2)
|
115 |
+
|
116 |
+
group_probs = [mood_time_group_probs[mood][time].get(g, 0.01) for g in group_list]
|
117 |
+
group = np.random.choice(group_list, p=group_probs / np.sum(group_probs))
|
118 |
+
group_snacks = snack_groups[group]
|
119 |
+
snack_probs = [
|
120 |
+
0.6 if (snack == 'suya' and time in ['evening', 'midnight']) or (snack == 'boli' and time == 'afternoon') or
|
121 |
+
(snack in ['puff puff', 'buns', 'doughnuts', 'meat pie', 'egg rolls'] and time in ['morning', 'afternoon']) or
|
122 |
+
(snack == 'akara' and time in ['morning', 'midnight']) or
|
123 |
+
(snack == 'chin chin' and time in ['morning', 'afternoon', 'midnight'])
|
124 |
+
else 0.35 if snack in ['kuli kuli', 'plantain chips', 'popcorn', 'kokoro', 'roasted groundnuts', 'kilishi']
|
125 |
+
else 0.2 for snack in group_snacks
|
126 |
+
]
|
127 |
+
if time not in ['evening', 'midnight'] and 'suya' in group_snacks:
|
128 |
+
snack_probs[group_snacks.index('suya')] = 0
|
129 |
+
if time != 'afternoon' and 'boli' in group_snacks:
|
130 |
+
snack_probs[group_snacks.index('boli')] = 0
|
131 |
+
if time not in ['morning', 'afternoon']:
|
132 |
+
for snack in ['puff puff', 'buns', 'doughnuts', 'meat pie', 'egg rolls']:
|
133 |
+
if snack in group_snacks:
|
134 |
+
snack_probs[group_snacks.index(snack)] = 0
|
135 |
+
if time not in ['morning', 'midnight'] and 'akara' in group_snacks:
|
136 |
+
snack_probs[group_snacks.index('akara')] = 0
|
137 |
+
snack_probs = [p / sum(snack_probs) if sum(snack_probs) > 0 else 0.2 for p in snack_probs]
|
138 |
+
snack = np.random.choice(group_snacks, p=snack_probs)
|
139 |
+
|
140 |
+
data['mood'].append(mood)
|
141 |
+
data['time_of_day'].append(time)
|
142 |
+
data['hunger_level'].append(hunger_level)
|
143 |
+
data['sentiment'].append(sentiment)
|
144 |
+
data['snack'].append(snack)
|
145 |
+
data['snack_group'].append(group)
|
146 |
+
|
147 |
+
df = pd.DataFrame(data)
|
148 |
+
|
149 |
+
# Adjust sentiment
|
150 |
+
df.loc[df['mood'].isin(['happy', 'excited', 'content', 'nostalgic']), 'sentiment'] = df.loc[
|
151 |
+
df['mood'].isin(['happy', 'excited', 'content', 'nostalgic']), 'sentiment'].clip(lower=0.2)
|
152 |
+
df.loc[df['mood'].isin(['stressed', 'sad', 'anxious', 'tired']), 'sentiment'] = df.loc[
|
153 |
+
df['mood'].isin(['stressed', 'sad', 'anxious', 'tired']), 'sentiment'].clip(upper=-0.1)
|
154 |
+
df.loc[df['mood'].isin(['bored', 'hungry']), 'sentiment'] = df.loc[
|
155 |
+
df['mood'].isin(['bored', 'hungry']), 'sentiment'].clip(-0.3, 0.3)
|
156 |
+
|
157 |
+
# Add snack_type and snack_texture
|
158 |
+
snack_types = {
|
159 |
+
'chin chin': 'sweet', 'puff puff': 'sweet', 'akara': 'savory', 'suya': 'spicy',
|
160 |
+
'kuli kuli': 'spicy', 'plantain chips': 'savory', 'coconut candy': 'sweet',
|
161 |
+
'dodo ikire': 'sweet', 'roasted groundnuts': 'savory', 'fruit': 'light',
|
162 |
+
'yogurt': 'light', 'veggies': 'light', 'granola bar': 'light', 'cheese': 'light',
|
163 |
+
'chocolate': 'sweet', 'candy': 'sweet', 'cookies': 'sweet', 'ice cream': 'sweet',
|
164 |
+
'chips': 'savory', 'popcorn': 'savory', 'pretzels': 'savory', 'crackers': 'savory',
|
165 |
+
'kokoro': 'savory', 'boli': 'savory', 'kilishi': 'spicy',
|
166 |
+
'buns': 'sweet', 'doughnuts': 'sweet', 'meat pie': 'savory', 'egg rolls': 'savory'
|
167 |
+
}
|
168 |
+
snack_textures = {
|
169 |
+
'chin chin': 'crisp', 'puff puff': 'soft', 'akara': 'soft', 'suya': 'chewy',
|
170 |
+
'kuli kuli': 'crisp', 'plantain chips': 'crisp', 'coconut candy': 'chewy',
|
171 |
+
'dodo ikire': 'soft', 'roasted groundnuts': 'crisp', 'fruit': 'soft',
|
172 |
+
'yogurt': 'soft', 'veggies': 'crisp', 'granola bar': 'crisp', 'cheese': 'soft',
|
173 |
+
'chocolate': 'soft', 'candy': 'chewy', 'cookies': 'crisp', 'ice cream': 'soft',
|
174 |
+
'chips': 'crisp', 'popcorn': 'crisp', 'pretzels': 'crisp', 'crackers': 'crisp',
|
175 |
+
'kokoro': 'crisp', 'boli': 'soft', 'kilishi': 'chewy',
|
176 |
+
'buns': 'soft', 'doughnuts': 'soft', 'meat pie': 'soft', 'egg rolls': 'soft'
|
177 |
+
}
|
178 |
+
df['snack_type'] = df['snack'].map(snack_types)
|
179 |
+
df['snack_texture'] = df['snack'].map(snack_textures)
|
180 |
+
|
181 |
+
# Encode features
|
182 |
+
le_mood = LabelEncoder()
|
183 |
+
le_time = LabelEncoder()
|
184 |
+
le_type = LabelEncoder()
|
185 |
+
le_texture = LabelEncoder()
|
186 |
+
le_group = LabelEncoder()
|
187 |
+
|
188 |
+
df['mood_encoded'] = le_mood.fit_transform(df['mood'])
|
189 |
+
df['time_encoded'] = le_time.fit_transform(df['time_of_day'])
|
190 |
+
df['type_encoded'] = le_type.fit_transform(df['snack_type'])
|
191 |
+
df['texture_encoded'] = le_texture.fit_transform(df['snack_texture'])
|
192 |
+
df['group_encoded'] = le_group.fit_transform(df['snack_group'])
|
193 |
+
|
194 |
+
X = df[['mood_encoded', 'time_encoded', 'hunger_level', 'sentiment', 'type_encoded', 'texture_encoded']]
|
195 |
+
y = df['group_encoded']
|
196 |
+
|
197 |
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
|
198 |
+
|
199 |
+
# Train model
|
200 |
+
param_grid = {
|
201 |
+
'n_estimators': [300, 400],
|
202 |
+
'max_depth': [12, 15],
|
203 |
+
'min_samples_split': [5, 10]
|
204 |
+
}
|
205 |
+
model = RandomForestClassifier(class_weight='balanced', random_state=42)
|
206 |
+
grid_search = GridSearchCV(model, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
|
207 |
+
grid_search.fit(X_train, y_train)
|
208 |
+
best_model = grid_search.best_estimator_
|
209 |
+
|
210 |
+
# Prediction function with error handling
|
211 |
+
def predict_snack(mood, time_of_day, hunger_level, sentiment, snack_type):
|
212 |
+
mood_enc = le_mood.transform([mood])[0]
|
213 |
+
time_enc = le_time.transform([time_of_day])[0]
|
214 |
+
type_enc = le_type.transform([snack_type])[0]
|
215 |
+
type_to_texture = {'sweet': 'soft', 'savory': 'crisp', 'spicy': 'chewy', 'light': 'soft'}
|
216 |
+
texture_enc = le_texture.transform([type_to_texture[snack_type]])[0]
|
217 |
+
input_data = np.array([[mood_enc, time_enc, hunger_level, sentiment, type_enc, texture_enc]])
|
218 |
+
pred = best_model.predict(input_data)
|
219 |
+
group = le_group.inverse_transform(pred)[0]
|
220 |
+
group_snacks = snack_groups[group]
|
221 |
+
snack_probs = [
|
222 |
+
0.6 if (snack == 'suya' and time_of_day in ['evening', 'midnight']) or
|
223 |
+
(snack == 'boli' and time_of_day == 'afternoon') or
|
224 |
+
(snack in ['puff puff', 'buns', 'doughnuts', 'meat pie', 'egg rolls'] and time_of_day in ['morning', 'afternoon']) or
|
225 |
+
(snack == 'akara' and time_of_day in ['morning', 'midnight']) or
|
226 |
+
(snack == 'chin chin' and time_of_day in ['morning', 'afternoon', 'midnight'])
|
227 |
+
else 0.35 if snack in ['kuli kuli', 'plantain chips', 'popcorn', 'kokoro', 'roasted groundnuts', 'kilishi']
|
228 |
+
else 0.2 for snack in group_snacks
|
229 |
+
]
|
230 |
+
# Only modify probabilities if the snack is in the group
|
231 |
+
if time_of_day not in ['evening', 'midnight'] and 'suya' in group_snacks:
|
232 |
+
snack_probs[group_snacks.index('suya')] = 0
|
233 |
+
if time_of_day != 'afternoon' and 'boli' in group_snacks:
|
234 |
+
snack_probs[group_snacks.index('boli')] = 0
|
235 |
+
if time_of_day not in ['morning', 'afternoon']:
|
236 |
+
for snack in ['puff puff', 'buns', 'doughnuts', 'meat pie', 'egg rolls']:
|
237 |
+
if snack in group_snacks:
|
238 |
+
snack_probs[group_snacks.index(snack)] = 0
|
239 |
+
if time_of_day not in ['morning', 'midnight'] and 'akara' in group_snacks:
|
240 |
+
snack_probs[group_snacks.index('akara')] = 0
|
241 |
+
snack_probs = [p / sum(snack_probs) if sum(snack_probs) > 0 else 0.2 for p in snack_probs]
|
242 |
+
snack = np.random.choice(group_snacks, p=snack_probs)
|
243 |
+
return f"You're craving: {snack} (from {group})!"
|
244 |
+
|
245 |
+
# Gradio interface
|
246 |
+
interface = gr.Interface(
|
247 |
+
fn=predict_snack,
|
248 |
+
inputs=[
|
249 |
+
gr.Dropdown(choices=moods, label="Mood", value="happy"),
|
250 |
+
gr.Dropdown(choices=times_of_day, label="Time of Day", value="morning"),
|
251 |
+
gr.Slider(minimum=0, maximum=1, step=0.1, label="Hunger Level (0 to 1)", value=0.5),
|
252 |
+
gr.Slider(minimum=-1, maximum=1, step=0.1, label="Sentiment (-1 to 1)", value=0.0),
|
253 |
+
gr.Dropdown(choices=['sweet', 'savory', 'spicy', 'light'], label="Snack Type", value="sweet")
|
254 |
+
],
|
255 |
+
outputs=gr.Textbox(label="Prediction"),
|
256 |
+
title="Snack Predictor",
|
257 |
+
description="Discover your perfect snack based on your mood,time of the day and preferences!"
|
258 |
+
)
|
259 |
+
|
260 |
+
# Launch the app
|
261 |
+
interface.launch(share=True)
|