DawnC commited on
Commit
4e15520
1 Parent(s): 418bc03

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +488 -1280
scoring_calculation_system.py CHANGED
@@ -3,59 +3,29 @@ from breed_health_info import breed_health_info
3
  from breed_noise_info import breed_noise_info
4
  import traceback
5
  import math
6
- import random
7
-
8
- # @dataclass
9
- # class UserPreferences:
10
-
11
- # """使用者偏好設定的資料結構"""
12
- # living_space: str # "apartment", "house_small", "house_large"
13
- # yard_access: str # "no_yard", "shared_yard", "private_yard"
14
- # exercise_time: int # minutes per day
15
- # exercise_type: str # "light_walks", "moderate_activity", "active_training"
16
- # grooming_commitment: str # "low", "medium", "high"
17
- # experience_level: str # "beginner", "intermediate", "advanced"
18
- # time_availability: str # "limited", "moderate", "flexible"
19
- # has_children: bool
20
- # children_age: str # "toddler", "school_age", "teenager"
21
- # noise_tolerance: str # "low", "medium", "high"
22
- # space_for_play: bool
23
- # other_pets: bool
24
- # climate: str # "cold", "moderate", "hot"
25
- # health_sensitivity: str = "medium"
26
- # barking_acceptance: str = None
27
-
28
- # def __post_init__(self):
29
- # """在初始化後運行,用於設置派生值"""
30
- # if self.barking_acceptance is None:
31
- # self.barking_acceptance = self.noise_tolerance
32
 
33
  @dataclass
34
  class UserPreferences:
35
- """使用者偏好設定的資料結構,整合基本條件與進階評估參數"""
36
- living_space: str # "apartment", "house_small", "house_large"
37
- yard_access: str # "no_yard", "shared_yard", "private_yard"
38
- exercise_time: int # 每日運動時間(分鐘)
39
- exercise_type: str # "light_walks", "moderate_activity", "active_training"
40
- grooming_commitment: str # "low", "medium", "high"
41
- experience_level: str # "beginner", "intermediate", "advanced"
42
- time_availability: str # "limited", "moderate", "flexible"
 
43
  has_children: bool
44
- children_age: str # "toddler", "school_age", "teenager"
45
- noise_tolerance: str # "low", "medium", "high"
46
  space_for_play: bool
47
  other_pets: bool
48
- climate: str # "cold", "moderate", "hot"
49
-
50
- living_floor: int = 1 # 居住樓層,對公寓住戶特別重要
51
- exercise_intensity: str = "moderate" # "low", "moderate", "high"
52
- home_alone_time: int = 4 # 每日獨處時間(小時)
53
- health_sensitivity: str = "medium" # "low", "medium", "high"
54
- barking_acceptance: str = None # 如果未指定,默認使用 noise_tolerance
55
- lifestyle_activity: str = "moderate" # "sedentary", "moderate", "active"
56
 
57
  def __post_init__(self):
58
- """初始化後執行,用於設置派生值和驗證"""
59
  if self.barking_acceptance is None:
60
  self.barking_acceptance = self.noise_tolerance
61
 
@@ -446,404 +416,182 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
446
  raise KeyError("Size information missing")
447
 
448
 
449
- # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
450
- # """
451
- # 主要改進:
452
- # 1. 更均衡的基礎分數分配
453
- # 2. 更細緻的空間需求評估
454
- # 3. 強化運動需求與空間的關聯性
455
- # """
456
- # # 重新設計基礎分數矩陣,降低普遍分數以增加區別度
457
- # base_scores = {
458
- # "Small": {
459
- # "apartment": 0.85, # 降低滿分機會
460
- # "house_small": 0.80, # 小型犬不應在大空間得到太高分數
461
- # "house_large": 0.75 # 避免小型犬總是得到最高分
462
- # },
463
- # "Medium": {
464
- # "apartment": 0.45, # 維持對公寓環境的限制
465
- # "house_small": 0.75, # 適中的分數
466
- # "house_large": 0.85 # 給予合理的獎勵
467
- # },
468
- # "Large": {
469
- # "apartment": 0.15, # 加重對大型犬在公寓的限制
470
- # "house_small": 0.65, # 中等適合度
471
- # "house_large": 0.90 # 最適合的環境
472
- # },
473
- # "Giant": {
474
- # "apartment": 0.10, # 更嚴格的限制
475
- # "house_small": 0.45, # 顯著的空間限制
476
- # "house_large": 0.95 # 最理想的配對
477
- # }
478
- # }
479
-
480
- # # 取得基礎分數
481
- # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
482
-
483
- # # 運動需求相關的調整更加動態
484
- # exercise_adjustments = {
485
- # "Very High": {
486
- # "apartment": -0.25, # 加重在受限空間的懲罰
487
- # "house_small": -0.15,
488
- # "house_large": -0.05
489
- # },
490
- # "High": {
491
- # "apartment": -0.20,
492
- # "house_small": -0.10,
493
- # "house_large": 0
494
- # },
495
- # "Moderate": {
496
- # "apartment": -0.10,
497
- # "house_small": -0.05,
498
- # "house_large": 0
499
- # },
500
- # "Low": {
501
- # "apartment": 0.05, # 低運動需求在小空間反而有優勢
502
- # "house_small": 0,
503
- # "house_large": -0.05 # 輕微降低評分,因為空間可能過大
504
- # }
505
- # }
506
-
507
- # # 根據空間類型獲取運動需求調整
508
- # adjustment = exercise_adjustments.get(exercise_needs,
509
- # exercise_adjustments["Moderate"])[living_space]
510
-
511
- # # 院子效益根據品種大小和運動需求動態調整
512
- # if has_yard:
513
- # yard_bonus = {
514
- # "Giant": 0.20,
515
- # "Large": 0.15,
516
- # "Medium": 0.10,
517
- # "Small": 0.05
518
- # }.get(size, 0.10)
519
-
520
- # # 運動需求會影響院子的重要性
521
- # if exercise_needs in ["Very High", "High"]:
522
- # yard_bonus *= 1.2
523
- # elif exercise_needs == "Low":
524
- # yard_bonus *= 0.8
525
-
526
- # current_score = base_score + adjustment + yard_bonus
527
- # else:
528
- # current_score = base_score + adjustment
529
-
530
- # # 確保分數在合理範圍內,但避免極端值
531
- # return min(0.95, max(0.15, current_score))
532
-
533
-
534
- # def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
535
- # """
536
- # 精確評估品種運動需求與使用者運動條件的匹配度
537
-
538
- # Parameters:
539
- # breed_needs: 品種的運動需求等級
540
- # exercise_time: 使用者能提供的運動時間(分鐘)
541
- # exercise_type: 使用者偏好的運動類型
542
-
543
- # Returns:
544
- # float: -0.2 到 0.2 之間的匹配分數
545
- # """
546
- # # 定義更細緻的運動需求等級
547
- # exercise_levels = {
548
- # 'VERY HIGH': {
549
- # 'min': 120,
550
- # 'ideal': 150,
551
- # 'max': 180,
552
- # 'intensity': 'high',
553
- # 'sessions': 'multiple',
554
- # 'preferred_types': ['active_training', 'intensive_exercise']
555
- # },
556
- # 'HIGH': {
557
- # 'min': 90,
558
- # 'ideal': 120,
559
- # 'max': 150,
560
- # 'intensity': 'moderate_high',
561
- # 'sessions': 'multiple',
562
- # 'preferred_types': ['active_training', 'moderate_activity']
563
- # },
564
- # 'MODERATE HIGH': {
565
- # 'min': 70,
566
- # 'ideal': 90,
567
- # 'max': 120,
568
- # 'intensity': 'moderate',
569
- # 'sessions': 'flexible',
570
- # 'preferred_types': ['moderate_activity', 'active_training']
571
- # },
572
- # 'MODERATE': {
573
- # 'min': 45,
574
- # 'ideal': 60,
575
- # 'max': 90,
576
- # 'intensity': 'moderate',
577
- # 'sessions': 'flexible',
578
- # 'preferred_types': ['moderate_activity', 'light_walks']
579
- # },
580
- # 'MODERATE LOW': {
581
- # 'min': 30,
582
- # 'ideal': 45,
583
- # 'max': 70,
584
- # 'intensity': 'light_moderate',
585
- # 'sessions': 'flexible',
586
- # 'preferred_types': ['light_walks', 'moderate_activity']
587
- # },
588
- # 'LOW': {
589
- # 'min': 15,
590
- # 'ideal': 30,
591
- # 'max': 45,
592
- # 'intensity': 'light',
593
- # 'sessions': 'single',
594
- # 'preferred_types': ['light_walks']
595
- # }
596
- # }
597
-
598
- # # 獲取品種的運動需求配置
599
- # breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
600
-
601
- # # 計算時間匹配度(使用更平滑的評分曲線)
602
- # if exercise_time >= breed_level['ideal']:
603
- # if exercise_time > breed_level['max']:
604
- # # 運動時間過長,適度降分
605
- # time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30)
606
- # else:
607
- # time_score = 0.15
608
- # elif exercise_time >= breed_level['min']:
609
- # # 在最小需求和理想需求之間,線性計算分數
610
- # time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
611
- # time_score = 0.05 + (time_ratio * 0.10)
612
- # else:
613
- # # 運動時間不足,根據差距程度扣分
614
- # time_ratio = max(0, exercise_time / breed_level['min'])
615
- # time_score = -0.15 * (1 - time_ratio)
616
-
617
- # # 運動類型匹配度評估
618
- # type_score = 0.0
619
- # if exercise_type in breed_level['preferred_types']:
620
- # type_score = 0.05
621
- # if exercise_type == breed_level['preferred_types'][0]:
622
- # type_score = 0.08 # 最佳匹配類型給予更高分數
623
-
624
- # return max(-0.2, min(0.2, time_score + type_score))
625
-
626
-
627
- def calculate_space_score(breed_info: dict, user_prefs: UserPreferences) -> float:
628
- """
629
- 計算品種與居住空間的匹配程度
630
-
631
- 這個函數實現了一個全面的空間評分系統,考慮:
632
- 1. 基本空間需求(住所類型與品種大小的匹配)
633
- 2. 樓層因素(特別是公寓住戶)
634
- 3. 戶外活動空間(院子類型及可用性)
635
- 4. 室內活動空間的實際可用性
636
- 5. 品種的特殊空間需求
637
-
638
- Parameters:
639
- -----------
640
- breed_info: 包含品種特徵的字典,包括體型、活動需求等
641
- user_prefs: 使用者偏好設定,包含居住條件相關信息
642
-
643
- Returns:
644
- --------
645
- float: 0.0-1.0 之間的匹配分數
646
  """
647
- # 取得品種基本信息
648
- size = breed_info.get('Size', 'Medium')
649
- temperament = breed_info.get('Temperament', '').lower()
650
- exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
651
-
652
- # 基礎空間需求評分矩陣 - 考慮品種大小與居住空間的基本匹配度
653
- base_space_scores = {
654
  "Small": {
655
- "apartment": 0.95, # 小型犬最適合公寓
656
- "house_small": 0.90, # 小房子也很適合
657
- "house_large": 0.85 # 大房子可能過大
658
  },
659
  "Medium": {
660
- "apartment": 0.60, # 中型犬在公寓有一定限制
661
- "house_small": 0.85, # 小房子較適合
662
- "house_large": 0.95 # 大房子最理想
663
  },
664
  "Large": {
665
- "apartment": 0.30, # 大型犬不適合公寓
666
- "house_small": 0.70, # 小房子稍嫌擁擠
667
- "house_large": 1.0 # 大房子最理想
668
  },
669
  "Giant": {
670
- "apartment": 0.20, # 極大型犬極不適合公寓
671
- "house_small": 0.50, # 小房子明顯不足
672
- "house_large": 1.0 # 大房子必需
673
  }
674
  }
675
 
676
- # 取得基礎空間分數
677
- base_score = base_space_scores.get(size, base_space_scores["Medium"])[user_prefs.living_space]
678
-
679
- # 公寓特殊考量
680
- if user_prefs.living_space == "apartment":
681
- # 樓層調整
682
- floor_penalty = 0
683
- if user_prefs.living_floor > 1:
684
- if size in ["Large", "Giant"]:
685
- floor_penalty = min(0.3, (user_prefs.living_floor - 1) * 0.05)
686
- elif size == "Medium":
687
- floor_penalty = min(0.2, (user_prefs.living_floor - 1) * 0.03)
688
- else:
689
- floor_penalty = min(0.1, (user_prefs.living_floor - 1) * 0.02)
690
- base_score = max(0.2, base_score - floor_penalty)
691
-
692
- # 戶外空間評估
693
- yard_scores = {
694
- "no_yard": 0,
695
- "shared_yard": 0.1,
696
- "private_yard": 0.2
697
- }
698
-
699
- # 根據品種大小調整院子加分
700
- yard_size_multipliers = {
701
- "Giant": 1.2,
702
- "Large": 1.1,
703
- "Medium": 1.0,
704
- "Small": 0.8
705
  }
706
 
707
- yard_bonus = yard_scores[user_prefs.yard_access] * yard_size_multipliers.get(size, 1.0)
708
-
709
- # 活動空間需求評估
710
- activity_space_score = 0
711
- if user_prefs.space_for_play:
712
- if exercise_needs in ["VERY HIGH", "HIGH"]:
713
- activity_space_score = 0.15
714
- elif exercise_needs == "MODERATE":
715
- activity_space_score = 0.10
716
- else:
717
- activity_space_score = 0.05
718
-
719
- # 品種特性評估
720
- temperament_adjustments = 0
721
- if 'active' in temperament or 'energetic' in temperament:
722
- if user_prefs.living_space == 'apartment':
723
- temperament_adjustments -= 0.15
724
- elif user_prefs.living_space == 'house_small':
725
- temperament_adjustments -= 0.05
726
-
727
- if 'calm' in temperament or 'lazy' in temperament:
728
- if user_prefs.living_space == 'apartment':
729
- temperament_adjustments += 0.10
730
 
731
- if 'adaptable' in temperament:
732
- temperament_adjustments += 0.05
733
-
734
- # 家庭環境考量
735
- if user_prefs.has_children:
736
- if user_prefs.living_space == 'apartment':
737
- # 公寓中有孩童需要更多活動空間
738
- if size in ["Large", "Giant"]:
739
- base_score *= 0.85
740
- elif size == "Medium":
741
- base_score *= 0.90
742
-
743
- # 整合所有評分因素
744
- final_score = base_score + yard_bonus + activity_space_score + temperament_adjustments
745
-
746
- # 確保最終分數在合理範圍內
747
- return max(0.15, min(1.0, final_score))
748
 
749
 
750
- def calculate_exercise_score(breed_needs: str, exercise_time: int, user_prefs: 'UserPreferences') -> float:
751
  """
752
- 計算品種運動需求與使用者條件的匹配分數
753
-
754
- 這個函數實現了一個精細的運動評分系統,考慮:
755
- 1. 運動時間的匹配度(0-180分鐘)
756
- 2. 運動強度的適配性
757
- 3. 品種特性對運動的特殊需求
758
- 4. 生活方式的整體活躍度
759
 
760
  Parameters:
761
- -----------
762
  breed_needs: 品種的運動需求等級
763
  exercise_time: 使用者能提供的運動時間(分鐘)
764
- user_prefs: 使用者偏好設定,包含運動類型和強度等信息
765
 
766
  Returns:
767
- --------
768
- float: 0.0-1.0 之間的匹配分數
769
  """
770
- # 定義更精確的運動需求標準
771
  exercise_levels = {
772
  'VERY HIGH': {
773
  'min': 120,
774
  'ideal': 150,
775
  'max': 180,
776
- 'intensity_required': 'high',
777
- 'intensity_factors': {'high': 1.2, 'moderate': 0.8, 'low': 0.6},
778
- 'type_bonus': {'active_training': 0.15, 'moderate_activity': 0.05, 'light_walks': -0.1}
779
  },
780
  'HIGH': {
781
  'min': 90,
782
  'ideal': 120,
783
  'max': 150,
784
- 'intensity_required': 'moderate',
785
- 'intensity_factors': {'high': 1.1, 'moderate': 1.0, 'low': 0.7},
786
- 'type_bonus': {'active_training': 0.1, 'moderate_activity': 0.1, 'light_walks': -0.05}
787
  },
788
- 'MODERATE': {
789
- 'min': 60,
790
  'ideal': 90,
791
  'max': 120,
792
- 'intensity_required': 'moderate',
793
- 'intensity_factors': {'high': 1.0, 'moderate': 1.0, 'low': 0.8},
794
- 'type_bonus': {'active_training': 0.05, 'moderate_activity': 0.1, 'light_walks': 0.05}
795
  },
796
- 'LOW': {
797
- 'min': 30,
798
  'ideal': 60,
799
  'max': 90,
800
- 'intensity_required': 'low',
801
- 'intensity_factors': {'high': 0.7, 'moderate': 0.9, 'low': 1.0},
802
- 'type_bonus': {'active_training': -0.05, 'moderate_activity': 0.05, 'light_walks': 0.1}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803
  }
804
  }
805
 
806
- # 獲取品種運動需求配置
807
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
808
 
809
- # 計算基礎運動時間分數
810
- def calculate_time_score(time: int, level: dict) -> float:
811
- if time < level['min']:
812
- # 運動時間不足,指數下降
813
- return max(0.3, (time / level['min']) ** 1.5)
814
- elif time < level['ideal']:
815
- # 運動時間接近理想,線性增長
816
- return 0.7 + 0.3 * ((time - level['min']) / (level['ideal'] - level['min']))
817
- elif time <= level['max']:
818
- # 理想運動時間範圍,高分保持
819
- return 1.0
820
  else:
821
- # 運動時間過多,緩慢扣分
822
- excess = (time - level['max']) / 30 # 每超過30分鐘扣分
823
- return max(0.7, 1.0 - (excess * 0.1))
824
-
825
- # 計算運動時間基礎分數
826
- time_score = calculate_time_score(exercise_time, breed_level)
827
-
828
- # 計算運動強度匹配度
829
- intensity_factor = breed_level['intensity_factors'].get(user_prefs.exercise_intensity, 1.0)
830
-
831
- # 運動類型加成
832
- type_bonus = breed_level['type_bonus'].get(user_prefs.exercise_type, 0)
833
-
834
- # 生活方式調整
835
- lifestyle_adjustments = {
836
- 'sedentary': -0.1,
837
- 'moderate': 0,
838
- 'active': 0.1
839
- }
840
- lifestyle_factor = lifestyle_adjustments.get(user_prefs.lifestyle_activity, 0)
841
-
842
- # 整合所有因素
843
- final_score = time_score * intensity_factor + type_bonus + lifestyle_factor
844
-
845
- # 確保分數在合理範圍內
846
- return max(0.1, min(1.0, final_score))
847
 
848
 
849
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
@@ -977,275 +725,114 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
977
  return max(0.1, min(1.0, final_score))
978
 
979
 
980
- # def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
981
- # """
982
- # 計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
983
-
984
- # 重要改進:
985
- # 1. 擴大基礎分數差異
986
- # 2. 加重困難特徵的懲罰
987
- # 3. 更細緻的品種特性評估
988
- # """
989
- # # 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
990
- # base_scores = {
991
- # "High": {
992
- # "beginner": 0.10, # 降低起始分,高難度品種對新手幾乎不推薦
993
- # "intermediate": 0.60, # 中級玩家仍需謹慎
994
- # "advanced": 1.0 # 資深者能完全勝任
995
- # },
996
- # "Moderate": {
997
- # "beginner": 0.35, # 適中難度對新手仍具挑戰
998
- # "intermediate": 0.80, # 中級玩家較適合
999
- # "advanced": 1.0 # 資深者完全勝任
1000
- # },
1001
- # "Low": {
1002
- # "beginner": 0.90, # 新手友善品種
1003
- # "intermediate": 0.95, # 中級玩家幾乎完全勝任
1004
- # "advanced": 1.0 # 資深者完全勝任
1005
- # }
1006
- # }
1007
-
1008
- # # 取得基礎分數
1009
- # score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
1010
-
1011
- # temperament_lower = temperament.lower()
1012
- # temperament_adjustments = 0.0
1013
-
1014
- # # 根據經驗等級設定不同的特徵評估標準
1015
- # if user_experience == "beginner":
1016
- # # 新手不適合的特徵 - 更嚴格的懲罰
1017
- # difficult_traits = {
1018
- # 'stubborn': -0.30, # 固執性格嚴重影響新手
1019
- # 'independent': -0.25, # 獨立性高的品種不適合新手
1020
- # 'dominant': -0.25, # 支配性強的品種需要經驗處理
1021
- # 'strong-willed': -0.20, # 強勢性格需要技巧管理
1022
- # 'protective': -0.20, # 保護性強需要適當訓練
1023
- # 'aloof': -0.15, # 冷漠性格需要耐心培養
1024
- # 'energetic': -0.15, # 活潑好動需要經驗引導
1025
- # 'aggressive': -0.35 # 攻擊傾向極不適合新手
1026
- # }
1027
-
1028
- # # 新手友善的特徵 - 適度的獎勵
1029
- # easy_traits = {
1030
- # 'gentle': 0.05, # 溫和性格適合新手
1031
- # 'friendly': 0.05, # 友善性格容易相處
1032
- # 'eager to please': 0.08, # 願意服從較容易訓練
1033
- # 'patient': 0.05, # 耐心的特質有助於建立關係
1034
- # 'adaptable': 0.05, # 適應性強較容易照顧
1035
- # 'calm': 0.06 # 冷靜的性格較好掌握
1036
- # }
1037
-
1038
- # # 計算特徵調整
1039
- # for trait, penalty in difficult_traits.items():
1040
- # if trait in temperament_lower:
1041
- # temperament_adjustments += penalty
1042
-
1043
- # for trait, bonus in easy_traits.items():
1044
- # if trait in temperament_lower:
1045
- # temperament_adjustments += bonus
1046
-
1047
- # # 品種類型特殊評估
1048
- # if 'terrier' in temperament_lower:
1049
- # temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
1050
- # elif 'working' in temperament_lower:
1051
- # temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
1052
- # elif 'guard' in temperament_lower:
1053
- # temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
1054
-
1055
- # elif user_experience == "intermediate":
1056
- # # 中級玩家的特徵評估
1057
- # moderate_traits = {
1058
- # 'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
1059
- # 'independent': -0.10,
1060
- # 'intelligent': 0.08, # 聰明的特質可以好好發揮
1061
- # 'athletic': 0.06, # 運動能力可以適當訓練
1062
- # 'versatile': 0.07, # 多功能性可以開發
1063
- # 'protective': -0.08 # 保護性仍需注意
1064
- # }
1065
-
1066
- # for trait, adjustment in moderate_traits.items():
1067
- # if trait in temperament_lower:
1068
- # temperament_adjustments += adjustment
1069
-
1070
- # else: # advanced
1071
- # # 資深玩家能夠應對挑戰性特徵
1072
- # advanced_traits = {
1073
- # 'stubborn': 0.05, # 困難特徵反而成為優勢
1074
- # 'independent': 0.05,
1075
- # 'intelligent': 0.10,
1076
- # 'protective': 0.05,
1077
- # 'strong-willed': 0.05
1078
- # }
1079
-
1080
- # for trait, bonus in advanced_traits.items():
1081
- # if trait in temperament_lower:
1082
- # temperament_adjustments += bonus
1083
-
1084
- # # 確保最終分數範圍更大,讓差異更明顯
1085
- # final_score = max(0.05, min(1.0, score + temperament_adjustments))
1086
-
1087
- # return final_score
1088
-
1089
-
1090
- def calculate_experience_score(breed_info: dict, user_prefs: UserPreferences) -> float:
1091
  """
1092
- 計算飼主經驗與品種需求的匹配分數
1093
-
1094
- 這個函數實現了一個全面的經驗評分系統,考慮:
1095
- 1. 品種的基本照護難度
1096
- 2. 飼主的經驗水平
1097
- 3. 特殊照護需求(如健康問題、行為訓練)
1098
- 4. 時間投入與生活方式的匹配
1099
- 5. 家庭環境對照護的影響
1100
-
1101
- 特別注意:
1102
- - 新手飼主面對高難度品種時的顯著降分
1103
- - 資深飼主照顧簡單品種的微幅降分
1104
- - 特殊需求品種的額外評估
1105
 
1106
- Parameters:
1107
- -----------
1108
- breed_info: 包含品種特徵的字典
1109
- user_prefs: 使用者偏好設定
1110
-
1111
- Returns:
1112
- --------
1113
- float: 0.0-1.0 之間的匹配���數
1114
  """
1115
- care_level = breed_info.get('Care Level', 'MODERATE').upper()
1116
- temperament = breed_info.get('Temperament', '').lower()
1117
- health_issues = breed_info.get('Health Issues', '').lower()
1118
-
1119
- # 基礎照護難度評分矩陣
1120
- base_experience_scores = {
1121
- "HIGH": {
1122
- "beginner": 0.30, # 高難度品種對新手極具挑戰
1123
- "intermediate": 0.70, # 中級飼主需要額外努力
1124
- "advanced": 0.95 # 資深飼主最適合
1125
  },
1126
- "MODERATE": {
1127
- "beginner": 0.60, # 中等難度對新手有一定挑戰
1128
- "intermediate": 0.85, # 中級飼主較適合
1129
- "advanced": 0.90 # 資深飼主可能稍嫌簡單
1130
  },
1131
- "LOW": {
1132
- "beginner": 0.90, # 低難度適合新手
1133
- "intermediate": 0.85, # 中級飼主可能感覺無趣
1134
- "advanced": 0.80 # 資深飼主可能缺乏挑戰
1135
  }
1136
  }
1137
 
1138
- # 取得基礎經驗分數
1139
- base_score = base_experience_scores.get(care_level,
1140
- base_experience_scores["MODERATE"])[user_prefs.experience_level]
1141
-
1142
- # 時間可用性評估
1143
- time_adjustments = {
1144
- "limited": {
1145
- "HIGH": -0.20,
1146
- "MODERATE": -0.15,
1147
- "LOW": -0.10
1148
- },
1149
- "moderate": {
1150
- "HIGH": -0.10,
1151
- "MODERATE": -0.05,
1152
- "LOW": 0
1153
- },
1154
- "flexible": {
1155
- "HIGH": 0,
1156
- "MODERATE": 0.05,
1157
- "LOW": 0.10
1158
- }
1159
- }
1160
 
1161
- time_adjustment = time_adjustments[user_prefs.time_availability][care_level]
 
1162
 
1163
- # 行為特徵評估
1164
- def evaluate_temperament(temp: str, exp_level: str) -> float:
1165
- """評估品種性格特徵與飼主經驗的匹配度"""
1166
- score = 0
1167
-
1168
- # 困難特徵評估
1169
  difficult_traits = {
1170
- 'stubborn': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': 0},
1171
- 'independent': {'beginner': -0.15, 'intermediate': -0.08, 'advanced': 0},
1172
- 'dominant': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': -0.05},
1173
- 'aggressive': {'beginner': -0.25, 'intermediate': -0.15, 'advanced': -0.10}
 
 
 
 
1174
  }
1175
 
1176
- # 友善特徵評估
1177
- friendly_traits = {
1178
- 'friendly': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0},
1179
- 'gentle': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0},
1180
- 'easy to train': {'beginner': 0.15, 'intermediate': 0.10, 'advanced': 0.05}
 
 
 
1181
  }
1182
 
1183
- # 計算特徵分數
1184
- for trait, penalties in difficult_traits.items():
1185
- if trait in temp:
1186
- score += penalties[exp_level]
1187
-
1188
- for trait, bonuses in friendly_traits.items():
1189
- if trait in temp:
1190
- score += bonuses[exp_level]
1191
-
1192
- return score
1193
-
1194
- temperament_adjustment = evaluate_temperament(temperament, user_prefs.experience_level)
1195
-
1196
- # 健康問題評估
1197
- def evaluate_health_needs(health: str, exp_level: str) -> float:
1198
- """評估健康問題的照護難度"""
1199
- score = 0
1200
- serious_conditions = ['hip dysplasia', 'heart disease', 'cancer']
1201
- moderate_conditions = ['allergies', 'skin problems', 'ear infections']
1202
 
1203
- # 根據經驗等級調整健康問題的影響
1204
- health_impact = {
1205
- 'beginner': {'serious': -0.20, 'moderate': -0.10},
1206
- 'intermediate': {'serious': -0.15, 'moderate': -0.05},
1207
- 'advanced': {'serious': -0.10, 'moderate': -0.03}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1208
  }
1209
 
1210
- for condition in serious_conditions:
1211
- if condition in health:
1212
- score += health_impact[exp_level]['serious']
1213
 
1214
- for condition in moderate_conditions:
1215
- if condition in health:
1216
- score += health_impact[exp_level]['moderate']
 
 
 
 
 
 
1217
 
1218
- return score
 
 
1219
 
1220
- health_adjustment = evaluate_health_needs(health_issues, user_prefs.experience_level)
 
1221
 
1222
- # 家庭環境考量
1223
- family_adjustment = 0
1224
- if user_prefs.has_children:
1225
- if user_prefs.children_age == 'toddler':
1226
- if user_prefs.experience_level == 'beginner':
1227
- family_adjustment -= 0.15
1228
- elif user_prefs.experience_level == 'intermediate':
1229
- family_adjustment -= 0.10
1230
- elif user_prefs.children_age == 'school_age':
1231
- if user_prefs.experience_level == 'beginner':
1232
- family_adjustment -= 0.10
1233
-
1234
- # 生活方式匹配度
1235
- lifestyle_adjustments = {
1236
- 'sedentary': -0.10 if care_level == 'HIGH' else 0,
1237
- 'moderate': 0,
1238
- 'active': 0.10 if care_level in ['HIGH', 'MODERATE'] else 0
1239
- }
1240
- lifestyle_adjustment = lifestyle_adjustments[user_prefs.lifestyle_activity]
1241
-
1242
- # 整合所有評分因素
1243
- final_score = base_score + time_adjustment + temperament_adjustment + \
1244
- health_adjustment + family_adjustment + lifestyle_adjustment
1245
-
1246
- # 確保最終分數在合理範圍內
1247
- return max(0.15, min(1.0, final_score))
1248
-
1249
 
1250
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
1251
  """
@@ -1355,343 +942,131 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1355
  return max(0.1, min(1.0, health_score))
1356
 
1357
 
1358
- # def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
1359
- # """
1360
- # 計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
1361
- # """
1362
- # if breed_name not in breed_noise_info:
1363
- # return 0.5
1364
-
1365
- # noise_info = breed_noise_info[breed_name]
1366
- # noise_level = noise_info['noise_level'].lower()
1367
- # noise_notes = noise_info['noise_notes'].lower()
1368
-
1369
- # # 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
1370
- # base_scores = {
1371
- # 'low': {
1372
- # 'low': 1.0, # 安靜的狗對低容忍完美匹配
1373
- # 'medium': 0.95, # 安靜的狗對一般容忍很好
1374
- # 'high': 0.90 # 安靜的狗對高容忍當然可以
1375
- # },
1376
- # 'medium': {
1377
- # 'low': 0.60, # 一般吠叫對低容忍較困難
1378
- # 'medium': 0.90, # 一般吠叫對一般容忍可接受
1379
- # 'high': 0.95 # 一般吠叫對高容忍很好
1380
- # },
1381
- # 'high': {
1382
- # 'low': 0.25, # 愛叫的狗對低容忍極不適合
1383
- # 'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
1384
- # 'high': 0.90 # 愛叫的狗對高容忍可以接受
1385
- # },
1386
- # 'varies': {
1387
- # 'low': 0.50, # 不確定的情況對低容忍風險較大
1388
- # 'medium': 0.75, # 不確定的情況對一般容忍可嘗試
1389
- # 'high': 0.85 # 不確定的情況對高容忍問題較小
1390
- # }
1391
- # }
1392
-
1393
- # # 取得基礎分數
1394
- # base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
1395
-
1396
- # # 吠叫原因評估,根據環境調整懲罰程度
1397
- # barking_penalties = {
1398
- # 'separation anxiety': {
1399
- # 'apartment': -0.30, # 在公寓對鄰居影響更大
1400
- # 'house_small': -0.25,
1401
- # 'house_large': -0.20
1402
- # },
1403
- # 'excessive barking': {
1404
- # 'apartment': -0.25,
1405
- # 'house_small': -0.20,
1406
- # 'house_large': -0.15
1407
- # },
1408
- # 'territorial': {
1409
- # 'apartment': -0.20, # 在公寓更容易被觸發
1410
- # 'house_small': -0.15,
1411
- # 'house_large': -0.10
1412
- # },
1413
- # 'alert barking': {
1414
- # 'apartment': -0.15, # 公寓環境刺激較多
1415
- # 'house_small': -0.10,
1416
- # 'house_large': -0.08
1417
- # },
1418
- # 'attention seeking': {
1419
- # 'apartment': -0.15,
1420
- # 'house_small': -0.12,
1421
- # 'house_large': -0.10
1422
- # }
1423
- # }
1424
-
1425
- # # 計算環境相關的吠叫懲罰
1426
- # living_space = user_prefs.living_space
1427
- # barking_penalty = 0
1428
- # for trigger, penalties in barking_penalties.items():
1429
- # if trigger in noise_notes:
1430
- # barking_penalty += penalties.get(living_space, -0.15)
1431
 
1432
- # # 特殊情況評估
1433
- # special_adjustments = 0
1434
- # if user_prefs.has_children:
1435
- # # 孩童年齡相關調整
1436
- # child_age_adjustments = {
1437
- # 'toddler': {
1438
- # 'high': -0.20, # 幼童對吵鬧更敏感
1439
- # 'medium': -0.15,
1440
- # 'low': -0.05
1441
- # },
1442
- # 'school_age': {
1443
- # 'high': -0.15,
1444
- # 'medium': -0.10,
1445
- # 'low': -0.05
1446
- # },
1447
- # 'teenager': {
1448
- # 'high': -0.10,
1449
- # 'medium': -0.05,
1450
- # 'low': -0.02
1451
- # }
1452
- # }
1453
-
1454
- # # 根據孩童年齡和噪音等級調整
1455
- # age_adj = child_age_adjustments.get(user_prefs.children_age,
1456
- # child_age_adjustments['school_age'])
1457
- # special_adjustments += age_adj.get(noise_level, -0.10)
1458
 
1459
- # # 訓練性補償評估
1460
- # trainability_bonus = 0
1461
- # if 'responds well to training' in noise_notes:
1462
- # trainability_bonus = 0.12
1463
- # elif 'can be trained' in noise_notes:
1464
- # trainability_bonus = 0.08
1465
- # elif 'difficult to train' in noise_notes:
1466
- # trainability_bonus = 0.02
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1467
 
1468
- # # 夜間吠叫特別考量
1469
- # if 'night barking' in noise_notes or 'howls' in noise_notes:
1470
- # if user_prefs.living_space == 'apartment':
1471
- # special_adjustments -= 0.15
1472
- # elif user_prefs.living_space == 'house_small':
1473
- # special_adjustments -= 0.10
1474
- # else:
1475
- # special_adjustments -= 0.05
1476
 
1477
- # # 計算最終分數,確保更大的分數範圍
1478
- # final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1479
- # return max(0.1, min(1.0, final_score))
1480
-
1481
-
1482
- def calculate_noise_score(breed_info: dict, user_prefs: UserPreferences) -> float:
1483
- """
1484
- 計算品種噪音特性與使用者需求的匹配分數
1485
-
1486
- 這個函數建立了一個細緻的噪音評估系統,考慮多個關鍵因素:
1487
- 1. 品種的基本吠叫傾向
1488
- 2. 居住環境對噪音的敏感度
1489
- 3. 吠叫的情境和原因
1490
- 4. 鄰居影響的考量
1491
- 5. 家庭成員的噪音承受度
1492
- 6. 訓練可能性的評估
1493
-
1494
- 特別注意:
1495
- - 公寓環境的嚴格標準
1496
- - 有幼童時的特殊考量
1497
- - 獨處時間的影響
1498
- - 品種的可訓練性
1499
-
1500
- Parameters:
1501
- -----------
1502
- breed_info: 包含品種特性的字典,包括吠叫傾向和訓練難度
1503
- user_prefs: 使用者偏好設定,包含噪音容忍度和環境因素
1504
-
1505
- Returns:
1506
- --------
1507
- float: 0.0-1.0 之間的匹配��數,分數越高表示噪音特性越符合需求
1508
- """
1509
-
1510
- # 提取基本資訊
1511
- noise_level = breed_info.get('Noise Level', 'MODERATE').upper()
1512
- barking_tendency = breed_info.get('Barking Tendency', 'MODERATE').upper()
1513
- trainability = breed_info.get('Trainability', 'MODERATE').upper()
1514
- temperament = breed_info.get('Temperament', '').lower()
1515
-
1516
- # 基礎噪音評分矩陣 - 考慮環境和噪音容忍度
1517
- base_noise_scores = {
1518
- "LOW": {
1519
- "apartment": {
1520
- "low": 1.0, # 安靜的狗在公寓最理想
1521
- "medium": 0.95,
1522
- "high": 0.90
1523
- },
1524
- "house_small": {
1525
- "low": 0.95,
1526
- "medium": 0.90,
1527
- "high": 0.85
1528
- },
1529
- "house_large": {
1530
- "low": 0.90,
1531
- "medium": 0.85,
1532
- "high": 0.80 # 太安靜可能不夠警戒
1533
- }
1534
  },
1535
- "MODERATE": {
1536
- "apartment": {
1537
- "low": 0.60,
1538
- "medium": 0.80,
1539
- "high": 0.85
1540
- },
1541
- "house_small": {
1542
- "low": 0.70,
1543
- "medium": 0.85,
1544
- "high": 0.90
1545
- },
1546
- "house_large": {
1547
- "low": 0.75,
1548
- "medium": 0.90,
1549
- "high": 0.95
1550
- }
1551
  },
1552
- "HIGH": {
1553
- "apartment": {
1554
- "low": 0.20, # 吵鬧的狗在公寓極不適合
1555
- "medium": 0.40,
1556
- "high": 0.60
1557
- },
1558
- "house_small": {
1559
- "low": 0.30,
1560
- "medium": 0.50,
1561
- "high": 0.70
1562
- },
1563
- "house_large": {
1564
- "low": 0.40,
1565
- "medium": 0.60,
1566
- "high": 0.80
1567
- }
1568
  }
1569
  }
1570
-
1571
- # 取得基礎噪音分數
1572
- base_score = base_noise_scores.get(noise_level, base_noise_scores["MODERATE"])\
1573
- [user_prefs.living_space][user_prefs.noise_tolerance]
1574
-
1575
- # 吠叫情境評估
1576
- def evaluate_barking_context(temp: str, living_space: str) -> float:
1577
- """評估不同情境下的吠叫問題嚴重度"""
1578
- context_score = 0
1579
-
1580
- # 不同吠叫原因的權重
1581
- barking_contexts = {
1582
- 'separation anxiety': {
1583
- 'apartment': -0.25,
1584
- 'house_small': -0.20,
1585
- 'house_large': -0.15
1586
- },
1587
- 'territorial': {
1588
- 'apartment': -0.20,
1589
- 'house_small': -0.15,
1590
- 'house_large': -0.10
1591
  },
1592
- 'alert barking': {
1593
- 'apartment': -0.15,
1594
- 'house_small': -0.10,
1595
- 'house_large': -0.05
1596
  },
1597
- 'attention seeking': {
1598
- 'apartment': -0.15,
1599
- 'house_small': -0.10,
1600
- 'house_large': -0.08
1601
  }
1602
  }
1603
 
1604
- for context, penalties in barking_contexts.items():
1605
- if context in temp:
1606
- context_score += penalties[living_space]
1607
-
1608
- return context_score
1609
-
1610
- # 計算吠叫情境的影響
1611
- barking_context_adjustment = evaluate_barking_context(temperament, user_prefs.living_space)
1612
-
1613
- # 訓練可能性評估
1614
- trainability_adjustments = {
1615
- "HIGH": 0.10, # 容易訓練可以改善吠叫問題
1616
- "MODERATE": 0.05,
1617
- "LOW": -0.05 # 難以訓練則較難改善
1618
- }
1619
- trainability_adjustment = trainability_adjustments.get(trainability, 0)
1620
-
1621
- # 家庭環境考量
1622
- family_adjustment = 0
1623
- if user_prefs.has_children:
1624
- child_age_factors = {
1625
- 'toddler': -0.20, # 幼童需要安靜環境
1626
- 'school_age': -0.15,
1627
- 'teenager': -0.10
1628
- }
1629
- family_adjustment = child_age_factors.get(user_prefs.children_age, -0.15)
1630
-
1631
- # 根據噪音等級調整影響程度
1632
- if noise_level == "HIGH":
1633
- family_adjustment *= 1.5
1634
- elif noise_level == "LOW":
1635
- family_adjustment *= 0.5
1636
-
1637
- # 獨處時間的影響
1638
- alone_time_adjustment = 0
1639
- if user_prefs.home_alone_time > 6:
1640
- if 'separation anxiety' in temperament or noise_level == "HIGH":
1641
- alone_time_adjustment = -0.15
1642
- elif noise_level == "MODERATE":
1643
- alone_time_adjustment = -0.10
1644
-
1645
- # 鄰居影響評估(特別是公寓環境)
1646
- neighbor_adjustment = 0
1647
- if user_prefs.living_space == "apartment":
1648
- if noise_level == "HIGH":
1649
- neighbor_adjustment = -0.15
1650
- elif noise_level == "MODERATE":
1651
- neighbor_adjustment = -0.10
1652
-
1653
- # 樓層因素
1654
- if user_prefs.living_floor > 1:
1655
- neighbor_adjustment -= min(0.10, (user_prefs.living_floor - 1) * 0.02)
1656
-
1657
- # 整合所有評分因素
1658
- final_score = base_score + barking_context_adjustment + trainability_adjustment + \
1659
- family_adjustment + alone_time_adjustment + neighbor_adjustment
1660
-
1661
- # 確保最終分數在合理範圍內
1662
- return max(0.15, min(1.0, final_score))
1663
-
1664
- except Exception as e:
1665
- print(f"Error calculating compatibility score: {str(e)}")
1666
- return 60.0 # 返回最低分數作為默認值
1667
-
1668
-
1669
- def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -> float:
1670
- """計算品種與環境的適應性加成"""
1671
- adaptability_score = 0.0
1672
- description = breed_info.get('Description', '').lower()
1673
- temperament = breed_info.get('Temperament', '').lower()
1674
-
1675
- # 環境適應性評估
1676
- if user_prefs.living_space == 'apartment':
1677
- if 'adaptable' in temperament or 'apartment' in description:
1678
- adaptability_score += 0.1
1679
- if breed_info.get('Size') == 'Small':
1680
- adaptability_score += 0.05
1681
- elif user_prefs.living_space == 'house_large':
1682
- if 'active' in temperament or 'energetic' in description:
1683
- adaptability_score += 0.1
1684
-
1685
- # 氣候適應性
1686
- if user_prefs.climate in description or user_prefs.climate in temperament:
1687
- adaptability_score += 0.05
1688
 
1689
- return min(0.2, adaptability_score)
1690
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1691
 
1692
- def calculate_breed_matching(breed_info: dict, user_prefs: UserPreferences) -> dict:
1693
- """計算品種的整體評分與匹配度"""
1694
- try:
1695
  print("\n=== 開始計算品種相容性分數 ===")
1696
  print(f"處理品種: {breed_info.get('Breed', 'Unknown')}")
1697
  print(f"品種信息: {breed_info}")
@@ -1699,46 +1074,58 @@ def calculate_breed_matching(breed_info: dict, user_prefs: UserPreferences) -> d
1699
 
1700
  # 計算所有基礎分數並整合到字典中
1701
  scores = {
1702
- 'space': calculate_space_score(breed_info, user_prefs),
 
 
 
 
 
1703
  'exercise': calculate_exercise_score(
1704
  breed_info.get('Exercise Needs', 'Moderate'),
1705
  user_prefs.exercise_time,
1706
- user_prefs
1707
  ),
1708
  'grooming': calculate_grooming_score(
1709
  breed_info.get('Grooming Needs', 'Moderate'),
1710
  user_prefs.grooming_commitment.lower(),
1711
  breed_info['Size']
1712
  ),
1713
- 'experience': calculate_experience_score(breed_info, user_prefs),
 
 
 
 
1714
  'health': calculate_health_score(
1715
  breed_info.get('Breed', ''),
1716
  user_prefs
1717
  ),
1718
  'noise': calculate_noise_score(
1719
- breed_info,
1720
  user_prefs
1721
  )
1722
  }
1723
 
1724
- # 計算最終相容性分數
1725
- final_score = calculate_compatibility_score(scores, user_prefs, breed_info)
1726
-
 
 
 
1727
  # 計算環境適應性加成
1728
  adaptability_bonus = calculate_environmental_fit(breed_info, user_prefs)
1729
-
1730
  # 整合最終分數和加成
1731
  final_score = (final_score * 0.9) + (adaptability_bonus * 0.1)
1732
  final_score = amplify_score_extreme(final_score)
1733
-
1734
  # 更新並返回完整的評分結果
1735
  scores.update({
1736
  'overall': final_score,
1737
  'adaptability_bonus': adaptability_bonus
1738
  })
1739
-
1740
  return scores
1741
-
1742
  except Exception as e:
1743
  print(f"\n!!!!! 發生嚴重錯誤 !!!!!")
1744
  print(f"錯誤類型: {type(e).__name__}")
@@ -1748,328 +1135,149 @@ def calculate_breed_matching(breed_info: dict, user_prefs: UserPreferences) -> d
1748
  return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
1749
 
1750
 
1751
- # def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1752
- # """
1753
- # 改進的品種相容性評分系統
1754
- # 通過更細緻的特徵評估和動態權重調整,自然產生分數差異
1755
- # """
1756
- # # 評估關鍵特徵的匹配度,使用更極端的調整係數
1757
- # def evaluate_key_features():
1758
- # # 空間適配性評估
1759
- # space_multiplier = 1.0
1760
- # if user_prefs.living_space == 'apartment':
1761
- # if breed_info['Size'] == 'Giant':
1762
- # space_multiplier = 0.3 # 嚴重不適合
1763
- # elif breed_info['Size'] == 'Large':
1764
- # space_multiplier = 0.4 # 明顯不適合
1765
- # elif breed_info['Size'] == 'Small':
1766
- # space_multiplier = 1.4 # 明顯優勢
 
 
 
1767
 
1768
- # # 運動需求評估
1769
- # exercise_multiplier = 1.0
1770
- # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1771
- # if exercise_needs == 'VERY HIGH':
1772
- # if user_prefs.exercise_time < 60:
1773
- # exercise_multiplier = 0.3 # 嚴重不足
1774
- # elif user_prefs.exercise_time > 150:
1775
- # exercise_multiplier = 1.5 # 完美匹配
1776
- # elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150:
1777
- # exercise_multiplier = 0.5 # 運動過度
1778
 
1779
- # return space_multiplier, exercise_multiplier
1780
 
1781
- # # 計算經驗匹配度
1782
- # def evaluate_experience():
1783
- # exp_multiplier = 1.0
1784
- # care_level = breed_info.get('Care Level', 'MODERATE')
 
 
 
 
 
 
 
 
 
 
 
 
1785
 
1786
- # if care_level == 'High':
1787
- # if user_prefs.experience_level == 'beginner':
1788
- # exp_multiplier = 0.4
1789
- # elif user_prefs.experience_level == 'advanced':
1790
- # exp_multiplier = 1.3
1791
- # elif care_level == 'Low':
1792
- # if user_prefs.experience_level == 'advanced':
1793
- # exp_multiplier = 0.9 # 略微降低評分,因為可能不夠有挑戰性
1794
-
1795
- # return exp_multiplier
1796
-
1797
- # # 取得特徵調整係數
1798
- # space_mult, exercise_mult = evaluate_key_features()
1799
- # exp_mult = evaluate_experience()
1800
 
1801
- # # 調整基礎分數
1802
- # adjusted_scores = {
1803
- # 'space': scores['space'] * space_mult,
1804
- # 'exercise': scores['exercise'] * exercise_mult,
1805
- # 'experience': scores['experience'] * exp_mult,
1806
- # 'grooming': scores['grooming'],
1807
- # 'health': scores['health'],
1808
- # 'noise': scores['noise']
1809
- # }
1810
 
1811
- # # 計算加權平均,關鍵特徵佔更大權重
1812
- # weights = {
1813
- # 'space': 0.35,
1814
- # 'exercise': 0.30,
1815
- # 'experience': 0.20,
1816
- # 'grooming': 0.15,
1817
- # 'health': 0.10,
1818
- # 'noise': 0.10
1819
- # }
 
 
 
 
 
 
1820
 
1821
- # # 動態調整權重
1822
- # if user_prefs.living_space == 'apartment':
1823
- # weights['space'] *= 1.5
1824
- # weights['noise'] *= 1.3
1825
-
1826
- # if abs(user_prefs.exercise_time - 120) > 60: # 運動時間極端情況
1827
- # weights['exercise'] *= 1.4
1828
 
1829
- # # 正規化權重
1830
- # total_weight = sum(weights.values())
1831
- # normalized_weights = {k: v/total_weight for k, v in weights.items()}
 
 
 
 
 
 
1832
 
1833
- # # 計算最終分數
1834
- # final_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys())
 
 
 
 
 
 
 
1835
 
1836
- # # 品種特性加成
1837
- # breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
 
 
1838
 
1839
- # # 整合最終分數,保持在0-1範圍內
1840
- # return min(1.0, max(0.0, (final_score * 0.85) + (breed_bonus * 0.15)))
1841
 
 
 
 
1842
 
1843
- # def amplify_score_extreme(score: float) -> float:
1844
- # """
1845
- # 改進的分數轉換函數
1846
- # 提供更大的分數範圍和更明顯的差異
1847
-
1848
- # 轉換邏輯:
1849
- # - 極差匹配 (0.0-0.3) -> 60-68%
1850
- # - 較差匹配 (0.3-0.5) -> 68-75%
1851
- # - 中等匹配 (0.5-0.7) -> 75-85%
1852
- # - 良好匹配 (0.7-0.85) -> 85-92%
1853
- # - 優秀匹配 (0.85-1.0) -> 92-95%
1854
- # """
1855
- # if score < 0.3:
1856
- # # 極差匹配:快速線性增長
1857
- # return 0.60 + (score / 0.3) * 0.08
1858
- # elif score < 0.5:
1859
- # # 較差匹配:緩慢增長
1860
- # position = (score - 0.3) / 0.2
1861
- # return 0.68 + position * 0.07
1862
- # elif score < 0.7:
1863
- # # 中等匹配:穩定線性增長
1864
- # position = (score - 0.5) / 0.2
1865
- # return 0.75 + position * 0.10
1866
- # elif score < 0.85:
1867
- # # 良好匹配:加速增長
1868
- # position = (score - 0.7) / 0.15
1869
- # return 0.85 + position * 0.07
1870
- # else:
1871
- # # 優秀匹配:最後衝刺
1872
- # position = (score - 0.85) / 0.15
1873
- # return 0.92 + position * 0.03
1874
-
1875
 
1876
- def calculate_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1877
- """
1878
- 計算品種與使用者的整體相容性分數
1879
-
1880
- 這是推薦系統的核心評分函數,負責:
1881
- 1. 智能整合各面向評分
1882
- 2. 動態調整評分權重
1883
- 3. 處理關鍵條件的優先級
1884
- 4. 產生最終的匹配分數
1885
-
1886
- 評分策略:
1887
- - 基礎分數:由各項指標的加權平均獲得
1888
- - 動態權重:根據用戶情況動態調整各項權重
1889
- - 關鍵條件:某些條件不滿足會顯著降低總分
1890
- - 加成系統:特殊匹配會提供額外加分
1891
-
1892
- Parameters:
1893
- -----------
1894
- scores: 包含各項評分的字典
1895
- user_prefs: 使用者偏好設定
1896
- breed_info: 品種特性信息
1897
 
1898
- Returns:
1899
- --------
1900
- float: 60.0-95.0 之間的最終匹配分數
1901
- """
1902
- def calculate_dynamic_weights() -> dict:
1903
- """計算動態權重分配"""
1904
- # 基礎權重設定
1905
- weights = {
1906
- 'space': 0.20,
1907
- 'exercise': 0.20,
1908
- 'experience': 0.15,
1909
- 'grooming': 0.15,
1910
- 'health': 0.15,
1911
- 'noise': 0.15
1912
- }
1913
-
1914
- # 公寓住戶權重調整
1915
- if user_prefs.living_space == "apartment":
1916
- weights['space'] *= 1.3
1917
- weights['noise'] *= 1.3
1918
- weights['exercise'] *= 0.8
1919
-
1920
- # 有幼童時的權重調整
1921
- if user_prefs.has_children and user_prefs.children_age == 'toddler':
1922
- weights['experience'] *= 1.3
1923
- weights['noise'] *= 1.2
1924
- weights['health'] *= 1.2
1925
-
1926
- # 新手飼主的權重調整
1927
- if user_prefs.experience_level == 'beginner':
1928
- weights['experience'] *= 1.4
1929
- weights['health'] *= 1.2
1930
- weights['grooming'] *= 1.2
1931
-
1932
- # 健康敏感度的權重調整
1933
- if user_prefs.health_sensitivity == 'high':
1934
- weights['health'] *= 1.3
1935
-
1936
- # 運動時間極端情況的權重調整
1937
- if abs(user_prefs.exercise_time - 120) > 60:
1938
- weights['exercise'] *= 1.3
1939
-
1940
- # 正規化權重
1941
- total = sum(weights.values())
1942
- return {k: v/total for k, v in weights.items()}
1943
-
1944
- def calculate_critical_factors() -> float:
1945
- """評估關鍵因素的影響"""
1946
- critical_score = 1.0
1947
-
1948
- # 空間關鍵條件
1949
- if user_prefs.living_space == "apartment":
1950
- if breed_info['Size'] == 'Giant':
1951
- critical_score *= 0.7
1952
- elif breed_info['Size'] == 'Large':
1953
- critical_score *= 0.8
1954
-
1955
- # 運動需求關鍵條件
1956
- exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1957
- if exercise_needs == 'VERY HIGH' and user_prefs.exercise_time < 60:
1958
- critical_score *= 0.75
1959
- elif exercise_needs == 'HIGH' and user_prefs.exercise_time < 45:
1960
- critical_score *= 0.8
1961
-
1962
- # 新手飼主關鍵條件
1963
- if user_prefs.experience_level == 'beginner':
1964
- if 'aggressive' in breed_info.get('Temperament', '').lower():
1965
- critical_score *= 0.7
1966
- elif 'dominant' in breed_info.get('Temperament', '').lower():
1967
- critical_score *= 0.8
1968
-
1969
- # 噪音關鍵條件
1970
- if user_prefs.living_space == "apartment" and \
1971
- breed_info.get('Noise Level', 'MODERATE').upper() == 'HIGH' and \
1972
- user_prefs.noise_tolerance == 'low':
1973
- critical_score *= 0.7
1974
-
1975
- return critical_score
1976
 
1977
- def calculate_bonus_factors() -> float:
1978
- """計算額外加分因素"""
1979
- bonus = 1.0
1980
- temperament = breed_info.get('Temperament', '').lower()
1981
-
1982
- # 完美匹配加分
1983
- perfect_matches = 0
1984
- for score in scores.values():
1985
- if score > 0.9:
1986
- perfect_matches += 1
1987
-
1988
- if perfect_matches >= 3:
1989
- bonus += 0.05
1990
-
1991
- # 特殊匹配加分
1992
- if user_prefs.has_children and 'good with children' in temperament:
1993
- bonus += 0.03
1994
-
1995
- if user_prefs.living_space == "apartment" and 'adaptable' in temperament:
1996
- bonus += 0.03
1997
-
1998
- if user_prefs.experience_level == 'beginner' and 'easy to train' in temperament:
1999
- bonus += 0.03
2000
-
2001
- return min(1.15, bonus)
2002
-
2003
- # 計算動態權重
2004
- weights = calculate_dynamic_weights()
2005
-
2006
- # 計算基礎加權分數
2007
- base_score = sum(scores[k] * weights[k] for k in scores.keys())
2008
-
2009
- # 應用關鍵因素
2010
- critical_factor = calculate_critical_factors()
2011
-
2012
- # 計算加分
2013
- bonus_factor = calculate_bonus_factors()
2014
-
2015
- # 計算最終原始分數
2016
- raw_score = base_score * critical_factor * bonus_factor
2017
-
2018
- # 轉換為最終分數(60-95範圍)
2019
- final_score = 60 + (raw_score * 35)
2020
-
2021
- # 確保分數在合理範圍內並保留兩位小數
2022
- return round(max(60.0, min(95.0, final_score)), 2)
2023
-
2024
 
2025
  def amplify_score_extreme(score: float) -> float:
2026
  """
2027
- 將原始相容性分數(0-1)轉換為最終評分(60-95)
2028
-
2029
- 這個函數負責:
2030
- 1. 將內部計算的原始分數轉換為更有意義的最終分數
2031
- 2. 確保分數分布更自然且有區別性
2032
- 3. 突出極佳和極差的匹配
2033
- 4. 避免分數過度集中在中間區域
2034
 
2035
- 轉換策略:
2036
- - 極佳匹配(0.85-1.0):轉換為 90-95 分
2037
- - 優良匹配(0.70-0.85):轉換為 85-90 分
2038
- - 良好匹配(0.55-0.70):轉換為 75-85
2039
- - 一般匹配(0.40-0.55):轉換為 70-75 分
2040
- - 勉強匹配(0.25-0.40):轉換為 65-70 分
2041
- - 不推薦匹配(0-0.25):轉換為 60-65 分
2042
-
2043
- Parameters:
2044
- -----------
2045
- score: 原始相容性分數(0.0-1.0)
2046
-
2047
- Returns:
2048
- --------
2049
- float: 轉換後的最終分數(60.0-95.0)
2050
  """
2051
- # 使用分段函數進行更自然的轉換
2052
- if score >= 0.85:
2053
- # 極佳匹配:90-95分
2054
- position = (score - 0.85) / 0.15
2055
- return 90.0 + (position * 5.0)
2056
- elif score >= 0.70:
2057
- # 優良匹配:85-90分
2058
- position = (score - 0.70) / 0.15
2059
- return 85.0 + (position * 5.0)
2060
- elif score >= 0.55:
2061
- # 良好匹配:75-85分
2062
- position = (score - 0.55) / 0.15
2063
- return 75.0 + (position * 10.0)
2064
- elif score >= 0.40:
2065
- # 一般匹配:70-75分
2066
- position = (score - 0.40) / 0.15
2067
- return 70.0 + (position * 5.0)
2068
- elif score >= 0.25:
2069
- # 勉強匹配:65-70分
2070
- position = (score - 0.25) / 0.15
2071
- return 65.0 + (position * 5.0)
2072
  else:
2073
- # 不推薦匹配:60-65分
2074
- position = score / 0.25
2075
- return 60.0 + (position * 5.0)
 
3
  from breed_noise_info import breed_noise_info
4
  import traceback
5
  import math
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  @dataclass
8
  class UserPreferences:
9
+
10
+ """使用者偏好設定的資料結構"""
11
+ living_space: str # "apartment", "house_small", "house_large"
12
+ yard_access: str # "no_yard", "shared_yard", "private_yard"
13
+ exercise_time: int # minutes per day
14
+ exercise_type: str # "light_walks", "moderate_activity", "active_training"
15
+ grooming_commitment: str # "low", "medium", "high"
16
+ experience_level: str # "beginner", "intermediate", "advanced"
17
+ time_availability: str # "limited", "moderate", "flexible"
18
  has_children: bool
19
+ children_age: str # "toddler", "school_age", "teenager"
20
+ noise_tolerance: str # "low", "medium", "high"
21
  space_for_play: bool
22
  other_pets: bool
23
+ climate: str # "cold", "moderate", "hot"
24
+ health_sensitivity: str = "medium"
25
+ barking_acceptance: str = None
 
 
 
 
 
26
 
27
  def __post_init__(self):
28
+ """在初始化後運行,用於設置派生值"""
29
  if self.barking_acceptance is None:
30
  self.barking_acceptance = self.noise_tolerance
31
 
 
416
  raise KeyError("Size information missing")
417
 
418
 
419
+ def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
420
+ """
421
+ 主要改進:
422
+ 1. 更均衡的基礎分數分配
423
+ 2. 更細緻的空間需求評估
424
+ 3. 強化運動需求與空間的關聯性
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  """
426
+ # 重新設計基礎分數矩陣,降低普遍分數以增加區別度
427
+ base_scores = {
 
 
 
 
 
428
  "Small": {
429
+ "apartment": 0.85, # 降低滿分機會
430
+ "house_small": 0.80, # 小型犬不應在大空間得到太高分數
431
+ "house_large": 0.75 # 避免小型犬總是得到最高分
432
  },
433
  "Medium": {
434
+ "apartment": 0.45, # 維持對公寓環境的限制
435
+ "house_small": 0.75, # 適中的分數
436
+ "house_large": 0.85 # 給予合理的獎勵
437
  },
438
  "Large": {
439
+ "apartment": 0.15, # 加重對大型犬在公寓的限制
440
+ "house_small": 0.65, # 中等適合度
441
+ "house_large": 0.90 # 最適合的環境
442
  },
443
  "Giant": {
444
+ "apartment": 0.10, # 更嚴格的限制
445
+ "house_small": 0.45, # 顯著的空間限制
446
+ "house_large": 0.95 # 最理想的配對
447
  }
448
  }
449
 
450
+ # 取得基礎分數
451
+ base_score = base_scores.get(size, base_scores["Medium"])[living_space]
452
+
453
+ # 運動需求相關的調整更加動態
454
+ exercise_adjustments = {
455
+ "Very High": {
456
+ "apartment": -0.25, # 加重在受限空間的懲罰
457
+ "house_small": -0.15,
458
+ "house_large": -0.05
459
+ },
460
+ "High": {
461
+ "apartment": -0.20,
462
+ "house_small": -0.10,
463
+ "house_large": 0
464
+ },
465
+ "Moderate": {
466
+ "apartment": -0.10,
467
+ "house_small": -0.05,
468
+ "house_large": 0
469
+ },
470
+ "Low": {
471
+ "apartment": 0.05, # 低運動需求在小空間反而有優勢
472
+ "house_small": 0,
473
+ "house_large": -0.05 # 輕微降低評分,因為空間可能過大
474
+ }
 
 
 
 
475
  }
476
 
477
+ # 根據空間類型獲取運動需求調整
478
+ adjustment = exercise_adjustments.get(exercise_needs,
479
+ exercise_adjustments["Moderate"])[living_space]
480
+
481
+ # 院子效益根據品種大小和運動需求動態調整
482
+ if has_yard:
483
+ yard_bonus = {
484
+ "Giant": 0.20,
485
+ "Large": 0.15,
486
+ "Medium": 0.10,
487
+ "Small": 0.05
488
+ }.get(size, 0.10)
489
+
490
+ # 運動需求會影響院子的重要性
491
+ if exercise_needs in ["Very High", "High"]:
492
+ yard_bonus *= 1.2
493
+ elif exercise_needs == "Low":
494
+ yard_bonus *= 0.8
 
 
 
 
 
495
 
496
+ current_score = base_score + adjustment + yard_bonus
497
+ else:
498
+ current_score = base_score + adjustment
499
+
500
+ # 確保分數在合理範圍內,但避免極端值
501
+ return min(0.95, max(0.15, current_score))
 
 
 
 
 
 
 
 
 
 
 
502
 
503
 
504
+ def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
505
  """
506
+ 精確評估品種運動需求與使用者運動條件的匹配度
 
 
 
 
 
 
507
 
508
  Parameters:
 
509
  breed_needs: 品種的運動需求等級
510
  exercise_time: 使用者能提供的運動時間(分鐘)
511
+ exercise_type: 使用者偏好的運動類型
512
 
513
  Returns:
514
+ float: -0.2 到 0.2 之間的匹配分數
 
515
  """
516
+ # 定義更細緻的運動需求等級
517
  exercise_levels = {
518
  'VERY HIGH': {
519
  'min': 120,
520
  'ideal': 150,
521
  'max': 180,
522
+ 'intensity': 'high',
523
+ 'sessions': 'multiple',
524
+ 'preferred_types': ['active_training', 'intensive_exercise']
525
  },
526
  'HIGH': {
527
  'min': 90,
528
  'ideal': 120,
529
  'max': 150,
530
+ 'intensity': 'moderate_high',
531
+ 'sessions': 'multiple',
532
+ 'preferred_types': ['active_training', 'moderate_activity']
533
  },
534
+ 'MODERATE HIGH': {
535
+ 'min': 70,
536
  'ideal': 90,
537
  'max': 120,
538
+ 'intensity': 'moderate',
539
+ 'sessions': 'flexible',
540
+ 'preferred_types': ['moderate_activity', 'active_training']
541
  },
542
+ 'MODERATE': {
543
+ 'min': 45,
544
  'ideal': 60,
545
  'max': 90,
546
+ 'intensity': 'moderate',
547
+ 'sessions': 'flexible',
548
+ 'preferred_types': ['moderate_activity', 'light_walks']
549
+ },
550
+ 'MODERATE LOW': {
551
+ 'min': 30,
552
+ 'ideal': 45,
553
+ 'max': 70,
554
+ 'intensity': 'light_moderate',
555
+ 'sessions': 'flexible',
556
+ 'preferred_types': ['light_walks', 'moderate_activity']
557
+ },
558
+ 'LOW': {
559
+ 'min': 15,
560
+ 'ideal': 30,
561
+ 'max': 45,
562
+ 'intensity': 'light',
563
+ 'sessions': 'single',
564
+ 'preferred_types': ['light_walks']
565
  }
566
  }
567
 
568
+ # 獲取品種的運動需求配置
569
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
570
 
571
+ # 計算時間匹配度(使用更平滑的評分曲線)
572
+ if exercise_time >= breed_level['ideal']:
573
+ if exercise_time > breed_level['max']:
574
+ # 運動時間過長,適度降分
575
+ time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30)
 
 
 
 
 
 
576
  else:
577
+ time_score = 0.15
578
+ elif exercise_time >= breed_level['min']:
579
+ # 在最小需求和理想需求之間,線性計算分數
580
+ time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
581
+ time_score = 0.05 + (time_ratio * 0.10)
582
+ else:
583
+ # 運動時間不足,根據差距程度扣分
584
+ time_ratio = max(0, exercise_time / breed_level['min'])
585
+ time_score = -0.15 * (1 - time_ratio)
586
+
587
+ # 運動類型匹配度評估
588
+ type_score = 0.0
589
+ if exercise_type in breed_level['preferred_types']:
590
+ type_score = 0.05
591
+ if exercise_type == breed_level['preferred_types'][0]:
592
+ type_score = 0.08 # 最佳匹配類型給予更高分數
593
+
594
+ return max(-0.2, min(0.2, time_score + type_score))
 
 
 
 
 
 
 
 
595
 
596
 
597
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
 
725
  return max(0.1, min(1.0, final_score))
726
 
727
 
728
+ def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
729
  """
730
+ 計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
 
 
 
 
 
 
 
 
 
 
 
 
731
 
732
+ 重要改進:
733
+ 1. 擴大基礎分數差異
734
+ 2. 加重困難特徵的懲罰
735
+ 3. 更細緻的品種特性評估
 
 
 
 
736
  """
737
+ # 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
738
+ base_scores = {
739
+ "High": {
740
+ "beginner": 0.10, # 降低起始分,高難度品種對新手幾乎不推薦
741
+ "intermediate": 0.60, # 中級玩家仍需謹慎
742
+ "advanced": 1.0 # 資深者能完全勝任
 
 
 
 
743
  },
744
+ "Moderate": {
745
+ "beginner": 0.35, # 適中難度對新手仍具挑戰
746
+ "intermediate": 0.80, # 中級玩家較適合
747
+ "advanced": 1.0 # 資深者完全勝任
748
  },
749
+ "Low": {
750
+ "beginner": 0.90, # 新手友善品種
751
+ "intermediate": 0.95, # 中級玩家幾乎完全勝任
752
+ "advanced": 1.0 # 資深者完全勝任
753
  }
754
  }
755
 
756
+ # 取得基礎分數
757
+ score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
 
759
+ temperament_lower = temperament.lower()
760
+ temperament_adjustments = 0.0
761
 
762
+ # 根據經驗等級設定不同的特徵評估標準
763
+ if user_experience == "beginner":
764
+ # 新手不適合的特徵 - 更嚴格的懲罰
 
 
 
765
  difficult_traits = {
766
+ 'stubborn': -0.30, # 固執性格嚴重影響新手
767
+ 'independent': -0.25, # 獨立性高的品種不適合新手
768
+ 'dominant': -0.25, # 支配性強的品種需要經驗處理
769
+ 'strong-willed': -0.20, # 強勢性格需要技巧管理
770
+ 'protective': -0.20, # 保護性強需要適當訓練
771
+ 'aloof': -0.15, # 冷漠性格需要耐心培養
772
+ 'energetic': -0.15, # 活潑好動需要經驗引導
773
+ 'aggressive': -0.35 # 攻擊傾向極不適合新手
774
  }
775
 
776
+ # 新手友善的特徵 - 適度的獎勵
777
+ easy_traits = {
778
+ 'gentle': 0.05, # 溫和性格適合新手
779
+ 'friendly': 0.05, # 友善性格容易相處
780
+ 'eager to please': 0.08, # 願意服從較容易訓練
781
+ 'patient': 0.05, # 耐心的特質有助於建立關係
782
+ 'adaptable': 0.05, # 適應性強較容易照顧
783
+ 'calm': 0.06 # 冷靜的性格較好掌握
784
  }
785
 
786
+ # 計算特徵調整
787
+ for trait, penalty in difficult_traits.items():
788
+ if trait in temperament_lower:
789
+ temperament_adjustments += penalty
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
 
791
+ for trait, bonus in easy_traits.items():
792
+ if trait in temperament_lower:
793
+ temperament_adjustments += bonus
794
+
795
+ # 品種類型特殊評估
796
+ if 'terrier' in temperament_lower:
797
+ temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
798
+ elif 'working' in temperament_lower:
799
+ temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
800
+ elif 'guard' in temperament_lower:
801
+ temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
802
+
803
+ elif user_experience == "intermediate":
804
+ # 中級玩家的特徵評估
805
+ moderate_traits = {
806
+ 'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
807
+ 'independent': -0.10,
808
+ 'intelligent': 0.08, # 聰明的特質可以好好發揮
809
+ 'athletic': 0.06, # 運動能力可以適當訓練
810
+ 'versatile': 0.07, # 多功能性可以開發
811
+ 'protective': -0.08 # 保護性仍需注意
812
  }
813
 
814
+ for trait, adjustment in moderate_traits.items():
815
+ if trait in temperament_lower:
816
+ temperament_adjustments += adjustment
817
 
818
+ else: # advanced
819
+ # 資深玩家能夠應對挑戰性特徵
820
+ advanced_traits = {
821
+ 'stubborn': 0.05, # 困難特徵反而成為優勢
822
+ 'independent': 0.05,
823
+ 'intelligent': 0.10,
824
+ 'protective': 0.05,
825
+ 'strong-willed': 0.05
826
+ }
827
 
828
+ for trait, bonus in advanced_traits.items():
829
+ if trait in temperament_lower:
830
+ temperament_adjustments += bonus
831
 
832
+ # 確保最終分數範圍更大,讓差異更明顯
833
+ final_score = max(0.05, min(1.0, score + temperament_adjustments))
834
 
835
+ return final_score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836
 
837
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
838
  """
 
942
  return max(0.1, min(1.0, health_score))
943
 
944
 
945
+ def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
946
+ """
947
+ 計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
948
+ """
949
+ if breed_name not in breed_noise_info:
950
+ return 0.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951
 
952
+ noise_info = breed_noise_info[breed_name]
953
+ noise_level = noise_info['noise_level'].lower()
954
+ noise_notes = noise_info['noise_notes'].lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955
 
956
+ # 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
957
+ base_scores = {
958
+ 'low': {
959
+ 'low': 1.0, # 安靜的狗對低容忍完美匹配
960
+ 'medium': 0.95, # 安靜的狗對一般容忍很好
961
+ 'high': 0.90 # 安靜的狗對高容忍當然可以
962
+ },
963
+ 'medium': {
964
+ 'low': 0.60, # 一般吠叫對低容忍較困難
965
+ 'medium': 0.90, # 一般吠叫對一般容忍可接受
966
+ 'high': 0.95 # 一般吠叫對高容忍很好
967
+ },
968
+ 'high': {
969
+ 'low': 0.25, # 愛叫的狗對低容忍極不適合
970
+ 'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
971
+ 'high': 0.90 # 愛叫的狗對高容忍可以接受
972
+ },
973
+ 'varies': {
974
+ 'low': 0.50, # 不確定的情況對低容忍風險較大
975
+ 'medium': 0.75, # 不確定的情況對一般容忍可嘗試
976
+ 'high': 0.85 # 不確定的情況對高容忍問題較小
977
+ }
978
+ }
979
 
980
+ # 取得基礎分數
981
+ base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
 
 
 
 
 
 
982
 
983
+ # 吠叫原因評估,根據環境調整懲罰程度
984
+ barking_penalties = {
985
+ 'separation anxiety': {
986
+ 'apartment': -0.30, # 在公寓對鄰居影響更大
987
+ 'house_small': -0.25,
988
+ 'house_large': -0.20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
989
  },
990
+ 'excessive barking': {
991
+ 'apartment': -0.25,
992
+ 'house_small': -0.20,
993
+ 'house_large': -0.15
 
 
 
 
 
 
 
 
 
 
 
 
994
  },
995
+ 'territorial': {
996
+ 'apartment': -0.20, # 在公寓更容易被觸發
997
+ 'house_small': -0.15,
998
+ 'house_large': -0.10
999
+ },
1000
+ 'alert barking': {
1001
+ 'apartment': -0.15, # 公寓環境刺激較多
1002
+ 'house_small': -0.10,
1003
+ 'house_large': -0.08
1004
+ },
1005
+ 'attention seeking': {
1006
+ 'apartment': -0.15,
1007
+ 'house_small': -0.12,
1008
+ 'house_large': -0.10
 
 
1009
  }
1010
  }
1011
+
1012
+ # 計算環境相關的吠叫懲罰
1013
+ living_space = user_prefs.living_space
1014
+ barking_penalty = 0
1015
+ for trigger, penalties in barking_penalties.items():
1016
+ if trigger in noise_notes:
1017
+ barking_penalty += penalties.get(living_space, -0.15)
1018
+
1019
+ # 特殊情況評估
1020
+ special_adjustments = 0
1021
+ if user_prefs.has_children:
1022
+ # 孩童年齡相關調整
1023
+ child_age_adjustments = {
1024
+ 'toddler': {
1025
+ 'high': -0.20, # 幼童對吵鬧更敏感
1026
+ 'medium': -0.15,
1027
+ 'low': -0.05
 
 
 
 
1028
  },
1029
+ 'school_age': {
1030
+ 'high': -0.15,
1031
+ 'medium': -0.10,
1032
+ 'low': -0.05
1033
  },
1034
+ 'teenager': {
1035
+ 'high': -0.10,
1036
+ 'medium': -0.05,
1037
+ 'low': -0.02
1038
  }
1039
  }
1040
 
1041
+ # 根據孩童年齡和噪音等級調整
1042
+ age_adj = child_age_adjustments.get(user_prefs.children_age,
1043
+ child_age_adjustments['school_age'])
1044
+ special_adjustments += age_adj.get(noise_level, -0.10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1045
 
1046
+ # 訓練性補償評估
1047
+ trainability_bonus = 0
1048
+ if 'responds well to training' in noise_notes:
1049
+ trainability_bonus = 0.12
1050
+ elif 'can be trained' in noise_notes:
1051
+ trainability_bonus = 0.08
1052
+ elif 'difficult to train' in noise_notes:
1053
+ trainability_bonus = 0.02
1054
+
1055
+ # 夜間吠叫特別考量
1056
+ if 'night barking' in noise_notes or 'howls' in noise_notes:
1057
+ if user_prefs.living_space == 'apartment':
1058
+ special_adjustments -= 0.15
1059
+ elif user_prefs.living_space == 'house_small':
1060
+ special_adjustments -= 0.10
1061
+ else:
1062
+ special_adjustments -= 0.05
1063
+
1064
+ # 計算最終分數,確保更大的分數範圍
1065
+ final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1066
+ return max(0.1, min(1.0, final_score))
1067
+
1068
 
1069
+ # 1. 計算基礎分數
 
 
1070
  print("\n=== 開始計算品種相容性分數 ===")
1071
  print(f"處理品種: {breed_info.get('Breed', 'Unknown')}")
1072
  print(f"品種信息: {breed_info}")
 
1074
 
1075
  # 計算所有基礎分數並整合到字典中
1076
  scores = {
1077
+ 'space': calculate_space_score(
1078
+ breed_info['Size'],
1079
+ user_prefs.living_space,
1080
+ user_prefs.yard_access != 'no_yard',
1081
+ breed_info.get('Exercise Needs', 'Moderate')
1082
+ ),
1083
  'exercise': calculate_exercise_score(
1084
  breed_info.get('Exercise Needs', 'Moderate'),
1085
  user_prefs.exercise_time,
1086
+ user_prefs.exercise_type
1087
  ),
1088
  'grooming': calculate_grooming_score(
1089
  breed_info.get('Grooming Needs', 'Moderate'),
1090
  user_prefs.grooming_commitment.lower(),
1091
  breed_info['Size']
1092
  ),
1093
+ 'experience': calculate_experience_score(
1094
+ breed_info.get('Care Level', 'Moderate'),
1095
+ user_prefs.experience_level,
1096
+ breed_info.get('Temperament', '')
1097
+ ),
1098
  'health': calculate_health_score(
1099
  breed_info.get('Breed', ''),
1100
  user_prefs
1101
  ),
1102
  'noise': calculate_noise_score(
1103
+ breed_info.get('Breed', ''),
1104
  user_prefs
1105
  )
1106
  }
1107
 
1108
+ final_score = calculate_breed_compatibility_score(
1109
+ scores=scores,
1110
+ user_prefs=user_prefs,
1111
+ breed_info=breed_info
1112
+ )
1113
+
1114
  # 計算環境適應性加成
1115
  adaptability_bonus = calculate_environmental_fit(breed_info, user_prefs)
1116
+
1117
  # 整合最終分數和加成
1118
  final_score = (final_score * 0.9) + (adaptability_bonus * 0.1)
1119
  final_score = amplify_score_extreme(final_score)
1120
+
1121
  # 更新並返回完整的評分結果
1122
  scores.update({
1123
  'overall': final_score,
1124
  'adaptability_bonus': adaptability_bonus
1125
  })
1126
+
1127
  return scores
1128
+
1129
  except Exception as e:
1130
  print(f"\n!!!!! 發生嚴重錯誤 !!!!!")
1131
  print(f"錯誤類型: {type(e).__name__}")
 
1135
  return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
1136
 
1137
 
1138
+ def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -> float:
1139
+ """計算品種與環境的適應性加成"""
1140
+ adaptability_score = 0.0
1141
+ description = breed_info.get('Description', '').lower()
1142
+ temperament = breed_info.get('Temperament', '').lower()
1143
+
1144
+ # ���境適應性評估
1145
+ if user_prefs.living_space == 'apartment':
1146
+ if 'adaptable' in temperament or 'apartment' in description:
1147
+ adaptability_score += 0.1
1148
+ if breed_info.get('Size') == 'Small':
1149
+ adaptability_score += 0.05
1150
+ elif user_prefs.living_space == 'house_large':
1151
+ if 'active' in temperament or 'energetic' in description:
1152
+ adaptability_score += 0.1
1153
+
1154
+ # 氣候適應性
1155
+ if user_prefs.climate in description or user_prefs.climate in temperament:
1156
+ adaptability_score += 0.05
1157
 
1158
+ return min(0.2, adaptability_score)
 
 
 
 
 
 
 
 
 
1159
 
 
1160
 
1161
+ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1162
+ """
1163
+ 改進的品種相容性評分系統
1164
+ 通過更細緻的特徵評估和動態權重調整,自然產生分數差異
1165
+ """
1166
+ # 評估關鍵特徵的匹配度,使用更極端的調整係數
1167
+ def evaluate_key_features():
1168
+ # 空間適配性評估
1169
+ space_multiplier = 1.0
1170
+ if user_prefs.living_space == 'apartment':
1171
+ if breed_info['Size'] == 'Giant':
1172
+ space_multiplier = 0.3 # 嚴重不適合
1173
+ elif breed_info['Size'] == 'Large':
1174
+ space_multiplier = 0.4 # 明顯不適合
1175
+ elif breed_info['Size'] == 'Small':
1176
+ space_multiplier = 1.4 # 明顯優勢
1177
 
1178
+ # 運動需求評估
1179
+ exercise_multiplier = 1.0
1180
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1181
+ if exercise_needs == 'VERY HIGH':
1182
+ if user_prefs.exercise_time < 60:
1183
+ exercise_multiplier = 0.3 # 嚴重不足
1184
+ elif user_prefs.exercise_time > 150:
1185
+ exercise_multiplier = 1.5 # 完美匹配
1186
+ elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150:
1187
+ exercise_multiplier = 0.5 # 運動過度
 
 
 
 
1188
 
1189
+ return space_multiplier, exercise_multiplier
 
 
 
 
 
 
 
 
1190
 
1191
+ # 計算經驗匹配度
1192
+ def evaluate_experience():
1193
+ exp_multiplier = 1.0
1194
+ care_level = breed_info.get('Care Level', 'MODERATE')
1195
+
1196
+ if care_level == 'High':
1197
+ if user_prefs.experience_level == 'beginner':
1198
+ exp_multiplier = 0.4
1199
+ elif user_prefs.experience_level == 'advanced':
1200
+ exp_multiplier = 1.3
1201
+ elif care_level == 'Low':
1202
+ if user_prefs.experience_level == 'advanced':
1203
+ exp_multiplier = 0.9 # 略微降低評分,因為可能不夠有挑戰性
1204
+
1205
+ return exp_multiplier
1206
 
1207
+ # 取得特徵調整係數
1208
+ space_mult, exercise_mult = evaluate_key_features()
1209
+ exp_mult = evaluate_experience()
 
 
 
 
1210
 
1211
+ # 調整基礎分數
1212
+ adjusted_scores = {
1213
+ 'space': scores['space'] * space_mult,
1214
+ 'exercise': scores['exercise'] * exercise_mult,
1215
+ 'experience': scores['experience'] * exp_mult,
1216
+ 'grooming': scores['grooming'],
1217
+ 'health': scores['health'],
1218
+ 'noise': scores['noise']
1219
+ }
1220
 
1221
+ # 計算加權平均,關鍵特徵佔更大權重
1222
+ weights = {
1223
+ 'space': 0.35,
1224
+ 'exercise': 0.30,
1225
+ 'experience': 0.20,
1226
+ 'grooming': 0.15,
1227
+ 'health': 0.10,
1228
+ 'noise': 0.10
1229
+ }
1230
 
1231
+ # 動態調整權重
1232
+ if user_prefs.living_space == 'apartment':
1233
+ weights['space'] *= 1.5
1234
+ weights['noise'] *= 1.3
1235
 
1236
+ if abs(user_prefs.exercise_time - 120) > 60: # 運動時間極端情況
1237
+ weights['exercise'] *= 1.4
1238
 
1239
+ # 正規化權重
1240
+ total_weight = sum(weights.values())
1241
+ normalized_weights = {k: v/total_weight for k, v in weights.items()}
1242
 
1243
+ # 計算最終分數
1244
+ final_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1245
 
1246
+ # 品種特性加成
1247
+ breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1248
 
1249
+ # 整合最終分數,保持在0-1範圍內
1250
+ return min(1.0, max(0.0, (final_score * 0.85) + (breed_bonus * 0.15)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1252
 
1253
  def amplify_score_extreme(score: float) -> float:
1254
  """
1255
+ 改進的分數轉換函數
1256
+ 提供更大的分數範圍和更明顯的差異
 
 
 
 
 
1257
 
1258
+ 轉換邏輯:
1259
+ - 極差匹配 (0.0-0.3) -> 60-68%
1260
+ - 較差匹配 (0.3-0.5) -> 68-75%
1261
+ - 中等匹配 (0.5-0.7) -> 75-85%
1262
+ - 良好匹配 (0.7-0.85) -> 85-92%
1263
+ - 優秀匹配 (0.85-1.0) -> 92-95%
 
 
 
 
 
 
 
 
 
1264
  """
1265
+ if score < 0.3:
1266
+ # 極差匹配:快速線性增長
1267
+ return 0.60 + (score / 0.3) * 0.08
1268
+ elif score < 0.5:
1269
+ # 較差匹配:緩慢增長
1270
+ position = (score - 0.3) / 0.2
1271
+ return 0.68 + position * 0.07
1272
+ elif score < 0.7:
1273
+ # 中等匹配:穩定線性增長
1274
+ position = (score - 0.5) / 0.2
1275
+ return 0.75 + position * 0.10
1276
+ elif score < 0.85:
1277
+ # 良好匹配:加速增長
1278
+ position = (score - 0.7) / 0.15
1279
+ return 0.85 + position * 0.07
 
 
 
 
 
 
1280
  else:
1281
+ # 優秀匹配:最後衝刺
1282
+ position = (score - 0.85) / 0.15
1283
+ return 0.92 + position * 0.03