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 | |
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 | |
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) | |
return min(0.5, max(-0.25, bonus)) | |
def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict: | |
"""計算額外的評估因素""" | |
factors = { | |
'versatility': 0.0, # 多功能性 | |
'trainability': 0.0, # 可訓練度 | |
'energy_level': 0.0, # 能量水平 | |
'grooming_needs': 0.0, # 美容需求 | |
'social_needs': 0.0, # 社交需求 | |
'weather_adaptability': 0.0 # 氣候適應性 | |
} | |
temperament = breed_info.get('Temperament', '').lower() | |
size = breed_info.get('Size', 'Medium') | |
# 1. 多功能性評估 | |
versatile_traits = ['intelligent', 'adaptable', 'trainable', 'athletic'] | |
working_roles = ['working', 'herding', 'hunting', 'sporting', 'companion'] | |
trait_score = sum(0.2 for trait in versatile_traits if trait in temperament) | |
role_score = sum(0.2 for role in working_roles if role in breed_info.get('Description', '').lower()) | |
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 | |
} | |
factors['trainability'] = min(1.0, sum(value for trait, value in trainable_traits.items() | |
if trait in temperament)) | |
# 3. 能量水平評估 | |
exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper() | |
energy_levels = { | |
'VERY HIGH': 1.0, | |
'HIGH': 0.8, | |
'MODERATE': 0.6, | |
'LOW': 0.4, | |
'VARIES': 0.6 | |
} | |
factors['energy_level'] = energy_levels.get(exercise_needs, 0.6) | |
# 4. 美容需求評估 | |
grooming_needs = breed_info.get('Grooming Needs', 'MODERATE').upper() | |
grooming_levels = { | |
'HIGH': 1.0, | |
'MODERATE': 0.6, | |
'LOW': 0.3 | |
} | |
coat_penalty = 0.2 if any(term in breed_info.get('Description', '').lower() | |
for term in ['long coat', 'double coat']) else 0 | |
factors['grooming_needs'] = min(1.0, grooming_levels.get(grooming_needs, 0.6) + coat_penalty) | |
# 5. 社交需求評估 | |
social_traits = ['friendly', 'social', 'affectionate', 'people-oriented'] | |
antisocial_traits = ['independent', 'aloof', 'reserved'] | |
social_score = sum(0.25 for trait in social_traits if trait in temperament) | |
antisocial_score = sum(-0.2 for trait in antisocial_traits if trait in temperament) | |
factors['social_needs'] = min(1.0, max(0.0, social_score + antisocial_score)) | |
# 6. 氣候適應性評估 | |
climate_terms = { | |
'cold': ['thick coat', 'winter', 'cold climate'], | |
'hot': ['short coat', 'warm climate', 'heat tolerant'], | |
'moderate': ['adaptable', 'all climate'] | |
} | |
climate_matches = sum(1 for term in climate_terms[user_prefs.climate] | |
if term in breed_info.get('Description', '').lower()) | |
factors['weather_adaptability'] = min(1.0, climate_matches * 0.3 + 0.4) # 基礎分0.4 | |
return factors | |
def calculate_family_safety_score(breed_info: dict, children_age: str) -> float: | |
temperament = breed_info.get('Temperament', '').lower() | |
size = breed_info.get('Size', 'Medium') | |
# 基礎安全分數必須根據孩童年齡有所不同 | |
base_safety_scores = { | |
'toddler': { | |
"Small": 0.85, # 幼童與小型犬相對安全 | |
"Medium": 0.60, # 中型犬需要更多注意 | |
"Large": 0.40, # 大型犬風險較高 | |
"Giant": 0.30 # 巨型犬風險最高 | |
}, | |
'school_age': { | |
"Small": 0.90, # 學齡兒童與小型犬很合適 | |
"Medium": 0.75, # 中型犬可以接受 | |
"Large": 0.55, # 大型犬需要注意 | |
"Giant": 0.45 # 巨型犬仍需謹慎 | |
}, | |
'teenager': { | |
"Small": 0.95, # 青少年幾乎能應付所有小型犬 | |
"Medium": 0.85, # 中型犬很合適 | |
"Large": 0.70, # 大型犬可以考慮 | |
"Giant": 0.60 # 巨型犬仍需小心 | |
} | |
} | |
# 根據孩童年齡選擇對應的基礎分數 | |
safety_score = base_safety_scores[children_age][size] | |
# 年齡特定的危險特徵評估 | |
age_specific_dangerous_traits = { | |
'toddler': { | |
'aggressive': -0.40, # 幼童最危險 | |
'territorial': -0.35, | |
'protective': -0.30, | |
'nervous': -0.30, | |
'dominant': -0.25, | |
'energetic': -0.20 # 過度活潑對幼童也是風險 | |
}, | |
'school_age': { | |
'aggressive': -0.30, | |
'territorial': -0.25, | |
'protective': -0.20, | |
'nervous': -0.20, | |
'dominant': -0.15, | |
'energetic': -0.10 | |
}, | |
'teenager': { | |
'aggressive': -0.20, | |
'territorial': -0.15, | |
'protective': -0.10, | |
'nervous': -0.15, | |
'dominant': -0.10, | |
'energetic': -0.05 | |
} | |
} | |
# 套用年齡特定的特徵評估 | |
for trait, penalty in age_specific_dangerous_traits[children_age].items(): | |
if trait in temperament: | |
safety_score += penalty | |
# 正面特徵評估(根據年齡調整獎勵程度) | |
positive_traits_by_age = { | |
'toddler': { | |
'gentle': 0.15, | |
'patient': 0.15, | |
'calm': 0.12, | |
'tolerant': 0.12 | |
}, | |
'school_age': { | |
'gentle': 0.12, | |
'patient': 0.12, | |
'playful': 0.10, | |
'friendly': 0.10 | |
}, | |
'teenager': { | |
'friendly': 0.10, | |
'playful': 0.10, | |
'adaptable': 0.08, | |
'trainable': 0.08 | |
} | |
} | |
# 套用正面特徵評估 | |
for trait, bonus in positive_traits_by_age[children_age].items(): | |
if trait in temperament: | |
safety_score += bonus | |
# 特殊風險評估(對所有年齡都很重要) | |
description = breed_info.get('Description', '').lower() | |
if 'history of' in description: | |
safety_score -= 0.25 | |
if 'requires experienced' in description: | |
safety_score -= 0.15 | |
# 確保分數在合理範圍內 | |
return max(0.2, min(0.95, safety_score)) | |
# def calculate_family_safety_score(breed_info: dict, children_age: str) -> float: | |
# """ | |
# 計算品種與家庭/兒童的安全相容性分數,作為calculate_compatibility_score的一部分 | |
# 參數: | |
# breed_info (dict): 品種資訊 | |
# children_age (str): 兒童年齡組別 ('toddler', 'school_age', 'teenager') | |
# 返回: | |
# float: 0.2-0.95之間的安全分數 | |
# """ | |
# temperament = breed_info.get('Temperament', '').lower() | |
# size = breed_info.get('Size', 'Medium') | |
# # 基礎安全分數(根據體型) | |
# base_safety_scores = { | |
# "Small": 0.80, # 從 0.85 降至 0.80 | |
# "Medium": 0.65, # 從 0.75 降至 0.65 | |
# "Large": 0.50, # 從 0.65 降至 0.50 | |
# "Giant": 0.40 # 從 0.55 降至 0.40 | |
# } | |
# safety_score = base_safety_scores.get(size, 0.60) | |
# # 加強年齡相關的調整力度 | |
# age_factors = { | |
# 'toddler': { | |
# 'base_modifier': -0.25, # 從 -0.15 降至 -0.25 | |
# 'size_penalty': { | |
# "Small": -0.10, # 從 -0.05 降至 -0.10 | |
# "Medium": -0.20, # 從 -0.10 降至 -0.20 | |
# "Large": -0.30, # 從 -0.20 降至 -0.30 | |
# "Giant": -0.35 # 從 -0.25 降至 -0.35 | |
# } | |
# }, | |
# 'school_age': { | |
# 'base_modifier': -0.15, # 從 -0.08 降至 -0.15 | |
# 'size_penalty': { | |
# "Small": -0.05, | |
# "Medium": -0.10, | |
# "Large": -0.20, | |
# "Giant": -0.25 | |
# } | |
# }, | |
# 'teenager': { | |
# 'base_modifier': -0.08, # 從 -0.05 降至 -0.08 | |
# 'size_penalty': { | |
# "Small": -0.02, | |
# "Medium": -0.05, | |
# "Large": -0.10, | |
# "Giant": -0.15 | |
# } | |
# } | |
# } | |
# # 加強對危險特徵的評估 | |
# dangerous_traits = { | |
# 'aggressive': -0.35, # 從 -0.25 加重到 -0.35 | |
# 'territorial': -0.30, # 從 -0.20 加重到 -0.30 | |
# 'protective': -0.25, # 從 -0.15 加重到 -0.25 | |
# 'nervous': -0.25, # 從 -0.15 加重到 -0.25 | |
# 'dominant': -0.20, # 從 -0.15 加重到 -0.20 | |
# 'strong-willed': -0.18, # 從 -0.12 加重到 -0.18 | |
# 'independent': -0.15, # 從 -0.10 加重到 -0.15 | |
# 'energetic': -0.12 # 從 -0.08 加重到 -0.12 | |
# } | |
# # 特殊風險評估加重 | |
# if 'history of' in breed_info.get('Description', '').lower(): | |
# safety_score -= 0.25 # 從 -0.15 加重到 -0.25 | |
# if 'requires experienced' in breed_info.get('Description', '').lower(): | |
# safety_score -= 0.20 # 從 -0.10 加重到 -0.20 | |
# # 計算特徵分數 | |
# for trait, bonus in positive_traits.items(): | |
# if trait in temperament: | |
# safety_score += bonus * 0.8 # 降低正面特徵的影響力 | |
# for trait, penalty in dangerous_traits.items(): | |
# if trait in temperament: | |
# # 對幼童加重懲罰 | |
# if children_age == 'toddler': | |
# safety_score += penalty * 1.3 | |
# # 對青少年略微減輕懲罰 | |
# elif children_age == 'teenager': | |
# safety_score += penalty * 0.8 | |
# else: | |
# safety_score += penalty | |
# # 特殊風險評估 | |
# description = breed_info.get('Description', '').lower() | |
# if 'history of' in description: | |
# safety_score -= 0.15 | |
# if 'requires experienced' in description: | |
# safety_score -= 0.10 | |
# # 將分數限制在合理範圍內 | |
# return max(0.2, min(0.95, safety_score)) | |
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: | |
"""空間分數計算""" | |
# 基礎空間需求矩陣 | |
base_scores = { | |
"Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90}, | |
"Medium": {"apartment": 0.60, "house_small": 0.90, "house_large": 1.0}, | |
"Large": {"apartment": 0.30, "house_small": 0.75, "house_large": 1.0}, | |
"Giant": {"apartment": 0.15, "house_small": 0.55, "house_large": 1.0} | |
} | |
# 取得基礎分數 | |
base_score = base_scores.get(size, base_scores["Medium"])[living_space] | |
# 運動需求調整 | |
exercise_adjustments = { | |
"Very High": -0.15 if living_space == "apartment" else 0, | |
"High": -0.10 if living_space == "apartment" else 0, | |
"Moderate": 0, | |
"Low": 0.05 if living_space == "apartment" else 0 | |
} | |
adjustments = exercise_adjustments.get(exercise_needs.strip(), 0) | |
# 院子獎勵 | |
if has_yard and size in ["Large", "Giant"]: | |
adjustments += 0.10 | |
elif has_yard: | |
adjustments += 0.05 | |
return min(1.0, max(0.1, base_score + adjustments)) | |
def calculate_exercise_score(breed_needs: str, user_time: int) -> float: | |
"""運動需求計算""" | |
exercise_needs = { | |
'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180}, | |
'HIGH': {'min': 90, 'ideal': 120, 'max': 150}, | |
'MODERATE': {'min': 45, 'ideal': 60, 'max': 90}, | |
'LOW': {'min': 20, 'ideal': 30, 'max': 45}, | |
'VARIES': {'min': 30, 'ideal': 60, 'max': 90} | |
} | |
breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE']) | |
# 計算匹配度 | |
if user_time >= breed_need['ideal']: | |
if user_time > breed_need['max']: | |
return 0.9 # 稍微降分,因為可能過度運動 | |
return 1.0 | |
elif user_time >= breed_need['min']: | |
return 0.8 + (user_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.2 | |
else: | |
return max(0.3, 0.8 * (user_time / breed_need['min'])) | |
def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float: | |
"""美容需求計算""" | |
# 基礎分數矩陣 | |
base_scores = { | |
"High": {"low": 0.3, "medium": 0.7, "high": 1.0}, | |
"Moderate": {"low": 0.5, "medium": 0.9, "high": 1.0}, | |
"Low": {"low": 1.0, "medium": 0.95, "high": 0.8} | |
} | |
# 取得基礎分數 | |
base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment] | |
# 體型影響調整 | |
size_adjustments = { | |
"Large": {"low": -0.2, "medium": -0.1, "high": 0}, | |
"Giant": {"low": -0.3, "medium": -0.15, "high": 0}, | |
} | |
if breed_size in size_adjustments: | |
adjustment = size_adjustments[breed_size].get(user_commitment, 0) | |
base_score = max(0.2, base_score + adjustment) | |
return base_score | |
# def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float: | |
# """ | |
# 計算使用者經驗與品種需求的匹配分數 | |
# 參數說明: | |
# care_level: 品種的照顧難度 ("High", "Moderate", "Low") | |
# user_experience: 使用者經驗等級 ("beginner", "intermediate", "advanced") | |
# temperament: 品種的性格特徵描述 | |
# 返回: | |
# float: 0.2-1.0 之間的匹配分數 | |
# """ | |
# # 基礎分數矩陣 - 更大的分數差異來反映經驗重要性 | |
# base_scores = { | |
# "High": { | |
# "beginner": 0.12, # 降低起始分,反映高難度品種對新手的挑戰 | |
# "intermediate": 0.65, # 中級玩家可以應付,但仍有改善空間 | |
# "advanced": 1.0 # 資深者能完全勝任 | |
# }, | |
# "Moderate": { | |
# "beginner": 0.35, # 適中難度對新手來說仍具挑戰 | |
# "intermediate": 0.82, # 中級玩家有很好的勝任能力 | |
# "advanced": 1.0 # 資深者完全勝任 | |
# }, | |
# "Low": { | |
# "beginner": 0.72, # 低難度品種適合新手 | |
# "intermediate": 0.92, # 中級玩家幾乎完全勝任 | |
# "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.15, # 加重固執的懲罰 | |
# 'independent': -0.12, # 加重獨立性的懲罰 | |
# 'dominant': -0.12, # 加重支配性的懲罰 | |
# 'strong-willed': -0.10, # 加重強勢的懲罰 | |
# 'protective': -0.08, # 加重保護性的懲罰 | |
# 'aloof': -0.08, # 加重冷漠的懲罰 | |
# 'energetic': -0.06 # 輕微懲罰高能量 | |
# } | |
# # 新手友善的特徵 - 提供更多獎勵 | |
# easy_traits = { | |
# 'gentle': 0.08, # 增加溫和的獎勵 | |
# 'friendly': 0.08, # 增加友善的獎勵 | |
# 'eager to please': 0.08, # 增加順從的獎勵 | |
# 'patient': 0.06, # 獎勵耐心 | |
# 'adaptable': 0.06, # 獎勵適應性 | |
# 'calm': 0.05 # 獎勵冷靜 | |
# } | |
# # 計算特徵調整 | |
# for trait, penalty in difficult_traits.items(): | |
# if trait in temperament_lower: | |
# temperament_adjustments += penalty * 1.2 # 加重新手的懲罰 | |
# for trait, bonus in easy_traits.items(): | |
# if trait in temperament_lower: | |
# temperament_adjustments += bonus | |
# # 品種特殊調整 | |
# if any(term in temperament_lower for term in ['terrier', 'working', 'guard']): | |
# temperament_adjustments -= 0.12 # 加重對特定類型品種的懲罰 | |
# elif user_experience == "intermediate": | |
# # 中級玩家的調整更加平衡 | |
# moderate_traits = { | |
# 'intelligent': 0.05, # 獎勵聰明 | |
# 'athletic': 0.04, # 獎勵運動能力 | |
# 'versatile': 0.04, # 獎勵多功能性 | |
# 'stubborn': -0.06, # 輕微懲罰固執 | |
# 'independent': -0.05, # 輕微懲罰獨立性 | |
# 'protective': -0.04 # 輕微懲罰保護性 | |
# } | |
# for trait, adjustment in moderate_traits.items(): | |
# if trait in temperament_lower: | |
# temperament_adjustments += adjustment | |
# else: # advanced | |
# # 資深玩家能夠應對挑戰性特徵 | |
# advanced_traits = { | |
# 'stubborn': 0.04, # 反轉為優勢 | |
# 'independent': 0.04, # 反轉為優勢 | |
# 'intelligent': 0.05, # 獎勵聰明 | |
# 'protective': 0.04, # 獎勵保護性 | |
# 'strong-willed': 0.03 # 獎勵強勢 | |
# } | |
# for trait, bonus in advanced_traits.items(): | |
# if trait in temperament_lower: | |
# temperament_adjustments += bonus | |
# # 確保最終分數在合理範圍內 | |
# final_score = max(0.2, min(1.0, score + temperament_adjustments)) | |
# return final_score | |
def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float: | |
temperament_lower = temperament.lower() | |
# 重新設計基礎分數,降低起始點以留出調整空間 | |
base_scores = { | |
"High": { | |
"beginner": 0.12, | |
"intermediate": 0.45, # 降低基礎分數 | |
"advanced": 0.60 # 降低基礎分數 | |
}, | |
"Moderate": { | |
"beginner": 0.35, | |
"intermediate": 0.55, | |
"advanced": 0.70 | |
}, | |
"Low": { | |
"beginner": 0.72, | |
"intermediate": 0.65, | |
"advanced": 0.75 | |
} | |
} | |
score = base_scores.get(care_level, base_scores["Moderate"])[user_experience] | |
# 計算品種複雜度分數 | |
def calculate_complexity_score(temperament: str) -> float: | |
complexity_factors = { | |
'aggressive': 0.3, | |
'stubborn': 0.25, | |
'independent': 0.2, | |
'protective': 0.2, | |
'dominant': 0.2, | |
'strong-willed': 0.15, | |
'energetic': 0.15 | |
} | |
complexity = sum(value for trait, value in complexity_factors.items() | |
if trait in temperament_lower) | |
return min(1.0, complexity) | |
complexity = calculate_complexity_score(temperament) | |
# 根據經驗等級調整複雜度的影響 | |
experience_multipliers = { | |
"beginner": 1.5, # 新手受複雜度影響最大 | |
"intermediate": 0.8, # 中級玩家受中等影響 | |
"advanced": 0.4 # 資深玩家受影響較小但仍然存在 | |
} | |
# 應用複雜度調整 | |
complexity_impact = complexity * experience_multipliers[user_experience] | |
score = score * (1 - complexity_impact) | |
# 特徵評估(保持動態性) | |
positive_trait_limit = { | |
"beginner": 0.1, | |
"intermediate": 0.15, | |
"advanced": 0.2 | |
} | |
negative_trait_impact = { | |
"beginner": 1.5, | |
"intermediate": 1.0, | |
"advanced": 0.7 | |
} | |
# 累積特徵影響 | |
positive_impact = 0 | |
negative_impact = 0 | |
# 計算特徵影響 | |
for trait in temperament_lower.split(): | |
if trait in ['gentle', 'friendly', 'patient', 'calm']: | |
positive_impact += 0.05 | |
if trait in ['aggressive', 'nervous', 'unpredictable']: | |
negative_impact += 0.08 * negative_trait_impact[user_experience] | |
# 限制正面特徵影響 | |
positive_impact = min(positive_trait_limit[user_experience], positive_impact) | |
# 應用特徵調整 | |
final_score = score + positive_impact - negative_impact | |
# 確保分數在合理範圍內 | |
return max(0.2, min(0.95, final_score)) | |
def calculate_health_score(breed_name: str) -> float: | |
"""計算品種健康分數""" | |
if breed_name not in breed_health_info: | |
return 0.5 | |
health_notes = breed_health_info[breed_name]['health_notes'].lower() | |
# 嚴重健康問題(降低0.15分) | |
severe_conditions = [ | |
'hip dysplasia', | |
'heart disease', | |
'progressive retinal atrophy', | |
'bloat', | |
'epilepsy', | |
'degenerative myelopathy', | |
'von willebrand disease' | |
] | |
# 中度健康問題(降低0.1分) | |
moderate_conditions = [ | |
'allergies', | |
'eye problems', | |
'joint problems', | |
'hypothyroidism', | |
'ear infections', | |
'skin issues' | |
] | |
# 輕微健康問題(降低0.05分) | |
minor_conditions = [ | |
'dental issues', | |
'weight gain tendency', | |
'minor allergies', | |
'seasonal allergies' | |
] | |
# 計算基礎健康分數 | |
health_score = 1.0 | |
# 根據問題嚴重程度扣分 | |
severe_count = sum(1 for condition in severe_conditions if condition in health_notes) | |
moderate_count = sum(1 for condition in moderate_conditions if condition in health_notes) | |
minor_count = sum(1 for condition in minor_conditions if condition in health_notes) | |
health_score -= (severe_count * 0.15) | |
health_score -= (moderate_count * 0.1) | |
health_score -= (minor_count * 0.05) | |
# 壽命影響 | |
try: | |
lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12') | |
years = float(lifespan.split('-')[0]) | |
if years < 8: | |
health_score *= 0.9 | |
elif years > 13: | |
health_score *= 1.1 | |
except: | |
pass | |
# 特殊健康優勢 | |
if 'generally healthy' in health_notes or 'hardy breed' in health_notes: | |
health_score *= 1.1 | |
return max(0.2, min(1.0, health_score)) | |
def calculate_noise_score(breed_name: str, user_noise_tolerance: str) -> 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.9, 'high': 0.8}, | |
'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.9}, | |
'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0}, | |
'varies': {'low': 0.6, 'medium': 0.8, 'high': 0.9} | |
} | |
# 獲取基礎分數 | |
base_score = base_scores.get(noise_level, {'low': 0.7, 'medium': 0.8, 'high': 0.6})[user_noise_tolerance] | |
# 吠叫原因評估 | |
barking_reasons_penalty = 0 | |
problematic_triggers = [ | |
('separation anxiety', -0.15), | |
('excessive barking', -0.12), | |
('territorial', -0.08), | |
('alert barking', -0.05), | |
('attention seeking', -0.05) | |
] | |
for trigger, penalty in problematic_triggers: | |
if trigger in noise_notes: | |
barking_reasons_penalty += penalty | |
# 可訓練性補償 | |
trainability_bonus = 0 | |
if 'responds well to training' in noise_notes: | |
trainability_bonus = 0.1 | |
elif 'can be trained' in noise_notes: | |
trainability_bonus = 0.05 | |
# 特殊情況 | |
special_adjustments = 0 | |
if 'rarely barks' in noise_notes: | |
special_adjustments += 0.1 | |
if 'howls' in noise_notes and user_noise_tolerance == 'low': | |
special_adjustments -= 0.1 | |
final_score = base_score + barking_reasons_penalty + trainability_bonus + special_adjustments | |
return max(0.2, min(1.0, final_score)) | |
# # 計算所有基礎分數 | |
# scores = { | |
# 'space': calculate_space_score( | |
# breed_info['Size'], | |
# user_prefs.living_space, | |
# user_prefs.space_for_play, | |
# breed_info.get('Exercise Needs', 'Moderate') | |
# ), | |
# 'exercise': calculate_exercise_score( | |
# breed_info.get('Exercise Needs', 'Moderate'), | |
# user_prefs.exercise_time | |
# ), | |
# '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', '')), | |
# 'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance) | |
# } | |
# # 優化權重配置 | |
# weights = { | |
# 'space': 0.28, | |
# 'exercise': 0.18, | |
# 'grooming': 0.12, | |
# 'experience': 0.22, | |
# 'health': 0.12, | |
# 'noise': 0.08 | |
# } | |
# # 計算加權總分 | |
# weighted_score = sum(score * weights[category] for category, score in scores.items()) | |
# def amplify_score(score): | |
# """ | |
# 優化分數放大函數,確保分數範圍合理且結果一致 | |
# """ | |
# # 基礎調整 | |
# adjusted = (score - 0.35) * 1.8 | |
# # 使用 3.2 次方使曲線更平滑 | |
# amplified = pow(adjusted, 3.2) / 5.8 + score | |
# # 特別處理高分區間,確保不超過95% | |
# if amplified > 0.90: | |
# # 壓縮高分區間,確保最高到95% | |
# amplified = 0.90 + (amplified - 0.90) * 0.5 | |
# # 確保最終分數在合理範圍內(0.55-0.95) | |
# final_score = max(0.55, min(0.95, amplified)) | |
# # 四捨五入到小數點後第三位 | |
# return round(final_score, 3) | |
# final_score = amplify_score(weighted_score) | |
# # 四捨五入所有分數 | |
# scores = {k: round(v, 4) for k, v in scores.items()} | |
# scores['overall'] = round(final_score, 4) | |
# return scores | |
# 計算所有基礎分數 | |
scores = { | |
'space': calculate_space_score( | |
breed_info['Size'], | |
user_prefs.living_space, | |
user_prefs.space_for_play, | |
breed_info.get('Exercise Needs', 'Moderate') | |
), | |
'exercise': calculate_exercise_score( | |
breed_info.get('Exercise Needs', 'Moderate'), | |
user_prefs.exercise_time | |
), | |
'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', '')), | |
'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance) | |
} | |
# 2. 計算品種加分 | |
breed_bonus = calculate_breed_bonus(breed_info, user_prefs) | |
# 3. 如果有孩童,計算安全分數,但不直接修改基礎分數 | |
if user_prefs.has_children: | |
family_safety = calculate_family_safety_score(breed_info, user_prefs.children_age) | |
# 創建安全性調整係數 | |
safety_adjustments = { | |
'toddler': 0.6, # 對幼童最嚴格 | |
'school_age': 0.75, # 學齡兒童較寬鬆 | |
'teenager': 0.85 # 青少年最寬鬆 | |
} | |
# 調整權重而不是直接修改分數 | |
safety_weight = safety_adjustments[user_prefs.children_age] | |
# 修改最終加權計算方式 | |
weights = { | |
'space': 0.22, | |
'exercise': 0.15, | |
'grooming': 0.10, | |
'experience': 0.18, | |
'health': 0.10, | |
'noise': 0.05 | |
} | |
# 加入安全性權重 | |
final_score = ( | |
sum(score * weights[category] for category, score in scores.items()) * safety_weight + | |
family_safety * (1 - safety_weight) | |
) | |
# 品種加分也要考慮安全性 | |
breed_bonus *= family_safety | |
else: | |
# 原有的權重 | |
weights = { | |
'space': 0.28, | |
'exercise': 0.18, | |
'grooming': 0.12, | |
'experience': 0.22, | |
'health': 0.12, | |
'noise': 0.08 | |
} | |
final_score = sum(score * weights[category] for category, score in scores.items()) | |
# 4. 應用品種加分 | |
final_score *= (1 + breed_bonus * 0.2) | |
# 5. 最終分數調整 | |
def amplify_score(score): | |
adjusted = (score - 0.25) * 1.8 | |
amplified = pow(adjusted, 2.2) / 3.5 + score | |
if amplified > 0.85: | |
amplified = 0.85 + (amplified - 0.85) * 0.6 | |
return max(0.45, min(0.95, amplified)) | |
final_score = amplify_score(final_score) | |
# 6. 回傳結果 | |
scores = {k: round(v, 4) for k, v in scores.items()} | |
scores['overall'] = round(final_score, 4) | |
return scores | |
# except Exception as e: | |
# print(f"Error details: {str(e)}") | |
# print(f"breed_info: {breed_info}") | |
# # print(f"Error in calculate_compatibility_score: {str(e)}") | |
# return {k: 0.5 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']} | |
except Exception as e: | |
print(f"Error in calculate_compatibility_score: {str(e)}") | |
return {k: 0.7 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']} | |