blanchon commited on
Commit
c2f344f
·
2 Parent(s): 8d151da a5d1d09

xMerge branch 'master'

Browse files
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .venv
2
+ .env
3
+ *_pycache_*
README.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: PixDiet
3
+ emoji: 🚀
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ hf_oauth: true
12
+ tags:
13
+ - mistral
14
+ - pixtral
15
+ - nutrition
16
+ - diet
17
+ - chatbot
18
+ ---
19
+
20
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from transformers import (
3
+ AutoProcessor,
4
+ BitsAndBytesConfig,
5
+ LlavaForConditionalGeneration,
6
+ )
7
+ from PIL import Image
8
+ import gradio as gr
9
+ from threading import Thread
10
+ from transformers import TextIteratorStreamer, AutoModelForCausalLM, CodeGenTokenizerFast as Tokenizer
11
+ from dotenv import load_dotenv
12
+ import os
13
+ # Import Supabase functions
14
+ from db_client import get_user_history, update_user_history, delete_user_history
15
+
16
+ load_dotenv()
17
+
18
+ # Add TESTING variable
19
+ TESTING = False # You can change this to False when not testing
20
+
21
+ IS_LOGGED_IN = True
22
+ USER_ID = "[email protected]"
23
+
24
+ # Hugging Face model id
25
+ model_id = "blanchon/pixtral-nutrition-2"
26
+
27
+ # BitsAndBytesConfig int-4 config
28
+ bnb_config = BitsAndBytesConfig(
29
+ load_in_4bit=True,
30
+ bnb_4bit_use_double_quant=True,
31
+ bnb_4bit_quant_type="nf4",
32
+ bnb_4bit_compute_dtype=torch.bfloat16,
33
+ )
34
+
35
+ # Modify the model and processor initialization
36
+ if TESTING:
37
+ model_id = "vikhyatk/moondream1"
38
+ model = AutoModelForCausalLM.from_pretrained(model_id, trust_remote_code=True)
39
+ processor = Tokenizer.from_pretrained(model_id)
40
+ else:
41
+ model = LlavaForConditionalGeneration.from_pretrained(
42
+ model_id,
43
+ device_map="auto",
44
+ torch_dtype=torch.bfloat16,
45
+ quantization_config=bnb_config,
46
+ )
47
+ processor = AutoProcessor.from_pretrained(model_id)
48
+
49
+ # Set the chat template for the tokenizer
50
+ processor.chat_template = """
51
+ {%- for message in messages %}
52
+ {%- if message.role == "user" %}
53
+ <s>[INST]
54
+ {%- for item in message.content %}
55
+ {%- if item.type == "text" %}
56
+ {{ item.text }}
57
+ {%- elif item.type == "image" %}
58
+ \n[IMG]
59
+ {%- endif %}
60
+ {%- endfor %}
61
+ [/INST]
62
+ {%- elif message.role == "assistant" %}
63
+ {%- for item in message.content %}
64
+ {%- if item.type == "text" %}
65
+ {{ item.text }}
66
+ {%- endif %}
67
+ {%- endfor %}
68
+ </s>
69
+ {%- endif %}
70
+ {%- endfor %}
71
+ """.replace(' ', "")
72
+
73
+ processor.tokenizer.pad_token = processor.tokenizer.eos_token
74
+
75
+
76
+ def bot_streaming(chatbot, image_input, max_new_tokens=250):
77
+ # Preprocess inputs
78
+ messages = get_user_history(USER_ID)
79
+ images = []
80
+ text_input = chatbot[-1][0]
81
+
82
+ if text_input != "":
83
+ text_input = "you are a nutrition expert. Identify the food/ingredients in this image. Is this a healthy meal? Can you think of how to improve it?"
84
+
85
+ # Add current message
86
+ if image_input is not None:
87
+ # Check if image_input is already a PIL Image
88
+ if isinstance(image_input, Image.Image):
89
+ image = image_input.convert("RGB")
90
+ else:
91
+ image = Image.fromarray(image_input).convert("RGB")
92
+ images.append(image)
93
+ messages.append({
94
+ "role": "user",
95
+ "content": [{"type": "text", "text": text_input}, {"type": "image"}]
96
+ })
97
+ else:
98
+ messages.append({
99
+ "role": "user",
100
+ "content": [{"type": "text", "text": text_input}]
101
+ })
102
+
103
+ # Apply chat template
104
+ texts = processor.apply_chat_template(messages)
105
+
106
+ # Process inputs
107
+ if not images:
108
+ inputs = processor(text=texts, return_tensors="pt").to("cuda")
109
+ else:
110
+ inputs = processor(text=texts, images=images, return_tensors="pt").to("cuda")
111
+
112
+ streamer = TextIteratorStreamer(
113
+ processor.tokenizer, skip_special_tokens=True, skip_prompt=True
114
+ )
115
+
116
+ generation_kwargs = dict(inputs, streamer=streamer, max_new_tokens=max_new_tokens)
117
+
118
+ thread = Thread(target=model.generate, kwargs=generation_kwargs)
119
+ thread.start()
120
+
121
+ response = ""
122
+ for new_text in streamer:
123
+ response += new_text
124
+ chatbot[-1][1] = response
125
+ yield chatbot
126
+
127
+ thread.join()
128
+
129
+ # Debug output
130
+ print('*'*60)
131
+ print('*'*60)
132
+ print('BOT_STREAMING_CONV_START')
133
+ for i, (request, answer) in enumerate(chatbot[:-1], 1):
134
+ print(f'Q{i}:\n {request}')
135
+ print(f'A{i}:\n {answer}')
136
+ print('New_Q:\n', text_input)
137
+ print('New_A:\n', response)
138
+ print('BOT_STREAMING_CONV_END')
139
+
140
+
141
+ if IS_LOGGED_IN:
142
+ new_history = messages + [{"role": "assistant", "content": [{"type": "text", "text": response}]}]
143
+ update_user_history(USER_ID, new_history)
144
+
145
+ # Define the HTML content for the header
146
+ html = f"""
147
+ <p align="center" style="font-size: 2.5em; line-height: 1;">
148
+ <span style="display: inline-block; vertical-align: middle;">🍽️</span>
149
+ <span style="display: inline-block; vertical-align: middle;">PixDiet</span>
150
+ </p>
151
+ <center><font size=3><b>PixDiet</b> is your AI nutrition expert. Upload an image of your meal and chat with our AI to get personalized advice on your diet, meal composition, and ways to improve your nutrition.</font></center>
152
+ <div style="display: flex; justify-content: center; align-items: center; margin-top: 20px;">
153
+ <img src="https://static.alan.com/murray/e5830dc1cc164ef2b054023851e32206_Alan_Lockup_Horizontal_Black_RGB_Large.png" alt="Alan AI Logo" style="height: 50px; margin-right: 20px;">
154
+ <img src="https://seeklogo.com/images/M/mistral-ai-icon-logo-B3319DCA6B-seeklogo.com.png" alt="Mistral AI Logo" style="height: 50px;">
155
+ </div>
156
+ """
157
+
158
+ # Define LaTeX delimiters
159
+ latex_delimiters_set = [
160
+ {"left": "\\(", "right": "\\)", "display": False},
161
+ {"left": "\\begin{equation}", "right": "\\end{equation}", "display": True},
162
+ {"left": "\\begin{align}", "right": "\\end{align}", "display": True},
163
+ {"left": "\\begin{alignat}", "right": "\\end{alignat}", "display": True},
164
+ {"left": "\\begin{gather}", "right": "\\end{gather}", "display": True},
165
+ {"left": "\\begin{CD}", "right": "\\end{CD}", "display": True},
166
+ {"left": "\\[", "right": "\\]", "display": True}
167
+ ]
168
+
169
+ # Create the Gradio interface
170
+ with gr.Blocks(title="PixDiet", theme=gr.themes.Ocean()) as demo:
171
+ gr.HTML(html)
172
+ with gr.Row():
173
+ with gr.Column(scale=3):
174
+ image_input = gr.Image(label="Upload your meal image", height=350, type="pil")
175
+ gr.Examples(
176
+ examples=[
177
+ ["./examples/mistral_breakfast.jpeg", ""],
178
+ ["./examples/pate_carbo.jpg", ""],
179
+ ["./examples/mc_do.jpeg", ""],
180
+ ],
181
+ inputs=[image_input, gr.Textbox(visible=False)]
182
+ )
183
+ with gr.Column(scale=7):
184
+ chatbot = gr.Chatbot(label="Chat with PixDiet", layout="panel", height=600, show_copy_button=True, latex_delimiters=latex_delimiters_set)
185
+ text_input = gr.Textbox(label="Ask about your meal", placeholder="Enter your question here...", lines=1, container=False)
186
+ with gr.Row():
187
+ send_btn = gr.Button("Send", variant="primary")
188
+ clear_btn = gr.Button("Delete my historic", variant="secondary")
189
+
190
+ def submit_chat(chatbot, text_input):
191
+ response = ''
192
+ chatbot.append((text_input, response))
193
+ return chatbot, ''
194
+
195
+ def clear_chat():
196
+ delete_user_history(USER_ID)
197
+ return [], None, ""
198
+
199
+ send_click_event = send_btn.click(submit_chat, [chatbot, text_input], [chatbot, text_input]).then(
200
+ bot_streaming, [chatbot, image_input], chatbot
201
+ )
202
+ # submit_event = text_input.submit(submit_chat, [chatbot, text_input], [chatbot, text_input]).then(
203
+ # bot_streaming, [chatbot, image_input], chatbot
204
+ # )
205
+ clear_btn.click(clear_chat, outputs=[chatbot, image_input, text_input])
206
+
207
+ if __name__ == "__main__":
208
+ demo.launch(debug=False, share=False, show_api=False)
db_client.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from supabase import create_client, Client
2
+ import os
3
+ import json
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+
8
+ # Initialize Supabase client
9
+ supabase: Client = create_client(os.getenv("SUPABASE_URL"), os.getenv("SUPABASE_KEY"))
10
+
11
+ def get_user_history(user_id):
12
+ response = supabase.table("history").select("messages").eq("user", user_id).order("created_at", desc=True).limit(1).execute()
13
+ if response.data:
14
+ return response.data[0]['messages']
15
+ return []
16
+
17
+ def update_user_history(user_id, new_history):
18
+ # Filter out messages with image type
19
+ filtered_history = [
20
+ message for message in new_history
21
+ if not (message["role"] == "user" and
22
+ isinstance(message["content"], list) and
23
+ any(item.get("type") == "image" for item in message["content"]))
24
+ ]
25
+
26
+ # Insert the filtered history into the database
27
+ supabase.table("history").insert({"user": user_id, "messages": filtered_history}).execute()
28
+
29
+ def delete_user_history(user_id):
30
+ response = supabase.table("history").delete().eq("user", user_id).execute()
31
+ return response.data
examples/mc_do.jpeg ADDED
examples/mistral_breakfast.jpeg ADDED
examples/pain_choc.jpeg ADDED
examples/pate_carbo.jpg ADDED
examples/salad_cesar.jpeg ADDED
publish.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import upload_folder
2
+
3
+ upload_folder(
4
+ folder_path="/mnt/sda/jeremy/PixDiet",
5
+ repo_id="eBoreal/PixDiet",
6
+ repo_type="space",
7
+ )
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch>=2.0.0
2
+ transformers==4.45.2
3
+ bitsandbytes>=0.39.0
4
+ accelerate>=0.20.0
5
+ pillow
6
+ gradio
7
+ torchvision
8
+ einops
9
+ timm
10
+ gradio[oauth]
11
+ python-dotenv
12
+ supabase
scenario.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ renal_failure = {
4
+ "context": {
5
+ "patient": "Matthieu, 27 years old, 65kg, diagnosed with stage 3 chronic kidney disease. Requires a low-sodium, low-potassium, and low-phosphorus diet. Advised to limit fluid intake.",
6
+ "chat_history": [
7
+ {
8
+ "day": 1,
9
+ "meal": "Breakfast",
10
+ "image_url": "https://example.com/breakfast_day1.jpg",
11
+ "bot_response": "Good morning, Matthieu! I see you have oatmeal with berries and a glass of water. This is a good start to your day. The oatmeal is low in sodium and phosphorus, which is great for your kidneys. The berries add some natural sweetness and vitamins. Just be mindful of the portion size of berries, as they contain some potassium. The water is good, but remember to stick to your recommended fluid intake. Overall, this is a kidney-friendly breakfast!",
12
+ },
13
+ {
14
+ "day": 1,
15
+ "meal": "Lunch",
16
+ "image_url": "https://example.com/lunch_day1.jpg",
17
+ "bot_response": "I see a sandwich with turkey, lettuce, and tomato on whole wheat bread. Good job on trying to reduce sodium! Turkey is a lean protein, which is good. However, deli meats are often high in sodium, so try to use fresh, unseasoned turkey breast next time. The lettuce is great, but tomatoes are high in potassium. Consider replacing them with cucumber or bell peppers. The whole wheat bread is okay in moderation, but watch your portion sizes as it contains phosphorus. Don't forget to pair this with a low-potassium fruit like apple slices or grapes.",
18
+ },
19
+ {
20
+ "day": 2,
21
+ "meal": "Breakfast",
22
+ "image_url": "https://example.com/breakfast_day2.jpg",
23
+ "bot_response": "Great job, Matthieu! I see scrambled egg whites with herbs, a small portion of low-sodium toast, and some sliced apples. This is an excellent kidney-friendly breakfast. Egg whites are a great source of protein without the phosphorus found in egg yolks. The herbs add flavor without sodium. The toast in moderation is fine, and apples are a perfect low-potassium fruit choice. Remember to measure your fluid intake with that glass of water. Keep up the good work!",
24
+ },
25
+ ],
26
+ },
27
+ "message": {
28
+ "day": 2,
29
+ "meal": "Lunch",
30
+ "image_url": "https://example.com/lunch_day2.jpg",
31
+ "bot_response": """Hello Matthieu! I'm glad to see you're focusing on incorporating more vegetables. Let's analyze your lunch:
32
+
33
+ 1. Grilled chicken breast: Excellent choice! It's a lean protein source that's low in sodium and phosphorus.
34
+
35
+ 2. Steamed vegetables: I see broccoli, carrots, and green beans. These are great low-potassium options. Broccoli is especially good as it's also low in phosphorus.
36
+
37
+ 3. Brown rice: While brown rice is nutritious, it's higher in phosphorus and potassium than white rice. For your condition, it's better to have white rice in moderation. Consider switching to bulgur wheat or couscous as alternatives.
38
+
39
+ 4. Lemon wedge: Great idea! Using lemon for flavor instead of salt is a smart move for reducing sodium intake.
40
+
41
+ 5. Glass of water: Good to see you staying hydrated, but remember to track your fluid intake as per your doctor's recommendations.
42
+
43
+ Overall, this is a much-improved meal compared to yesterday's lunch. Here are some tips for next time:
44
+ - Replace the brown rice with a lower phosphorus grain or reduce the portion size.
45
+ - Add some low-potassium fruits like strawberries or blueberries for dessert.
46
+ - Consider adding herbs like basil or oregano to your vegetables for extra flavor without sodium.
47
+
48
+ Keep up the great work in making these positive changes to your diet!
49
+ """,
50
+ },
51
+ }
52
+
53
+ marathon_runner = {
54
+ "context": {
55
+ "patient": "Jeremie, 27 years old, 1.92m, 75kg, lactose intolerant. Training for a marathon. Wants to optimize energy levels and reduce injury chances. Has difficulty gaining weight.",
56
+ "chat_history": [
57
+ {
58
+ "day": 1,
59
+ "meal": "Breakfast",
60
+ "image_url": "https://example.com/jeremie_breakfast_day1.jpg",
61
+ "bot_response": "Good morning, Jeremie! Your breakfast of oatmeal with banana and almond milk is a great start. Aim for 600-700 calories here. Add 2 tbsp of almond butter for healthy fats and extra calories. Consider 1 scoop of vegan protein powder for muscle recovery. Don't forget 500ml of water to start your hydration routine.",
62
+ },
63
+ {
64
+ "day": 1,
65
+ "meal": "Post-run Snack",
66
+ "image_url": "https://example.com/jeremie_snack_day1.jpg",
67
+ "bot_response": "Good choice with the apple and peanut butter. Aim for a 3:1 carb to protein ratio within 30 minutes post-run. Add a slice of whole grain toast to hit about 30g of carbs. Consider 10g of branched-chain amino acids (BCAAs) to reduce muscle soreness and improve recovery.",
68
+ },
69
+ {
70
+ "day": 2,
71
+ "meal": "Lunch",
72
+ "image_url": "https://example.com/jeremie_lunch_day2.jpg",
73
+ "bot_response": "Great quinoa and vegetable bowl! For your needs, increase portion to 150g of quinoa (dry weight) and 150g of chicken. Add 1 tbsp olive oil for healthy fats. Aim for 800-900 calories here. Include a kiwi for vitamin C to aid iron absorption. Remember to drink 500ml of water with electrolytes during this meal.",
74
+ },
75
+ ],
76
+ },
77
+ "message": {
78
+ "day": 2,
79
+ "meal": "Dinner",
80
+ "image_url": "https://example.com/jeremie_dinner_day2.jpg",
81
+ "bot_response": """Hi Jeremie! Let's analyze your dinner:
82
+
83
+ 1. Salmon (200g): Excellent! Rich in omega-3s (about 4g) for reducing inflammation. Provides about 44g of protein.
84
+
85
+ 2. Sweet potato (150g): Good complex carbs, about 30g. Rich in beta-carotene for immune function.
86
+
87
+ 3. Broccoli (100g): Great for fiber and micronutrients. Only 6g of carbs but packed with vitamins.
88
+
89
+ 4. Olive oil drizzle: Good for healthy fats. Aim for 1 tbsp (14g) for about 120 calories.
90
+
91
+ This meal is a good start but could use some adjustments:
92
+
93
+ - Increase sweet potato to 250g for more carbs (50g total) to support your training.
94
+ - Add 1 cup of cooked quinoa (185g) for extra 220 calories and 8g of protein.
95
+ - Include 1 tbsp of chia seeds for extra 70 calories and 2g of omega-3s.
96
+
97
+ Total calories should be around 900-1000 for this meal.
98
+
99
+ Supplements to consider:
100
+ - 1000mg of Vitamin D3 daily for bone health
101
+ - 500mg of Vitamin C to support your immune system
102
+ - 5g of creatine monohydrate daily for improved performance and recovery
103
+
104
+ Remember to drink at least 500ml of water with this meal. Aim for a total daily fluid intake of 3-4 liters, increasing on heavy training days.
105
+
106
+ Keep up the great work, Jeremie!""",
107
+ },
108
+ }
109
+
110
+ startup_coder = {
111
+ "context": {
112
+ "patient": "Julien, 25 years old, 70kg. Hardcore coder participating in a hackathon. Wants to optimize energy, reduce stress, and improve sleep.",
113
+ "chat_history": [
114
+ {
115
+ "day": 1,
116
+ "meal": "Breakfast",
117
+ "image_url": "https://example.com/julien_breakfast_day1.jpg",
118
+ "bot_response": "Good morning, Julien! Your breakfast of fruits, pain au raisin, and coffee is a quick start, but let's improve it. The fruits provide vitamins and fiber, which is great. However, the pain au raisin is high in sugar and low in protein. Try adding some Greek yogurt or eggs for protein to stabilize your energy. Limit coffee to 1-2 cups to avoid jitters and sleep disruption.",
119
+ },
120
+ {
121
+ "day": 1,
122
+ "meal": "Lunch",
123
+ "image_url": "https://example.com/julien_lunch_day1.jpg",
124
+ "bot_response": "Your lunch of a chicken sandwich with salad is a good base. The chicken provides protein for sustained energy, and the salad offers nutrients. However, the brownie is a sugar spike waiting to happen. Next time, opt for a piece of dark chocolate if you need something sweet. Add some whole grain bread and avocado to your sandwich for complex carbs and healthy fats.",
125
+ },
126
+ {
127
+ "day": 1,
128
+ "meal": "Afternoon Snack",
129
+ "image_url": "https://example.com/julien_snack_day1.jpg",
130
+ "bot_response": "I see you've been snacking on madeleines throughout the afternoon. While they're tasty, they're not the best for sustained energy. Try switching to nuts, seeds, or fresh fruit with nut butter for a better balance of protein, healthy fats, and complex carbs. This will help maintain your energy levels without the sugar crashes.",
131
+ },
132
+ ],
133
+ },
134
+ "message": {
135
+ "day": 1,
136
+ "meal": "Dinner",
137
+ "image_url": "https://example.com/julien_dinner_day1.jpg",
138
+ "bot_response": """Hey Julien! Let's take a look at your dinner and plan for tomorrow:
139
+
140
+ 1. Bowl of pasta: While pasta provides quick energy, it's not the best choice for sustained focus and good sleep. Here's how to improve it:
141
+ - Switch to whole grain pasta for more fiber and nutrients.
142
+ - Add grilled chicken or tofu for protein.
143
+ - Include plenty of vegetables like spinach, broccoli, and cherry tomatoes.
144
+ - Use olive oil and herbs instead of heavy sauces.
145
+
146
+ 2. For tomorrow, I suggest:
147
+ - Breakfast: Overnight oats with chia seeds, berries, and a scoop of protein powder. Green tea instead of coffee.
148
+ - Morning snack: Apple slices with almond butter.
149
+ - Lunch: Quinoa bowl with grilled chicken, mixed vegetables, and avocado. Add a small dark chocolate square for a treat.
150
+ - Afternoon snack: Greek yogurt with walnuts and a drizzle of honey.
151
+ - Dinner: Grilled salmon, sweet potato, and steamed broccoli. Add a small side salad with olive oil and lemon dressing.
152
+
153
+ 3. General tips:
154
+ - Stay hydrated! Aim for at least 2-3 liters of water throughout the day.
155
+ - Take short breaks every hour to stretch and rest your eyes.
156
+ - Consider supplements like Omega-3, Vitamin D, and Magnesium for brain function and stress reduction.
157
+ - Limit caffeine after 2 PM to improve sleep quality.
158
+ - Try meditation or deep breathing exercises to manage stress.
159
+
160
+ Remember, good nutrition, hydration, and regular breaks are key to maintaining high performance during your hackathon. Good luck, Julien!""",
161
+ },
162
+ }
static/alan.png ADDED
static/mistral.png ADDED