Spaces:
Running
on
Zero
Running
on
Zero
| import math | |
| from typing import Dict, Any | |
| from dataclasses import 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 | |
| size_preference: str = "no_preference" # "no_preference", "small", "medium", "large", "giant" | |
| 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 | |
| class BonusPenaltyEngine: | |
| """ | |
| 加分扣分引擎類別 | |
| 負責處理所有品種加分機制、額外評估因素和分數分布優化 | |
| """ | |
| def __init__(self): | |
| """初始化加分扣分引擎""" | |
| pass | |
| def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float: | |
| """ | |
| 計算品種額外加分 | |
| Args: | |
| breed_info: 品種資訊字典 | |
| user_prefs: 使用者偏好設定 | |
| Returns: | |
| float: 品種加分 (-0.25 到 0.5 之間) | |
| """ | |
| 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.15) | |
| 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 amplify_score_extreme(self, score: float) -> float: | |
| """ | |
| 優化分數分布,提供更有意義的評分範圍。 | |
| 純粹進行數學轉換,不依賴外部資訊。 | |
| Parameters: | |
| score: 原始評分(0-1之間的浮點數) | |
| Returns: | |
| float: 調整後的評分(0-1之間的浮點數) | |
| """ | |
| def smooth_curve(x: float, steepness: float = 12) -> float: | |
| """創建平滑的S型曲線用於分數轉換""" | |
| return 1 / (1 + math.exp(-steepness * (x - 0.5))) | |
| # 90-100分的轉換(極佳匹配) | |
| if score >= 0.90: | |
| position = (score - 0.90) / 0.10 | |
| return 0.96 + (position * 0.04) | |
| # 80-90分的轉換(優秀匹配) | |
| elif score >= 0.80: | |
| position = (score - 0.80) / 0.10 | |
| return 0.90 + (position * 0.06) | |
| # 70-80分的轉換(良好匹配) | |
| elif score >= 0.70: | |
| position = (score - 0.70) / 0.10 | |
| return 0.82 + (position * 0.08) | |
| # 50-70分的轉換(可接受匹配) | |
| elif score >= 0.50: | |
| position = (score - 0.50) / 0.20 | |
| return 0.75 + (smooth_curve(position) * 0.07) | |
| # 50分以下的轉換(較差匹配) | |
| else: | |
| position = score / 0.50 | |
| return 0.70 + (smooth_curve(position) * 0.05) | |
| def apply_special_case_adjustments(self, score: float, user_prefs: UserPreferences, breed_info: dict) -> float: | |
| """ | |
| 處理特殊情況和極端案例的評分調整。這個函數特別關注: | |
| 1. 條件組合的協同效應 | |
| 2. 品種特性的獨特需求 | |
| 3. 極端情況的合理處理 | |
| 這個函數就像是一個細心的裁判,會考慮到各種特殊情況, | |
| 並根據具體場景做出合理的評分調整。 | |
| Parameters: | |
| score: 初始評分 | |
| user_prefs: 使用者偏好 | |
| breed_info: 品種資訊 | |
| Returns: | |
| float: 調整後的評分(0.2-1.0之間) | |
| """ | |
| severity_multiplier = 1.0 | |
| def evaluate_spatial_exercise_combination() -> float: | |
| """ | |
| 評估空間與運動需求的組合效應。 | |
| 這個函數不再過分懲罰大型犬,而是更多地考慮品種的實際特性。 | |
| 就像評估一個運動員是否適合在特定場地訓練一樣,我們需要考慮 | |
| 場地大小和運動需求的整體匹配度。 | |
| """ | |
| multiplier = 1.0 | |
| if user_prefs.living_space == 'apartment': | |
| temperament = breed_info.get('Temperament', '').lower() | |
| description = breed_info.get('Description', '').lower() | |
| # 檢查品種是否有利於公寓生活的特徵 | |
| apartment_friendly = any(trait in temperament or trait in description | |
| for trait in ['calm', 'adaptable', 'quiet']) | |
| # 大型犬的特殊處理 | |
| if breed_info['Size'] in ['Large', 'Giant']: | |
| if apartment_friendly: | |
| multiplier *= 0.85 # 從0.7提升到0.85,降低懲罰 | |
| else: | |
| multiplier *= 0.75 # 從0.5提升到0.75 | |
| # 檢查運動需求的匹配度 | |
| exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() | |
| exercise_time = user_prefs.exercise_time | |
| if exercise_needs in ['HIGH', 'VERY HIGH']: | |
| if exercise_time >= 120: # 高運動量可以部分補償空間限制 | |
| multiplier *= 1.1 | |
| return multiplier | |
| def evaluate_experience_combination() -> float: | |
| """ | |
| 評估經驗需求的複合影響。 | |
| 這個函數就像是評估一個工作崗位與應聘者經驗的匹配度, | |
| 需要綜合考慮工作難度和應聘者能力。 | |
| """ | |
| multiplier = 1.0 | |
| temperament = breed_info.get('Temperament', '').lower() | |
| care_level = breed_info.get('Care Level', 'MODERATE') | |
| # 新手飼主的特殊考慮,更寬容的評估標準 | |
| if user_prefs.experience_level == 'beginner': | |
| if care_level == 'HIGH': | |
| if user_prefs.has_children: | |
| multiplier *= 0.7 # 從0.5提升到0.7 | |
| else: | |
| multiplier *= 0.8 # 從0.6提升到0.8 | |
| # 性格特徵影響,降低懲罰程度 | |
| challenging_traits = { | |
| 'stubborn': -0.10, # 從-0.15降低 | |
| 'independent': -0.08, # 從-0.12降低 | |
| 'dominant': -0.08, # 從-0.12降低 | |
| 'protective': -0.06, # 從-0.10降低 | |
| 'aggressive': -0.15 # 保持較高懲罰因安全考慮 | |
| } | |
| for trait, penalty in challenging_traits.items(): | |
| if trait in temperament: | |
| multiplier *= (1 + penalty) | |
| return multiplier | |
| def evaluate_breed_specific_requirements() -> float: | |
| """ | |
| 評估品種特定需求。 | |
| 這個函數就像是為每個品種量身定制評估標準, | |
| 考慮其獨特的特性和需求。 | |
| """ | |
| multiplier = 1.0 | |
| exercise_time = user_prefs.exercise_time | |
| exercise_type = user_prefs.exercise_type | |
| # 檢查品種特性 | |
| temperament = breed_info.get('Temperament', '').lower() | |
| description = breed_info.get('Description', '').lower() | |
| exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() | |
| # 運動需求匹配度評估,更合理的標準 | |
| if exercise_needs == 'LOW': | |
| if exercise_time > 120: | |
| multiplier *= 0.85 # 從0.5提升到0.85 | |
| elif exercise_needs == 'VERY HIGH': | |
| if exercise_time < 60: | |
| multiplier *= 0.7 # 從0.5提升到0.7 | |
| # 特殊品種類型的考慮 | |
| if 'sprint' in temperament: | |
| if exercise_time > 120 and exercise_type != 'active_training': | |
| multiplier *= 0.85 # 從0.7提升到0.85 | |
| if any(trait in temperament for trait in ['working', 'herding']): | |
| if exercise_time < 90 or exercise_type == 'light_walks': | |
| multiplier *= 0.8 # 從0.7提升到0.8 | |
| return multiplier | |
| # 計算各項調整 | |
| space_exercise_mult = evaluate_spatial_exercise_combination() | |
| experience_mult = evaluate_experience_combination() | |
| breed_specific_mult = evaluate_breed_specific_requirements() | |
| # 整合所有調整因素 | |
| severity_multiplier *= space_exercise_mult | |
| severity_multiplier *= experience_mult | |
| severity_multiplier *= breed_specific_mult | |
| # 應用最終調整,確保分數在合理範圍內 | |
| final_score = score * severity_multiplier | |
| return max(0.2, min(1.0, final_score)) | |