Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
@@ -3,6 +3,7 @@ import torch
|
|
3 |
from transformers import AutoModel, AutoProcessor
|
4 |
import pandas as pd
|
5 |
from PIL import Image
|
|
|
6 |
|
7 |
# Carrega o modelo
|
8 |
model = AutoModel.from_pretrained("openbmb/MiniCPM-o-2_6", trust_remote_code=True)
|
@@ -14,7 +15,10 @@ NUTRITION_DB = {
|
|
14 |
"feijão": {"calorias": 77, "proteinas": 5.2, "carboidratos": 13.6, "gorduras": 0.5},
|
15 |
"carne": {"calorias": 250, "proteinas": 26, "carboidratos": 0, "gorduras": 17},
|
16 |
"batata frita": {"calorias": 312, "proteinas": 3.4, "carboidratos": 41, "gorduras": 15},
|
17 |
-
"salada": {"calorias": 15, "proteinas": 1.4, "carboidratos": 2.9, "gorduras": 0.2}
|
|
|
|
|
|
|
18 |
}
|
19 |
|
20 |
def process_image(image, progress=gr.Progress()):
|
@@ -25,13 +29,25 @@ def process_image(image, progress=gr.Progress()):
|
|
25 |
# Prepara a imagem
|
26 |
if isinstance(image, str):
|
27 |
image = Image.open(image)
|
|
|
|
|
28 |
|
29 |
# Processa a imagem com o modelo
|
30 |
-
inputs = processor(
|
|
|
|
|
|
|
|
|
31 |
|
32 |
progress(0.6, desc="Analisando conteúdo...")
|
33 |
# Gera a descrição
|
34 |
-
outputs = model.generate(
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
description = processor.decode(outputs[0], skip_special_tokens=True)
|
36 |
|
37 |
progress(1.0, desc="Concluído!")
|
@@ -57,7 +73,38 @@ def analyze_nutrition(foods_list):
|
|
57 |
for nutrient, value in NUTRITION_DB[food].items():
|
58 |
total_nutrients[nutrient] += value
|
59 |
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
def analyze_image(image):
|
63 |
"""Função principal de análise"""
|
@@ -66,7 +113,10 @@ def analyze_image(image):
|
|
66 |
description = process_image(image)
|
67 |
|
68 |
# Analisa nutrientes
|
69 |
-
total_nutrients, found_foods = analyze_nutrition(description)
|
|
|
|
|
|
|
70 |
|
71 |
# Prepara dados para visualização
|
72 |
table_data = [
|
@@ -87,22 +137,20 @@ def analyze_image(image):
|
|
87 |
})
|
88 |
|
89 |
# Monta o relatório
|
90 |
-
analysis = f"""### 🔍 Análise da Imagem
|
91 |
{description}
|
92 |
|
93 |
-
### 🍽️ Alimentos Identificados
|
94 |
{', '.join(found_foods)}
|
95 |
|
96 |
-
### 📊 Informação Nutricional
|
97 |
-
• Calorias: {total_nutrients['calorias']:.1f} kcal
|
98 |
-
• Proteínas: {total_nutrients['proteinas']:.1f}g
|
99 |
-
• Carboidratos: {total_nutrients['carboidratos']:.1f}g
|
100 |
-
• Gorduras: {total_nutrients['gorduras']:.1f}g
|
101 |
|
102 |
-
### 💡 Recomendações
|
103 |
-
{
|
104 |
-
{"⚠️ Considere reduzir carboidratos" if total_nutrients['carboidratos'] > 60 else "✅ Carboidratos adequados"}
|
105 |
-
{"⚠️ Alto teor de gorduras" if total_nutrients['gorduras'] > 20 else "✅ Gorduras adequadas"}
|
106 |
"""
|
107 |
|
108 |
return analysis, table_data, plot_data
|
@@ -110,20 +158,145 @@ def analyze_image(image):
|
|
110 |
except Exception as e:
|
111 |
return str(e), None, None
|
112 |
|
113 |
-
#
|
114 |
-
|
115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
with gr.Row():
|
118 |
with gr.Column():
|
|
|
119 |
image_input = gr.Image(
|
120 |
type="pil",
|
121 |
-
label="
|
122 |
sources=["upload", "webcam"]
|
123 |
)
|
124 |
-
analyze_btn = gr.Button("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
-
with gr.Column():
|
|
|
127 |
output_text = gr.Markdown()
|
128 |
|
129 |
with gr.Row():
|
@@ -139,6 +312,27 @@ with gr.Blocks(theme=gr.themes.Soft()) as iface:
|
|
139 |
height=300
|
140 |
)
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
analyze_btn.click(
|
143 |
fn=analyze_image,
|
144 |
inputs=[image_input],
|
|
|
3 |
from transformers import AutoModel, AutoProcessor
|
4 |
import pandas as pd
|
5 |
from PIL import Image
|
6 |
+
import numpy as np
|
7 |
|
8 |
# Carrega o modelo
|
9 |
model = AutoModel.from_pretrained("openbmb/MiniCPM-o-2_6", trust_remote_code=True)
|
|
|
15 |
"feijão": {"calorias": 77, "proteinas": 5.2, "carboidratos": 13.6, "gorduras": 0.5},
|
16 |
"carne": {"calorias": 250, "proteinas": 26, "carboidratos": 0, "gorduras": 17},
|
17 |
"batata frita": {"calorias": 312, "proteinas": 3.4, "carboidratos": 41, "gorduras": 15},
|
18 |
+
"salada": {"calorias": 15, "proteinas": 1.4, "carboidratos": 2.9, "gorduras": 0.2},
|
19 |
+
"ovo": {"calorias": 155, "proteinas": 13, "carboidratos": 1.1, "gorduras": 11},
|
20 |
+
"peixe": {"calorias": 206, "proteinas": 22, "carboidratos": 0, "gorduras": 12},
|
21 |
+
"macarrão": {"calorias": 158, "proteinas": 5.8, "carboidratos": 31, "gorduras": 1.2}
|
22 |
}
|
23 |
|
24 |
def process_image(image, progress=gr.Progress()):
|
|
|
29 |
# Prepara a imagem
|
30 |
if isinstance(image, str):
|
31 |
image = Image.open(image)
|
32 |
+
elif isinstance(image, np.ndarray):
|
33 |
+
image = Image.fromarray(image)
|
34 |
|
35 |
# Processa a imagem com o modelo
|
36 |
+
inputs = processor(
|
37 |
+
images=image,
|
38 |
+
text="List all foods present in this image, including their preparation method if visible.",
|
39 |
+
return_tensors="pt"
|
40 |
+
)
|
41 |
|
42 |
progress(0.6, desc="Analisando conteúdo...")
|
43 |
# Gera a descrição
|
44 |
+
outputs = model.generate(
|
45 |
+
**inputs,
|
46 |
+
max_new_tokens=100,
|
47 |
+
num_beams=5,
|
48 |
+
temperature=0.7,
|
49 |
+
top_p=0.9
|
50 |
+
)
|
51 |
description = processor.decode(outputs[0], skip_special_tokens=True)
|
52 |
|
53 |
progress(1.0, desc="Concluído!")
|
|
|
73 |
for nutrient, value in NUTRITION_DB[food].items():
|
74 |
total_nutrients[nutrient] += value
|
75 |
|
76 |
+
# Calcula proporções de macronutrientes
|
77 |
+
total_cal = total_nutrients['calorias']
|
78 |
+
if total_cal > 0:
|
79 |
+
protein_pct = (total_nutrients['proteinas'] * 4 / total_cal) * 100
|
80 |
+
carb_pct = (total_nutrients['carboidratos'] * 4 / total_cal) * 100
|
81 |
+
fat_pct = (total_nutrients['gorduras'] * 9 / total_cal) * 100
|
82 |
+
else:
|
83 |
+
protein_pct = carb_pct = fat_pct = 0
|
84 |
+
|
85 |
+
return total_nutrients, found_foods, (protein_pct, carb_pct, fat_pct)
|
86 |
+
|
87 |
+
def get_recommendations(nutrients, percentages):
|
88 |
+
"""Gera recomendações baseadas nos valores nutricionais"""
|
89 |
+
protein_pct, carb_pct, fat_pct = percentages
|
90 |
+
recommendations = []
|
91 |
+
|
92 |
+
if nutrients['calorias'] > 800:
|
93 |
+
recommendations.append("⚠️ Valor calórico elevado - considere reduzir as porções")
|
94 |
+
|
95 |
+
if protein_pct < 15:
|
96 |
+
recommendations.append("⚠️ Baixo teor de proteínas - adicione mais fontes proteicas")
|
97 |
+
|
98 |
+
if carb_pct > 60:
|
99 |
+
recommendations.append("⚠️ Alto teor de carboidratos - considere reduzir")
|
100 |
+
|
101 |
+
if fat_pct > 30:
|
102 |
+
recommendations.append("⚠️ Alto teor de gorduras - opte por preparações mais leves")
|
103 |
+
|
104 |
+
if not recommendations:
|
105 |
+
recommendations.append("✅ Refeição bem balanceada! Continue assim!")
|
106 |
+
|
107 |
+
return recommendations
|
108 |
|
109 |
def analyze_image(image):
|
110 |
"""Função principal de análise"""
|
|
|
113 |
description = process_image(image)
|
114 |
|
115 |
# Analisa nutrientes
|
116 |
+
total_nutrients, found_foods, percentages = analyze_nutrition(description)
|
117 |
+
|
118 |
+
# Gera recomendações
|
119 |
+
recommendations = get_recommendations(total_nutrients, percentages)
|
120 |
|
121 |
# Prepara dados para visualização
|
122 |
table_data = [
|
|
|
137 |
})
|
138 |
|
139 |
# Monta o relatório
|
140 |
+
analysis = f"""### 🔍 Análise da Imagem
|
141 |
{description}
|
142 |
|
143 |
+
### 🍽️ Alimentos Identificados
|
144 |
{', '.join(found_foods)}
|
145 |
|
146 |
+
### 📊 Informação Nutricional
|
147 |
+
• Calorias Totais: {total_nutrients['calorias']:.1f} kcal
|
148 |
+
• Proteínas: {total_nutrients['proteinas']:.1f}g ({percentages[0]:.1f}%)
|
149 |
+
• Carboidratos: {total_nutrients['carboidratos']:.1f}g ({percentages[1]:.1f}%)
|
150 |
+
• Gorduras: {total_nutrients['gorduras']:.1f}g ({percentages[2]:.1f}%)
|
151 |
|
152 |
+
### 💡 Recomendações
|
153 |
+
{chr(10).join(recommendations)}
|
|
|
|
|
154 |
"""
|
155 |
|
156 |
return analysis, table_data, plot_data
|
|
|
158 |
except Exception as e:
|
159 |
return str(e), None, None
|
160 |
|
161 |
+
# CSS personalizado para marketing
|
162 |
+
css = """
|
163 |
+
.marketing-header {
|
164 |
+
text-align: center;
|
165 |
+
margin-bottom: 2rem;
|
166 |
+
background: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
|
167 |
+
padding: 2rem;
|
168 |
+
border-radius: 1rem;
|
169 |
+
color: white;
|
170 |
+
text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
171 |
+
}
|
172 |
+
|
173 |
+
.features {
|
174 |
+
display: grid;
|
175 |
+
grid-template-columns: repeat(3, 1fr);
|
176 |
+
gap: 1rem;
|
177 |
+
margin: 2rem 0;
|
178 |
+
}
|
179 |
+
|
180 |
+
.feature-card {
|
181 |
+
background: white;
|
182 |
+
padding: 1.5rem;
|
183 |
+
border-radius: 0.5rem;
|
184 |
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
185 |
+
text-align: center;
|
186 |
+
}
|
187 |
+
|
188 |
+
.benefits {
|
189 |
+
background: #f8f9fa;
|
190 |
+
padding: 1.5rem;
|
191 |
+
border-radius: 0.5rem;
|
192 |
+
margin: 1rem 0;
|
193 |
+
}
|
194 |
+
|
195 |
+
.testimonial {
|
196 |
+
font-style: italic;
|
197 |
+
color: #666;
|
198 |
+
background: #fff;
|
199 |
+
padding: 1rem;
|
200 |
+
border-left: 4px solid #84fab0;
|
201 |
+
margin: 1rem 0;
|
202 |
+
}
|
203 |
+
|
204 |
+
.cta-button {
|
205 |
+
background: linear-gradient(45deg, #84fab0, #8fd3f4);
|
206 |
+
padding: 1rem 2rem;
|
207 |
+
border: none;
|
208 |
+
border-radius: 2rem;
|
209 |
+
color: white;
|
210 |
+
font-weight: bold;
|
211 |
+
cursor: pointer;
|
212 |
+
transition: all 0.3s ease;
|
213 |
+
}
|
214 |
+
|
215 |
+
.cta-button:hover {
|
216 |
+
transform: translateY(-2px);
|
217 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
218 |
+
}
|
219 |
+
|
220 |
+
.results-container {
|
221 |
+
background: white;
|
222 |
+
padding: 1.5rem;
|
223 |
+
border-radius: 0.5rem;
|
224 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
225 |
+
}
|
226 |
+
"""
|
227 |
+
|
228 |
+
# Interface Gradio com Marketing
|
229 |
+
with gr.Blocks(theme=gr.themes.Soft(), css=css) as iface:
|
230 |
+
with gr.Row(elem_classes="marketing-header"):
|
231 |
+
gr.Markdown("""
|
232 |
+
# 🍽️ NutriAI - Sua Análise Nutricional Inteligente
|
233 |
+
|
234 |
+
### Transforme sua alimentação com o poder da Inteligência Artificial
|
235 |
+
Análise nutricional precisa e personalizada em segundos!
|
236 |
+
""")
|
237 |
+
|
238 |
+
with gr.Row(elem_classes="features"):
|
239 |
+
with gr.Column(elem_classes="feature-card"):
|
240 |
+
gr.Markdown("""
|
241 |
+
### 🎯 Análise Precisa
|
242 |
+
- Reconhecimento avançado de alimentos
|
243 |
+
- Cálculo nutricional detalhado
|
244 |
+
- Tecnologia de ponta
|
245 |
+
""")
|
246 |
+
|
247 |
+
with gr.Column(elem_classes="feature-card"):
|
248 |
+
gr.Markdown("""
|
249 |
+
### ⚡ Resultados Instantâneos
|
250 |
+
- Análise em segundos
|
251 |
+
- Relatório completo
|
252 |
+
- Recomendações personalizadas
|
253 |
+
""")
|
254 |
+
|
255 |
+
with gr.Column(elem_classes="feature-card"):
|
256 |
+
gr.Markdown("""
|
257 |
+
### 💡 Inteligência Artificial
|
258 |
+
- Modelo MiniCPM avançado
|
259 |
+
- Aprendizado contínuo
|
260 |
+
- Alta precisão
|
261 |
+
""")
|
262 |
+
|
263 |
+
with gr.Row(elem_classes="benefits"):
|
264 |
+
gr.Markdown("""
|
265 |
+
### 🌟 Benefícios
|
266 |
+
|
267 |
+
✓ **Controle sua alimentação** de forma inteligente
|
268 |
+
✓ **Monitore nutrientes** essenciais
|
269 |
+
✓ **Receba dicas** personalizadas
|
270 |
+
✓ **Economize tempo** na contagem de calorias
|
271 |
+
✓ **Melhore seus hábitos** alimentares
|
272 |
+
""")
|
273 |
|
274 |
with gr.Row():
|
275 |
with gr.Column():
|
276 |
+
gr.Markdown("## 📸 Analise seu Prato")
|
277 |
image_input = gr.Image(
|
278 |
type="pil",
|
279 |
+
label="Faça upload ou tire uma foto do seu prato",
|
280 |
sources=["upload", "webcam"]
|
281 |
)
|
282 |
+
analyze_btn = gr.Button("🔍 Analisar Agora", variant="primary", size="lg", elem_classes="cta-button")
|
283 |
+
|
284 |
+
with gr.Accordion("📝 Guia de Uso", open=False):
|
285 |
+
gr.Markdown("""
|
286 |
+
### Como obter os melhores resultados:
|
287 |
+
1. Use fotos bem iluminadas
|
288 |
+
2. Fotografe de cima para baixo
|
289 |
+
3. Mantenha todos os alimentos visíveis
|
290 |
+
4. Evite sombras ou reflexos
|
291 |
+
|
292 |
+
### Por que usar o NutriAI?
|
293 |
+
- Análise nutricional profissional
|
294 |
+
- Recomendações baseadas em ciência
|
295 |
+
- Interface intuitiva e fácil de usar
|
296 |
+
""")
|
297 |
|
298 |
+
with gr.Column(elem_classes="results-container"):
|
299 |
+
gr.Markdown("### Resultados da Análise")
|
300 |
output_text = gr.Markdown()
|
301 |
|
302 |
with gr.Row():
|
|
|
312 |
height=300
|
313 |
)
|
314 |
|
315 |
+
with gr.Row(elem_classes="testimonial"):
|
316 |
+
gr.Markdown("""
|
317 |
+
> "O NutriAI revolucionou minha forma de me alimentar. Agora consigo entender exatamente o que estou comendo e fazer escolhas mais saudáveis."
|
318 |
+
>
|
319 |
+
> *— Maria S., Nutricionista*
|
320 |
+
""")
|
321 |
+
|
322 |
+
gr.Markdown("""
|
323 |
+
### 🔒 Sua privacidade é importante
|
324 |
+
- Análise segura e privada
|
325 |
+
- Sem armazenamento de dados pessoais
|
326 |
+
- Tecnologia de ponta em segurança
|
327 |
+
|
328 |
+
### 📱 Disponível em qualquer dispositivo
|
329 |
+
Acesse pelo celular, tablet ou computador - em qualquer lugar, a qualquer momento!
|
330 |
+
|
331 |
+
### 🤝 Suporte ao cliente
|
332 |
+
Precisa de ajuda? Entre em contato com nossa equipe de suporte!
|
333 |
+
""")
|
334 |
+
|
335 |
+
# Eventos
|
336 |
analyze_btn.click(
|
337 |
fn=analyze_image,
|
338 |
inputs=[image_input],
|