Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
@@ -1,15 +1,24 @@
|
|
1 |
import gradio as gr
|
2 |
-
from transformers import AutoProcessor,
|
3 |
-
from PIL import Image
|
4 |
import torch
|
5 |
-
import
|
6 |
import pandas as pd
|
|
|
7 |
|
8 |
-
# Carregar o modelo e processador
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
-
# Base de dados nutricional
|
13 |
NUTRITIONAL_DB = {
|
14 |
"arroz": {
|
15 |
"calorias": 130,
|
@@ -17,6 +26,9 @@ NUTRITIONAL_DB = {
|
|
17 |
"carboidratos": 28,
|
18 |
"gorduras": 0.3,
|
19 |
"fibras": 0.4,
|
|
|
|
|
|
|
20 |
},
|
21 |
"feijão": {
|
22 |
"calorias": 77,
|
@@ -24,71 +36,188 @@ NUTRITIONAL_DB = {
|
|
24 |
"carboidratos": 13.6,
|
25 |
"gorduras": 0.5,
|
26 |
"fibras": 5.4,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
},
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
-
def
|
32 |
"""
|
33 |
-
|
34 |
"""
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
"carboidratos": 0,
|
51 |
-
"gorduras": 0,
|
52 |
-
"fibras": 0,
|
53 |
-
}
|
54 |
-
|
55 |
-
report = "🍽️ Relatório Nutricional\n\n"
|
56 |
-
report += "Alimentos identificados:\n"
|
57 |
-
|
58 |
-
for food in food_list:
|
59 |
-
if food in NUTRITIONAL_DB:
|
60 |
-
report += f"- {food.capitalize()}\n"
|
61 |
-
for nutrient, value in NUTRITIONAL_DB[food].items():
|
62 |
-
total_nutrients[nutrient] += value
|
63 |
-
|
64 |
-
report += "\n📊 Informação Nutricional Total:\n"
|
65 |
-
report += f"Calorias: {total_nutrients['calorias']:.1f} kcal\n"
|
66 |
-
report += f"Proteínas: {total_nutrients['proteinas']:.1f}g\n"
|
67 |
-
report += f"Carboidratos: {total_nutrients['carboidratos']:.1f}g\n"
|
68 |
-
report += f"Gorduras: {total_nutrients['gorduras']:.1f}g\n"
|
69 |
-
report += f"Fibras: {total_nutrients['fibras']:.1f}g\n"
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
79 |
|
80 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
# Interface Gradio
|
83 |
iface = gr.Interface(
|
84 |
fn=analyze_food,
|
85 |
-
inputs=gr.Image(type="pil"),
|
86 |
-
outputs=gr.Textbox(label="Relatório Nutricional", lines=
|
87 |
-
title="Análise Nutricional
|
88 |
-
description="
|
89 |
-
|
|
|
|
|
|
|
90 |
theme=gr.themes.Soft()
|
91 |
)
|
92 |
|
93 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
94 |
iface.launch(share=True)
|
|
|
1 |
import gradio as gr
|
2 |
+
from transformers import AutoProcessor, AutoModelForCausalLM
|
|
|
3 |
import torch
|
4 |
+
from PIL import Image
|
5 |
import pandas as pd
|
6 |
+
import json
|
7 |
|
8 |
+
# Carregar o modelo e processador CogVLM (mais adequado para análise de imagens)
|
9 |
+
model_name = "THUDM/cogvlm-chat-hf"
|
10 |
+
model = AutoModelForCausalLM.from_pretrained(
|
11 |
+
model_name,
|
12 |
+
torch_dtype=torch.float16,
|
13 |
+
device_map="auto",
|
14 |
+
trust_remote_code=True
|
15 |
+
)
|
16 |
+
processor = AutoProcessor.from_pretrained(
|
17 |
+
model_name,
|
18 |
+
trust_remote_code=True
|
19 |
+
)
|
20 |
|
21 |
+
# Base de dados nutricional expandida
|
22 |
NUTRITIONAL_DB = {
|
23 |
"arroz": {
|
24 |
"calorias": 130,
|
|
|
26 |
"carboidratos": 28,
|
27 |
"gorduras": 0.3,
|
28 |
"fibras": 0.4,
|
29 |
+
"vitamina_b1": 0.02,
|
30 |
+
"vitamina_b3": 0.4,
|
31 |
+
"ferro": 0.2,
|
32 |
},
|
33 |
"feijão": {
|
34 |
"calorias": 77,
|
|
|
36 |
"carboidratos": 13.6,
|
37 |
"gorduras": 0.5,
|
38 |
"fibras": 5.4,
|
39 |
+
"ferro": 1.5,
|
40 |
+
"potássio": 255,
|
41 |
+
"magnésio": 42,
|
42 |
+
},
|
43 |
+
"frango grelhado": {
|
44 |
+
"calorias": 165,
|
45 |
+
"proteinas": 31,
|
46 |
+
"carboidratos": 0,
|
47 |
+
"gorduras": 3.6,
|
48 |
+
"vitamina_b6": 0.5,
|
49 |
+
"niacina": 13.7,
|
50 |
+
"fósforo": 200,
|
51 |
},
|
52 |
+
"salada de alface": {
|
53 |
+
"calorias": 15,
|
54 |
+
"proteinas": 1.4,
|
55 |
+
"carboidratos": 2.9,
|
56 |
+
"gorduras": 0.2,
|
57 |
+
"fibras": 1.3,
|
58 |
+
"vitamina_a": 370,
|
59 |
+
"vitamina_k": 126,
|
60 |
+
"folato": 38,
|
61 |
+
}
|
62 |
}
|
63 |
|
64 |
+
def generate_food_prompt(image):
|
65 |
"""
|
66 |
+
Gera um prompt específico para análise de alimentos
|
67 |
"""
|
68 |
+
return (
|
69 |
+
"Analise detalhadamente esta imagem e liste todos os alimentos visíveis. "
|
70 |
+
"Para cada alimento, forneça: \n"
|
71 |
+
"1. Nome do alimento\n"
|
72 |
+
"2. Quantidade aproximada em gramas ou porções\n"
|
73 |
+
"3. Estado (cru, cozido, grelhado, etc.)\n"
|
74 |
+
"Formate a resposta em uma lista clara."
|
75 |
+
)
|
76 |
+
|
77 |
+
def process_model_response(response):
|
78 |
+
"""
|
79 |
+
Processa a resposta do modelo para extrair informações estruturadas
|
80 |
+
"""
|
81 |
+
foods = []
|
82 |
+
current_lines = response.split('\n')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
84 |
+
for line in current_lines:
|
85 |
+
line = line.lower().strip()
|
86 |
+
for food in NUTRITIONAL_DB.keys():
|
87 |
+
if food in line:
|
88 |
+
# Tenta extrair quantidade (assume padrão se não encontrar)
|
89 |
+
qty = 100 # quantidade padrão em gramas
|
90 |
+
if 'g' in line:
|
91 |
+
try:
|
92 |
+
qty = int(''.join(filter(str.isdigit, line.split('g')[0])))
|
93 |
+
except:
|
94 |
+
pass
|
95 |
+
foods.append((food, qty))
|
96 |
|
97 |
+
return foods
|
98 |
+
|
99 |
+
def analyze_food(image):
|
100 |
+
"""
|
101 |
+
Analisa a imagem do alimento e retorna um relatório nutricional detalhado
|
102 |
+
"""
|
103 |
+
try:
|
104 |
+
# Preparar a imagem e gerar o prompt
|
105 |
+
prompt = generate_food_prompt(image)
|
106 |
+
inputs = processor(images=image, text=prompt, return_tensors="pt").to(model.device)
|
107 |
+
|
108 |
+
# Gerar análise
|
109 |
+
with torch.no_grad():
|
110 |
+
outputs = model.generate(
|
111 |
+
**inputs,
|
112 |
+
max_new_tokens=500,
|
113 |
+
do_sample=True,
|
114 |
+
temperature=0.7,
|
115 |
+
top_p=0.9,
|
116 |
+
)
|
117 |
+
|
118 |
+
response = processor.decode(outputs[0], skip_special_tokens=True)
|
119 |
+
foods = process_model_response(response)
|
120 |
+
|
121 |
+
# Gerar relatório nutricional
|
122 |
+
report = "🍽️ RELATÓRIO NUTRICIONAL DETALHADO\n\n"
|
123 |
+
report += "📝 Alimentos Identificados:\n"
|
124 |
+
|
125 |
+
total_nutrients = {
|
126 |
+
"calorias": 0,
|
127 |
+
"proteinas": 0,
|
128 |
+
"carboidratos": 0,
|
129 |
+
"gorduras": 0,
|
130 |
+
"fibras": 0,
|
131 |
+
}
|
132 |
+
|
133 |
+
vitamins_minerals = {}
|
134 |
+
|
135 |
+
for food, quantity in foods:
|
136 |
+
multiplier = quantity / 100 # Ajusta para a quantidade real
|
137 |
+
report += f"\n• {food.capitalize()} ({quantity}g)\n"
|
138 |
+
|
139 |
+
if food in NUTRITIONAL_DB:
|
140 |
+
for nutrient, value in NUTRITIONAL_DB[food].items():
|
141 |
+
adjusted_value = value * multiplier
|
142 |
+
|
143 |
+
# Adiciona aos totais principais
|
144 |
+
if nutrient in total_nutrients:
|
145 |
+
total_nutrients[nutrient] += adjusted_value
|
146 |
+
# Coleta vitaminas e minerais
|
147 |
+
elif nutrient not in ['calorias', 'proteinas', 'carboidratos', 'gorduras', 'fibras']:
|
148 |
+
if nutrient not in vitamins_minerals:
|
149 |
+
vitamins_minerals[nutrient] = 0
|
150 |
+
vitamins_minerals[nutrient] += adjusted_value
|
151 |
+
|
152 |
+
# Adiciona seção de macronutrientes
|
153 |
+
report += "\n📊 MACRONUTRIENTES:\n"
|
154 |
+
report += f"• Calorias: {total_nutrients['calorias']:.1f} kcal\n"
|
155 |
+
report += f"• Proteínas: {total_nutrients['proteinas']:.1f}g\n"
|
156 |
+
report += f"• Carboidratos: {total_nutrients['carboidratos']:.1f}g\n"
|
157 |
+
report += f"• Gorduras: {total_nutrients['gorduras']:.1f}g\n"
|
158 |
+
report += f"• Fibras: {total_nutrients['fibras']:.1f}g\n"
|
159 |
+
|
160 |
+
# Adiciona seção de micronutrientes
|
161 |
+
if vitamins_minerals:
|
162 |
+
report += "\n🧬 VITAMINAS E MINERAIS:\n"
|
163 |
+
for nutrient, value in vitamins_minerals.items():
|
164 |
+
report += f"• {nutrient.replace('_', ' ').capitalize()}: {value:.1f}mg\n"
|
165 |
+
|
166 |
+
# Adiciona recomendações personalizadas
|
167 |
+
report += "\n💡 RECOMENDAÇÕES:\n"
|
168 |
+
|
169 |
+
# Análise de macronutrientes
|
170 |
+
if total_nutrients['calorias'] > 800:
|
171 |
+
report += "• Alto valor calórico - considere reduzir as porções\n"
|
172 |
+
if total_nutrients['proteinas'] < 15:
|
173 |
+
report += "• Baixo teor de proteínas - considere adicionar fontes proteicas\n"
|
174 |
+
if total_nutrients['fibras'] < 6:
|
175 |
+
report += "• Baixo teor de fibras - adicione mais vegetais e grãos integrais\n"
|
176 |
+
|
177 |
+
# Análise de proporções
|
178 |
+
protein_cal = (total_nutrients['proteinas'] * 4)
|
179 |
+
carb_cal = (total_nutrients['carboidratos'] * 4)
|
180 |
+
fat_cal = (total_nutrients['gorduras'] * 9)
|
181 |
+
total_cal = protein_cal + carb_cal + fat_cal
|
182 |
+
|
183 |
+
if total_cal > 0:
|
184 |
+
protein_pct = (protein_cal / total_cal) * 100
|
185 |
+
carb_pct = (carb_cal / total_cal) * 100
|
186 |
+
fat_pct = (fat_cal / total_cal) * 100
|
187 |
+
|
188 |
+
report += f"\n📈 DISTRIBUIÇÃO CALÓRICA:\n"
|
189 |
+
report += f"• Proteínas: {protein_pct:.1f}%\n"
|
190 |
+
report += f"• Carboidratos: {carb_pct:.1f}%\n"
|
191 |
+
report += f"• Gorduras: {fat_pct:.1f}%\n"
|
192 |
+
|
193 |
+
if protein_pct < 10:
|
194 |
+
report += "\n⚠️ Proporção de proteínas abaixo do recomendado\n"
|
195 |
+
if fat_pct > 35:
|
196 |
+
report += "⚠️ Proporção de gorduras acima do recomendado\n"
|
197 |
+
|
198 |
+
return report
|
199 |
+
|
200 |
+
except Exception as e:
|
201 |
+
return f"Erro na análise: {str(e)}\nPor favor, tente novamente com outra imagem."
|
202 |
|
203 |
# Interface Gradio
|
204 |
iface = gr.Interface(
|
205 |
fn=analyze_food,
|
206 |
+
inputs=gr.Image(type="pil", label="Upload da Imagem do Prato"),
|
207 |
+
outputs=gr.Textbox(label="Relatório Nutricional", lines=20),
|
208 |
+
title="🍽️ Análise Nutricional com IA",
|
209 |
+
description="""
|
210 |
+
Faça upload de uma foto do seu prato para receber uma análise nutricional detalhada.
|
211 |
+
O sistema identificará os alimentos e fornecerá informações nutricionais completas.
|
212 |
+
""",
|
213 |
+
|
214 |
theme=gr.themes.Soft()
|
215 |
)
|
216 |
|
217 |
if __name__ == "__main__":
|
218 |
+
# Configuração para usar GPU se disponível
|
219 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
220 |
+
print(f"Using device: {device}")
|
221 |
+
|
222 |
+
# Iniciar a interface
|
223 |
iface.launch(share=True)
|