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:
|