shukdevdatta123 commited on
Commit
30c01d5
·
verified ·
1 Parent(s): 5389033

Create v2.txt

Browse files
Files changed (1) hide show
  1. v2.txt +495 -0
v2.txt ADDED
@@ -0,0 +1,495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import base64
3
+ import requests
4
+ import io
5
+ from PIL import Image
6
+ import json
7
+ import os
8
+ from together import Together
9
+ import tempfile
10
+ import uuid
11
+
12
+ def encode_image_to_base64(image_path):
13
+ """Convert image to base64 encoding"""
14
+ with open(image_path, "rb") as image_file:
15
+ return base64.b64encode(image_file.read()).decode('utf-8')
16
+
17
+ def save_uploaded_image(image):
18
+ """Save uploaded image to a temporary file and return the path"""
19
+ if image is None:
20
+ return None
21
+
22
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as temp_file:
23
+ if isinstance(image, dict) and "path" in image:
24
+ with open(image["path"], "rb") as img_file:
25
+ temp_file.write(img_file.read())
26
+ elif isinstance(image, Image.Image):
27
+ image.save(temp_file.name, format="JPEG")
28
+ else:
29
+ try:
30
+ Image.open(image).save(temp_file.name, format="JPEG")
31
+ except Exception:
32
+ return None
33
+
34
+ return temp_file.name
35
+
36
+ def analyze_single_image(client, img_path):
37
+ """Analyze a single image to identify ingredients"""
38
+ system_prompt = """You are a culinary expert AI assistant that specializes in identifying ingredients in images.
39
+ Your task is to analyze the provided image and list all the food ingredients you can identify.
40
+ Be specific and detailed about what you see. Only list ingredients, don't suggest recipes yet."""
41
+
42
+ user_prompt = "Please identify all the food ingredients visible in this image. List each ingredient on a new line."
43
+
44
+ try:
45
+ with open(img_path, "rb") as image_file:
46
+ base64_image = base64.b64encode(image_file.read()).decode('utf-8')
47
+
48
+ content = [
49
+ {"type": "text", "text": user_prompt},
50
+ {
51
+ "type": "image_url",
52
+ "image_url": {
53
+ "url": f"data:image/jpeg;base64,{base64_image}"
54
+ }
55
+ }
56
+ ]
57
+
58
+ response = client.chat.completions.create(
59
+ model="meta-llama/Llama-Vision-Free",
60
+ messages=[
61
+ {"role": "system", "content": system_prompt},
62
+ {"role": "user", "content": content}
63
+ ],
64
+ max_tokens=500,
65
+ temperature=0.2
66
+ )
67
+
68
+ return response.choices[0].message.content
69
+ except Exception as e:
70
+ return f"Error analyzing image: {str(e)}"
71
+
72
+ def get_recipe_suggestions(api_key, images, num_recipes=3, dietary_restrictions="None", cuisine_preference="Any"):
73
+ """Get recipe suggestions based on the uploaded images of ingredients"""
74
+ if not api_key:
75
+ return "Please provide your Together API key."
76
+
77
+ if not images or len(images) == 0 or all(img is None for img in images):
78
+ return "Please upload at least one image of ingredients."
79
+
80
+ valid_images = [img for img in images if img is not None]
81
+
82
+ if len(valid_images) == 0:
83
+ return "No valid images were uploaded. Please try again."
84
+
85
+ image_paths = []
86
+ for img in valid_images:
87
+ img_path = save_uploaded_image(img)
88
+ if img_path:
89
+ image_paths.append(img_path)
90
+
91
+ if not image_paths:
92
+ return "Failed to process the uploaded images."
93
+
94
+ try:
95
+ client = Together(api_key=api_key)
96
+
97
+ all_ingredients = []
98
+ for img_path in image_paths:
99
+ ingredients_text = analyze_single_image(client, img_path)
100
+ all_ingredients.append(ingredients_text)
101
+
102
+ combined_ingredients = "\n\n".join([f"Image {i+1} ingredients:\n{ingredients}"
103
+ for i, ingredients in enumerate(all_ingredients)])
104
+
105
+ system_prompt = """You are a culinary expert AI assistant that specializes in creating recipes based on available ingredients.
106
+ You will be provided with lists of ingredients identified from multiple images. Your task is to suggest creative,
107
+ detailed recipes that use as many of the identified ingredients as possible.
108
+
109
+ For each recipe suggestion, include:
110
+ 1. Recipe name
111
+ 2. Brief description of the dish
112
+ 3. Complete ingredients list (including estimated quantities and any additional staple ingredients that might be needed)
113
+ 4. Step-by-step cooking instructions
114
+ 5. Approximate cooking time
115
+ 6. Difficulty level (Easy, Medium, Advanced)
116
+ 7. Nutritional highlights
117
+
118
+ Consider any dietary restrictions and cuisine preferences mentioned by the user."""
119
+
120
+ user_prompt = f"""Based on the following ingredients identified from multiple images, suggest {num_recipes} creative and delicious recipes.
121
+
122
+ {combined_ingredients}
123
+
124
+ Dietary restrictions to consider: {dietary_restrictions}
125
+ Cuisine preference: {cuisine_preference}
126
+
127
+ Please be creative with your recipe suggestions and try to use ingredients from multiple images if possible."""
128
+
129
+ response = client.chat.completions.create(
130
+ model="meta-llama/Llama-Vision-Free",
131
+ messages=[
132
+ {"role": "system", "content": system_prompt},
133
+ {"role": "user", "content": user_prompt}
134
+ ],
135
+ max_tokens=2048,
136
+ temperature=0.7
137
+ )
138
+
139
+ for img_path in image_paths:
140
+ try:
141
+ os.unlink(img_path)
142
+ except:
143
+ pass
144
+
145
+ result = "## 📋 Ingredients Identified\n\n"
146
+ result += combined_ingredients
147
+ result += "\n\n---\n\n"
148
+ result += "## 🍽️ Recipe Suggestions\n\n"
149
+ result += response.choices[0].message.content
150
+
151
+ return result
152
+
153
+ except Exception as e:
154
+ for img_path in image_paths:
155
+ try:
156
+ os.unlink(img_path)
157
+ except:
158
+ pass
159
+ return f"Error: {str(e)}"
160
+
161
+ custom_css = """
162
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
163
+ :root {
164
+ --primary-color: #E67E22;
165
+ --primary-dark: #D35400;
166
+ --secondary-color: #2ECC71;
167
+ --accent-color: #F1C40F;
168
+ --background-color: #FFFFFF;
169
+ --text-color: #4A4A4A;
170
+ --card-background: #F8F9FA;
171
+ --border-radius: 10px;
172
+ --font-family: 'Poppins', sans-serif;
173
+ }
174
+ body {
175
+ font-family: var(--font-family);
176
+ background-color: var(--background-color);
177
+ color: var(--text-color);
178
+ margin: 0;
179
+ padding: 0;
180
+ }
181
+ .container {
182
+ max-width: 1200px;
183
+ margin: 0 auto;
184
+ padding: 20px;
185
+ }
186
+ .app-header {
187
+ background-color: var(--primary-color);
188
+ color: white;
189
+ padding: 40px 20px;
190
+ text-align: center;
191
+ border-radius: 0 0 20px 20px;
192
+ box-shadow: 0 4px 10px rgba(0,0,0,0.1);
193
+ }
194
+ .app-title {
195
+ font-size: 2.5em;
196
+ margin-bottom: 10px;
197
+ font-weight: 700;
198
+ }
199
+ .app-subtitle {
200
+ font-size: 1.2em;
201
+ font-weight: 300;
202
+ max-width: 600px;
203
+ margin: 0 auto;
204
+ }
205
+ .input-section, .output-section {
206
+ background-color: var(--card-background);
207
+ border-radius: var(--border-radius);
208
+ padding: 30px;
209
+ box-shadow: 0 4px 15px rgba(0,0,0,0.05);
210
+ margin-bottom: 30px;
211
+ }
212
+ .section-header {
213
+ font-size: 1.5em;
214
+ font-weight: 600;
215
+ color: var(--text-color);
216
+ margin-bottom: 20px;
217
+ border-bottom: 2px solid var(--primary-color);
218
+ padding-bottom: 10px;
219
+ }
220
+ .image-upload-container {
221
+ border: 2px dashed var(--secondary-color);
222
+ border-radius: var(--border-radius);
223
+ padding: 40px;
224
+ text-align: center;
225
+ background-color: rgba(46, 204, 113, 0.05);
226
+ transition: all 0.3s ease;
227
+ }
228
+ .image-upload-container:hover {
229
+ border-color: var(--primary-color);
230
+ background-color: rgba(230, 126, 34, 0.05);
231
+ }
232
+ button.primary-button {
233
+ background-color: var(--primary-color);
234
+ color: white;
235
+ border: none;
236
+ padding: 15px 30px;
237
+ border-radius: 5px;
238
+ font-size: 1.1em;
239
+ cursor: pointer;
240
+ transition: all 0.3s ease;
241
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
242
+ width: 100%;
243
+ }
244
+ button.primary-button:hover {
245
+ background-color: var(--primary-dark);
246
+ box-shadow: 0 4px 10px rgba(0,0,0,0.15);
247
+ }
248
+ .gallery-container {
249
+ display: grid;
250
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
251
+ gap: 15px;
252
+ margin-top: 20px;
253
+ }
254
+ .gallery-item {
255
+ border-radius: 8px;
256
+ overflow: hidden;
257
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
258
+ transition: transform 0.3s ease;
259
+ }
260
+ .gallery-item:hover {
261
+ transform: scale(1.05);
262
+ }
263
+ .recipe-output {
264
+ font-size: 1.1em;
265
+ line-height: 1.6;
266
+ color: var(--text-color);
267
+ max-height: 600px;
268
+ overflow-y: auto;
269
+ padding-right: 10px;
270
+ }
271
+ .recipe-output h2 {
272
+ color: var(--primary-color);
273
+ margin-top: 30px;
274
+ font-size: 1.8em;
275
+ }
276
+ .recipe-output h3 {
277
+ color: var(--secondary-color);
278
+ font-size: 1.4em;
279
+ margin-top: 20px;
280
+ }
281
+ .loading-container {
282
+ display: flex;
283
+ flex-direction: column;
284
+ justify-content: center;
285
+ align-items: center;
286
+ position: fixed;
287
+ top: 0;
288
+ left: 0;
289
+ width: 100%;
290
+ height: 100%;
291
+ background-color: rgba(0, 0, 0, 0.5);
292
+ z-index: 1000;
293
+ opacity: 0;
294
+ visibility: hidden;
295
+ transition: opacity 0.3s ease, visibility 0.3s ease;
296
+ }
297
+ .loading-container.visible {
298
+ opacity: 1;
299
+ visibility: visible;
300
+ }
301
+ .loading-spinner {
302
+ border: 8px solid #f3f3f3;
303
+ border-top: 8px solid var(--primary-color);
304
+ border-radius: 50%;
305
+ width: 60px;
306
+ height: 60px;
307
+ animation: spin 1s linear infinite;
308
+ }
309
+ @keyframes spin {
310
+ 0% { transform: rotate(0deg); }
311
+ 100% { transform: rotate(360deg); }
312
+ }
313
+ .loading-text {
314
+ color: white;
315
+ font-size: 1.2em;
316
+ margin-top: 20px;
317
+ }
318
+ .footer {
319
+ background-color: var(--card-background);
320
+ padding: 40px 20px;
321
+ text-align: center;
322
+ color: var(--text-color);
323
+ font-size: 1em;
324
+ box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
325
+ }
326
+ .footer-content {
327
+ max-width: 800px;
328
+ margin: 0 auto;
329
+ }
330
+ .footer-brand {
331
+ font-weight: 700;
332
+ color: var(--primary-color);
333
+ }
334
+ .footer-links a {
335
+ color: var(--secondary-color);
336
+ text-decoration: none;
337
+ margin: 0 15px;
338
+ transition: color 0.3s ease;
339
+ }
340
+ .footer-links a:hover {
341
+ color: var(--primary-color);
342
+ }
343
+ """
344
+
345
+ html_header = """
346
+ <div class="app-header">
347
+ <div class="app-title">🍲 Visual Recipe Assistant</div>
348
+ <div class="app-subtitle">Upload images of ingredients you have on hand and get personalized recipe suggestions powered by AI</div>
349
+ </div>
350
+ <div id="loading-overlay" class="loading-container">
351
+ <div class="loading-spinner"></div>
352
+ <div class="loading-text">Generating your recipes...</div>
353
+ </div>
354
+ <script>
355
+ function showLoading() {
356
+ document.getElementById('loading-overlay').classList.add('visible');
357
+ }
358
+
359
+ function hideLoading() {
360
+ document.getElementById('loading-overlay').classList.remove('visible');
361
+ }
362
+ </script>
363
+ """
364
+
365
+ html_footer = """
366
+ <div class="footer">
367
+ <div class="footer-content">
368
+ <p><span class="footer-brand">🍲 Visual Recipe Assistant</span></p>
369
+ <p>Powered by Meta's Llama-Vision-Free Model & Together AI</p>
370
+ <p>Upload multiple ingredient images for more creative recipe combinations</p>
371
+ <div class="footer-links">
372
+ <a href="#" target="_blank">How It Works</a>
373
+ <a href="#" target="_blank">Privacy Policy</a>
374
+ <a href="#" target="_blank">Contact Us</a>
375
+ </div>
376
+ </div>
377
+ </div>
378
+ <script>
379
+ document.addEventListener('DOMContentLoaded', function() {
380
+ const submitBtn = document.querySelector('button.primary-button');
381
+ if (submitBtn) {
382
+ submitBtn.addEventListener('click', function() {
383
+ showLoading();
384
+ setTimeout(function() {
385
+ const output = document.querySelector('.recipe-output');
386
+ if (output && output.textContent.trim().length > 0) {
387
+ hideLoading();
388
+ } else {
389
+ const checkInterval = setInterval(function() {
390
+ if (output && output.textContent.trim().length > 0) {
391
+ hideLoading();
392
+ clearInterval(checkInterval);
393
+ }
394
+ }, 1000);
395
+ setTimeout(function() {
396
+ hideLoading();
397
+ clearInterval(checkInterval);
398
+ }, 30000);
399
+ }
400
+ }, 3000);
401
+ });
402
+ }
403
+ });
404
+ </script>
405
+ """
406
+
407
+ with gr.Blocks(css=custom_css) as app:
408
+ gr.HTML(html_header)
409
+
410
+ with gr.Row():
411
+ with gr.Column(scale=1):
412
+ with gr.Group(elem_classes="input-section"):
413
+ gr.HTML('<h3 class="section-header">API Configuration</h3>')
414
+ api_key_input = gr.Textbox(
415
+ label="Together API Key",
416
+ placeholder="Enter your Together API key here...",
417
+ type="password",
418
+ elem_classes="input-group"
419
+ )
420
+
421
+ gr.HTML('<h3 class="section-header">Upload Ingredients</h3>')
422
+ file_upload = gr.File(
423
+ label="Upload images of ingredients",
424
+ file_types=["image"],
425
+ file_count="multiple",
426
+ elem_classes="image-upload-container"
427
+ )
428
+
429
+ image_input = gr.Gallery(
430
+ label="Uploaded Ingredients",
431
+ elem_id="ingredient-gallery",
432
+ columns=3,
433
+ rows=2,
434
+ height="auto",
435
+ visible=False
436
+ )
437
+
438
+ gr.HTML('<h3 class="section-header">Recipe Preferences</h3>')
439
+ with gr.Row():
440
+ num_recipes = gr.Slider(
441
+ minimum=1,
442
+ maximum=5,
443
+ value=3,
444
+ step=1,
445
+ label="Number of Recipe Suggestions",
446
+ elem_classes="input-group"
447
+ )
448
+
449
+ with gr.Row():
450
+ with gr.Column():
451
+ dietary_restrictions = gr.Dropdown(
452
+ choices=["None", "Vegetarian", "Vegan", "Gluten-Free", "Dairy-Free", "Low-Carb", "Keto", "Paleo"],
453
+ value="None",
454
+ label="Dietary Restrictions",
455
+ elem_classes="input-group"
456
+ )
457
+
458
+ with gr.Column():
459
+ cuisine_preference = gr.Dropdown(
460
+ choices=["Any", "Italian", "Asian", "Mexican", "Mediterranean", "Indian", "American", "French", "Middle Eastern"],
461
+ value="Any",
462
+ label="Cuisine Preference",
463
+ elem_classes="input-group"
464
+ )
465
+
466
+ submit_button = gr.Button("Get Recipe Suggestions", elem_classes="primary-button")
467
+
468
+ with gr.Column(scale=1):
469
+ with gr.Group(elem_classes="output-section"):
470
+ gr.HTML('<h3 class="section-header">Your Personalized Recipes</h3>')
471
+ output = gr.Markdown(elem_classes="recipe-output")
472
+
473
+ gr.HTML(html_footer)
474
+
475
+ def update_gallery(files):
476
+ if not files:
477
+ return gr.Gallery.update(visible=False)
478
+ return gr.Gallery.update(value=[file.name for file in files], visible=True)
479
+
480
+ file_upload.change(fn=update_gallery, inputs=file_upload, outputs=image_input)
481
+
482
+ def process_recipe_request(api_key, files, num_recipes, dietary_restrictions, cuisine_preference):
483
+ if not files:
484
+ return "Please upload at least one image of ingredients."
485
+ images = [file.name for file in files]
486
+ return get_recipe_suggestions(api_key, images, num_recipes, dietary_restrictions, cuisine_preference)
487
+
488
+ submit_button.click(
489
+ fn=process_recipe_request,
490
+ inputs=[api_key_input, file_upload, num_recipes, dietary_restrictions, cuisine_preference],
491
+ outputs=output
492
+ )
493
+
494
+ if __name__ == "__main__":
495
+ app.launch()