Spaces:
Running
on
Zero
Running
on
Zero
Update scoring_calculation_system.py
Browse files- scoring_calculation_system.py +207 -87
scoring_calculation_system.py
CHANGED
|
@@ -143,6 +143,7 @@ def calculate_breed_bonus(breed_info: dict, user_prefs: UserPreferences) -> floa
|
|
| 143 |
"""
|
| 144 |
bonus = 0.0
|
| 145 |
temperament = breed_info.get('Temperament', '').lower()
|
|
|
|
| 146 |
|
| 147 |
# 壽命評估 - 重新設計以反映更實際的考量
|
| 148 |
try:
|
|
@@ -206,6 +207,47 @@ def calculate_breed_bonus(breed_info: dict, user_prefs: UserPreferences) -> floa
|
|
| 206 |
|
| 207 |
bonus += max(-0.25, min(0.25, personality_score))
|
| 208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
# 適應性評估 - 根據具體環境給予更細緻的評分
|
| 210 |
adaptability_bonus = 0.0
|
| 211 |
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
|
|
@@ -779,8 +821,20 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
|
|
| 779 |
return min(0.95, max(0.15, current_score))
|
| 780 |
|
| 781 |
|
| 782 |
-
# def calculate_exercise_score(breed_needs: str,
|
| 783 |
-
# """
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 784 |
# exercise_needs = {
|
| 785 |
# 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
|
| 786 |
# 'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
|
|
@@ -791,57 +845,115 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
|
|
| 791 |
|
| 792 |
# breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
|
| 793 |
|
| 794 |
-
# #
|
| 795 |
-
# if
|
| 796 |
-
# if
|
| 797 |
-
#
|
| 798 |
-
#
|
| 799 |
-
#
|
| 800 |
-
#
|
|
|
|
|
|
|
|
|
|
| 801 |
# else:
|
| 802 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 803 |
|
| 804 |
|
| 805 |
-
def
|
| 806 |
"""
|
| 807 |
-
|
| 808 |
|
| 809 |
Parameters:
|
| 810 |
-
breed_needs:
|
| 811 |
-
exercise_time:
|
|
|
|
| 812 |
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
2. 更合理的時間匹配計算
|
| 816 |
-
3. 避免極端評分
|
| 817 |
"""
|
| 818 |
-
#
|
| 819 |
-
|
| 820 |
-
'VERY HIGH': {
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 825 |
}
|
| 826 |
|
| 827 |
-
|
|
|
|
| 828 |
|
| 829 |
-
#
|
| 830 |
-
if exercise_time >=
|
| 831 |
-
if exercise_time >
|
| 832 |
-
#
|
| 833 |
-
time_score = 0.
|
| 834 |
else:
|
| 835 |
-
time_score =
|
| 836 |
-
elif exercise_time >=
|
| 837 |
# 在最小需求和理想需求之間,線性計算分數
|
| 838 |
-
|
|
|
|
| 839 |
else:
|
| 840 |
-
#
|
| 841 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 842 |
|
| 843 |
-
|
| 844 |
-
return min(1.0, max(0.3, time_score))
|
| 845 |
|
| 846 |
|
| 847 |
def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
|
|
@@ -1462,67 +1574,75 @@ def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -
|
|
| 1462 |
return min(0.2, adaptability_score)
|
| 1463 |
|
| 1464 |
|
| 1465 |
-
def
|
| 1466 |
-
scores: dict,
|
| 1467 |
-
user_prefs: UserPreferences,
|
| 1468 |
-
breed_info: dict,
|
| 1469 |
-
adaptability_bonus: float
|
| 1470 |
-
) -> float:
|
| 1471 |
"""
|
| 1472 |
-
|
|
|
|
| 1473 |
"""
|
| 1474 |
-
|
| 1475 |
-
|
| 1476 |
-
'
|
| 1477 |
-
'exercise': 0.25, # 重視運動需求
|
| 1478 |
'grooming': 0.15,
|
| 1479 |
'experience': 0.15,
|
| 1480 |
-
'health': 0.
|
| 1481 |
-
'noise': 0.
|
| 1482 |
}
|
| 1483 |
-
|
| 1484 |
-
# 條件特殊化評分
|
| 1485 |
-
special_conditions = 0.0
|
| 1486 |
|
| 1487 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1488 |
if user_prefs.living_space == 'apartment':
|
| 1489 |
-
|
| 1490 |
-
|
| 1491 |
-
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
-
|
| 1495 |
-
|
| 1496 |
-
if user_prefs.exercise_time > 120: # 高運動量
|
| 1497 |
-
if exercise_needs in ['VERY HIGH', 'HIGH']:
|
| 1498 |
-
special_conditions += 0.20
|
| 1499 |
-
elif exercise_needs == 'LOW':
|
| 1500 |
-
special_conditions -= 0.25
|
| 1501 |
-
elif user_prefs.exercise_time < 45: # 低運動量
|
| 1502 |
-
if exercise_needs in ['VERY HIGH', 'HIGH']:
|
| 1503 |
-
special_conditions -= 0.25
|
| 1504 |
-
elif exercise_needs == 'LOW':
|
| 1505 |
-
special_conditions += 0.15
|
| 1506 |
-
|
| 1507 |
-
# 經驗等級極端匹配
|
| 1508 |
if user_prefs.experience_level == 'beginner':
|
| 1509 |
-
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
|
| 1513 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1514 |
|
| 1515 |
-
|
| 1516 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1517 |
|
| 1518 |
-
#
|
| 1519 |
breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
|
| 1520 |
|
| 1521 |
-
#
|
| 1522 |
-
|
| 1523 |
-
|
| 1524 |
-
#
|
| 1525 |
-
return amplify_score_extreme(
|
| 1526 |
|
| 1527 |
|
| 1528 |
def amplify_score_extreme(score: float) -> float:
|
|
|
|
| 143 |
"""
|
| 144 |
bonus = 0.0
|
| 145 |
temperament = breed_info.get('Temperament', '').lower()
|
| 146 |
+
description = breed_info.get('Description', '').lower()
|
| 147 |
|
| 148 |
# 壽命評估 - 重新設計以反映更實際的考量
|
| 149 |
try:
|
|
|
|
| 207 |
|
| 208 |
bonus += max(-0.25, min(0.25, personality_score))
|
| 209 |
|
| 210 |
+
exercise_match = calculate_exercise_match(
|
| 211 |
+
breed_info.get('Exercise_Needs', 'MODERATE'),
|
| 212 |
+
user_prefs.exercise_time,
|
| 213 |
+
user_prefs.exercise_type
|
| 214 |
+
)
|
| 215 |
+
bonus += exercise_match
|
| 216 |
+
|
| 217 |
+
# 運動類型特性評估
|
| 218 |
+
exercise_traits = {
|
| 219 |
+
'active_training': {
|
| 220 |
+
'athletic': 0.10,
|
| 221 |
+
'energetic': 0.08,
|
| 222 |
+
'working': 0.08,
|
| 223 |
+
'intelligent': 0.06
|
| 224 |
+
},
|
| 225 |
+
'moderate_activity': {
|
| 226 |
+
'adaptable': 0.08,
|
| 227 |
+
'balanced': 0.06,
|
| 228 |
+
'versatile': 0.06,
|
| 229 |
+
'steady': 0.04
|
| 230 |
+
},
|
| 231 |
+
'light_walks': {
|
| 232 |
+
'calm': 0.08,
|
| 233 |
+
'gentle': 0.06,
|
| 234 |
+
'easy-going': 0.06,
|
| 235 |
+
'patient': 0.04
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
# 計算運動類型特性匹配度
|
| 240 |
+
if user_prefs.exercise_type in exercise_traits:
|
| 241 |
+
trait_score = 0
|
| 242 |
+
matched_traits = 0
|
| 243 |
+
for trait, value in exercise_traits[user_prefs.exercise_type].items():
|
| 244 |
+
if trait in temperament:
|
| 245 |
+
trait_score += value
|
| 246 |
+
matched_traits += 1
|
| 247 |
+
if matched_traits > 0:
|
| 248 |
+
bonus += min(0.15, trait_score * (1 + (matched_traits - 1) * 0.1))
|
| 249 |
+
|
| 250 |
+
|
| 251 |
# 適應性評估 - 根據具體環境給予更細緻的評分
|
| 252 |
adaptability_bonus = 0.0
|
| 253 |
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
|
|
|
|
| 821 |
return min(0.95, max(0.15, current_score))
|
| 822 |
|
| 823 |
|
| 824 |
+
# def calculate_exercise_score(breed_needs: str, exercise_time: int) -> float:
|
| 825 |
+
# """
|
| 826 |
+
# 優化的運動需求評分系統
|
| 827 |
+
|
| 828 |
+
# Parameters:
|
| 829 |
+
# breed_needs: str - 品種的運動需求等級
|
| 830 |
+
# exercise_time: int - 使用者可提供的運動時間(分鐘)
|
| 831 |
+
|
| 832 |
+
# 改進:
|
| 833 |
+
# 1. 更細緻的運動需求評估
|
| 834 |
+
# 2. 更合理的時間匹配計算
|
| 835 |
+
# 3. 避免極端評分
|
| 836 |
+
# """
|
| 837 |
+
# # 基礎運動需求評估
|
| 838 |
# exercise_needs = {
|
| 839 |
# 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
|
| 840 |
# 'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
|
|
|
|
| 845 |
|
| 846 |
# breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
|
| 847 |
|
| 848 |
+
# # 基礎時間匹配度計算
|
| 849 |
+
# if exercise_time >= breed_need['ideal']:
|
| 850 |
+
# if exercise_time > breed_need['max']:
|
| 851 |
+
# # 運動時間過長,稍微降低分數
|
| 852 |
+
# time_score = 0.9
|
| 853 |
+
# else:
|
| 854 |
+
# time_score = 1.0
|
| 855 |
+
# elif exercise_time >= breed_need['min']:
|
| 856 |
+
# # 在最小需求和理想需求之間,線性計算分數
|
| 857 |
+
# time_score = 0.7 + (exercise_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.3
|
| 858 |
# else:
|
| 859 |
+
# # 運動時間不足,但仍根據比例給予分數
|
| 860 |
+
# time_score = max(0.3, 0.7 * (exercise_time / breed_need['min']))
|
| 861 |
+
|
| 862 |
+
# # 確保分數在合理範圍內
|
| 863 |
+
# return min(1.0, max(0.3, time_score))
|
| 864 |
|
| 865 |
|
| 866 |
+
def calculate_exercise_match(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
|
| 867 |
"""
|
| 868 |
+
精確評估品種運動需求與使用者運動條件的匹配度
|
| 869 |
|
| 870 |
Parameters:
|
| 871 |
+
breed_needs: 品種的運動���求等級
|
| 872 |
+
exercise_time: 使用者能提供的運動時間(分鐘)
|
| 873 |
+
exercise_type: 使用者偏好的運動類型
|
| 874 |
|
| 875 |
+
Returns:
|
| 876 |
+
float: -0.2 到 0.2 之間的匹配分數
|
|
|
|
|
|
|
| 877 |
"""
|
| 878 |
+
# 定義更細緻的運動需求等級
|
| 879 |
+
exercise_levels = {
|
| 880 |
+
'VERY HIGH': {
|
| 881 |
+
'min': 120,
|
| 882 |
+
'ideal': 150,
|
| 883 |
+
'max': 180,
|
| 884 |
+
'intensity': 'high',
|
| 885 |
+
'sessions': 'multiple',
|
| 886 |
+
'preferred_types': ['active_training', 'intensive_exercise']
|
| 887 |
+
},
|
| 888 |
+
'HIGH': {
|
| 889 |
+
'min': 90,
|
| 890 |
+
'ideal': 120,
|
| 891 |
+
'max': 150,
|
| 892 |
+
'intensity': 'moderate_high',
|
| 893 |
+
'sessions': 'multiple',
|
| 894 |
+
'preferred_types': ['active_training', 'moderate_activity']
|
| 895 |
+
},
|
| 896 |
+
'MODERATE HIGH': {
|
| 897 |
+
'min': 70,
|
| 898 |
+
'ideal': 90,
|
| 899 |
+
'max': 120,
|
| 900 |
+
'intensity': 'moderate',
|
| 901 |
+
'sessions': 'flexible',
|
| 902 |
+
'preferred_types': ['moderate_activity', 'active_training']
|
| 903 |
+
},
|
| 904 |
+
'MODERATE': {
|
| 905 |
+
'min': 45,
|
| 906 |
+
'ideal': 60,
|
| 907 |
+
'max': 90,
|
| 908 |
+
'intensity': 'moderate',
|
| 909 |
+
'sessions': 'flexible',
|
| 910 |
+
'preferred_types': ['moderate_activity', 'light_walks']
|
| 911 |
+
},
|
| 912 |
+
'MODERATE LOW': {
|
| 913 |
+
'min': 30,
|
| 914 |
+
'ideal': 45,
|
| 915 |
+
'max': 70,
|
| 916 |
+
'intensity': 'light_moderate',
|
| 917 |
+
'sessions': 'flexible',
|
| 918 |
+
'preferred_types': ['light_walks', 'moderate_activity']
|
| 919 |
+
},
|
| 920 |
+
'LOW': {
|
| 921 |
+
'min': 15,
|
| 922 |
+
'ideal': 30,
|
| 923 |
+
'max': 45,
|
| 924 |
+
'intensity': 'light',
|
| 925 |
+
'sessions': 'single',
|
| 926 |
+
'preferred_types': ['light_walks']
|
| 927 |
+
}
|
| 928 |
}
|
| 929 |
|
| 930 |
+
# 獲取品種的運動需求配置
|
| 931 |
+
breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
|
| 932 |
|
| 933 |
+
# 計算時間匹配度(使用更平滑的評分曲線)
|
| 934 |
+
if exercise_time >= breed_level['ideal']:
|
| 935 |
+
if exercise_time > breed_level['max']:
|
| 936 |
+
# 運動時間過長,適度降分
|
| 937 |
+
time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30)
|
| 938 |
else:
|
| 939 |
+
time_score = 0.15
|
| 940 |
+
elif exercise_time >= breed_level['min']:
|
| 941 |
# 在最小需求和理想需求之間,線性計算分數
|
| 942 |
+
time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
|
| 943 |
+
time_score = 0.05 + (time_ratio * 0.10)
|
| 944 |
else:
|
| 945 |
+
# 運動時間不足,根據差距程度扣分
|
| 946 |
+
time_ratio = max(0, exercise_time / breed_level['min'])
|
| 947 |
+
time_score = -0.15 * (1 - time_ratio)
|
| 948 |
+
|
| 949 |
+
# 運動類型匹配度評估
|
| 950 |
+
type_score = 0.0
|
| 951 |
+
if exercise_type in breed_level['preferred_types']:
|
| 952 |
+
type_score = 0.05
|
| 953 |
+
if exercise_type == breed_level['preferred_types'][0]:
|
| 954 |
+
type_score = 0.08 # 最佳匹配類型給予更高分數
|
| 955 |
|
| 956 |
+
return max(-0.2, min(0.2, time_score + type_score))
|
|
|
|
| 957 |
|
| 958 |
|
| 959 |
def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
|
|
|
|
| 1574 |
return min(0.2, adaptability_score)
|
| 1575 |
|
| 1576 |
|
| 1577 |
+
def calculate_dynamic_weights(user_prefs: UserPreferences, breed_info: dict) -> dict:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1578 |
"""
|
| 1579 |
+
根據使用者條件動態計算權重
|
| 1580 |
+
這個系統會根據具體情況調整各個評分項目的重要性
|
| 1581 |
"""
|
| 1582 |
+
weights = {
|
| 1583 |
+
'space': 0.25, # 降低基礎空間權重
|
| 1584 |
+
'exercise': 0.20,
|
|
|
|
| 1585 |
'grooming': 0.15,
|
| 1586 |
'experience': 0.15,
|
| 1587 |
+
'health': 0.15,
|
| 1588 |
+
'noise': 0.10
|
| 1589 |
}
|
|
|
|
|
|
|
|
|
|
| 1590 |
|
| 1591 |
+
# 運動時間對權重的影響
|
| 1592 |
+
if user_prefs.exercise_time > 150:
|
| 1593 |
+
weights['exercise'] *= 1.4
|
| 1594 |
+
weights['space'] *= 0.8
|
| 1595 |
+
elif user_prefs.exercise_time < 30:
|
| 1596 |
+
weights['exercise'] *= 0.8
|
| 1597 |
+
weights['health'] *= 1.2
|
| 1598 |
+
|
| 1599 |
+
# 居住環境對權重的影響
|
| 1600 |
if user_prefs.living_space == 'apartment':
|
| 1601 |
+
weights['noise'] *= 1.3
|
| 1602 |
+
weights['space'] *= 1.2
|
| 1603 |
+
elif user_prefs.living_space == 'house_large':
|
| 1604 |
+
weights['exercise'] *= 1.2
|
| 1605 |
+
weights['space'] *= 0.8
|
| 1606 |
+
|
| 1607 |
+
# 經驗等級對權重的影響
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1608 |
if user_prefs.experience_level == 'beginner':
|
| 1609 |
+
weights['experience'] *= 1.3
|
| 1610 |
+
weights['health'] *= 1.2
|
| 1611 |
+
|
| 1612 |
+
# 有孩童時的權重調整
|
| 1613 |
+
if user_prefs.has_children:
|
| 1614 |
+
if user_prefs.children_age == 'toddler':
|
| 1615 |
+
weights['temperament'] = 0.20 # 新增性格權重
|
| 1616 |
+
weights['space'] *= 0.8
|
| 1617 |
+
|
| 1618 |
+
# 重新正規化權重
|
| 1619 |
+
total = sum(weights.values())
|
| 1620 |
+
return {k: v/total for k, v in weights.items()}
|
| 1621 |
+
|
| 1622 |
|
| 1623 |
+
def calculate_final_weighted_score(
|
| 1624 |
+
scores: dict,
|
| 1625 |
+
user_prefs: UserPreferences,
|
| 1626 |
+
breed_info: dict,
|
| 1627 |
+
adaptability_bonus: float
|
| 1628 |
+
) -> float:
|
| 1629 |
+
"""
|
| 1630 |
+
整合動態權重的最終分數計算系統
|
| 1631 |
+
"""
|
| 1632 |
+
# 第一步:計算動態權重
|
| 1633 |
+
weights = calculate_dynamic_weights(user_prefs, breed_info) # 內部函數
|
| 1634 |
+
|
| 1635 |
+
# 第二步:計算基礎加權分數
|
| 1636 |
+
weighted_base = sum(score * weights[category] for category, score in scores.items())
|
| 1637 |
|
| 1638 |
+
# 第三步:計算品種特性加成
|
| 1639 |
breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
|
| 1640 |
|
| 1641 |
+
# 第四步:最終分數計算
|
| 1642 |
+
final_score = (weighted_base * 0.70) + (breed_bonus * 0.20) + (adaptability_bonus * 0.10)
|
| 1643 |
+
|
| 1644 |
+
# 第五步:分數轉換
|
| 1645 |
+
return amplify_score_extreme(final_score)
|
| 1646 |
|
| 1647 |
|
| 1648 |
def amplify_score_extreme(score: float) -> float:
|