Spaces:
Running
Running
from dataclasses import dataclass | |
from breed_health_info import breed_health_info | |
from breed_noise_info import breed_noise_info | |
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 | |
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 | |
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']} | |