agroplan-ai-cli 1.0.0
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.
- package/README.md +95 -0
- package/backend-template/.env.example +21 -0
- package/backend-template/Dockerfile +21 -0
- package/backend-template/README.md +274 -0
- package/backend-template/api.py +538 -0
- package/backend-template/core/bruteforce_validator.py +248 -0
- package/backend-template/core/genetic_optimizer.py +328 -0
- package/backend-template/core/loader.py +8 -0
- package/backend-template/core/planner.py +79 -0
- package/backend-template/core/report_generator.py +785 -0
- package/backend-template/core/scenario_simulator.py +286 -0
- package/backend-template/core/scorer.py +101 -0
- package/backend-template/core/terrain_analyzer.py +123 -0
- package/backend-template/data/culturas.csv +11 -0
- package/backend-template/data/regras_culturas.csv +11 -0
- package/backend-template/data/talhoes.csv +11 -0
- package/backend-template/main.py +487 -0
- package/backend-template/reports/.gitkeep +1 -0
- package/backend-template/requirements.txt +6 -0
- package/dist/index.js +719 -0
- package/package.json +51 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simulador de cenários para comparar diferentes estratégias de planejamento agrícola
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from core.terrain_analyzer import analisar_todos_talhoes
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def calcular_metricas_plano(plano):
|
|
9
|
+
"""Calcula métricas agregadas de um plano"""
|
|
10
|
+
lucro_total = sum(p['lucro_estimado'] for p in plano)
|
|
11
|
+
area_total = sum(p['area'] for p in plano)
|
|
12
|
+
risco_ponderado = sum(p['risco'] * p['area'] for p in plano)
|
|
13
|
+
risco_medio = risco_ponderado / area_total if area_total > 0 else 0
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
'lucro_total': lucro_total,
|
|
17
|
+
'area_total': area_total,
|
|
18
|
+
'risco_medio': risco_medio
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def gerar_cenario_equilibrado(analises):
|
|
23
|
+
"""
|
|
24
|
+
Cenário Equilibrado: Escolhe a cultura com maior nota_final
|
|
25
|
+
Melhor equilíbrio entre lucro, compatibilidade e risco
|
|
26
|
+
"""
|
|
27
|
+
plano = []
|
|
28
|
+
|
|
29
|
+
for analise in analises:
|
|
30
|
+
talhao = analise['talhao']
|
|
31
|
+
melhor = analise['melhor_cultura'] # Já é a de maior nota
|
|
32
|
+
|
|
33
|
+
if melhor:
|
|
34
|
+
plano.append({
|
|
35
|
+
'talhao': talhao['id'],
|
|
36
|
+
'area': talhao['area'],
|
|
37
|
+
'cultura': melhor['cultura'],
|
|
38
|
+
'lucro_estimado': melhor['lucro_total'],
|
|
39
|
+
'risco': melhor['risco'],
|
|
40
|
+
'nota': melhor['nota']
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
metricas = calcular_metricas_plano(plano)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
'nome': 'Equilibrado',
|
|
47
|
+
'descricao': 'Melhor equilíbrio entre lucro, compatibilidade e risco.',
|
|
48
|
+
'plano': plano,
|
|
49
|
+
**metricas
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def gerar_cenario_maximo_lucro(analises):
|
|
54
|
+
"""
|
|
55
|
+
Cenário Máximo Lucro: Prioriza lucro_estimado
|
|
56
|
+
O risco pode ser maior, mas ainda aparece no relatório
|
|
57
|
+
"""
|
|
58
|
+
plano = []
|
|
59
|
+
|
|
60
|
+
for analise in analises:
|
|
61
|
+
talhao = analise['talhao']
|
|
62
|
+
ranking = analise['ranking']
|
|
63
|
+
|
|
64
|
+
# Escolhe a cultura com maior lucro
|
|
65
|
+
melhor_lucro = max(ranking, key=lambda x: x['lucro_total'])
|
|
66
|
+
|
|
67
|
+
plano.append({
|
|
68
|
+
'talhao': talhao['id'],
|
|
69
|
+
'area': talhao['area'],
|
|
70
|
+
'cultura': melhor_lucro['cultura'],
|
|
71
|
+
'lucro_estimado': melhor_lucro['lucro_total'],
|
|
72
|
+
'risco': melhor_lucro['risco'],
|
|
73
|
+
'nota': melhor_lucro['nota']
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
metricas = calcular_metricas_plano(plano)
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
'nome': 'Máximo Lucro',
|
|
80
|
+
'descricao': 'Prioriza o maior retorno financeiro estimado.',
|
|
81
|
+
'plano': plano,
|
|
82
|
+
**metricas
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def gerar_cenario_baixo_risco(analises):
|
|
87
|
+
"""
|
|
88
|
+
Cenário Baixo Risco: Prioriza culturas com menor risco
|
|
89
|
+
Em caso de empate, escolhe maior nota_final
|
|
90
|
+
"""
|
|
91
|
+
plano = []
|
|
92
|
+
|
|
93
|
+
for analise in analises:
|
|
94
|
+
talhao = analise['talhao']
|
|
95
|
+
ranking = analise['ranking']
|
|
96
|
+
|
|
97
|
+
# Ordena por risco (crescente) e depois por nota (decrescente)
|
|
98
|
+
ranking_ordenado = sorted(ranking, key=lambda x: (x['risco'], -x['nota']))
|
|
99
|
+
melhor_baixo_risco = ranking_ordenado[0]
|
|
100
|
+
|
|
101
|
+
plano.append({
|
|
102
|
+
'talhao': talhao['id'],
|
|
103
|
+
'area': talhao['area'],
|
|
104
|
+
'cultura': melhor_baixo_risco['cultura'],
|
|
105
|
+
'lucro_estimado': melhor_baixo_risco['lucro_total'],
|
|
106
|
+
'risco': melhor_baixo_risco['risco'],
|
|
107
|
+
'nota': melhor_baixo_risco['nota']
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
metricas = calcular_metricas_plano(plano)
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
'nome': 'Baixo Risco',
|
|
114
|
+
'descricao': 'Prioriza segurança e menor exposição a perdas.',
|
|
115
|
+
'plano': plano,
|
|
116
|
+
**metricas
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def gerar_cenario_sustentavel(analises):
|
|
121
|
+
"""
|
|
122
|
+
Cenário Sustentável: Prioriza boa compatibilidade com solo, água e risco menor
|
|
123
|
+
Não escolhe apenas pelo lucro
|
|
124
|
+
"""
|
|
125
|
+
plano = []
|
|
126
|
+
|
|
127
|
+
for analise in analises:
|
|
128
|
+
talhao = analise['talhao']
|
|
129
|
+
ranking = analise['ranking']
|
|
130
|
+
|
|
131
|
+
# Calcula score de sustentabilidade
|
|
132
|
+
# Prioriza compatibilidades altas e risco baixo
|
|
133
|
+
def score_sustentavel(cultura):
|
|
134
|
+
compatibilidade = (
|
|
135
|
+
cultura['compatibilidade_solo'] +
|
|
136
|
+
cultura['compatibilidade_clima'] +
|
|
137
|
+
cultura['compatibilidade_agua']
|
|
138
|
+
)
|
|
139
|
+
# Penaliza risco mais fortemente
|
|
140
|
+
return compatibilidade - (cultura['risco'] / 5)
|
|
141
|
+
|
|
142
|
+
melhor_sustentavel = max(ranking, key=score_sustentavel)
|
|
143
|
+
|
|
144
|
+
plano.append({
|
|
145
|
+
'talhao': talhao['id'],
|
|
146
|
+
'area': talhao['area'],
|
|
147
|
+
'cultura': melhor_sustentavel['cultura'],
|
|
148
|
+
'lucro_estimado': melhor_sustentavel['lucro_total'],
|
|
149
|
+
'risco': melhor_sustentavel['risco'],
|
|
150
|
+
'nota': melhor_sustentavel['nota']
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
metricas = calcular_metricas_plano(plano)
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
'nome': 'Sustentável',
|
|
157
|
+
'descricao': 'Prioriza compatibilidade ambiental e uso eficiente de recursos.',
|
|
158
|
+
'plano': plano,
|
|
159
|
+
**metricas
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def gerar_cenario_conservador(analises):
|
|
164
|
+
"""
|
|
165
|
+
Cenário Conservador: Evita culturas com risco alto
|
|
166
|
+
Escolhe opções com boa nota e risco controlado
|
|
167
|
+
"""
|
|
168
|
+
plano = []
|
|
169
|
+
|
|
170
|
+
for analise in analises:
|
|
171
|
+
talhao = analise['talhao']
|
|
172
|
+
ranking = analise['ranking']
|
|
173
|
+
|
|
174
|
+
# Filtra culturas com risco <= 30%, se possível
|
|
175
|
+
ranking_baixo_risco = [c for c in ranking if c['risco'] <= 30]
|
|
176
|
+
|
|
177
|
+
# Se não houver opções de baixo risco, usa todas
|
|
178
|
+
if not ranking_baixo_risco:
|
|
179
|
+
ranking_baixo_risco = ranking
|
|
180
|
+
|
|
181
|
+
# Entre as de baixo risco, escolhe a de maior nota
|
|
182
|
+
melhor_conservador = max(ranking_baixo_risco, key=lambda x: x['nota'])
|
|
183
|
+
|
|
184
|
+
plano.append({
|
|
185
|
+
'talhao': talhao['id'],
|
|
186
|
+
'area': talhao['area'],
|
|
187
|
+
'cultura': melhor_conservador['cultura'],
|
|
188
|
+
'lucro_estimado': melhor_conservador['lucro_total'],
|
|
189
|
+
'risco': melhor_conservador['risco'],
|
|
190
|
+
'nota': melhor_conservador['nota']
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
metricas = calcular_metricas_plano(plano)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
'nome': 'Conservador',
|
|
197
|
+
'descricao': 'Evita riscos altos, priorizando segurança e estabilidade.',
|
|
198
|
+
'plano': plano,
|
|
199
|
+
**metricas
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def simular_cenarios(culturas, talhoes, regras):
|
|
204
|
+
"""
|
|
205
|
+
Simula diferentes cenários de planejamento agrícola
|
|
206
|
+
|
|
207
|
+
Retorna um dicionário com todos os cenários e suas métricas
|
|
208
|
+
"""
|
|
209
|
+
# Analisa todos os talhões uma única vez
|
|
210
|
+
analises = analisar_todos_talhoes(talhoes, culturas, regras)
|
|
211
|
+
|
|
212
|
+
# Gera todos os cenários
|
|
213
|
+
cenarios = {
|
|
214
|
+
'equilibrado': gerar_cenario_equilibrado(analises),
|
|
215
|
+
'maximo_lucro': gerar_cenario_maximo_lucro(analises),
|
|
216
|
+
'baixo_risco': gerar_cenario_baixo_risco(analises),
|
|
217
|
+
'sustentavel': gerar_cenario_sustentavel(analises),
|
|
218
|
+
'conservador': gerar_cenario_conservador(analises)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return cenarios
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def recomendar_melhor_cenario(cenarios):
|
|
225
|
+
"""
|
|
226
|
+
Recomenda o melhor cenário baseado em critérios balanceados
|
|
227
|
+
|
|
228
|
+
Considera:
|
|
229
|
+
- Lucro razoável (não necessariamente o máximo)
|
|
230
|
+
- Risco controlado
|
|
231
|
+
- Equilíbrio geral
|
|
232
|
+
"""
|
|
233
|
+
# Por padrão, recomenda o equilibrado
|
|
234
|
+
melhor = 'equilibrado'
|
|
235
|
+
|
|
236
|
+
# Mas verifica se há cenários melhores
|
|
237
|
+
equilibrado = cenarios['equilibrado']
|
|
238
|
+
baixo_risco = cenarios['baixo_risco']
|
|
239
|
+
|
|
240
|
+
# Se o baixo risco tem lucro muito próximo (>90%) e risco menor, prefere ele
|
|
241
|
+
if baixo_risco['lucro_total'] >= equilibrado['lucro_total'] * 0.9:
|
|
242
|
+
if baixo_risco['risco_medio'] < equilibrado['risco_medio']:
|
|
243
|
+
melhor = 'baixo_risco'
|
|
244
|
+
|
|
245
|
+
justificativa = gerar_justificativa_recomendacao(cenarios, melhor)
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
'cenario': melhor,
|
|
249
|
+
'justificativa': justificativa
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def gerar_justificativa_recomendacao(cenarios, cenario_escolhido):
|
|
254
|
+
"""Gera justificativa para a recomendação do cenário"""
|
|
255
|
+
cenario = cenarios[cenario_escolhido]
|
|
256
|
+
|
|
257
|
+
justificativas = {
|
|
258
|
+
'equilibrado': (
|
|
259
|
+
f"O cenário {cenario['nome']} foi recomendado porque apresenta "
|
|
260
|
+
f"bom lucro estimado (R$ {cenario['lucro_total']:,.2f}), "
|
|
261
|
+
f"risco controlado ({cenario['risco_medio']:.1f}%) e "
|
|
262
|
+
f"alta compatibilidade entre culturas e características dos talhões."
|
|
263
|
+
),
|
|
264
|
+
'baixo_risco': (
|
|
265
|
+
f"O cenário {cenario['nome']} foi recomendado porque oferece "
|
|
266
|
+
f"excelente segurança com risco médio de apenas {cenario['risco_medio']:.1f}%, "
|
|
267
|
+
f"mantendo lucro razoável de R$ {cenario['lucro_total']:,.2f}."
|
|
268
|
+
),
|
|
269
|
+
'maximo_lucro': (
|
|
270
|
+
f"O cenário {cenario['nome']} foi recomendado porque maximiza "
|
|
271
|
+
f"o retorno financeiro (R$ {cenario['lucro_total']:,.2f}), "
|
|
272
|
+
f"com risco aceitável de {cenario['risco_medio']:.1f}%."
|
|
273
|
+
),
|
|
274
|
+
'sustentavel': (
|
|
275
|
+
f"O cenário {cenario['nome']} foi recomendado porque prioriza "
|
|
276
|
+
f"compatibilidade ambiental e uso eficiente de recursos, "
|
|
277
|
+
f"com lucro de R$ {cenario['lucro_total']:,.2f} e risco de {cenario['risco_medio']:.1f}%."
|
|
278
|
+
),
|
|
279
|
+
'conservador': (
|
|
280
|
+
f"O cenário {cenario['nome']} foi recomendado porque evita "
|
|
281
|
+
f"riscos altos, mantendo risco médio de {cenario['risco_medio']:.1f}% "
|
|
282
|
+
f"e lucro de R$ {cenario['lucro_total']:,.2f}."
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return justificativas.get(cenario_escolhido, "Cenário recomendado pelo sistema.")
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sistema de pontuação para avaliar compatibilidade entre culturas e talhões
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
def calcular_compatibilidade_solo(solo_talhao, solos_ideais):
|
|
6
|
+
"""Calcula compatibilidade do solo (0-25 pontos)"""
|
|
7
|
+
solos = [s.strip() for s in solos_ideais.split(';')]
|
|
8
|
+
return 25 if solo_talhao in solos else 0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def calcular_compatibilidade_clima(clima_talhao, climas_ideais):
|
|
12
|
+
"""Calcula compatibilidade do clima (0-25 pontos)"""
|
|
13
|
+
climas = [c.strip() for c in climas_ideais.split(';')]
|
|
14
|
+
return 25 if clima_talhao in climas else 0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def calcular_compatibilidade_relevo(relevo_talhao, relevos_ideais):
|
|
18
|
+
"""Calcula compatibilidade do relevo (0-15 pontos)"""
|
|
19
|
+
relevos = [r.strip() for r in relevos_ideais.split(';')]
|
|
20
|
+
return 15 if relevo_talhao in relevos else 0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def calcular_compatibilidade_agua(agua_talhao, agua_necessaria):
|
|
24
|
+
"""Calcula compatibilidade da disponibilidade de água (0-15 pontos)"""
|
|
25
|
+
# Mapeamento de níveis
|
|
26
|
+
niveis = {'baixa': 1, 'media': 2, 'alta': 3}
|
|
27
|
+
|
|
28
|
+
nivel_talhao = niveis.get(agua_talhao, 0)
|
|
29
|
+
nivel_necessario = niveis.get(agua_necessaria, 0)
|
|
30
|
+
|
|
31
|
+
# Pontuação máxima se atende ou excede a necessidade
|
|
32
|
+
if nivel_talhao >= nivel_necessario:
|
|
33
|
+
return 15
|
|
34
|
+
# Penalidade se não atende
|
|
35
|
+
elif nivel_talhao == nivel_necessario - 1:
|
|
36
|
+
return 8
|
|
37
|
+
else:
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def calcular_lucro_por_hectare(cultura):
|
|
42
|
+
"""Calcula lucro estimado por hectare"""
|
|
43
|
+
return (cultura['preco'] * cultura['produtividade']) - cultura['custo']
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def normalizar_lucro(lucro, lucro_min, lucro_max):
|
|
47
|
+
"""Normaliza lucro para escala 0-10"""
|
|
48
|
+
if lucro_max == lucro_min:
|
|
49
|
+
return 5
|
|
50
|
+
return 10 * (lucro - lucro_min) / (lucro_max - lucro_min)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def calcular_nota_final(talhao, cultura, regra, lucro_normalizado):
|
|
54
|
+
"""
|
|
55
|
+
Calcula nota final da cultura para o talhão
|
|
56
|
+
|
|
57
|
+
Componentes:
|
|
58
|
+
- Solo: 0-25 pontos
|
|
59
|
+
- Clima: 0-25 pontos
|
|
60
|
+
- Relevo: 0-15 pontos
|
|
61
|
+
- Água: 0-15 pontos
|
|
62
|
+
- Lucro: 0-10 pontos
|
|
63
|
+
- Risco: -risco_base pontos
|
|
64
|
+
|
|
65
|
+
Total máximo: 90 pontos (antes do risco)
|
|
66
|
+
"""
|
|
67
|
+
nota = 0
|
|
68
|
+
|
|
69
|
+
# Compatibilidades
|
|
70
|
+
nota += calcular_compatibilidade_solo(talhao['solo'], regra['solos_ideais'])
|
|
71
|
+
nota += calcular_compatibilidade_clima(talhao['clima'], regra['climas_ideais'])
|
|
72
|
+
nota += calcular_compatibilidade_relevo(talhao['relevo'], regra['relevo_ideal'])
|
|
73
|
+
nota += calcular_compatibilidade_agua(talhao['agua'], regra['agua_necessaria'])
|
|
74
|
+
|
|
75
|
+
# Lucro normalizado
|
|
76
|
+
nota += lucro_normalizado
|
|
77
|
+
|
|
78
|
+
# Penalidade por risco
|
|
79
|
+
nota -= (regra['risco_base'] / 10)
|
|
80
|
+
|
|
81
|
+
return round(nota, 2)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def avaliar_cultura_para_talhao(talhao, cultura, regra, lucro_normalizado):
|
|
85
|
+
"""Avalia uma cultura específica para um talhão e retorna detalhes completos"""
|
|
86
|
+
lucro_por_ha = calcular_lucro_por_hectare(cultura)
|
|
87
|
+
lucro_total = lucro_por_ha * talhao['area']
|
|
88
|
+
nota = calcular_nota_final(talhao, cultura, regra, lucro_normalizado)
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
'cultura': cultura['nome'],
|
|
92
|
+
'nota': nota,
|
|
93
|
+
'lucro_por_ha': lucro_por_ha,
|
|
94
|
+
'lucro_total': lucro_total,
|
|
95
|
+
'risco': regra['risco_base'],
|
|
96
|
+
'tempo': cultura['tempo'],
|
|
97
|
+
'compatibilidade_solo': calcular_compatibilidade_solo(talhao['solo'], regra['solos_ideais']),
|
|
98
|
+
'compatibilidade_clima': calcular_compatibilidade_clima(talhao['clima'], regra['climas_ideais']),
|
|
99
|
+
'compatibilidade_relevo': calcular_compatibilidade_relevo(talhao['relevo'], regra['relevo_ideal']),
|
|
100
|
+
'compatibilidade_agua': calcular_compatibilidade_agua(talhao['agua'], regra['agua_necessaria'])
|
|
101
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Analisador de terreno que avalia e recomenda culturas para cada talhão
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from core.scorer import calcular_lucro_por_hectare, normalizar_lucro, avaliar_cultura_para_talhao
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def analisar_talhao(talhao, culturas, regras):
|
|
9
|
+
"""
|
|
10
|
+
Analisa um talhão e retorna ranking de culturas recomendadas
|
|
11
|
+
|
|
12
|
+
Retorna:
|
|
13
|
+
- ranking: lista de culturas ordenadas por nota
|
|
14
|
+
- melhor_cultura: cultura com maior nota
|
|
15
|
+
- justificativa: texto explicando a recomendação
|
|
16
|
+
"""
|
|
17
|
+
avaliacoes = []
|
|
18
|
+
|
|
19
|
+
# Calcula lucro de todas as culturas para normalização
|
|
20
|
+
lucros = []
|
|
21
|
+
for _, cultura in culturas.iterrows():
|
|
22
|
+
lucro = calcular_lucro_por_hectare(cultura)
|
|
23
|
+
lucros.append(lucro)
|
|
24
|
+
|
|
25
|
+
lucro_min = min(lucros)
|
|
26
|
+
lucro_max = max(lucros)
|
|
27
|
+
|
|
28
|
+
# Avalia cada cultura para este talhão
|
|
29
|
+
for _, cultura in culturas.iterrows():
|
|
30
|
+
# Busca regras da cultura
|
|
31
|
+
regra = regras[regras['cultura'] == cultura['nome']]
|
|
32
|
+
|
|
33
|
+
if regra.empty:
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
regra = regra.iloc[0]
|
|
37
|
+
|
|
38
|
+
# Calcula lucro normalizado
|
|
39
|
+
lucro = calcular_lucro_por_hectare(cultura)
|
|
40
|
+
lucro_normalizado = normalizar_lucro(lucro, lucro_min, lucro_max)
|
|
41
|
+
|
|
42
|
+
# Avalia cultura
|
|
43
|
+
avaliacao = avaliar_cultura_para_talhao(talhao, cultura, regra, lucro_normalizado)
|
|
44
|
+
avaliacoes.append(avaliacao)
|
|
45
|
+
|
|
46
|
+
# Ordena por nota (decrescente)
|
|
47
|
+
ranking = sorted(avaliacoes, key=lambda x: x['nota'], reverse=True)
|
|
48
|
+
|
|
49
|
+
# Melhor cultura
|
|
50
|
+
melhor = ranking[0] if ranking else None
|
|
51
|
+
|
|
52
|
+
# Gera justificativa
|
|
53
|
+
justificativa = gerar_justificativa(talhao, melhor)
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
'ranking': ranking,
|
|
57
|
+
'melhor_cultura': melhor,
|
|
58
|
+
'justificativa': justificativa
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def gerar_justificativa(talhao, avaliacao):
|
|
63
|
+
"""Gera texto explicando por que a cultura foi recomendada"""
|
|
64
|
+
if not avaliacao:
|
|
65
|
+
return "Nenhuma cultura compatível encontrada."
|
|
66
|
+
|
|
67
|
+
cultura = avaliacao['cultura']
|
|
68
|
+
pontos_fortes = []
|
|
69
|
+
pontos_fracos = []
|
|
70
|
+
|
|
71
|
+
# Analisa compatibilidades
|
|
72
|
+
if avaliacao['compatibilidade_solo'] == 25:
|
|
73
|
+
pontos_fortes.append(f"solo {talhao['solo']}")
|
|
74
|
+
elif avaliacao['compatibilidade_solo'] == 0:
|
|
75
|
+
pontos_fracos.append(f"solo {talhao['solo']} não é ideal")
|
|
76
|
+
|
|
77
|
+
if avaliacao['compatibilidade_clima'] == 25:
|
|
78
|
+
pontos_fortes.append(f"clima {talhao['clima']}")
|
|
79
|
+
elif avaliacao['compatibilidade_clima'] == 0:
|
|
80
|
+
pontos_fracos.append(f"clima {talhao['clima']} não é ideal")
|
|
81
|
+
|
|
82
|
+
if avaliacao['compatibilidade_relevo'] == 15:
|
|
83
|
+
pontos_fortes.append(f"relevo {talhao['relevo']}")
|
|
84
|
+
elif avaliacao['compatibilidade_relevo'] == 0:
|
|
85
|
+
pontos_fracos.append(f"relevo {talhao['relevo']} não é ideal")
|
|
86
|
+
|
|
87
|
+
if avaliacao['compatibilidade_agua'] == 15:
|
|
88
|
+
pontos_fortes.append(f"disponibilidade {talhao['agua']} de água")
|
|
89
|
+
elif avaliacao['compatibilidade_agua'] < 15:
|
|
90
|
+
if avaliacao['compatibilidade_agua'] == 0:
|
|
91
|
+
pontos_fracos.append("disponibilidade de água insuficiente")
|
|
92
|
+
else:
|
|
93
|
+
pontos_fracos.append("disponibilidade de água abaixo do ideal")
|
|
94
|
+
|
|
95
|
+
# Monta justificativa
|
|
96
|
+
texto = f"A cultura {cultura} foi recomendada porque "
|
|
97
|
+
|
|
98
|
+
if pontos_fortes:
|
|
99
|
+
texto += f"apresenta alta compatibilidade com {', '.join(pontos_fortes)}"
|
|
100
|
+
|
|
101
|
+
if pontos_fracos:
|
|
102
|
+
if pontos_fortes:
|
|
103
|
+
texto += f", apesar de {', '.join(pontos_fracos)}"
|
|
104
|
+
else:
|
|
105
|
+
texto += f"é a melhor opção disponível, embora {', '.join(pontos_fracos)}"
|
|
106
|
+
|
|
107
|
+
# Adiciona informação sobre lucro e risco
|
|
108
|
+
texto += f". Oferece lucro estimado de R$ {avaliacao['lucro_total']:,.2f} "
|
|
109
|
+
texto += f"com risco de {avaliacao['risco']}% e ciclo de {avaliacao['tempo']} dias."
|
|
110
|
+
|
|
111
|
+
return texto
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def analisar_todos_talhoes(talhoes, culturas, regras):
|
|
115
|
+
"""Analisa todos os talhões e retorna recomendações completas"""
|
|
116
|
+
analises = []
|
|
117
|
+
|
|
118
|
+
for _, talhao in talhoes.iterrows():
|
|
119
|
+
analise = analisar_talhao(talhao, culturas, regras)
|
|
120
|
+
analise['talhao'] = talhao
|
|
121
|
+
analises.append(analise)
|
|
122
|
+
|
|
123
|
+
return analises
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
nome,custo,preco,produtividade,tempo
|
|
2
|
+
soja,1500,3000,3.2,120
|
|
3
|
+
milho,1200,2500,4.5,100
|
|
4
|
+
feijao,1000,2200,2.8,90
|
|
5
|
+
trigo,1300,2400,3.5,110
|
|
6
|
+
algodao,1800,3500,2.5,140
|
|
7
|
+
cafe,2200,4500,2.0,180
|
|
8
|
+
cana,1400,2800,5.5,150
|
|
9
|
+
sorgo,900,1800,3.8,85
|
|
10
|
+
mandioca,800,1600,4.2,240
|
|
11
|
+
arroz,1100,2300,3.6,130
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
cultura,solos_ideais,climas_ideais,relevo_ideal,agua_necessaria,risco_base
|
|
2
|
+
soja,argiloso;misto,quente;ameno,plano;leve,media,30
|
|
3
|
+
milho,argiloso;misto;arenoso,quente;ameno,plano;leve,alta,35
|
|
4
|
+
feijao,misto;arenoso,ameno;quente,plano,media,25
|
|
5
|
+
trigo,argiloso;misto,frio;ameno,plano;leve,media,40
|
|
6
|
+
algodao,argiloso;arenoso,quente,plano;leve,alta,45
|
|
7
|
+
cafe,argiloso;siltoso,ameno;quente,leve;moderado,alta,50
|
|
8
|
+
cana,argiloso;misto,quente,plano,alta,38
|
|
9
|
+
sorgo,arenoso;siltoso,quente;ameno,plano;leve,baixa,20
|
|
10
|
+
mandioca,arenoso;misto,quente;ameno,plano;leve,baixa,18
|
|
11
|
+
arroz,argiloso;siltoso,ameno;frio,plano,alta,42
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id,area,solo,clima,relevo,agua
|
|
2
|
+
1,10,argiloso,quente,plano,media
|
|
3
|
+
2,15,arenoso,quente,leve,baixa
|
|
4
|
+
3,8,misto,ameno,plano,alta
|
|
5
|
+
4,12,siltoso,ameno,leve,media
|
|
6
|
+
5,18,argiloso,frio,plano,alta
|
|
7
|
+
6,9,arenoso,quente,moderado,baixa
|
|
8
|
+
7,14,misto,ameno,plano,media
|
|
9
|
+
8,11,argiloso,quente,leve,alta
|
|
10
|
+
9,7,siltoso,frio,moderado,media
|
|
11
|
+
10,13,misto,ameno,ingreme,baixa
|