Hozifa Elgharbawy commited on
Commit
7c9783f
·
1 Parent(s): b1140b3
models-server/models/fitness_model.py DELETED
@@ -1,259 +0,0 @@
1
- from sklearn.preprocessing import OneHotEncoder
2
- import random
3
- import pandas as pd
4
- import os
5
- import pickle
6
-
7
- SERVER_FILE_DIR = os.path.dirname(os.path.abspath(__file__))
8
- FITNESS_MODEL_PATH = os.path.join(
9
- SERVER_FILE_DIR, *"../resources/models/fitness_model.pkl".split("/")
10
- )
11
-
12
-
13
- class FitnessModel:
14
- def __init__(self, excercise_path, kmeans_path, plan_classifier_path):
15
- self.data = pd.read_csv(excercise_path)
16
- self.kmeans = None
17
- self.plan_classifier = None
18
- self.encoder = None
19
- self.cluster_data = {}
20
- self.X_train_cols = [
21
- "level_Advanced",
22
- "level_Beginner",
23
- "level_Intermediate",
24
- "goal_ Get Fitter",
25
- "goal_ Lose Weight",
26
- "goal_Gain Muscle",
27
- "goal_Get Fitter",
28
- "goal_Increase Endurance",
29
- "goal_Increase Strength",
30
- "goal_Sports Performance",
31
- "gender_Female",
32
- "gender_Male",
33
- "gender_Male & Female",
34
- ]
35
-
36
- # Load kmeans model
37
- with open(kmeans_path, "rb") as f:
38
- self.kmeans = pickle.load(f)
39
-
40
- # Load plan classifier model
41
- with open(plan_classifier_path, "rb") as f:
42
- self.plan_classifier = pickle.load(f)
43
-
44
- # Iterate over each cluster label
45
- for cluster_label in range(90):
46
- # Filter the dataset to get data for the current cluster
47
- cluster_subset = self.data[self.data["cluster"] == cluster_label]
48
-
49
- # Add the cluster data to the dictionary
50
- self.cluster_data[cluster_label] = cluster_subset
51
-
52
- features = self.data[["Level", "goal", "bodyPart"]]
53
-
54
- # Perform one-hot encoding for categorical features
55
- self.encoder = OneHotEncoder(sparse=False)
56
- encoded_features = self.encoder.fit_transform(features)
57
-
58
- def choose_plan(self, level, goal, gender):
59
- global plan_classifier
60
- # Convert input into a DataFrame
61
- input_data = pd.DataFrame(
62
- {"level": [level], "goal": [goal], "gender": [gender]}
63
- )
64
-
65
- # One-hot encode the input data
66
- input_encoded = pd.get_dummies(input_data, columns=["level", "goal", "gender"])
67
-
68
- # Ensure that input has the same columns as the model was trained on
69
- # This is necessary in case some categories are missing in the input
70
- missing_cols = set(self.X_train_cols) - set(input_encoded.columns)
71
- for col in missing_cols:
72
- input_encoded[col] = 0
73
-
74
- # Reorder columns to match the order of columns in X_train
75
- input_encoded = input_encoded[self.X_train_cols]
76
-
77
- # Make prediction for the given input using the trained model
78
- prediction = self.plan_classifier.predict(input_encoded)
79
-
80
- # Convert each string in the list to a list of strings
81
- daily_activities_lists = [day.split(", ") for day in prediction[0]]
82
-
83
- return daily_activities_lists
84
-
85
- def get_daily_recommendation(self, home_or_gym, level, goal, bodyParts, equipments):
86
- if goal in ["Lose Weight", "Get Fitter"]:
87
- goal = "Get Fitter & Lose Weight"
88
- daily_recommendations = []
89
-
90
- bodyParts = [bp for bp in bodyParts if "-" not in bp]
91
- # Repeat elements in bodyParts until it reaches a size of 6
92
- while len(bodyParts) < 6:
93
- bodyParts += bodyParts
94
-
95
- # Limit bodyParts to size 6
96
- bodyParts = bodyParts[:6]
97
-
98
- for bodyPart in bodyParts:
99
- # Predict cluster for the specified combination of goal, level, and body part
100
- input_data = [[level, goal, bodyPart]]
101
- predicted_cluster = self.kmeans.predict(self.encoder.transform(input_data))[
102
- 0
103
- ]
104
- print(predicted_cluster)
105
- # Get data for the predicted cluster
106
- cluster_subset = self.cluster_data[predicted_cluster]
107
-
108
- # Filter data based on location (home or gym)
109
- if home_or_gym == 0:
110
- cluster_subset = cluster_subset[
111
- ~cluster_subset["equipment"].isin(equipments)
112
- ]
113
-
114
- # Randomly select one exercise from the cluster if any left after equipment filtering
115
- if not cluster_subset.empty:
116
- selected_exercise = random.choice(
117
- cluster_subset.to_dict(orient="records")
118
- )
119
- daily_recommendations.append(selected_exercise)
120
-
121
- # Remove duplicates from the list
122
- unique_recommendations = []
123
- seen_names = set()
124
- for exercise in daily_recommendations:
125
- if exercise["name"] not in seen_names:
126
- unique_recommendations.append(exercise)
127
- seen_names.add(exercise["name"])
128
-
129
- return unique_recommendations
130
-
131
- def get_gender_adjustment(self, gender):
132
- return 1.0 if gender == "Male" else 0.7
133
-
134
- def get_age_adjustment(self, age):
135
- if age < 30:
136
- return 1.0
137
- elif 30 <= age < 50:
138
- return 0.5
139
- else:
140
- return 0.1
141
-
142
- def get_level_adjustment(self, level):
143
- if level == "Beginner":
144
- return 0.8
145
- elif level == "Intermediate":
146
- return 1.0
147
- elif level == "Advanced":
148
- return 1.2
149
-
150
- def get_body_part_adjustment(self, body_part):
151
- body_parts = {
152
- "chest": 1,
153
- "shoulders": 0.8,
154
- "waist": 0.6,
155
- "upper legs": 0.7,
156
- "back": 0.9,
157
- "lower legs": 0.5,
158
- "upper arms": 0.8,
159
- "cardio": 0.7,
160
- "lower arms": 0.6,
161
- "neck": 0.5,
162
- }
163
- return body_parts.get(body_part, 0)
164
-
165
- def adjust_workout(self, gender, age, feedback, body_part, level, old_weight):
166
- gender_adjustment = self.get_gender_adjustment(gender)
167
- age_adjustment = self.get_age_adjustment(age)
168
- level_adjustment = self.get_level_adjustment(level)
169
- body_part_adjustment = self.get_body_part_adjustment(body_part)
170
-
171
- increasing_factor_of_weight = (
172
- age_adjustment
173
- * body_part_adjustment
174
- * gender_adjustment
175
- * level_adjustment
176
- * 0.3
177
- )
178
-
179
- if not feedback:
180
- increasing_factor_of_weight = (1 - increasing_factor_of_weight) * -0.1
181
-
182
- new_weight = old_weight + increasing_factor_of_weight * old_weight
183
-
184
- return new_weight
185
-
186
- def calculate_new_repetition(self, level, goal):
187
- if goal in ["Lose Weight", "Get Fitter"]:
188
- if level == "Beginner":
189
- return 15
190
- elif level == "Intermediate":
191
- return 12
192
- elif level == "Expert":
193
- return 10
194
- elif goal == "Gain Muscle":
195
- if level == "Beginner":
196
- return 10
197
- elif level == "Intermediate":
198
- return 8
199
- elif level == "Advanced":
200
- return 6
201
-
202
- def calculate_new_duration(self, level):
203
-
204
- if level == "Beginner":
205
- return 20
206
- elif level == "Intermediate":
207
- return 50
208
- elif level == "Advanced":
209
- return 80
210
-
211
- def predict(
212
- self, home_or_gym, level, goal, gender, age, feedback, old_weight, equipments
213
- ):
214
-
215
- plan = self.choose_plan(level, goal, gender)
216
- print(plan)
217
-
218
- while len(plan) < 30:
219
- plan.extend(plan)
220
- plan = plan[:30]
221
-
222
- all_recommendations = []
223
- for day_body_parts in plan:
224
- daily_exercises = self.get_daily_recommendation(
225
- home_or_gym, level, goal, day_body_parts, equipments
226
- )
227
- daily_recommendations = []
228
-
229
- for exercise in daily_exercises:
230
- weights = self.adjust_workout(
231
- gender, age, feedback, exercise["bodyPart"], level, old_weight
232
- )
233
- repetitions = self.calculate_new_repetition(level, goal)
234
- duration = self.calculate_new_duration(level)
235
- weights_or_duration = (
236
- weights if exercise["type"] == "weight" else duration
237
- )
238
- exercise_recommendations = {
239
- "name": exercise["name"],
240
- "type": exercise["type"],
241
- "equipment": exercise["equipment"],
242
- "bodyPart": exercise["bodyPart"],
243
- "target": exercise["target"],
244
- "weights_or_duration": weights_or_duration,
245
- "sets": exercise["sets"],
246
- "repetitions": repetitions,
247
- }
248
- daily_recommendations.append(exercise_recommendations)
249
- all_recommendations.append(daily_recommendations)
250
-
251
- return all_recommendations # Trim to ensure exactly 30 elements
252
-
253
- @classmethod
254
- def load(cls):
255
- with open(FITNESS_MODEL_PATH, "rb") as f:
256
- print(f)
257
- fitness_model = pickle.load(f)
258
-
259
- return fitness_model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models-server/models/nutrition_model.py DELETED
@@ -1,96 +0,0 @@
1
- import random
2
- import pandas as pd
3
- import numpy as np
4
- import pickle
5
- import os
6
-
7
- SERVER_FILE_DIR = os.path.dirname(os.path.abspath(__file__))
8
- NUTRITION_MODEL_PATH = os.path.join(SERVER_FILE_DIR, "../resources/models/nutrition_model.pkl")
9
- MEALS_JSON_PATH = os.path.join(SERVER_FILE_DIR, "../../src/resources/meals.json")
10
-
11
- # Ensure the file exists
12
- if not os.path.exists(MEALS_JSON_PATH):
13
- raise FileNotFoundError(f"File {MEALS_JSON_PATH} does not exist")
14
-
15
- df = pd.read_json(MEALS_JSON_PATH)
16
-
17
- class NutritionModel:
18
- def __init__(self):
19
- self.load()
20
-
21
- def generate_plan(self, calories):
22
- lunch_attr = {
23
- "Calories": calories * 0.5,
24
- "FatContent": random.uniform(19, 97),
25
- "SaturatedFatContent": random.uniform(6, 12),
26
- "CholesterolContent": random.uniform(77, 299),
27
- "SodiumContent": random.uniform(565, 2299),
28
- "CarbohydrateContent": random.uniform(28, 317),
29
- "FiberContent": random.uniform(2, 38),
30
- "SugarContent": random.uniform(0, 38),
31
- "ProteinContent": random.uniform(20, 123)
32
- }
33
-
34
- lunch_df = pd.DataFrame(lunch_attr, index=[0])
35
-
36
- breakfast_attr = {
37
- "Calories": calories * 0.30,
38
- "FatContent": random.uniform(8.7, 20),
39
- "SaturatedFatContent": random.uniform(1.7, 3.7),
40
- "CholesterolContent": random.uniform(0, 63),
41
- "SodiumContent": random.uniform(163, 650),
42
- "CarbohydrateContent": random.uniform(23, 56),
43
- "FiberContent": random.uniform(2.6, 8),
44
- "SugarContent": random.uniform(3.5, 13),
45
- "ProteinContent": random.uniform(6, 25)
46
- }
47
-
48
- breakfast_df = pd.DataFrame(breakfast_attr, index=[0])
49
-
50
- dinner_attr = {
51
- "Calories": calories * 0.30,
52
- "FatContent": random.uniform(8.7, 20),
53
- "SaturatedFatContent": random.uniform(1.7, 3.7),
54
- "CholesterolContent": random.uniform(0, 63),
55
- "SodiumContent": random.uniform(163, 650),
56
- "CarbohydrateContent": random.uniform(23, 56),
57
- "FiberContent": random.uniform(2.6, 8),
58
- "SugarContent": random.uniform(3.5, 13),
59
- "ProteinContent": random.uniform(6, 25)
60
- }
61
-
62
- dinner_df = pd.DataFrame(dinner_attr, index=[0])
63
-
64
- snack_attr = {
65
- "Calories": random.uniform(90, 190),
66
- "FatContent": random.uniform(1.7, 10),
67
- "SaturatedFatContent": random.uniform(0.7, 3),
68
- "CholesterolContent": random.uniform(2, 16),
69
- "SodiumContent": random.uniform(47, 200),
70
- "CarbohydrateContent": random.uniform(10, 31),
71
- "FiberContent": random.uniform(0.4, 2.5),
72
- "SugarContent": random.uniform(5.7, 21),
73
- "ProteinContent": random.uniform(3, 20)
74
- }
75
-
76
- snack_df = pd.DataFrame(snack_attr, index=[0])
77
-
78
- lunch = self.nutrition_model.transform(lunch_df)
79
- breakfast = self.nutrition_model.transform(breakfast_df)
80
- dinner = self.nutrition_model.transform(dinner_df)
81
- snack = self.nutrition_model.transform(snack_df)
82
-
83
- meals = np.concatenate((breakfast, lunch, dinner, snack), axis=0)
84
- meals = np.transpose(meals)
85
-
86
- days = []
87
- for i in range(7):
88
- day_meals = df.iloc[meals[i]].to_dict(orient="records")
89
- days.append(day_meals)
90
-
91
- return days
92
-
93
- def load(self):
94
- with open(NUTRITION_MODEL_PATH, "rb") as f:
95
- self.nutrition_model = pickle.load(f)
96
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models-server/resources/models/fitness_model.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:665d34c71c506fa1cdbd8d74b54f6ca84f1b9f5a397a6bb90d608cc699f2a61d
3
- size 95457799
 
 
 
 
models-server/resources/models/nutrition_model.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9cd0dc84cc9dcc0c985725e8d5cda8d9f9b0571c6c3219bdef2309f177b46ae1
3
- size 258480
 
 
 
 
models-server/server.py DELETED
@@ -1,62 +0,0 @@
1
- from flask import Flask, request, jsonify
2
- from dotenv import load_dotenv
3
- import os
4
- from models.fitness_model import FitnessModel
5
- from models.nutrition_model import NutritionModel
6
-
7
- load_dotenv()
8
-
9
-
10
- HOST = os.getenv("MODELS_HOST") or "127.0.0.1"
11
- PORT = os.getenv("MODELS_PORT") or "3030"
12
-
13
-
14
- fitness_model = FitnessModel.load()
15
- nutrition_model = NutritionModel()
16
- nutrition_model.load()
17
- app = Flask("model-server")
18
-
19
-
20
- @app.get("/")
21
- def health():
22
- return "I'm alive!!"
23
-
24
-
25
- @app.post("/fitness")
26
- def fitness_predict():
27
- paramNames = [
28
- "home_or_gym",
29
- "level",
30
- "goal",
31
- "gender",
32
- "age",
33
- "feedback",
34
- "old_weight",
35
- "equipments",
36
- ]
37
-
38
- params = {}
39
- for paramName in paramNames:
40
- value = request.json.get(paramName)
41
- if value is None:
42
- return jsonify({"error": f"{paramName} is missing"}), 400
43
- params[paramName] = value
44
-
45
- return jsonify({"result": fitness_model.predict(**params)})
46
-
47
-
48
- @app.post("/nutrition")
49
- def nutrition_predict():
50
- paramNames = ["calories"]
51
-
52
- params = {}
53
- for paramName in paramNames:
54
- value = request.json.get(paramName)
55
- if value is None:
56
- return jsonify({"error": f"{paramName} is missing"}), 400
57
- params[paramName] = value
58
- return jsonify({"result": nutrition_model.generate_plan(**params)})
59
-
60
-
61
- if __name__ == "__main__":
62
- app.run(host=HOST, port=PORT, debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package-lock.json CHANGED
@@ -27,12 +27,14 @@
27
  "npm": "^10.2.5",
28
  "path": "^0.12.7",
29
  "swagger-ui-express": "^5.0.0",
30
- "tsc-alias": "^1.8.8"
 
31
  },
32
  "devDependencies": {
33
  "@faker-js/faker": "^8.4.1",
34
  "@types/express": "^4.17.21",
35
  "@types/swagger-ui-express": "^4.1.6",
 
36
  "nodemon": "^3.0.2",
37
  "ts-node": "^10.9.2",
38
  "ts-node-dev": "^2.0.0",
@@ -457,6 +459,12 @@
457
  "@types/serve-static": "*"
458
  }
459
  },
 
 
 
 
 
 
460
  "node_modules/@types/webidl-conversions": {
461
  "version": "7.0.3",
462
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -5779,6 +5787,18 @@
5779
  "node": ">= 0.4.0"
5780
  }
5781
  },
 
 
 
 
 
 
 
 
 
 
 
 
5782
  "node_modules/v8-compile-cache-lib": {
5783
  "version": "3.0.1",
5784
  "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
 
27
  "npm": "^10.2.5",
28
  "path": "^0.12.7",
29
  "swagger-ui-express": "^5.0.0",
30
+ "tsc-alias": "^1.8.8",
31
+ "uuid": "^10.0.0"
32
  },
33
  "devDependencies": {
34
  "@faker-js/faker": "^8.4.1",
35
  "@types/express": "^4.17.21",
36
  "@types/swagger-ui-express": "^4.1.6",
37
+ "@types/uuid": "^9.0.8",
38
  "nodemon": "^3.0.2",
39
  "ts-node": "^10.9.2",
40
  "ts-node-dev": "^2.0.0",
 
459
  "@types/serve-static": "*"
460
  }
461
  },
462
+ "node_modules/@types/uuid": {
463
+ "version": "9.0.8",
464
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
465
+ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
466
+ "dev": true
467
+ },
468
  "node_modules/@types/webidl-conversions": {
469
  "version": "7.0.3",
470
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
 
5787
  "node": ">= 0.4.0"
5788
  }
5789
  },
5790
+ "node_modules/uuid": {
5791
+ "version": "10.0.0",
5792
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
5793
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
5794
+ "funding": [
5795
+ "https://github.com/sponsors/broofa",
5796
+ "https://github.com/sponsors/ctavan"
5797
+ ],
5798
+ "bin": {
5799
+ "uuid": "dist/bin/uuid"
5800
+ }
5801
+ },
5802
  "node_modules/v8-compile-cache-lib": {
5803
  "version": "3.0.1",
5804
  "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
package.json CHANGED
@@ -17,6 +17,7 @@
17
  "@faker-js/faker": "^8.4.1",
18
  "@types/express": "^4.17.21",
19
  "@types/swagger-ui-express": "^4.1.6",
 
20
  "nodemon": "^3.0.2",
21
  "ts-node": "^10.9.2",
22
  "ts-node-dev": "^2.0.0",
@@ -42,6 +43,7 @@
42
  "npm": "^10.2.5",
43
  "path": "^0.12.7",
44
  "swagger-ui-express": "^5.0.0",
45
- "tsc-alias": "^1.8.8"
 
46
  }
47
  }
 
17
  "@faker-js/faker": "^8.4.1",
18
  "@types/express": "^4.17.21",
19
  "@types/swagger-ui-express": "^4.1.6",
20
+ "@types/uuid": "^9.0.8",
21
  "nodemon": "^3.0.2",
22
  "ts-node": "^10.9.2",
23
  "ts-node-dev": "^2.0.0",
 
43
  "npm": "^10.2.5",
44
  "path": "^0.12.7",
45
  "swagger-ui-express": "^5.0.0",
46
+ "tsc-alias": "^1.8.8",
47
+ "uuid": "^10.0.0"
48
  }
49
  }
src/common/models/template.model.ts CHANGED
@@ -9,7 +9,7 @@ export interface ITemplate {
9
  }
10
 
11
  const templateSchema = new Schema({
12
- name: { type: String, required: true, unique: true, dropDups: true },
13
  user: { type: mongoose.Types.ObjectId, ref: "users" },
14
  creationDate: { type: Date, default: Date.now() },
15
  exercises: [{ type: mongoose.Types.ObjectId, ref: "exercises" }],
 
9
  }
10
 
11
  const templateSchema = new Schema({
12
+ name: { type: String, required: true },
13
  user: { type: mongoose.Types.ObjectId, ref: "users" },
14
  creationDate: { type: Date, default: Date.now() },
15
  exercises: [{ type: mongoose.Types.ObjectId, ref: "exercises" }],
src/modules/users/modules/meal-plans/services/meal-plans.service.ts CHANGED
@@ -30,16 +30,26 @@ export class MealPlansService extends CrudService(MealPlan) {
30
 
31
  const mealsNames = pMealPlan.flat().map((meal) => meal.Name);
32
  const meals = await this.mealsService.listAll({ name: { $in: mealsNames } });
33
- const todayDate = new Date().toLocaleDateString('en-US', {
34
- year: 'numeric',
35
- month: 'long',
36
- day: 'numeric'
37
- });
 
 
 
 
 
 
 
 
 
 
38
  const mealPlan = await this.create({
39
  aiGenerated: true,
40
  image: "https://placehold.co/300x400",
41
  description: `This AI-generated meal plan is designed specifically for you, considering your personal fitness goal of ${user.preferences.fitness_goal}.
42
- Created on ${todayDate}, this plan is tailored to provide a balanced and nutritious diet that supports your workout frequency of ${user.preferences.workout_frequency} times per week.
43
  Whether you prefer working out on ${user.preferences.preferred_days.join(", ")}, at ${user.preferences.workout_place}, or using ${user.preferences.preferred_equipment.join(", ")}, this meal plan will help you achieve your health and fitness goals. Enjoy a variety of delicious and nutritious meals selected just for you.`,
44
  duration: 28,
45
  level: user.fitness_level,
@@ -50,6 +60,7 @@ export class MealPlansService extends CrudService(MealPlan) {
50
  });
51
 
52
 
 
53
 
54
  await this.userRegisteredMealPlansService.createForUser(
55
  {
 
30
 
31
  const mealsNames = pMealPlan.flat().map((meal) => meal.Name);
32
  const meals = await this.mealsService.listAll({ name: { $in: mealsNames } });
33
+ const today = new Date();
34
+ const todayDate = today.toLocaleDateString('en-US', {
35
+ year: 'numeric',
36
+ month: 'long',
37
+ day: 'numeric'
38
+ });
39
+ const currentTime = today.toLocaleTimeString('en-US', {
40
+ hour: '2-digit',
41
+ minute: '2-digit',
42
+ second: '2-digit',
43
+ hour12: false
44
+ });
45
+ const milliseconds = today.getMilliseconds();
46
+
47
+
48
  const mealPlan = await this.create({
49
  aiGenerated: true,
50
  image: "https://placehold.co/300x400",
51
  description: `This AI-generated meal plan is designed specifically for you, considering your personal fitness goal of ${user.preferences.fitness_goal}.
52
+ Created on ${todayDate} at ${currentTime}.${milliseconds}, this plan is tailored to provide a balanced and nutritious diet that supports your workout frequency of ${user.preferences.workout_frequency} times per week.
53
  Whether you prefer working out on ${user.preferences.preferred_days.join(", ")}, at ${user.preferences.workout_place}, or using ${user.preferences.preferred_equipment.join(", ")}, this meal plan will help you achieve your health and fitness goals. Enjoy a variety of delicious and nutritious meals selected just for you.`,
54
  duration: 28,
55
  level: user.fitness_level,
 
60
  });
61
 
62
 
63
+
64
 
65
  await this.userRegisteredMealPlansService.createForUser(
66
  {
src/modules/users/modules/templates/controllers/templates.controller.ts CHANGED
@@ -101,7 +101,7 @@ export class templateController extends BaseController {
101
  @SwaggerSummary("Create custom plan")
102
  @SwaggerDescription("Create a new custom plan")
103
  create = async (req: userRequest, res: Response) => {
104
- const data = await this.templatesService.create(req.body);
105
  return JsonResponse.success(
106
  {
107
  status: 201,
 
101
  @SwaggerSummary("Create custom plan")
102
  @SwaggerDescription("Create a new custom plan")
103
  create = async (req: userRequest, res: Response) => {
104
+ const data = await this.templatesService.create(req.body);
105
  return JsonResponse.success(
106
  {
107
  status: 201,
src/modules/users/modules/templates/services/templates.service.ts CHANGED
@@ -1,4 +1,6 @@
1
  import { Template } from "@common/models/template.model";
2
  import { CrudService } from "@lib/services/crud.service";
3
 
4
- export class TemplateService extends CrudService(Template) {}
 
 
 
1
  import { Template } from "@common/models/template.model";
2
  import { CrudService } from "@lib/services/crud.service";
3
 
4
+ export class TemplateService extends CrudService(Template) {
5
+
6
+ }
src/modules/users/modules/workouts/services/workouts.service.ts CHANGED
@@ -6,6 +6,7 @@ import { CrudService } from "@lib/services/crud.service";
6
  import { calcAge } from "@lib/utils/age";
7
  import { ExerciseService } from "../../exercises/services/exercises.service";
8
  import { UserRegisteredWorkoutsService } from "../../user-registered-workouts/services/user-registered-workouts.service";
 
9
 
10
  export class WorkoutService extends CrudService(Workout) {
11
  private exerciseService = new ExerciseService();
@@ -34,15 +35,25 @@ export class WorkoutService extends CrudService(Workout) {
34
 
35
  const exercisesNames = pworkout.flat().map((e) => e.name);
36
  const exercises = await this.exerciseService.listAll({ name: { $in: exercisesNames } });
37
- const todayDate = new Date().toLocaleDateString('en-US', {
 
38
  year: 'numeric',
39
  month: 'long',
40
  day: 'numeric'
41
  });
 
 
 
 
 
 
 
 
 
42
  const workout = await this.create({
43
  aiGenerated: true,
44
- name: `AI Generated Workout (${user.preferences.fitness_goal} - ${user.fitness_level}) - ${todayDate}`,
45
- description: `This AI-generated workout plan, created on ${todayDate}, is tailored for your ${user.fitness_level.toLowerCase()} fitness level and ${user.preferences.fitness_goal.toLowerCase()} goal. It is designed to be performed ${user.preferences.workout_place === WorkoutPlace.GYM ? "at the gym" : "at home"} using your preferred equipment.`,
46
  type: "AI Generated",
47
  created_by: user._id,
48
  image: "https://placehold.co/300x400",
 
6
  import { calcAge } from "@lib/utils/age";
7
  import { ExerciseService } from "../../exercises/services/exercises.service";
8
  import { UserRegisteredWorkoutsService } from "../../user-registered-workouts/services/user-registered-workouts.service";
9
+ import { v4 as uuidv4 } from 'uuid';
10
 
11
  export class WorkoutService extends CrudService(Workout) {
12
  private exerciseService = new ExerciseService();
 
35
 
36
  const exercisesNames = pworkout.flat().map((e) => e.name);
37
  const exercises = await this.exerciseService.listAll({ name: { $in: exercisesNames } });
38
+ const today = new Date();
39
+ const todayDate = today.toLocaleDateString('en-US', {
40
  year: 'numeric',
41
  month: 'long',
42
  day: 'numeric'
43
  });
44
+ const currentTime = today.toLocaleTimeString('en-US', {
45
+ hour: '2-digit',
46
+ minute: '2-digit',
47
+ second: '2-digit',
48
+ hour12: false
49
+ });
50
+ const milliseconds = today.getMilliseconds();
51
+ const uuid = uuidv4();
52
+
53
  const workout = await this.create({
54
  aiGenerated: true,
55
+ name: `AI Generated Workout (${user.preferences.fitness_goal} - ${user.fitness_level}) - ${todayDate} ${currentTime}.${milliseconds} - ${uuid}`,
56
+ description: `This AI-generated workout plan, created on ${todayDate} at ${currentTime}.${milliseconds}, is tailored for your ${user.fitness_level.toLowerCase()} fitness level and ${user.preferences.fitness_goal.toLowerCase()} goal. It is designed to be performed ${user.preferences.workout_place === WorkoutPlace.GYM ? "at the gym" : "at home"} using your preferred equipment.`,
57
  type: "AI Generated",
58
  created_by: user._id,
59
  image: "https://placehold.co/300x400",
src/resources/meals.json CHANGED
The diff for this file is too large to render. See raw diff