agroplan-ai-cli 1.0.26 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"cli_version": "1.0.
|
|
3
|
-
"backend_template_version": "1.0.
|
|
2
|
+
"cli_version": "1.0.27",
|
|
3
|
+
"backend_template_version": "1.0.27",
|
|
4
4
|
"zarc_index_version": "2025-2026-fast-index-v2",
|
|
5
5
|
"price_index_version": "2025-05-reference-v1",
|
|
6
6
|
"features": [
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"price_display_only",
|
|
15
15
|
"price_unit_normalization",
|
|
16
16
|
"market_profit_estimate",
|
|
17
|
-
"market_profit_validation"
|
|
17
|
+
"market_profit_validation",
|
|
18
|
+
"market_profit_confidence_refinement"
|
|
18
19
|
],
|
|
19
|
-
"generated_at": "2026-05-
|
|
20
|
+
"generated_at": "2026-05-09T23:00:00Z"
|
|
20
21
|
}
|
|
@@ -47,20 +47,27 @@ def classificar_confiabilidade_lucro(item: Dict) -> Dict:
|
|
|
47
47
|
"""
|
|
48
48
|
Classifica confiabilidade do lucro de mercado para um item do plano.
|
|
49
49
|
|
|
50
|
+
Critérios refinados (Fase 9.5):
|
|
51
|
+
- Baixa: diferença >= 150%, dados incompletos, lucro invertido, fallback com diferença >= 100%
|
|
52
|
+
- Média: diferença 50-150%, fallback, lucro negativo
|
|
53
|
+
- Alta: diferença < 50%, sem fallback, dados completos
|
|
54
|
+
|
|
50
55
|
Args:
|
|
51
56
|
item: Item do plano com dados de lucro
|
|
52
57
|
|
|
53
58
|
Returns:
|
|
54
|
-
Dict com confiabilidade (alta/media/baixa) e
|
|
59
|
+
Dict com confiabilidade (alta/media/baixa), motivos e flag crítico
|
|
55
60
|
"""
|
|
56
61
|
motivos = []
|
|
62
|
+
critico = False
|
|
57
63
|
|
|
58
64
|
# Verificar se tem preço normalizado
|
|
59
65
|
preco_norm = item.get("preco_normalizado", {})
|
|
60
66
|
if not preco_norm.get("normalizado"):
|
|
61
67
|
return {
|
|
62
68
|
"confiabilidade": "baixa",
|
|
63
|
-
"motivos": ["Preço não normalizado ou não disponível"]
|
|
69
|
+
"motivos": ["Preço não normalizado ou não disponível"],
|
|
70
|
+
"critico": True
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
# Verificar se tem produtividade e custo
|
|
@@ -76,7 +83,8 @@ def classificar_confiabilidade_lucro(item: Dict) -> Dict:
|
|
|
76
83
|
if motivos:
|
|
77
84
|
return {
|
|
78
85
|
"confiabilidade": "baixa",
|
|
79
|
-
"motivos": motivos
|
|
86
|
+
"motivos": motivos,
|
|
87
|
+
"critico": True
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
# Verificar se tem lucro de mercado calculado
|
|
@@ -84,7 +92,8 @@ def classificar_confiabilidade_lucro(item: Dict) -> Dict:
|
|
|
84
92
|
if lucro_mercado is None:
|
|
85
93
|
return {
|
|
86
94
|
"confiabilidade": "baixa",
|
|
87
|
-
"motivos": ["Lucro de mercado não calculado"]
|
|
95
|
+
"motivos": ["Lucro de mercado não calculado"],
|
|
96
|
+
"critico": True
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
# Calcular diferença com lucro do sistema
|
|
@@ -92,34 +101,61 @@ def classificar_confiabilidade_lucro(item: Dict) -> Dict:
|
|
|
92
101
|
diferenca = calcular_diferenca_lucro(lucro_sistema, lucro_mercado)
|
|
93
102
|
diferenca_percentual = abs(diferenca["diferenca_percentual"])
|
|
94
103
|
|
|
95
|
-
#
|
|
96
|
-
|
|
104
|
+
# Verificar se é fallback
|
|
105
|
+
preco_real = item.get("preco_real", {})
|
|
106
|
+
is_fallback = preco_real.get("fallback", False)
|
|
107
|
+
|
|
108
|
+
# Verificar inversão de sinal (lucro vira prejuízo ou vice-versa)
|
|
109
|
+
lucro_invertido = (lucro_sistema > 0 and lucro_mercado < 0) or (lucro_sistema < 0 and lucro_mercado > 0)
|
|
110
|
+
|
|
111
|
+
# CRITÉRIOS REFINADOS (Fase 9.5)
|
|
112
|
+
|
|
113
|
+
# Baixa confiabilidade (crítico)
|
|
114
|
+
if diferenca_percentual >= 150:
|
|
115
|
+
confiabilidade = "baixa"
|
|
116
|
+
motivos.append(f"Diferença extrema ({diferenca_percentual:.1f}%) entre lucro sistema e mercado")
|
|
117
|
+
critico = True
|
|
118
|
+
elif lucro_invertido and lucro_sistema > 0:
|
|
119
|
+
confiabilidade = "baixa"
|
|
120
|
+
motivos.append("Lucro do sistema é positivo mas lucro de mercado indica prejuízo")
|
|
121
|
+
critico = True
|
|
122
|
+
elif is_fallback and diferenca_percentual >= 100:
|
|
123
|
+
confiabilidade = "baixa"
|
|
124
|
+
motivos.append(f"Preço de fallback com diferença muito alta ({diferenca_percentual:.1f}%)")
|
|
125
|
+
critico = True
|
|
126
|
+
elif diferenca_percentual >= 100:
|
|
127
|
+
# Diferença > 100% mesmo sem fallback é baixa confiabilidade
|
|
97
128
|
confiabilidade = "baixa"
|
|
98
129
|
motivos.append(f"Diferença muito alta ({diferenca_percentual:.1f}%) entre lucro sistema e mercado")
|
|
99
|
-
|
|
130
|
+
critico = False # Não crítico se não for fallback
|
|
131
|
+
|
|
132
|
+
# Média confiabilidade
|
|
133
|
+
elif diferenca_percentual >= 50:
|
|
100
134
|
confiabilidade = "media"
|
|
101
135
|
motivos.append(f"Diferença moderada ({diferenca_percentual:.1f}%) entre lucro sistema e mercado")
|
|
136
|
+
elif is_fallback:
|
|
137
|
+
confiabilidade = "media"
|
|
138
|
+
motivos.append("Preço de referência (fallback) - pode não refletir mercado local")
|
|
139
|
+
elif lucro_mercado < 0:
|
|
140
|
+
confiabilidade = "media"
|
|
141
|
+
motivos.append("Lucro de mercado indica prejuízo - requer validação")
|
|
142
|
+
|
|
143
|
+
# Alta confiabilidade
|
|
102
144
|
else:
|
|
103
145
|
confiabilidade = "alta"
|
|
104
146
|
motivos.append(f"Diferença aceitável ({diferenca_percentual:.1f}%) entre lucro sistema e mercado")
|
|
147
|
+
if not is_fallback:
|
|
148
|
+
motivos.append("Preço real disponível (não fallback)")
|
|
105
149
|
|
|
106
|
-
#
|
|
107
|
-
if
|
|
108
|
-
|
|
109
|
-
confiabilidade = "media"
|
|
110
|
-
motivos.append("Lucro de mercado indica prejuízo - requer validação de preço/produtividade")
|
|
111
|
-
|
|
112
|
-
# Verificar se é fallback
|
|
113
|
-
preco_real = item.get("preco_real", {})
|
|
114
|
-
if preco_real.get("fallback"):
|
|
115
|
-
if confiabilidade == "alta":
|
|
116
|
-
confiabilidade = "media"
|
|
117
|
-
motivos.append("Preço usando fallback (referência) - pode não refletir mercado local")
|
|
150
|
+
# Adicionar informação sobre normalização bem-sucedida
|
|
151
|
+
if preco_norm.get("normalizado") and confiabilidade != "baixa":
|
|
152
|
+
motivos.append("Unidade comercial normalizada com sucesso")
|
|
118
153
|
|
|
119
154
|
return {
|
|
120
155
|
"confiabilidade": confiabilidade,
|
|
121
156
|
"motivos": motivos,
|
|
122
|
-
"diferenca": diferenca
|
|
157
|
+
"diferenca": diferenca,
|
|
158
|
+
"critico": critico
|
|
123
159
|
}
|
|
124
160
|
|
|
125
161
|
|
|
@@ -140,6 +176,7 @@ def validar_plano_lucro_mercado(resultado: Dict) -> Dict:
|
|
|
140
176
|
alta_confiabilidade = 0
|
|
141
177
|
media_confiabilidade = 0
|
|
142
178
|
baixa_confiabilidade = 0
|
|
179
|
+
itens_criticos = 0
|
|
143
180
|
alertas = []
|
|
144
181
|
|
|
145
182
|
# Validar cada item do plano
|
|
@@ -160,11 +197,16 @@ def validar_plano_lucro_mercado(resultado: Dict) -> Dict:
|
|
|
160
197
|
cultura = item.get("cultura", "desconhecida")
|
|
161
198
|
talhao = item.get("talhao", "?")
|
|
162
199
|
alertas.append(f"Talhão {talhao} ({cultura}): {', '.join(validacao['motivos'])}")
|
|
200
|
+
|
|
201
|
+
# Contabilizar itens críticos
|
|
202
|
+
if validacao.get("critico", False):
|
|
203
|
+
itens_criticos += 1
|
|
163
204
|
|
|
164
205
|
# Adicionar resumo de validação
|
|
165
206
|
total = len(resultado["plano"])
|
|
166
207
|
percentual_alta = (alta_confiabilidade / total * 100) if total > 0 else 0
|
|
167
208
|
percentual_baixa = (baixa_confiabilidade / total * 100) if total > 0 else 0
|
|
209
|
+
percentual_critico = (itens_criticos / total * 100) if total > 0 else 0
|
|
168
210
|
|
|
169
211
|
resultado["validacao_lucro_mercado"] = {
|
|
170
212
|
"ativo": True,
|
|
@@ -172,31 +214,38 @@ def validar_plano_lucro_mercado(resultado: Dict) -> Dict:
|
|
|
172
214
|
"itens_alta_confiabilidade": alta_confiabilidade,
|
|
173
215
|
"itens_media_confiabilidade": media_confiabilidade,
|
|
174
216
|
"itens_baixa_confiabilidade": baixa_confiabilidade,
|
|
217
|
+
"itens_criticos": itens_criticos,
|
|
175
218
|
"percentual_alta_confiabilidade": round(percentual_alta, 1),
|
|
176
219
|
"percentual_baixa_confiabilidade": round(percentual_baixa, 1),
|
|
220
|
+
"percentual_critico": round(percentual_critico, 1),
|
|
177
221
|
"alertas": alertas[:5], # Limitar a 5 alertas principais
|
|
178
222
|
"total_alertas": len(alertas),
|
|
179
|
-
"recomendacao": _gerar_recomendacao(percentual_alta, percentual_baixa)
|
|
223
|
+
"recomendacao": _gerar_recomendacao(percentual_alta, percentual_baixa, percentual_critico)
|
|
180
224
|
}
|
|
181
225
|
|
|
182
226
|
return resultado
|
|
183
227
|
|
|
184
228
|
|
|
185
|
-
def _gerar_recomendacao(percentual_alta: float, percentual_baixa: float) -> str:
|
|
229
|
+
def _gerar_recomendacao(percentual_alta: float, percentual_baixa: float, percentual_critico: float = 0) -> str:
|
|
186
230
|
"""
|
|
187
231
|
Gera recomendação baseada nos percentuais de confiabilidade.
|
|
188
232
|
|
|
189
233
|
Args:
|
|
190
234
|
percentual_alta: Percentual de itens com alta confiabilidade
|
|
191
235
|
percentual_baixa: Percentual de itens com baixa confiabilidade
|
|
236
|
+
percentual_critico: Percentual de itens críticos
|
|
192
237
|
|
|
193
238
|
Returns:
|
|
194
239
|
String com recomendação
|
|
195
240
|
"""
|
|
196
|
-
if
|
|
241
|
+
if percentual_critico >= 30:
|
|
242
|
+
return "Há valores críticos no lucro de mercado. Eles não devem ser usados para otimização sem validação manual."
|
|
243
|
+
elif percentual_alta >= 70:
|
|
197
244
|
return "Lucro de mercado apresenta boa confiabilidade. Considere validação detalhada antes de ativar PRICE_APPLY_TO_PROFIT."
|
|
198
245
|
elif percentual_baixa >= 50:
|
|
199
246
|
return "Muitos itens com baixa confiabilidade. Valide preços, produtividades e custos antes de usar lucro de mercado."
|
|
247
|
+
elif percentual_critico > 0:
|
|
248
|
+
return "Alguns valores críticos detectados. Revise itens com baixa confiabilidade antes de usar lucro de mercado."
|
|
200
249
|
else:
|
|
201
250
|
return "Confiabilidade mista. Revise itens com baixa confiabilidade e valide dados de mercado."
|
|
202
251
|
|
|
@@ -279,14 +279,31 @@ def gerar_secao_validacao_lucro_mercado(resultado, formato='md'):
|
|
|
279
279
|
alta = validacao.get("itens_alta_confiabilidade", 0)
|
|
280
280
|
media = validacao.get("itens_media_confiabilidade", 0)
|
|
281
281
|
baixa = validacao.get("itens_baixa_confiabilidade", 0)
|
|
282
|
+
criticos = validacao.get("itens_criticos", 0)
|
|
282
283
|
|
|
283
284
|
perc_alta = validacao.get("percentual_alta_confiabilidade", 0)
|
|
284
285
|
perc_baixa = validacao.get("percentual_baixa_confiabilidade", 0)
|
|
286
|
+
perc_critico = validacao.get("percentual_critico", 0)
|
|
285
287
|
|
|
286
288
|
secao += f"- **Total de itens analisados**: {total}\n"
|
|
287
289
|
secao += f"- **Alta confiabilidade**: {alta} ({perc_alta:.1f}%) 🟢\n"
|
|
288
290
|
secao += f"- **Média confiabilidade**: {media} ({100 - perc_alta - perc_baixa:.1f}%) 🟡\n"
|
|
289
|
-
secao += f"- **Baixa confiabilidade**: {baixa} ({perc_baixa:.1f}%) 🔴\n
|
|
291
|
+
secao += f"- **Baixa confiabilidade**: {baixa} ({perc_baixa:.1f}%) 🔴\n"
|
|
292
|
+
|
|
293
|
+
if criticos > 0:
|
|
294
|
+
secao += f"- **⚠️ Itens críticos**: {criticos} ({perc_critico:.1f}%)\n"
|
|
295
|
+
|
|
296
|
+
secao += "\n"
|
|
297
|
+
|
|
298
|
+
# Aviso de itens críticos
|
|
299
|
+
if criticos > 0:
|
|
300
|
+
secao += "### ⚠️ ATENÇÃO: Valores Críticos Detectados\n\n"
|
|
301
|
+
secao += f"**{criticos} item(ns) apresenta(m) valores críticos** que indicam possível desalinhamento entre:\n"
|
|
302
|
+
secao += "- Preço de mercado vs preço interno\n"
|
|
303
|
+
secao += "- Produtividade estimada vs real\n"
|
|
304
|
+
secao += "- Custos operacionais\n"
|
|
305
|
+
secao += "- Unidade comercial\n\n"
|
|
306
|
+
secao += "**Estes valores não devem ser usados para otimização sem validação manual.**\n\n"
|
|
290
307
|
|
|
291
308
|
# Recomendação
|
|
292
309
|
recomendacao = validacao.get("recomendacao", "")
|
|
@@ -332,8 +349,14 @@ def gerar_secao_validacao_lucro_mercado(resultado, formato='md'):
|
|
|
332
349
|
diferenca_fmt = "N/A"
|
|
333
350
|
|
|
334
351
|
confiabilidade = validacao_item.get("confiabilidade", "baixa")
|
|
335
|
-
|
|
336
|
-
|
|
352
|
+
critico = validacao_item.get("critico", False)
|
|
353
|
+
|
|
354
|
+
if critico:
|
|
355
|
+
conf_emoji = "⚠️🔴"
|
|
356
|
+
conf_label = "**CRÍTICO**"
|
|
357
|
+
else:
|
|
358
|
+
conf_emoji = "🟢" if confiabilidade == "alta" else "🟡" if confiabilidade == "media" else "🔴"
|
|
359
|
+
conf_label = confiabilidade.title()
|
|
337
360
|
|
|
338
361
|
secao += f"| {talhao} | {cultura} | {lucro_sistema_fmt} | {lucro_mercado_fmt} | {diferenca_fmt} | {conf_emoji} {conf_label} |\n"
|
|
339
362
|
|
|
@@ -343,8 +366,9 @@ def gerar_secao_validacao_lucro_mercado(resultado, formato='md'):
|
|
|
343
366
|
secao += "### 📊 Sobre a Classificação de Confiabilidade\n\n"
|
|
344
367
|
secao += "A confiabilidade do lucro de mercado é classificada com base em:\n\n"
|
|
345
368
|
secao += "- **Alta (🟢)**: Diferença < 50% entre lucro sistema e mercado, preço normalizado disponível\n"
|
|
346
|
-
secao += "- **Média (🟡)**: Diferença 50-
|
|
347
|
-
secao += "- **Baixa (🔴)**: Diferença >
|
|
369
|
+
secao += "- **Média (🟡)**: Diferença 50-150%, uso de fallback, ou lucro negativo\n"
|
|
370
|
+
secao += "- **Baixa (🔴)**: Diferença > 150%, dados incompletos, ou preço não disponível\n"
|
|
371
|
+
secao += "- **⚠️ CRÍTICO**: Diferença extrema (>150%), lucro invertido, ou fallback com diferença >100%\n\n"
|
|
348
372
|
|
|
349
373
|
secao += "### ⚠️ Aviso Importante\n\n"
|
|
350
374
|
secao += "**O lucro de mercado ainda é experimental e não substitui o lucro principal do sistema.**\n\n"
|