import streamlit as st
from PIL import Image
import os
import base64
import io
import textwrap
from typing import Optional, Tuple
from dotenv import load_dotenv
from groq import Groq
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image as ReportLabImage
from reportlab.lib.styles import getSampleStyleSheet
# ======================
# CONFIGURATION
# ======================
st.set_page_config(
page_title="Smart Diet Analyzer",
page_icon="🍎",
layout="wide",
initial_sidebar_state="expanded"
)
ALLOWED_FILE_TYPES = ['png', 'jpg', 'jpeg']
MODEL_NAME = "llama-3.2-11b-vision-preview"
MODEL_SETTINGS = {
'temperature': 0.2,
'max_tokens': 400,
'top_p': 0.5
}
LOGO_PATH = "src/logo.png"
# ======================
# CACHED RESOURCES
# ======================
@st.cache_data
def get_logo_base64() -> Optional[str]:
"""Load and cache logo as base64 string"""
try:
with open(LOGO_PATH, "rb") as img_file:
return base64.b64encode(img_file.read()).decode("utf-8")
except FileNotFoundError:
st.error(f"Logo file not found at {LOGO_PATH}")
return None
@st.cache_resource
def initialize_groq_client() -> Groq:
"""Initialize and cache Groq API client"""
load_dotenv()
if api_key := os.getenv("GROQ_API_KEY"):
return Groq(api_key=api_key)
st.error("GROQ_API_KEY not found in environment")
st.stop()
# ======================
# CORE FUNCTIONALITY
# ======================
def process_image(uploaded_file: io.BytesIO) -> Optional[Tuple[str, str]]:
"""Process uploaded image to base64 string with format detection"""
try:
with Image.open(uploaded_file) as img:
fmt = img.format or 'PNG'
buffer = io.BytesIO()
img.save(buffer, format=fmt)
return base64.b64encode(buffer.getvalue()).decode('utf-8'), fmt
except Exception as e:
st.error(f"Image processing error: {str(e)}")
return None
def generate_pdf_content(report_text: str, logo_b64: Optional[str]) -> io.BytesIO:
"""Generate PDF report with logo and analysis content"""
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=letter)
styles = getSampleStyleSheet()
story = []
# Add logo if available
if logo_b64:
try:
logo_data = base64.b64decode(logo_b64)
with Image.open(io.BytesIO(logo_data)) as logo_img:
aspect = logo_img.height / logo_img.width
max_width = 150
img_width = min(logo_img.width, max_width)
img_height = img_width * aspect
story.append(
ReportLabImage(io.BytesIO(logo_data), width=img_width, height=img_height)
)
story.append(Spacer(1, 12))
except Exception as e:
st.error(f"Logo processing error: {str(e)}")
# Add report content
story.extend([
Paragraph("Nutrition Analysis Report", styles['Title']),
Spacer(1, 12),
Paragraph(report_text.replace('\n', '
'), styles['BodyText'])
])
try:
doc.build(story)
except Exception as e:
st.error(f"PDF generation failed: {str(e)}")
buffer.seek(0)
return buffer
def generate_ai_analysis(client: Groq, image_b64: str, img_format: str) -> Optional[str]:
"""Generate nutritional analysis using Groq's vision API"""
vision_prompt = textwrap.dedent("""
As an expert nutritionist with advanced image analysis capabilities, analyze the provided food image:
1. Identify all visible food items
2. Estimate calorie content considering:
- Portion size
- Cooking method
- Food density
3. Mark estimates as "approximate" when assumptions are needed
4. Calculate total meal calories
Output format:
- Food Item 1: [Name] – Estimated Calories: [value] kcal
- ...
- **Total Estimated Calories:** [value] kcal
Include confidence levels for unclear images and specify limitations.
""")
try:
response = client.chat.completions.create(
model=MODEL_NAME,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": vision_prompt},
{"type": "image_url", "image_url": {
"url": f"data:image/{img_format.lower()};base64,{image_b64}"
}}
]
}],
**MODEL_SETTINGS
)
return response.choices[0].message.content
except Exception as e:
st.error(f"API Error: {str(e)}")
return None
# ======================
# UI COMPONENTS
# ======================
def render_main_content(logo_b64: Optional[str]):
"""Main content layout and interactions"""
st.markdown(f"""
AI-Powered Food & Nutrition Analysis