DawnC commited on
Commit
d0648e6
1 Parent(s): 8ea8640

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +951 -243
scoring_calculation_system.py CHANGED
@@ -29,103 +29,259 @@ class UserPreferences:
29
  self.barking_acceptance = self.noise_tolerance
30
 
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  @staticmethod
33
- def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float:
34
- """計算品種額外加分"""
 
 
 
 
 
 
 
 
35
  bonus = 0.0
36
  temperament = breed_info.get('Temperament', '').lower()
37
 
38
- # 1. 壽命加分(最高0.05)
39
  try:
40
  lifespan = breed_info.get('Lifespan', '10-12 years')
41
  years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
42
- longevity_bonus = min(0.05, (max(years) - 10) * 0.01)
43
- bonus += longevity_bonus
 
 
 
 
 
 
 
 
 
44
  except:
45
  pass
46
 
47
- # 2. 性格特徵加分(最高0.15)
48
  positive_traits = {
49
- 'friendly': 0.05,
50
- 'gentle': 0.05,
51
- 'patient': 0.05,
52
- 'intelligent': 0.04,
53
- 'adaptable': 0.04,
54
- 'affectionate': 0.04,
55
- 'easy-going': 0.03,
56
- 'calm': 0.03
57
  }
58
 
59
  negative_traits = {
60
- 'aggressive': -0.08,
61
- 'stubborn': -0.06,
62
- 'dominant': -0.06,
63
- 'aloof': -0.04,
64
- 'nervous': -0.05,
65
- 'protective': -0.04
66
  }
67
 
68
- personality_score = sum(value for trait, value in positive_traits.items() if trait in temperament)
69
- personality_score += sum(value for trait, value in negative_traits.items() if trait in temperament)
70
- bonus += max(-0.15, min(0.15, personality_score))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
- # 3. 適應性加分(最高0.1)
73
  adaptability_bonus = 0.0
74
  if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
75
- adaptability_bonus += 0.05
 
 
76
  if 'adaptable' in temperament or 'versatile' in temperament:
77
- adaptability_bonus += 0.05
78
- bonus += min(0.1, adaptability_bonus)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- # 4. 家庭相容性(最高0.1)
81
  if user_prefs.has_children:
82
  family_traits = {
83
- 'good with children': 0.06,
84
- 'patient': 0.05,
85
- 'gentle': 0.05,
86
- 'tolerant': 0.04,
87
- 'playful': 0.03
88
  }
 
89
  unfriendly_traits = {
90
- 'aggressive': -0.08,
91
- 'nervous': -0.07,
92
- 'protective': -0.06,
93
- 'territorial': -0.05
94
  }
95
 
96
- # 年齡評估這樣能更細緻
97
  age_adjustments = {
98
- 'toddler': {'bonus_mult': 0.7, 'penalty_mult': 1.3},
99
- 'school_age': {'bonus_mult': 1.0, 'penalty_mult': 1.0},
100
- 'teenager': {'bonus_mult': 1.2, 'penalty_mult': 0.8}
 
 
 
 
 
 
 
 
 
101
  }
102
 
103
  adj = age_adjustments.get(user_prefs.children_age,
104
  {'bonus_mult': 1.0, 'penalty_mult': 1.0})
105
 
106
- family_bonus = sum(value for trait, value in family_traits.items()
107
- if trait in temperament) * adj['bonus_mult']
108
- family_penalty = sum(value for trait, value in unfriendly_traits.items()
109
- if trait in temperament) * adj['penalty_mult']
 
 
 
 
 
110
 
111
- bonus += min(0.15, max(-0.2, family_bonus + family_penalty))
112
-
113
-
114
- # 5. 專門技能加分(最高0.1)
115
- skill_bonus = 0.0
116
- special_abilities = {
117
- 'working': 0.03,
118
- 'herding': 0.03,
119
- 'hunting': 0.03,
120
- 'tracking': 0.03,
121
- 'agility': 0.02
122
- }
123
- for ability, value in special_abilities.items():
124
- if ability in temperament.lower():
125
- skill_bonus += value
126
- bonus += min(0.1, skill_bonus)
127
 
128
- return min(0.5, max(-0.25, bonus))
 
129
 
130
 
131
  @staticmethod
@@ -216,36 +372,105 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
216
  print("Missing Size information")
217
  raise KeyError("Size information missing")
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
220
- """空間分數計算"""
221
- # 基礎空間需求矩陣
222
  base_scores = {
223
- "Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90},
224
- "Medium": {"apartment": 0.60, "house_small": 0.90, "house_large": 1.0},
225
- "Large": {"apartment": 0.30, "house_small": 0.75, "house_large": 1.0},
226
- "Giant": {"apartment": 0.15, "house_small": 0.55, "house_large": 1.0}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  }
228
 
229
  # 取得基礎分數
230
  base_score = base_scores.get(size, base_scores["Medium"])[living_space]
231
 
232
- # 運動需求調整
233
  exercise_adjustments = {
234
- "Very High": -0.15 if living_space == "apartment" else 0,
235
- "High": -0.10 if living_space == "apartment" else 0,
236
- "Moderate": 0,
237
- "Low": 0.05 if living_space == "apartment" else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
 
240
- adjustments = exercise_adjustments.get(exercise_needs.strip(), 0)
 
 
241
 
242
- # 院子獎勵
243
- if has_yard and size in ["Large", "Giant"]:
244
- adjustments += 0.10
245
- elif has_yard:
246
- adjustments += 0.05
247
-
248
- return min(1.0, max(0.1, base_score + adjustments))
 
 
 
 
 
249
 
250
  def calculate_exercise_score(breed_needs: str, user_time: int) -> float:
251
  """運動需求計算"""
@@ -269,29 +494,160 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
269
  else:
270
  return max(0.3, 0.8 * (user_time / breed_need['min']))
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
273
- """美容需求計算"""
274
- # 基礎分數矩陣
 
 
 
275
  base_scores = {
276
- "High": {"low": 0.3, "medium": 0.7, "high": 1.0},
277
- "Moderate": {"low": 0.5, "medium": 0.9, "high": 1.0},
278
- "Low": {"low": 1.0, "medium": 0.95, "high": 0.8}
 
 
 
 
 
 
 
 
 
 
 
 
279
  }
280
-
281
  # 取得基礎分數
282
  base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
283
-
284
- # 體型影響調整
285
  size_adjustments = {
286
- "Large": {"low": -0.2, "medium": -0.1, "high": 0},
287
- "Giant": {"low": -0.3, "medium": -0.15, "high": 0},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
289
-
290
- if breed_size in size_adjustments:
291
- adjustment = size_adjustments[breed_size].get(user_commitment, 0)
292
- base_score = max(0.2, base_score + adjustment)
 
 
 
 
 
 
 
293
 
294
- return base_score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
 
296
 
297
  # def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
@@ -403,24 +759,29 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
403
 
404
  def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
405
  """
406
- 計算經驗分數,加強不同經驗等級的區別
 
 
 
 
 
407
  """
408
- # 基礎分數矩陣 - 調整分數範圍,讓差異更明顯
409
  base_scores = {
410
  "High": {
411
- "beginner": 0.15, # 從0.12降到0.15,對新手更嚴格
412
- "intermediate": 0.65, # 保持不變
413
- "advanced": 1.0
414
  },
415
  "Moderate": {
416
- "beginner": 0.45, # 從0.35提高到0.45,增加區別
417
- "intermediate": 0.82,
418
- "advanced": 1.0
419
  },
420
  "Low": {
421
- "beginner": 0.85, # 從0.72提高到0.85,更適合新手
422
- "intermediate": 0.92,
423
- "advanced": 1.0
424
  }
425
  }
426
 
@@ -430,29 +791,31 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
430
  temperament_lower = temperament.lower()
431
  temperament_adjustments = 0.0
432
 
 
433
  if user_experience == "beginner":
434
- # 調整新手的懲罰力度
435
  difficult_traits = {
436
- 'stubborn': -0.25, # 從-0.15加重到-0.25
437
- 'independent': -0.20, # 從-0.12加重到-0.20
438
- 'dominant': -0.20,
439
- 'strong-willed': -0.18,
440
- 'protective': -0.15,
441
- 'aloof': -0.15,
442
- 'energetic': -0.12 # 從-0.06加重到-0.12
 
443
  }
444
 
445
- # 新手友善特徵的獎勵略微減少,避免過度補償
446
  easy_traits = {
447
- 'gentle': 0.06,
448
- 'friendly': 0.06,
449
- 'eager to please': 0.06,
450
- 'patient': 0.04,
451
- 'adaptable': 0.04,
452
- 'calm': 0.04
453
  }
454
 
455
- # 新手的特徵懲罰不再乘以1.2,而是直接使用更重的懲罰值
456
  for trait, penalty in difficult_traits.items():
457
  if trait in temperament_lower:
458
  temperament_adjustments += penalty
@@ -461,19 +824,23 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
461
  if trait in temperament_lower:
462
  temperament_adjustments += bonus
463
 
464
- # 特定品種類型的懲罰加重
465
- if any(term in temperament_lower for term in ['terrier', 'working', 'guard']):
466
- temperament_adjustments -= 0.20
 
 
 
 
467
 
468
  elif user_experience == "intermediate":
469
- # 中級玩家的調整更加平衡
470
  moderate_traits = {
471
- 'intelligent': 0.05, # 獎勵聰明
472
- 'athletic': 0.04, # 獎勵運動能力
473
- 'versatile': 0.04, # 獎勵多功能性
474
- 'stubborn': -0.06, # 輕微懲罰固執
475
- 'independent': -0.05, # 輕微懲罰獨立性
476
- 'protective': -0.04 # 輕微懲罰保護性
477
  }
478
 
479
  for trait, adjustment in moderate_traits.items():
@@ -483,140 +850,447 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
483
  else: # advanced
484
  # 資深玩家能夠應對挑戰性特徵
485
  advanced_traits = {
486
- 'stubborn': 0.04, # 反轉為優勢
487
- 'independent': 0.04, # 反轉為優勢
488
- 'intelligent': 0.05, # 獎勵聰明
489
- 'protective': 0.04, # 獎勵保護性
490
- 'strong-willed': 0.03 # 獎勵強勢
491
  }
492
 
493
  for trait, bonus in advanced_traits.items():
494
  if trait in temperament_lower:
495
  temperament_adjustments += bonus
496
 
497
- # 確保最終分數在合理範圍內
498
- final_score = max(0.2, min(1.0, score + temperament_adjustments))
 
499
  return final_score
500
 
501
 
502
- def calculate_health_score(breed_name: str) -> float:
503
- """計算品種健康分數"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  if breed_name not in breed_health_info:
505
  return 0.5
506
-
507
  health_notes = breed_health_info[breed_name]['health_notes'].lower()
508
 
509
- # 嚴重健康問題(降低0.15分)
510
- severe_conditions = [
511
- 'hip dysplasia',
512
- 'heart disease',
513
- 'progressive retinal atrophy',
514
- 'bloat',
515
- 'epilepsy',
516
- 'degenerative myelopathy',
517
- 'von willebrand disease'
518
- ]
519
-
520
- # 中度健康問題(降低0.1分)
521
- moderate_conditions = [
522
- 'allergies',
523
- 'eye problems',
524
- 'joint problems',
525
- 'hypothyroidism',
526
- 'ear infections',
527
- 'skin issues'
528
- ]
529
-
530
- # 輕微健康問題(降低0.05分)
531
- minor_conditions = [
532
- 'dental issues',
533
- 'weight gain tendency',
534
- 'minor allergies',
535
- 'seasonal allergies'
536
- ]
537
-
538
  # 計算基礎健康分數
539
  health_score = 1.0
540
 
541
- # 根據問題嚴重程度扣分
542
- severe_count = sum(1 for condition in severe_conditions if condition in health_notes)
543
- moderate_count = sum(1 for condition in moderate_conditions if condition in health_notes)
544
- minor_count = sum(1 for condition in minor_conditions if condition in health_notes)
 
 
545
 
546
- health_score -= (severe_count * 0.15)
547
- health_score -= (moderate_count * 0.1)
548
- health_score -= (minor_count * 0.05)
549
-
550
- # 壽命影響
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  try:
552
  lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
553
  years = float(lifespan.split('-')[0])
554
  if years < 8:
555
- health_score *= 0.9
 
 
556
  elif years > 13:
557
- health_score *= 1.1
558
  except:
559
  pass
560
-
561
  # 特殊健康優勢
562
  if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
 
 
563
  health_score *= 1.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
 
565
- return max(0.2, min(1.0, health_score))
 
 
566
 
567
- def calculate_noise_score(breed_name: str, user_noise_tolerance: str) -> float:
568
- """計算品種噪音分數"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  if breed_name not in breed_noise_info:
570
  return 0.5
571
-
572
  noise_info = breed_noise_info[breed_name]
573
  noise_level = noise_info['noise_level'].lower()
574
  noise_notes = noise_info['noise_notes'].lower()
575
-
576
- # 基礎噪音分數矩陣
577
  base_scores = {
578
- 'low': {'low': 1.0, 'medium': 0.9, 'high': 0.8},
579
- 'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.9},
580
- 'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0},
581
- 'varies': {'low': 0.6, 'medium': 0.8, 'high': 0.9}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  }
583
-
584
- # 獲取基礎分數
585
- base_score = base_scores.get(noise_level, {'low': 0.7, 'medium': 0.8, 'high': 0.6})[user_noise_tolerance]
586
-
587
- # 吠叫原因評估
588
- barking_reasons_penalty = 0
589
- problematic_triggers = [
590
- ('separation anxiety', -0.15),
591
- ('excessive barking', -0.12),
592
- ('territorial', -0.08),
593
- ('alert barking', -0.05),
594
- ('attention seeking', -0.05)
595
- ]
596
-
597
- for trigger, penalty in problematic_triggers:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
598
  if trigger in noise_notes:
599
- barking_reasons_penalty += penalty
600
-
601
- # 可訓練性補償
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  trainability_bonus = 0
603
  if 'responds well to training' in noise_notes:
604
- trainability_bonus = 0.1
605
  elif 'can be trained' in noise_notes:
606
- trainability_bonus = 0.05
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
 
608
- # 特殊情況
609
- special_adjustments = 0
610
- if 'rarely barks' in noise_notes:
611
- special_adjustments += 0.1
612
- if 'howls' in noise_notes and user_noise_tolerance == 'low':
613
- special_adjustments -= 0.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
 
615
- final_score = base_score + barking_reasons_penalty + trainability_bonus + special_adjustments
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
 
617
- return max(0.2, min(1.0, final_score))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
 
619
- # 計算所有基礎分數
620
  scores = {
621
  'space': calculate_space_score(
622
  breed_info['Size'],
@@ -642,9 +1316,8 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
642
  'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance)
643
  }
644
 
645
-
646
- # 優化權重配置
647
- weights = {
648
  'space': 0.28,
649
  'exercise': 0.18,
650
  'grooming': 0.12,
@@ -653,40 +1326,75 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
653
  'noise': 0.08
654
  }
655
 
656
- # 計算加權總分
657
- weighted_score = sum(score * weights[category] for category, score in scores.items())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
658
 
 
 
 
 
659
  def amplify_score(score):
660
  """
661
- 優化分數放大函數,確保分數範圍合理且結果一致
 
 
 
 
 
662
  """
663
- # 基礎調整
664
- adjusted = (score - 0.35) * 1.8
665
 
666
- # 使用 3.2 次方使曲線更平滑
667
- amplified = pow(adjusted, 3.2) / 5.8 + score
668
 
669
- # 特別處理高分區間,確保不超過95%
670
- if amplified > 0.90:
671
- # 壓縮高分區間,確保最高到95%
672
- amplified = 0.90 + (amplified - 0.90) * 0.5
 
673
 
674
- # 確保最終分數在合理範圍內(0.55-0.95
675
- final_score = max(0.55, min(0.95, amplified))
676
 
677
  # 四捨五入到小數點後第三位
678
  return round(final_score, 3)
679
-
 
680
  final_score = amplify_score(weighted_score)
 
 
 
 
 
 
681
 
682
- # 四捨五入所有分數
683
  scores = {k: round(v, 4) for k, v in scores.items()}
684
  scores['overall'] = round(final_score, 4)
685
-
686
  return scores
687
 
688
  except Exception as e:
689
  print(f"Error details: {str(e)}")
690
  print(f"breed_info: {breed_info}")
691
- # print(f"Error in calculate_compatibility_score: {str(e)}")
692
  return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
 
29
  self.barking_acceptance = self.noise_tolerance
30
 
31
 
32
+ # @staticmethod
33
+ # def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float:
34
+ # """計算品種額外加分"""
35
+ # bonus = 0.0
36
+ # temperament = breed_info.get('Temperament', '').lower()
37
+
38
+ # # 1. 壽命加分(最高0.05)
39
+ # try:
40
+ # lifespan = breed_info.get('Lifespan', '10-12 years')
41
+ # years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
42
+ # longevity_bonus = min(0.05, (max(years) - 10) * 0.01)
43
+ # bonus += longevity_bonus
44
+ # except:
45
+ # pass
46
+
47
+ # # 2. 性格特徵加分(最高0.15)
48
+ # positive_traits = {
49
+ # 'friendly': 0.05,
50
+ # 'gentle': 0.05,
51
+ # 'patient': 0.05,
52
+ # 'intelligent': 0.04,
53
+ # 'adaptable': 0.04,
54
+ # 'affectionate': 0.04,
55
+ # 'easy-going': 0.03,
56
+ # 'calm': 0.03
57
+ # }
58
+
59
+ # negative_traits = {
60
+ # 'aggressive': -0.08,
61
+ # 'stubborn': -0.06,
62
+ # 'dominant': -0.06,
63
+ # 'aloof': -0.04,
64
+ # 'nervous': -0.05,
65
+ # 'protective': -0.04
66
+ # }
67
+
68
+ # personality_score = sum(value for trait, value in positive_traits.items() if trait in temperament)
69
+ # personality_score += sum(value for trait, value in negative_traits.items() if trait in temperament)
70
+ # bonus += max(-0.15, min(0.15, personality_score))
71
+
72
+ # # 3. 適應性加分(最高0.1)
73
+ # adaptability_bonus = 0.0
74
+ # if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
75
+ # adaptability_bonus += 0.05
76
+ # if 'adaptable' in temperament or 'versatile' in temperament:
77
+ # adaptability_bonus += 0.05
78
+ # bonus += min(0.1, adaptability_bonus)
79
+
80
+ # # 4. 家庭相容性(最高0.1)
81
+ # if user_prefs.has_children:
82
+ # family_traits = {
83
+ # 'good with children': 0.06,
84
+ # 'patient': 0.05,
85
+ # 'gentle': 0.05,
86
+ # 'tolerant': 0.04,
87
+ # 'playful': 0.03
88
+ # }
89
+ # unfriendly_traits = {
90
+ # 'aggressive': -0.08,
91
+ # 'nervous': -0.07,
92
+ # 'protective': -0.06,
93
+ # 'territorial': -0.05
94
+ # }
95
+
96
+ # # 年齡評估這樣能更細緻
97
+ # age_adjustments = {
98
+ # 'toddler': {'bonus_mult': 0.7, 'penalty_mult': 1.3},
99
+ # 'school_age': {'bonus_mult': 1.0, 'penalty_mult': 1.0},
100
+ # 'teenager': {'bonus_mult': 1.2, 'penalty_mult': 0.8}
101
+ # }
102
+
103
+ # adj = age_adjustments.get(user_prefs.children_age,
104
+ # {'bonus_mult': 1.0, 'penalty_mult': 1.0})
105
+
106
+ # family_bonus = sum(value for trait, value in family_traits.items()
107
+ # if trait in temperament) * adj['bonus_mult']
108
+ # family_penalty = sum(value for trait, value in unfriendly_traits.items()
109
+ # if trait in temperament) * adj['penalty_mult']
110
+
111
+ # bonus += min(0.15, max(-0.2, family_bonus + family_penalty))
112
+
113
+
114
+ # # 5. 專門技能加分(最高0.1)
115
+ # skill_bonus = 0.0
116
+ # special_abilities = {
117
+ # 'working': 0.03,
118
+ # 'herding': 0.03,
119
+ # 'hunting': 0.03,
120
+ # 'tracking': 0.03,
121
+ # 'agility': 0.02
122
+ # }
123
+ # for ability, value in special_abilities.items():
124
+ # if ability in temperament.lower():
125
+ # skill_bonus += value
126
+ # bonus += min(0.1, skill_bonus)
127
+
128
+ # return min(0.5, max(-0.25, bonus))
129
+
130
+
131
  @staticmethod
132
+ def calculate_breed_bonus(breed_info: dict, user_prefs: UserPreferences) -> float:
133
+ """
134
+ 計算品種的額外加分,評估品種的特殊特徵對使用者需求的適配性。
135
+
136
+ 這個函數考慮四個主要面向:
137
+ 1. 壽命評估:考慮飼養的長期承諾
138
+ 2. 性格特徵評估:評估品種性格與使用者需求的匹配度
139
+ 3. 環境適應性:評估品種在特定生活環境中的表現
140
+ 4. 家庭相容性:特別關注品種與家庭成員的互動
141
+ """
142
  bonus = 0.0
143
  temperament = breed_info.get('Temperament', '').lower()
144
 
145
+ # 壽命評估 - 重新設計以反映更實際的考量
146
  try:
147
  lifespan = breed_info.get('Lifespan', '10-12 years')
148
  years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
149
+ avg_years = float(years[0])
150
+
151
+ # 根據壽命長短給予不同程度的獎勵或懲罰
152
+ if avg_years < 8:
153
+ bonus -= 0.08 # 短壽命可能帶來情感負擔
154
+ elif avg_years < 10:
155
+ bonus -= 0.04 # 稍短壽命輕微降低評分
156
+ elif avg_years > 13:
157
+ bonus += 0.06 # 長壽命適度加分
158
+ elif avg_years > 15:
159
+ bonus += 0.08 # 特別長壽的品種獲得更多加分
160
  except:
161
  pass
162
 
163
+ # 性格特徵評估 - 擴充並細化評分標準
164
  positive_traits = {
165
+ 'friendly': 0.08, # 提高友善性的重要性
166
+ 'gentle': 0.08, # 溫和性格更受歡迎
167
+ 'patient': 0.07, # 耐心是重要特質
168
+ 'intelligent': 0.06, # 聰明但不過分重要
169
+ 'adaptable': 0.06, # 適應性佳的特質
170
+ 'affectionate': 0.06, # 親密性很重要
171
+ 'easy-going': 0.05, # 容易相處的性格
172
+ 'calm': 0.05 # 冷靜的特質
173
  }
174
 
175
  negative_traits = {
176
+ 'aggressive': -0.15, # 嚴重懲罰攻擊性
177
+ 'stubborn': -0.10, # 固執性格不易處理
178
+ 'dominant': -0.10, # 支配性可能造成問題
179
+ 'aloof': -0.08, # 冷漠性格影響互動
180
+ 'nervous': -0.08, # 緊張性格需要更多關注
181
+ 'protective': -0.06 # 過度保護可能有風險
182
  }
183
 
184
+ # 性格評分計算 - 加入累積效應
185
+ personality_score = 0
186
+ positive_count = 0
187
+ negative_count = 0
188
+
189
+ for trait, value in positive_traits.items():
190
+ if trait in temperament:
191
+ personality_score += value
192
+ positive_count += 1
193
+
194
+ for trait, value in negative_traits.items():
195
+ if trait in temperament:
196
+ personality_score += value
197
+ negative_count += 1
198
+
199
+ # 多重特徵的累積效應
200
+ if positive_count > 2:
201
+ personality_score *= (1 + (positive_count - 2) * 0.1)
202
+ if negative_count > 1:
203
+ personality_score *= (1 - (negative_count - 1) * 0.15)
204
+
205
+ bonus += max(-0.25, min(0.25, personality_score))
206
 
207
+ # 適應性評估 - 根據具體環境給予更細緻的評分
208
  adaptability_bonus = 0.0
209
  if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
210
+ adaptability_bonus += 0.08 # 小型犬更適合公寓
211
+
212
+ # 環境適應性評估
213
  if 'adaptable' in temperament or 'versatile' in temperament:
214
+ if user_prefs.living_space == "apartment":
215
+ adaptability_bonus += 0.10 # 適應性在公寓環境更重要
216
+ else:
217
+ adaptability_bonus += 0.05 # 其他環境仍有加分
218
+
219
+ # 氣候適應性
220
+ description = breed_info.get('Description', '').lower()
221
+ climate = user_prefs.climate
222
+ if climate == 'hot':
223
+ if 'heat tolerant' in description or 'warm climate' in description:
224
+ adaptability_bonus += 0.08
225
+ elif 'thick coat' in description or 'cold climate' in description:
226
+ adaptability_bonus -= 0.10
227
+ elif climate == 'cold':
228
+ if 'thick coat' in description or 'cold climate' in description:
229
+ adaptability_bonus += 0.08
230
+ elif 'heat tolerant' in description or 'short coat' in description:
231
+ adaptability_bonus -= 0.10
232
+
233
+ bonus += min(0.15, adaptability_bonus)
234
 
235
+ # 家庭相容性評估 - 特別關注有孩童的家庭
236
  if user_prefs.has_children:
237
  family_traits = {
238
+ 'good with children': 0.12, # 提高與孩童相處的重要性
239
+ 'patient': 0.10,
240
+ 'gentle': 0.10,
241
+ 'tolerant': 0.08,
242
+ 'playful': 0.06
243
  }
244
+
245
  unfriendly_traits = {
246
+ 'aggressive': -0.15, # 加重攻擊性的懲罰
247
+ 'nervous': -0.12, # 緊張特質可能有風險
248
+ 'protective': -0.10, # 過度保護性需要注意
249
+ 'territorial': -0.08 # 地域性可能造成問題
250
  }
251
 
252
+ # 根據孩童年齡調整評分權重
253
  age_adjustments = {
254
+ 'toddler': {
255
+ 'bonus_mult': 0.6, # 降低正面特質的獎勵
256
+ 'penalty_mult': 1.5 # 加重負面特質的懲罰
257
+ },
258
+ 'school_age': {
259
+ 'bonus_mult': 1.0,
260
+ 'penalty_mult': 1.0
261
+ },
262
+ 'teenager': {
263
+ 'bonus_mult': 1.2, # 提高正面特質的獎勵
264
+ 'penalty_mult': 0.8 # 降低負面特質的懲罰
265
+ }
266
  }
267
 
268
  adj = age_adjustments.get(user_prefs.children_age,
269
  {'bonus_mult': 1.0, 'penalty_mult': 1.0})
270
 
271
+ # 計算家庭相容性分數
272
+ family_score = 0
273
+ for trait, value in family_traits.items():
274
+ if trait in temperament:
275
+ family_score += value * adj['bonus_mult']
276
+
277
+ for trait, value in unfriendly_traits.items():
278
+ if trait in temperament:
279
+ family_score += value * adj['penalty_mult']
280
 
281
+ bonus += min(0.20, max(-0.30, family_score))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
+ # 確保總體加分在合理範圍內,但允許更大的變化
284
+ return min(0.5, max(-0.35, bonus))
285
 
286
 
287
  @staticmethod
 
372
  print("Missing Size information")
373
  raise KeyError("Size information missing")
374
 
375
+ # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
376
+ # """空間分數計算"""
377
+ # # 基礎空間需求矩陣
378
+ # base_scores = {
379
+ # "Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90},
380
+ # "Medium": {"apartment": 0.60, "house_small": 0.90, "house_large": 1.0},
381
+ # "Large": {"apartment": 0.30, "house_small": 0.75, "house_large": 1.0},
382
+ # "Giant": {"apartment": 0.15, "house_small": 0.55, "house_large": 1.0}
383
+ # }
384
+
385
+ # # 取得基礎分數
386
+ # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
387
+
388
+ # # 運動需求調整
389
+ # exercise_adjustments = {
390
+ # "Very High": -0.15 if living_space == "apartment" else 0,
391
+ # "High": -0.10 if living_space == "apartment" else 0,
392
+ # "Moderate": 0,
393
+ # "Low": 0.05 if living_space == "apartment" else 0
394
+ # }
395
+
396
+ # adjustments = exercise_adjustments.get(exercise_needs.strip(), 0)
397
+
398
+ # # 院子獎勵
399
+ # if has_yard and size in ["Large", "Giant"]:
400
+ # adjustments += 0.10
401
+ # elif has_yard:
402
+ # adjustments += 0.05
403
+
404
+ # return min(1.0, max(0.1, base_score + adjustments))
405
+
406
  def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
407
+ # 重新設計基礎分數矩陣
 
408
  base_scores = {
409
+ "Small": {
410
+ "apartment": 1.0, # 小型犬最適合公寓
411
+ "house_small": 0.95, # 在大房子反而稍微降分
412
+ "house_large": 0.85 # 可能浪費空間
413
+ },
414
+ "Medium": {
415
+ "apartment": 0.45, # 中���犬在公寓明顯受限
416
+ "house_small": 0.85,
417
+ "house_large": 1.0
418
+ },
419
+ "Large": {
420
+ "apartment": 0.15, # 大型犬在公寓極不適合
421
+ "house_small": 0.60, # 在小房子仍然受限
422
+ "house_large": 1.0
423
+ },
424
+ "Giant": {
425
+ "apartment": 0.1, # 更嚴格的限制
426
+ "house_small": 0.45,
427
+ "house_large": 1.0
428
+ }
429
  }
430
 
431
  # 取得基礎分數
432
  base_score = base_scores.get(size, base_scores["Medium"])[living_space]
433
 
434
+ # 運動需求調整更明顯
435
  exercise_adjustments = {
436
+ "Very High": {
437
+ "apartment": -0.25, # 在公寓更嚴重的懲罰
438
+ "house_small": -0.15,
439
+ "house_large": -0.05
440
+ },
441
+ "High": {
442
+ "apartment": -0.20,
443
+ "house_small": -0.10,
444
+ "house_large": 0
445
+ },
446
+ "Moderate": {
447
+ "apartment": -0.10,
448
+ "house_small": -0.05,
449
+ "house_large": 0
450
+ },
451
+ "Low": {
452
+ "apartment": 0.05,
453
+ "house_small": 0,
454
+ "house_large": 0
455
+ }
456
  }
457
 
458
+ # 根據空間類型獲取對應的運動調整
459
+ adjustment = exercise_adjustments.get(exercise_needs,
460
+ exercise_adjustments["Moderate"])[living_space]
461
 
462
+ # 院子獎勵也要根據犬種大小調整
463
+ yard_bonus = 0
464
+ if has_yard:
465
+ if size in ["Large", "Giant"]:
466
+ yard_bonus = 0.20 if living_space != "apartment" else 0.10
467
+ elif size == "Medium":
468
+ yard_bonus = 0.15 if living_space != "apartment" else 0.08
469
+ else:
470
+ yard_bonus = 0.10 if living_space != "apartment" else 0.05
471
+
472
+ final_score = base_score + adjustment + yard_bonus
473
+ return min(1.0, max(0.1, final_score))
474
 
475
  def calculate_exercise_score(breed_needs: str, user_time: int) -> float:
476
  """運動需求計算"""
 
494
  else:
495
  return max(0.3, 0.8 * (user_time / breed_need['min']))
496
 
497
+ # def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
498
+ # """美容需求計算"""
499
+ # # 基礎分數矩陣
500
+ # base_scores = {
501
+ # "High": {"low": 0.3, "medium": 0.7, "high": 1.0},
502
+ # "Moderate": {"low": 0.5, "medium": 0.9, "high": 1.0},
503
+ # "Low": {"low": 1.0, "medium": 0.95, "high": 0.8}
504
+ # }
505
+
506
+ # # 取得基礎分數
507
+ # base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
508
+
509
+ # # 體型影響調整
510
+ # size_adjustments = {
511
+ # "Large": {"low": -0.2, "medium": -0.1, "high": 0},
512
+ # "Giant": {"low": -0.3, "medium": -0.15, "high": 0},
513
+ # }
514
+
515
+ # if breed_size in size_adjustments:
516
+ # adjustment = size_adjustments[breed_size].get(user_commitment, 0)
517
+ # base_score = max(0.2, base_score + adjustment)
518
+
519
+ # return base_score
520
+
521
+
522
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
523
+ """
524
+ 計算美容需求分數,強化美容維護需求與使用者承諾度的匹配評估。
525
+ 這個函數特別注意品種大小對美容工作的影響,以及不同程度的美容需求對時間投入的要求。
526
+ """
527
+ # 重新設計基礎分數矩陣,讓美容需求的差異更加明顯
528
  base_scores = {
529
+ "High": {
530
+ "low": 0.20, # 高需求對低承諾極不合適,顯著降低初始分數
531
+ "medium": 0.65, # 中等承諾仍有挑戰
532
+ "high": 1.0 # 高承諾最適合
533
+ },
534
+ "Moderate": {
535
+ "low": 0.45, # 中等需求對低承諾有困難
536
+ "medium": 0.85, # 較好的匹配
537
+ "high": 0.95 # 高承諾會有餘力
538
+ },
539
+ "Low": {
540
+ "low": 0.90, # 低需求對低承諾很合適
541
+ "medium": 0.85, # 略微降低以反映可能過度投入
542
+ "high": 0.80 # 可能造成資源浪費
543
+ }
544
  }
545
+
546
  # 取得基礎分數
547
  base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
548
+
549
+ # 根據品種大小調整美容工作量
550
  size_adjustments = {
551
+ "Giant": {
552
+ "low": -0.35, # 大型犬的美容工作量顯著增加
553
+ "medium": -0.20,
554
+ "high": -0.10
555
+ },
556
+ "Large": {
557
+ "low": -0.25,
558
+ "medium": -0.15,
559
+ "high": -0.05
560
+ },
561
+ "Medium": {
562
+ "low": -0.15,
563
+ "medium": -0.10,
564
+ "high": 0
565
+ },
566
+ "Small": {
567
+ "low": -0.10,
568
+ "medium": -0.05,
569
+ "high": 0
570
+ }
571
  }
572
+
573
+ # 應用體型調整
574
+ size_adjustment = size_adjustments.get(breed_size, size_adjustments["Medium"])[user_commitment]
575
+ current_score = base_score + size_adjustment
576
+
577
+ # 特殊毛髮類型的額外調整
578
+ def get_coat_adjustment(breed_description: str, commitment: str) -> float:
579
+ """
580
+ 評估特殊毛髮類型所需的額外維護工作
581
+ """
582
+ adjustments = 0
583
 
584
+ # 長毛品種需要更多維護
585
+ if 'long coat' in breed_description.lower():
586
+ coat_penalties = {
587
+ 'low': -0.20,
588
+ 'medium': -0.15,
589
+ 'high': -0.05
590
+ }
591
+ adjustments += coat_penalties[commitment]
592
+
593
+ # 雙層毛的品種掉毛量更大
594
+ if 'double coat' in breed_description.lower():
595
+ double_coat_penalties = {
596
+ 'low': -0.15,
597
+ 'medium': -0.10,
598
+ 'high': -0.05
599
+ }
600
+ adjustments += double_coat_penalties[commitment]
601
+
602
+ # 捲毛品種需要定期專業修剪
603
+ if 'curly' in breed_description.lower():
604
+ curly_penalties = {
605
+ 'low': -0.15,
606
+ 'medium': -0.10,
607
+ 'high': -0.05
608
+ }
609
+ adjustments += curly_penalties[commitment]
610
+
611
+ return adjustments
612
+
613
+ # 季節性考量
614
+ def get_seasonal_adjustment(breed_description: str, commitment: str) -> float:
615
+ """
616
+ 評估季節性掉毛對美容需求的影響
617
+ """
618
+ if 'seasonal shedding' in breed_description.lower():
619
+ seasonal_penalties = {
620
+ 'low': -0.15,
621
+ 'medium': -0.10,
622
+ 'high': -0.05
623
+ }
624
+ return seasonal_penalties[commitment]
625
+ return 0
626
+
627
+ # 專業美容需求評估
628
+ def get_professional_grooming_adjustment(breed_description: str, commitment: str) -> float:
629
+ """
630
+ 評估需要專業美容服務的影響
631
+ """
632
+ if 'professional grooming' in breed_description.lower():
633
+ grooming_penalties = {
634
+ 'low': -0.20,
635
+ 'medium': -0.15,
636
+ 'high': -0.05
637
+ }
638
+ return grooming_penalties[commitment]
639
+ return 0
640
+
641
+ # 應用所有額外調整
642
+ # 由於這些是示例調整,實際使用時需要根據品種描述信息進行調整
643
+ coat_adjustment = get_coat_adjustment("", user_commitment)
644
+ seasonal_adjustment = get_seasonal_adjustment("", user_commitment)
645
+ professional_adjustment = get_professional_grooming_adjustment("", user_commitment)
646
+
647
+ final_score = current_score + coat_adjustment + seasonal_adjustment + professional_adjustment
648
+
649
+ # 確保分數在有意義的範圍內,但允許更大的差異
650
+ return max(0.1, min(1.0, final_score))
651
 
652
 
653
  # def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
 
759
 
760
  def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
761
  """
762
+ 計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
763
+
764
+ 重要改進:
765
+ 1. 擴大基礎分數差異
766
+ 2. 加重困難特徵的懲罰
767
+ 3. 更細緻的品種特性評估
768
  """
769
+ # 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
770
  base_scores = {
771
  "High": {
772
+ "beginner": 0.10, # 降低起始分,高難度品種對新手幾乎不推薦
773
+ "intermediate": 0.60, # 中級玩家仍需謹慎
774
+ "advanced": 1.0 # 資深者能完全勝任
775
  },
776
  "Moderate": {
777
+ "beginner": 0.35, # 適中難度對新手仍具挑戰
778
+ "intermediate": 0.80, # 中級玩家較適合
779
+ "advanced": 1.0 # 資深者完全勝任
780
  },
781
  "Low": {
782
+ "beginner": 0.90, # 新手友善品種
783
+ "intermediate": 0.95, # 中級玩家幾乎完全勝任
784
+ "advanced": 1.0 # 資深者完全勝任
785
  }
786
  }
787
 
 
791
  temperament_lower = temperament.lower()
792
  temperament_adjustments = 0.0
793
 
794
+ # 根據經驗等級設定不同的特徵評估標準
795
  if user_experience == "beginner":
796
+ # 新手不適合的特徵 - 更嚴格的懲罰
797
  difficult_traits = {
798
+ 'stubborn': -0.30, # 固執性格嚴重影響新手
799
+ 'independent': -0.25, # 獨立性高的品種不適合新手
800
+ 'dominant': -0.25, # 支配性強的品種需要經驗處理
801
+ 'strong-willed': -0.20, # 強勢性格需要技巧管理
802
+ 'protective': -0.20, # 保護性強需要適當訓練
803
+ 'aloof': -0.15, # 冷漠性格需要耐心培養
804
+ 'energetic': -0.15, # 活潑好動需要經驗引導
805
+ 'aggressive': -0.35 # 攻擊傾向極不適合新手
806
  }
807
 
808
+ # 新手友善的特徵 - 適度的獎勵
809
  easy_traits = {
810
+ 'gentle': 0.05, # 溫和性格適合新手
811
+ 'friendly': 0.05, # 友善性格��易相處
812
+ 'eager to please': 0.08, # 願意服從較容易訓練
813
+ 'patient': 0.05, # 耐心的特質有助於建立關係
814
+ 'adaptable': 0.05, # 適應性強較容易照顧
815
+ 'calm': 0.06 # 冷靜的性格較好掌握
816
  }
817
 
818
+ # 計算特徵調整
819
  for trait, penalty in difficult_traits.items():
820
  if trait in temperament_lower:
821
  temperament_adjustments += penalty
 
824
  if trait in temperament_lower:
825
  temperament_adjustments += bonus
826
 
827
+ # 品種類型特殊評估
828
+ if 'terrier' in temperament_lower:
829
+ temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
830
+ elif 'working' in temperament_lower:
831
+ temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
832
+ elif 'guard' in temperament_lower:
833
+ temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
834
 
835
  elif user_experience == "intermediate":
836
+ # 中級玩家的特徵評估
837
  moderate_traits = {
838
+ 'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
839
+ 'independent': -0.10,
840
+ 'intelligent': 0.08, # 聰明的特質可以好好發揮
841
+ 'athletic': 0.06, # 運動能力可以適當訓練
842
+ 'versatile': 0.07, # 多功能性可以開發
843
+ 'protective': -0.08 # 保護性仍需注意
844
  }
845
 
846
  for trait, adjustment in moderate_traits.items():
 
850
  else: # advanced
851
  # 資深玩家能夠應對挑戰性特徵
852
  advanced_traits = {
853
+ 'stubborn': 0.05, # 困難特徵反而成為優勢
854
+ 'independent': 0.05,
855
+ 'intelligent': 0.10,
856
+ 'protective': 0.05,
857
+ 'strong-willed': 0.05
858
  }
859
 
860
  for trait, bonus in advanced_traits.items():
861
  if trait in temperament_lower:
862
  temperament_adjustments += bonus
863
 
864
+ # 確保最終分數範圍更大,讓差異更明顯
865
+ final_score = max(0.05, min(1.0, score + temperament_adjustments))
866
+
867
  return final_score
868
 
869
 
870
+ # def calculate_health_score(breed_name: str) -> float:
871
+ # """計算品種健康分數"""
872
+ # if breed_name not in breed_health_info:
873
+ # return 0.5
874
+
875
+ # health_notes = breed_health_info[breed_name]['health_notes'].lower()
876
+
877
+ # # 嚴重健康問題(降低0.15分)
878
+ # severe_conditions = [
879
+ # 'hip dysplasia',
880
+ # 'heart disease',
881
+ # 'progressive retinal atrophy',
882
+ # 'bloat',
883
+ # 'epilepsy',
884
+ # 'degenerative myelopathy',
885
+ # 'von willebrand disease'
886
+ # ]
887
+
888
+ # # 中度健康問題(降低0.1分)
889
+ # moderate_conditions = [
890
+ # 'allergies',
891
+ # 'eye problems',
892
+ # 'joint problems',
893
+ # 'hypothyroidism',
894
+ # 'ear infections',
895
+ # 'skin issues'
896
+ # ]
897
+
898
+ # # 輕微健康問題(降低0.05分)
899
+ # minor_conditions = [
900
+ # 'dental issues',
901
+ # 'weight gain tendency',
902
+ # 'minor allergies',
903
+ # 'seasonal allergies'
904
+ # ]
905
+
906
+ # # 計算基礎健康分數
907
+ # health_score = 1.0
908
+
909
+ # # 根據問題嚴重程度扣分
910
+ # severe_count = sum(1 for condition in severe_conditions if condition in health_notes)
911
+ # moderate_count = sum(1 for condition in moderate_conditions if condition in health_notes)
912
+ # minor_count = sum(1 for condition in minor_conditions if condition in health_notes)
913
+
914
+ # health_score -= (severe_count * 0.15)
915
+ # health_score -= (moderate_count * 0.1)
916
+ # health_score -= (minor_count * 0.05)
917
+
918
+ # # 壽命影響
919
+ # try:
920
+ # lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
921
+ # years = float(lifespan.split('-')[0])
922
+ # if years < 8:
923
+ # health_score *= 0.9
924
+ # elif years > 13:
925
+ # health_score *= 1.1
926
+ # except:
927
+ # pass
928
+
929
+ # # 特殊健康優勢
930
+ # if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
931
+ # health_score *= 1.1
932
+
933
+ # return max(0.2, min(1.0, health_score))
934
+
935
+ def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
936
+ """
937
+ 計算品種健康分數,加強健康問題的影響力和與使用者敏感度的連結
938
+
939
+ 重要改進:
940
+ 1. 根據使用者的健康敏感度調整分數
941
+ 2. 更嚴格的健康問題評估
942
+ 3. 考慮多重健康問題的累積效應
943
+ 4. 加入遺傳疾病的特別考量
944
+ """
945
  if breed_name not in breed_health_info:
946
  return 0.5
947
+
948
  health_notes = breed_health_info[breed_name]['health_notes'].lower()
949
 
950
+ # 嚴重健康問題 - 加重扣分
951
+ severe_conditions = {
952
+ 'hip dysplasia': -0.25, # 髖關節發育不良,影響生活品質
953
+ 'heart disease': -0.25, # 心臟疾病,需要長期治療
954
+ 'progressive retinal atrophy': -0.20, # 進行性視網膜萎縮,導致失明
955
+ 'bloat': -0.22, # 胃扭轉,致命風險
956
+ 'epilepsy': -0.20, # 癲癇,需要長期藥物控制
957
+ 'degenerative myelopathy': -0.20, # 脊髓退化,影響行動能力
958
+ 'von willebrand disease': -0.18 # 血液凝固障礙
959
+ }
960
+
961
+ # 中度健康問題 - 適度扣分
962
+ moderate_conditions = {
963
+ 'allergies': -0.12, # 過敏問題,需要持續關注
964
+ 'eye problems': -0.15, # 眼睛問題,可能需要手術
965
+ 'joint problems': -0.15, # 關節問題,影響運動能力
966
+ 'hypothyroidism': -0.12, # 甲狀腺功能低下,需要藥物治療
967
+ 'ear infections': -0.10, # 耳道感染,需要定期清理
968
+ 'skin issues': -0.12 # 皮膚問題,需要特殊護理
969
+ }
970
+
971
+ # 輕微健康問題 - 輕微扣分
972
+ minor_conditions = {
973
+ 'dental issues': -0.08, # 牙齒問題,需要定期護理
974
+ 'weight gain tendency': -0.08, # 易胖體質,需要控制飲食
975
+ 'minor allergies': -0.06, # 輕微過敏,可控制
976
+ 'seasonal allergies': -0.06 # 季節性過敏
977
+ }
978
+
979
  # 計算基礎健康分數
980
  health_score = 1.0
981
 
982
+ # 健康問題累積效應計算
983
+ condition_counts = {
984
+ 'severe': 0,
985
+ 'moderate': 0,
986
+ 'minor': 0
987
+ }
988
 
989
+ # 計算各等級健康問題的數量和影響
990
+ for condition, penalty in severe_conditions.items():
991
+ if condition in health_notes:
992
+ health_score += penalty
993
+ condition_counts['severe'] += 1
994
+
995
+ for condition, penalty in moderate_conditions.items():
996
+ if condition in health_notes:
997
+ health_score += penalty
998
+ condition_counts['moderate'] += 1
999
+
1000
+ for condition, penalty in minor_conditions.items():
1001
+ if condition in health_notes:
1002
+ health_score += penalty
1003
+ condition_counts['minor'] += 1
1004
+
1005
+ # 多重問題的額外懲罰(累積效應)
1006
+ if condition_counts['severe'] > 1:
1007
+ health_score *= (0.85 ** (condition_counts['severe'] - 1))
1008
+ if condition_counts['moderate'] > 2:
1009
+ health_score *= (0.90 ** (condition_counts['moderate'] - 2))
1010
+
1011
+ # 根據使用者健康敏感度調整分數
1012
+ sensitivity_multipliers = {
1013
+ 'low': 1.1, # 較不在意健康問題
1014
+ 'medium': 1.0, # 標準評估
1015
+ 'high': 0.85 # 非常注重健康問題
1016
+ }
1017
+
1018
+ health_score *= sensitivity_multipliers.get(user_prefs.health_sensitivity, 1.0)
1019
+
1020
+ # 壽命影響評估
1021
  try:
1022
  lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
1023
  years = float(lifespan.split('-')[0])
1024
  if years < 8:
1025
+ health_score *= 0.85 # 短壽命顯著降低分數
1026
+ elif years < 10:
1027
+ health_score *= 0.92 # 較短壽命輕微降低分數
1028
  elif years > 13:
1029
+ health_score *= 1.1 # 長壽命適度加分
1030
  except:
1031
  pass
1032
+
1033
  # 特殊健康優勢
1034
  if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
1035
+ health_score *= 1.15
1036
+ elif 'robust health' in health_notes or 'few health issues' in health_notes:
1037
  health_score *= 1.1
1038
+
1039
+ # 確保分數在合理範圍內,但允許更大的分數差異
1040
+ return max(0.1, min(1.0, health_score))
1041
+
1042
+
1043
+ # def calculate_noise_score(breed_name: str, user_noise_tolerance: str) -> float:
1044
+ # """計算品種噪音分數"""
1045
+ # if breed_name not in breed_noise_info:
1046
+ # return 0.5
1047
+
1048
+ # noise_info = breed_noise_info[breed_name]
1049
+ # noise_level = noise_info['noise_level'].lower()
1050
+ # noise_notes = noise_info['noise_notes'].lower()
1051
+
1052
+ # # 基礎噪音分數矩陣
1053
+ # base_scores = {
1054
+ # 'low': {'low': 1.0, 'medium': 0.9, 'high': 0.8},
1055
+ # 'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.9},
1056
+ # 'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0},
1057
+ # 'varies': {'low': 0.6, 'medium': 0.8, 'high': 0.9}
1058
+ # }
1059
+
1060
+ # # 獲取基礎分數
1061
+ # base_score = base_scores.get(noise_level, {'low': 0.7, 'medium': 0.8, 'high': 0.6})[user_noise_tolerance]
1062
+
1063
+ # # 吠叫原因評估
1064
+ # barking_reasons_penalty = 0
1065
+ # problematic_triggers = [
1066
+ # ('separation anxiety', -0.15),
1067
+ # ('excessive barking', -0.12),
1068
+ # ('territorial', -0.08),
1069
+ # ('alert barking', -0.05),
1070
+ # ('attention seeking', -0.05)
1071
+ # ]
1072
 
1073
+ # for trigger, penalty in problematic_triggers:
1074
+ # if trigger in noise_notes:
1075
+ # barking_reasons_penalty += penalty
1076
 
1077
+ # # 可訓練性補償
1078
+ # trainability_bonus = 0
1079
+ # if 'responds well to training' in noise_notes:
1080
+ # trainability_bonus = 0.1
1081
+ # elif 'can be trained' in noise_notes:
1082
+ # trainability_bonus = 0.05
1083
+
1084
+ # # 特殊情況
1085
+ # special_adjustments = 0
1086
+ # if 'rarely barks' in noise_notes:
1087
+ # special_adjustments += 0.1
1088
+ # if 'howls' in noise_notes and user_noise_tolerance == 'low':
1089
+ # special_adjustments -= 0.1
1090
+
1091
+ # final_score = base_score + barking_reasons_penalty + trainability_bonus + special_adjustments
1092
+
1093
+ # return max(0.2, min(1.0, final_score))
1094
+
1095
+ def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
1096
+ """
1097
+ 計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
1098
+ """
1099
  if breed_name not in breed_noise_info:
1100
  return 0.5
1101
+
1102
  noise_info = breed_noise_info[breed_name]
1103
  noise_level = noise_info['noise_level'].lower()
1104
  noise_notes = noise_info['noise_notes'].lower()
1105
+
1106
+ # 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
1107
  base_scores = {
1108
+ 'low': {
1109
+ 'low': 1.0, # 安靜的狗對低容忍完美匹配
1110
+ 'medium': 0.95, # 安靜的狗對一般容忍很好
1111
+ 'high': 0.90 # 安靜的狗對高容忍當然可以
1112
+ },
1113
+ 'medium': {
1114
+ 'low': 0.60, # 一般吠叫對低容忍較困難
1115
+ 'medium': 0.90, # 一般吠叫對一般容忍可接受
1116
+ 'high': 0.95 # 一般吠叫對高容忍很好
1117
+ },
1118
+ 'high': {
1119
+ 'low': 0.25, # 愛叫的狗對低容忍極不適合
1120
+ 'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
1121
+ 'high': 0.90 # 愛叫的狗對高容忍可以接受
1122
+ },
1123
+ 'varies': {
1124
+ 'low': 0.50, # 不確定的情況對低容忍風險較大
1125
+ 'medium': 0.75, # 不確定的情況對一般容忍可嘗試
1126
+ 'high': 0.85 # 不確定的情況對高容忍問題較小
1127
+ }
1128
  }
1129
+
1130
+ # 取得基礎分數
1131
+ base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
1132
+
1133
+ # 吠叫原因評估,根據環境調整懲罰程度
1134
+ barking_penalties = {
1135
+ 'separation anxiety': {
1136
+ 'apartment': -0.30, # 在公寓對鄰居影響更大
1137
+ 'house_small': -0.25,
1138
+ 'house_large': -0.20
1139
+ },
1140
+ 'excessive barking': {
1141
+ 'apartment': -0.25,
1142
+ 'house_small': -0.20,
1143
+ 'house_large': -0.15
1144
+ },
1145
+ 'territorial': {
1146
+ 'apartment': -0.20, # 在公寓更容易被觸發
1147
+ 'house_small': -0.15,
1148
+ 'house_large': -0.10
1149
+ },
1150
+ 'alert barking': {
1151
+ 'apartment': -0.15, # 公寓環境刺激較多
1152
+ 'house_small': -0.10,
1153
+ 'house_large': -0.08
1154
+ },
1155
+ 'attention seeking': {
1156
+ 'apartment': -0.15,
1157
+ 'house_small': -0.12,
1158
+ 'house_large': -0.10
1159
+ }
1160
+ }
1161
+
1162
+ # 計算環境相關的吠叫懲罰
1163
+ living_space = user_prefs.living_space
1164
+ barking_penalty = 0
1165
+ for trigger, penalties in barking_penalties.items():
1166
  if trigger in noise_notes:
1167
+ barking_penalty += penalties.get(living_space, -0.15)
1168
+
1169
+ # 特殊情況評估
1170
+ special_adjustments = 0
1171
+ if user_prefs.has_children:
1172
+ # 孩童年齡相關調整
1173
+ child_age_adjustments = {
1174
+ 'toddler': {
1175
+ 'high': -0.20, # 幼童對吵鬧更敏感
1176
+ 'medium': -0.15,
1177
+ 'low': -0.05
1178
+ },
1179
+ 'school_age': {
1180
+ 'high': -0.15,
1181
+ 'medium': -0.10,
1182
+ 'low': -0.05
1183
+ },
1184
+ 'teenager': {
1185
+ 'high': -0.10,
1186
+ 'medium': -0.05,
1187
+ 'low': -0.02
1188
+ }
1189
+ }
1190
+
1191
+ # 根據孩童年齡和噪音等級調整
1192
+ age_adj = child_age_adjustments.get(user_prefs.children_age,
1193
+ child_age_adjustments['school_age'])
1194
+ special_adjustments += age_adj.get(noise_level, -0.10)
1195
+
1196
+ # 訓練性補償評估
1197
  trainability_bonus = 0
1198
  if 'responds well to training' in noise_notes:
1199
+ trainability_bonus = 0.12
1200
  elif 'can be trained' in noise_notes:
1201
+ trainability_bonus = 0.08
1202
+ elif 'difficult to train' in noise_notes:
1203
+ trainability_bonus = 0.02
1204
+
1205
+ # 夜間吠叫特別考量
1206
+ if 'night barking' in noise_notes or 'howls' in noise_notes:
1207
+ if user_prefs.living_space == 'apartment':
1208
+ special_adjustments -= 0.15
1209
+ elif user_prefs.living_space == 'house_small':
1210
+ special_adjustments -= 0.10
1211
+ else:
1212
+ special_adjustments -= 0.05
1213
+
1214
+ # 計算最終分數,確保更大的分數範圍
1215
+ final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1216
+ return max(0.1, min(1.0, final_score))
1217
+
1218
 
1219
+ # # 計算所有基礎分數
1220
+ # scores = {
1221
+ # 'space': calculate_space_score(
1222
+ # breed_info['Size'],
1223
+ # user_prefs.living_space,
1224
+ # user_prefs.space_for_play,
1225
+ # breed_info.get('Exercise Needs', 'Moderate')
1226
+ # ),
1227
+ # 'exercise': calculate_exercise_score(
1228
+ # breed_info.get('Exercise Needs', 'Moderate'),
1229
+ # user_prefs.exercise_time
1230
+ # ),
1231
+ # 'grooming': calculate_grooming_score(
1232
+ # breed_info.get('Grooming Needs', 'Moderate'),
1233
+ # user_prefs.grooming_commitment.lower(),
1234
+ # breed_info['Size']
1235
+ # ),
1236
+ # 'experience': calculate_experience_score(
1237
+ # breed_info.get('Care Level', 'Moderate'),
1238
+ # user_prefs.experience_level,
1239
+ # breed_info.get('Temperament', '')
1240
+ # ),
1241
+ # 'health': calculate_health_score(breed_info.get('Breed', '')),
1242
+ # 'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance)
1243
+ # }
1244
+
1245
+
1246
+ # # 優化權重配置
1247
+ # weights = {
1248
+ # 'space': 0.28,
1249
+ # 'exercise': 0.18,
1250
+ # 'grooming': 0.12,
1251
+ # 'experience': 0.22,
1252
+ # 'health': 0.12,
1253
+ # 'noise': 0.08
1254
+ # }
1255
 
1256
+ # # 計算加權總分
1257
+ # weighted_score = sum(score * weights[category] for category, score in scores.items())
1258
+
1259
+ # def amplify_score(score):
1260
+ # """
1261
+ # 優化分數放大函數,確保分數範圍合理且結果一致
1262
+ # """
1263
+ # # 基礎調整
1264
+ # adjusted = (score - 0.35) * 1.8
1265
+
1266
+ # # 使用 3.2 次方使曲線更平滑
1267
+ # amplified = pow(adjusted, 3.2) / 5.8 + score
1268
+
1269
+ # # 特別處理高分區間,確保不超過95%
1270
+ # if amplified > 0.90:
1271
+ # # 壓縮高分區間,確保最高到95%
1272
+ # amplified = 0.90 + (amplified - 0.90) * 0.5
1273
 
1274
+ # # 確保最終分數在合理範圍內(0.55-0.95)
1275
+ # final_score = max(0.55, min(0.95, amplified))
1276
+
1277
+ # # 四捨五入到小數點後第三位
1278
+ # return round(final_score, 3)
1279
+
1280
+ # final_score = amplify_score(weighted_score)
1281
+
1282
+ # # 四捨五入所有分數
1283
+ # scores = {k: round(v, 4) for k, v in scores.items()}
1284
+ # scores['overall'] = round(final_score, 4)
1285
+
1286
+ # return scores
1287
+
1288
+ # except Exception as e:
1289
+ # print(f"Error details: {str(e)}")
1290
+ # print(f"breed_info: {breed_info}")
1291
+ # # print(f"Error in calculate_compatibility_score: {str(e)}")
1292
+ # return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
1293
 
 
1294
  scores = {
1295
  'space': calculate_space_score(
1296
  breed_info['Size'],
 
1316
  'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance)
1317
  }
1318
 
1319
+ # 2. 優化權重配置 - 根據使用者情況動態調整權重
1320
+ base_weights = {
 
1321
  'space': 0.28,
1322
  'exercise': 0.18,
1323
  'grooming': 0.12,
 
1326
  'noise': 0.08
1327
  }
1328
 
1329
+ # 根據特殊情況調整權重
1330
+ weights = base_weights.copy()
1331
+
1332
+ # 有孩童時的權重調整
1333
+ if user_prefs.has_children:
1334
+ if user_prefs.children_age == 'toddler':
1335
+ weights['experience'] *= 1.4 # 幼童需要更有經驗的配對
1336
+ weights['noise'] *= 1.3 # 噪音影響更重要
1337
+ weights['health'] *= 1.2 # 健康因素更關鍵
1338
+ elif user_prefs.children_age == 'school_age':
1339
+ weights['experience'] *= 1.2
1340
+ weights['noise'] *= 1.2
1341
+
1342
+ # 居住環境的權重調整
1343
+ if user_prefs.living_space == 'apartment':
1344
+ weights['space'] *= 1.3 # 空間限制更重要
1345
+ weights['noise'] *= 1.2 # 噪音影響更顯著
1346
+
1347
+ # 重新正規化權重
1348
+ total_weight = sum(weights.values())
1349
+ weights = {k: v/total_weight for k, v in weights.items()}
1350
 
1351
+ # 3. 計算加權總分
1352
+ weighted_score = sum(score * weights[category] for category, score in scores.items())
1353
+
1354
+ # 4. 改進的分數放大函數
1355
  def amplify_score(score):
1356
  """
1357
+ 改進的分數放大函數,提供更大的分數差異。
1358
+
1359
+ 主要改進:
1360
+ 1. 調整基礎計算參數以產生更明顯的差異
1361
+ 2. 根據分數區間使用不同的放大策略
1362
+ 3. 擴大最終分數範圍
1363
  """
1364
+ # 基礎調整,擴大差異
1365
+ adjusted = (score - 0.4) * 2.0 # 從0.35調整到0.4,倍數從1.8提高到2.0
1366
 
1367
+ # 使用更陡峭的曲線,從3.2降到2.8使曲線不會過於極端
1368
+ amplified = pow(adjusted, 2.8) / 4.5 + score
1369
 
1370
+ # 分數區間處理
1371
+ if score < 0.65: # 低分區間
1372
+ amplified *= 0.85 # 進一步降低不適合的配對
1373
+ elif score > 0.85: # 高分區間
1374
+ amplified = 0.85 + (amplified - 0.85) * 0.4 # 高分區間的緩和壓縮
1375
 
1376
+ # 擴大分數範圍到0.45-0.95,原本是0.55-0.95
1377
+ final_score = max(0.45, min(0.95, amplified))
1378
 
1379
  # 四捨五入到小數點後第三位
1380
  return round(final_score, 3)
1381
+
1382
+ # 5. 計算最終分數並應用關鍵條件檢查
1383
  final_score = amplify_score(weighted_score)
1384
+
1385
+ # 針對特殊情況的最終調整
1386
+ if user_prefs.has_children and scores['experience'] < 0.4:
1387
+ final_score *= 0.8 # 有孩童但經驗分數過低時大幅降低
1388
+ if user_prefs.living_space == 'apartment' and scores['noise'] < 0.3:
1389
+ final_score *= 0.75 # 住公寓但噪音分數極低時顯著降低
1390
 
1391
+ # 6. 準備返回結果
1392
  scores = {k: round(v, 4) for k, v in scores.items()}
1393
  scores['overall'] = round(final_score, 4)
1394
+
1395
  return scores
1396
 
1397
  except Exception as e:
1398
  print(f"Error details: {str(e)}")
1399
  print(f"breed_info: {breed_info}")
 
1400
  return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}