Spaces:
Running
on
Zero
Running
on
Zero
| from dataclasses import dataclass | |
| from breed_health_info import breed_health_info | |
| from breed_noise_info import breed_noise_info | |
| import traceback | |
| import math | |
| 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 | |
| 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)) | |
| 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.90, # 降低滿分機會 | |
| # "house_small": 0.85, # 小型犬不應在大空間得到太高分數 | |
| # "house_large": 0.80 # 避免小型犬總是得到最高分 | |
| # }, | |
| # "Medium": { | |
| # "apartment": 0.40, # 維持對公寓環境的限制 | |
| # "house_small": 0.80, # 適中的分數 | |
| # "house_large": 0.90 # 給予合理的獎勵 | |
| # }, | |
| # "Large": { | |
| # "apartment": 0.10, # 加重對大型犬在公寓的限制 | |
| # "house_small": 0.60, # 中等適合度 | |
| # "house_large": 0.95 # 最適合的環境 | |
| # }, | |
| # "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.08 * (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.20 * (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(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: | |
| # """ | |
| # 改進的品種相容性評分系統 | |
| # 通過更細緻的特徵評估和動態權重調整,自然產生分數差異 | |
| # """ | |
| # # 評估關鍵特徵的匹配度,使用更極端的調整係數 | |
| # 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.has_children: | |
| # if user_prefs.children_age == 'toddler': | |
| # weights['noise'] *= 1.5 # 幼童對噪音更敏感 | |
| # weights['experience'] *= 1.3 # 需要更有經驗的飼主 | |
| # if user_prefs.living_space == 'apartment': | |
| # weights['space'] *= 1.4 # 公寓空間限制更重要 | |
| # weights['noise'] *= 1.3 # 噪音問題更重要 | |
| # # 運動時間極端情況 | |
| # if user_prefs.exercise_time < 30: | |
| # weights['exercise'] *= 1.5 # 運動時間極少時加重權重 | |
| # elif user_prefs.exercise_time > 150: | |
| # weights['exercise'] *= 1.3 # 運動時間充足時略微加重 | |
| # # 正規化權重 | |
| # 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.2) -> 50-60% | |
| # - 較差匹配 (0.2-0.4) -> 60-70% | |
| # - 中等匹配 (0.4-0.6) -> 70-82% | |
| # - 良好匹配 (0.6-0.8) -> 82-90% | |
| # - 優秀匹配 (0.8-1.0) -> 90-98% | |
| # """ | |
| # if score < 0.2: | |
| # # 極差匹配:更低的起始分數 | |
| # return 0.50 + (score / 0.2) * 0.10 | |
| # elif score < 0.4: | |
| # # 較差匹配:緩慢增長 | |
| # position = (score - 0.2) / 0.2 | |
| # return 0.60 + position * 0.10 | |
| # elif score < 0.6: | |
| # # 中等匹配:較大的分數增長 | |
| # position = (score - 0.4) / 0.2 | |
| # return 0.70 + position * 0.12 | |
| # elif score < 0.8: | |
| # # 良好匹配:快速增長 | |
| # position = (score - 0.6) / 0.2 | |
| # return 0.82 + position * 0.08 | |
| # else: | |
| # # 優秀匹配:達到更高分數 | |
| # position = (score - 0.8) / 0.2 | |
| # return 0.90 + position * 0.08 | |
| # 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.2 # 更嚴重的懲罰 | |
| # elif breed_info['Size'] == 'Large': | |
| # space_multiplier = 0.3 | |
| # elif breed_info['Size'] == 'Medium': | |
| # space_multiplier = 0.7 | |
| # elif breed_info['Size'] == 'Small': | |
| # space_multiplier = 1.6 # 更大的獎勵 | |
| # # 運動需求評估 - 更細緻的匹配 | |
| # exercise_multiplier = 1.0 | |
| # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() | |
| # # 運動時間差異計算 | |
| # time_diff_ratio = abs(user_prefs.exercise_time - get_ideal_exercise_time(exercise_needs)) / 60.0 | |
| # if exercise_needs == 'VERY HIGH': | |
| # if user_prefs.exercise_time < 90: | |
| # exercise_multiplier = max(0.2, 1.0 - time_diff_ratio) | |
| # elif user_prefs.exercise_time > 150: | |
| # exercise_multiplier = min(2.0, 1.0 + time_diff_ratio/2) | |
| # elif exercise_needs == 'HIGH': | |
| # if user_prefs.exercise_time < 60: | |
| # exercise_multiplier = max(0.3, 1.0 - time_diff_ratio) | |
| # elif user_prefs.exercise_time > 120: | |
| # exercise_multiplier = min(1.8, 1.0 + time_diff_ratio/2) | |
| # elif exercise_needs == 'LOW': | |
| # if user_prefs.exercise_time > 120: | |
| # exercise_multiplier = max(0.4, 1.0 - time_diff_ratio/2) | |
| # return space_multiplier, exercise_multiplier | |
| # def get_ideal_exercise_time(exercise_needs: str) -> int: | |
| # """獲取理想運動時間""" | |
| # return { | |
| # 'VERY HIGH': 150, | |
| # 'HIGH': 120, | |
| # 'MODERATE HIGH': 90, | |
| # 'MODERATE': 60, | |
| # 'MODERATE LOW': 45, | |
| # 'LOW': 30 | |
| # }.get(exercise_needs, 60) | |
| # # 經驗匹配度評估 - 更強的影響力 | |
| # 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.3 # 更嚴重的懲罰 | |
| # elif user_prefs.experience_level == 'advanced': | |
| # exp_multiplier = 1.5 # 更大的獎勵 | |
| # elif care_level == 'Low': | |
| # if user_prefs.experience_level == 'advanced': | |
| # exp_multiplier = 0.8 | |
| # 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'] * (1.5 if user_prefs.health_sensitivity == 'high' else 1.0), | |
| # 'noise': scores['noise'] | |
| # } | |
| # # 基礎權重 | |
| # weights = { | |
| # 'space': 0.25, | |
| # 'exercise': 0.25, | |
| # 'experience': 0.15, | |
| # 'grooming': 0.15, | |
| # 'health': 0.10, | |
| # 'noise': 0.10 | |
| # } | |
| # # 動態權重調整 - 更強的條件反應 | |
| # if user_prefs.has_children: | |
| # if user_prefs.children_age == 'toddler': | |
| # weights['noise'] *= 2.0 # 更強的噪音影響 | |
| # weights['experience'] *= 1.5 | |
| # weights['health'] *= 1.3 | |
| # elif user_prefs.children_age == 'school_age': | |
| # weights['noise'] *= 1.5 | |
| # weights['experience'] *= 1.3 | |
| # if user_prefs.living_space == 'apartment': | |
| # weights['space'] *= 1.8 # 更強的空間限制 | |
| # weights['noise'] *= 1.6 | |
| # # 運動時間極端情況 | |
| # if user_prefs.exercise_time < 30: | |
| # weights['exercise'] *= 2.0 | |
| # elif user_prefs.exercise_time > 150: | |
| # weights['exercise'] *= 1.5 | |
| # # 正規化權重 | |
| # total_weight = sum(weights.values()) | |
| # normalized_weights = {k: v/total_weight for k, v in weights.items()} | |
| # # 計算基礎分數 | |
| # base_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys()) | |
| # # 品種特性加成 | |
| # breed_bonus = calculate_breed_bonus(breed_info, user_prefs) | |
| # # 動態整合係數 | |
| # bonus_weight = min(0.25, max(0.15, breed_bonus)) # 讓優秀特性有更大影響 | |
| # # 完美匹配加成 | |
| # if all(score >= 0.8 for score in adjusted_scores.values()): | |
| # base_score *= 1.2 | |
| # # 極端不匹配懲罰 | |
| # if any(score <= 0.3 for score in adjusted_scores.values()): | |
| # base_score *= 0.6 | |
| # return min(1.0, max(0.0, (base_score * (1.0 - bonus_weight)) + (breed_bonus * bonus_weight))) | |
| # def amplify_score_extreme(score: float) -> float: | |
| # """ | |
| # 改進的分數轉換函數,提供更動態的分數範圍 | |
| # 動態轉換邏輯: | |
| # - 極差匹配 (0.0-0.2) -> 45-58% | |
| # - 較差匹配 (0.2-0.4) -> 58-72% | |
| # - 中等匹配 (0.4-0.6) -> 72-85% | |
| # - 良好匹配 (0.6-0.8) -> 85-92% | |
| # - 優秀匹配 (0.8-0.9) -> 92-96% | |
| # - 完美匹配 (0.9-1.0) -> 96-99% | |
| # """ | |
| # if score < 0.2: | |
| # return 0.45 + (score / 0.2) * 0.13 | |
| # elif score < 0.4: | |
| # position = (score - 0.2) / 0.2 | |
| # return 0.58 + position * 0.14 | |
| # elif score < 0.6: | |
| # position = (score - 0.4) / 0.2 | |
| # return 0.72 + position * 0.13 | |
| # elif score < 0.8: | |
| # position = (score - 0.6) / 0.2 | |
| # return 0.85 + position * 0.07 | |
| # elif score < 0.9: | |
| # position = (score - 0.8) / 0.1 | |
| # return 0.92 + position * 0.04 | |
| # else: | |
| # position = (score - 0.9) / 0.1 | |
| # return 0.96 + position * 0.03 | |
| def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float: | |
| """ | |
| 改進的品種相容性評分系統,提供更動態和精確的評分 | |
| 主要改進: | |
| 1. 更動態的權重系統 | |
| 2. 更強的極端情況處理 | |
| 3. 更精確的品種特性評估 | |
| """ | |
| def evaluate_condition_extremity(): | |
| """評估使用者條件的極端程度""" | |
| extremity_count = 0 | |
| # 空間條件極端性 | |
| if user_prefs.living_space == 'apartment' and breed_info['Size'] in ['Large', 'Giant']: | |
| extremity_count += 2 | |
| elif user_prefs.living_space == 'house_large' and breed_info['Size'] == 'Small': | |
| extremity_count += 1 | |
| # 運動需求極端性 | |
| exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() | |
| if exercise_needs == 'VERY HIGH' and user_prefs.exercise_time < 60: | |
| extremity_count += 2 | |
| elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150: | |
| extremity_count += 1 | |
| # 經驗等級極端性 | |
| care_level = breed_info.get('Care Level', 'MODERATE') | |
| if care_level == 'High' and user_prefs.experience_level == 'beginner': | |
| extremity_count += 2 | |
| return extremity_count | |
| def calculate_dynamic_weights(): | |
| """計算動態權重""" | |
| # 基礎權重 | |
| 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'] *= 2.0 | |
| weights['noise'] *= 1.8 | |
| # 根據家庭情況調整 | |
| if user_prefs.has_children: | |
| if user_prefs.children_age == 'toddler': | |
| weights['noise'] *= 2.0 | |
| weights['experience'] *= 1.8 | |
| weights['health'] *= 1.5 | |
| elif user_prefs.children_age == 'school_age': | |
| weights['noise'] *= 1.5 | |
| weights['experience'] *= 1.3 | |
| # 根據運動時間調整 | |
| if user_prefs.exercise_time < 30: | |
| weights['exercise'] *= 2.5 | |
| elif user_prefs.exercise_time > 150: | |
| weights['exercise'] *= 2.0 | |
| # 根據健康敏感度調整 | |
| if user_prefs.health_sensitivity == 'high': | |
| weights['health'] *= 1.8 | |
| return weights | |
| # 計算條件極端程度 | |
| extremity_level = evaluate_condition_extremity() | |
| # 計算動態權重 | |
| weights = calculate_dynamic_weights() | |
| # 正規化權重 | |
| total_weight = sum(weights.values()) | |
| normalized_weights = {k: v/total_weight for k, v in weights.items()} | |
| # 計算加權分數 | |
| weighted_scores = { | |
| k: scores[k] * normalized_weights[k] for k in scores.keys() | |
| } | |
| # 基礎分數 | |
| base_score = sum(weighted_scores.values()) | |
| # 品種特性加成 | |
| breed_bonus = calculate_breed_bonus(breed_info, user_prefs) | |
| # 根據極端程度調整最終分數 | |
| if extremity_level >= 3: | |
| base_score *= 0.6 # 多個極端條件的嚴重懲罰 | |
| elif extremity_level >= 2: | |
| base_score *= 0.8 # 較少極端條件的適度懲罰 | |
| # 完美匹配加成 | |
| if all(score >= 0.8 for score in scores.values()): | |
| base_score *= 1.3 | |
| # 品種特性影響力隨匹配度增加 | |
| bonus_weight = min(0.35, max(0.15, breed_bonus)) | |
| # 最終分數計算 | |
| final_score = (base_score * (1.0 - bonus_weight)) + (breed_bonus * bonus_weight) | |
| return min(1.0, max(0.0, final_score)) | |
| def amplify_score_extreme(score: float) -> float: | |
| """ | |
| 改進的分數轉換函數,提供更合理的分數分布 | |
| 特點: | |
| 1. 更大的分數範圍 | |
| 2. 更平滑的轉換曲線 | |
| 3. 更準確的極端情況處理 | |
| """ | |
| def sigmoid_transform(x: float, steepness: float = 10) -> float: | |
| """使用 sigmoid 函數實現更平滑的轉換""" | |
| import math | |
| return 1 / (1 + math.exp(-steepness * (x - 0.5))) | |
| if score < 0.2: | |
| # 極差匹配:使用更低的起始分數 | |
| base = 0.40 | |
| range_score = 0.15 | |
| position = score / 0.2 | |
| return base + (sigmoid_transform(position) * range_score) | |
| elif score < 0.4: | |
| # 較差匹配:緩慢增長 | |
| base = 0.55 | |
| range_score = 0.15 | |
| position = (score - 0.2) / 0.2 | |
| return base + (sigmoid_transform(position) * range_score) | |
| elif score < 0.6: | |
| # 中等匹配:較大增長 | |
| base = 0.70 | |
| range_score = 0.15 | |
| position = (score - 0.4) / 0.2 | |
| return base + (sigmoid_transform(position) * range_score) | |
| elif score < 0.8: | |
| # 良好匹配:快速增長 | |
| base = 0.85 | |
| range_score = 0.10 | |
| position = (score - 0.6) / 0.2 | |
| return base + (sigmoid_transform(position) * range_score) | |
| elif score < 0.9: | |
| # 優秀匹配:接近最高分 | |
| base = 0.95 | |
| range_score = 0.03 | |
| position = (score - 0.8) / 0.1 | |
| return base + (sigmoid_transform(position) * range_score) | |
| else: | |
| # 完美匹配:可能達到最高分 | |
| base = 0.98 | |
| range_score = 0.02 | |
| position = (score - 0.9) / 0.1 | |
| return base + (sigmoid_transform(position) * range_score) |