DHEIVER commited on
Commit
30e029e
·
verified ·
1 Parent(s): 58996b4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -230
app.py CHANGED
@@ -1,267 +1,168 @@
1
  import gradio as gr
2
- import numpy as np
3
- import os
4
- from dotenv import load_dotenv
5
- import pandas as pd
6
- from transformers import Blip2Processor, Blip2ForConditionalGeneration
7
  import torch
8
- import time
9
-
10
- # Carrega variáveis de ambiente
11
- load_dotenv()
12
- API_KEY = os.getenv('NUTRITION_API_KEY', '')
13
 
14
- # Carrega o modelo BLIP2
15
- model_name = "Salesforce/blip2-opt-2.7b"
16
- processor = Blip2Processor.from_pretrained(model_name)
17
- model = Blip2ForConditionalGeneration.from_pretrained(model_name, torch_dtype=torch.float16, device_map="auto")
 
 
 
 
18
 
19
- def identify_foods(image):
20
- """Identifica alimentos na imagem usando BLIP2"""
21
- prompt = "Liste todos os alimentos visíveis nesta imagem de refeição."
22
- inputs = processor(image, text=prompt, return_tensors="pt").to(model.device)
23
-
24
- outputs = model.generate(
25
- **inputs,
26
- max_new_tokens=100,
27
- do_sample=False,
28
- num_beams=5,
29
- temperature=1.0,
30
- top_p=0.9,
31
- )
32
-
33
- return processor.decode(outputs[0], skip_special_tokens=True)
34
 
35
- def analyze_nutrition(image, progress=gr.Progress()):
36
- """Análise nutricional da imagem"""
37
  try:
38
- # Status inicial
39
- progress(0, desc="Iniciando análise...")
40
- yield "Iniciando análise...", None, None, None, None, "processing"
41
- time.sleep(1) # Simula processamento
42
 
43
- # Identificação dos alimentos
44
- progress(0.2, desc="Identificando alimentos...")
45
- identified_foods = identify_foods(image)
46
- yield f"🔄 Identificando alimentos...\n\n{identified_foods}", None, None, None, None, "processing"
47
- time.sleep(1)
 
 
 
48
 
49
- # Análise nutricional
50
- progress(0.4, desc="Calculando valores nutricionais...")
51
- nutrients = {
52
- "calorias": 450,
53
- "proteinas": 25,
54
- "carboidratos": 55,
55
- "gorduras": 15,
56
- "fibras": 8
57
- }
58
 
59
- # Dados do gráfico
60
- plot_data = pd.DataFrame({
61
- 'Nutriente': ['Proteínas', 'Carboidratos', 'Gorduras'],
62
- 'Quantidade': [nutrients['proteinas'], nutrients['carboidratos'], nutrients['gorduras']]
63
- })
 
 
 
 
 
 
 
64
 
65
- # Tabela nutricional
66
- table_data = [
67
- ["Calorias", f"{nutrients['calorias']:.1f} kcal"],
68
- ["Proteínas", f"{nutrients['proteinas']:.1f}g"],
69
- ["Carboidratos", f"{nutrients['carboidratos']:.1f}g"],
70
- ["Gorduras", f"{nutrients['gorduras']:.1f}g"],
71
- ["Fibras", f"{nutrients['fibras']:.1f}g"]
72
- ]
73
 
74
- progress(0.6, desc="Gerando análise...")
75
- yield (
76
- f"🔄 Gerando análise...\n\n{identified_foods}",
77
- table_data,
78
- plot_data,
79
- "🔄 Analisando valores...",
80
- "🔄 Preparando recomendações...",
81
- "processing"
82
- )
83
- time.sleep(1)
84
 
85
- # Análise
86
- analysis = []
87
- if nutrients['calorias'] > 800:
88
- analysis.append("⚠️ Alto valor calórico")
89
- if nutrients['proteinas'] < 15:
90
- analysis.append("⚠️ Baixo teor de proteínas")
91
- if nutrients['fibras'] < 6:
92
- analysis.append("⚠️ Baixo teor de fibras")
93
 
94
- analysis_text = "\n".join(analysis) if analysis else "✅ Valores nutricionais adequados"
 
 
 
95
 
96
- progress(0.8, desc="Gerando recomendações...")
97
- # Recomendações
98
- recommendations = []
99
- if "Alto valor calórico" in analysis_text:
100
- recommendations.append(" Considere reduzir as porções")
101
- if "Baixo teor de proteínas" in analysis_text:
102
- recommendations.append("• Adicione mais fontes de proteína como frango, peixe ou leguminosas")
103
- if "Baixo teor de fibras" in analysis_text:
104
- recommendations.append("• Inclua mais vegetais e grãos integrais")
105
-
106
- recommendations_text = "\n".join(recommendations) if recommendations else "• Continue mantendo uma alimentação equilibrada!"
107
 
108
- progress(1.0, desc="Concluído!")
109
- # Resultado final
110
- yield (
111
- f"### 🍽️ Alimentos Identificados\n{identified_foods}",
112
- table_data,
113
- plot_data,
114
- f"### 📊 Análise\n{analysis_text}",
115
- f"### 💡 Recomendações\n{recommendations_text}",
116
- "success"
117
- )
118
 
119
- except Exception as e:
120
- yield (
121
- "❌ Erro na identificação",
122
- None,
123
- None,
124
- "❌ Erro na análise",
125
- f"Erro: {str(e)}",
126
- "error"
127
- )
128
 
129
- css = """
130
- .container { max-width: 1200px; margin: auto; padding: 20px; }
131
- .header { text-align: center; margin-bottom: 30px; }
132
- .result-box {
133
- border: 1px solid #ddd;
134
- border-radius: 8px;
135
- padding: 15px;
136
- margin: 10px 0;
137
- background-color: #fff;
138
- }
139
- .processing {
140
- display: flex;
141
- justify-content: center;
142
- align-items: center;
143
- padding: 20px;
144
- background: #f7f7f7;
145
- border-radius: 8px;
146
- margin: 10px 0;
147
- }
148
- .status-progress {
149
- padding: 10px;
150
- margin: 10px 0;
151
- border-radius: 4px;
152
- font-weight: bold;
153
- }
154
- .status-error { background: #fee; color: #c00; }
155
- .status-success { background: #efe; color: #0c0; }
156
- .status-processing { background: #eef; color: #00c; }
157
  """
 
 
 
 
 
 
158
 
159
  # Interface Gradio
160
- with gr.Blocks(theme=gr.themes.Soft(), css=css) as iface:
161
- # Cabeçalho
162
- with gr.Row(elem_classes="header"):
163
- gr.Markdown("""
164
- # 🍽️ Análise Nutricional com IA
165
- Faça upload da foto do seu prato para análise nutricional detalhada
166
- """)
167
 
168
- # Container Principal
169
  with gr.Row():
170
- # Coluna da Esquerda - Input
171
- with gr.Column(scale=2):
172
- gr.Markdown("### 📸 Foto do Prato")
173
  image_input = gr.Image(
174
  type="pil",
175
- sources=["upload", "webcam"],
176
- height=400,
177
- label=""
178
  )
179
- with gr.Row():
180
- analyze_btn = gr.Button("🔍 Analisar Prato", variant="primary", size="lg")
181
- clear_btn = gr.Button("🔄 Limpar", size="lg")
182
 
183
- with gr.Accordion("📝 Dicas", open=False):
184
- gr.Markdown("""
185
- - Use fotos bem iluminadas
186
- - Fotografe de cima para baixo
187
- - Certifique-se que todos os alimentos estão visíveis
188
- - Evite sombras ou reflexos fortes
189
- """)
190
-
191
- # Coluna da Direita - Resultados
192
- with gr.Column(scale=3):
193
- # Status
194
- status = gr.Markdown(elem_classes="status-progress", visible=False)
195
 
196
- with gr.Tabs() as tabs:
197
- # Tab de Identificação
198
- with gr.Tab("🔍 Identificação"):
199
- with gr.Group(elem_classes="result-box"):
200
- foods_detected = gr.Markdown()
201
-
202
- # Tab de Nutrientes
203
- with gr.Tab("📊 Nutrição"):
204
- with gr.Group(elem_classes="result-box"):
205
- nutri_table = gr.Dataframe(
206
- headers=["Nutriente", "Quantidade"],
207
- label="Informação Nutricional",
208
- wrap=True
209
- )
210
- macro_plot = gr.BarPlot(
211
- title="Distribuição de Macronutrientes (g)",
212
- x="Nutriente",
213
- y="Quantidade",
214
- height=300,
215
- tooltip=["Nutriente", "Quantidade"]
216
- )
217
 
218
- # Tab de Análise
219
- with gr.Tab("💡 Análise"):
220
- with gr.Group(elem_classes="result-box"):
221
- analysis_output = gr.Markdown()
222
- gr.Markdown("---")
223
- recommendations_output = gr.Markdown()
224
-
225
- # Event handlers
226
- def clear_outputs():
227
- return {
228
- foods_detected: None,
229
- nutri_table: None,
230
- macro_plot: None,
231
- analysis_output: None,
232
- recommendations_output: None,
233
- status: gr.Markdown(visible=False)
234
- }
235
 
 
236
  analyze_btn.click(
237
- fn=analyze_nutrition,
238
  inputs=[image_input],
239
  outputs=[
240
- foods_detected,
241
- nutri_table,
242
- macro_plot,
243
  analysis_output,
244
- recommendations_output,
245
- status
246
- ]
247
- )
248
-
249
- clear_btn.click(
250
- fn=clear_outputs,
251
- outputs=[
252
- foods_detected,
253
- nutri_table,
254
- macro_plot,
255
- analysis_output,
256
- recommendations_output,
257
- status
258
  ]
259
  )
260
 
261
- # Inicia a interface
262
  if __name__ == "__main__":
263
- if not API_KEY:
264
- print("⚠️ Atenção: API Key não encontrada!")
265
- print("Configure a variável de ambiente NUTRITION_API_KEY no arquivo .env")
266
-
267
- iface.launch(share=False)
 
1
  import gradio as gr
 
 
 
 
 
2
  import torch
3
+ from transformers import Blip2Processor, Blip2ForConditionalGeneration
4
+ import pandas as pd
5
+ from PIL import Image
6
+ import numpy as np
 
7
 
8
+ # Inicializa o modelo BLIP2
9
+ device = "cuda" if torch.cuda.is_available() else "cpu"
10
+ processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b")
11
+ model = Blip2ForConditionalGeneration.from_pretrained(
12
+ "Salesforce/blip2-opt-2.7b",
13
+ torch_dtype=torch.float16 if device == "cuda" else torch.float32,
14
+ device_map="auto"
15
+ )
16
 
17
+ # Base de dados nutricional
18
+ NUTRITION_DB = {
19
+ "arroz": {"calorias": 130, "proteinas": 2.7, "carboidratos": 28, "gorduras": 0.3},
20
+ "feijão": {"calorias": 77, "proteinas": 5.2, "carboidratos": 13.6, "gorduras": 0.5},
21
+ "frango": {"calorias": 165, "proteinas": 31, "carboidratos": 0, "gorduras": 3.6},
22
+ "salada": {"calorias": 15, "proteinas": 1.4, "carboidratos": 2.9, "gorduras": 0.2},
23
+ "batata": {"calorias": 93, "proteinas": 2.5, "carboidratos": 21, "gorduras": 0.1},
24
+ "carne": {"calorias": 250, "proteinas": 26, "carboidratos": 0, "gorduras": 17},
25
+ "peixe": {"calorias": 206, "proteinas": 22, "carboidratos": 0, "gorduras": 12},
26
+ "macarrão": {"calorias": 158, "proteinas": 5.8, "carboidratos": 31, "gorduras": 1.2},
27
+ "ovo": {"calorias": 155, "proteinas": 13, "carboidratos": 1.1, "gorduras": 11},
28
+ }
 
 
 
29
 
30
+ def analyze_image(image, progress=gr.Progress()):
31
+ """Analisa a imagem usando BLIP2 e retorna descrição dos alimentos"""
32
  try:
33
+ progress(0.2, desc="Processando imagem...")
 
 
 
34
 
35
+ # Garante que a imagem está no formato correto
36
+ if isinstance(image, str):
37
+ image = Image.open(image)
38
+ elif isinstance(image, np.ndarray):
39
+ image = Image.fromarray(image)
40
+
41
+ # Gera prompt específico para identificação de alimentos
42
+ prompt = "Identifique e liste todos os alimentos visíveis nesta imagem de refeição. Forneça uma lista detalhada."
43
 
44
+ progress(0.4, desc="Analisando alimentos...")
45
+ inputs = processor(image, text=prompt, return_tensors="pt").to(device)
 
 
 
 
 
 
 
46
 
47
+ progress(0.6, desc="Gerando descrição...")
48
+ with torch.no_grad():
49
+ outputs = model.generate(
50
+ **inputs,
51
+ max_new_tokens=100,
52
+ num_beams=5,
53
+ temperature=1.0,
54
+ top_p=0.9,
55
+ )
56
+
57
+ food_description = processor.decode(outputs[0], skip_special_tokens=True)
58
+ progress(0.8, desc="Calculando nutrientes...")
59
 
60
+ # Identifica alimentos conhecidos na descrição
61
+ found_foods = []
62
+ for food in NUTRITION_DB.keys():
63
+ if food in food_description.lower():
64
+ found_foods.append(food)
 
 
 
65
 
66
+ if not found_foods:
67
+ return None, None, None, "Não foi possível identificar alimentos conhecidos na imagem."
 
 
 
 
 
 
 
 
68
 
69
+ # Calcula nutrientes totais
70
+ total_nutrients = {
71
+ "calorias": 0,
72
+ "proteinas": 0,
73
+ "carboidratos": 0,
74
+ "gorduras": 0
75
+ }
 
76
 
77
+ # Soma nutrientes de cada alimento encontrado
78
+ for food in found_foods:
79
+ for nutrient, value in NUTRITION_DB[food].items():
80
+ total_nutrients[nutrient] += value
81
 
82
+ # Prepara dados para visualização
83
+ nutrients_table = [
84
+ ["Calorias", f"{total_nutrients['calorias']:.1f} kcal"],
85
+ ["Proteínas", f"{total_nutrients['proteinas']:.1f}g"],
86
+ ["Carboidratos", f"{total_nutrients['carboidratos']:.1f}g"],
87
+ ["Gorduras", f"{total_nutrients['gorduras']:.1f}g"]
88
+ ]
 
 
 
 
89
 
90
+ # Dados para o gráfico
91
+ plot_data = pd.DataFrame({
92
+ 'Nutriente': ['Proteínas', 'Carboidratos', 'Gorduras'],
93
+ 'Quantidade': [
94
+ total_nutrients['proteinas'],
95
+ total_nutrients['carboidratos'],
96
+ total_nutrients['gorduras']
97
+ ]
98
+ })
 
99
 
100
+ # Gera análise
101
+ analysis = f"""### Alimentos Identificados:
102
+ {food_description}
 
 
 
 
 
 
103
 
104
+ ### Alimentos na Base de Dados:
105
+ {', '.join(found_foods)}
106
+
107
+ ### Análise Nutricional:
108
+ - Valor Calórico: {total_nutrients['calorias']:.1f} kcal
109
+ - Proporção de Macronutrientes:
110
+ • Proteínas: {total_nutrients['proteinas']:.1f}g
111
+ • Carboidratos: {total_nutrients['carboidratos']:.1f}g
112
+ • Gorduras: {total_nutrients['gorduras']:.1f}g
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  """
114
+
115
+ progress(1.0, desc="Concluído!")
116
+ return analysis, nutrients_table, plot_data, None
117
+
118
+ except Exception as e:
119
+ return None, None, None, f"Erro na análise: {str(e)}"
120
 
121
  # Interface Gradio
122
+ with gr.Blocks(theme=gr.themes.Soft()) as iface:
123
+ gr.Markdown("# 🍽️ Análise Nutricional com IA")
 
 
 
 
 
124
 
 
125
  with gr.Row():
126
+ with gr.Column(scale=1):
127
+ # Input
 
128
  image_input = gr.Image(
129
  type="pil",
130
+ label="Foto do Prato",
131
+ sources=["upload", "webcam"]
 
132
  )
133
+ analyze_btn = gr.Button("Analisar", variant="primary")
 
 
134
 
135
+ with gr.Column(scale=2):
136
+ # Output
137
+ error_output = gr.Markdown(visible=False)
 
 
 
 
 
 
 
 
 
138
 
139
+ with gr.Tabs():
140
+ with gr.Tab("Análise"):
141
+ analysis_output = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
+ with gr.Tab("Nutrientes"):
144
+ nutrients_table = gr.Dataframe(
145
+ headers=["Nutriente", "Quantidade"],
146
+ label="Informação Nutricional"
147
+ )
148
+ nutrients_plot = gr.BarPlot(
149
+ x="Nutriente",
150
+ y="Quantidade",
151
+ title="Macronutrientes (g)",
152
+ height=300
153
+ )
 
 
 
 
 
 
154
 
155
+ # Eventos
156
  analyze_btn.click(
157
+ fn=analyze_image,
158
  inputs=[image_input],
159
  outputs=[
 
 
 
160
  analysis_output,
161
+ nutrients_table,
162
+ nutrients_plot,
163
+ error_output
 
 
 
 
 
 
 
 
 
 
 
164
  ]
165
  )
166
 
 
167
  if __name__ == "__main__":
168
+ iface.launch()