DawnC commited on
Commit
9038885
1 Parent(s): 5e7395c

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +634 -247
scoring_calculation_system.py CHANGED
@@ -632,21 +632,26 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
632
 
633
  def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
634
  """
635
- 精確評估品種運動需求與使用者運動條件的匹配度
636
- 1. 擴大分數範圍到 0.1-1.0
637
- 2. 加強運動類型影響
638
- 3. 考慮運動強度與時間的綜合效果
639
- 4. 更細緻的時間匹配評估
 
 
 
 
 
 
 
640
  """
 
641
  exercise_levels = {
642
  'VERY HIGH': {
643
- 'min': 120,
644
- 'ideal': 150,
645
- 'max': 180,
646
- 'intensity': 'high',
647
- 'sessions': 'multiple',
648
- 'preferred_types': ['active_training', 'intensive_exercise'],
649
- 'type_weights': {
650
  'active_training': 1.0,
651
  'moderate_activity': 0.6,
652
  'light_walks': 0.3
@@ -656,61 +661,26 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
656
  'min': 90,
657
  'ideal': 120,
658
  'max': 150,
659
- 'intensity': 'moderate_high',
660
- 'sessions': 'multiple',
661
- 'preferred_types': ['active_training', 'moderate_activity'],
662
  'type_weights': {
663
  'active_training': 0.9,
664
  'moderate_activity': 0.8,
665
  'light_walks': 0.4
666
  }
667
  },
668
- 'MODERATE HIGH': {
669
- 'min': 70,
670
- 'ideal': 90,
671
- 'max': 120,
672
- 'intensity': 'moderate',
673
- 'sessions': 'flexible',
674
- 'preferred_types': ['moderate_activity', 'active_training'],
675
- 'type_weights': {
676
- 'active_training': 0.8,
677
- 'moderate_activity': 0.9,
678
- 'light_walks': 0.5
679
- }
680
- },
681
  'MODERATE': {
682
  'min': 45,
683
  'ideal': 60,
684
  'max': 90,
685
- 'intensity': 'moderate',
686
- 'sessions': 'flexible',
687
- 'preferred_types': ['moderate_activity', 'light_walks'],
688
  'type_weights': {
689
  'active_training': 0.7,
690
  'moderate_activity': 1.0,
691
  'light_walks': 0.8
692
  }
693
  },
694
- 'MODERATE LOW': {
695
- 'min': 30,
696
- 'ideal': 45,
697
- 'max': 70,
698
- 'intensity': 'light_moderate',
699
- 'sessions': 'flexible',
700
- 'preferred_types': ['light_walks', 'moderate_activity'],
701
- 'type_weights': {
702
- 'active_training': 0.6,
703
- 'moderate_activity': 0.9,
704
- 'light_walks': 1.0
705
- }
706
- },
707
  'LOW': {
708
  'min': 15,
709
  'ideal': 30,
710
  'max': 45,
711
- 'intensity': 'light',
712
- 'sessions': 'single',
713
- 'preferred_types': ['light_walks'],
714
  'type_weights': {
715
  'active_training': 0.5,
716
  'moderate_activity': 0.8,
@@ -719,51 +689,70 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
719
  }
720
  }
721
 
 
722
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
723
 
724
- # 時間匹配度評估(基礎分數)
725
  def calculate_time_score():
726
- if exercise_time >= breed_level['ideal']:
727
- if exercise_time > breed_level['max']:
728
- excess = (exercise_time - breed_level['max']) / breed_level['max']
729
- bonus = min(0.15, excess * 0.3)
730
- return min(1.0, 1.0 + bonus)
731
- return 1.0 # 理想範圍內給予滿分
732
- elif exercise_time >= breed_level['min']:
733
- # 在最小值和理想值之間使用更陡峭的曲線
734
  progress = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
735
- return 0.5 + (progress * 0.5)
 
 
 
 
 
 
736
  else:
737
- # 低於最小值時給予更嚴厲的懲罰
738
- deficit_ratio = exercise_time / breed_level['min']
739
- return max(0.1, deficit_ratio * 0.5)
 
 
740
 
741
- # 運動類型匹配度評估
742
  def calculate_type_score():
743
- type_weight = breed_level['type_weights'].get(exercise_type, 0.5)
744
-
745
- # 根據運動需求等級調整類型權重
746
- if breed_needs.upper() in ['VERY HIGH', 'HIGH']:
747
- if exercise_type == 'light_walks':
748
- type_weight *= 0.5 # 高需求品種做輕度運動的懲罰
749
- elif breed_needs.upper() == 'LOW':
750
- if exercise_type == 'active_training':
751
- type_weight *= 0.7 # 低需求品種做高強度運動的輕微懲罰
752
 
753
- return type_weight
 
 
 
 
 
 
 
 
754
 
755
  # 計算最終分數
756
  time_score = calculate_time_score()
757
  type_score = calculate_type_score()
758
 
759
- # 綜合評分,運動時間佔70%,類型佔30%
760
- final_score = (time_score * 0.7) + (type_score * 0.3)
761
-
762
- # 特殊情況調整
763
- if exercise_time < breed_level['min'] * 0.5: # 運動時間嚴重不足
 
 
 
 
 
 
 
 
 
 
 
764
  final_score *= 0.5
765
- elif exercise_time > breed_level['max'] * 1.5: # 運動時間過多
766
- final_score *= 0.7
767
 
768
  return max(0.1, min(1.0, final_score))
769
 
@@ -1583,41 +1572,132 @@ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreference
1583
  return max(0.2, min(1.0, base_score - trait_penalty))
1584
 
1585
  # 第三部分:生活環境評估
1586
- def evaluate_living_conditions():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1587
  size = breed_info['Size']
1588
  exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1589
-
1590
- # 空間需求矩陣
 
 
1591
  space_requirements = {
1592
  'apartment': {
1593
- 'Small': 1.0, 'Medium': 0.4, 'Large': 0.2, 'Giant': 0.1
 
 
 
1594
  },
1595
  'house_small': {
1596
- 'Small': 0.9, 'Medium': 1.0, 'Large': 0.5, 'Giant': 0.3
 
 
 
1597
  },
1598
  'house_large': {
1599
- 'Small': 0.8, 'Medium': 0.9, 'Large': 1.0, 'Giant': 1.0
 
 
 
1600
  }
1601
  }
1602
-
1603
  # 基礎空間分數
1604
- space_score = space_requirements.get(user_prefs.living_space,
1605
- space_requirements['house_small'])[size]
1606
-
1607
- # 活動空間需求調整
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1608
  if exercise_needs in ['HIGH', 'VERY HIGH']:
1609
  if user_prefs.living_space != 'house_large':
1610
- space_score *= 0.8
1611
-
1612
- # 院子可用性評估
1613
  yard_scores = {
1614
- 'no_yard': 0.7,
1615
- 'shared_yard': 0.85,
1616
  'private_yard': 1.0
1617
  }
1618
- space_score *= yard_scores.get(user_prefs.yard_access, 0.8)
1619
-
1620
- return space_score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1621
 
1622
  # 第四部分:品種特性評估
1623
  def evaluate_breed_traits():
@@ -1653,63 +1733,135 @@ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreference
1653
 
1654
  return perfect_matches
1655
 
1656
- def calculate_weights():
1657
  """
1658
- 1. 條件極端度對權重的影響
1659
- 2. 多重條件組合的權重調整
1660
- 3. 品種特性對權重分配的影響
 
 
 
 
1661
  """
1662
- # 基礎權重設定
1663
  base_weights = {
1664
- 'space': 0.20,
1665
- 'exercise': 0.20,
1666
- 'experience': 0.20,
1667
- 'grooming': 0.15,
1668
- 'noise': 0.15,
1669
- 'health': 0.10
1670
  }
1671
-
1672
- def analyze_condition_extremity():
1673
- """評估各條件的極端程度及其影響"""
 
 
 
1674
  extremities = {}
1675
-
1676
- # 運動時間極端度分析
1677
- def analyze_exercise_extremity():
1678
- if user_prefs.exercise_time <= 30:
1679
- return ('extremely_low', 0.9)
1680
- elif user_prefs.exercise_time <= 60:
1681
- return ('low', 0.7)
1682
- elif user_prefs.exercise_time >= 180:
1683
- return ('extremely_high', 0.9)
1684
- elif user_prefs.exercise_time >= 120:
1685
- return ('high', 0.7)
1686
- return ('moderate', 0.4)
1687
-
1688
- # 空間限制極端度分析
1689
- def analyze_space_extremity():
1690
- space_extremity = {
1691
- 'apartment': ('highly_restricted', 0.9),
1692
- 'house_small': ('restricted', 0.6),
1693
- 'house_large': ('spacious', 0.4)
1694
- }
1695
- return space_extremity.get(user_prefs.living_space, ('moderate', 0.5))
1696
-
1697
- # 經驗水平極端度分析
1698
- def analyze_experience_extremity():
1699
- experience_extremity = {
1700
- 'beginner': ('low', 0.8),
1701
- 'intermediate': ('moderate', 0.5),
1702
- 'advanced': ('high', 0.7)
1703
- }
1704
- return experience_extremity.get(user_prefs.experience_level, ('moderate', 0.5))
1705
 
1706
- # 整合各項極端度評估
1707
- extremities['exercise'] = analyze_exercise_extremity()
1708
- extremities['space'] = analyze_space_extremity()
1709
- extremities['experience'] = analyze_experience_extremity()
1710
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1711
  return extremities
1712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1713
  def calculate_weight_adjustments(extremities):
1714
  """
1715
  1. 高運動量時對耐力型犬種的偏好
@@ -1812,150 +1964,264 @@ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreference
1812
 
1813
  return final_weights
1814
 
1815
- def apply_special_case_adjustments(score):
1816
  """
 
1817
  1. 條件組合的協同效應
1818
- 2. 品種特性的特殊要求
1819
- 3. 極端情況的處理
 
 
 
 
 
 
 
 
1820
  """
1821
  severity_multiplier = 1.0
1822
-
1823
- def evaluate_spatial_exercise_combination():
1824
  """
1825
- 評估空間與運動需求的組合影響
1826
- 修改重點:移除對高運動需求的懲罰,只保留體型相關評估
 
 
 
1827
  """
1828
  multiplier = 1.0
1829
 
1830
  if user_prefs.living_space == 'apartment':
1831
- # 移除運動需求相關的懲罰
 
 
 
 
 
1832
 
1833
- # 只保留體型的基本評估,但降低懲罰程度
1834
  if breed_info['Size'] in ['Large', 'Giant']:
1835
- multiplier *= 0.7 # 從0.5提升到0.7,因為大型犬確實需要考慮空間限制
 
 
 
 
 
 
 
 
 
 
 
1836
 
1837
  return multiplier
1838
-
1839
- def evaluate_experience_combination():
1840
- """評估經驗需求的複合影響"""
 
 
 
 
 
1841
  multiplier = 1.0
1842
  temperament = breed_info.get('Temperament', '').lower()
1843
  care_level = breed_info.get('Care Level', 'MODERATE')
1844
 
1845
- # 新手飼主的特殊考量
1846
  if user_prefs.experience_level == 'beginner':
1847
- # 高難度品種的嚴格限制
1848
  if care_level == 'HIGH':
1849
  if user_prefs.has_children:
1850
- multiplier *= 0.5
1851
  else:
1852
- multiplier *= 0.6
1853
-
1854
- # 特殊性格特徵的影響
1855
- challenging_traits = ['independent', 'dominant', 'protective', 'strong-willed']
1856
- trait_count = sum(1 for trait in challenging_traits if trait in temperament)
1857
- if trait_count > 0:
1858
- multiplier *= (0.8 ** trait_count)
1859
-
1860
- # 進階飼主的特殊考量
1861
- elif user_prefs.experience_level == 'advanced':
1862
- if care_level == 'LOW' and breed_info.get('Exercise Needs') == 'LOW':
1863
- multiplier *= 0.9 # 對專家來說可能過於簡單
1864
-
 
 
1865
  return multiplier
1866
-
1867
- def evaluate_breed_specific_requirements():
1868
- """評估品種特定的要求,加強運動需求的判斷"""
 
 
 
 
 
1869
  multiplier = 1.0
1870
  exercise_time = user_prefs.exercise_time
1871
  exercise_type = user_prefs.exercise_type
1872
 
1873
- # 檢查品種的基本特性
1874
  temperament = breed_info.get('Temperament', '').lower()
1875
  description = breed_info.get('Description', '').lower()
1876
  exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1877
 
1878
- # 加強運動需求的匹配判斷
1879
  if exercise_needs == 'LOW':
1880
- if exercise_time > 90: # 如果用戶運動時間過長
1881
- multiplier *= 0.5 # 給予更強的懲罰
1882
  elif exercise_needs == 'VERY HIGH':
1883
- if exercise_time < 60: # 如果用戶運動時間過短
1884
- multiplier *= 0.5
1885
-
 
1886
  if 'sprint' in temperament:
1887
  if exercise_time > 120 and exercise_type != 'active_training':
1888
- multiplier *= 0.7
1889
 
1890
  if any(trait in temperament for trait in ['working', 'herding']):
1891
  if exercise_time < 90 or exercise_type == 'light_walks':
1892
- multiplier *= 0.7
1893
-
1894
- return multiplier
1895
-
1896
- def evaluate_environmental_impact():
1897
- """評估環境因素的影響"""
1898
- multiplier = 1.0
1899
 
1900
- # 時間限制的影響
1901
- if user_prefs.time_availability == 'limited':
1902
- if breed_info.get('Exercise Needs').upper() in ['VERY HIGH', 'HIGH']:
1903
- multiplier *= 0.7
1904
-
1905
- # 噪音敏感度的影響
1906
- if user_prefs.noise_tolerance == 'low':
1907
- if breed_info.get('Breed') in breed_noise_info:
1908
- if breed_noise_info[breed_info['Breed']]['noise_level'].lower() == 'high':
1909
- multiplier *= 0.6
1910
-
1911
  return multiplier
1912
 
1913
- # 整合所有特殊情況的評估
1914
- severity_multiplier *= evaluate_spatial_exercise_combination()
1915
- severity_multiplier *= evaluate_experience_combination()
1916
- severity_multiplier *= evaluate_breed_specific_requirements()
1917
- severity_multiplier *= evaluate_environmental_impact()
1918
 
1919
- # 確保最終分數在合理範圍內
 
 
 
 
 
1920
  final_score = score * severity_multiplier
1921
  return max(0.2, min(1.0, final_score))
1922
 
1923
  def calculate_base_score(scores: dict, weights: dict) -> float:
1924
  """
1925
- 計算基礎分數,更寬容地處理極端組合
1926
- """
1927
- # 進一步降低關鍵指標閾值,使系統更包容極端組合
1928
- critical_thresholds = {
1929
- 'space': 0.45, # 進一步降低閾值
1930
- 'exercise': 0.45,
1931
- 'experience': 0.55,
1932
- 'noise': 0.55
1933
- }
1934
 
1935
- critical_failures = []
1936
- for metric, threshold in critical_thresholds.items():
1937
- if scores[metric] < threshold:
1938
- critical_failures.append((metric, scores[metric]))
 
1939
 
1940
- base_score = sum(scores[k] * weights[k] for k in scores.keys())
 
 
1941
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1942
  if critical_failures:
 
1943
  space_exercise_penalty = 0
1944
  other_penalty = 0
1945
 
1946
  for metric, score in critical_failures:
1947
  if metric in ['space', 'exercise']:
1948
- space_exercise_penalty += (critical_thresholds[metric] - score) * 0.15 # 降低懲罰
 
 
1949
  else:
1950
- other_penalty += (critical_thresholds[metric] - score) * 0.3
1951
-
 
 
 
1952
  total_penalty = (space_exercise_penalty + other_penalty) / 2
1953
  base_score *= (1 - total_penalty)
1954
-
 
1955
  if len(critical_failures) > 1:
1956
- base_score *= (0.98 ** (len(critical_failures) - 1)) # 進一步降低多重失敗懲罰
1957
-
1958
- return base_score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1959
 
1960
 
1961
  def evaluate_condition_interactions(scores: dict) -> float:
@@ -2056,27 +2322,148 @@ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreference
2056
  return min(max_possible_score, max(min_possible_score, final_score))
2057
 
2058
  def amplify_score_extreme(score: float) -> float:
2059
- """優化分數分布,提供更高的分數範圍"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2060
  def smooth_curve(x: float, steepness: float = 12) -> float:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2061
  import math
2062
  return 1 / (1 + math.exp(-steepness * (x - 0.5)))
2063
 
2064
- if score >= 0.9:
2065
- position = (score - 0.9) / 0.1
2066
- return 0.96 + (position * 0.04) # 90-100的原始分映射到96-100
2067
 
2068
- elif score >= 0.8:
2069
- position = (score - 0.8) / 0.1
2070
- return 0.90 + (position * 0.06) # 80-90的原始分映射到90-96
2071
 
2072
- elif score >= 0.7:
2073
- position = (score - 0.7) / 0.1
2074
- return 0.82 + (position * 0.08) # 70-80的原始分映射到82-90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2075
 
2076
- elif score >= 0.5:
2077
- position = (score - 0.5) / 0.2
2078
- return 0.75 + (smooth_curve(position) * 0.07) # 50-70的原始分映射到75-82
2079
 
2080
- else:
2081
- position = score / 0.5
2082
- return 0.70 + (smooth_curve(position) * 0.05) # 50以下的原始分映射到70-75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
632
 
633
  def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
634
  """
635
+ 計算品種運動需求與使用者運動條件的匹配度。此函數特別著重:
636
+ 1. 不同品種的運動耐受度差異
637
+ 2. 運動時間與類型的匹配度
638
+ 3. 極端運動量的嚴格限制
639
+
640
+ Parameters:
641
+ breed_needs: 品種的運動需求等級
642
+ exercise_time: 使用者計劃的運動時間(分鐘)
643
+ exercise_type: 運動類型(輕度/中度/高度)
644
+
645
+ Returns:
646
+ float: 0.1到1.0之間的匹配分數
647
  """
648
+ # 定義每個運動需求等級的具體參數
649
  exercise_levels = {
650
  'VERY HIGH': {
651
+ 'min': 120, # 最低需求
652
+ 'ideal': 150, # 理想運動量
653
+ 'max': 180, # 最大建議量
654
+ 'type_weights': { # 不同運動類型的權重
 
 
 
655
  'active_training': 1.0,
656
  'moderate_activity': 0.6,
657
  'light_walks': 0.3
 
661
  'min': 90,
662
  'ideal': 120,
663
  'max': 150,
 
 
 
664
  'type_weights': {
665
  'active_training': 0.9,
666
  'moderate_activity': 0.8,
667
  'light_walks': 0.4
668
  }
669
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
670
  'MODERATE': {
671
  'min': 45,
672
  'ideal': 60,
673
  'max': 90,
 
 
 
674
  'type_weights': {
675
  'active_training': 0.7,
676
  'moderate_activity': 1.0,
677
  'light_walks': 0.8
678
  }
679
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
680
  'LOW': {
681
  'min': 15,
682
  'ideal': 30,
683
  'max': 45,
 
 
 
684
  'type_weights': {
685
  'active_training': 0.5,
686
  'moderate_activity': 0.8,
 
689
  }
690
  }
691
 
692
+ # 獲取品種的運動參數
693
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
694
 
695
+ # 計算時間匹配度
696
  def calculate_time_score():
697
+ """計算運動時間的匹配度,特別處理過度運動的情況"""
698
+ if exercise_time < breed_level['min']:
699
+ # 運動不足的嚴格懲罰
700
+ deficit_ratio = exercise_time / breed_level['min']
701
+ return max(0.1, deficit_ratio * 0.4)
702
+
703
+ elif exercise_time <= breed_level['ideal']:
704
+ # 理想範圍內的漸進提升
705
  progress = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
706
+ return 0.6 + (progress * 0.4)
707
+
708
+ elif exercise_time <= breed_level['max']:
709
+ # 理想到最大範圍的平緩下降
710
+ excess_ratio = (exercise_time - breed_level['ideal']) / (breed_level['max'] - breed_level['ideal'])
711
+ return 1.0 - (excess_ratio * 0.2)
712
+
713
  else:
714
+ # 過度運動的顯著懲罰
715
+ excess = (exercise_time - breed_level['max']) / breed_level['max']
716
+ # 低運動需求品種的過度運動懲罰更嚴重
717
+ penalty_factor = 1.5 if breed_needs.upper() == 'LOW' else 1.0
718
+ return max(0.1, 0.8 - (excess * 0.5 * penalty_factor))
719
 
720
+ # 計算運動類型匹配度
721
  def calculate_type_score():
722
+ """評估運動類型的適合度,考慮品種特性"""
723
+ base_type_score = breed_level['type_weights'].get(exercise_type, 0.5)
 
 
 
 
 
 
 
724
 
725
+ # 特殊情況處理
726
+ if breed_needs.upper() == 'LOW' and exercise_type == 'active_training':
727
+ # 低運動需求品種不適合高強度運動
728
+ base_type_score *= 0.5
729
+ elif breed_needs.upper() == 'VERY HIGH' and exercise_type == 'light_walks':
730
+ # 高運動需求品種需要更多強度
731
+ base_type_score *= 0.6
732
+
733
+ return base_type_score
734
 
735
  # 計算最終分數
736
  time_score = calculate_time_score()
737
  type_score = calculate_type_score()
738
 
739
+ # 根據運動需求等級調整權重
740
+ if breed_needs.upper() == 'LOW':
741
+ # 低運動需求品種更重視運動類型的合適性
742
+ final_score = (time_score * 0.6) + (type_score * 0.4)
743
+ elif breed_needs.upper() == 'VERY HIGH':
744
+ # 高運動需求品種更重視運動時間的充足性
745
+ final_score = (time_score * 0.7) + (type_score * 0.3)
746
+ else:
747
+ final_score = (time_score * 0.65) + (type_score * 0.35)
748
+
749
+ # 極端情況的最終調整
750
+ if breed_needs.upper() == 'LOW' and exercise_time > breed_level['max'] * 2:
751
+ # 低運動需求品種的過度運動顯著降分
752
+ final_score *= 0.6
753
+ elif breed_needs.upper() == 'VERY HIGH' and exercise_time < breed_level['min'] * 0.5:
754
+ # 高運動需求品種運動嚴重不足降分
755
  final_score *= 0.5
 
 
756
 
757
  return max(0.1, min(1.0, final_score))
758
 
 
1572
  return max(0.2, min(1.0, base_score - trait_penalty))
1573
 
1574
  # 第三部分:生活環境評估
1575
+ # def evaluate_living_conditions():
1576
+ # size = breed_info['Size']
1577
+ # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1578
+
1579
+ # # 空間需求矩陣
1580
+ # space_requirements = {
1581
+ # 'apartment': {
1582
+ # 'Small': 1.0, 'Medium': 0.4, 'Large': 0.2, 'Giant': 0.1
1583
+ # },
1584
+ # 'house_small': {
1585
+ # 'Small': 0.9, 'Medium': 1.0, 'Large': 0.5, 'Giant': 0.3
1586
+ # },
1587
+ # 'house_large': {
1588
+ # 'Small': 0.8, 'Medium': 0.9, 'Large': 1.0, 'Giant': 1.0
1589
+ # }
1590
+ # }
1591
+
1592
+ # # 基礎空間分數
1593
+ # space_score = space_requirements.get(user_prefs.living_space,
1594
+ # space_requirements['house_small'])[size]
1595
+
1596
+ # # 活動空間需求調整
1597
+ # if exercise_needs in ['HIGH', 'VERY HIGH']:
1598
+ # if user_prefs.living_space != 'house_large':
1599
+ # space_score *= 0.8
1600
+
1601
+ # # 院子可用性評估
1602
+ # yard_scores = {
1603
+ # 'no_yard': 0.7,
1604
+ # 'shared_yard': 0.85,
1605
+ # 'private_yard': 1.0
1606
+ # }
1607
+ # space_score *= yard_scores.get(user_prefs.yard_access, 0.8)
1608
+
1609
+ # return space_score
1610
+
1611
+ def evaluate_living_conditions() -> float:
1612
+ """
1613
+ 評估生活環境適配性,特別加強:
1614
+ 1. 降低對大型犬的過度懲罰
1615
+ 2. 增加品種特性評估
1616
+ 3. 提升對適應性的重視度
1617
+ """
1618
  size = breed_info['Size']
1619
  exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1620
+ temperament = breed_info.get('Temperament', '').lower()
1621
+ description = breed_info.get('Description', '').lower()
1622
+
1623
+ # 重新定義空間需求矩陣,降低對大型犬的懲罰
1624
  space_requirements = {
1625
  'apartment': {
1626
+ 'Small': 1.0,
1627
+ 'Medium': 0.7, # 從0.4提升到0.7
1628
+ 'Large': 0.6, # 從0.2提升到0.6
1629
+ 'Giant': 0.5 # 從0.1提升到0.5
1630
  },
1631
  'house_small': {
1632
+ 'Small': 0.9,
1633
+ 'Medium': 1.0,
1634
+ 'Large': 0.8, # 從0.5提升到0.8
1635
+ 'Giant': 0.7 # 從0.3提升到0.7
1636
  },
1637
  'house_large': {
1638
+ 'Small': 0.8,
1639
+ 'Medium': 0.9,
1640
+ 'Large': 1.0,
1641
+ 'Giant': 1.0
1642
  }
1643
  }
1644
+
1645
  # 基礎空間分數
1646
+ space_score = space_requirements.get(
1647
+ user_prefs.living_space,
1648
+ space_requirements['house_small']
1649
+ )[size]
1650
+
1651
+ # 品種適應性評估
1652
+ adaptability_bonus = 0
1653
+ adaptable_traits = ['adaptable', 'calm', 'quiet', 'gentle', 'laid-back']
1654
+ challenging_traits = ['hyperactive', 'restless', 'requires space']
1655
+
1656
+ # 計算適應性加分
1657
+ if user_prefs.living_space == 'apartment':
1658
+ for trait in adaptable_traits:
1659
+ if trait in temperament or trait in description:
1660
+ adaptability_bonus += 0.1
1661
+
1662
+ # 特別處理大型犬的適應性
1663
+ if size in ['Large', 'Giant']:
1664
+ apartment_friendly_traits = ['calm', 'gentle', 'quiet']
1665
+ matched_traits = sum(1 for trait in apartment_friendly_traits
1666
+ if trait in temperament or trait in description)
1667
+ if matched_traits > 0:
1668
+ adaptability_bonus += 0.15 * matched_traits
1669
+
1670
+ # 活動空間需求調整,更寬容的評估
1671
  if exercise_needs in ['HIGH', 'VERY HIGH']:
1672
  if user_prefs.living_space != 'house_large':
1673
+ space_score *= 0.9 # 從0.8提升到0.9,降低懲罰
1674
+
1675
+ # 院子可用性評估,提供更合理的獎勵
1676
  yard_scores = {
1677
+ 'no_yard': 0.85, # 從0.7提升到0.85
1678
+ 'shared_yard': 0.92, # 從0.85提升到0.92
1679
  'private_yard': 1.0
1680
  }
1681
+ yard_multiplier = yard_scores.get(user_prefs.yard_access, 0.85)
1682
+
1683
+ # 根據體型調整院子重要性
1684
+ if size in ['Large', 'Giant']:
1685
+ yard_importance = 1.2
1686
+ elif size == 'Medium':
1687
+ yard_importance = 1.1
1688
+ else:
1689
+ yard_importance = 1.0
1690
+
1691
+ # 計算最終分數
1692
+ final_score = space_score * (1 + adaptability_bonus)
1693
+
1694
+ # 應用院子影響
1695
+ if user_prefs.yard_access != 'no_yard':
1696
+ yard_bonus = (yard_multiplier - 1) * yard_importance
1697
+ final_score = min(1.0, final_score + yard_bonus)
1698
+
1699
+ # 確保分數在合理範圍內,但提供更高的基礎分數
1700
+ return max(0.4, min(1.0, final_score))
1701
 
1702
  # 第四部分:品種特性評估
1703
  def evaluate_breed_traits():
 
1733
 
1734
  return perfect_matches
1735
 
1736
+ def calculate_weights() -> dict:
1737
  """
1738
+ 動態計算評分權重,特別關注:
1739
+ 1. 極端情況的權重調整
1740
+ 2. 使用者條件的協同效應
1741
+ 3. 品種特性的影響
1742
+
1743
+ Returns:
1744
+ dict: 包含各評分項目權重的字典
1745
  """
1746
+ # 定義基礎權重 - 提供更合理的起始分配
1747
  base_weights = {
1748
+ 'space': 0.25, # 提升空間權重,因為這是最基本的需求
1749
+ 'exercise': 0.25, # 運動需求同樣重要
1750
+ 'experience': 0.20, # 保持經驗的重要性
1751
+ 'grooming': 0.10, # 稍微降低美容需求的權重
1752
+ 'noise': 0.10, # 維持噪音評估的權重
1753
+ 'health': 0.10 # 維持健康評估的權重
1754
  }
1755
+
1756
+ def analyze_condition_extremity() -> dict:
1757
+ """
1758
+ 評估使用者條件的極端程度,這影響權重的動態調整。
1759
+ 根據條件的極端程度返回相應的調整建議。
1760
+ """
1761
  extremities = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1762
 
1763
+ # 運動時間評估 - 更細緻的分級
1764
+ if user_prefs.exercise_time <= 30:
1765
+ extremities['exercise'] = ('extremely_low', 0.8)
1766
+ elif user_prefs.exercise_time <= 60:
1767
+ extremities['exercise'] = ('low', 0.6)
1768
+ elif user_prefs.exercise_time >= 180:
1769
+ extremities['exercise'] = ('extremely_high', 0.8)
1770
+ elif user_prefs.exercise_time >= 120:
1771
+ extremities['exercise'] = ('high', 0.6)
1772
+ else:
1773
+ extremities['exercise'] = ('moderate', 0.3)
1774
+
1775
+ # 空間限制評估 - 更合理的空間評估
1776
+ space_extremity = {
1777
+ 'apartment': ('restricted', 0.7), # 從0.9降低到0.7,減少限制
1778
+ 'house_small': ('moderate', 0.5),
1779
+ 'house_large': ('spacious', 0.3)
1780
+ }
1781
+ extremities['space'] = space_extremity.get(user_prefs.living_space, ('moderate', 0.5))
1782
+
1783
+ # 經驗水平評估 - 保持原有的評估邏輯
1784
+ experience_extremity = {
1785
+ 'beginner': ('low', 0.7),
1786
+ 'intermediate': ('moderate', 0.4),
1787
+ 'advanced': ('high', 0.6)
1788
+ }
1789
+ extremities['experience'] = experience_extremity.get(user_prefs.experience_level, ('moderate', 0.5))
1790
+
1791
  return extremities
1792
 
1793
+ def calculate_weight_adjustments(extremities: dict) -> dict:
1794
+ """
1795
+ 根據極端程度計算權重調整,特別注意條件組合的影響。
1796
+ """
1797
+ adjustments = {}
1798
+ temperament = breed_info.get('Temperament', '').lower()
1799
+ is_working_dog = any(trait in temperament
1800
+ for trait in ['herding', 'working', 'intelligent', 'tireless'])
1801
+
1802
+ # 空間權重調整 - 更平衡的調整方式
1803
+ if extremities['space'][0] == 'restricted':
1804
+ if extremities['exercise'][0] in ['high', 'extremely_high']:
1805
+ adjustments['space'] = 1.5 # 從1.8降低到1.5
1806
+ adjustments['exercise'] = 1.8 # 從2.5降低到1.8
1807
+ else:
1808
+ adjustments['space'] = 1.6 # 從2.5降低到1.6
1809
+ adjustments['noise'] = 1.5 # 保持合理的噪音權重
1810
+
1811
+ # 運動需求權重調整 - 更合理的運動評估
1812
+ if extremities['exercise'][0] in ['extremely_high', 'extremely_low']:
1813
+ base_adjustment = 1.8 # 從2.5降低到1.8
1814
+ if extremities['exercise'][0] == 'extremely_high':
1815
+ if is_working_dog:
1816
+ base_adjustment = 2.0 # 從3.0降低到2.0
1817
+ adjustments['exercise'] = base_adjustment
1818
+
1819
+ # 經驗需求權重調整 - 維持原有的評估邏輯
1820
+ if extremities['experience'][0] == 'low':
1821
+ adjustments['experience'] = 1.8
1822
+ if breed_info.get('Care Level') == 'HIGH':
1823
+ adjustments['experience'] = 2.0
1824
+ elif extremities['experience'][0] == 'high':
1825
+ if is_working_dog:
1826
+ adjustments['experience'] = 1.8 # 從2.5降低到1.8
1827
+
1828
+ # 特殊組合的處理
1829
+ def adjust_for_combinations():
1830
+ if (extremities['space'][0] == 'restricted' and
1831
+ extremities['exercise'][0] in ['high', 'extremely_high']):
1832
+ # 適度降低極端組合的影響
1833
+ adjustments['space'] = adjustments.get('space', 1.0) * 1.2
1834
+ adjustments['exercise'] = adjustments.get('exercise', 1.0) * 1.2
1835
+
1836
+ # 理想組合的獎勵
1837
+ if (extremities['experience'][0] == 'high' and
1838
+ extremities['space'][0] == 'spacious' and
1839
+ extremities['exercise'][0] in ['high', 'extremely_high'] and
1840
+ is_working_dog):
1841
+ adjustments['exercise'] = adjustments.get('exercise', 1.0) * 1.3
1842
+ adjustments['experience'] = adjustments.get('experience', 1.0) * 1.3
1843
+
1844
+ adjust_for_combinations()
1845
+ return adjustments
1846
+
1847
+ # 獲取條件極端度
1848
+ extremities = analyze_condition_extremity()
1849
+
1850
+ # 計算權重調整
1851
+ weight_adjustments = calculate_weight_adjustments(extremities)
1852
+
1853
+ # 應用權重調整,確保總和為1
1854
+ final_weights = base_weights.copy()
1855
+ for key, adjustment in weight_adjustments.items():
1856
+ if key in final_weights:
1857
+ final_weights[key] *= adjustment
1858
+
1859
+ # 正規化權重
1860
+ total_weight = sum(final_weights.values())
1861
+ normalized_weights = {k: v/total_weight for k, v in final_weights.items()}
1862
+
1863
+ return normalized_weights
1864
+
1865
  def calculate_weight_adjustments(extremities):
1866
  """
1867
  1. 高運動量時對耐力型犬種的偏好
 
1964
 
1965
  return final_weights
1966
 
1967
+ def apply_special_case_adjustments(score: float) -> float:
1968
  """
1969
+ 處理特殊情況和極端案例的評分調整。這個函數特別關注:
1970
  1. 條件組合的協同效應
1971
+ 2. 品種特性的獨特需求
1972
+ 3. 極端情況的合理處理
1973
+
1974
+ 這個函數就像是一個細心的裁判,會考慮到各種特殊情況,
1975
+ 並根據具體場景做出合理的評分調整。
1976
+
1977
+ Parameters:
1978
+ score: 初始評分
1979
+ Returns:
1980
+ float: 調整後的評分(0.2-1.0之間)
1981
  """
1982
  severity_multiplier = 1.0
1983
+
1984
+ def evaluate_spatial_exercise_combination() -> float:
1985
  """
1986
+ 評估空間與運動需求的組合效應。
1987
+
1988
+ 這個函數不再過分懲罰大型犬,而是更多地考慮品種的實際特性。
1989
+ 就像評估一個運動員是否適合在特定場地訓練一樣,我們需要考慮
1990
+ 場地大小和運動需求的整體匹配度。
1991
  """
1992
  multiplier = 1.0
1993
 
1994
  if user_prefs.living_space == 'apartment':
1995
+ temperament = breed_info.get('Temperament', '').lower()
1996
+ description = breed_info.get('Description', '').lower()
1997
+
1998
+ # 檢查品種是否有利於公寓生活的特徵
1999
+ apartment_friendly = any(trait in temperament or trait in description
2000
+ for trait in ['calm', 'adaptable', 'quiet'])
2001
 
2002
+ # 大型犬的特殊處理
2003
  if breed_info['Size'] in ['Large', 'Giant']:
2004
+ if apartment_friendly:
2005
+ multiplier *= 0.85 # 從0.7提升到0.85,降低懲罰
2006
+ else:
2007
+ multiplier *= 0.75 # 從0.5提升到0.75
2008
+
2009
+ # 檢查運動需求的匹配度
2010
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
2011
+ exercise_time = user_prefs.exercise_time
2012
+
2013
+ if exercise_needs in ['HIGH', 'VERY HIGH']:
2014
+ if exercise_time >= 120: # 高運動量可以部分補償空間限制
2015
+ multiplier *= 1.1
2016
 
2017
  return multiplier
2018
+
2019
+ def evaluate_experience_combination() -> float:
2020
+ """
2021
+ 評估經驗需求的複合影響。
2022
+
2023
+ 這個函數就像是評估一個工作崗位與應聘者經驗的匹配度,
2024
+ 需要綜合考慮工作難度和應聘者能力。
2025
+ """
2026
  multiplier = 1.0
2027
  temperament = breed_info.get('Temperament', '').lower()
2028
  care_level = breed_info.get('Care Level', 'MODERATE')
2029
 
2030
+ # 新手飼主的特殊考慮,更寬容的評估標準
2031
  if user_prefs.experience_level == 'beginner':
 
2032
  if care_level == 'HIGH':
2033
  if user_prefs.has_children:
2034
+ multiplier *= 0.7 # 從0.5提升到0.7
2035
  else:
2036
+ multiplier *= 0.8 # 從0.6提升到0.8
2037
+
2038
+ # 性格特徵影響,降低懲罰程度
2039
+ challenging_traits = {
2040
+ 'stubborn': -0.10, # 從-0.15降低
2041
+ 'independent': -0.08, # 從-0.12降低
2042
+ 'dominant': -0.08, # 從-0.12降低
2043
+ 'protective': -0.06, # 從-0.10降低
2044
+ 'aggressive': -0.15 # 保持較高懲罰因安全考慮
2045
+ }
2046
+
2047
+ for trait, penalty in challenging_traits.items():
2048
+ if trait in temperament:
2049
+ multiplier *= (1 + penalty)
2050
+
2051
  return multiplier
2052
+
2053
+ def evaluate_breed_specific_requirements() -> float:
2054
+ """
2055
+ 評估品種特定需求。
2056
+
2057
+ 這個函數就像是為每個品種量身定制評估標準,
2058
+ 考慮其獨特的特性和需求。
2059
+ """
2060
  multiplier = 1.0
2061
  exercise_time = user_prefs.exercise_time
2062
  exercise_type = user_prefs.exercise_type
2063
 
2064
+ # 檢查品種特性
2065
  temperament = breed_info.get('Temperament', '').lower()
2066
  description = breed_info.get('Description', '').lower()
2067
  exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
2068
 
2069
+ # 運動需求匹配度評估,更合理的標準
2070
  if exercise_needs == 'LOW':
2071
+ if exercise_time > 120:
2072
+ multiplier *= 0.85 # 從0.5提升到0.85
2073
  elif exercise_needs == 'VERY HIGH':
2074
+ if exercise_time < 60:
2075
+ multiplier *= 0.7 # 從0.5提升到0.7
2076
+
2077
+ # 特殊品種類型的考慮
2078
  if 'sprint' in temperament:
2079
  if exercise_time > 120 and exercise_type != 'active_training':
2080
+ multiplier *= 0.85 # 從0.7提升到0.85
2081
 
2082
  if any(trait in temperament for trait in ['working', 'herding']):
2083
  if exercise_time < 90 or exercise_type == 'light_walks':
2084
+ multiplier *= 0.8 # 從0.7提升到0.8
 
 
 
 
 
 
2085
 
 
 
 
 
 
 
 
 
 
 
 
2086
  return multiplier
2087
 
2088
+ # 計算各項調整
2089
+ space_exercise_mult = evaluate_spatial_exercise_combination()
2090
+ experience_mult = evaluate_experience_combination()
2091
+ breed_specific_mult = evaluate_breed_specific_requirements()
 
2092
 
2093
+ # 整合所有調整因素
2094
+ severity_multiplier *= space_exercise_mult
2095
+ severity_multiplier *= experience_mult
2096
+ severity_multiplier *= breed_specific_mult
2097
+
2098
+ # 應用最終調整,確保分數在合理範圍內
2099
  final_score = score * severity_multiplier
2100
  return max(0.2, min(1.0, final_score))
2101
 
2102
  def calculate_base_score(scores: dict, weights: dict) -> float:
2103
  """
2104
+ 計算基礎評分分數,採用更靈活的評分機制。
 
 
 
 
 
 
 
 
2105
 
2106
+ 這個函數使用了改進後的評分邏輯,主要關注:
2107
+ 1. 降低關鍵指標的最低門檻,使系統更包容
2108
+ 2. 引入非線性評分曲線,讓分數分布更合理
2109
+ 3. 優化多重條件失敗的處理方式
2110
+ 4. 加強對品種特性的考慮
2111
 
2112
+ Parameters:
2113
+ scores: 包含各項評���的字典
2114
+ weights: 包含各項權重的字典
2115
 
2116
+ Returns:
2117
+ float: 0.2到1.0之間的基礎分數
2118
+ """
2119
+ # 重新定義關鍵指標閾值,提供更寬容的評分標準
2120
+ critical_thresholds = {
2121
+ 'space': 0.4, # 從0.45降低到0.4
2122
+ 'exercise': 0.4, # 從0.45降低到0.4
2123
+ 'experience': 0.5, # 從0.55降低到0.5
2124
+ 'noise': 0.5 # 保持不變,因為噪音確實是重要考慮因素
2125
+ }
2126
+
2127
+ # 評估關鍵指標失敗情況
2128
+ def evaluate_critical_failures() -> list:
2129
+ """
2130
+ 評估關鍵指標的失敗情況,但採用更寬容的標準。
2131
+ 根據品種特性動態調整失敗判定。
2132
+ """
2133
+ failures = []
2134
+ temperament = breed_info.get('Temperament', '').lower()
2135
+
2136
+ for metric, threshold in critical_thresholds.items():
2137
+ if scores[metric] < threshold:
2138
+ # 特殊情況處理:適應性強的品種可以有更低的空間要求
2139
+ if metric == 'space' and any(trait in temperament
2140
+ for trait in ['adaptable', 'calm', 'apartment']):
2141
+ if scores[metric] >= threshold - 0.1:
2142
+ continue
2143
+
2144
+ # 運動需求的特殊處理
2145
+ elif metric == 'exercise':
2146
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
2147
+ if exercise_needs == 'LOW' and scores[metric] >= threshold - 0.1:
2148
+ continue
2149
+
2150
+ failures.append((metric, scores[metric]))
2151
+
2152
+ return failures
2153
+
2154
+ # 計算基礎分數
2155
+ def calculate_weighted_score() -> float:
2156
+ """
2157
+ 計算加權分數,使用非線性函數使分數分布更合理。
2158
+ """
2159
+ weighted_scores = []
2160
+ for key, score in scores.items():
2161
+ if key in weights:
2162
+ # 使用sigmoid函數使分數曲線更平滑
2163
+ adjusted_score = 1 / (1 + math.exp(-10 * (score - 0.5)))
2164
+ weighted_scores.append(adjusted_score * weights[key])
2165
+
2166
+ return sum(weighted_scores)
2167
+
2168
+ # 處理臨界失敗情況
2169
+ critical_failures = evaluate_critical_failures()
2170
+ base_score = calculate_weighted_score()
2171
+
2172
  if critical_failures:
2173
+ # 分離空間和運動相關的懲罰
2174
  space_exercise_penalty = 0
2175
  other_penalty = 0
2176
 
2177
  for metric, score in critical_failures:
2178
  if metric in ['space', 'exercise']:
2179
+ # 降低空間和運動失敗的懲罰程度
2180
+ penalty = (critical_thresholds[metric] - score) * 0.12 # 從0.15降低到0.12
2181
+ space_exercise_penalty += penalty
2182
  else:
2183
+ # 其他失敗的懲罰保持較高
2184
+ penalty = (critical_thresholds[metric] - score) * 0.25 # 從0.3降低到0.25
2185
+ other_penalty += penalty
2186
+
2187
+ # 計算總懲罰,但使用更溫和的方式
2188
  total_penalty = (space_exercise_penalty + other_penalty) / 2
2189
  base_score *= (1 - total_penalty)
2190
+
2191
+ # 多重失敗的處理更寬容
2192
  if len(critical_failures) > 1:
2193
+ # 0.98提升到0.99,降低多重失敗的疊加懲罰
2194
+ base_score *= (0.99 ** (len(critical_failures) - 1))
2195
+
2196
+ # 品種特性加分
2197
+ def apply_breed_bonus() -> float:
2198
+ """
2199
+ 根據品種特性提供額外加分,
2200
+ 特別是對於在特定環境下表現良好的品種。
2201
+ """
2202
+ bonus = 0
2203
+ temperament = breed_info.get('Temperament', '').lower()
2204
+ description = breed_info.get('Description', '').lower()
2205
+
2206
+ # 適應性加分
2207
+ adaptability_traits = ['adaptable', 'versatile', 'easy-going']
2208
+ if any(trait in temperament for trait in adaptability_traits):
2209
+ bonus += 0.05
2210
+
2211
+ # 公寓適應性加分
2212
+ if user_prefs.living_space == 'apartment':
2213
+ apartment_traits = ['calm', 'quiet', 'good for apartments']
2214
+ if any(trait in temperament or trait in description for trait in apartment_traits):
2215
+ bonus += 0.05
2216
+
2217
+ return min(0.1, bonus) # 限制最大加分
2218
+
2219
+ # 應用品種特性加分
2220
+ breed_bonus = apply_breed_bonus()
2221
+ base_score = min(1.0, base_score * (1 + breed_bonus))
2222
+
2223
+ # 確保最終分數在合理範圍內
2224
+ return max(0.2, min(1.0, base_score))
2225
 
2226
 
2227
  def evaluate_condition_interactions(scores: dict) -> float:
 
2322
  return min(max_possible_score, max(min_possible_score, final_score))
2323
 
2324
  def amplify_score_extreme(score: float) -> float:
2325
+ """
2326
+ 優化分數分布,提供更有意義的評分範圍。
2327
+
2328
+ 這個函數就像是一個分數校準器,它的作用類似於相機的色彩校準,
2329
+ 讓原始的分數分布能更好地反映實際的匹配程度。比如,一個90分的匹配
2330
+ 應該確實代表一個非常好的搭配,而不是一個僅僅"還可以"的選擇。
2331
+
2332
+ 我們使用分段函數和平滑曲線來實現這個目標:
2333
+ - 90-100分代表極佳匹配(映射到96-100)
2334
+ - 80-90分代表優秀匹配(映射到90-96)
2335
+ - 70-80分代表良好匹配(映射到82-90)
2336
+ - 50-70分代表可接受匹配(映射到75-82)
2337
+ - 50分以下代表較差匹配(映射到70-75)
2338
+
2339
+ Parameters:
2340
+ score: 原始評分(0-1之間的浮點數)
2341
+
2342
+ Returns:
2343
+ float: 調整後的評分(0-1之間的浮點數)
2344
+ """
2345
  def smooth_curve(x: float, steepness: float = 12) -> float:
2346
+ """
2347
+ 創建平滑的S型曲線用於分數轉換。
2348
+
2349
+ 這個函數使用sigmoid函數來產生平滑的轉換曲線,避免分數在
2350
+ 不同區間之間產生突兀的跳變。就像是在照片編輯中,我們會使用
2351
+ 漸變而不是突變來調整色調。
2352
+
2353
+ Parameters:
2354
+ x: 輸入值(0-1之間)
2355
+ steepness: 曲線的陡峭程度,越大曲線越陡
2356
+
2357
+ Returns:
2358
+ float: 轉換後的值(0-1之間)
2359
+ """
2360
  import math
2361
  return 1 / (1 + math.exp(-steepness * (x - 0.5)))
2362
 
2363
+ def apply_range_mapping(score: float) -> float:
2364
+ """
2365
+ 將分數映射到新的範圍,並保持平滑過渡。
2366
 
2367
+ 這個函數負責將原始分數轉換到新的分數範圍。就像是將溫度從
2368
+ 攝氏度轉換到華氏度,但要保持溫度變化的連續性。
 
2369
 
2370
+ Parameters:
2371
+ score: 原始分數
2372
+
2373
+ Returns:
2374
+ float: 映射後的分數
2375
+ """
2376
+ # 極佳匹配區間(90-100)
2377
+ if score >= 0.90:
2378
+ # 計算在當前區間內的相對位置
2379
+ position = (score - 0.90) / 0.10
2380
+ # 映射到96-100的範圍
2381
+ return 0.96 + (position * 0.04)
2382
+
2383
+ # 優秀匹配區間(80-90)
2384
+ elif score >= 0.80:
2385
+ position = (score - 0.80) / 0.10
2386
+ # 使用平滑曲線進行轉換
2387
+ transition = smooth_curve(position)
2388
+ return 0.90 + (transition * 0.06)
2389
+
2390
+ # 良好匹配區間(70-80)
2391
+ elif score >= 0.70:
2392
+ position = (score - 0.70) / 0.10
2393
+ # 加入輕微的非線性轉換
2394
+ return 0.82 + (math.pow(position, 0.9) * 0.08)
2395
+
2396
+ # 可接受匹配區間(50-70)
2397
+ elif score >= 0.50:
2398
+ position = (score - 0.50) / 0.20
2399
+ # 使用更平緩的曲線
2400
+ return 0.75 + (smooth_curve(position) * 0.07)
2401
+
2402
+ # 較差匹配區間(50以下)
2403
+ else:
2404
+ position = score / 0.50
2405
+ # 確保即使是較低分數也能得到基本分數
2406
+ return 0.70 + (smooth_curve(position) * 0.05)
2407
+
2408
+ def apply_context_bonus(score: float) -> float:
2409
+ """
2410
+ 根據具體情況添加額外的分數調整。
2411
 
2412
+ 這個函數考慮特定的場景來微調分數,就像是考試時會根據題目
2413
+ 的難度來調整給分標準。
 
2414
 
2415
+ Parameters:
2416
+ score: 當前分數
2417
+
2418
+ Returns:
2419
+ float: 調整後的分數
2420
+ """
2421
+ bonus = 0
2422
+
2423
+ # 特殊場景加分
2424
+ temperament = breed_info.get('Temperament', '').lower()
2425
+ if user_prefs.living_space == 'apartment':
2426
+ if 'adaptable' in temperament and score > 0.85:
2427
+ bonus += 0.02
2428
+
2429
+ # 運動需求匹配度加分
2430
+ if breed_info.get('Exercise Needs', 'MODERATE').upper() == 'LOW':
2431
+ if user_prefs.exercise_time <= 60 and score > 0.85:
2432
+ bonus += 0.01
2433
+
2434
+ return min(1.0, score + bonus)
2435
+
2436
+ # 應用基本的範圍映射
2437
+ adjusted_score = apply_range_mapping(score)
2438
+
2439
+ # 應用情境相關的調整
2440
+ final_score = apply_context_bonus(adjusted_score)
2441
+
2442
+ # 確保分數在有效範圍內
2443
+ return round(min(1.0, max(0.0, final_score)), 4)
2444
+
2445
+ # def amplify_score_extreme(score: float) -> float:
2446
+ # """優化分數分布,提供更高的分數範圍"""
2447
+ # def smooth_curve(x: float, steepness: float = 12) -> float:
2448
+ # import math
2449
+ # return 1 / (1 + math.exp(-steepness * (x - 0.5)))
2450
+
2451
+ # if score >= 0.9:
2452
+ # position = (score - 0.9) / 0.1
2453
+ # return 0.96 + (position * 0.04) # 90-100的原始分映射到96-100
2454
+
2455
+ # elif score >= 0.8:
2456
+ # position = (score - 0.8) / 0.1
2457
+ # return 0.90 + (position * 0.06) # 80-90的原始分映射到90-96
2458
+
2459
+ # elif score >= 0.7:
2460
+ # position = (score - 0.7) / 0.1
2461
+ # return 0.82 + (position * 0.08) # 70-80的原始分映射到82-90
2462
+
2463
+ # elif score >= 0.5:
2464
+ # position = (score - 0.5) / 0.2
2465
+ # return 0.75 + (smooth_curve(position) * 0.07) # 50-70的原始分映射到75-82
2466
+
2467
+ # else:
2468
+ # position = score / 0.5
2469
+ # return 0.70 + (smooth_curve(position) * 0.05) # 50以下的原始分映射到70-75