DmitrMakeev commited on
Commit
26c9ae8
·
verified ·
1 Parent(s): f57200f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -36
app.py CHANGED
@@ -689,17 +689,21 @@ def nutri_call():
689
  class NutrientCalculator:
690
  def __init__(self, volume_liters=1.0):
691
  self.volume = volume_liters
692
- self.results = defaultdict(lambda: {'grams': 0.0, 'adds': defaultdict(float)})
693
- self.target = {
694
  'P': 0, 'K': 0, 'Mg': 0, 'Ca': 0, 'S': 0,
695
- 'NO3': 0, 'NH4': 0
 
 
 
 
696
  }
697
- self.actual = defaultdict(float)
698
  self.fertilizers = {}
699
  self.total_ec = 0.0
700
 
701
  def set_target_profile(self, profile_data):
702
- self.target.update({
 
703
  'P': float(profile_data.get('P', 0)),
704
  'K': float(profile_data.get('K', 0)),
705
  'Mg': float(profile_data.get('Mg', 0)),
@@ -710,6 +714,7 @@ class NutrientCalculator:
710
  })
711
 
712
  def set_fertilizers(self, fertilizers_data):
 
713
  self.fertilizers = {
714
  "Сульфат магния": {
715
  "Mg": float(fertilizers_data["Сульфат магния"]["Mg"]),
@@ -738,29 +743,30 @@ class NutrientCalculator:
738
  }
739
 
740
  def calculate(self):
 
741
  try:
742
- # 1. Обязательные компоненты
743
  self._apply_fertilizer("Сульфат магния", "Mg")
744
  self._apply_fertilizer("Монофосфат калия", "P")
745
 
746
- # 2. Азотный баланс
747
  self._apply_fertilizer("Аммоний азотнокислый", "NH4")
748
 
749
  # 3. Кальций с контролем NO3
750
- remaining_no3 = max(self.target['NO3'] - self.actual['NO3'], 0)
751
  if remaining_no3 > 0.1:
752
  self._apply_fertilizer("Кальциевая селитра", "Ca")
753
 
754
- # 4. Калий
755
- k_deficit = self.target['K'] - self.actual['K']
756
  if k_deficit > 0.1:
757
- if self.actual['NO3'] < self.target['NO3']:
758
  self._apply_fertilizer("Калий азотнокислый", "K")
759
  else:
760
  self._apply_fertilizer("Калий сернокислый", "K")
761
 
762
  # 5. Сера
763
- s_deficit = self.target['S'] - self.actual['S']
764
  if s_deficit > 0.1:
765
  self._apply_fertilizer("Калий сернокислый", "S")
766
 
@@ -770,11 +776,12 @@ class NutrientCalculator:
770
  return False
771
 
772
  def _apply_fertilizer(self, name, main_element, required_ppm=None):
 
773
  if name not in self.fertilizers:
774
  return
775
 
776
  if required_ppm is None:
777
- required_ppm = self.target[main_element] - self.actual[main_element]
778
 
779
  if required_ppm <= 0:
780
  return
@@ -783,22 +790,28 @@ class NutrientCalculator:
783
  if content <= 0:
784
  return
785
 
786
- # Контроль NO3
787
  if 'NO3' in self.fertilizers[name]:
788
- no3_limit = max(self.target['NO3'] - self.actual['NO3'], 0)
789
  if no3_limit <= 0:
790
- return
791
  max_grams = (no3_limit * self.volume) / (self.fertilizers[name]['NO3'] * 1000)
792
  required_grams = (required_ppm * self.volume) / (content * 1000)
793
  grams = min(required_grams, max_grams)
794
  else:
795
  grams = (required_ppm * self.volume) / (content * 1000)
796
 
 
 
 
 
797
  # Обновление данных
798
  self.results[name]['grams'] += grams
799
  for element, percent in self.fertilizers[name].items():
800
  added_ppm = (grams * percent * 1000) / self.volume
801
- self.actual[element] += added_ppm
 
 
802
  self.results[name]['adds'][element] += added_ppm
803
 
804
  # Расчёт EC
@@ -813,6 +826,7 @@ class NutrientCalculator:
813
  )
814
 
815
  def get_results(self):
 
816
  return {
817
  'fertilizers': [
818
  {
@@ -822,40 +836,49 @@ class NutrientCalculator:
822
  } for name, data in self.results.items()
823
  ],
824
  'profile': [
825
- {'element': 'P', 'ppm': round(self.actual['P'], 3)},
826
- {'element': 'K', 'ppm': round(self.actual['K'], 3)},
827
- {'element': 'Mg', 'ppm': round(self.actual['Mg'], 3)},
828
- {'element': 'Ca', 'ppm': round(self.actual['Ca'], 3)},
829
- {'element': 'S', 'ppm': round(self.actual['S'], 3)},
830
- {'element': 'N-NO3', 'ppm': round(self.actual['NO3'], 3)},
831
- {'element': 'N-NH4', 'ppm': round(self.actual['NH4'], 3)}
832
  ],
833
  'ec': round(self.total_ec, 2),
834
  'deficits': {
835
- 'Ca': max(self.target['Ca'] - self.actual['Ca'], 0),
836
- 'K': max(self.target['K'] - self.actual['K'], 0),
837
- 'Mg': max(self.target['Mg'] - self.actual['Mg'], 0),
838
- 'N (NH4+)': max(self.target['NH4'] - self.actual['NH4'], 0),
839
- 'N (NO3-)': max(self.target['NO3'] - self.actual['NO3'], 0),
840
- 'P': max(self.target['P'] - self.actual['P'], 0),
841
- 'S': max(self.target['S'] - self.actual['S'], 0)
842
  }
843
  }
844
 
845
- @app.route('/calculation', methods=['POST']) # Точный эндпоинт из ошибки
846
  def handle_calculation():
847
  try:
848
  data = request.json
849
 
850
  # Валидация
851
- required = ['P', 'K', 'Mg', 'Ca', 'S', 'N (NO3-)', 'N (NH4+)', 'liters']
852
- if not all(k in data['profileSettings'] for k in required):
853
- return jsonify({'status': 'error', 'message': 'Missing required fields'}), 400
854
-
 
 
 
 
 
 
 
 
855
  calculator = NutrientCalculator(volume_liters=data['profileSettings']['liters'])
856
  calculator.set_target_profile(data['profileSettings'])
857
  calculator.set_fertilizers(data['fertilizerConstants'])
858
 
 
859
  if calculator.calculate():
860
  return jsonify({
861
  'status': 'success',
 
689
  class NutrientCalculator:
690
  def __init__(self, volume_liters=1.0):
691
  self.volume = volume_liters
692
+ self.results = {}
693
+ self.target_profile = {
694
  'P': 0, 'K': 0, 'Mg': 0, 'Ca': 0, 'S': 0,
695
+ 'NO3': 0, 'NH4': 0 # Упрощенные ключи
696
+ }
697
+ self.actual_profile = {
698
+ 'P': 0.0, 'K': 0.0, 'Mg': 0.0, 'Ca': 0.0, 'S': 0.0,
699
+ 'NO3': 0.0, 'NH4': 0.0
700
  }
 
701
  self.fertilizers = {}
702
  self.total_ec = 0.0
703
 
704
  def set_target_profile(self, profile_data):
705
+ """Устанавливаем целевые значения с преобразованием ключей"""
706
+ self.target_profile.update({
707
  'P': float(profile_data.get('P', 0)),
708
  'K': float(profile_data.get('K', 0)),
709
  'Mg': float(profile_data.get('Mg', 0)),
 
714
  })
715
 
716
  def set_fertilizers(self, fertilizers_data):
717
+ """Преобразуем входные данные в единый формат"""
718
  self.fertilizers = {
719
  "Сульфат магния": {
720
  "Mg": float(fertilizers_data["Сульфат магния"]["Mg"]),
 
743
  }
744
 
745
  def calculate(self):
746
+ """Новая логика расчёта с приоритетом по азоту"""
747
  try:
748
+ # 1. Вносим обязательные компоненты
749
  self._apply_fertilizer("Сульфат магния", "Mg")
750
  self._apply_fertilizer("Монофосфат калия", "P")
751
 
752
+ # 2. Контроль азота
753
  self._apply_fertilizer("Аммоний азотнокислый", "NH4")
754
 
755
  # 3. Кальций с контролем NO3
756
+ remaining_no3 = max(self.target_profile['NO3'] - self.actual_profile['NO3'], 0)
757
  if remaining_no3 > 0.1:
758
  self._apply_fertilizer("Кальциевая селитра", "Ca")
759
 
760
+ # 4. Калий с минимальным NO3
761
+ k_deficit = self.target_profile['K'] - self.actual_profile['K']
762
  if k_deficit > 0.1:
763
+ if self.actual_profile['NO3'] < self.target_profile['NO3']:
764
  self._apply_fertilizer("Калий азотнокислый", "K")
765
  else:
766
  self._apply_fertilizer("Калий сернокислый", "K")
767
 
768
  # 5. Сера
769
+ s_deficit = self.target_profile['S'] - self.actual_profile['S']
770
  if s_deficit > 0.1:
771
  self._apply_fertilizer("Калий сернокислый", "S")
772
 
 
776
  return False
777
 
778
  def _apply_fertilizer(self, name, main_element, required_ppm=None):
779
+ """Умное внесение удобрений с контролем NO3"""
780
  if name not in self.fertilizers:
781
  return
782
 
783
  if required_ppm is None:
784
+ required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
785
 
786
  if required_ppm <= 0:
787
  return
 
790
  if content <= 0:
791
  return
792
 
793
+ # Корректировка для NO3
794
  if 'NO3' in self.fertilizers[name]:
795
+ no3_limit = max(self.target_profile['NO3'] - self.actual_profile['NO3'], 0)
796
  if no3_limit <= 0:
797
+ return # Превышение NO3
798
  max_grams = (no3_limit * self.volume) / (self.fertilizers[name]['NO3'] * 1000)
799
  required_grams = (required_ppm * self.volume) / (content * 1000)
800
  grams = min(required_grams, max_grams)
801
  else:
802
  grams = (required_ppm * self.volume) / (content * 1000)
803
 
804
+ # Инициализация записи
805
+ if name not in self.results:
806
+ self.results[name] = {'grams': 0.0, 'adds': {}}
807
+
808
  # Обновление данных
809
  self.results[name]['grams'] += grams
810
  for element, percent in self.fertilizers[name].items():
811
  added_ppm = (grams * percent * 1000) / self.volume
812
+ self.actual_profile[element] += added_ppm
813
+ if element not in self.results[name]['adds']:
814
+ self.results[name]['adds'][element] = 0.0
815
  self.results[name]['adds'][element] += added_ppm
816
 
817
  # Расчёт EC
 
826
  )
827
 
828
  def get_results(self):
829
+ """Форматируем выходные данные"""
830
  return {
831
  'fertilizers': [
832
  {
 
836
  } for name, data in self.results.items()
837
  ],
838
  'profile': [
839
+ {'element': 'P', 'ppm': round(self.actual_profile['P'], 3)},
840
+ {'element': 'K', 'ppm': round(self.actual_profile['K'], 3)},
841
+ {'element': 'Mg', 'ppm': round(self.actual_profile['Mg'], 3)},
842
+ {'element': 'Ca', 'ppm': round(self.actual_profile['Ca'], 3)},
843
+ {'element': 'S', 'ppm': round(self.actual_profile['S'], 3)},
844
+ {'element': 'N-NO3', 'ppm': round(self.actual_profile['NO3'], 3)},
845
+ {'element': 'N-NH4', 'ppm': round(self.actual_profile['NH4'], 3)}
846
  ],
847
  'ec': round(self.total_ec, 2),
848
  'deficits': {
849
+ 'Ca': max(self.target_profile['Ca'] - self.actual_profile['Ca'], 0),
850
+ 'K': max(self.target_profile['K'] - self.actual_profile['K'], 0),
851
+ 'Mg': max(self.target_profile['Mg'] - self.actual_profile['Mg'], 0),
852
+ 'N (NH4+)': max(self.target_profile['NH4'] - self.actual_profile['NH4'], 0),
853
+ 'N (NO3-)': max(self.target_profile['NO3'] - self.actual_profile['NO3'], 0),
854
+ 'P': max(self.target_profile['P'] - self.actual_profile['P'], 0),
855
+ 'S': max(self.target_profile['S'] - self.actual_profile['S'], 0)
856
  }
857
  }
858
 
859
+ @app.route('/calculation', methods=['POST'])
860
  def handle_calculation():
861
  try:
862
  data = request.json
863
 
864
  # Валидация
865
+ required_fields = ['P', 'K', 'Mg', 'Ca', 'S', 'N (NO3-)', 'N (NH4+)', 'liters']
866
+ if not all(field in data['profileSettings'] for field in required_fields):
867
+ return jsonify({'status': 'error', 'message': 'Missing required profile fields'}), 400
868
+
869
+ required_fertilizers = [
870
+ "Кальциевая селитра", "Калий азотнокислый", "Аммоний азотнокислый",
871
+ "Сульфат магния", "Монофосфат калия", "Калий сернокислый"
872
+ ]
873
+ if not all(fert in data['fertilizerConstants'] for fert in required_fertilizers):
874
+ return jsonify({'status': 'error', 'message': 'Missing required fertilizers'}), 400
875
+
876
+ # Инициализация калькулятора
877
  calculator = NutrientCalculator(volume_liters=data['profileSettings']['liters'])
878
  calculator.set_target_profile(data['profileSettings'])
879
  calculator.set_fertilizers(data['fertilizerConstants'])
880
 
881
+ # Расчёт
882
  if calculator.calculate():
883
  return jsonify({
884
  'status': 'success',