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)) | |