Hammad712 commited on
Commit
cc45232
·
verified ·
1 Parent(s): b618274

Upload recipe_app.py

Browse files
Files changed (1) hide show
  1. recipe_app.py +356 -0
recipe_app.py ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from pymongo import MongoClient
3
+ from urllib.parse import quote_plus
4
+ import uuid
5
+ from typing import List
6
+ import json
7
+ from fastapi import FastAPI, File, UploadFile, HTTPException
8
+ import os
9
+ import base64
10
+ from groq import Groq
11
+ import time
12
+
13
+ api_keys = ['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', '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']
14
+
15
+ # MongoDB connection setup
16
+ def get_mongo_client():
17
+ password = quote_plus("momimaad@123") # Change this to your MongoDB password
18
+ mongo_uri = f"mongodb+srv://hammad:{password}@cluster0.2a9yu.mongodb.net/"
19
+ return MongoClient(mongo_uri)
20
+
21
+ db_client = get_mongo_client()
22
+ db = db_client["recipe"]
23
+ user_collection = db["user_info"]
24
+
25
+ # Pydantic models for user data
26
+ class User(BaseModel):
27
+ first_name: str
28
+ last_name: str
29
+ email: str
30
+ password: str
31
+
32
+ class UserData(BaseModel):
33
+ email: str
34
+ password: str
35
+
36
+ class UserToken(BaseModel):
37
+ token: str
38
+
39
+ class RecipeData(BaseModel):
40
+ name: str
41
+
42
+ class AltrecipeData(BaseModel):
43
+ recipe_name: str
44
+ dietary_restrictions: str
45
+ allergies: List
46
+
47
+ class Ingredient(BaseModel):
48
+ name: str
49
+ quantity: str
50
+
51
+
52
+ class Recipe(BaseModel):
53
+ recipe_name: str
54
+ ingredients: List[Ingredient]
55
+ directions: List[str]
56
+
57
+
58
+ class get_recipe_name(BaseModel):
59
+ recipe_name: List[str]
60
+ ingredients: List[List[str]]
61
+
62
+ # Data model for LLM to generate
63
+ class Alternative_Ingredient(BaseModel):
64
+ name: str
65
+ quantity: str
66
+
67
+ class Alternative_Recipe(BaseModel):
68
+ recipe_name: str
69
+ alternative_ingredients: List[Alternative_Ingredient]
70
+ alternative_directions: List[str]
71
+
72
+ def encode_image(self, image_path):
73
+ with open(image_path, "rb") as image_file:
74
+ return base64.b64encode(image_file.read()).decode('utf-8')
75
+
76
+ def get_recipe(recipe_name: str) -> Recipe:
77
+ groq_models = ["llama3-groq-70b-8192-tool-use-preview", "llama-3.1-70b-versatile", "llama3-70b-8192"]
78
+ while True:
79
+ try:
80
+ for api_key in api_keys:
81
+ client = Groq(api_key=api_key)
82
+ for groq_model in groq_models:
83
+ chat_completion = client.chat.completions.create(
84
+ messages=[
85
+ {
86
+ "role": "system",
87
+ "content": f"""Your are an expert agent to generate a recipes with proper and corrected ingredients and direction. Your directions should be concise and to the point and dont explain any irrelevant text.
88
+ You are a recipe database that outputs recipes in JSON.\n
89
+ The JSON object must use the schema: {json.dumps(Recipe.model_json_schema(), indent=2)}""",
90
+ },
91
+ {
92
+ "role": "user",
93
+ "content": f"Fetch a recipe for {recipe_name}",
94
+ },
95
+ ],
96
+ model=groq_model,
97
+ temperature=0,
98
+ # Streaming is not supported in JSON mode
99
+ stream=False,
100
+ # Enable JSON mode by setting the response format
101
+ response_format={"type": "json_object"},
102
+ )
103
+ return Recipe.model_validate_json(chat_completion.choices[0].message.content)
104
+
105
+
106
+ except Exception as e:
107
+ time.sleep(2)
108
+
109
+ continue
110
+
111
+
112
+
113
+ def Suggest_ingredient_alternatives(recipe_name: str, dietary_restrictions: str, allergies: List) -> Alternative_Recipe:
114
+ groq_models = ["llama3-groq-70b-8192-tool-use-preview", "llama-3.1-70b-versatile", "llama3-70b-8192"]
115
+ while True:
116
+ try:
117
+ for api_key in api_keys:
118
+ client = Groq(api_key=api_key)
119
+ for groq_model in groq_models:
120
+ chat_completion = client.chat.completions.create(
121
+ messages=[
122
+ {
123
+ "role": "system",
124
+ "content": f"""
125
+ You are an expert agent to suggest alternatives for specific allergies ingredients for the provided recipe {recipe_name}.
126
+
127
+ Please take the following into account:
128
+ - If the user has dietary restrictions, suggest substitutes that align with their needs (e.g., vegan, gluten-free, etc.) in alternative_directions and your alternative_directions should be concise and to the point.
129
+ -In ingredient you will recommend the safe ingredient for avoid any allergy and dietary restriction.
130
+ - Consider the following allergies {allergies} and recommend the safe ingredient to avoid this allergies.
131
+
132
+ recipe_name: {recipe_name}
133
+ Dietary Restrictions: {dietary_restrictions}
134
+ Allergies: {', '.join(allergies)}
135
+
136
+ You are a recipe database that outputs alternative recipes to avoid allergy and dietary_restrictions in JSON.\n
137
+ The JSON object must use the schema: {json.dumps(Alternative_Recipe.model_json_schema(), indent=2)}""",
138
+ },
139
+ {
140
+ "role": "user",
141
+ "content": f"""Fetch a alternative recipe for recipe_name: {recipe_name}
142
+ Dietary Restrictions: {dietary_restrictions}
143
+ Allergies: {', '.join(allergies)}""",
144
+ },
145
+ ],
146
+ model=groq_model,
147
+ temperature=0,
148
+ # Streaming is not supported in JSON mode
149
+ stream=False,
150
+ # Enable JSON mode by setting the response format
151
+ response_format={"type": "json_object"},
152
+ )
153
+ return Alternative_Recipe.model_validate_json(chat_completion.choices[0].message.content)
154
+ except Exception as e:
155
+ time.sleep(2)
156
+
157
+ continue
158
+
159
+
160
+ def get_explanation(base64_image):
161
+
162
+ while True:
163
+
164
+
165
+ try:
166
+ for api_key in api_keys:
167
+ client = Groq(api_key=api_key)
168
+ completion = client.chat.completions.create(
169
+ model="llama-3.2-90b-vision-preview",
170
+ messages=[
171
+ {
172
+ "role": "user",
173
+ "content": [
174
+ {
175
+ "type": "text",
176
+ "text": """Explain the following image in detail with the recipes names if it were present in images with expanation of ingredients"""
177
+ },
178
+ {
179
+ "type": "image_url",
180
+ "image_url": {
181
+ "url": f"data:image/jpeg;base64,{base64_image}"
182
+ }
183
+ }
184
+ ]
185
+ }
186
+ ],
187
+ temperature=1,
188
+ max_tokens=1024,
189
+ top_p=1,
190
+ stream=False,
191
+ stop=None,
192
+ )
193
+
194
+ return completion.choices[0].message.content
195
+ except Exception as e:
196
+ time.sleep(2)
197
+
198
+ continue
199
+
200
+
201
+ def generate_recipe_info(context):
202
+ groq_models = ["llama3-groq-70b-8192-tool-use-preview", "llama-3.1-70b-versatile", "llama3-70b-8192"]
203
+ output_format = '''
204
+ Kindly generate the following json output format and iwant this format same to same dont change anything and add irrelevant text
205
+ Generate a output according to json format:
206
+
207
+ {'recipes': [it can be empty if there is no data about recipes in context and it conatin many recipes if there are multiple etc for example
208
+ {'recipe_name': '',
209
+ 'ingredients':[only three to four just or minimum]},
210
+ {'recipe_name': '',
211
+ 'ingredients':[only three to four just or minimum]},
212
+ {'recipe_name': '',
213
+ 'ingredients':[only three to four just or minimum]},
214
+ so on
215
+
216
+ ]
217
+ }
218
+ '''
219
+ while True:
220
+ try:
221
+ for api_key in api_keys:
222
+ client = Groq(api_key=api_key)
223
+
224
+ for groq_model in groq_models:
225
+
226
+ chat_completion = client.chat.completions.create(
227
+ messages=[
228
+ {
229
+ "role": "user",
230
+ "content": f'''
231
+ You are an expert agent to analyze the following context and find out recipes name with proper ingredients and i want the out[ut according to following json format and dont need to change anything.
232
+ JSON OUTPUT FORMAT: {output_format}
233
+ Consider the followng contexto answer to answer
234
+ Context:
235
+ {context}
236
+ ''' + output_format
237
+ }
238
+ ],
239
+ temperature=0,
240
+ # Streaming is not supported in JSON mode
241
+ stream=False,
242
+ # Enable JSON mode by setting the response format
243
+ response_format={"type": "json_object"},
244
+ model=groq_model,
245
+ )
246
+
247
+ return chat_completion.choices[0].message.content
248
+ except Exception as e:
249
+ time.sleep(2)
250
+
251
+ continue
252
+
253
+
254
+ app = FastAPI()
255
+
256
+ @app.post("/get_recipe/{token}")
257
+ async def get_recipe_response(token: str, recipe_user: RecipeData):
258
+ user = user_collection.find_one({"token": token})
259
+ if not user:
260
+ raise HTTPException(status_code=401, detail="Invalid token")
261
+
262
+ # Find user by email
263
+ recipe_name = recipe_user.name
264
+ response = get_recipe(recipe_name)
265
+ return {
266
+ "Response": response
267
+ }
268
+
269
+ @app.post("/get_recipe_alternative/{token}")
270
+ async def get_alternative_recipe_response(token: str, altrecipe_user: AltrecipeData):
271
+ user = user_collection.find_one({"token": token})
272
+ if not user:
273
+ raise HTTPException(status_code=401, detail="Invalid token")
274
+
275
+ response = Suggest_ingredient_alternatives(altrecipe_user.recipe_name, altrecipe_user.dietary_restrictions, altrecipe_user.allergies)
276
+ return {
277
+ "Response": response
278
+ }
279
+
280
+
281
+ # Directory to save uploaded images
282
+ UPLOAD_DIR = "uploads"
283
+
284
+ # Ensure the upload directory exists
285
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
286
+
287
+
288
+ # Endpoint to upload an image
289
+ @app.post("/upload-image/{token}")
290
+ async def upload_image(token: str, file: UploadFile = File(...)):
291
+ user = user_collection.find_one({"token": token})
292
+ if not user:
293
+ raise HTTPException(status_code=401, detail="Invalid token")
294
+
295
+ # Validate the file type
296
+ if not file.filename.lower().endswith(('.png', '.jpg', '.jpeg')):
297
+ raise HTTPException(status_code=400, detail="Invalid file type. Only PNG, JPG, and JPEG are allowed.")
298
+
299
+ # Create a file path for saving the uploaded file
300
+ file_path = os.path.join(UPLOAD_DIR, file.filename)
301
+
302
+ # Save the file
303
+ with open(file_path, "wb") as buffer:
304
+ buffer.write(await file.read())
305
+
306
+ context = get_explanation(file_path)
307
+ result = generate_recipe_info(context)
308
+ json_result = json.loads(result)
309
+
310
+ return {
311
+ "Response": json_result
312
+ }
313
+
314
+
315
+ # Endpoint to register a new user
316
+ @app.post("/register")
317
+ async def register_user(user: User):
318
+ # Check if user already exists
319
+ existing_user = user_collection.find_one({"email": user.email})
320
+ if existing_user:
321
+ raise HTTPException(status_code=400, detail="Email already registered")
322
+
323
+ # Create user data
324
+ user_data = {
325
+ "first_name": user.first_name,
326
+ "last_name": user.last_name,
327
+ "email": user.email,
328
+ "password": user.password, # Store plaintext password (not recommended in production)
329
+ }
330
+
331
+ # Insert the user data into the user_info collection
332
+ result = user_collection.insert_one(user_data)
333
+ return {"msg": "User registered successfully", "user_id": str(result.inserted_id)}
334
+
335
+ # Endpoint to check user credentials and generate a token
336
+ @app.post("/get_token")
337
+ async def check_credentials(user: UserData):
338
+ # Find user by email
339
+ existing_user = user_collection.find_one({"email": user.email})
340
+
341
+ # Check if user exists and password matches
342
+ if not existing_user or existing_user["password"] != user.password:
343
+ raise HTTPException(status_code=401, detail="Invalid email or password")
344
+
345
+ # Generate a UUID token
346
+ token = str(uuid.uuid4())
347
+
348
+ # Update the user document with the token
349
+ user_collection.update_one({"email": user.email}, {"$set": {"token": token}})
350
+
351
+ return {
352
+ "first_name": existing_user["first_name"],
353
+ "last_name": existing_user["last_name"],
354
+ "token": token,
355
+ }
356
+