PawMatchAI / scoring_calculation_system.py
DawnC's picture
Update scoring_calculation_system.py
679c889 verified
raw
history blame
38.3 kB
from dataclasses import dataclass
from breed_health_info import breed_health_info
from breed_noise_info import breed_noise_info
import traceback
@dataclass
class UserPreferences:
"""使用者偏好設定的資料結構"""
living_space: str # "apartment", "house_small", "house_large"
yard_access: str # "no_yard", "shared_yard", "private_yard"
exercise_time: int # minutes per day
exercise_type: str # "light_walks", "moderate_activity", "active_training"
grooming_commitment: str # "low", "medium", "high"
experience_level: str # "beginner", "intermediate", "advanced"
time_availability: str # "limited", "moderate", "flexible"
has_children: bool
children_age: str # "toddler", "school_age", "teenager"
noise_tolerance: str # "low", "medium", "high"
space_for_play: bool
other_pets: bool
climate: str # "cold", "moderate", "hot"
health_sensitivity: str = "medium"
barking_acceptance: str = None
def __post_init__(self):
"""在初始化後運行,用於設置派生值"""
if self.barking_acceptance is None:
self.barking_acceptance = self.noise_tolerance
@staticmethod
def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float:
"""計算品種額外加分"""
bonus = 0.0
temperament = breed_info.get('Temperament', '').lower()
# 1. 壽命加分(最高0.05)
try:
lifespan = breed_info.get('Lifespan', '10-12 years')
years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
longevity_bonus = min(0.05, (max(years) - 10) * 0.01)
bonus += longevity_bonus
except:
pass
# 2. 性格特徵加分(最高0.15)
positive_traits = {
'friendly': 0.05,
'gentle': 0.05,
'patient': 0.05,
'intelligent': 0.04,
'adaptable': 0.04,
'affectionate': 0.04,
'easy-going': 0.03,
'calm': 0.03
}
negative_traits = {
'aggressive': -0.08,
'stubborn': -0.06,
'dominant': -0.06,
'aloof': -0.04,
'nervous': -0.05,
'protective': -0.04
}
personality_score = sum(value for trait, value in positive_traits.items() if trait in temperament)
personality_score += sum(value for trait, value in negative_traits.items() if trait in temperament)
bonus += max(-0.15, min(0.15, personality_score))
# 3. 適應性加分(最高0.1)
adaptability_bonus = 0.0
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
adaptability_bonus += 0.05
if 'adaptable' in temperament or 'versatile' in temperament:
adaptability_bonus += 0.05
bonus += min(0.1, adaptability_bonus)
# 4. 家庭相容性(最高0.1)
if user_prefs.has_children:
family_traits = {
'good with children': 0.06,
'patient': 0.05,
'gentle': 0.05,
'tolerant': 0.04,
'playful': 0.03
}
unfriendly_traits = {
'aggressive': -0.08,
'nervous': -0.07,
'protective': -0.06,
'territorial': -0.05
}
# 年齡評估這樣能更細緻
age_adjustments = {
'toddler': {'bonus_mult': 0.7, 'penalty_mult': 1.3},
'school_age': {'bonus_mult': 1.0, 'penalty_mult': 1.0},
'teenager': {'bonus_mult': 1.2, 'penalty_mult': 0.8}
}
adj = age_adjustments.get(user_prefs.children_age,
{'bonus_mult': 1.0, 'penalty_mult': 1.0})
family_bonus = sum(value for trait, value in family_traits.items()
if trait in temperament) * adj['bonus_mult']
family_penalty = sum(value for trait, value in unfriendly_traits.items()
if trait in temperament) * adj['penalty_mult']
bonus += min(0.15, max(-0.2, family_bonus + family_penalty))
# 5. 專門技能加分(最高0.1)
skill_bonus = 0.0
special_abilities = {
'working': 0.03,
'herding': 0.03,
'hunting': 0.03,
'tracking': 0.03,
'agility': 0.02
}
for ability, value in special_abilities.items():
if ability in temperament.lower():
skill_bonus += value
bonus += min(0.1, skill_bonus)
return min(0.5, max(-0.25, bonus))
@staticmethod
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
@staticmethod
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:
"""
計算使用者經驗與品種需求的匹配分數
參數說明:
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.02, # 降低加分幅度
'independent': 0.02,
'intelligent': 0.05,
'protective': 0.02,
'strong-willed': 0.02,
'aggressive': -0.04, # 新增負面特徵
'nervous': -0.03,
'dominant': -0.02
}
for trait, bonus in advanced_traits.items():
if trait in temperament_lower:
# 加入條件評估
if bonus > 0: # 正面特徵
# 限制正面特徵的累積加分不超過0.15
if temperament_adjustments + bonus <= 0.15:
temperament_adjustments += bonus
else: # 負面特徵
# 負面特徵一定要計算
temperament_adjustments += bonus
# 確保最終分數在合理範圍內
final_score = max(0.2, min(1.0, score + temperament_adjustments))
return 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)
}
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())
# 如果有孩童,加入家庭安全考量
if user_prefs.has_children:
try:
family_safety = calculate_family_safety_score(breed_info, user_prefs.children_age)
# family_safety 作為調整因子,而不是新的分數項目
# 這裡的 0.4 表示 family_safety 最多可以降低 60% 的分數
safety_modifier = (family_safety * 0.6) + 0.4
weighted_score *= safety_modifier
except Exception as e:
print(f"Family safety calculation error: {str(e)}")
# 發生錯誤時使用較保守的預設值
weighted_score *= 0.7
# 加入品種加分的影響
try:
breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
# breed_bonus 作為加成效果,但限制其影響範圍
bonus_modifier = 1 + (breed_bonus * 0.3) # 品種加分最多提升 30%
weighted_score *= bonus_modifier
except Exception as e:
print(f"Breed bonus calculation error: {str(e)}")
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
# 確保分數在合理範圍內(0.45-0.95)
final_score = max(0.45, 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
# 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"Critical error in compatibility score calculation:")
print(f"Error type: {type(e).__name__}")
print(f"Error message: {str(e)}")
print(f"Breed info: {breed_info}")
print(f"User preferences: {user_prefs.__dict__}")
# 嘗試返回已計算的分數,若完全失敗則返回預設值
try:
return scores
except:
return {
'space': 0.7,
'exercise': 0.7,
'grooming': 0.7,
'experience': 0.7,
'health': 0.7,
'noise': 0.7,
'overall': 0.7
}