PawMatchAI / scoring_calculation_system.py
DawnC's picture
Update scoring_calculation_system.py
306b3c6 verified
raw
history blame
97.3 kB
from dataclasses import dataclass
from breed_health_info import breed_health_info
from breed_noise_info import breed_noise_info
import traceback
import math
@dataclass
class UserPreferences:
"""使用者偏好設定的資料結構"""
living_space: str # "apartment", "house_small", "house_large"
yard_access: str # "no_yard", "shared_yard", "private_yard"
exercise_time: int # minutes per day
exercise_type: str # "light_walks", "moderate_activity", "active_training"
grooming_commitment: str # "low", "medium", "high"
experience_level: str # "beginner", "intermediate", "advanced"
time_availability: str # "limited", "moderate", "flexible"
has_children: bool
children_age: str # "toddler", "school_age", "teenager"
noise_tolerance: str # "low", "medium", "high"
space_for_play: bool
other_pets: bool
climate: str # "cold", "moderate", "hot"
health_sensitivity: str = "medium"
barking_acceptance: str = None
training_commitment: str = "medium" # "low", "medium", "high" - 訓練投入程度
living_environment: str = "ground_floor" # "ground_floor", "with_elevator", "walk_up" - 居住環境細節
def __post_init__(self):
"""在初始化後運行,用於設置派生值"""
if self.barking_acceptance is None:
self.barking_acceptance = self.noise_tolerance
@staticmethod
def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float:
"""計算品種額外加分"""
bonus = 0.0
temperament = breed_info.get('Temperament', '').lower()
# 1. 壽命加分(最高0.05)
try:
lifespan = breed_info.get('Lifespan', '10-12 years')
years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
longevity_bonus = min(0.05, (max(years) - 10) * 0.01)
bonus += longevity_bonus
except:
pass
# 2. 性格特徵加分(最高0.15)
positive_traits = {
'friendly': 0.05,
'gentle': 0.05,
'patient': 0.05,
'intelligent': 0.04,
'adaptable': 0.04,
'affectionate': 0.04,
'easy-going': 0.03,
'calm': 0.03
}
negative_traits = {
'aggressive': -0.08,
'stubborn': -0.06,
'dominant': -0.06,
'aloof': -0.04,
'nervous': -0.05,
'protective': -0.04
}
personality_score = sum(value for trait, value in positive_traits.items() if trait in temperament)
personality_score += sum(value for trait, value in negative_traits.items() if trait in temperament)
bonus += max(-0.15, min(0.15, personality_score))
# 3. 適應性加分(最高0.1)
adaptability_bonus = 0.0
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
adaptability_bonus += 0.05
if 'adaptable' in temperament or 'versatile' in temperament:
adaptability_bonus += 0.05
bonus += min(0.1, adaptability_bonus)
# 4. 家庭相容性(最高0.1)
if user_prefs.has_children:
family_traits = {
'good with children': 0.06,
'patient': 0.05,
'gentle': 0.05,
'tolerant': 0.04,
'playful': 0.03
}
unfriendly_traits = {
'aggressive': -0.08,
'nervous': -0.07,
'protective': -0.06,
'territorial': -0.05
}
# 年齡評估這樣能更細緻
age_adjustments = {
'toddler': {'bonus_mult': 0.7, 'penalty_mult': 1.3},
'school_age': {'bonus_mult': 1.0, 'penalty_mult': 1.0},
'teenager': {'bonus_mult': 1.2, 'penalty_mult': 0.8}
}
adj = age_adjustments.get(user_prefs.children_age,
{'bonus_mult': 1.0, 'penalty_mult': 1.0})
family_bonus = sum(value for trait, value in family_traits.items()
if trait in temperament) * adj['bonus_mult']
family_penalty = sum(value for trait, value in unfriendly_traits.items()
if trait in temperament) * adj['penalty_mult']
bonus += min(0.15, max(-0.2, family_bonus + family_penalty))
# 5. 專門技能加分(最高0.1)
skill_bonus = 0.0
special_abilities = {
'working': 0.03,
'herding': 0.03,
'hunting': 0.03,
'tracking': 0.03,
'agility': 0.02
}
for ability, value in special_abilities.items():
if ability in temperament.lower():
skill_bonus += value
bonus += min(0.1, skill_bonus)
# 6. 適應性評估 - 根據具體環境給予更細緻的評分
adaptability_bonus = 0.0
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
adaptability_bonus += 0.08 # 小型犬更適合公寓
# 環境適應性評估
if 'adaptable' in temperament or 'versatile' in temperament:
if user_prefs.living_space == "apartment":
adaptability_bonus += 0.10 # 適應性在公寓環境更重要
else:
adaptability_bonus += 0.05 # 其他環境仍有加分
# 氣候適應性
description = breed_info.get('Description', '').lower()
climate = user_prefs.climate
if climate == 'hot':
if 'heat tolerant' in description or 'warm climate' in description:
adaptability_bonus += 0.08
elif 'thick coat' in description or 'cold climate' in description:
adaptability_bonus -= 0.10
elif climate == 'cold':
if 'thick coat' in description or 'cold climate' in description:
adaptability_bonus += 0.08
elif 'heat tolerant' in description or 'short coat' in description:
adaptability_bonus -= 0.10
bonus += min(0.15, adaptability_bonus)
return min(0.5, max(-0.25, bonus))
@staticmethod
def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
"""
計算額外的評估因素,結合品種特性與使用者需求的全面評估系統
此函數整合了:
1. 多功能性評估 - 品種的多樣化能力
2. 訓練性評估 - 學習和服從能力
3. 能量水平評估 - 活力和運動需求
4. 美容需求評估 - 護理和維護需求
5. 社交需求評估 - 與人互動的需求程度
6. 氣候適應性 - 對環境的適應能力
7. 運動類型匹配 - 與使用者運動習慣的契合度
8. 生活方式適配 - 與使用者日常生活的匹配度
"""
factors = {
'versatility': 0.0, # 多功能性
'trainability': 0.0, # 可訓練度
'energy_level': 0.0, # 能量水平
'grooming_needs': 0.0, # 美容需求
'social_needs': 0.0, # 社交需求
'weather_adaptability': 0.0,# 氣候適應性
'exercise_match': 0.0, # 運動匹配度
'lifestyle_fit': 0.0 # 生活方式適配度
}
temperament = breed_info.get('Temperament', '').lower()
description = breed_info.get('Description', '').lower()
size = breed_info.get('Size', 'Medium')
# 1. 多功能性評估 - 加強品種用途評估
versatile_traits = {
'intelligent': 0.25,
'adaptable': 0.25,
'trainable': 0.20,
'athletic': 0.15,
'versatile': 0.15
}
working_roles = {
'working': 0.20,
'herding': 0.15,
'hunting': 0.15,
'sporting': 0.15,
'companion': 0.10
}
# 計算特質分數
trait_score = sum(value for trait, value in versatile_traits.items()
if trait in temperament)
# 計算角色分數
role_score = sum(value for role, value in working_roles.items()
if role in description)
# 根據使用者需求調整多功能性評分
purpose_traits = {
'light_walks': ['calm', 'gentle', 'easy-going'],
'moderate_activity': ['adaptable', 'balanced', 'versatile'],
'active_training': ['intelligent', 'trainable', 'working']
}
if user_prefs.exercise_type in purpose_traits:
matching_traits = sum(1 for trait in purpose_traits[user_prefs.exercise_type]
if trait in temperament)
trait_score += matching_traits * 0.15
factors['versatility'] = min(1.0, trait_score + role_score)
# 2. 訓練性評估 - 考慮使用者經驗
trainable_traits = {
'intelligent': 0.3,
'eager to please': 0.3,
'trainable': 0.2,
'quick learner': 0.2,
'obedient': 0.2
}
base_trainability = sum(value for trait, value in trainable_traits.items()
if trait in temperament)
# 根據使用者經驗調整訓練性評分
experience_multipliers = {
'beginner': 1.2, # 新手更需要容易訓練的狗
'intermediate': 1.0,
'advanced': 0.8 # 專家能處理較難訓練的狗
}
factors['trainability'] = min(1.0, base_trainability *
experience_multipliers.get(user_prefs.experience_level, 1.0))
# 3. 能量水平評估 - 強化運動需求匹配
exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
energy_levels = {
'VERY HIGH': {
'score': 1.0,
'min_exercise': 120,
'ideal_exercise': 150
},
'HIGH': {
'score': 0.8,
'min_exercise': 90,
'ideal_exercise': 120
},
'MODERATE': {
'score': 0.6,
'min_exercise': 60,
'ideal_exercise': 90
},
'LOW': {
'score': 0.4,
'min_exercise': 30,
'ideal_exercise': 60
}
}
breed_energy = energy_levels.get(exercise_needs, energy_levels['MODERATE'])
# 計算運動時間匹配度
if user_prefs.exercise_time >= breed_energy['ideal_exercise']:
energy_score = breed_energy['score']
else:
# 如果運動時間不足,按比例降低分數
deficit_ratio = max(0.4, user_prefs.exercise_time / breed_energy['ideal_exercise'])
energy_score = breed_energy['score'] * deficit_ratio
factors['energy_level'] = energy_score
# 4. 美容需求評估 - 加入更多毛髮類型考量
grooming_needs = breed_info.get('Grooming Needs', 'MODERATE').upper()
grooming_levels = {
'HIGH': 1.0,
'MODERATE': 0.6,
'LOW': 0.3
}
# 特殊毛髮類型評估
coat_adjustments = 0
if 'long coat' in description:
coat_adjustments += 0.2
if 'double coat' in description:
coat_adjustments += 0.15
if 'curly' in description:
coat_adjustments += 0.15
# 根據使用者承諾度調整
commitment_multipliers = {
'low': 1.5, # 低承諾度時加重美容需求的影響
'medium': 1.0,
'high': 0.8 # 高承諾度時降低美容需求的影響
}
base_grooming = grooming_levels.get(grooming_needs, 0.6) + coat_adjustments
factors['grooming_needs'] = min(1.0, base_grooming *
commitment_multipliers.get(user_prefs.grooming_commitment, 1.0))
# 5. 社交需求評估 - 加強家庭情況考量
social_traits = {
'friendly': 0.25,
'social': 0.25,
'affectionate': 0.20,
'people-oriented': 0.20
}
antisocial_traits = {
'independent': -0.20,
'aloof': -0.20,
'reserved': -0.15
}
social_score = sum(value for trait, value in social_traits.items()
if trait in temperament)
antisocial_score = sum(value for trait, value in antisocial_traits.items()
if trait in temperament)
# 家庭情況調整
if user_prefs.has_children:
child_friendly_bonus = 0.2 if 'good with children' in temperament else 0
social_score += child_friendly_bonus
factors['social_needs'] = min(1.0, max(0.0, social_score + antisocial_score))
# 6. 氣候適應性評估 - 更細緻的環境適應評估
climate_traits = {
'cold': {
'positive': ['thick coat', 'winter', 'cold climate'],
'negative': ['short coat', 'heat sensitive']
},
'hot': {
'positive': ['short coat', 'heat tolerant', 'warm climate'],
'negative': ['thick coat', 'cold climate']
},
'moderate': {
'positive': ['adaptable', 'all climate'],
'negative': []
}
}
climate_score = 0.4 # 基礎分數
if user_prefs.climate in climate_traits:
# 正面特質加分
climate_score += sum(0.2 for term in climate_traits[user_prefs.climate]['positive']
if term in description)
# 負面特質減分
climate_score -= sum(0.2 for term in climate_traits[user_prefs.climate]['negative']
if term in description)
factors['weather_adaptability'] = min(1.0, max(0.0, climate_score))
# 7. 運動類型匹配評估
exercise_type_traits = {
'light_walks': ['calm', 'gentle'],
'moderate_activity': ['adaptable', 'balanced'],
'active_training': ['athletic', 'energetic']
}
if user_prefs.exercise_type in exercise_type_traits:
match_score = sum(0.25 for trait in exercise_type_traits[user_prefs.exercise_type]
if trait in temperament)
factors['exercise_match'] = min(1.0, match_score + 0.5) # 基礎分0.5
# 8. 生活方式適配評估
lifestyle_score = 0.5 # 基礎分數
# 空間適配
if user_prefs.living_space == 'apartment':
if size == 'Small':
lifestyle_score += 0.2
elif size == 'Large':
lifestyle_score -= 0.2
elif user_prefs.living_space == 'house_large':
if size in ['Large', 'Giant']:
lifestyle_score += 0.2
# 時間可用性適配
time_availability_bonus = {
'limited': -0.1,
'moderate': 0,
'flexible': 0.1
}
lifestyle_score += time_availability_bonus.get(user_prefs.time_availability, 0)
factors['lifestyle_fit'] = min(1.0, max(0.0, lifestyle_score))
return factors
def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences) -> dict:
"""計算品種與使用者條件的相容性分數"""
try:
print(f"Processing breed: {breed_info.get('Breed', 'Unknown')}")
print(f"Breed info keys: {breed_info.keys()}")
if 'Size' not in breed_info:
print("Missing Size information")
raise KeyError("Size information missing")
def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
"""
1. 動態的基礎分數矩陣
2. 強化空間品質評估
3. 增加極端情況處理
4. 考慮不同空間組合的協同效應
"""
def get_base_score():
# 基礎分數矩陣 - 更極端的分數分配
base_matrix = {
"Small": {
"apartment": {
"no_yard": 0.85, # 小型犬在公寓仍然適合
"shared_yard": 0.90, # 共享院子提供額外活動空間
"private_yard": 0.95 # 私人院子最理想
},
"house_small": {
"no_yard": 0.80,
"shared_yard": 0.85,
"private_yard": 0.90
},
"house_large": {
"no_yard": 0.75,
"shared_yard": 0.80,
"private_yard": 0.85
}
},
"Medium": {
"apartment": {
"no_yard": 0.35, # 中型犬在公寓較受限
"shared_yard": 0.45,
"private_yard": 0.55
},
"house_small": {
"no_yard": 0.75,
"shared_yard": 0.85,
"private_yard": 0.90
},
"house_large": {
"no_yard": 0.85,
"shared_yard": 0.90,
"private_yard": 0.95
}
},
"Large": {
"apartment": {
"no_yard": 0.15, # 大型犬在公寓極不適合
"shared_yard": 0.25,
"private_yard": 0.35
},
"house_small": {
"no_yard": 0.55,
"shared_yard": 0.65,
"private_yard": 0.75
},
"house_large": {
"no_yard": 0.85,
"shared_yard": 0.90,
"private_yard": 1.0
}
},
"Giant": {
"apartment": {
"no_yard": 0.10, # 巨型犬在公寓基本不適合
"shared_yard": 0.20,
"private_yard": 0.30
},
"house_small": {
"no_yard": 0.40,
"shared_yard": 0.50,
"private_yard": 0.60
},
"house_large": {
"no_yard": 0.80,
"shared_yard": 0.90,
"private_yard": 1.0
}
}
}
yard_type = "private_yard" if has_yard else "no_yard"
return base_matrix.get(size, base_matrix["Medium"])[living_space][yard_type]
def calculate_exercise_adjustment():
# 運動需求對空間評分的影響
exercise_impact = {
"Very High": {
"apartment": -0.30, # 高運動需求在公寓環境更受限
"house_small": -0.15,
"house_large": -0.05
},
"High": {
"apartment": -0.25,
"house_small": -0.10,
"house_large": 0
},
"Moderate": {
"apartment": -0.15,
"house_small": -0.05,
"house_large": 0
},
"Low": {
"apartment": 0.10, # 低運動需求反而適合小空間
"house_small": 0.05,
"house_large": 0
}
}
return exercise_impact.get(exercise_needs, exercise_impact["Moderate"])[living_space]
def calculate_yard_bonus():
# 院子效益評估更加細緻
if not has_yard:
return 0
yard_benefits = {
"Giant": {
"Very High": 0.25,
"High": 0.20,
"Moderate": 0.15,
"Low": 0.10
},
"Large": {
"Very High": 0.20,
"High": 0.15,
"Moderate": 0.10,
"Low": 0.05
},
"Medium": {
"Very High": 0.15,
"High": 0.10,
"Moderate": 0.08,
"Low": 0.05
},
"Small": {
"Very High": 0.10,
"High": 0.08,
"Moderate": 0.05,
"Low": 0.03
}
}
size_benefits = yard_benefits.get(size, yard_benefits["Medium"])
return size_benefits.get(exercise_needs, size_benefits["Moderate"])
def apply_extreme_case_adjustments(score):
# 處理極端情況
if size == "Giant" and living_space == "apartment":
return score * 0.5 # 巨型犬在公寓給予更嚴重的懲罰
if size == "Large" and living_space == "apartment" and exercise_needs == "Very High":
return score * 0.6 # 高運動需求的大型犬在公寓更不適合
if size == "Small" and living_space == "house_large" and exercise_needs == "Low":
return score * 0.9 # 低運動需求的小型犬在大房子可能過於寬敞
return score
# 計算最終分數
base_score = get_base_score()
exercise_adj = calculate_exercise_adjustment()
yard_bonus = calculate_yard_bonus()
# 整合所有評分因素
initial_score = base_score + exercise_adj + yard_bonus
# 應用極端情況調整
final_score = apply_extreme_case_adjustments(initial_score)
# 確保分數在有效範圍內,但允許更極端的結果
return max(0.05, min(1.0, final_score))
def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
"""
精確評估品種運動需求與使用者運動條件的匹配度
改進重點:
1. 擴大分數範圍到 0.1-1.0
2. 加強運動類型影響
3. 考慮運動強度與時間的綜合效果
4. 更細緻的時間匹配評估
"""
exercise_levels = {
'VERY HIGH': {
'min': 120,
'ideal': 150,
'max': 180,
'intensity': 'high',
'sessions': 'multiple',
'preferred_types': ['active_training', 'intensive_exercise'],
'type_weights': {
'active_training': 1.0,
'moderate_activity': 0.6,
'light_walks': 0.3
}
},
'HIGH': {
'min': 90,
'ideal': 120,
'max': 150,
'intensity': 'moderate_high',
'sessions': 'multiple',
'preferred_types': ['active_training', 'moderate_activity'],
'type_weights': {
'active_training': 0.9,
'moderate_activity': 0.8,
'light_walks': 0.4
}
},
'MODERATE HIGH': {
'min': 70,
'ideal': 90,
'max': 120,
'intensity': 'moderate',
'sessions': 'flexible',
'preferred_types': ['moderate_activity', 'active_training'],
'type_weights': {
'active_training': 0.8,
'moderate_activity': 0.9,
'light_walks': 0.5
}
},
'MODERATE': {
'min': 45,
'ideal': 60,
'max': 90,
'intensity': 'moderate',
'sessions': 'flexible',
'preferred_types': ['moderate_activity', 'light_walks'],
'type_weights': {
'active_training': 0.7,
'moderate_activity': 1.0,
'light_walks': 0.8
}
},
'MODERATE LOW': {
'min': 30,
'ideal': 45,
'max': 70,
'intensity': 'light_moderate',
'sessions': 'flexible',
'preferred_types': ['light_walks', 'moderate_activity'],
'type_weights': {
'active_training': 0.6,
'moderate_activity': 0.9,
'light_walks': 1.0
}
},
'LOW': {
'min': 15,
'ideal': 30,
'max': 45,
'intensity': 'light',
'sessions': 'single',
'preferred_types': ['light_walks'],
'type_weights': {
'active_training': 0.5,
'moderate_activity': 0.8,
'light_walks': 1.0
}
}
}
breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
# 時間匹配度評估(基礎分數)
def calculate_time_score():
if exercise_time >= breed_level['ideal']:
if exercise_time > breed_level['max']:
# 超出最大值的懲罰更明顯
excess = (exercise_time - breed_level['max']) / 30
return max(0.4, 1.0 - (excess * 0.2))
return 1.0 # 理想範圍內給予滿分
elif exercise_time >= breed_level['min']:
# 在最小值和理想值之間使用更陡峭的曲線
progress = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
return 0.5 + (progress * 0.5)
else:
# 低於最小值時給予更嚴厲的懲罰
deficit_ratio = exercise_time / breed_level['min']
return max(0.1, deficit_ratio * 0.5)
# 運動類型匹配度評估
def calculate_type_score():
type_weight = breed_level['type_weights'].get(exercise_type, 0.5)
# 根據運動需求等級調整類型權重
if breed_needs.upper() in ['VERY HIGH', 'HIGH']:
if exercise_type == 'light_walks':
type_weight *= 0.5 # 高需求品種做輕度運動的懲罰
elif breed_needs.upper() == 'LOW':
if exercise_type == 'active_training':
type_weight *= 0.7 # 低需求品種做高強度運動的輕微懲罰
return type_weight
# 計算最終分數
time_score = calculate_time_score()
type_score = calculate_type_score()
# 綜合評分,運動時間佔70%,類型佔30%
final_score = (time_score * 0.7) + (type_score * 0.3)
# 特殊情況調整
if exercise_time < breed_level['min'] * 0.5: # 運動時間嚴重不足
final_score *= 0.5
elif exercise_time > breed_level['max'] * 1.5: # 運動時間過多
final_score *= 0.7
return max(0.1, min(1.0, final_score))
def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
"""
計算美容需求分數,強化美容維護需求與使用者承諾度的匹配評估。
這個函數特別注意品種大小對美容工作的影響,以及不同程度的美容需求對時間投入的要求。
"""
# 重新設計基礎分數矩陣,讓美容需求的差異更加明顯
base_scores = {
"High": {
"low": 0.20, # 高需求對低承諾極不合適,顯著降低初始分數
"medium": 0.65, # 中等承諾仍有挑戰
"high": 1.0 # 高承諾最適合
},
"Moderate": {
"low": 0.45, # 中等需求對低承諾有困難
"medium": 0.85, # 較好的匹配
"high": 0.95 # 高承諾會有餘力
},
"Low": {
"low": 0.90, # 低需求對低承諾很合適
"medium": 0.85, # 略微降低以反映可能過度投入
"high": 0.80 # 可能造成資源浪費
}
}
# 取得基礎分數
base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
# 根據品種大小調整美容工作量
size_adjustments = {
"Giant": {
"low": -0.35, # 大型犬的美容工作量顯著增加
"medium": -0.20,
"high": -0.10
},
"Large": {
"low": -0.25,
"medium": -0.15,
"high": -0.05
},
"Medium": {
"low": -0.15,
"medium": -0.10,
"high": 0
},
"Small": {
"low": -0.10,
"medium": -0.05,
"high": 0
}
}
# 應用體型調整
size_adjustment = size_adjustments.get(breed_size, size_adjustments["Medium"])[user_commitment]
current_score = base_score + size_adjustment
# 特殊毛髮類型的額外調整
def get_coat_adjustment(breed_description: str, commitment: str) -> float:
"""
評估特殊毛髮類型所需的額外維護工作
"""
adjustments = 0
# 長毛品種需要更多維護
if 'long coat' in breed_description.lower():
coat_penalties = {
'low': -0.20,
'medium': -0.15,
'high': -0.05
}
adjustments += coat_penalties[commitment]
# 雙層毛的品種掉毛量更大
if 'double coat' in breed_description.lower():
double_coat_penalties = {
'low': -0.15,
'medium': -0.10,
'high': -0.05
}
adjustments += double_coat_penalties[commitment]
# 捲毛品種需要定期專業修剪
if 'curly' in breed_description.lower():
curly_penalties = {
'low': -0.15,
'medium': -0.10,
'high': -0.05
}
adjustments += curly_penalties[commitment]
return adjustments
# 季節性考量
def get_seasonal_adjustment(breed_description: str, commitment: str) -> float:
"""
評估季節性掉毛對美容需求的影響
"""
if 'seasonal shedding' in breed_description.lower():
seasonal_penalties = {
'low': -0.15,
'medium': -0.10,
'high': -0.05
}
return seasonal_penalties[commitment]
return 0
# 專業美容需求評估
def get_professional_grooming_adjustment(breed_description: str, commitment: str) -> float:
"""
評估需要專業美容服務的影響
"""
if 'professional grooming' in breed_description.lower():
grooming_penalties = {
'low': -0.20,
'medium': -0.15,
'high': -0.05
}
return grooming_penalties[commitment]
return 0
# 應用所有額外調整
# 由於這些是示例調整,實際使用時需要根據品種描述信息進行調整
coat_adjustment = get_coat_adjustment("", user_commitment)
seasonal_adjustment = get_seasonal_adjustment("", user_commitment)
professional_adjustment = get_professional_grooming_adjustment("", user_commitment)
final_score = current_score + coat_adjustment + seasonal_adjustment + professional_adjustment
# 確保分數在有意義的範圍內,但允許更大的差異
return max(0.1, min(1.0, final_score))
def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
"""
計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
重要改進:
1. 擴大基礎分數差異
2. 加重困難特徵的懲罰
3. 更細緻的品種特性評估
"""
# 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
base_scores = {
"High": {
"beginner": 0.15, # 降低起始分,高難度品種對新手幾乎不推薦
"intermediate": 0.65, # 中級玩家仍需謹慎
"advanced": 1.0 # 資深者能完全勝任
},
"Moderate": {
"beginner": 0.40, # 適中難度對新手仍具挑戰
"intermediate": 0.85, # 中級玩家較適合
"advanced": 0.95 # 資深者完全勝任
},
"Low": {
"beginner": 0.85, # 新手友善品種
"intermediate": 0.90, # 中級玩家幾乎完全勝任
"advanced": 0.85 # 資深者完全勝任
}
}
# 取得基礎分數
score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
temperament_lower = temperament.lower()
temperament_adjustments = 0.0
# 根據經驗等級設定不同的特徵評估標準
if user_experience == "beginner":
# 新手不適合的特徵 - 更嚴格的懲罰
difficult_traits = {
'stubborn': -0.30, # 固執性格嚴重影響新手
'independent': -0.25, # 獨立性高的品種不適合新手
'dominant': -0.25, # 支配性強的品種需要經驗處理
'strong-willed': -0.20, # 強勢性格需要技巧管理
'protective': -0.20, # 保護性強需要適當訓練
'aloof': -0.15, # 冷漠性格需要耐心培養
'energetic': -0.15, # 活潑好動需要經驗引導
'aggressive': -0.35 # 攻擊傾向極不適合新手
}
# 新手友善的特徵 - 適度的獎勵
easy_traits = {
'gentle': 0.05, # 溫和性格適合新手
'friendly': 0.05, # 友善性格容易相處
'eager to please': 0.08, # 願意服從較容易訓練
'patient': 0.05, # 耐心的特質有助於建立關係
'adaptable': 0.05, # 適應性強較容易照顧
'calm': 0.06 # 冷靜的性格較好掌握
}
# 計算特徵調整
for trait, penalty in difficult_traits.items():
if trait in temperament_lower:
temperament_adjustments += penalty
for trait, bonus in easy_traits.items():
if trait in temperament_lower:
temperament_adjustments += bonus
# 品種類型特殊評估
if 'terrier' in temperament_lower:
temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
elif 'working' in temperament_lower:
temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
elif 'guard' in temperament_lower:
temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
elif user_experience == "intermediate":
# 中級玩家的特徵評估
moderate_traits = {
'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
'independent': -0.10,
'intelligent': 0.08, # 聰明的特質可以好好發揮
'athletic': 0.06, # 運動能力可以適當訓練
'versatile': 0.07, # 多功能性可以開發
'protective': -0.08 # 保護性仍需注意
}
for trait, adjustment in moderate_traits.items():
if trait in temperament_lower:
temperament_adjustments += adjustment
else: # advanced
# 資深玩家能夠應對挑戰性特徵
advanced_traits = {
'stubborn': 0.05, # 困難特徵反而成為優勢
'independent': 0.05,
'intelligent': 0.10,
'protective': 0.05,
'strong-willed': 0.05
}
for trait, bonus in advanced_traits.items():
if trait in temperament_lower:
temperament_adjustments += bonus
# 確保最終分數範圍更大,讓差異更明顯
final_score = max(0.05, min(1.0, score + temperament_adjustments))
return final_score
def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
"""
計算品種健康分數,加強健康問題的影響力和與使用者敏感度的連結
重要改進:
1. 根據使用者的健康敏感度調整分數
2. 更嚴格的健康問題評估
3. 考慮多重健康問題的累積效應
4. 加入遺傳疾病的特別考量
"""
if breed_name not in breed_health_info:
return 0.5
health_notes = breed_health_info[breed_name]['health_notes'].lower()
# 嚴重健康問題 - 加重扣分
severe_conditions = {
'hip dysplasia': -0.25, # 髖關節發育不良,影響生活品質
'heart disease': -0.25, # 心臟疾病,需要長期治療
'progressive retinal atrophy': -0.20, # 進行性視網膜萎縮,導致失明
'bloat': -0.22, # 胃扭轉,致命風險
'epilepsy': -0.20, # 癲癇,需要長期藥物控制
'degenerative myelopathy': -0.20, # 脊髓退化,影響行動能力
'von willebrand disease': -0.18 # 血液凝固障礙
}
# 中度健康問題 - 適度扣分
moderate_conditions = {
'allergies': -0.12, # 過敏問題,需要持續關注
'eye problems': -0.15, # 眼睛問題,可能需要手術
'joint problems': -0.15, # 關節問題,影響運動能力
'hypothyroidism': -0.12, # 甲狀腺功能低下,需要藥物治療
'ear infections': -0.10, # 耳道感染,需要定期清理
'skin issues': -0.12 # 皮膚問題,需要特殊護理
}
# 輕微健康問題 - 輕微扣分
minor_conditions = {
'dental issues': -0.08, # 牙齒問題,需要定期護理
'weight gain tendency': -0.08, # 易胖體質,需要控制飲食
'minor allergies': -0.06, # 輕微過敏,可控制
'seasonal allergies': -0.06 # 季節性過敏
}
# 計算基礎健康分數
health_score = 1.0
# 健康問題累積效應計算
condition_counts = {
'severe': 0,
'moderate': 0,
'minor': 0
}
# 計算各等級健康問題的數量和影響
for condition, penalty in severe_conditions.items():
if condition in health_notes:
health_score += penalty
condition_counts['severe'] += 1
for condition, penalty in moderate_conditions.items():
if condition in health_notes:
health_score += penalty
condition_counts['moderate'] += 1
for condition, penalty in minor_conditions.items():
if condition in health_notes:
health_score += penalty
condition_counts['minor'] += 1
# 多重問題的額外懲罰(累積效應)
if condition_counts['severe'] > 1:
health_score *= (0.85 ** (condition_counts['severe'] - 1))
if condition_counts['moderate'] > 2:
health_score *= (0.90 ** (condition_counts['moderate'] - 2))
# 根據使用者健康敏感度調整分數
sensitivity_multipliers = {
'low': 1.1, # 較不在意健康問題
'medium': 1.0, # 標準評估
'high': 0.85 # 非常注重健康問題
}
health_score *= sensitivity_multipliers.get(user_prefs.health_sensitivity, 1.0)
# 壽命影響評估
try:
lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
years = float(lifespan.split('-')[0])
if years < 8:
health_score *= 0.85 # 短壽命顯著降低分數
elif years < 10:
health_score *= 0.92 # 較短壽命輕微降低分數
elif years > 13:
health_score *= 1.1 # 長壽命適度加分
except:
pass
# 特殊健康優勢
if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
health_score *= 1.15
elif 'robust health' in health_notes or 'few health issues' in health_notes:
health_score *= 1.1
# 確保分數在合理範圍內,但允許更大的分數差異
return max(0.1, min(1.0, health_score))
def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
"""
計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
"""
if breed_name not in breed_noise_info:
return 0.5
noise_info = breed_noise_info[breed_name]
noise_level = noise_info['noise_level'].lower()
noise_notes = noise_info['noise_notes'].lower()
# 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
base_scores = {
'low': {
'low': 1.0, # 安靜的狗對低容忍完美匹配
'medium': 0.95, # 安靜的狗對一般容忍很好
'high': 0.90 # 安靜的狗對高容忍當然可以
},
'medium': {
'low': 0.60, # 一般吠叫對低容忍較困難
'medium': 0.90, # 一般吠叫對一般容忍可接受
'high': 0.95 # 一般吠叫對高容忍很好
},
'high': {
'low': 0.25, # 愛叫的狗對低容忍極不適合
'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
'high': 0.90 # 愛叫的狗對高容忍可以接受
},
'varies': {
'low': 0.50, # 不確定的情況對低容忍風險較大
'medium': 0.75, # 不確定的情況對一般容忍可嘗試
'high': 0.85 # 不確定的情況對高容忍問題較小
}
}
# 取得基礎分數
base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
# 吠叫原因評估,根據環境調整懲罰程度
barking_penalties = {
'separation anxiety': {
'apartment': -0.30, # 在公寓對鄰居影響更大
'house_small': -0.25,
'house_large': -0.20
},
'excessive barking': {
'apartment': -0.25,
'house_small': -0.20,
'house_large': -0.15
},
'territorial': {
'apartment': -0.20, # 在公寓更容易被觸發
'house_small': -0.15,
'house_large': -0.10
},
'alert barking': {
'apartment': -0.15, # 公寓環境刺激較多
'house_small': -0.10,
'house_large': -0.08
},
'attention seeking': {
'apartment': -0.15,
'house_small': -0.12,
'house_large': -0.10
}
}
# 計算環境相關的吠叫懲罰
living_space = user_prefs.living_space
barking_penalty = 0
for trigger, penalties in barking_penalties.items():
if trigger in noise_notes:
barking_penalty += penalties.get(living_space, -0.15)
# 特殊情況評估
special_adjustments = 0
if user_prefs.has_children:
# 孩童年齡相關調整
child_age_adjustments = {
'toddler': {
'high': -0.20, # 幼童對吵鬧更敏感
'medium': -0.15,
'low': -0.05
},
'school_age': {
'high': -0.15,
'medium': -0.10,
'low': -0.05
},
'teenager': {
'high': -0.10,
'medium': -0.05,
'low': -0.02
}
}
# 根據孩童年齡和噪音等級調整
age_adj = child_age_adjustments.get(user_prefs.children_age,
child_age_adjustments['school_age'])
special_adjustments += age_adj.get(noise_level, -0.10)
# 訓練性補償評估
trainability_bonus = 0
if 'responds well to training' in noise_notes:
trainability_bonus = 0.12
elif 'can be trained' in noise_notes:
trainability_bonus = 0.08
elif 'difficult to train' in noise_notes:
trainability_bonus = 0.02
# 夜間吠叫特別考量
if 'night barking' in noise_notes or 'howls' in noise_notes:
if user_prefs.living_space == 'apartment':
special_adjustments -= 0.15
elif user_prefs.living_space == 'house_small':
special_adjustments -= 0.10
else:
special_adjustments -= 0.05
# 計算最終分數,確保更大的分數範圍
final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
return max(0.1, min(1.0, final_score))
# 1. 計算基礎分數
print("\n=== 開始計算品種相容性分數 ===")
print(f"處理品種: {breed_info.get('Breed', 'Unknown')}")
print(f"品種信息: {breed_info}")
print(f"使用者偏好: {vars(user_prefs)}")
# 計算所有基礎分數並整合到字典中
scores = {
'space': calculate_space_score(
breed_info['Size'],
user_prefs.living_space,
user_prefs.yard_access != 'no_yard',
breed_info.get('Exercise Needs', 'Moderate')
),
'exercise': calculate_exercise_score(
breed_info.get('Exercise Needs', 'Moderate'),
user_prefs.exercise_time,
user_prefs.exercise_type
),
'grooming': calculate_grooming_score(
breed_info.get('Grooming Needs', 'Moderate'),
user_prefs.grooming_commitment.lower(),
breed_info['Size']
),
'experience': calculate_experience_score(
breed_info.get('Care Level', 'Moderate'),
user_prefs.experience_level,
breed_info.get('Temperament', '')
),
'health': calculate_health_score(
breed_info.get('Breed', ''),
user_prefs
),
'noise': calculate_noise_score(
breed_info.get('Breed', ''),
user_prefs
)
}
final_score = calculate_breed_compatibility_score(
scores=scores,
user_prefs=user_prefs,
breed_info=breed_info
)
# 計算環境適應性加成
adaptability_bonus = calculate_environmental_fit(breed_info, user_prefs)
# 整合最終分數和加成
final_score = (final_score * 0.9) + (adaptability_bonus * 0.1)
final_score = amplify_score_extreme(final_score)
# 更新並返回完整的評分結果
scores.update({
'overall': final_score,
'adaptability_bonus': adaptability_bonus
})
return scores
except Exception as e:
print(f"\n!!!!! 發生嚴重錯誤 !!!!!")
print(f"錯誤類型: {type(e).__name__}")
print(f"錯誤訊息: {str(e)}")
print(f"完整錯誤追蹤:")
print(traceback.format_exc())
return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -> float:
"""計算品種與環境的適應性加成"""
adaptability_score = 0.0
description = breed_info.get('Description', '').lower()
temperament = breed_info.get('Temperament', '').lower()
# 環境適應性評估
if user_prefs.living_space == 'apartment':
if 'adaptable' in temperament or 'apartment' in description:
adaptability_score += 0.1
if breed_info.get('Size') == 'Small':
adaptability_score += 0.05
elif user_prefs.living_space == 'house_large':
if 'active' in temperament or 'energetic' in description:
adaptability_score += 0.1
# 氣候適應性
if user_prefs.climate in description or user_prefs.climate in temperament:
adaptability_score += 0.05
return min(0.2, adaptability_score)
# def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
# """
# 1. 運動類型與時間的精確匹配
# 2. 進階使用者的專業需求
# 3. 空間利用的實際效果
# 4. 條件組合的嚴格評估
# """
# def evaluate_perfect_conditions():
# """評估條件匹配度,特別強化運動類型與專業程度的評估"""
# perfect_matches = {
# 'size_match': 0,
# 'exercise_match': 0,
# 'experience_match': 0,
# 'living_condition_match': 0
# }
# # 運動類型與需求的精確匹配
# exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
# exercise_time = user_prefs.exercise_time
# exercise_type = user_prefs.exercise_type
# # 定義品種的理想運動模式
# breed_exercise_preferences = {
# 'VERY HIGH': {
# 'ideal_type': 'active_training',
# 'acceptable_types': ['moderate_activity'],
# 'time_ranges': {
# 'ideal': (120, 180),
# 'acceptable': (90, 200)
# }
# },
# 'HIGH': {
# 'ideal_type': 'moderate_activity',
# 'acceptable_types': ['active_training', 'light_walks'],
# 'time_ranges': {
# 'ideal': (90, 150),
# 'acceptable': (60, 180)
# }
# },
# 'MODERATE': {
# 'ideal_type': 'moderate_activity',
# 'acceptable_types': ['light_walks', 'active_training'],
# 'time_ranges': {
# 'ideal': (45, 90),
# 'acceptable': (30, 120)
# }
# },
# 'LOW': {
# 'ideal_type': 'light_walks',
# 'acceptable_types': ['moderate_activity'],
# 'time_ranges': {
# 'ideal': (30, 60),
# 'acceptable': (15, 90)
# }
# }
# }
# # 計算運動匹配度
# exercise_profile = breed_exercise_preferences.get(exercise_needs,
# breed_exercise_preferences['MODERATE'])
# # 時間匹配度計算
# time_ranges = exercise_profile['time_ranges']
# if time_ranges['ideal'][0] <= exercise_time <= time_ranges['ideal'][1]:
# time_score = 1.0
# elif time_ranges['acceptable'][0] <= exercise_time <= time_ranges['acceptable'][1]:
# # 計算與理想範圍的距離
# if exercise_time < time_ranges['ideal'][0]:
# deviation = (time_ranges['ideal'][0] - exercise_time) / time_ranges['ideal'][0]
# else:
# deviation = (exercise_time - time_ranges['ideal'][1]) / time_ranges['ideal'][1]
# time_score = max(0.4, 1 - (deviation * 0.6))
# else:
# time_score = 0.3
# # 運動類型匹配度計算
# if exercise_type == exercise_profile['ideal_type']:
# type_score = 1.0
# elif exercise_type in exercise_profile['acceptable_types']:
# type_score = 0.7
# else:
# type_score = 0.4
# # 若運動時間過長但強度不足,額外降低分數
# if exercise_time > time_ranges['acceptable'][1] and exercise_type != exercise_profile['ideal_type']:
# type_score *= 0.7
# perfect_matches['exercise_match'] = (time_score * 0.6) + (type_score * 0.4)
# # 體型與空間的實際利用評估
# space_utilization = {
# 'apartment': {
# 'Small': 1.0,
# 'Medium': 0.4,
# 'Large': 0.2,
# 'Giant': 0.1
# },
# 'house_small': {
# 'Small': 0.9,
# 'Medium': 1.0,
# 'Large': 0.5,
# 'Giant': 0.3
# },
# 'house_large': {
# 'Small': 0.7,
# 'Medium': 0.9,
# 'Large': 1.0,
# 'Giant': 0.95
# }
# }
# # 增加活動空間需求評估
# space_needs = 'high' if exercise_needs in ['VERY HIGH', 'HIGH'] else 'moderate'
# if space_needs == 'high' and user_prefs.living_space != 'house_large':
# space_score = space_utilization[user_prefs.living_space][breed_info['Size']] * 0.8
# else:
# space_score = space_utilization.get(user_prefs.living_space,
# space_utilization['house_small'])[breed_info['Size']]
# perfect_matches['size_match'] = space_score
# # 經驗需求的專業評估
# care_level = breed_info.get('Care Level', 'MODERATE').upper()
# temperament = breed_info.get('Temperament', '').lower()
# # 定義進階特徵
# advanced_traits = ['working', 'independent', 'dominant', 'protective']
# advanced_trait_count = sum(1 for trait in advanced_traits if trait in temperament)
# # 經驗匹配度計算
# experience_matrix = {
# 'HIGH': {
# 'beginner': 0.2, # 更嚴格的新手限制
# 'intermediate': 0.6,
# 'advanced': 1.0
# },
# 'MODERATE': {
# 'beginner': 0.5,
# 'intermediate': 0.9,
# 'advanced': 0.95
# },
# 'LOW': {
# 'beginner': 0.9,
# 'intermediate': 0.85,
# 'advanced': 0.8 # 對專家稍微降低簡單品種的分數
# }
# }
# experience_score = experience_matrix[care_level][user_prefs.experience_level]
# # 根據進階特徵調整分數
# if advanced_trait_count > 0:
# if user_prefs.experience_level == 'beginner':
# experience_score *= (0.8 ** advanced_trait_count)
# elif user_prefs.experience_level == 'advanced':
# experience_score *= (1.1 ** min(advanced_trait_count, 2))
# perfect_matches['experience_match'] = experience_score
# # 生活條件整體評估
# living_score = 1.0
# # 院子影響的嚴格評估
# if breed_info.get('Exercise Needs', 'MODERATE').upper() in ['HIGH', 'VERY HIGH']:
# yard_impacts = {
# 'no_yard': 0.5, # 更嚴格的懲罰
# 'shared_yard': 0.7,
# 'private_yard': 1.0
# }
# living_score *= yard_impacts.get(user_prefs.yard_access, 0.7)
# # 時間可用性評估
# time_impacts = {
# 'limited': 0.6, # 更嚴格的時間限制影響
# 'moderate': 0.8,
# 'flexible': 1.0
# }
# living_score *= time_impacts.get(user_prefs.time_availability, 0.8)
# perfect_matches['living_condition_match'] = living_score
# return perfect_matches
# def calculate_weights():
# """計算動態權重,強化條件極端情況的影響"""
# base_weights = {
# 'space': 0.20,
# 'exercise': 0.20,
# 'experience': 0.20,
# 'grooming': 0.15,
# 'noise': 0.15,
# 'health': 0.10
# }
# # 計算條件極端度
# def calculate_condition_extremity():
# extremities = {}
# # 運動時間極端度評估
# if user_prefs.exercise_time < 30:
# extremities['exercise'] = ('very_low', 0.9)
# elif user_prefs.exercise_time < 60:
# extremities['exercise'] = ('low', 0.7)
# elif user_prefs.exercise_time > 150:
# extremities['exercise'] = ('very_high', 0.9)
# elif user_prefs.exercise_time > 120:
# extremities['exercise'] = ('high', 0.7)
# else:
# extremities['exercise'] = ('moderate', 0.3)
# # 空間限制極端度評估
# if user_prefs.living_space == 'apartment':
# extremities['space'] = ('very_restricted', 0.9)
# elif user_prefs.living_space == 'house_small':
# extremities['space'] = ('restricted', 0.6)
# else:
# extremities['space'] = ('spacious', 0.3)
# return extremities
# extremities = calculate_condition_extremity()
# # 權重調整
# weight_adjustments = {}
# # 空間權重調整
# if extremities['space'][0] == 'very_restricted':
# weight_adjustments['space'] = 3.0
# weight_adjustments['noise'] = 2.5
# elif extremities['space'][0] == 'restricted':
# weight_adjustments['space'] = 2.0
# weight_adjustments['noise'] = 1.8
# elif extremities['space'][0] == 'spacious':
# weight_adjustments['space'] = 0.7 # 大空間時降低空間權重
# weight_adjustments['exercise'] = 1.5 # 提升運動重要性
# # 運動需求權重調整
# if extremities['exercise'][0] in ['very_low', 'very_high']:
# weight_adjustments['exercise'] = 3.0
# elif extremities['exercise'][0] in ['low', 'high']:
# weight_adjustments['exercise'] = 2.0
# # 經驗需求權重調整
# if user_prefs.experience_level == 'beginner':
# weight_adjustments['experience'] = 2.5
# elif user_prefs.experience_level == 'advanced':
# weight_adjustments['experience'] = 2.0
# # 應用權重調整
# final_weights = base_weights.copy()
# for key, adjustment in weight_adjustments.items():
# final_weights[key] *= adjustment
# return final_weights
# def apply_special_case_adjustments(score):
# """處理特殊情況,更嚴格的條件組合評估"""
# severity = 1.0
# # 空間與運動組合的嚴格評估
# if user_prefs.living_space == 'apartment':
# if breed_info.get('Exercise Needs', 'MODERATE').upper() == 'VERY HIGH':
# severity *= 0.5 # 更嚴重的懲罰
# elif breed_info.get('Exercise Needs') == 'HIGH':
# severity *= 0.6
# if breed_info['Size'] in ['Large', 'Giant']:
# severity *= 0.5
# # 經驗與品種難度組合的嚴格評估
# if user_prefs.experience_level == 'beginner':
# if breed_info.get('Care Level') == 'HIGH':
# if user_prefs.has_children:
# severity *= 0.5
# else:
# severity *= 0.6
# # 時間限制與需求組合的嚴格評估
# if user_prefs.time_availability == 'limited':
# if breed_info.get('Exercise Needs').upper() in ['VERY HIGH', 'HIGH']:
# severity *= 0.6
# # 運動類型不匹配的懲罰
# if user_prefs.exercise_time > 120:
# exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
# if exercise_needs == 'LOW':
# severity *= 0.7
# elif exercise_needs == 'VERY HIGH' and user_prefs.exercise_type == 'light_walks':
# severity *= 0.6
# return score * severity
# # 評估完美匹配條件
# perfect_conditions = evaluate_perfect_conditions()
# # 計算動態權重
# weights = calculate_weights()
# # 正規化權重
# total_weight = sum(weights.values())
# normalized_weights = {k: v/total_weight for k, v in weights.items()}
# # 計算基礎分數
# base_score = sum(scores[k] * normalized_weights[k] for k in scores.keys())
# # 完美匹配獎勵計算(降低獎勵影響)
# perfect_bonus = 1.0
# perfect_bonus += 0.12 * perfect_conditions['size_match']
# perfect_bonus += 0.12 * perfect_conditions['exercise_match']
# perfect_bonus += 0.12 * perfect_conditions['experience_match']
# perfect_bonus += 0.04 * perfect_conditions['living_condition_match']
# # 品種特性加成
# breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
# # 計算最終分數
# final_score = (base_score * 0.85 + breed_bonus * 0.15) * perfect_bonus
# # 應用特殊情況調整
# final_score = apply_special_case_adjustments(final_score)
# return min(1.0, final_score)
def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
"""
1. 運動類型與時間的精確匹配
2. 進階使用者的專業需求
3. 空間利用的實際效果
4. 條件組合的嚴格評估
"""
def evaluate_perfect_conditions():
"""
評估條件匹配度,特別強化:
1. 運動類型與時間的綜合評估
2. 專業技能需求評估
3. 品種特性評估
"""
perfect_matches = {
'size_match': 0,
'exercise_match': 0,
'experience_match': 0,
'living_condition_match': 0,
'breed_trait_match': 0 # 新增品種特性匹配度
}
# 第一部分:運動需求評估
def evaluate_exercise_compatibility():
"""
評估運動需求的匹配度,特別關注:
1. 時間與強度的合理搭配
2. 不同品種的運動特性
3. 運動類型的適配性
這個函數就像是一個體育教練,需要根據每個"運動員"(狗品種)的特點,
為他們制定合適的訓練計劃。
"""
exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
exercise_time = user_prefs.exercise_time
exercise_type = user_prefs.exercise_type
temperament = breed_info.get('Temperament', '').lower()
description = breed_info.get('Description', '').lower()
# 定義更精確的品種運動特性
breed_exercise_patterns = {
'sprint_type': { # 短跑型犬種,如 Whippet, Saluki
'identifiers': ['fast', 'speed', 'sprint', 'racing', 'coursing', 'sight hound'],
'ideal_exercise': {
'active_training': 1.0, # 完美匹配高強度訓練
'moderate_activity': 0.5, # 持續運動不是最佳選擇
'light_walks': 0.3 # 輕度運動效果很差
},
'time_ranges': {
'ideal': (30, 60), # 最適合的運動時間範圍
'acceptable': (20, 90), # 可以接受的時間範圍
'penalty_start': 90 # 開始給予懲罰的時間點
},
'penalty_rate': 0.8 # 超出範圍時的懲罰係數
},
'endurance_type': { # 耐力型犬種,如 Border Collie
'identifiers': ['herding', 'working', 'tireless', 'energetic', 'stamina', 'athletic'],
'ideal_exercise': {
'active_training': 0.9, # 高強度訓練很好
'moderate_activity': 1.0, # 持續運動是最佳選擇
'light_walks': 0.4 # 輕度運動不足
},
'time_ranges': {
'ideal': (90, 180), # 需要較長的運動時間
'acceptable': (60, 180),
'penalty_start': 60 # 運動時間過短會受罰
},
'penalty_rate': 0.7
},
'moderate_type': { # 一般活動型犬種,如 Labrador
'identifiers': ['friendly', 'playful', 'adaptable', 'versatile', 'companion'],
'ideal_exercise': {
'active_training': 0.8,
'moderate_activity': 1.0,
'light_walks': 0.6
},
'time_ranges': {
'ideal': (60, 120),
'acceptable': (45, 150),
'penalty_start': 150
},
'penalty_rate': 0.6
}
}
def determine_breed_type():
"""
根據品種的描述和性格特徵判斷其運動類型。
就像體育教練要先了解運動員的特點才能制定訓練計劃。
"""
# 優先檢查特殊運動類型的標識符
for breed_type, pattern in breed_exercise_patterns.items():
if any(identifier in temperament or identifier in description
for identifier in pattern['identifiers']):
return breed_type
# 如果沒有特殊標識,根據運動需求級別判斷
if exercise_needs in ['VERY HIGH', 'HIGH']:
return 'endurance_type'
elif exercise_needs == 'LOW':
return 'moderate_type'
return 'moderate_type'
def calculate_time_match(pattern):
"""
計算運動時間的匹配度。
這就像在判斷運動時間是否符合訓練計劃。
"""
ideal_min, ideal_max = pattern['time_ranges']['ideal']
accept_min, accept_max = pattern['time_ranges']['acceptable']
penalty_start = pattern['time_ranges']['penalty_start']
# 在理想範圍內
if ideal_min <= exercise_time <= ideal_max:
return 1.0
# 超出可接受範圍的嚴格懲罰
elif exercise_time < accept_min:
deficit = accept_min - exercise_time
return max(0.2, 1 - (deficit / accept_min) * 1.2)
elif exercise_time > accept_max:
excess = exercise_time - penalty_start
penalty = min(0.8, (excess / penalty_start) * pattern['penalty_rate'])
return max(0.2, 1 - penalty)
# 在可接受範圍但不在理想範圍
else:
if exercise_time < ideal_min:
progress = (exercise_time - accept_min) / (ideal_min - accept_min)
return 0.6 + (0.4 * progress)
else:
remaining = (accept_max - exercise_time) / (accept_max - ideal_max)
return 0.6 + (0.4 * remaining)
def apply_special_adjustments(time_score, type_score, breed_type, pattern):
"""
處理特殊情況,確保運動方式真正符合品種需求。
就像確保訓練計劃不會違背運動員的特點。
"""
# 短跑型品種的特殊處理
if breed_type == 'sprint_type':
if exercise_time > pattern['time_ranges']['penalty_start']:
# 時間過長的嚴重懲罰
time_score *= 0.5
# 如果同時運動類型不適合,更嚴重的懲罰
if exercise_type != 'active_training':
type_score *= 0.4
# 耐力型品種的特殊處理
elif breed_type == 'endurance_type':
if exercise_time < pattern['time_ranges']['penalty_start']:
time_score *= 0.6
# 運動強度不足的懲罰
if exercise_type == 'light_walks' and exercise_time > 90:
type_score *= 0.5
return time_score, type_score
# 執行評估流程
breed_type = determine_breed_type()
pattern = breed_exercise_patterns[breed_type]
# 計算基礎分數
time_score = calculate_time_match(pattern)
type_score = pattern['ideal_exercise'].get(exercise_type, 0.5)
# 應用特殊調整
time_score, type_score = apply_special_adjustments(time_score, type_score, breed_type, pattern)
# 根據品種類型決定最終權重
if breed_type == 'sprint_type':
if exercise_time > pattern['time_ranges']['penalty_start']:
# 超時時更重視運動類型的匹配度
return (time_score * 0.3) + (type_score * 0.7)
else:
return (time_score * 0.5) + (type_score * 0.5)
elif breed_type == 'endurance_type':
if exercise_time < pattern['time_ranges']['penalty_start']:
# 時間不足時更重視時間因素
return (time_score * 0.7) + (type_score * 0.3)
else:
return (time_score * 0.6) + (type_score * 0.4)
else:
return (time_score * 0.5) + (type_score * 0.5)
# 第二部分:專業技能需求評估
def evaluate_expertise_requirements():
care_level = breed_info.get('Care Level', 'MODERATE').upper()
temperament = breed_info.get('Temperament', '').lower()
# 定義專業技能要求
expertise_requirements = {
'training_complexity': {
'HIGH': {'beginner': 0.3, 'intermediate': 0.7, 'advanced': 1.0},
'MODERATE': {'beginner': 0.6, 'intermediate': 0.9, 'advanced': 1.0},
'LOW': {'beginner': 0.9, 'intermediate': 0.95, 'advanced': 0.9}
},
'special_traits': {
'working': 0.2, # 工作犬需要額外技能
'herding': 0.2, # 牧羊犬需要特殊訓練
'intelligent': 0.15,# 高智商犬種需要心智刺激
'independent': 0.15,# 獨立性強的需要特殊處理
'protective': 0.1 # 護衛犬需要適當訓練
}
}
# 基礎分數
base_score = expertise_requirements['training_complexity'][care_level][user_prefs.experience_level]
# 特殊特徵評估
trait_penalty = 0
for trait, penalty in expertise_requirements['special_traits'].items():
if trait in temperament:
if user_prefs.experience_level == 'beginner':
trait_penalty += penalty
elif user_prefs.experience_level == 'advanced':
trait_penalty -= penalty * 0.5 # 專家反而因應對特殊特徵而加分
return max(0.2, min(1.0, base_score - trait_penalty))
# 第三部分:生活環境評估
def evaluate_living_conditions():
size = breed_info['Size']
exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
# 空間需求矩陣
space_requirements = {
'apartment': {
'Small': 1.0, 'Medium': 0.4, 'Large': 0.2, 'Giant': 0.1
},
'house_small': {
'Small': 0.9, 'Medium': 1.0, 'Large': 0.5, 'Giant': 0.3
},
'house_large': {
'Small': 0.8, 'Medium': 0.9, 'Large': 1.0, 'Giant': 1.0
}
}
# 基礎空間分數
space_score = space_requirements.get(user_prefs.living_space,
space_requirements['house_small'])[size]
# 活動空間需求調整
if exercise_needs in ['HIGH', 'VERY HIGH']:
if user_prefs.living_space != 'house_large':
space_score *= 0.8
# 院子可用性評估
yard_scores = {
'no_yard': 0.7,
'shared_yard': 0.85,
'private_yard': 1.0
}
space_score *= yard_scores.get(user_prefs.yard_access, 0.8)
return space_score
# 第四部分:品種特性評估(新增)
def evaluate_breed_traits():
temperament = breed_info.get('Temperament', '').lower()
description = breed_info.get('Description', '').lower()
trait_scores = []
# 評估性格特徵
if user_prefs.has_children:
if 'good with children' in description:
trait_scores.append(1.0)
elif 'patient' in temperament or 'gentle' in temperament:
trait_scores.append(0.8)
else:
trait_scores.append(0.5)
# 評估適應性
adaptability_keywords = ['adaptable', 'versatile', 'flexible']
if any(keyword in temperament for keyword in adaptability_keywords):
trait_scores.append(1.0)
else:
trait_scores.append(0.7)
return sum(trait_scores) / len(trait_scores) if trait_scores else 0.7
# 計算各項匹配分數
perfect_matches['exercise_match'] = evaluate_exercise_compatibility()
perfect_matches['experience_match'] = evaluate_expertise_requirements()
perfect_matches['living_condition_match'] = evaluate_living_conditions()
perfect_matches['size_match'] = evaluate_living_conditions() # 共用生活環境評估
perfect_matches['breed_trait_match'] = evaluate_breed_traits()
return perfect_matches
def calculate_weights():
"""
計算動態權重,特別關注:
1. 條件極端度對權重的影響
2. 多重條件組合的權重調整
3. 品種特性對權重分配的影響
"""
# 基礎權重設定
base_weights = {
'space': 0.20,
'exercise': 0.20,
'experience': 0.20,
'grooming': 0.15,
'noise': 0.15,
'health': 0.10
}
def analyze_condition_extremity():
"""評估各條件的極端程度及其影響"""
extremities = {}
# 運動時間極端度分析
def analyze_exercise_extremity():
if user_prefs.exercise_time <= 30:
return ('extremely_low', 0.9)
elif user_prefs.exercise_time <= 60:
return ('low', 0.7)
elif user_prefs.exercise_time >= 180:
return ('extremely_high', 0.9)
elif user_prefs.exercise_time >= 120:
return ('high', 0.7)
return ('moderate', 0.4)
# 空間限制極端度分析
def analyze_space_extremity():
space_extremity = {
'apartment': ('highly_restricted', 0.9),
'house_small': ('restricted', 0.6),
'house_large': ('spacious', 0.4)
}
return space_extremity.get(user_prefs.living_space, ('moderate', 0.5))
# 經驗水平極端度分析
def analyze_experience_extremity():
experience_extremity = {
'beginner': ('low', 0.8),
'intermediate': ('moderate', 0.5),
'advanced': ('high', 0.7)
}
return experience_extremity.get(user_prefs.experience_level, ('moderate', 0.5))
# 整合各項極端度評估
extremities['exercise'] = analyze_exercise_extremity()
extremities['space'] = analyze_space_extremity()
extremities['experience'] = analyze_experience_extremity()
return extremities
def calculate_weight_adjustments(extremities):
"""根據條件極端度計算權重調整"""
adjustments = {}
# 空間權重調整邏輯
if extremities['space'][0] == 'highly_restricted':
adjustments['space'] = 2.5
adjustments['noise'] = 2.0
elif extremities['space'][0] == 'restricted':
adjustments['space'] = 1.8
adjustments['noise'] = 1.5
elif extremities['space'][0] == 'spacious':
adjustments['space'] = 0.8 # 降低空間權重
adjustments['exercise'] = 1.4 # 提升運動重要性
# 運動需求權重調整
if extremities['exercise'][0] in ['extremely_low', 'extremely_high']:
adjustments['exercise'] = 2.5
elif extremities['exercise'][0] in ['low', 'high']:
adjustments['exercise'] = 1.8
# 經驗需求權重調整
if extremities['experience'][0] == 'low':
adjustments['experience'] = 2.2
if breed_info.get('Care Level') == 'HIGH':
adjustments['experience'] = 2.5
elif extremities['experience'][0] == 'high':
adjustments['experience'] = 1.8
# 綜合條件影響
def adjust_for_combinations():
# 公寓 + 高運動需求
if (extremities['space'][0] == 'highly_restricted' and
extremities['exercise'][0] in ['high', 'extremely_high']):
adjustments['space'] = adjustments.get('space', 1.0) * 1.3
adjustments['exercise'] = adjustments.get('exercise', 1.0) * 1.3
# 新手 + 大空間 + 高運動量
if (extremities['experience'][0] == 'low' and
extremities['space'][0] == 'spacious' and
extremities['exercise'][0] in ['high', 'extremely_high']):
adjustments['experience'] = adjustments.get('experience', 1.0) * 1.4
# 空間充足時降低其權重
if extremities['space'][0] == 'spacious':
for key in ['grooming', 'health', 'noise']:
if key not in adjustments:
adjustments[key] = 1.2
adjust_for_combinations()
return adjustments
# 獲取條件極端度
extremities = analyze_condition_extremity()
# 計算權重調整
weight_adjustments = calculate_weight_adjustments(extremities)
# 應用權重調整
final_weights = base_weights.copy()
for key, adjustment in weight_adjustments.items():
if key in final_weights:
final_weights[key] *= adjustment
return final_weights
def apply_special_case_adjustments(score):
"""
處理特殊情況的分數調整,著重:
1. 條件組合的協同效應
2. 品種特性的特殊要求
3. 極端情況的嚴格處理
"""
severity_multiplier = 1.0
def evaluate_spatial_exercise_combination():
"""評估空間與運動需求的組合影響"""
multiplier = 1.0
if user_prefs.living_space == 'apartment':
if breed_info.get('Exercise Needs', 'MODERATE').upper() == 'VERY HIGH':
multiplier *= 0.5
elif breed_info.get('Exercise Needs') == 'HIGH':
multiplier *= 0.6
# 大型犬在公寓的額外懲罰
if breed_info['Size'] in ['Large', 'Giant']:
multiplier *= 0.5
return multiplier
def evaluate_experience_combination():
"""評估經驗需求的複合影響"""
multiplier = 1.0
temperament = breed_info.get('Temperament', '').lower()
care_level = breed_info.get('Care Level', 'MODERATE')
# 新手飼主的特殊考量
if user_prefs.experience_level == 'beginner':
# 高難度品種的嚴格限制
if care_level == 'HIGH':
if user_prefs.has_children:
multiplier *= 0.5
else:
multiplier *= 0.6
# 特殊性格特徵的影響
challenging_traits = ['independent', 'dominant', 'protective', 'strong-willed']
trait_count = sum(1 for trait in challenging_traits if trait in temperament)
if trait_count > 0:
multiplier *= (0.8 ** trait_count)
# 進階飼主的特殊考量
elif user_prefs.experience_level == 'advanced':
if care_level == 'LOW' and breed_info.get('Exercise Needs') == 'LOW':
multiplier *= 0.9 # 對專家來說可能過於簡單
return multiplier
def evaluate_breed_specific_requirements():
"""評估品種特定的要求"""
multiplier = 1.0
exercise_time = user_prefs.exercise_time
exercise_type = user_prefs.exercise_type
# 特定品種的運動模式評估
if 'sprint' in breed_info.get('Temperament', '').lower():
if exercise_time > 120 and exercise_type != 'active_training':
multiplier *= 0.7 # 衝刺型品種不適合長時間中低強度運動
# 工作犬種的特殊需求
if any(trait in breed_info.get('Temperament', '').lower()
for trait in ['working', 'herding']):
if exercise_time < 90 or exercise_type == 'light_walks':
multiplier *= 0.7
return multiplier
def evaluate_environmental_impact():
"""評估環境因素的影響"""
multiplier = 1.0
# 時間限制的影響
if user_prefs.time_availability == 'limited':
if breed_info.get('Exercise Needs').upper() in ['VERY HIGH', 'HIGH']:
multiplier *= 0.7
# 噪音敏感度的影響
if user_prefs.noise_tolerance == 'low':
if breed_info.get('Breed') in breed_noise_info:
if breed_noise_info[breed_info['Breed']]['noise_level'].lower() == 'high':
multiplier *= 0.6
return multiplier
# 整合所有特殊情況的評估
severity_multiplier *= evaluate_spatial_exercise_combination()
severity_multiplier *= evaluate_experience_combination()
severity_multiplier *= evaluate_breed_specific_requirements()
severity_multiplier *= evaluate_environmental_impact()
# 確保最終分數在合理範圍內
final_score = score * severity_multiplier
return max(0.2, min(1.0, final_score))
def calculate_base_score(scores: dict, weights: dict) -> float:
"""
計算基礎分數,加入更嚴格的評估機制。
就像學校的評分系統,某些科目不及格會嚴重影響總成績。
"""
# 檢查關鍵指標是否有嚴重不足
critical_thresholds = {
'space': 0.7,
'exercise': 0.7,
'experience': 0.7,
'noise': 0.65
}
critical_failures = []
for metric, threshold in critical_thresholds.items():
if scores[metric] < threshold:
critical_failures.append((metric, scores[metric]))
# 計算基礎加權分數
base_score = sum(scores[k] * weights[k] for k in scores.keys())
# 根據關鍵指標的不足程度進行懲罰
if critical_failures:
# 計算最嚴重的不足程度
worst_failure = min(score for _, score in critical_failures)
penalty = (critical_thresholds['space'] - worst_failure) * 0.6
base_score *= (1 - penalty)
# 多個指標不足時的額外懲罰
if len(critical_failures) > 1:
base_score *= (0.9 ** (len(critical_failures) - 1))
return base_score
def evaluate_condition_interactions(scores: dict) -> float:
"""
評估不同條件之間的相互影響。
就像運動訓練中,不同因素之間的配合度會影響整體效果。
"""
interaction_penalty = 1.0
# 居住空間與運動需求的互動
if user_prefs.living_space == 'house_small':
if user_prefs.exercise_time > 120:
interaction_penalty *= 0.85
elif user_prefs.exercise_time > 90:
interaction_penalty *= 0.9
# 經驗等級與其他因素的互動
if user_prefs.experience_level == 'beginner':
if breed_info.get('Care Level') == 'HIGH':
interaction_penalty *= 0.8
if user_prefs.exercise_time > 150:
interaction_penalty *= 0.85
if breed_info.get('Exercise Needs', 'MODERATE').upper() == 'VERY HIGH':
interaction_penalty *= 0.85
# 空間限制與品種大小的互動
if user_prefs.living_space != 'house_large':
if breed_info['Size'] in ['Large', 'Giant']:
interaction_penalty *= 0.8
# 運動時間與類型的互動
exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
if exercise_needs == 'VERY HIGH' and user_prefs.exercise_type == 'light_walks':
interaction_penalty *= 0.85
return interaction_penalty
def calculate_adjusted_perfect_bonus(perfect_conditions: dict) -> float:
"""
計算完美匹配獎勵,但更注重條件的整體表現。
就像全能運動員的評分,需要在各個項目都表現出色。
"""
bonus = 1.0
# 降低單項獎勵的影響力
bonus += 0.06 * perfect_conditions['size_match']
bonus += 0.06 * perfect_conditions['exercise_match']
bonus += 0.06 * perfect_conditions['experience_match']
bonus += 0.03 * perfect_conditions['living_condition_match']
# 如果有任何條件表現不佳,降低整體獎勵
low_scores = [score for score in perfect_conditions.values() if score < 0.6]
if low_scores:
bonus *= (0.85 ** len(low_scores))
# 確保獎勵不會過高
return min(1.25, bonus)
def apply_breed_specific_adjustments(score: float) -> float:
"""
根據品種特性進行最終調整。
考慮品種的特殊性質和限制因素。
"""
# 檢查是否存在極端不匹配的情況
exercise_mismatch = False
size_mismatch = False
experience_mismatch = False
# 運動需求極端不匹配
if breed_info.get('Exercise Needs', 'MODERATE').upper() == 'VERY HIGH':
if user_prefs.exercise_time < 90 or user_prefs.exercise_type == 'light_walks':
exercise_mismatch = True
# 體型與空間極端不匹配
if user_prefs.living_space == 'apartment' and breed_info['Size'] in ['Large', 'Giant']:
size_mismatch = True
# 經驗需求極端不匹配
if user_prefs.experience_level == 'beginner' and breed_info.get('Care Level') == 'HIGH':
experience_mismatch = True
# 根據不匹配的數量進行懲罰
mismatch_count = sum([exercise_mismatch, size_mismatch, experience_mismatch])
if mismatch_count > 0:
score *= (0.8 ** mismatch_count)
return score
# 計算動態權重
weights = calculate_weights()
# 正規化權重
total_weight = sum(weights.values())
normalized_weights = {k: v/total_weight for k, v in weights.items()}
# 計算基礎分數
base_score = calculate_base_score(scores, normalized_weights)
# 評估條件互動
interaction_multiplier = evaluate_condition_interactions(scores)
# 計算完美匹配獎勵
perfect_conditions = evaluate_perfect_conditions()
perfect_bonus = calculate_adjusted_perfect_bonus(perfect_conditions)
# 計算初步分數
preliminary_score = base_score * interaction_multiplier * perfect_bonus
# 應用品種特定調整
final_score = apply_breed_specific_adjustments(preliminary_score)
# 確保分數在合理範圍內,並降低最高可能分數
max_possible_score = 0.96 # 降低最高可能分數
min_possible_score = 0.3
return min(max_possible_score, max(min_possible_score, final_score))
def amplify_score_extreme(score: float) -> float:
"""
- 完美匹配可達到95-99%
- 優秀匹配在90-95%
- 良好匹配在85-90%
- 一般匹配在75-85%
- 較差匹配在65-75%
- 極差匹配在50-65%
"""
def smooth_curve(x: float, steepness: float = 12) -> float:
"""使用sigmoid curve"""
import math
return 1 / (1 + math.exp(-steepness * (x - 0.5)))
if score >= 0.9:
# 完美匹配:95-99%
position = (score - 0.9) / 0.1
return 0.95 + (position * 0.04)
elif score >= 0.8:
# 優秀匹配:90-95%
position = (score - 0.8) / 0.1
return 0.90 + (position * 0.05)
elif score >= 0.7:
# 良好匹配:85-90%
position = (score - 0.7) / 0.1
return 0.85 + (position * 0.05)
elif score >= 0.5:
# 一般匹配:75-85%
position = (score - 0.5) / 0.2
base = 0.75
return base + (smooth_curve(position) * 0.10)
elif score >= 0.3:
# 較差匹配:65-75%
position = (score - 0.3) / 0.2
base = 0.65
return base + (smooth_curve(position) * 0.10)
else:
# 極差匹配:50-65%
position = score / 0.3
base = 0.50
return base + (smooth_curve(position) * 0.15)