CoolFace
Apppublic

AlvesS077/SmartPlate

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index.html266 linesDownload Raw Back to root
1<!DOCTYPE html>
2<html lang="pt-br">
3<head>
4  <meta charset="UTF-8" />
5  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6  <title>Food Classifier</title>
7  <script src="https://cdn.tailwindcss.com"></script>
8  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9  <style>
10    .upload-box {
11      transition: all 0.3s ease;
12    }
13    .upload-box:hover {
14      transform: translateY(-2px);
15      box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
16    }
17    .preview-container {
18      transition: all 0.5s ease;
19    }
20    .loading-spinner {
21      display: none;
22    }
23    @keyframes fade-in {
24      from { opacity: 0; transform: translateY(30px);}
25      to { opacity: 1; transform: translateY(0);}
26    }
27    .animate-fade-in {
28      animation: fade-in 0.8s cubic-bezier(.4,0,.2,1) both;
29    }
30  </style>
31</head>
32<body class="bg-gradient-to-br from-green-50 to-blue-50 min-h-screen">
33  <div class="container mx-auto px-4 py-12 max-w-4xl">
34    <div class="text-center mb-12">
35      <h1 class="text-4xl font-bold text-green-800 mb-3">🍽️ Food Classifier</h1>
36      <p class="text-lg text-gray-600">Upload an image of your food and we'll analyze its nutritional content</p>
37    </div>
38
39    <div class="bg-white rounded-xl shadow-lg p-8 mb-8">
40      <div class="upload-box bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg p-12 text-center cursor-pointer mb-8"
41           onclick="document.getElementById('upload').click()">
42        <div class="flex flex-col items-center justify-center">
43          <i class="fas fa-cloud-upload-alt text-4xl text-green-500 mb-4"></i>
44          <h3 class="text-xl font-semibold text-gray-700 mb-2">Upload your food image</h3>
45          <p class="text-gray-500">Drag & drop or click to browse</p>
46        </div>
47        <input type="file" id="upload" accept="image/*" class="hidden" onchange="mostrarImagem(event)" />
48      </div>
49
50      <div class="preview-container flex flex-col items-center justify-center mb-8">
51        <div id="preview-wrapper" class="relative hidden">
52          <img id="preview" src="" alt="Preview" class="rounded-lg shadow-md max-h-96 object-contain" />
53          <button id="remove-btn" class="absolute -top-3 -right-3 bg-red-500 text-white rounded-full w-8 h-8 flex items-center justify-center shadow-md hover:bg-red-600 transition" onclick="removeImage()">
54            <i class="fas fa-times"></i>
55          </button>
56        </div>
57        <p id="no-image-text" class="text-gray-400 italic">No image selected</p>
58      </div>
59
60      <div class="flex justify-center">
61        <button id="submit-btn" class="submit-btn bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-8 rounded-full shadow-lg transition flex items-center disabled:opacity-50 disabled:cursor-not-allowed"
62                onclick="enviarImagem()" disabled>
63          <span id="btn-text">Analyze Food</span>
64          <div id="loading-spinner" class="loading-spinner ml-2">
65            <i class="fas fa-circle-notch fa-spin"></i>
66          </div>
67        </button>
68      </div>
69    </div>
70
71    <div class="bg-white rounded-xl shadow-lg p-8">
72      <h2 class="text-2xl font-semibold text-gray-800 mb-4">How it works</h2>
73      <div class="grid md:grid-cols-3 gap-6">
74        <div class="flex flex-col items-center text-center">
75          <div class="bg-green-100 p-4 rounded-full mb-3">
76            <i class="fas fa-upload text-green-600 text-2xl"></i>
77          </div>
78          <h3 class="font-medium text-gray-700 mb-2">1. Upload Image</h3>
79          <p class="text-gray-500">Upload a clear photo of your food</p>
80        </div>
81        <div class="flex flex-col items-center text-center">
82          <div class="bg-blue-100 p-4 rounded-full mb-3">
83            <i class="fas fa-brain text-blue-600 text-2xl"></i>
84          </div>
85          <h3 class="font-medium text-gray-700 mb-2">2. AI Analysis</h3>
86          <p class="text-gray-500">Our AI analyzes the food components</p>
87        </div>
88        <div class="flex flex-col items-center text-center">
89          <div class="bg-purple-100 p-4 rounded-full mb-3">
90            <i class="fas fa-chart-pie text-purple-600 text-2xl"></i>
91          </div>
92          <h3 class="font-medium text-gray-700 mb-2">3. Get Results</h3>
93          <p class="text-gray-500">Receive detailed nutritional information</p>
94        </div>
95      </div>
96    </div>
97  </div>
98
99  <script>
100    function mostrarImagem(event) {
101      const file = event.target.files[0];
102      if (file) {
103        const reader = new FileReader();
104        reader.onload = function(e) {
105          const preview = document.getElementById('preview');
106          preview.src = e.target.result;
107          document.getElementById('preview-wrapper').classList.remove('hidden');
108          document.getElementById('no-image-text').classList.add('hidden');
109          document.getElementById('submit-btn').disabled = false;
110        };
111        reader.readAsDataURL(file);
112      }
113    }
114
115    function removeImage() {
116      document.getElementById('preview').src = '';
117      document.getElementById('preview-wrapper').classList.add('hidden');
118      document.getElementById('no-image-text').classList.remove('hidden');
119      document.getElementById('upload').value = '';
120      document.getElementById('submit-btn').disabled = true;
121    }
122
123    function enviarImagem() {
124      const btn = document.getElementById('submit-btn');
125      const btnText = document.getElementById('btn-text');
126      const spinner = document.getElementById('loading-spinner');
127      const uploadInput = document.getElementById('upload');
128      const previewWrapper = document.getElementById('preview-wrapper');
129
130      // Show loading state
131      btn.disabled = true;
132      btnText.textContent = 'Analyzing...';
133      spinner.style.display = 'inline-block';
134
135      const file = uploadInput.files[0];
136      if (!file) {
137        alert('Please select an image first.');
138        btn.disabled = false;
139        btnText.textContent = 'Analyze Food';
140        spinner.style.display = 'none';
141        return;
142      }
143
144      const formData = new FormData();
145      formData.append('image', file);
146
147      fetch('http://127.0.0.1:5000/analyze-food', {
148        method: 'POST',
149        body: formData
150      })
151      .then(response => response.json())
152      .then(data => {
153        btn.disabled = false;
154        btnText.textContent = 'Analyze Food';
155        spinner.style.display = 'none';
156
157        if (data.error) {
158          alert('Error: ' + data.error);
159          return;
160        }
161
162        let resultsContainer = document.getElementById('results-container');
163        if (!resultsContainer) {
164          resultsContainer = document.createElement('div');
165          resultsContainer.id = 'results-container';
166          resultsContainer.className = 'bg-white rounded-xl shadow-lg p-8 mt-8';
167          document.querySelector('.container').appendChild(resultsContainer);
168        }
169
170        // Ordem correta das colunas
171        const orderedColumns = [
172          'Plate Name',
173          'Protein (g)',
174          'Calories',
175          'Fat (g)',
176          'Carbs (g)',
177          'Fiber (g)'
178        ];
179
180        let excelHtml = '';
181        if (data.excel && !data.excel.error) {
182          excelHtml = '<ul class="list-disc pl-5">';
183          orderedColumns.forEach(key => {
184            if (data.excel[key] !== undefined) {
185              excelHtml += `<li><strong>${key}:</strong> ${data.excel[key]}</li>`;
186            }
187          });
188          excelHtml += '</ul>';
189        } else if (data.excel && data.excel.error) {
190          excelHtml = `<p class="text-red-500">${data.excel.error}</p>`;
191        }
192
193        resultsContainer.innerHTML = `
194          <div class="relative bg-gradient-to-br from-green-100 via-blue-50 to-purple-100 rounded-2xl shadow-2xl p-8 border-4 border-green-200 ring-2 ring-green-400/30 animate-fade-in">
195            <div class="absolute -top-8 left-1/2 -translate-x-1/2 flex items-center justify-center">
196              <span class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-gradient-to-br from-green-400 to-green-600 shadow-lg border-4 border-white">
197                <i class="fas fa-leaf text-white text-3xl"></i>
198              </span>
199            </div>
200            <h2 class="text-3xl font-extrabold text-green-800 text-center mt-10 mb-6 tracking-tight drop-shadow">Analysis Results</h2>
201            <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
202              <div class="flex-1 text-center md:text-left">
203                <p class="text-lg font-semibold text-gray-700 mb-2">Could Cause:</p>
204                <span class="inline-block bg-green-200 text-green-900 font-bold text-xl px-6 py-2 rounded-full shadow-md border border-green-400 tracking-wide animate-pulse">${data.class}</span>
205              </div>
206              <div class="flex-1 mt-6 md:mt-0">
207                <div class="bg-white/80 rounded-xl p-4 shadow-inner border border-gray-200">
208                  <h3 class="text-lg font-semibold text-purple-700 mb-2">Alternative Meal:</h3>
209                  <div class="text-gray-700 text-base">
210                    ${excelHtml}
211                  </div>
212                </div>
213              </div>
214            </div>
215          </div>
216        `;
217      })
218      .catch(error => {
219        btn.disabled = false;
220        btnText.textContent = 'Analyze Food';
221        spinner.style.display = 'none';
222        alert('Error: ' + error.message);
223      });
224    }
225
226    // Drag and drop functionality
227    const uploadBox = document.querySelector('.upload-box');
228    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
229      uploadBox.addEventListener(eventName, preventDefaults, false);
230    });
231
232    function preventDefaults(e) {
233      e.preventDefault();
234      e.stopPropagation();
235    }
236
237    ['dragenter', 'dragover'].forEach(eventName => {
238      uploadBox.addEventListener(eventName, highlight, false);
239    });
240
241    ['dragleave', 'drop'].forEach(eventName => {
242      uploadBox.addEventListener(eventName, unhighlight, false);
243    });
244
245    function highlight() {
246      uploadBox.classList.add('border-green-400', 'bg-green-50');
247    }
248
249    function unhighlight() {
250      uploadBox.classList.remove('border-green-400', 'bg-green-50');
251    }
252
253    uploadBox.addEventListener('drop', handleDrop, false);
254
255    function handleDrop(e) {
256      const dt = e.dataTransfer;
257      const files = dt.files;
258      if (files.length) {
259        document.getElementById('upload').files = files;
260        mostrarImagem({target: {files: files}});
261      }
262    }
263  </script>
264</body>
265</html>
266