from dataclasses import dataclass from breed_health_info import breed_health_info from breed_noise_info import breed_noise_info import traceback @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 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) # return min(0.5, max(-0.25, bonus)) @staticmethod def calculate_breed_bonus(breed_info: dict, user_prefs: UserPreferences) -> float: """ 計算品種的額外加分,評估品種的特殊特徵對使用者需求的適配性。 這個函數考慮四個主要面向: 1. 壽命評估:考慮飼養的長期承諾 2. 性格特徵評估:評估品種性格與使用者需求的匹配度 3. 環境適應性:評估品種在特定生活環境中的表現 4. 家庭相容性:特別關注品種與家庭成員的互動 """ bonus = 0.0 temperament = breed_info.get('Temperament', '').lower() # 壽命評估 - 重新設計以反映更實際的考量 try: lifespan = breed_info.get('Lifespan', '10-12 years') years = [int(x) for x in lifespan.split('-')[0].split()[0:1]] avg_years = float(years[0]) # 根據壽命長短給予不同程度的獎勵或懲罰 if avg_years < 8: bonus -= 0.08 # 短壽命可能帶來情感負擔 elif avg_years < 10: bonus -= 0.04 # 稍短壽命輕微降低評分 elif avg_years > 13: bonus += 0.06 # 長壽命適度加分 elif avg_years > 15: bonus += 0.08 # 特別長壽的品種獲得更多加分 except: pass # 性格特徵評估 - 擴充並細化評分標準 positive_traits = { 'friendly': 0.08, # 提高友善性的重要性 'gentle': 0.08, # 溫和性格更受歡迎 'patient': 0.07, # 耐心是重要特質 'intelligent': 0.06, # 聰明但不過分重要 'adaptable': 0.06, # 適應性佳的特質 'affectionate': 0.06, # 親密性很重要 'easy-going': 0.05, # 容易相處的性格 'calm': 0.05 # 冷靜的特質 } negative_traits = { 'aggressive': -0.15, # 嚴重懲罰攻擊性 'stubborn': -0.10, # 固執性格不易處理 'dominant': -0.10, # 支配性可能造成問題 'aloof': -0.08, # 冷漠性格影響互動 'nervous': -0.08, # 緊張性格需要更多關注 'protective': -0.06 # 過度保護可能有風險 } # 性格評分計算 - 加入累積效應 personality_score = 0 positive_count = 0 negative_count = 0 for trait, value in positive_traits.items(): if trait in temperament: personality_score += value positive_count += 1 for trait, value in negative_traits.items(): if trait in temperament: personality_score += value negative_count += 1 # 多重特徵的累積效應 if positive_count > 2: personality_score *= (1 + (positive_count - 2) * 0.1) if negative_count > 1: personality_score *= (1 - (negative_count - 1) * 0.15) bonus += max(-0.25, min(0.25, personality_score)) # 適應性評估 - 根據具體環境給予更細緻的評分 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) # 家庭相容性評估 - 特別關注有孩童的家庭 if user_prefs.has_children: family_traits = { 'good with children': 0.12, # 提高與孩童相處的重要性 'patient': 0.10, 'gentle': 0.10, 'tolerant': 0.08, 'playful': 0.06 } unfriendly_traits = { 'aggressive': -0.15, # 加重攻擊性的懲罰 'nervous': -0.12, # 緊張特質可能有風險 'protective': -0.10, # 過度保護性需要注意 'territorial': -0.08 # 地域性可能造成問題 } # 根據孩童年齡調整評分權重 age_adjustments = { 'toddler': { 'bonus_mult': 0.6, # 降低正面特質的獎勵 'penalty_mult': 1.5 # 加重負面特質的懲罰 }, '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_score = 0 for trait, value in family_traits.items(): if trait in temperament: family_score += value * adj['bonus_mult'] for trait, value in unfriendly_traits.items(): if trait in temperament: family_score += value * adj['penalty_mult'] bonus += min(0.20, max(-0.30, family_score)) # 確保總體加分在合理範圍內,但允許更大的變化 return min(0.5, max(-0.35, bonus)) @staticmethod def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict: """計算額外的評估因素""" factors = { 'versatility': 0.0, # 多功能性 'trainability': 0.0, # 可訓練度 'energy_level': 0.0, # 能量水平 'grooming_needs': 0.0, # 美容需求 'social_needs': 0.0, # 社交需求 'weather_adaptability': 0.0 # 氣候適應性 } temperament = breed_info.get('Temperament', '').lower() size = breed_info.get('Size', 'Medium') # 1. 多功能性評估 versatile_traits = ['intelligent', 'adaptable', 'trainable', 'athletic'] working_roles = ['working', 'herding', 'hunting', 'sporting', 'companion'] trait_score = sum(0.2 for trait in versatile_traits if trait in temperament) role_score = sum(0.2 for role in working_roles if role in breed_info.get('Description', '').lower()) 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 } factors['trainability'] = min(1.0, sum(value for trait, value in trainable_traits.items() if trait in temperament)) # 3. 能量水平評估 exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() energy_levels = { 'VERY HIGH': 1.0, 'HIGH': 0.8, 'MODERATE': 0.6, 'LOW': 0.4, 'VARIES': 0.6 } factors['energy_level'] = energy_levels.get(exercise_needs, 0.6) # 4. 美容需求評估 grooming_needs = breed_info.get('Grooming Needs', 'MODERATE').upper() grooming_levels = { 'HIGH': 1.0, 'MODERATE': 0.6, 'LOW': 0.3 } coat_penalty = 0.2 if any(term in breed_info.get('Description', '').lower() for term in ['long coat', 'double coat']) else 0 factors['grooming_needs'] = min(1.0, grooming_levels.get(grooming_needs, 0.6) + coat_penalty) # 5. 社交需求評估 social_traits = ['friendly', 'social', 'affectionate', 'people-oriented'] antisocial_traits = ['independent', 'aloof', 'reserved'] social_score = sum(0.25 for trait in social_traits if trait in temperament) antisocial_score = sum(-0.2 for trait in antisocial_traits if trait in temperament) factors['social_needs'] = min(1.0, max(0.0, social_score + antisocial_score)) # 6. 氣候適應性評估 climate_terms = { 'cold': ['thick coat', 'winter', 'cold climate'], 'hot': ['short coat', 'warm climate', 'heat tolerant'], 'moderate': ['adaptable', 'all climate'] } climate_matches = sum(1 for term in climate_terms[user_prefs.climate] if term in breed_info.get('Description', '').lower()) factors['weather_adaptability'] = min(1.0, climate_matches * 0.3 + 0.4) # 基礎分0.4 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: # # 重新設計基礎分數矩陣 # base_scores = { # "Small": { # "apartment": 1.0, # 小型犬最適合公寓 # "house_small": 0.95, # 在大房子反而稍微降分 # "house_large": 0.85 # 可能浪費空間 # }, # "Medium": { # "apartment": 0.45, # 中型犬在公寓明顯受限 # "house_small": 0.85, # "house_large": 1.0 # }, # "Large": { # "apartment": 0.15, # 大型犬在公寓極不適合 # "house_small": 0.60, # 在小房子仍然受限 # "house_large": 1.0 # }, # "Giant": { # "apartment": 0.1, # 更嚴格的限制 # "house_small": 0.45, # "house_large": 1.0 # } # } # # 取得基礎分數 # base_score = base_scores.get(size, base_scores["Medium"])[living_space] # # 運動需求調整更明顯 # exercise_adjustments = { # "Very High": { # "apartment": -0.25, # 在公寓更嚴重的懲罰 # "house_small": -0.15, # "house_large": -0.05 # }, # "High": { # "apartment": -0.20, # "house_small": -0.10, # "house_large": 0 # }, # "Moderate": { # "apartment": -0.10, # "house_small": -0.05, # "house_large": 0 # }, # "Low": { # "apartment": 0.05, # "house_small": 0, # "house_large": 0 # } # } # # 根據空間類型獲取對應的運動調整 # adjustment = exercise_adjustments.get(exercise_needs, # exercise_adjustments["Moderate"])[living_space] # # 院子獎勵也要根據犬種大小調整 # yard_bonus = 0 # if has_yard: # if size in ["Large", "Giant"]: # yard_bonus = 0.20 if living_space != "apartment" else 0.10 # elif size == "Medium": # yard_bonus = 0.15 if living_space != "apartment" else 0.08 # else: # yard_bonus = 0.10 if living_space != "apartment" else 0.05 # final_score = base_score + adjustment + yard_bonus # return min(1.0, max(0.1, final_score)) def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float: """ 優化的空間分數計算函數 主要改進: 1. 更均衡的基礎分數分配 2. 更細緻的空間需求評估 3. 強化運動需求與空間的關聯性 """ # 重新設計基礎分數矩陣,降低普遍分數以增加區別度 base_scores = { "Small": { "apartment": 0.85, # 降低滿分機會 "house_small": 0.80, # 小型犬不應在大空間得到太高分數 "house_large": 0.75 # 避免小型犬總是得到最高分 }, "Medium": { "apartment": 0.45, # 維持對公寓環境的限制 "house_small": 0.75, # 適中的分數 "house_large": 0.85 # 給予合理的獎勵 }, "Large": { "apartment": 0.15, # 加重對大型犬在公寓的限制 "house_small": 0.65, # 中等適合度 "house_large": 0.90 # 最適合的環境 }, "Giant": { "apartment": 0.10, # 更嚴格的限制 "house_small": 0.45, # 顯著的空間限制 "house_large": 0.95 # 最理想的配對 } } # 取得基礎分數 base_score = base_scores.get(size, base_scores["Medium"])[living_space] # 運動需求相關的調整更加動態 exercise_adjustments = { "Very High": { "apartment": -0.25, # 加重在受限空間的懲罰 "house_small": -0.15, "house_large": -0.05 }, "High": { "apartment": -0.20, "house_small": -0.10, "house_large": 0 }, "Moderate": { "apartment": -0.10, "house_small": -0.05, "house_large": 0 }, "Low": { "apartment": 0.05, # 低運動需求在小空間反而有優勢 "house_small": 0, "house_large": -0.05 # 輕微降低評分,因為空間可能過大 } } # 根據空間類型獲取運動需求調整 adjustment = exercise_adjustments.get(exercise_needs, exercise_adjustments["Moderate"])[living_space] # 院子效益根據品種大小和運動需求動態調整 if has_yard: yard_bonus = { "Giant": 0.20, "Large": 0.15, "Medium": 0.10, "Small": 0.05 }.get(size, 0.10) # 運動需求會影響院子的重要性 if exercise_needs in ["Very High", "High"]: yard_bonus *= 1.2 elif exercise_needs == "Low": yard_bonus *= 0.8 current_score = base_score + adjustment + yard_bonus else: current_score = base_score + adjustment # 確保分數在合理範圍內,但避免極端值 return min(0.95, max(0.15, current_score)) # def calculate_exercise_score(breed_needs: str, user_time: int) -> float: # """運動需求計算""" # exercise_needs = { # 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180}, # 'HIGH': {'min': 90, 'ideal': 120, 'max': 150}, # 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90}, # 'LOW': {'min': 20, 'ideal': 30, 'max': 45}, # 'VARIES': {'min': 30, 'ideal': 60, 'max': 90} # } # breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE']) # # 計算匹配度 # if user_time >= breed_need['ideal']: # if user_time > breed_need['max']: # return 0.9 # 稍微降分,因為可能過度運動 # return 1.0 # elif user_time >= breed_need['min']: # return 0.8 + (user_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.2 # else: # return max(0.3, 0.8 * (user_time / breed_need['min'])) def calculate_exercise_score(breed_needs: str, exercise_time: int) -> float: """ 優化的運動需求評分系統 Parameters: breed_needs: str - 品種的運動需求等級 exercise_time: int - 使用者可提供的運動時間(分鐘) 改進: 1. 更細緻的運動需求評估 2. 更合理的時間匹配計算 3. 避免極端評分 """ # 基礎運動需求評估 exercise_needs = { 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180}, 'HIGH': {'min': 90, 'ideal': 120, 'max': 150}, 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90}, 'LOW': {'min': 20, 'ideal': 30, 'max': 45}, 'VARIES': {'min': 30, 'ideal': 60, 'max': 90} } breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE']) # 基礎時間匹配度計算 if exercise_time >= breed_need['ideal']: if exercise_time > breed_need['max']: # 運動時間過長,稍微降低分數 time_score = 0.9 else: time_score = 1.0 elif exercise_time >= breed_need['min']: # 在最小需求和理想需求之間,線性計算分數 time_score = 0.7 + (exercise_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.3 else: # 運動時間不足,但仍根據比例給予分數 time_score = max(0.3, 0.7 * (exercise_time / breed_need['min'])) # 確保分數在合理範圍內 return min(1.0, max(0.3, time_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.10, # 降低起始分,高難度品種對新手幾乎不推薦 "intermediate": 0.60, # 中級玩家仍需謹慎 "advanced": 1.0 # 資深者能完全勝任 }, "Moderate": { "beginner": 0.35, # 適中難度對新手仍具挑戰 "intermediate": 0.80, # 中級玩家較適合 "advanced": 1.0 # 資深者完全勝任 }, "Low": { "beginner": 0.90, # 新手友善品種 "intermediate": 0.95, # 中級玩家幾乎完全勝任 "advanced": 1.0 # 資深者完全勝任 } } # 取得基礎分數 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 ), '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 ) } # 檢查關鍵不適配情況 critical_issues = check_critical_matches(scores, user_prefs) if critical_issues['has_critical']: return apply_critical_penalty(scores, critical_issues) # 計算環境適應性加成 adaptability_bonus = calculate_environmental_fit(breed_info, user_prefs) # 計算最終加權分數 final_score = calculate_final_weighted_score( scores=scores, user_prefs=user_prefs, breed_info=breed_info, adaptability_bonus=adaptability_bonus ) # 更新最終結果 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 check_critical_matches(scores: dict, user_prefs: UserPreferences) -> dict: """評估是否存在極端不適配的情況""" critical_issues = { 'has_critical': False, 'reasons': [] } # 檢查極端不適配情況 if scores['space'] < 0.3: critical_issues['has_critical'] = True critical_issues['reasons'].append('space_incompatible') if scores['noise'] < 0.3 and user_prefs.living_space == 'apartment': critical_issues['has_critical'] = True critical_issues['reasons'].append('noise_incompatible') if scores['experience'] < 0.3 and user_prefs.experience_level == 'beginner': critical_issues['has_critical'] = True critical_issues['reasons'].append('too_challenging') return critical_issues def apply_critical_penalty(scores: dict, critical_issues: dict) -> dict: """當發現關鍵不適配時,調整分數""" penalized_scores = scores.copy() penalty_factor = 0.6 for reason in critical_issues['reasons']: if reason == 'space_incompatible': penalized_scores['overall'] *= penalty_factor penalized_scores['space'] *= penalty_factor elif reason == 'noise_incompatible': penalized_scores['overall'] *= penalty_factor penalized_scores['noise'] *= penalty_factor elif reason == 'too_challenging': penalized_scores['overall'] *= penalty_factor penalized_scores['experience'] *= penalty_factor return penalized_scores 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_final_weighted_score(scores: dict, user_prefs: UserPreferences, breed_info: dict, adaptability_bonus: float) -> float: """計算最終加權分數""" base_weights = { 'space': 0.25, 'exercise': 0.20, 'grooming': 0.15, 'experience': 0.18, 'health': 0.12, 'noise': 0.10 } # 根據居住環境動態調整權重 if user_prefs.living_space == 'apartment': base_weights['space'] *= 1.4 base_weights['noise'] *= 1.3 base_weights['exercise'] *= 0.8 elif user_prefs.living_space == 'house_large': base_weights['exercise'] *= 1.3 base_weights['space'] *= 0.9 base_weights['noise'] *= 0.8 # 根據經驗等級調整權重 if user_prefs.experience_level == 'beginner': base_weights['experience'] *= 1.5 base_weights['health'] *= 1.2 elif user_prefs.experience_level == 'advanced': base_weights['exercise'] *= 1.2 base_weights['experience'] *= 0.8 # 有孩童時的特殊調整 if user_prefs.has_children: base_weights['noise'] *= 1.3 base_weights['health'] *= 1.2 # 重新正規化權重 total_weight = sum(base_weights.values()) weights = {k: v/total_weight for k, v in base_weights.items()} # 計算基礎加權分數 weighted_base = sum(score * weights[category] for category, score in scores.items()) # 品種特性加成 breed_bonus = calculate_breed_bonus(breed_info, user_prefs) # 計算最終分數 final_score = (weighted_base * 0.75) + (breed_bonus * 0.15) + (adaptability_bonus * 0.10) # 擴大分數範圍 amplified_score = amplify_score_range(final_score) return round(amplified_score, 4) def amplify_score_range(score: float) -> float: """擴大分數範圍,使差異更明顯""" min_score = 0.45 max_score = 0.95 # 正規化到 0-1 範圍 normalized = (score - 0.5) / 0.5 # 非線性轉換 amplified = math.pow(abs(normalized), 1.5) * math.copysign(1, normalized) # 映射回目標範圍 final = min_score + (max_score - min_score) * ((amplified + 1) / 2) return min(max_score, max(min_score, final))