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(): 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() # 定義品種運動特性 exercise_patterns = { 'sprint_type': { # 短跑型,如 Whippet 'keywords': ['fast', 'speed', 'agile', 'sprint'], 'ideal_time': (30, 90), 'ideal_type': 'active_training', 'time_penalties': { 'over': 0.7, # 運動時間過長的懲罰 'under': 0.6 # 運動時間不足的懲罰 } }, 'endurance_type': { # 耐力型,如 Border Collie 'keywords': ['herding', 'working', 'energetic', 'tireless'], 'ideal_time': (90, 180), 'ideal_type': 'moderate_activity', 'time_penalties': { 'over': 0.9, # 耐力型對超時較寬容 'under': 0.5 # 但對運動不足較敏感 } }, 'moderate_type': { # 一般型 'keywords': ['playful', 'active', 'friendly'], 'ideal_time': (60, 120), 'ideal_type': 'moderate_activity', 'time_penalties': { 'over': 0.8, 'under': 0.7 } } } # 判斷品種的運動類型 breed_type = 'moderate_type' # 預設值 for pattern_type, pattern in exercise_patterns.items(): if any(keyword in temperament for keyword in pattern['keywords']): breed_type = pattern_type break pattern = exercise_patterns[breed_type] min_time, max_time = pattern['ideal_time'] # 計算時間匹配度 if min_time <= exercise_time <= max_time: time_score = 1.0 elif exercise_time < min_time: time_score = pattern['time_penalties']['under'] else: time_score = pattern['time_penalties']['over'] # 運動類型匹配度 type_scores = { 'light_walks': 0.7, 'moderate_activity': 0.9, 'active_training': 1.0 } type_score = type_scores.get(exercise_type, 0.7) # 特殊情況處理 if breed_type == 'sprint_type' and exercise_time > 120: if exercise_type != 'active_training': type_score *= 0.6 # 衝刺型品種不適合長時間中低強度運動 return (time_score * 0.6) + (type_score * 0.4) # 第二部分:專業技能需求評估 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)) # 評估完美匹配條件 perfect_conditions = evaluate_perfect_conditions() # 計算動態權重 weights = calculate_weights() # 正規化權重確保總和為1 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.10 * perfect_conditions['size_match'] # 降低單項獎勵 perfect_bonus += 0.10 * perfect_conditions['exercise_match'] perfect_bonus += 0.10 * perfect_conditions['experience_match'] perfect_bonus += 0.05 * perfect_conditions['living_condition_match'] perfect_bonus += 0.05 * perfect_conditions['breed_trait_match'] # 新增品種特性獎勵 # 計算品種特性加成(使用更嚴格的係數) breed_bonus = calculate_breed_bonus(breed_info, user_prefs) * 0.15 # 降低品種加成的影響 # 計算初步分數 initial_score = (base_score * 0.85 + breed_bonus * 0.15) * perfect_bonus # 應用特殊情況調整 final_score = apply_special_case_adjustments(initial_score) # 確保最終分數在有效範圍內 return min(1.0, max(0.3, 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)