PawMatchAI / scoring_calculation_system.py
DawnC's picture
Update scoring_calculation_system.py
2c41ede verified
raw
history blame
11.4 kB
from dataclasses import dataclass
from breed_health_info import breed_health_info
from breed_noise_info import breed_noise_info
@dataclass
class UserPreferences:
"""使用者偏好設定的資料結構"""
living_space: str # "apartment", "house_small", "house_large"
exercise_time: int # minutes per day
grooming_commitment: str # "low", "medium", "high"
experience_level: str # "beginner", "intermediate", "advanced"
has_children: bool
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
# 壽命加分
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
# 性格特徵加分
temperament = breed_info.get('Temperament', '').lower()
if user_prefs.has_children:
if 'gentle' in temperament or 'patient' in temperament:
bonus += 0.03
# 適應性加分
if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
bonus += 0.02
return bonus
@staticmethod
def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
"""計算額外的排序因素"""
factors = {
'versatility': 0.0,
'health_score': 0.0,
'adaptability': 0.0
}
# 計算多功能性分數
temperament = breed_info.get('Temperament', '').lower()
versatile_traits = ['intelligent', 'adaptable', 'versatile', 'trainable']
factors['versatility'] = sum(trait in temperament for trait in versatile_traits) / len(versatile_traits)
# 計算健康分數(基於預期壽命)
lifespan = breed_info.get('Lifespan', '10-12 years')
try:
years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
factors['health_score'] = min(1.0, max(years) / 15) # 標準化到0-1範圍
except:
factors['health_score'] = 0.5 # 預設值
# 計算適應性分數
size = breed_info.get('Size', 'Medium')
factors['adaptability'] = {
'Small': 0.9,
'Medium': 0.7,
'Large': 0.5,
'Giant': 0.3
}.get(size, 0.5)
return factors
def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences) -> dict:
"""計算品種與使用者條件的相容性分數"""
scores = {}
try:
# 1. 空間相容性計算
def calculate_space_score(size, living_space, has_yard):
base_scores = {
"Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90},
"Medium": {"apartment": 0.65, "house_small": 0.90, "house_large": 1.0},
"Large": {"apartment": 0.35, "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]
adjustments = 0
# 特殊情況調整
if living_space == "apartment":
if size == "Small":
adjustments += 0.05
elif size in ["Large", "Giant"]:
adjustments -= 0.15
if has_yard and living_space in ["house_small", "house_large"]:
adjustments += 0.05
return min(1.0, max(0, base_score + adjustments))
# 2. 運動相容性計算
def calculate_exercise_score(breed_exercise_needs, user_exercise_time):
exercise_needs = {
'VERY HIGH': 120,
'HIGH': 90,
'MODERATE': 60,
'LOW': 30,
'VARIES': 60
}
breed_need = exercise_needs.get(breed_exercise_needs.strip().upper(), 60)
difference = abs(user_exercise_time - breed_need) / breed_need
if difference == 0:
return 1.0
elif difference <= 0.2:
return 0.95
elif difference <= 0.4:
return 0.85
elif difference <= 0.6:
return 0.70
elif difference <= 0.8:
return 0.50
else:
return 0.30
# 3. 美容需求計算
def calculate_grooming_score(breed_grooming_needs, user_commitment, breed_size):
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.9}
}
base_score = base_scores.get(breed_grooming_needs, base_scores["Moderate"])[user_commitment]
if breed_size == "Large" and user_commitment == "low":
base_score *= 0.80
elif breed_size == "Giant" and user_commitment == "low":
base_score *= 0.70
return base_score
# 4. 經驗等級計算
def calculate_experience_score(care_level, user_experience, temperament):
base_scores = {
"High": {"beginner": 0.3, "intermediate": 0.7, "advanced": 1.0},
"Moderate": {"beginner": 0.6, "intermediate": 0.9, "advanced": 1.0},
"Low": {"beginner": 0.9, "intermediate": 1.0, "advanced": 1.0}
}
score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
temperament_lower = temperament.lower()
if user_experience == "beginner":
if any(trait in temperament_lower for trait in ['stubborn', 'independent', 'intelligent']):
score *= 0.80
if any(trait in temperament_lower for trait in ['easy', 'gentle', 'friendly']):
score *= 1.15
return min(1.0, 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()
# 嚴重健康問題
severe_conditions = [
'cancer', 'cardiomyopathy', 'epilepsy', 'dysplasia',
'bloat', 'progressive', 'syndrome'
]
# 中等健康問題
moderate_conditions = [
'allergies', 'infections', 'thyroid', 'luxation',
'skin problems', 'ear'
]
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)
health_score = 1.0
health_score -= (severe_count * 0.1)
health_score -= (moderate_count * 0.05)
# 特殊條件調整
if user_prefs.has_children:
if 'requires frequent' in health_notes or 'regular monitoring' in health_notes:
health_score *= 0.9
if user_prefs.experience_level == 'beginner':
if 'requires frequent' in health_notes or 'requires experienced' in health_notes:
health_score *= 0.8
return max(0.3, 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_matrix = {
'low': {'low': 1.0, 'medium': 0.8, 'high': 0.6},
'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.8},
'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0}
}
# 從噪音矩陣獲取基礎分數
base_score = noise_matrix.get(noise_level, {'low': 0.7, 'medium': 0.7, 'high': 0.7})[user_noise_tolerance]
# 特殊情況調整
special_adjustments = 0
if user_prefs.has_children and noise_level == 'high':
special_adjustments -= 0.1
if user_prefs.living_space == 'apartment':
if noise_level == 'high':
special_adjustments -= 0.15
elif noise_level == 'medium':
special_adjustments -= 0.05
final_score = base_score + special_adjustments
return max(0.3, min(1.0, final_score))
# 計算所有基礎分數
scores = {
'space': calculate_space_score(breed_info['Size'], user_prefs.living_space, user_prefs.space_for_play),
'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.20,
'exercise': 0.20,
'grooming': 0.15,
'experience': 0.15,
'health': 0.15,
'noise': 0.15
}
# 基礎分數計算
base_score = sum(score * weights[category]
for category, score in scores.items()
if category != 'overall')
# 額外調整
adjustments = 0
# 1. 適應性加分
if breed_info.get('Adaptability', 'Medium') == 'High':
adjustments += 0.02
# 2. 氣候相容性
if user_prefs.climate in breed_info.get('Suitable Climate', '').split(','):
adjustments += 0.02
# 3. 其他寵物相容性
if user_prefs.other_pets and breed_info.get('Good with Other Pets') == 'Yes':
adjustments += 0.02
final_score = min(1.0, max(0, base_score + adjustments))
scores['overall'] = round(final_score, 4)
# 四捨五入所有分數
for key in scores:
scores[key] = round(scores[key], 4)
return scores
except Exception as e:
print(f"Error in calculate_compatibility_score: {str(e)}")
return {k: 0.5 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}