SURESHBEEKHANI commited on
Commit
e1f3336
Β·
verified Β·
1 Parent(s): af22188

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +197 -182
app.py CHANGED
@@ -1,182 +1,197 @@
1
- import streamlit as st
2
- from PIL import Image
3
- import os
4
- import base64
5
- import io
6
- from dotenv import load_dotenv
7
- from groq import Groq
8
- from reportlab.lib.pagesizes import letter
9
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
10
- from reportlab.lib.styles import getSampleStyleSheet
11
-
12
- # ======================
13
- # CONFIGURATION SETTINGS
14
- # ======================
15
- st.set_page_config(
16
- page_title="Smart Diet Analyzer",
17
- page_icon="🍎",
18
- layout="wide",
19
- initial_sidebar_state="expanded"
20
- )
21
-
22
- ALLOWED_FILE_TYPES = ['png', 'jpg', 'jpeg']
23
-
24
- # ======================
25
- # UTILITY FUNCTIONS
26
- # ======================
27
-
28
- def initialize_api_client():
29
- """Initialize Groq API client"""
30
- load_dotenv()
31
- api_key = os.getenv("GROQ_API_KEY")
32
- if not api_key:
33
- st.error("API key not found. Please verify .env configuration.")
34
- st.stop()
35
- return Groq(api_key=api_key)
36
-
37
-
38
- def encode_image(image_path):
39
- """Encode an image to base64"""
40
- try:
41
- with open(image_path, "rb") as img_file:
42
- return base64.b64encode(img_file.read()).decode("utf-8")
43
- except FileNotFoundError:
44
- return ""
45
-
46
-
47
- def process_image(uploaded_file):
48
- """Convert image to base64 string"""
49
- try:
50
- image = Image.open(uploaded_file)
51
- buffer = io.BytesIO()
52
- image.save(buffer, format=image.format)
53
- return base64.b64encode(buffer.getvalue()).decode('utf-8'), image.format
54
- except Exception as e:
55
- st.error(f"Image processing error: {e}")
56
- return None, None
57
-
58
-
59
- def generate_pdf(report_text):
60
- """Generate a PDF report"""
61
- buffer = io.BytesIO()
62
- doc = SimpleDocTemplate(buffer, pagesize=letter)
63
- styles = getSampleStyleSheet()
64
- story = [Paragraph("<b>Nutrition Analysis Report</b>", styles['Title']), Spacer(1, 12),
65
- Paragraph(report_text.replace('\n', '<br/>'), styles['BodyText'])]
66
- doc.build(story)
67
- buffer.seek(0)
68
- return buffer
69
-
70
-
71
- def generate_analysis(uploaded_file, client):
72
- """Generate AI-powered food analysis"""
73
- base64_image, img_format = process_image(uploaded_file)
74
- if not base64_image:
75
- return None
76
-
77
- image_url = f"data:image/{img_format.lower()};base64,{base64_image}"
78
-
79
- try:
80
- response = client.chat.completions.create(
81
- model="llama-3.2-11b-vision-preview",
82
- messages=[
83
- {
84
- "role": "user",
85
- "content": [
86
- {"type": "text", "text": """
87
- You are an expert nutritionist with advanced image analysis capabilities.
88
- Your task is to analyze the provided image, identify all visible food items, and estimate their calorie content as accurately as possible.
89
-
90
- **Instructions:**
91
- - List each identified food item separately.
92
- - Use known nutritional data to provide accurate calorie estimates.
93
- - Consider portion size, cooking method, and density of food.
94
- - Clearly specify if an item's calorie count is an estimate due to ambiguity.
95
- - Provide the total estimated calorie count for the entire meal.
96
-
97
- **Output Format:**
98
- - Food Item 1: [Name] – Estimated Calories: [value] kcal
99
- - Food Item 2: [Name] – Estimated Calories: [value] kcal
100
- - ...
101
- - **Total Estimated Calories:** [value] kcal
102
-
103
- If the image is unclear or lacks enough details, state the limitations and provide a confidence percentage for the estimation.
104
- """},
105
- {"type": "image_url", "image_url": {"url": image_url}}
106
- ]
107
- }
108
- ],
109
- temperature=0.2,
110
- max_tokens=400,
111
- top_p=0.5
112
- )
113
- return response.choices[0].message.content
114
- except Exception as e:
115
- st.error(f"API communication error: {e}")
116
- return None
117
-
118
- # ======================
119
- # UI COMPONENTS
120
- # ======================
121
-
122
- def display_main_interface():
123
- """Render primary application interface"""
124
- logo_b64 = encode_image("src/logo.png")
125
-
126
- # HTML with inline styles to change text colors
127
- st.markdown(f"""
128
- <div style="text-align: center;">
129
- <img src="data:image/png;base64,{logo_b64}" width="100">
130
- <h2 style="color: #4CAF50;">Smart Diet Analyzer</h2>
131
- <p style="color: #FF6347;">AI-Powered Food & Nutrition Analysis</p>
132
- </div>
133
- """, unsafe_allow_html=True)
134
-
135
- st.markdown("---")
136
-
137
- if st.session_state.get('analysis_result'):
138
- # Create two columns: one for download and one for clear button
139
- col1, col2 = st.columns([1, 1])
140
-
141
- # Left column for the Download button
142
- with col1:
143
- pdf_report = generate_pdf(st.session_state.analysis_result)
144
- st.download_button("πŸ“„ Download Nutrition Report", data=pdf_report, file_name="nutrition_report.pdf", mime="application/pdf")
145
-
146
- # Right column for the Clear button
147
- with col2:
148
- if st.button("Clear Analysis πŸ—‘οΈ"):
149
- st.session_state.pop('analysis_result')
150
- st.rerun()
151
-
152
- if st.session_state.get('analysis_result'):
153
- st.markdown("### 🎯 Nutrition Analysis Report")
154
- st.info(st.session_state.analysis_result)
155
-
156
-
157
- def render_sidebar(client):
158
- """Create sidebar UI elements"""
159
- with st.sidebar:
160
- st.subheader("Image Upload")
161
- uploaded_file = st.file_uploader("Upload Food Image", type=ALLOWED_FILE_TYPES)
162
-
163
- if uploaded_file:
164
- st.image(Image.open(uploaded_file), caption="Uploaded Food Image")
165
- if st.button("Analyze Meal 🍽️"):
166
- with st.spinner("Analyzing image..."):
167
- report = generate_analysis(uploaded_file, client)
168
- st.session_state.analysis_result = report
169
- st.rerun()
170
-
171
- # ======================
172
- # APPLICATION ENTRYPOINT
173
- # ======================
174
-
175
- def main():
176
- """Primary application controller"""
177
- client = initialize_api_client()
178
- display_main_interface()
179
- render_sidebar(client)
180
-
181
- if __name__ == "__main__":
182
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ import os
4
+ import base64
5
+ import io
6
+ from dotenv import load_dotenv
7
+ from groq import Groq
8
+ from reportlab.lib.pagesizes import letter
9
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
10
+ from reportlab.lib.styles import getSampleStyleSheet
11
+
12
+ # ======================
13
+ # CONFIGURATION SETTINGS
14
+ # ======================
15
+ st.set_page_config(
16
+ page_title="Smart Diet Analyzer",
17
+ page_icon="🍎",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ ALLOWED_FILE_TYPES = ['png', 'jpg', 'jpeg']
23
+
24
+ # ======================
25
+ # UTILITY FUNCTIONS
26
+ # ======================
27
+
28
+ def initialize_api_client():
29
+ """Initialize Groq API client"""
30
+ load_dotenv()
31
+ api_key = os.getenv("GROQ_API_KEY")
32
+ if not api_key:
33
+ st.error("API key not found. Please verify .env configuration.")
34
+ st.stop()
35
+ return Groq(api_key=api_key)
36
+
37
+
38
+ def encode_image(image_path):
39
+ """Encode an image to base64"""
40
+ try:
41
+ with open(image_path, "rb") as img_file:
42
+ return base64.b64encode(img_file.read()).decode("utf-8")
43
+ except FileNotFoundError:
44
+ return ""
45
+
46
+
47
+ def process_image(uploaded_file):
48
+ """Convert image to base64 string"""
49
+ try:
50
+ image = Image.open(uploaded_file)
51
+ buffer = io.BytesIO()
52
+ image.save(buffer, format=image.format)
53
+ return base64.b64encode(buffer.getvalue()).decode('utf-8'), image.format
54
+ except Exception as e:
55
+ st.error(f"Image processing error: {e}")
56
+ return None, None
57
+
58
+
59
+ def generate_pdf(report_text, logo_b64):
60
+ """Generate a PDF report"""
61
+ buffer = io.BytesIO()
62
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
63
+ styles = getSampleStyleSheet()
64
+
65
+ # Include logo at the beginning of the report
66
+ logo_image = Image.open(io.BytesIO(base64.b64decode(logo_b64)))
67
+ logo_width, logo_height = logo_image.size
68
+ logo_aspect = logo_height / logo_width
69
+ max_logo_width = 150 # Adjust as needed
70
+ logo_width = min(logo_width, max_logo_width)
71
+ logo_height = int(logo_width * logo_aspect)
72
+
73
+ story = [
74
+ Paragraph(f'<img src="data:image/png;base64,{logo_b64}" width="{logo_width}" height="{logo_height}">', styles['Title']),
75
+ Spacer(1, 12),
76
+ Paragraph("<b>Nutrition Analysis Report</b>", styles['Title']),
77
+ Spacer(1, 12),
78
+ Paragraph(report_text.replace('\n', '<br/>'), styles['BodyText'])
79
+ ]
80
+
81
+ doc.build(story)
82
+ buffer.seek(0)
83
+ return buffer
84
+
85
+
86
+ def generate_analysis(uploaded_file, client):
87
+ """Generate AI-powered food analysis"""
88
+ base64_image, img_format = process_image(uploaded_file)
89
+ if not base64_image:
90
+ return None
91
+
92
+ image_url = f"data:image/{img_format.lower()};base64,{base64_image}"
93
+
94
+ try:
95
+ response = client.chat.completions.create(
96
+ model="llama-3.2-11b-vision-preview",
97
+ messages=[
98
+ {
99
+ "role": "user",
100
+ "content": [
101
+ {"type": "text", "text": """
102
+ You are an expert nutritionist with advanced image analysis capabilities.
103
+ Your task is to analyze the provided image, identify all visible food items, and estimate their calorie content as accurately as possible.
104
+
105
+ **Instructions:**
106
+ - List each identified food item separately.
107
+ - Use known nutritional data to provide accurate calorie estimates.
108
+ - Consider portion size, cooking method, and density of food.
109
+ - Clearly specify if an item's calorie count is an estimate due to ambiguity.
110
+ - Provide the total estimated calorie count for the entire meal.
111
+
112
+ **Output Format:**
113
+ - Food Item 1: [Name] – Estimated Calories: [value] kcal
114
+ - Food Item 2: [Name] – Estimated Calories: [value] kcal
115
+ - ...
116
+ - **Total Estimated Calories:** [value] kcal
117
+
118
+ If the image is unclear or lacks enough details, state the limitations and provide a confidence percentage for the estimation.
119
+ """},
120
+ {"type": "image_url", "image_url": {"url": image_url}}
121
+ ]
122
+ }
123
+ ],
124
+ temperature=0.2,
125
+ max_tokens=400,
126
+ top_p=0.5
127
+ )
128
+ return response.choices[0].message.content
129
+ except Exception as e:
130
+ st.error(f"API communication error: {e}")
131
+ return None
132
+
133
+ # ======================
134
+ # UI COMPONENTS
135
+ # ======================
136
+
137
+ def display_main_interface():
138
+ """Render primary application interface"""
139
+ logo_b64 = encode_image("src/logo.png")
140
+
141
+ # HTML with inline styles to change text colors
142
+ st.markdown(f"""
143
+ <div style="text-align: center;">
144
+ <img src="data:image/png;base64,{logo_b64}" width="100">
145
+ <h2 style="color: #4CAF50;">Smart Diet Analyzer</h2>
146
+ <p style="color: #FF6347;">AI-Powered Food & Nutrition Analysis</p>
147
+ </div>
148
+ """, unsafe_allow_html=True)
149
+
150
+ st.markdown("---")
151
+
152
+ if st.session_state.get('analysis_result'):
153
+ # Create two columns: one for download and one for clear button
154
+ col1, col2 = st.columns([1, 1])
155
+
156
+ # Left column for the Download button
157
+ with col1:
158
+ pdf_report = generate_pdf(st.session_state.analysis_result, logo_b64)
159
+ st.download_button("πŸ“„ Download Nutrition Report", data=pdf_report, file_name="nutrition_report.pdf", mime="application/pdf")
160
+
161
+ # Right column for the Clear button
162
+ with col2:
163
+ if st.button("Clear Analysis πŸ—‘οΈ"):
164
+ st.session_state.pop('analysis_result')
165
+ st.rerun()
166
+
167
+ if st.session_state.get('analysis_result'):
168
+ st.markdown("### 🎯 Nutrition Analysis Report")
169
+ st.info(st.session_state.analysis_result)
170
+
171
+
172
+ def render_sidebar(client):
173
+ """Create sidebar UI elements"""
174
+ with st.sidebar:
175
+ st.subheader("Image Upload")
176
+ uploaded_file = st.file_uploader("Upload Food Image", type=ALLOWED_FILE_TYPES)
177
+
178
+ if uploaded_file:
179
+ st.image(Image.open(uploaded_file), caption="Uploaded Food Image")
180
+ if st.button("Analyze Meal 🍽️"):
181
+ with st.spinner("Analyzing image..."):
182
+ report = generate_analysis(uploaded_file, client)
183
+ st.session_state.analysis_result = report
184
+ st.rerun()
185
+
186
+ # ======================
187
+ # APPLICATION ENTRYPOINT
188
+ # ======================
189
+
190
+ def main():
191
+ """Primary application controller"""
192
+ client = initialize_api_client()
193
+ display_main_interface()
194
+ render_sidebar(client)
195
+
196
+ if __name__ == "__main__":
197
+ main()