Untitled

 avatar
unknown
plain_text
10 months ago
6.8 kB
18
Indexable
# File: nutrisnap/app.py
import os
from flask import Flask, render_template, request, jsonify
from dotenv import load_dotenv
from main import estimate_nutrition

load_dotenv()

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload():
    if 'image' not in request.files:
        return jsonify({'error': 'No image uploaded'}), 400
    
    file = request.files['image']
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400
    
    image_path = 'temp_image.jpg'
    file.save(image_path)
    
    try:
        result = estimate_nutrition(image_path)
        os.remove(image_path)
        return jsonify(result)
    except Exception as e:
        os.remove(image_path)
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

# File: nutrisnap/main.py
import os
import base64
import json
from openai import OpenAI
from PIL import Image, ImageOps
from io import BytesIO

MODEL = "gpt-4o"

def resize_image(image_path, target_width=1000):
    with Image.open(image_path) as img:
        img = ImageOps.exif_transpose(img)
        original_width, original_height = img.size
        target_height = int((target_width / original_width) * original_height)
        resized_img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)
        return resized_img

def pil_image_to_base64(img):
    buffered = BytesIO()
    img.save(buffered, format="JPEG")
    base64_str = base64.b64encode(buffered.getvalue()).decode('utf-8')
    return base64_str

def estimate_nutrition(image_path):
    resized_image = resize_image(image_path, 1000)
    base64_image = pil_image_to_base64(resized_image)
    
    system_prompt = "You are a nutrition expert. Analyze the meal photo and estimate calories and nutrients."
    user_prompt = """
    The photo shows a meal. Determine the items and return ONLY as JSON:
    {
        "items": [
            {
                "title": "item name",
                "weight_grams": estimated weight,
                "calories_per_100g": calories per 100g,
                "proteins_per_100g": proteins per 100g,
                "fats_per_100g": fats per 100g,
                "carbs_per_100g": carbs per 100g,
                "fiber_per_100g": fiber per 100g
            }
        ],
        "total_calories": total calories for the meal,
        "suggestions": "Brief health tips or swaps"
    }
    """
    
    client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
    completion = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": [
                {"type": "text", "text": user_prompt},
                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
            ]}
        ],
        response_format={"type": "json_object"}
    )
    
    response_content = completion.choices[0].message.content
    return json.loads(response_content)

# File: nutrisnap/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NutriSnap - AI Meal Analyzer</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <h1>NutriSnap</h1>
        <p>Snap a photo of your meal to get instant nutrition info!</p>
        <button id="upload-btn">Upload Meal Photo</button>
        <div id="result" style="display: none;">
            <h2>Analysis:</h2>
            <pre id="output"></pre>
        </div>
        <div id="loading" style="display: none;">Analyzing... <div class="spinner"></div></div>
    </div>
    <script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>

# File: nutrisnap/static/style.css
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.container {
    text-align: center;
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

#upload-btn {
    background: #4CAF50;
    color: white;
    padding: 10px 20px;
    border: none;
    cursor: pointer;
    font-size: 16px;
}

#upload-btn:hover {
    background: #45a049;
}

#result {
    margin-top: 20px;
}

pre {
    text-align: left;
    background: #eee;
    padding: 10px;
    border-radius: 4px;
}

#loading {
    margin-top: 10px;
}

.spinner {
    border: 4px solid #f3f3f3;
    border-top: 4px solid #3498db;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    animation: spin 1s linear infinite;
    display: inline-block;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

# File: nutrisnap/static/script.js
document.getElementById('upload-btn').addEventListener('click', function() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'image/*';
    input.onchange = function(event) {
        const file = event.target.files[0];
        if (file) {
            const formData = new FormData();
            formData.append('image', file);
            
            document.getElementById('loading').style.display = 'block';
            document.getElementById('upload-btn').style.display = 'none';
            
            fetch('/upload', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                document.getElementById('loading').style.display = 'none';
                document.getElementById('result').style.display = 'block';
                document.getElementById('output').textContent = JSON.stringify(data, null, 2);
                document.getElementById('upload-btn').style.display = 'block';
            })
            .catch(error => {
                console.error('Error:', error);
                document.getElementById('loading').style.display = 'none';
                alert('Error analyzing image');
                document.getElementById('upload-btn').style.display = 'block';
            });
        }
    };
    input.click();
});

# File: nutrisnap/requirements.txt
flask==3.0.3
openai==1.40.0
pillow==10.4.0
python-dotenv==1.0.1

# File: nutrisnap/.env (create manually, add your API key)
OPENAI_API_KEY=your_api_key_here
Editor is loading...
Leave a Comment