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 | |
| 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']} | |