from dataclasses import dataclass from breed_health_info import breed_health_info from breed_noise_info import breed_noise_info import traceback import math import random # @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 @dataclass class UserPreferences: """使用者偏好設定的資料結構,整合基本條件與進階評估參數""" living_space: str # "apartment", "house_small", "house_large" yard_access: str # "no_yard", "shared_yard", "private_yard" exercise_time: int # 每日運動時間(分鐘) 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" living_floor: int = 1 # 居住樓層,對公寓住戶特別重要 exercise_intensity: str = "moderate" # "low", "moderate", "high" home_alone_time: int = 4 # 每日獨處時間(小時) health_sensitivity: str = "medium" # "low", "medium", "high" barking_acceptance: str = None # 如果未指定,默認使用 noise_tolerance lifestyle_activity: str = "moderate" # "sedentary", "moderate", "active" 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. 強化運動需求與空間的關聯性 # """ # # 重新設計基礎分數矩陣,降低普遍分數以增加區別度 # 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, exercise_time: int, exercise_type: str) -> float: # """ # 精確評估品種運動需求與使用者運動條件的匹配度 # Parameters: # breed_needs: 品種的運動需求等級 # exercise_time: 使用者能提供的運動時間(分鐘) # exercise_type: 使用者偏好的運動類型 # Returns: # float: -0.2 到 0.2 之間的匹配分數 # """ # # 定義更細緻的運動需求等級 # exercise_levels = { # 'VERY HIGH': { # 'min': 120, # 'ideal': 150, # 'max': 180, # 'intensity': 'high', # 'sessions': 'multiple', # 'preferred_types': ['active_training', 'intensive_exercise'] # }, # 'HIGH': { # 'min': 90, # 'ideal': 120, # 'max': 150, # 'intensity': 'moderate_high', # 'sessions': 'multiple', # 'preferred_types': ['active_training', 'moderate_activity'] # }, # 'MODERATE HIGH': { # 'min': 70, # 'ideal': 90, # 'max': 120, # 'intensity': 'moderate', # 'sessions': 'flexible', # 'preferred_types': ['moderate_activity', 'active_training'] # }, # 'MODERATE': { # 'min': 45, # 'ideal': 60, # 'max': 90, # 'intensity': 'moderate', # 'sessions': 'flexible', # 'preferred_types': ['moderate_activity', 'light_walks'] # }, # 'MODERATE LOW': { # 'min': 30, # 'ideal': 45, # 'max': 70, # 'intensity': 'light_moderate', # 'sessions': 'flexible', # 'preferred_types': ['light_walks', 'moderate_activity'] # }, # 'LOW': { # 'min': 15, # 'ideal': 30, # 'max': 45, # 'intensity': 'light', # 'sessions': 'single', # 'preferred_types': ['light_walks'] # } # } # # 獲取品種的運動需求配置 # breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE']) # # 計算時間匹配度(使用更平滑的評分曲線) # if exercise_time >= breed_level['ideal']: # if exercise_time > breed_level['max']: # # 運動時間過長,適度降分 # time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30) # else: # time_score = 0.15 # elif exercise_time >= breed_level['min']: # # 在最小需求和理想需求之間,線性計算分數 # time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min']) # time_score = 0.05 + (time_ratio * 0.10) # else: # # 運動時間不足,根據差距程度扣分 # time_ratio = max(0, exercise_time / breed_level['min']) # time_score = -0.15 * (1 - time_ratio) # # 運動類型匹配度評估 # type_score = 0.0 # if exercise_type in breed_level['preferred_types']: # type_score = 0.05 # if exercise_type == breed_level['preferred_types'][0]: # type_score = 0.08 # 最佳匹配類型給予更高分數 # return max(-0.2, min(0.2, time_score + type_score)) def calculate_space_score(breed_info: dict, user_prefs: UserPreferences) -> float: """ 計算品種與居住空間的匹配程度 這個函數實現了一個全面的空間評分系統,考慮: 1. 基本空間需求(住所類型與品種大小的匹配) 2. 樓層因素(特別是公寓住戶) 3. 戶外活動空間(院子類型及可用性) 4. 室內活動空間的實際可用性 5. 品種的特殊空間需求 Parameters: ----------- breed_info: 包含品種特徵的字典,包括體型、活動需求等 user_prefs: 使用者偏好設定,包含居住條件相關信息 Returns: -------- float: 0.0-1.0 之間的匹配分數 """ # 取得品種基本信息 size = breed_info.get('Size', 'Medium') temperament = breed_info.get('Temperament', '').lower() exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() # 基礎空間需求評分矩陣 - 考慮品種大小與居住空間的基本匹配度 base_space_scores = { "Small": { "apartment": 0.95, # 小型犬最適合公寓 "house_small": 0.90, # 小房子也很適合 "house_large": 0.85 # 大房子可能過大 }, "Medium": { "apartment": 0.60, # 中型犬在公寓有一定限制 "house_small": 0.85, # 小房子較適合 "house_large": 0.95 # 大房子最理想 }, "Large": { "apartment": 0.30, # 大型犬不適合公寓 "house_small": 0.70, # 小房子稍嫌擁擠 "house_large": 1.0 # 大房子最理想 }, "Giant": { "apartment": 0.20, # 極大型犬極不適合公寓 "house_small": 0.50, # 小房子明顯不足 "house_large": 1.0 # 大房子必需 } } # 取得基礎空間分數 base_score = base_space_scores.get(size, base_space_scores["Medium"])[user_prefs.living_space] # 公寓特殊考量 if user_prefs.living_space == "apartment": # 樓層調整 floor_penalty = 0 if user_prefs.living_floor > 1: if size in ["Large", "Giant"]: floor_penalty = min(0.3, (user_prefs.living_floor - 1) * 0.05) elif size == "Medium": floor_penalty = min(0.2, (user_prefs.living_floor - 1) * 0.03) else: floor_penalty = min(0.1, (user_prefs.living_floor - 1) * 0.02) base_score = max(0.2, base_score - floor_penalty) # 戶外空間評估 yard_scores = { "no_yard": 0, "shared_yard": 0.1, "private_yard": 0.2 } # 根據品種大小調整院子加分 yard_size_multipliers = { "Giant": 1.2, "Large": 1.1, "Medium": 1.0, "Small": 0.8 } yard_bonus = yard_scores[user_prefs.yard_access] * yard_size_multipliers.get(size, 1.0) # 活動空間需求評估 activity_space_score = 0 if user_prefs.space_for_play: if exercise_needs in ["VERY HIGH", "HIGH"]: activity_space_score = 0.15 elif exercise_needs == "MODERATE": activity_space_score = 0.10 else: activity_space_score = 0.05 # 品種特性評估 temperament_adjustments = 0 if 'active' in temperament or 'energetic' in temperament: if user_prefs.living_space == 'apartment': temperament_adjustments -= 0.15 elif user_prefs.living_space == 'house_small': temperament_adjustments -= 0.05 if 'calm' in temperament or 'lazy' in temperament: if user_prefs.living_space == 'apartment': temperament_adjustments += 0.10 if 'adaptable' in temperament: temperament_adjustments += 0.05 # 家庭環境考量 if user_prefs.has_children: if user_prefs.living_space == 'apartment': # 公寓中有孩童需要更多活動空間 if size in ["Large", "Giant"]: base_score *= 0.85 elif size == "Medium": base_score *= 0.90 # 整合所有評分因素 final_score = base_score + yard_bonus + activity_space_score + temperament_adjustments # 確保最終分數在合理範圍內 return max(0.15, min(1.0, final_score)) def calculate_exercise_score(breed_needs: str, exercise_time: int, user_prefs: 'UserPreferences') -> float: """ 計算品種運動需求與使用者條件的匹配分數 這個函數實現了一個精細的運動評分系統,考慮: 1. 運動時間的匹配度(0-180分鐘) 2. 運動強度的適配性 3. 品種特性對運動的特殊需求 4. 生活方式的整體活躍度 Parameters: ----------- breed_needs: 品種的運動需求等級 exercise_time: 使用者能提供的運動時間(分鐘) user_prefs: 使用者偏好設定,包含運動類型和強度等信息 Returns: -------- float: 0.0-1.0 之間的匹配分數 """ # 定義更精確的運動需求標準 exercise_levels = { 'VERY HIGH': { 'min': 120, 'ideal': 150, 'max': 180, 'intensity_required': 'high', 'intensity_factors': {'high': 1.2, 'moderate': 0.8, 'low': 0.6}, 'type_bonus': {'active_training': 0.15, 'moderate_activity': 0.05, 'light_walks': -0.1} }, 'HIGH': { 'min': 90, 'ideal': 120, 'max': 150, 'intensity_required': 'moderate', 'intensity_factors': {'high': 1.1, 'moderate': 1.0, 'low': 0.7}, 'type_bonus': {'active_training': 0.1, 'moderate_activity': 0.1, 'light_walks': -0.05} }, 'MODERATE': { 'min': 60, 'ideal': 90, 'max': 120, 'intensity_required': 'moderate', 'intensity_factors': {'high': 1.0, 'moderate': 1.0, 'low': 0.8}, 'type_bonus': {'active_training': 0.05, 'moderate_activity': 0.1, 'light_walks': 0.05} }, 'LOW': { 'min': 30, 'ideal': 60, 'max': 90, 'intensity_required': 'low', 'intensity_factors': {'high': 0.7, 'moderate': 0.9, 'low': 1.0}, 'type_bonus': {'active_training': -0.05, 'moderate_activity': 0.05, 'light_walks': 0.1} } } # 獲取品種運動需求配置 breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE']) # 計算基礎運動時間分數 def calculate_time_score(time: int, level: dict) -> float: if time < level['min']: # 運動時間不足,指數下降 return max(0.3, (time / level['min']) ** 1.5) elif time < level['ideal']: # 運動時間接近理想,線性增長 return 0.7 + 0.3 * ((time - level['min']) / (level['ideal'] - level['min'])) elif time <= level['max']: # 理想運動時間範圍,高分保持 return 1.0 else: # 運動時間過多,緩慢扣分 excess = (time - level['max']) / 30 # 每超過30分鐘扣分 return max(0.7, 1.0 - (excess * 0.1)) # 計算運動時間基礎分數 time_score = calculate_time_score(exercise_time, breed_level) # 計算運動強度匹配度 intensity_factor = breed_level['intensity_factors'].get(user_prefs.exercise_intensity, 1.0) # 運動類型加成 type_bonus = breed_level['type_bonus'].get(user_prefs.exercise_type, 0) # 生活方式調整 lifestyle_adjustments = { 'sedentary': -0.1, 'moderate': 0, 'active': 0.1 } lifestyle_factor = lifestyle_adjustments.get(user_prefs.lifestyle_activity, 0) # 整合所有因素 final_score = time_score * intensity_factor + type_bonus + lifestyle_factor # 確保分數在合理範圍內 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.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_experience_score(breed_info: dict, user_prefs: UserPreferences) -> float: """ 計算飼主經驗與品種需求的匹配分數 這個函數實現了一個全面的經驗評分系統,考慮: 1. 品種的基本照護難度 2. 飼主的經驗水平 3. 特殊照護需求(如健康問題、行為訓練) 4. 時間投入與生活方式的匹配 5. 家庭環境對照護的影響 特別注意: - 新手飼主面對高難度品種時的顯著降分 - 資深飼主照顧簡單品種的微幅降分 - 特殊需求品種的額外評估 Parameters: ----------- breed_info: 包含品種特徵的字典 user_prefs: 使用者偏好設定 Returns: -------- float: 0.0-1.0 之間的匹配分數 """ care_level = breed_info.get('Care Level', 'MODERATE').upper() temperament = breed_info.get('Temperament', '').lower() health_issues = breed_info.get('Health Issues', '').lower() # 基礎照護難度評分矩陣 base_experience_scores = { "HIGH": { "beginner": 0.30, # 高難度品種對新手極具挑戰 "intermediate": 0.70, # 中級飼主需要額外努力 "advanced": 0.95 # 資深飼主最適合 }, "MODERATE": { "beginner": 0.60, # 中等難度對新手有一定挑戰 "intermediate": 0.85, # 中級飼主較適合 "advanced": 0.90 # 資深飼主可能稍嫌簡單 }, "LOW": { "beginner": 0.90, # 低難度適合新手 "intermediate": 0.85, # 中級飼主可能感覺無趣 "advanced": 0.80 # 資深飼主可能缺乏挑戰 } } # 取得基礎經驗分數 base_score = base_experience_scores.get(care_level, base_experience_scores["MODERATE"])[user_prefs.experience_level] # 時間可用性評估 time_adjustments = { "limited": { "HIGH": -0.20, "MODERATE": -0.15, "LOW": -0.10 }, "moderate": { "HIGH": -0.10, "MODERATE": -0.05, "LOW": 0 }, "flexible": { "HIGH": 0, "MODERATE": 0.05, "LOW": 0.10 } } time_adjustment = time_adjustments[user_prefs.time_availability][care_level] # 行為特徵評估 def evaluate_temperament(temp: str, exp_level: str) -> float: """評估品種性格特徵與飼主經驗的匹配度""" score = 0 # 困難特徵評估 difficult_traits = { 'stubborn': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': 0}, 'independent': {'beginner': -0.15, 'intermediate': -0.08, 'advanced': 0}, 'dominant': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': -0.05}, 'aggressive': {'beginner': -0.25, 'intermediate': -0.15, 'advanced': -0.10} } # 友善特徵評估 friendly_traits = { 'friendly': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0}, 'gentle': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0}, 'easy to train': {'beginner': 0.15, 'intermediate': 0.10, 'advanced': 0.05} } # 計算特徵分數 for trait, penalties in difficult_traits.items(): if trait in temp: score += penalties[exp_level] for trait, bonuses in friendly_traits.items(): if trait in temp: score += bonuses[exp_level] return score temperament_adjustment = evaluate_temperament(temperament, user_prefs.experience_level) # 健康問題評估 def evaluate_health_needs(health: str, exp_level: str) -> float: """評估健康問題的照護難度""" score = 0 serious_conditions = ['hip dysplasia', 'heart disease', 'cancer'] moderate_conditions = ['allergies', 'skin problems', 'ear infections'] # 根據經驗等級調整健康問題的影響 health_impact = { 'beginner': {'serious': -0.20, 'moderate': -0.10}, 'intermediate': {'serious': -0.15, 'moderate': -0.05}, 'advanced': {'serious': -0.10, 'moderate': -0.03} } for condition in serious_conditions: if condition in health: score += health_impact[exp_level]['serious'] for condition in moderate_conditions: if condition in health: score += health_impact[exp_level]['moderate'] return score health_adjustment = evaluate_health_needs(health_issues, user_prefs.experience_level) # 家庭環境考量 family_adjustment = 0 if user_prefs.has_children: if user_prefs.children_age == 'toddler': if user_prefs.experience_level == 'beginner': family_adjustment -= 0.15 elif user_prefs.experience_level == 'intermediate': family_adjustment -= 0.10 elif user_prefs.children_age == 'school_age': if user_prefs.experience_level == 'beginner': family_adjustment -= 0.10 # 生活方式匹配度 lifestyle_adjustments = { 'sedentary': -0.10 if care_level == 'HIGH' else 0, 'moderate': 0, 'active': 0.10 if care_level in ['HIGH', 'MODERATE'] else 0 } lifestyle_adjustment = lifestyle_adjustments[user_prefs.lifestyle_activity] # 整合所有評分因素 final_score = base_score + time_adjustment + temperament_adjustment + \ health_adjustment + family_adjustment + lifestyle_adjustment # 確保最終分數在合理範圍內 return max(0.15, min(1.0, 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)) def calculate_noise_score(breed_info: dict, user_prefs: UserPreferences) -> float: """ 計算品種噪音特性與使用者需求的匹配分數 這個函數建立了一個細緻的噪音評估系統,考慮多個關鍵因素: 1. 品種的基本吠叫傾向 2. 居住環境對噪音的敏感度 3. 吠叫的情境和原因 4. 鄰居影響的考量 5. 家庭成員的噪音承受度 6. 訓練可能性的評估 特別注意: - 公寓環境的嚴格標準 - 有幼童時的特殊考量 - 獨處時間的影響 - 品種的可訓練性 Parameters: ----------- breed_info: 包含品種特性的字典,包括吠叫傾向和訓練難度 user_prefs: 使用者偏好設定,包含噪音容忍度和環境因素 Returns: -------- float: 0.0-1.0 之間的匹配分數,分數越高表示噪音特性越符合需求 """ # 提取基本資訊 noise_level = breed_info.get('Noise Level', 'MODERATE').upper() barking_tendency = breed_info.get('Barking Tendency', 'MODERATE').upper() trainability = breed_info.get('Trainability', 'MODERATE').upper() temperament = breed_info.get('Temperament', '').lower() # 基礎噪音評分矩陣 - 考慮環境和噪音容忍度 base_noise_scores = { "LOW": { "apartment": { "low": 1.0, # 安靜的狗在公寓最理想 "medium": 0.95, "high": 0.90 }, "house_small": { "low": 0.95, "medium": 0.90, "high": 0.85 }, "house_large": { "low": 0.90, "medium": 0.85, "high": 0.80 # 太安靜可能不夠警戒 } }, "MODERATE": { "apartment": { "low": 0.60, "medium": 0.80, "high": 0.85 }, "house_small": { "low": 0.70, "medium": 0.85, "high": 0.90 }, "house_large": { "low": 0.75, "medium": 0.90, "high": 0.95 } }, "HIGH": { "apartment": { "low": 0.20, # 吵鬧的狗在公寓極不適合 "medium": 0.40, "high": 0.60 }, "house_small": { "low": 0.30, "medium": 0.50, "high": 0.70 }, "house_large": { "low": 0.40, "medium": 0.60, "high": 0.80 } } } # 取得基礎噪音分數 base_score = base_noise_scores.get(noise_level, base_noise_scores["MODERATE"])\ [user_prefs.living_space][user_prefs.noise_tolerance] # 吠叫情境評估 def evaluate_barking_context(temp: str, living_space: str) -> float: """評估不同情境下的吠叫問題嚴重度""" context_score = 0 # 不同吠叫原因的權重 barking_contexts = { 'separation anxiety': { '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.05 }, 'attention seeking': { 'apartment': -0.15, 'house_small': -0.10, 'house_large': -0.08 } } for context, penalties in barking_contexts.items(): if context in temp: context_score += penalties[living_space] return context_score # 計算吠叫情境的影響 barking_context_adjustment = evaluate_barking_context(temperament, user_prefs.living_space) # 訓練可能性評估 trainability_adjustments = { "HIGH": 0.10, # 容易訓練可以改善吠叫問題 "MODERATE": 0.05, "LOW": -0.05 # 難以訓練則較難改善 } trainability_adjustment = trainability_adjustments.get(trainability, 0) # 家庭環境考量 family_adjustment = 0 if user_prefs.has_children: child_age_factors = { 'toddler': -0.20, # 幼童需要安靜環境 'school_age': -0.15, 'teenager': -0.10 } family_adjustment = child_age_factors.get(user_prefs.children_age, -0.15) # 根據噪音等級調整影響程度 if noise_level == "HIGH": family_adjustment *= 1.5 elif noise_level == "LOW": family_adjustment *= 0.5 # 獨處時間的影響 alone_time_adjustment = 0 if user_prefs.home_alone_time > 6: if 'separation anxiety' in temperament or noise_level == "HIGH": alone_time_adjustment = -0.15 elif noise_level == "MODERATE": alone_time_adjustment = -0.10 # 鄰居影響評估(特別是公寓環境) neighbor_adjustment = 0 if user_prefs.living_space == "apartment": if noise_level == "HIGH": neighbor_adjustment = -0.15 elif noise_level == "MODERATE": neighbor_adjustment = -0.10 # 樓層因素 if user_prefs.living_floor > 1: neighbor_adjustment -= min(0.10, (user_prefs.living_floor - 1) * 0.02) # 整合所有評分因素 final_score = base_score + barking_context_adjustment + trainability_adjustment + \ family_adjustment + alone_time_adjustment + neighbor_adjustment # 確保最終分數在合理範圍內 return max(0.15, min(1.0, final_score)) 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_matching(breed_info: dict, user_prefs: UserPreferences) -> dict: """計算品種的整體評分與匹配度""" try: 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_compatibility_score(scores, user_prefs, 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_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float: # """ # 改進的品種相容性評分系統 # 通過更細緻的特徵評估和動態權重調整,自然產生分數差異 # """ # # 評估關鍵特徵的匹配度,使用更極端的調整係數 # def evaluate_key_features(): # # 空間適配性評估 # space_multiplier = 1.0 # if user_prefs.living_space == 'apartment': # if breed_info['Size'] == 'Giant': # space_multiplier = 0.3 # 嚴重不適合 # elif breed_info['Size'] == 'Large': # space_multiplier = 0.4 # 明顯不適合 # elif breed_info['Size'] == 'Small': # space_multiplier = 1.4 # 明顯優勢 # # 運動需求評估 # exercise_multiplier = 1.0 # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() # if exercise_needs == 'VERY HIGH': # if user_prefs.exercise_time < 60: # exercise_multiplier = 0.3 # 嚴重不足 # elif user_prefs.exercise_time > 150: # exercise_multiplier = 1.5 # 完美匹配 # elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150: # exercise_multiplier = 0.5 # 運動過度 # return space_multiplier, exercise_multiplier # # 計算經驗匹配度 # def evaluate_experience(): # exp_multiplier = 1.0 # care_level = breed_info.get('Care Level', 'MODERATE') # if care_level == 'High': # if user_prefs.experience_level == 'beginner': # exp_multiplier = 0.4 # elif user_prefs.experience_level == 'advanced': # exp_multiplier = 1.3 # elif care_level == 'Low': # if user_prefs.experience_level == 'advanced': # exp_multiplier = 0.9 # 略微降低評分,因為可能不夠有挑戰性 # return exp_multiplier # # 取得特徵調整係數 # space_mult, exercise_mult = evaluate_key_features() # exp_mult = evaluate_experience() # # 調整基礎分數 # adjusted_scores = { # 'space': scores['space'] * space_mult, # 'exercise': scores['exercise'] * exercise_mult, # 'experience': scores['experience'] * exp_mult, # 'grooming': scores['grooming'], # 'health': scores['health'], # 'noise': scores['noise'] # } # # 計算加權平均,關鍵特徵佔更大權重 # weights = { # 'space': 0.35, # 'exercise': 0.30, # 'experience': 0.20, # 'grooming': 0.15, # 'health': 0.10, # 'noise': 0.10 # } # # 動態調整權重 # if user_prefs.living_space == 'apartment': # weights['space'] *= 1.5 # weights['noise'] *= 1.3 # if abs(user_prefs.exercise_time - 120) > 60: # 運動時間極端情況 # weights['exercise'] *= 1.4 # # 正規化權重 # total_weight = sum(weights.values()) # normalized_weights = {k: v/total_weight for k, v in weights.items()} # # 計算最終分數 # final_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys()) # # 品種特性加成 # breed_bonus = calculate_breed_bonus(breed_info, user_prefs) # # 整合最終分數,保持在0-1範圍內 # return min(1.0, max(0.0, (final_score * 0.85) + (breed_bonus * 0.15))) # def amplify_score_extreme(score: float) -> float: # """ # 改進的分數轉換函數 # 提供更大的分數範圍和更明顯的差異 # 轉換邏輯: # - 極差匹配 (0.0-0.3) -> 60-68% # - 較差匹配 (0.3-0.5) -> 68-75% # - 中等匹配 (0.5-0.7) -> 75-85% # - 良好匹配 (0.7-0.85) -> 85-92% # - 優秀匹配 (0.85-1.0) -> 92-95% # """ # if score < 0.3: # # 極差匹配:快速線性增長 # return 0.60 + (score / 0.3) * 0.08 # elif score < 0.5: # # 較差匹配:緩慢增長 # position = (score - 0.3) / 0.2 # return 0.68 + position * 0.07 # elif score < 0.7: # # 中等匹配:穩定線性增長 # position = (score - 0.5) / 0.2 # return 0.75 + position * 0.10 # elif score < 0.85: # # 良好匹配:加速增長 # position = (score - 0.7) / 0.15 # return 0.85 + position * 0.07 # else: # # 優秀匹配:最後衝刺 # position = (score - 0.85) / 0.15 # return 0.92 + position * 0.03 def calculate_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float: """ 計算品種與使用者的整體相容性分數 這是推薦系統的核心評分函數,負責: 1. 智能整合各面向評分 2. 動態調整評分權重 3. 處理關鍵條件的優先級 4. 產生最終的匹配分數 評分策略: - 基礎分數:由各項指標的加權平均獲得 - 動態權重:根據用戶情況動態調整各項權重 - 關鍵條件:某些條件不滿足會顯著降低總分 - 加成系統:特殊匹配會提供額外加分 Parameters: ----------- scores: 包含各項評分的字典 user_prefs: 使用者偏好設定 breed_info: 品種特性信息 Returns: -------- float: 60.0-95.0 之間的最終匹配分數 """ def calculate_dynamic_weights() -> dict: """計算動態權重分配""" # 基礎權重設定 weights = { 'space': 0.20, 'exercise': 0.20, 'experience': 0.15, 'grooming': 0.15, 'health': 0.15, 'noise': 0.15 } # 公寓住戶權重調整 if user_prefs.living_space == "apartment": weights['space'] *= 1.3 weights['noise'] *= 1.3 weights['exercise'] *= 0.8 # 有幼童時的權重調整 if user_prefs.has_children and user_prefs.children_age == 'toddler': weights['experience'] *= 1.3 weights['noise'] *= 1.2 weights['health'] *= 1.2 # 新手飼主的權重調整 if user_prefs.experience_level == 'beginner': weights['experience'] *= 1.4 weights['health'] *= 1.2 weights['grooming'] *= 1.2 # 健康敏感度的權重調整 if user_prefs.health_sensitivity == 'high': weights['health'] *= 1.3 # 運動時間極端情況的權重調整 if abs(user_prefs.exercise_time - 120) > 60: weights['exercise'] *= 1.3 # 正規化權重 total = sum(weights.values()) return {k: v/total for k, v in weights.items()} def calculate_critical_factors() -> float: """評估關鍵因素的影響""" critical_score = 1.0 # 空間關鍵條件 if user_prefs.living_space == "apartment": if breed_info['Size'] == 'Giant': critical_score *= 0.7 elif breed_info['Size'] == 'Large': critical_score *= 0.8 # 運動需求關鍵條件 exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() if exercise_needs == 'VERY HIGH' and user_prefs.exercise_time < 60: critical_score *= 0.75 elif exercise_needs == 'HIGH' and user_prefs.exercise_time < 45: critical_score *= 0.8 # 新手飼主關鍵條件 if user_prefs.experience_level == 'beginner': if 'aggressive' in breed_info.get('Temperament', '').lower(): critical_score *= 0.7 elif 'dominant' in breed_info.get('Temperament', '').lower(): critical_score *= 0.8 # 噪音關鍵條件 if user_prefs.living_space == "apartment" and \ breed_info.get('Noise Level', 'MODERATE').upper() == 'HIGH' and \ user_prefs.noise_tolerance == 'low': critical_score *= 0.7 return critical_score def calculate_bonus_factors() -> float: """計算額外加分因素""" bonus = 1.0 temperament = breed_info.get('Temperament', '').lower() # 完美匹配加分 perfect_matches = 0 for score in scores.values(): if score > 0.9: perfect_matches += 1 if perfect_matches >= 3: bonus += 0.05 # 特殊匹配加分 if user_prefs.has_children and 'good with children' in temperament: bonus += 0.03 if user_prefs.living_space == "apartment" and 'adaptable' in temperament: bonus += 0.03 if user_prefs.experience_level == 'beginner' and 'easy to train' in temperament: bonus += 0.03 return min(1.15, bonus) # 計算動態權重 weights = calculate_dynamic_weights() # 計算基礎加權分數 base_score = sum(scores[k] * weights[k] for k in scores.keys()) # 應用關鍵因素 critical_factor = calculate_critical_factors() # 計算加分 bonus_factor = calculate_bonus_factors() # 計算最終原始分數 raw_score = base_score * critical_factor * bonus_factor # 轉換為最終分數(60-95範圍) final_score = 60 + (raw_score * 35) # 確保分數在合理範圍內並保留兩位小數 return round(max(60.0, min(95.0, final_score)), 2) def amplify_score_extreme(score: float) -> float: """ 將原始相容性分數(0-1)轉換為最終評分(60-95) 這個函數負責: 1. 將內部計算的原始分數轉換為更有意義的最終分數 2. 確保分數分布更自然且有區別性 3. 突出極佳和極差的匹配 4. 避免分數過度集中在中間區域 轉換策略: - 極佳匹配(0.85-1.0):轉換為 90-95 分 - 優良匹配(0.70-0.85):轉換為 85-90 分 - 良好匹配(0.55-0.70):轉換為 75-85 分 - 一般匹配(0.40-0.55):轉換為 70-75 分 - 勉強匹配(0.25-0.40):轉換為 65-70 分 - 不推薦匹配(0-0.25):轉換為 60-65 分 Parameters: ----------- score: 原始相容性分數(0.0-1.0) Returns: -------- float: 轉換後的最終分數(60.0-95.0) """ # 使用分段函數進行更自然的轉換 if score >= 0.85: # 極佳匹配:90-95分 position = (score - 0.85) / 0.15 return 90.0 + (position * 5.0) elif score >= 0.70: # 優良匹配:85-90分 position = (score - 0.70) / 0.15 return 85.0 + (position * 5.0) elif score >= 0.55: # 良好匹配:75-85分 position = (score - 0.55) / 0.15 return 75.0 + (position * 10.0) elif score >= 0.40: # 一般匹配:70-75分 position = (score - 0.40) / 0.15 return 70.0 + (position * 5.0) elif score >= 0.25: # 勉強匹配:65-70分 position = (score - 0.25) / 0.15 return 65.0 + (position * 5.0) else: # 不推薦匹配:60-65分 position = score / 0.25 return 60.0 + (position * 5.0)