DawnC commited on
Commit
230a819
1 Parent(s): e6e4287

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +1202 -744
scoring_calculation_system.py CHANGED
@@ -5,28 +5,67 @@ 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
 
@@ -157,242 +196,7 @@ def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> fl
157
  bonus += min(0.15, adaptability_bonus)
158
 
159
  return min(0.5, max(-0.25, bonus))
160
-
161
-
162
- # @staticmethod
163
- # def calculate_breed_bonus(breed_info: dict, user_prefs: UserPreferences) -> float:
164
- # """
165
- # 計算品種的額外加分,評估品種的特殊特徵對使用者需求的適配性。
166
-
167
- # 這個函數考慮四個主要面向:
168
- # 1. 壽命評估:考慮飼養的長期承諾
169
- # 2. 性格特徵評估:評估品種性格與使用者需求的匹配度
170
- # 3. 環境適應性:評估品種在特定生活環境中的表現
171
- # 4. 家庭相容性:特別關注品種與家庭成員的互動
172
- # """
173
- # bonus = 0.0
174
- # temperament = breed_info.get('Temperament', '').lower()
175
- # description = breed_info.get('Description', '').lower()
176
-
177
- # # 壽命評估 - 重新設計以反映更實際的考量
178
- # try:
179
- # lifespan = breed_info.get('Lifespan', '10-12 years')
180
- # years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
181
- # avg_years = float(years[0])
182
-
183
- # # 根據壽命長短給予不同程度的獎勵或懲罰
184
- # if avg_years < 8:
185
- # bonus -= 0.08 # 短壽命可能帶來情感負擔
186
- # elif avg_years < 10:
187
- # bonus -= 0.04 # 稍短壽命輕微降低評分
188
- # elif avg_years > 13:
189
- # bonus += 0.06 # 長壽命適度加分
190
- # elif avg_years > 15:
191
- # bonus += 0.08 # 特別長壽的品種獲得更多加分
192
- # except:
193
- # pass
194
-
195
- # # 性格特徵評估 - 擴充並細化評分標準
196
- # positive_traits = {
197
- # 'friendly': 0.08, # 提高友善性的重要性
198
- # 'gentle': 0.08, # 溫和性格更受歡迎
199
- # 'patient': 0.07, # 耐心是重要特質
200
- # 'intelligent': 0.06, # 聰明但不過分重要
201
- # 'adaptable': 0.06, # 適應性佳的特質
202
- # 'affectionate': 0.06, # 親密性很重要
203
- # 'easy-going': 0.05, # 容易相處的性格
204
- # 'calm': 0.05 # 冷靜的特質
205
- # }
206
-
207
- # negative_traits = {
208
- # 'aggressive': -0.15, # 嚴重懲罰攻擊性
209
- # 'stubborn': -0.10, # 固執性格不易處理
210
- # 'dominant': -0.10, # 支配性可能造成問題
211
- # 'aloof': -0.08, # 冷漠性格影響互動
212
- # 'nervous': -0.08, # 緊張性格需要更多關注
213
- # 'protective': -0.06 # 過度保護可能有風險
214
- # }
215
-
216
- # # 性格評分計算 - 加入累積效應
217
- # personality_score = 0
218
- # positive_count = 0
219
- # negative_count = 0
220
-
221
- # for trait, value in positive_traits.items():
222
- # if trait in temperament:
223
- # personality_score += value
224
- # positive_count += 1
225
-
226
- # for trait, value in negative_traits.items():
227
- # if trait in temperament:
228
- # personality_score += value
229
- # negative_count += 1
230
 
231
- # # 多重特徵的累積效應
232
- # if positive_count > 2:
233
- # personality_score *= (1 + (positive_count - 2) * 0.1)
234
- # if negative_count > 1:
235
- # personality_score *= (1 - (negative_count - 1) * 0.15)
236
-
237
- # bonus += max(-0.25, min(0.25, personality_score))
238
-
239
- # # 適應性評估 - 根據具體環境給予更細緻的評分
240
- # adaptability_bonus = 0.0
241
- # if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
242
- # adaptability_bonus += 0.08 # 小型犬更適合公寓
243
-
244
- # # 環境適應性評估
245
- # if 'adaptable' in temperament or 'versatile' in temperament:
246
- # if user_prefs.living_space == "apartment":
247
- # adaptability_bonus += 0.10 # 適應性在公寓環境更重要
248
- # else:
249
- # adaptability_bonus += 0.05 # 其他環境仍有加分
250
-
251
- # # 氣候適應性
252
- # description = breed_info.get('Description', '').lower()
253
- # climate = user_prefs.climate
254
- # if climate == 'hot':
255
- # if 'heat tolerant' in description or 'warm climate' in description:
256
- # adaptability_bonus += 0.08
257
- # elif 'thick coat' in description or 'cold climate' in description:
258
- # adaptability_bonus -= 0.10
259
- # elif climate == 'cold':
260
- # if 'thick coat' in description or 'cold climate' in description:
261
- # adaptability_bonus += 0.08
262
- # elif 'heat tolerant' in description or 'short coat' in description:
263
- # adaptability_bonus -= 0.10
264
-
265
- # bonus += min(0.15, adaptability_bonus)
266
-
267
- # # 家庭相容性評估 - 特別關注有孩童的家庭
268
- # if user_prefs.has_children:
269
- # family_traits = {
270
- # 'good with children': 0.12, # 提高與孩童相處的重要性
271
- # 'patient': 0.10,
272
- # 'gentle': 0.10,
273
- # 'tolerant': 0.08,
274
- # 'playful': 0.06
275
- # }
276
-
277
- # unfriendly_traits = {
278
- # 'aggressive': -0.15, # 加重攻擊性的懲罰
279
- # 'nervous': -0.12, # 緊張特質可能有風險
280
- # 'protective': -0.10, # 過度保護性需要注意
281
- # 'territorial': -0.08 # 地域性可能造成問題
282
- # }
283
-
284
- # # 根據孩童年齡調整評分權重
285
- # age_adjustments = {
286
- # 'toddler': {
287
- # 'bonus_mult': 0.6, # 降低正面特質的獎勵
288
- # 'penalty_mult': 1.5 # 加重負面特質的懲罰
289
- # },
290
- # 'school_age': {
291
- # 'bonus_mult': 1.0,
292
- # 'penalty_mult': 1.0
293
- # },
294
- # 'teenager': {
295
- # 'bonus_mult': 1.2, # 提高正面特質的獎勵
296
- # 'penalty_mult': 0.8 # 降低負面特質的懲罰
297
- # }
298
- # }
299
-
300
- # adj = age_adjustments.get(user_prefs.children_age,
301
- # {'bonus_mult': 1.0, 'penalty_mult': 1.0})
302
-
303
- # # 計算家庭相容性分數
304
- # family_score = 0
305
- # for trait, value in family_traits.items():
306
- # if trait in temperament:
307
- # family_score += value * adj['bonus_mult']
308
-
309
- # for trait, value in unfriendly_traits.items():
310
- # if trait in temperament:
311
- # family_score += value * adj['penalty_mult']
312
-
313
- # bonus += min(0.20, max(-0.30, family_score))
314
-
315
- # # 確保總體加分在合理範圍內,但允許更大的變化
316
- # return min(0.5, max(-0.35, bonus))
317
-
318
-
319
- # @staticmethod
320
- # def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
321
- # """計算額外的評估因素"""
322
- # factors = {
323
- # 'versatility': 0.0, # 多功能性
324
- # 'trainability': 0.0, # 可訓練度
325
- # 'energy_level': 0.0, # 能量水平
326
- # 'grooming_needs': 0.0, # 美容需求
327
- # 'social_needs': 0.0, # 社交需求
328
- # 'weather_adaptability': 0.0 # 氣候適應性
329
- # }
330
-
331
- # temperament = breed_info.get('Temperament', '').lower()
332
- # size = breed_info.get('Size', 'Medium')
333
-
334
- # # 1. 多功能性評估
335
- # versatile_traits = ['intelligent', 'adaptable', 'trainable', 'athletic']
336
- # working_roles = ['working', 'herding', 'hunting', 'sporting', 'companion']
337
-
338
- # trait_score = sum(0.2 for trait in versatile_traits if trait in temperament)
339
- # role_score = sum(0.2 for role in working_roles if role in breed_info.get('Description', '').lower())
340
-
341
- # factors['versatility'] = min(1.0, trait_score + role_score)
342
-
343
- # # 2. 可訓練度評估
344
- # trainable_traits = {
345
- # 'intelligent': 0.3,
346
- # 'eager to please': 0.3,
347
- # 'trainable': 0.2,
348
- # 'quick learner': 0.2
349
- # }
350
- # factors['trainability'] = min(1.0, sum(value for trait, value in trainable_traits.items()
351
- # if trait in temperament))
352
-
353
- # # 3. 能量水平評估
354
- # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
355
- # energy_levels = {
356
- # 'VERY HIGH': 1.0,
357
- # 'HIGH': 0.8,
358
- # 'MODERATE': 0.6,
359
- # 'LOW': 0.4,
360
- # 'VARIES': 0.6
361
- # }
362
- # factors['energy_level'] = energy_levels.get(exercise_needs, 0.6)
363
-
364
- # # 4. 美容需求評估
365
- # grooming_needs = breed_info.get('Grooming Needs', 'MODERATE').upper()
366
- # grooming_levels = {
367
- # 'HIGH': 1.0,
368
- # 'MODERATE': 0.6,
369
- # 'LOW': 0.3
370
- # }
371
- # coat_penalty = 0.2 if any(term in breed_info.get('Description', '').lower()
372
- # for term in ['long coat', 'double coat']) else 0
373
- # factors['grooming_needs'] = min(1.0, grooming_levels.get(grooming_needs, 0.6) + coat_penalty)
374
-
375
- # # 5. 社交需求評估
376
- # social_traits = ['friendly', 'social', 'affectionate', 'people-oriented']
377
- # antisocial_traits = ['independent', 'aloof', 'reserved']
378
-
379
- # social_score = sum(0.25 for trait in social_traits if trait in temperament)
380
- # antisocial_score = sum(-0.2 for trait in antisocial_traits if trait in temperament)
381
- # factors['social_needs'] = min(1.0, max(0.0, social_score + antisocial_score))
382
-
383
- # # 6. 氣候適應性評估
384
- # climate_terms = {
385
- # 'cold': ['thick coat', 'winter', 'cold climate'],
386
- # 'hot': ['short coat', 'warm climate', 'heat tolerant'],
387
- # 'moderate': ['adaptable', 'all climate']
388
- # }
389
-
390
- # climate_matches = sum(1 for term in climate_terms[user_prefs.climate]
391
- # if term in breed_info.get('Description', '').lower())
392
- # factors['weather_adaptability'] = min(1.0, climate_matches * 0.3 + 0.4) # 基礎分0.4
393
-
394
- # return factors
395
-
396
 
397
  @staticmethod
398
  def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
@@ -653,37 +457,43 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
653
 
654
 
655
  # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
656
- # # 重新設計基礎分數矩陣
 
 
 
 
 
 
657
  # base_scores = {
658
  # "Small": {
659
- # "apartment": 1.0, # 小型犬最適合公寓
660
- # "house_small": 0.95, # 在大房子反而稍微降分
661
- # "house_large": 0.85 # 可能浪費空間
662
  # },
663
  # "Medium": {
664
- # "apartment": 0.45, # 中型犬在公寓明顯受限
665
- # "house_small": 0.85,
666
- # "house_large": 1.0
667
  # },
668
  # "Large": {
669
- # "apartment": 0.15, # 大型犬在公寓極不適合
670
- # "house_small": 0.60, # 在小房子仍然受限
671
- # "house_large": 1.0
672
  # },
673
  # "Giant": {
674
- # "apartment": 0.1, # 更嚴格的限制
675
- # "house_small": 0.45,
676
- # "house_large": 1.0
677
  # }
678
  # }
679
 
680
  # # 取得基礎分數
681
  # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
682
 
683
- # # 運動需求調整更明顯
684
  # exercise_adjustments = {
685
  # "Very High": {
686
- # "apartment": -0.25, # 在公寓更嚴重的懲罰
687
  # "house_small": -0.15,
688
  # "house_large": -0.05
689
  # },
@@ -698,250 +508,352 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
698
  # "house_large": 0
699
  # },
700
  # "Low": {
701
- # "apartment": 0.05,
702
  # "house_small": 0,
703
- # "house_large": 0
704
  # }
705
  # }
706
 
707
- # # 根據空間類型獲取對應的運動調整
708
  # adjustment = exercise_adjustments.get(exercise_needs,
709
  # exercise_adjustments["Moderate"])[living_space]
710
 
711
- # # 院子獎勵也要根據犬種大小調整
712
- # yard_bonus = 0
713
  # if has_yard:
714
- # if size in ["Large", "Giant"]:
715
- # yard_bonus = 0.20 if living_space != "apartment" else 0.10
716
- # elif size == "Medium":
717
- # yard_bonus = 0.15 if living_space != "apartment" else 0.08
718
- # else:
719
- # yard_bonus = 0.10 if living_space != "apartment" else 0.05
 
 
 
 
 
 
720
 
721
- # final_score = base_score + adjustment + yard_bonus
722
- # return min(1.0, max(0.1, final_score))
 
 
 
 
723
 
724
 
725
- def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  """
727
- 優化的空間分數計算函數
728
 
729
- 主要改進:
730
- 1. 更均衡的基礎分數分配
731
- 2. 更細緻的空間需求評估
732
- 3. 強化運動需求與空間的關聯性
 
 
 
 
 
 
 
 
 
 
 
733
  """
734
- # 重新設計基礎分數矩陣,降低普遍分數以增加區別度
735
- base_scores = {
 
 
 
 
 
736
  "Small": {
737
- "apartment": 0.85, # 降低滿分機會
738
- "house_small": 0.80, # 小型犬不應在大空間得到太高分數
739
- "house_large": 0.75 # 避免小型犬總是得到最高分
740
  },
741
  "Medium": {
742
- "apartment": 0.45, # 維持對公寓環境的限制
743
- "house_small": 0.75, # 適中的分數
744
- "house_large": 0.85 # 給予合理的獎勵
745
  },
746
  "Large": {
747
- "apartment": 0.15, # 加重對大型犬在公寓的限制
748
- "house_small": 0.65, # 中等適合度
749
- "house_large": 0.90 # 最適合的環境
750
  },
751
  "Giant": {
752
- "apartment": 0.10, # 更嚴格的限制
753
- "house_small": 0.45, # 顯著的空間限制
754
- "house_large": 0.95 # 最理想的配對
755
  }
756
  }
757
 
758
- # 取得基礎分數
759
- base_score = base_scores.get(size, base_scores["Medium"])[living_space]
760
-
761
- # 運動需求相關的調整更加動態
762
- exercise_adjustments = {
763
- "Very High": {
764
- "apartment": -0.25, # 加重在受限空間的懲罰
765
- "house_small": -0.15,
766
- "house_large": -0.05
767
- },
768
- "High": {
769
- "apartment": -0.20,
770
- "house_small": -0.10,
771
- "house_large": 0
772
- },
773
- "Moderate": {
774
- "apartment": -0.10,
775
- "house_small": -0.05,
776
- "house_large": 0
777
- },
778
- "Low": {
779
- "apartment": 0.05, # 低運動需求在小空間反而有優勢
780
- "house_small": 0,
781
- "house_large": -0.05 # 輕微降低評分,因為空間可能過大
782
- }
783
  }
784
 
785
- # 根據空間類型獲取運動需求調整
786
- adjustment = exercise_adjustments.get(exercise_needs,
787
- exercise_adjustments["Moderate"])[living_space]
788
-
789
- # 院子效益根據品種大小和運動需求動態調整
790
- if has_yard:
791
- yard_bonus = {
792
- "Giant": 0.20,
793
- "Large": 0.15,
794
- "Medium": 0.10,
795
- "Small": 0.05
796
- }.get(size, 0.10)
797
-
798
- # 運動需求會影響院子的重要性
799
- if exercise_needs in ["Very High", "High"]:
800
- yard_bonus *= 1.2
801
- elif exercise_needs == "Low":
802
- yard_bonus *= 0.8
803
-
804
- current_score = base_score + adjustment + yard_bonus
805
- else:
806
- current_score = base_score + adjustment
807
-
808
- # 確保分數在合理範圍內,但避免極端值
809
- return min(0.95, max(0.15, current_score))
810
 
811
-
812
- # def calculate_exercise_score(breed_needs: str, exercise_time: int) -> float:
813
- # """
814
- # 優化的運動需求評分系統
815
 
816
- # Parameters:
817
- # breed_needs: str - 品種的運動需求等級
818
- # exercise_time: int - 使用者可提供的運動時間(分鐘)
 
 
 
 
 
 
819
 
820
- # 改進:
821
- # 1. 更細緻的運動需求評估
822
- # 2. 更合理的時間匹配計算
823
- # 3. 避免極端評分
824
- # """
825
- # # 基礎運動需求評估
826
- # exercise_needs = {
827
- # 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
828
- # 'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
829
- # 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90},
830
- # 'LOW': {'min': 20, 'ideal': 30, 'max': 45},
831
- # 'VARIES': {'min': 30, 'ideal': 60, 'max': 90}
832
- # }
 
833
 
834
- # breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
 
 
 
 
 
 
 
835
 
836
- # # 基礎時間匹配度計算
837
- # if exercise_time >= breed_need['ideal']:
838
- # if exercise_time > breed_need['max']:
839
- # # 運動時間過長,稍微降低分數
840
- # time_score = 0.9
841
- # else:
842
- # time_score = 1.0
843
- # elif exercise_time >= breed_need['min']:
844
- # # 在最小需求和理想需求之間,線性計算分數
845
- # time_score = 0.7 + (exercise_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.3
846
- # else:
847
- # # 運動時間不足,但仍根據比例給予分數
848
- # time_score = max(0.3, 0.7 * (exercise_time / breed_need['min']))
849
 
850
- # # 確保分數在合理範圍內
851
- # return min(1.0, max(0.3, time_score))
852
 
853
 
854
- def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
855
  """
856
- 精確評估品種運動需求與使用者運動條件的匹配度
 
 
 
 
 
 
857
 
858
  Parameters:
 
859
  breed_needs: 品種的運動需求等級
860
  exercise_time: 使用者能提供的運動時間(分鐘)
861
- exercise_type: 使用者偏好的運動類型
862
 
863
  Returns:
864
- float: -0.2 到 0.2 之間的匹配分數
 
865
  """
866
- # 定義更細緻的運動需求等級
867
  exercise_levels = {
868
  'VERY HIGH': {
869
  'min': 120,
870
  'ideal': 150,
871
  'max': 180,
872
- 'intensity': 'high',
873
- 'sessions': 'multiple',
874
- 'preferred_types': ['active_training', 'intensive_exercise']
875
  },
876
  'HIGH': {
877
  'min': 90,
878
  'ideal': 120,
879
  'max': 150,
880
- 'intensity': 'moderate_high',
881
- 'sessions': 'multiple',
882
- 'preferred_types': ['active_training', 'moderate_activity']
883
  },
884
- 'MODERATE HIGH': {
885
- 'min': 70,
886
  'ideal': 90,
887
  'max': 120,
888
- 'intensity': 'moderate',
889
- 'sessions': 'flexible',
890
- 'preferred_types': ['moderate_activity', 'active_training']
891
  },
892
- 'MODERATE': {
893
- 'min': 45,
894
  'ideal': 60,
895
  'max': 90,
896
- 'intensity': 'moderate',
897
- 'sessions': 'flexible',
898
- 'preferred_types': ['moderate_activity', 'light_walks']
899
- },
900
- 'MODERATE LOW': {
901
- 'min': 30,
902
- 'ideal': 45,
903
- 'max': 70,
904
- 'intensity': 'light_moderate',
905
- 'sessions': 'flexible',
906
- 'preferred_types': ['light_walks', 'moderate_activity']
907
- },
908
- 'LOW': {
909
- 'min': 15,
910
- 'ideal': 30,
911
- 'max': 45,
912
- 'intensity': 'light',
913
- 'sessions': 'single',
914
- 'preferred_types': ['light_walks']
915
  }
916
  }
917
 
918
- # 獲取品種的運動需求配置
919
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
920
 
921
- # 計算時間匹配度(使用更平滑的評分曲線)
922
- if exercise_time >= breed_level['ideal']:
923
- if exercise_time > breed_level['max']:
924
- # 運動時間過長,適度降分
925
- time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30)
 
 
 
 
 
 
926
  else:
927
- time_score = 0.15
928
- elif exercise_time >= breed_level['min']:
929
- # 在最小需求和理想需求之間,線性計算分數
930
- time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
931
- time_score = 0.05 + (time_ratio * 0.10)
932
- else:
933
- # 運動時間不足,根據差距程度扣分
934
- time_ratio = max(0, exercise_time / breed_level['min'])
935
- time_score = -0.15 * (1 - time_ratio)
936
-
937
- # 運動類型匹配度評估
938
- type_score = 0.0
939
- if exercise_type in breed_level['preferred_types']:
940
- type_score = 0.05
941
- if exercise_type == breed_level['preferred_types'][0]:
942
- type_score = 0.08 # 最佳匹配類型給予更高分數
943
-
944
- return max(-0.2, min(0.2, time_score + type_score))
 
 
 
 
 
 
 
 
945
 
946
 
947
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
@@ -1075,114 +987,275 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1075
  return max(0.1, min(1.0, final_score))
1076
 
1077
 
1078
- def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1079
  """
1080
- 計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
1081
 
1082
- 重要改進:
1083
- 1. 擴大基礎分數差異
1084
- 2. 加重困難特徵的懲罰
1085
- 3. 更細緻的品種特性評估
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1086
  """
1087
- # 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
1088
- base_scores = {
1089
- "High": {
1090
- "beginner": 0.10, # 降低起始分,高難度品種對新手幾乎不推薦
1091
- "intermediate": 0.60, # 中級玩家仍需謹慎
1092
- "advanced": 1.0 # 資深者能完全勝任
 
 
 
 
1093
  },
1094
- "Moderate": {
1095
- "beginner": 0.35, # 適中難度對新手仍具挑戰
1096
- "intermediate": 0.80, # 中級玩家較適合
1097
- "advanced": 1.0 # 資深者完全勝任
1098
  },
1099
- "Low": {
1100
- "beginner": 0.90, # 新手友善品種
1101
- "intermediate": 0.95, # 中級玩家幾乎完全勝任
1102
- "advanced": 1.0 # 資深者完全勝任
1103
  }
1104
  }
1105
 
1106
- # 取得基礎分數
1107
- score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
 
1108
 
1109
- temperament_lower = temperament.lower()
1110
- temperament_adjustments = 0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1111
 
1112
- # 根據經驗等級設定不同的特徵評估標準
1113
- if user_experience == "beginner":
1114
- # 新手不適合的特徵 - 更嚴格的懲罰
 
 
 
 
 
1115
  difficult_traits = {
1116
- 'stubborn': -0.30, # 固執性格嚴重影響新手
1117
- 'independent': -0.25, # 獨立性高的品種不適合新手
1118
- 'dominant': -0.25, # 支配性強的品種需要經驗處理
1119
- 'strong-willed': -0.20, # 強勢性格需要技巧管理
1120
- 'protective': -0.20, # 保護性強需要適當訓練
1121
- 'aloof': -0.15, # 冷漠性格需要耐心培養
1122
- 'energetic': -0.15, # 活潑好動需要經驗引導
1123
- 'aggressive': -0.35 # 攻擊傾向極不適合新手
1124
  }
1125
 
1126
- # 新手友善的特徵 - 適度的獎勵
1127
- easy_traits = {
1128
- 'gentle': 0.05, # 溫和性格適合新手
1129
- 'friendly': 0.05, # 友善性格容易相處
1130
- 'eager to please': 0.08, # 願意服從較容易訓練
1131
- 'patient': 0.05, # 耐心的特質有助於建立關係
1132
- 'adaptable': 0.05, # 適應性強較容易照顧
1133
- 'calm': 0.06 # 冷靜的性格較好掌握
1134
  }
1135
 
1136
- # 計算特徵調整
1137
- for trait, penalty in difficult_traits.items():
1138
- if trait in temperament_lower:
1139
- temperament_adjustments += penalty
1140
-
1141
- for trait, bonus in easy_traits.items():
1142
- if trait in temperament_lower:
1143
- temperament_adjustments += bonus
1144
 
1145
- # 品種類型特殊評估
1146
- if 'terrier' in temperament_lower:
1147
- temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
1148
- elif 'working' in temperament_lower:
1149
- temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
1150
- elif 'guard' in temperament_lower:
1151
- temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
1152
-
1153
- elif user_experience == "intermediate":
1154
- # 中級玩家的特徵評估
1155
- moderate_traits = {
1156
- 'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
1157
- 'independent': -0.10,
1158
- 'intelligent': 0.08, # 聰明的特質可以好好發揮
1159
- 'athletic': 0.06, # 運動能力可以適當訓練
1160
- 'versatile': 0.07, # 多功能性可以開發
1161
- 'protective': -0.08 # 保護性仍需注意
 
 
 
1162
  }
1163
 
1164
- for trait, adjustment in moderate_traits.items():
1165
- if trait in temperament_lower:
1166
- temperament_adjustments += adjustment
1167
 
1168
- else: # advanced
1169
- # 資深玩家能夠應對挑戰性特徵
1170
- advanced_traits = {
1171
- 'stubborn': 0.05, # 困難特徵反而成為優勢
1172
- 'independent': 0.05,
1173
- 'intelligent': 0.10,
1174
- 'protective': 0.05,
1175
- 'strong-willed': 0.05
1176
- }
1177
 
1178
- for trait, bonus in advanced_traits.items():
1179
- if trait in temperament_lower:
1180
- temperament_adjustments += bonus
1181
 
1182
- # 確保最終分數範圍更大,讓差異更明顯
1183
- final_score = max(0.05, min(1.0, score + temperament_adjustments))
1184
 
1185
- return final_score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1186
 
1187
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
1188
  """
@@ -1292,128 +1365,311 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1292
  return max(0.1, min(1.0, health_score))
1293
 
1294
 
1295
- def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
1296
- """
1297
- 計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
1298
- """
1299
- if breed_name not in breed_noise_info:
1300
- return 0.5
1301
 
1302
- noise_info = breed_noise_info[breed_name]
1303
- noise_level = noise_info['noise_level'].lower()
1304
- noise_notes = noise_info['noise_notes'].lower()
1305
 
1306
- # 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
1307
- base_scores = {
1308
- 'low': {
1309
- 'low': 1.0, # 安靜的狗對低容忍完美匹配
1310
- 'medium': 0.95, # 安靜的狗對一般容忍很好
1311
- 'high': 0.90 # 安靜的狗對高容忍當然可以
1312
- },
1313
- 'medium': {
1314
- 'low': 0.60, # 一般吠叫對低容忍較困難
1315
- 'medium': 0.90, # 一般吠叫對一般容忍可接受
1316
- 'high': 0.95 # 一般吠叫對高容忍很好
1317
- },
1318
- 'high': {
1319
- 'low': 0.25, # 愛叫的狗對低容忍極不適合
1320
- 'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
1321
- 'high': 0.90 # 愛叫的狗對高容忍可以接受
1322
- },
1323
- 'varies': {
1324
- 'low': 0.50, # 不確定的情況對低容忍風險較大
1325
- 'medium': 0.75, # 不確定的情況對一般容忍可嘗試
1326
- 'high': 0.85 # 不確定的情況對高容忍問題較小
1327
- }
1328
- }
1329
 
1330
- # 取得基礎分數
1331
- base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
1332
 
1333
- # 吠叫原因評估,根據環境調整懲罰程度
1334
- barking_penalties = {
1335
- 'separation anxiety': {
1336
- 'apartment': -0.30, # 在公寓對鄰居影響更大
1337
- 'house_small': -0.25,
1338
- 'house_large': -0.20
1339
- },
1340
- 'excessive barking': {
1341
- 'apartment': -0.25,
1342
- 'house_small': -0.20,
1343
- 'house_large': -0.15
1344
- },
1345
- 'territorial': {
1346
- 'apartment': -0.20, # 在公寓更容易被觸發
1347
- 'house_small': -0.15,
1348
- 'house_large': -0.10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1349
  },
1350
- 'alert barking': {
1351
- 'apartment': -0.15, # 公寓環境刺激較多
1352
- 'house_small': -0.10,
1353
- 'house_large': -0.08
 
 
 
 
 
 
 
 
 
 
 
 
1354
  },
1355
- 'attention seeking': {
1356
- 'apartment': -0.15,
1357
- 'house_small': -0.12,
1358
- 'house_large': -0.10
 
 
 
 
 
 
 
 
 
 
 
 
1359
  }
1360
  }
1361
-
1362
- # 計算環境相關的吠叫懲罰
1363
- living_space = user_prefs.living_space
1364
- barking_penalty = 0
1365
- for trigger, penalties in barking_penalties.items():
1366
- if trigger in noise_notes:
1367
- barking_penalty += penalties.get(living_space, -0.15)
1368
-
1369
- # 特殊情況評估
1370
- special_adjustments = 0
1371
- if user_prefs.has_children:
1372
- # 孩童年齡相關調整
1373
- child_age_adjustments = {
1374
- 'toddler': {
1375
- 'high': -0.20, # 幼童對吵鬧更敏感
1376
- 'medium': -0.15,
1377
- 'low': -0.05
1378
  },
1379
- 'school_age': {
1380
- 'high': -0.15,
1381
- 'medium': -0.10,
1382
- 'low': -0.05
 
 
 
 
 
1383
  },
1384
- 'teenager': {
1385
- 'high': -0.10,
1386
- 'medium': -0.05,
1387
- 'low': -0.02
1388
  }
1389
  }
1390
 
1391
- # 根據孩童年齡和噪音等級調整
1392
- age_adj = child_age_adjustments.get(user_prefs.children_age,
1393
- child_age_adjustments['school_age'])
1394
- special_adjustments += age_adj.get(noise_level, -0.10)
1395
-
1396
- # 訓練性補償評估
1397
- trainability_bonus = 0
1398
- if 'responds well to training' in noise_notes:
1399
- trainability_bonus = 0.12
1400
- elif 'can be trained' in noise_notes:
1401
- trainability_bonus = 0.08
1402
- elif 'difficult to train' in noise_notes:
1403
- trainability_bonus = 0.02
1404
-
1405
- # 夜間吠叫特別考量
1406
- if 'night barking' in noise_notes or 'howls' in noise_notes:
1407
- if user_prefs.living_space == 'apartment':
1408
- special_adjustments -= 0.15
1409
- elif user_prefs.living_space == 'house_small':
1410
- special_adjustments -= 0.10
1411
- else:
1412
- special_adjustments -= 0.05
1413
-
1414
- # 計算最終分數,確保更大的分數範圍
1415
- final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1416
- return max(0.1, min(1.0, final_score))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1417
 
1418
 
1419
  # 1. 計算基礎分數
@@ -1508,126 +1764,328 @@ def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -
1508
  return min(0.2, adaptability_score)
1509
 
1510
 
1511
- def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1512
- """
1513
- 改進的品種相容性評分系統
1514
- 通過更細緻的特徵評估和動態權重調整,自然產生分數差異
1515
- """
1516
- # 評估關鍵特徵的匹配度,使用更極端的調整係數
1517
- def evaluate_key_features():
1518
- # 空間適配性評估
1519
- space_multiplier = 1.0
1520
- if user_prefs.living_space == 'apartment':
1521
- if breed_info['Size'] == 'Giant':
1522
- space_multiplier = 0.3 # 嚴重不適合
1523
- elif breed_info['Size'] == 'Large':
1524
- space_multiplier = 0.4 # 明顯不適合
1525
- elif breed_info['Size'] == 'Small':
1526
- space_multiplier = 1.4 # 明顯優勢
1527
 
1528
- # 運動需求評估
1529
- exercise_multiplier = 1.0
1530
- exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1531
- if exercise_needs == 'VERY HIGH':
1532
- if user_prefs.exercise_time < 60:
1533
- exercise_multiplier = 0.3 # 嚴重不足
1534
- elif user_prefs.exercise_time > 150:
1535
- exercise_multiplier = 1.5 # 完美匹配
1536
- elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150:
1537
- exercise_multiplier = 0.5 # 運動過度
1538
 
1539
- return space_multiplier, exercise_multiplier
1540
 
1541
- # 計算經驗匹配度
1542
- def evaluate_experience():
1543
- exp_multiplier = 1.0
1544
- care_level = breed_info.get('Care Level', 'MODERATE')
1545
 
1546
- if care_level == 'High':
1547
- if user_prefs.experience_level == 'beginner':
1548
- exp_multiplier = 0.4
1549
- elif user_prefs.experience_level == 'advanced':
1550
- exp_multiplier = 1.3
1551
- elif care_level == 'Low':
1552
- if user_prefs.experience_level == 'advanced':
1553
- exp_multiplier = 0.9 # 略微降低評分,因為可能不夠有挑戰性
1554
 
1555
- return exp_multiplier
1556
 
1557
- # 取得特徵調整係數
1558
- space_mult, exercise_mult = evaluate_key_features()
1559
- exp_mult = evaluate_experience()
1560
 
1561
- # 調整基礎分數
1562
- adjusted_scores = {
1563
- 'space': scores['space'] * space_mult,
1564
- 'exercise': scores['exercise'] * exercise_mult,
1565
- 'experience': scores['experience'] * exp_mult,
1566
- 'grooming': scores['grooming'],
1567
- 'health': scores['health'],
1568
- 'noise': scores['noise']
1569
- }
1570
 
1571
- # 計算加權平均,關鍵特徵佔更大權重
1572
- weights = {
1573
- 'space': 0.35,
1574
- 'exercise': 0.30,
1575
- 'experience': 0.20,
1576
- 'grooming': 0.15,
1577
- 'health': 0.10,
1578
- 'noise': 0.10
1579
- }
1580
 
1581
- # 動態調整權重
1582
- if user_prefs.living_space == 'apartment':
1583
- weights['space'] *= 1.5
1584
- weights['noise'] *= 1.3
1585
 
1586
- if abs(user_prefs.exercise_time - 120) > 60: # 運動時間極端情況
1587
- weights['exercise'] *= 1.4
 
 
 
 
1588
 
1589
- # 正規化權重
1590
- total_weight = sum(weights.values())
1591
- normalized_weights = {k: v/total_weight for k, v in weights.items()}
 
 
 
 
 
1592
 
1593
- # 計算最終分數
1594
- final_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys())
1595
 
1596
- # 品種特性加成
1597
- breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1598
 
1599
- # 整合最終分數,保持在0-1範圍內
1600
- return min(1.0, max(0.0, (final_score * 0.85) + (breed_bonus * 0.15)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1601
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1602
 
1603
  def amplify_score_extreme(score: float) -> float:
1604
  """
1605
- 改進的分數轉換函數
1606
- 提供更大的分數範圍和更明顯的差異
1607
-
1608
- 轉換邏輯:
1609
- - 極差匹配 (0.0-0.3) -> 60-68%
1610
- - 較差匹配 (0.3-0.5) -> 68-75%
1611
- - 中等匹配 (0.5-0.7) -> 75-85%
1612
- - 良好匹配 (0.7-0.85) -> 85-92%
1613
- - 優秀匹配 (0.85-1.0) -> 92-95%
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1614
  """
1615
- if score < 0.3:
1616
- # 極差匹配:快速線性增長
1617
- return 0.60 + (score / 0.3) * 0.08
1618
- elif score < 0.5:
1619
- # 較差匹配:緩慢增長
1620
- position = (score - 0.3) / 0.2
1621
- return 0.68 + position * 0.07
1622
- elif score < 0.7:
1623
- # 中等匹配:穩定線性增長
1624
- position = (score - 0.5) / 0.2
1625
- return 0.75 + position * 0.10
1626
- elif score < 0.85:
1627
- # 良好匹配:加速增長
1628
- position = (score - 0.7) / 0.15
1629
- return 0.85 + position * 0.07
1630
- else:
1631
- # 優秀匹配:最後衝刺
1632
  position = (score - 0.85) / 0.15
1633
- return 0.92 + position * 0.03
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # 基礎居住條件
37
+ living_space: str # "apartment", "house_small", "house_large"
38
+ yard_access: str # "no_yard", "shared_yard", "private_yard"
39
+ living_floor: int = 1 # 居住樓層,對公寓住戶特別重要
40
+
41
+ # 運動相關參數
42
+ exercise_time: int # 每日運動時間(分鐘)
43
+ exercise_type: str # "light_walks", "moderate_activity", "active_training"
44
+ exercise_intensity: str = "moderate" # "low", "moderate", "high"
45
+
46
+ # 照護能力與時間
47
+ grooming_commitment: str # "low", "medium", "high"
48
+ experience_level: str # "beginner", "intermediate", "advanced"
49
+ time_availability: str # "limited", "moderate", "flexible"
50
+ home_alone_time: int = 4 # 每日獨處時間(小時)
51
+
52
+ # 家庭環境
53
  has_children: bool
54
+ children_age: str # "toddler", "school_age", "teenager"
 
 
55
  other_pets: bool
56
+
57
+ # 環境適應性
58
+ noise_tolerance: str # "low", "medium", "high"
59
+ space_for_play: bool
60
+ climate: str # "cold", "moderate", "hot"
61
+
62
+ # 特殊需求
63
+ health_sensitivity: str = "medium" # "low", "medium", "high"
64
+ barking_acceptance: str = None # 如果未指定,默認使用 noise_tolerance
65
+ lifestyle_activity: str = "moderate" # "sedentary", "moderate", "active"
66
 
67
  def __post_init__(self):
68
+ """初始化後執行,用於設置派生值和驗證"""
69
  if self.barking_acceptance is None:
70
  self.barking_acceptance = self.noise_tolerance
71
 
 
196
  bonus += min(0.15, adaptability_bonus)
197
 
198
  return min(0.5, max(-0.25, bonus))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  @staticmethod
202
  def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
 
457
 
458
 
459
  # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
460
+ # """
461
+ # 主要改進:
462
+ # 1. 更均衡的基礎分數分配
463
+ # 2. 更細緻的空間需求評估
464
+ # 3. 強化運動需求與空間的關聯性
465
+ # """
466
+ # # 重新設計基礎分數矩陣,降低普遍分數以增加區別度
467
  # base_scores = {
468
  # "Small": {
469
+ # "apartment": 0.85, # 降低滿分機會
470
+ # "house_small": 0.80, # 小型犬不應在大空間得到太高分數
471
+ # "house_large": 0.75 # 避免小型犬總是得到最高分
472
  # },
473
  # "Medium": {
474
+ # "apartment": 0.45, # 維持對公寓環境的限制
475
+ # "house_small": 0.75, # 適中的分數
476
+ # "house_large": 0.85 # 給予合理的獎勵
477
  # },
478
  # "Large": {
479
+ # "apartment": 0.15, # 加重對大型犬在公寓的限制
480
+ # "house_small": 0.65, # 中等適合度
481
+ # "house_large": 0.90 # 最適合的環境
482
  # },
483
  # "Giant": {
484
+ # "apartment": 0.10, # 更嚴格的限制
485
+ # "house_small": 0.45, # 顯著的空間限制
486
+ # "house_large": 0.95 # 最理想的配對
487
  # }
488
  # }
489
 
490
  # # 取得基礎分數
491
  # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
492
 
493
+ # # 運動需求相關的調整更加動態
494
  # exercise_adjustments = {
495
  # "Very High": {
496
+ # "apartment": -0.25, # 加重在受限空間的懲罰
497
  # "house_small": -0.15,
498
  # "house_large": -0.05
499
  # },
 
508
  # "house_large": 0
509
  # },
510
  # "Low": {
511
+ # "apartment": 0.05, # 低運動需求在小空間反而有優勢
512
  # "house_small": 0,
513
+ # "house_large": -0.05 # 輕微降低評分,因為空間可能過大
514
  # }
515
  # }
516
 
517
+ # # 根據空間類型獲取運動需求調整
518
  # adjustment = exercise_adjustments.get(exercise_needs,
519
  # exercise_adjustments["Moderate"])[living_space]
520
 
521
+ # # 院子效益根據品種大小和運動需求動態調整
 
522
  # if has_yard:
523
+ # yard_bonus = {
524
+ # "Giant": 0.20,
525
+ # "Large": 0.15,
526
+ # "Medium": 0.10,
527
+ # "Small": 0.05
528
+ # }.get(size, 0.10)
529
+
530
+ # # 運動需求會影響院子的重要性
531
+ # if exercise_needs in ["Very High", "High"]:
532
+ # yard_bonus *= 1.2
533
+ # elif exercise_needs == "Low":
534
+ # yard_bonus *= 0.8
535
 
536
+ # current_score = base_score + adjustment + yard_bonus
537
+ # else:
538
+ # current_score = base_score + adjustment
539
+
540
+ # # 確保分數在合理範圍內,但避免極端值
541
+ # return min(0.95, max(0.15, current_score))
542
 
543
 
544
+ # def calculate_exercise_score(breed_needs: str, exercise_time: int, exercise_type: str) -> float:
545
+ # """
546
+ # 精確評估品種運動需求與使用者運動條件的匹配度
547
+
548
+ # Parameters:
549
+ # breed_needs: 品種的運動需求等級
550
+ # exercise_time: 使用者能提供的運動時間(分鐘)
551
+ # exercise_type: 使用者偏好的運動類型
552
+
553
+ # Returns:
554
+ # float: -0.2 到 0.2 之間的匹配分數
555
+ # """
556
+ # # 定義更細緻的運動需求等級
557
+ # exercise_levels = {
558
+ # 'VERY HIGH': {
559
+ # 'min': 120,
560
+ # 'ideal': 150,
561
+ # 'max': 180,
562
+ # 'intensity': 'high',
563
+ # 'sessions': 'multiple',
564
+ # 'preferred_types': ['active_training', 'intensive_exercise']
565
+ # },
566
+ # 'HIGH': {
567
+ # 'min': 90,
568
+ # 'ideal': 120,
569
+ # 'max': 150,
570
+ # 'intensity': 'moderate_high',
571
+ # 'sessions': 'multiple',
572
+ # 'preferred_types': ['active_training', 'moderate_activity']
573
+ # },
574
+ # 'MODERATE HIGH': {
575
+ # 'min': 70,
576
+ # 'ideal': 90,
577
+ # 'max': 120,
578
+ # 'intensity': 'moderate',
579
+ # 'sessions': 'flexible',
580
+ # 'preferred_types': ['moderate_activity', 'active_training']
581
+ # },
582
+ # 'MODERATE': {
583
+ # 'min': 45,
584
+ # 'ideal': 60,
585
+ # 'max': 90,
586
+ # 'intensity': 'moderate',
587
+ # 'sessions': 'flexible',
588
+ # 'preferred_types': ['moderate_activity', 'light_walks']
589
+ # },
590
+ # 'MODERATE LOW': {
591
+ # 'min': 30,
592
+ # 'ideal': 45,
593
+ # 'max': 70,
594
+ # 'intensity': 'light_moderate',
595
+ # 'sessions': 'flexible',
596
+ # 'preferred_types': ['light_walks', 'moderate_activity']
597
+ # },
598
+ # 'LOW': {
599
+ # 'min': 15,
600
+ # 'ideal': 30,
601
+ # 'max': 45,
602
+ # 'intensity': 'light',
603
+ # 'sessions': 'single',
604
+ # 'preferred_types': ['light_walks']
605
+ # }
606
+ # }
607
+
608
+ # # 獲取品種的運動需求配置
609
+ # breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
610
+
611
+ # # 計算時間匹配度(使用更平滑的評分曲線)
612
+ # if exercise_time >= breed_level['ideal']:
613
+ # if exercise_time > breed_level['max']:
614
+ # # 運動時間過長,適度降分
615
+ # time_score = 0.15 - (0.05 * (exercise_time - breed_level['max']) / 30)
616
+ # else:
617
+ # time_score = 0.15
618
+ # elif exercise_time >= breed_level['min']:
619
+ # # 在最小需求和理想需求之間,線性計算分數
620
+ # time_ratio = (exercise_time - breed_level['min']) / (breed_level['ideal'] - breed_level['min'])
621
+ # time_score = 0.05 + (time_ratio * 0.10)
622
+ # else:
623
+ # # 運動時間不足,根據差距程度扣分
624
+ # time_ratio = max(0, exercise_time / breed_level['min'])
625
+ # time_score = -0.15 * (1 - time_ratio)
626
+
627
+ # # 運動類型匹配度評估
628
+ # type_score = 0.0
629
+ # if exercise_type in breed_level['preferred_types']:
630
+ # type_score = 0.05
631
+ # if exercise_type == breed_level['preferred_types'][0]:
632
+ # type_score = 0.08 # 最佳匹配類型給予更高分數
633
+
634
+ # return max(-0.2, min(0.2, time_score + type_score))
635
+
636
+
637
+ def calculate_space_score(breed_info: dict, user_prefs: UserPreferences) -> float:
638
  """
639
+ 計算品種與居住空間的匹配程度
640
 
641
+ 這個函數實現了一個全面的空間評分系統,考慮:
642
+ 1. 基本空間需求(住所類型與品種大小的匹配)
643
+ 2. 樓層因素(特別是公寓住戶)
644
+ 3. 戶外活動空間(院子類型及可用性)
645
+ 4. 室內活動空間的實際可用性
646
+ 5. 品種的特殊空間需求
647
+
648
+ Parameters:
649
+ -----------
650
+ breed_info: 包含品種特徵的字典,包括體型、活動需求等
651
+ user_prefs: 使用者偏好設定,包含居住條件相關信息
652
+
653
+ Returns:
654
+ --------
655
+ float: 0.0-1.0 之間的匹配分數
656
  """
657
+ # 取得品種基本信息
658
+ size = breed_info.get('Size', 'Medium')
659
+ temperament = breed_info.get('Temperament', '').lower()
660
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
661
+
662
+ # 基礎空間需求評分矩陣 - 考慮品種大小與居住空間的基本匹配度
663
+ base_space_scores = {
664
  "Small": {
665
+ "apartment": 0.95, # 小型犬最適合��寓
666
+ "house_small": 0.90, # 小房子也很適合
667
+ "house_large": 0.85 # 大房子可能過大
668
  },
669
  "Medium": {
670
+ "apartment": 0.60, # 中型犬在公寓有一定限制
671
+ "house_small": 0.85, # 小房子較適合
672
+ "house_large": 0.95 # 大房子最理想
673
  },
674
  "Large": {
675
+ "apartment": 0.30, # 大型犬不適合公寓
676
+ "house_small": 0.70, # 小房子稍嫌擁擠
677
+ "house_large": 1.0 # 大房子最理想
678
  },
679
  "Giant": {
680
+ "apartment": 0.20, # 極大型犬極不適合公寓
681
+ "house_small": 0.50, # 小房子明顯不足
682
+ "house_large": 1.0 # 大房子必需
683
  }
684
  }
685
 
686
+ # 取得基礎空間分數
687
+ base_score = base_space_scores.get(size, base_space_scores["Medium"])[user_prefs.living_space]
688
+
689
+ # 公寓特殊考量
690
+ if user_prefs.living_space == "apartment":
691
+ # 樓層調整
692
+ floor_penalty = 0
693
+ if user_prefs.living_floor > 1:
694
+ if size in ["Large", "Giant"]:
695
+ floor_penalty = min(0.3, (user_prefs.living_floor - 1) * 0.05)
696
+ elif size == "Medium":
697
+ floor_penalty = min(0.2, (user_prefs.living_floor - 1) * 0.03)
698
+ else:
699
+ floor_penalty = min(0.1, (user_prefs.living_floor - 1) * 0.02)
700
+ base_score = max(0.2, base_score - floor_penalty)
701
+
702
+ # 戶外空間評估
703
+ yard_scores = {
704
+ "no_yard": 0,
705
+ "shared_yard": 0.1,
706
+ "private_yard": 0.2
 
 
 
 
707
  }
708
 
709
+ # 根據品種大小調整院子加分
710
+ yard_size_multipliers = {
711
+ "Giant": 1.2,
712
+ "Large": 1.1,
713
+ "Medium": 1.0,
714
+ "Small": 0.8
715
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
 
717
+ yard_bonus = yard_scores[user_prefs.yard_access] * yard_size_multipliers.get(size, 1.0)
 
 
 
718
 
719
+ # 活動空間需求評估
720
+ activity_space_score = 0
721
+ if user_prefs.space_for_play:
722
+ if exercise_needs in ["VERY HIGH", "HIGH"]:
723
+ activity_space_score = 0.15
724
+ elif exercise_needs == "MODERATE":
725
+ activity_space_score = 0.10
726
+ else:
727
+ activity_space_score = 0.05
728
 
729
+ # 品種特性評估
730
+ temperament_adjustments = 0
731
+ if 'active' in temperament or 'energetic' in temperament:
732
+ if user_prefs.living_space == 'apartment':
733
+ temperament_adjustments -= 0.15
734
+ elif user_prefs.living_space == 'house_small':
735
+ temperament_adjustments -= 0.05
736
+
737
+ if 'calm' in temperament or 'lazy' in temperament:
738
+ if user_prefs.living_space == 'apartment':
739
+ temperament_adjustments += 0.10
740
+
741
+ if 'adaptable' in temperament:
742
+ temperament_adjustments += 0.05
743
 
744
+ # 家庭環境考量
745
+ if user_prefs.has_children:
746
+ if user_prefs.living_space == 'apartment':
747
+ # 公寓中有孩童需要更多活動空間
748
+ if size in ["Large", "Giant"]:
749
+ base_score *= 0.85
750
+ elif size == "Medium":
751
+ base_score *= 0.90
752
 
753
+ # 整合所有評分因素
754
+ final_score = base_score + yard_bonus + activity_space_score + temperament_adjustments
 
 
 
 
 
 
 
 
 
 
 
755
 
756
+ # 確保最終分數在合理範圍內
757
+ return max(0.15, min(1.0, final_score))
758
 
759
 
760
+ def calculate_exercise_score(breed_needs: str, exercise_time: int, user_prefs: 'UserPreferences') -> float:
761
  """
762
+ 計算品種運動需求與使用者條件的匹配分數
763
+
764
+ 這個函數實現了一個精細的運動評分系統,考慮:
765
+ 1. 運動時間的匹配度(0-180分鐘)
766
+ 2. 運動強度的適配性
767
+ 3. 品種特性對運動的特殊需求
768
+ 4. 生活方式的整體活躍度
769
 
770
  Parameters:
771
+ -----------
772
  breed_needs: 品種的運動需求等級
773
  exercise_time: 使用者能提供的運動時間(分鐘)
774
+ user_prefs: 使用者偏好設定,包含運動類型和強度等信息
775
 
776
  Returns:
777
+ --------
778
+ float: 0.0-1.0 之間的匹配分數
779
  """
780
+ # 定義更精確的運動需求標準
781
  exercise_levels = {
782
  'VERY HIGH': {
783
  'min': 120,
784
  'ideal': 150,
785
  'max': 180,
786
+ 'intensity_required': 'high',
787
+ 'intensity_factors': {'high': 1.2, 'moderate': 0.8, 'low': 0.6},
788
+ 'type_bonus': {'active_training': 0.15, 'moderate_activity': 0.05, 'light_walks': -0.1}
789
  },
790
  'HIGH': {
791
  'min': 90,
792
  'ideal': 120,
793
  'max': 150,
794
+ 'intensity_required': 'moderate',
795
+ 'intensity_factors': {'high': 1.1, 'moderate': 1.0, 'low': 0.7},
796
+ 'type_bonus': {'active_training': 0.1, 'moderate_activity': 0.1, 'light_walks': -0.05}
797
  },
798
+ 'MODERATE': {
799
+ 'min': 60,
800
  'ideal': 90,
801
  'max': 120,
802
+ 'intensity_required': 'moderate',
803
+ 'intensity_factors': {'high': 1.0, 'moderate': 1.0, 'low': 0.8},
804
+ 'type_bonus': {'active_training': 0.05, 'moderate_activity': 0.1, 'light_walks': 0.05}
805
  },
806
+ 'LOW': {
807
+ 'min': 30,
808
  'ideal': 60,
809
  'max': 90,
810
+ 'intensity_required': 'low',
811
+ 'intensity_factors': {'high': 0.7, 'moderate': 0.9, 'low': 1.0},
812
+ 'type_bonus': {'active_training': -0.05, 'moderate_activity': 0.05, 'light_walks': 0.1}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
813
  }
814
  }
815
 
816
+ # 獲取品種運動需求配置
817
  breed_level = exercise_levels.get(breed_needs.upper(), exercise_levels['MODERATE'])
818
 
819
+ # 計算基礎運動時間分數
820
+ def calculate_time_score(time: int, level: dict) -> float:
821
+ if time < level['min']:
822
+ # 運動時間不足,指數下降
823
+ return max(0.3, (time / level['min']) ** 1.5)
824
+ elif time < level['ideal']:
825
+ # 運動時間接近理想,線性增長
826
+ return 0.7 + 0.3 * ((time - level['min']) / (level['ideal'] - level['min']))
827
+ elif time <= level['max']:
828
+ # 理想運動時間範圍,高分保持
829
+ return 1.0
830
  else:
831
+ # 運動時間過多,緩慢扣分
832
+ excess = (time - level['max']) / 30 # 每超過30分鐘扣分
833
+ return max(0.7, 1.0 - (excess * 0.1))
834
+
835
+ # 計算運動時間基礎分數
836
+ time_score = calculate_time_score(exercise_time, breed_level)
837
+
838
+ # 計算運動強度匹配度
839
+ intensity_factor = breed_level['intensity_factors'].get(user_prefs.exercise_intensity, 1.0)
840
+
841
+ # 運動類型加成
842
+ type_bonus = breed_level['type_bonus'].get(user_prefs.exercise_type, 0)
843
+
844
+ # 生活方式調整
845
+ lifestyle_adjustments = {
846
+ 'sedentary': -0.1,
847
+ 'moderate': 0,
848
+ 'active': 0.1
849
+ }
850
+ lifestyle_factor = lifestyle_adjustments.get(user_prefs.lifestyle_activity, 0)
851
+
852
+ # 整合所有因素
853
+ final_score = time_score * intensity_factor + type_bonus + lifestyle_factor
854
+
855
+ # 確保分數在合理範圍內
856
+ return max(0.1, min(1.0, final_score))
857
 
858
 
859
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
 
987
  return max(0.1, min(1.0, final_score))
988
 
989
 
990
+ # def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
991
+ # """
992
+ # 計算使用者經驗與品種需求的匹配分數,加強經驗等級的影響力
993
+
994
+ # 重要改進:
995
+ # 1. 擴大基礎分數差異
996
+ # 2. 加重困難特徵的懲罰
997
+ # 3. 更細緻的品種特性評估
998
+ # """
999
+ # # 基礎分數矩陣 - 大幅擴大不同經驗等級的分數差異
1000
+ # base_scores = {
1001
+ # "High": {
1002
+ # "beginner": 0.10, # 降低起始分,高難度品種對新手幾乎不推薦
1003
+ # "intermediate": 0.60, # 中級玩家仍需謹慎
1004
+ # "advanced": 1.0 # 資深者能完全勝任
1005
+ # },
1006
+ # "Moderate": {
1007
+ # "beginner": 0.35, # 適中難度對新手仍具挑戰
1008
+ # "intermediate": 0.80, # 中級玩家較適合
1009
+ # "advanced": 1.0 # 資深者完全勝任
1010
+ # },
1011
+ # "Low": {
1012
+ # "beginner": 0.90, # 新手友善品種
1013
+ # "intermediate": 0.95, # 中級玩家幾乎完全勝任
1014
+ # "advanced": 1.0 # 資深者完全勝任
1015
+ # }
1016
+ # }
1017
+
1018
+ # # 取得基礎分數
1019
+ # score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
1020
+
1021
+ # temperament_lower = temperament.lower()
1022
+ # temperament_adjustments = 0.0
1023
+
1024
+ # # 根據經驗等級設定不同的特徵評估標準
1025
+ # if user_experience == "beginner":
1026
+ # # 新手不適合的特徵 - 更嚴格的懲罰
1027
+ # difficult_traits = {
1028
+ # 'stubborn': -0.30, # 固執性格嚴重影響新手
1029
+ # 'independent': -0.25, # 獨立性高的品種不適合新手
1030
+ # 'dominant': -0.25, # 支配性強的品種需要經驗處理
1031
+ # 'strong-willed': -0.20, # 強勢性格需要技巧管理
1032
+ # 'protective': -0.20, # 保護性強需要適當訓練
1033
+ # 'aloof': -0.15, # 冷漠性格需要耐心培養
1034
+ # 'energetic': -0.15, # 活潑好動需要經驗引導
1035
+ # 'aggressive': -0.35 # 攻擊傾向極不適合新手
1036
+ # }
1037
+
1038
+ # # 新手友善的特徵 - 適度的獎勵
1039
+ # easy_traits = {
1040
+ # 'gentle': 0.05, # 溫和性格適合新手
1041
+ # 'friendly': 0.05, # 友善性格容易相處
1042
+ # 'eager to please': 0.08, # 願意服從較容易訓練
1043
+ # 'patient': 0.05, # 耐心的特質有助於建立關係
1044
+ # 'adaptable': 0.05, # 適應性強較容易照顧
1045
+ # 'calm': 0.06 # 冷靜的性格較好掌握
1046
+ # }
1047
+
1048
+ # # 計算特徵調整
1049
+ # for trait, penalty in difficult_traits.items():
1050
+ # if trait in temperament_lower:
1051
+ # temperament_adjustments += penalty
1052
+
1053
+ # for trait, bonus in easy_traits.items():
1054
+ # if trait in temperament_lower:
1055
+ # temperament_adjustments += bonus
1056
+
1057
+ # # 品種類型特殊評估
1058
+ # if 'terrier' in temperament_lower:
1059
+ # temperament_adjustments -= 0.20 # 梗類犬種通常不適合新手
1060
+ # elif 'working' in temperament_lower:
1061
+ # temperament_adjustments -= 0.25 # 工作犬需要經驗豐富的主人
1062
+ # elif 'guard' in temperament_lower:
1063
+ # temperament_adjustments -= 0.25 # 護衛犬需要專業訓練
1064
+
1065
+ # elif user_experience == "intermediate":
1066
+ # # 中級玩家的特徵評估
1067
+ # moderate_traits = {
1068
+ # 'stubborn': -0.15, # 仍然需要注意,但懲罰較輕
1069
+ # 'independent': -0.10,
1070
+ # 'intelligent': 0.08, # 聰明的特質可以好好發揮
1071
+ # 'athletic': 0.06, # 運動能力可以適當訓練
1072
+ # 'versatile': 0.07, # 多功能性可以開發
1073
+ # 'protective': -0.08 # 保護性仍需注意
1074
+ # }
1075
+
1076
+ # for trait, adjustment in moderate_traits.items():
1077
+ # if trait in temperament_lower:
1078
+ # temperament_adjustments += adjustment
1079
+
1080
+ # else: # advanced
1081
+ # # 資深玩家能夠應對挑戰性特徵
1082
+ # advanced_traits = {
1083
+ # 'stubborn': 0.05, # 困難特徵反而成為優勢
1084
+ # 'independent': 0.05,
1085
+ # 'intelligent': 0.10,
1086
+ # 'protective': 0.05,
1087
+ # 'strong-willed': 0.05
1088
+ # }
1089
+
1090
+ # for trait, bonus in advanced_traits.items():
1091
+ # if trait in temperament_lower:
1092
+ # temperament_adjustments += bonus
1093
+
1094
+ # # 確保最終分數範圍更大,讓差異更明顯
1095
+ # final_score = max(0.05, min(1.0, score + temperament_adjustments))
1096
+
1097
+ # return final_score
1098
+
1099
+
1100
+ def calculate_experience_score(breed_info: dict, user_prefs: UserPreferences) -> float:
1101
  """
1102
+ 計算飼主經驗與品種需求的匹配分數
1103
 
1104
+ 這個函數實現了一個全面的經驗評分系統,考慮:
1105
+ 1. 品種的基本照護難度
1106
+ 2. 飼主的經驗水平
1107
+ 3. 特殊照護需求(如健康問題、行為訓練)
1108
+ 4. 時間投入與生活方式的匹配
1109
+ 5. 家庭環境對照護的影響
1110
+
1111
+ 特別注意:
1112
+ - 新手飼主面對高難度品種時的顯著降分
1113
+ - 資深飼主照顧簡單品種的微幅降分
1114
+ - 特殊需求品種的額外評估
1115
+
1116
+ Parameters:
1117
+ -----------
1118
+ breed_info: 包含品種特徵的字典
1119
+ user_prefs: 使用者偏好設定
1120
+
1121
+ Returns:
1122
+ --------
1123
+ float: 0.0-1.0 之間的匹配分數
1124
  """
1125
+ care_level = breed_info.get('Care Level', 'MODERATE').upper()
1126
+ temperament = breed_info.get('Temperament', '').lower()
1127
+ health_issues = breed_info.get('Health Issues', '').lower()
1128
+
1129
+ # 基礎照護難度評分矩陣
1130
+ base_experience_scores = {
1131
+ "HIGH": {
1132
+ "beginner": 0.30, # 高難度品種對新手極具挑戰
1133
+ "intermediate": 0.70, # 中級飼主需要額外努力
1134
+ "advanced": 0.95 # 資深飼主最適合
1135
  },
1136
+ "MODERATE": {
1137
+ "beginner": 0.60, # 中等難度對新手有一定挑戰
1138
+ "intermediate": 0.85, # 中級飼主較適合
1139
+ "advanced": 0.90 # 資深飼主可能稍嫌簡單
1140
  },
1141
+ "LOW": {
1142
+ "beginner": 0.90, # 低難度適合新手
1143
+ "intermediate": 0.85, # 中級飼主可能感覺無趣
1144
+ "advanced": 0.80 # 資深飼主可能缺乏挑戰
1145
  }
1146
  }
1147
 
1148
+ # 取得基礎經驗分數
1149
+ base_score = base_experience_scores.get(care_level,
1150
+ base_experience_scores["MODERATE"])[user_prefs.experience_level]
1151
 
1152
+ # 時間可用性評估
1153
+ time_adjustments = {
1154
+ "limited": {
1155
+ "HIGH": -0.20,
1156
+ "MODERATE": -0.15,
1157
+ "LOW": -0.10
1158
+ },
1159
+ "moderate": {
1160
+ "HIGH": -0.10,
1161
+ "MODERATE": -0.05,
1162
+ "LOW": 0
1163
+ },
1164
+ "flexible": {
1165
+ "HIGH": 0,
1166
+ "MODERATE": 0.05,
1167
+ "LOW": 0.10
1168
+ }
1169
+ }
1170
 
1171
+ time_adjustment = time_adjustments[user_prefs.time_availability][care_level]
1172
+
1173
+ # 行為特徵評估
1174
+ def evaluate_temperament(temp: str, exp_level: str) -> float:
1175
+ """評估品種性格特徵與飼主經驗的匹配度"""
1176
+ score = 0
1177
+
1178
+ # 困難特徵評估
1179
  difficult_traits = {
1180
+ 'stubborn': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': 0},
1181
+ 'independent': {'beginner': -0.15, 'intermediate': -0.08, 'advanced': 0},
1182
+ 'dominant': {'beginner': -0.20, 'intermediate': -0.10, 'advanced': -0.05},
1183
+ 'aggressive': {'beginner': -0.25, 'intermediate': -0.15, 'advanced': -0.10}
 
 
 
 
1184
  }
1185
 
1186
+ # 友善特徵評估
1187
+ friendly_traits = {
1188
+ 'friendly': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0},
1189
+ 'gentle': {'beginner': 0.10, 'intermediate': 0.05, 'advanced': 0},
1190
+ 'easy to train': {'beginner': 0.15, 'intermediate': 0.10, 'advanced': 0.05}
 
 
 
1191
  }
1192
 
1193
+ # 計算特徵分數
1194
+ for trait, penalties in difficult_traits.items():
1195
+ if trait in temp:
1196
+ score += penalties[exp_level]
 
 
 
 
1197
 
1198
+ for trait, bonuses in friendly_traits.items():
1199
+ if trait in temp:
1200
+ score += bonuses[exp_level]
1201
+
1202
+ return score
1203
+
1204
+ temperament_adjustment = evaluate_temperament(temperament, user_prefs.experience_level)
1205
+
1206
+ # 健康問題評估
1207
+ def evaluate_health_needs(health: str, exp_level: str) -> float:
1208
+ """評估健康問題的照護難度"""
1209
+ score = 0
1210
+ serious_conditions = ['hip dysplasia', 'heart disease', 'cancer']
1211
+ moderate_conditions = ['allergies', 'skin problems', 'ear infections']
1212
+
1213
+ # 根據經驗等級調整健康問題的影響
1214
+ health_impact = {
1215
+ 'beginner': {'serious': -0.20, 'moderate': -0.10},
1216
+ 'intermediate': {'serious': -0.15, 'moderate': -0.05},
1217
+ 'advanced': {'serious': -0.10, 'moderate': -0.03}
1218
  }
1219
 
1220
+ for condition in serious_conditions:
1221
+ if condition in health:
1222
+ score += health_impact[exp_level]['serious']
1223
 
1224
+ for condition in moderate_conditions:
1225
+ if condition in health:
1226
+ score += health_impact[exp_level]['moderate']
 
 
 
 
 
 
1227
 
1228
+ return score
 
 
1229
 
1230
+ health_adjustment = evaluate_health_needs(health_issues, user_prefs.experience_level)
 
1231
 
1232
+ # 家庭環境考量
1233
+ family_adjustment = 0
1234
+ if user_prefs.has_children:
1235
+ if user_prefs.children_age == 'toddler':
1236
+ if user_prefs.experience_level == 'beginner':
1237
+ family_adjustment -= 0.15
1238
+ elif user_prefs.experience_level == 'intermediate':
1239
+ family_adjustment -= 0.10
1240
+ elif user_prefs.children_age == 'school_age':
1241
+ if user_prefs.experience_level == 'beginner':
1242
+ family_adjustment -= 0.10
1243
+
1244
+ # 生活方式匹配度
1245
+ lifestyle_adjustments = {
1246
+ 'sedentary': -0.10 if care_level == 'HIGH' else 0,
1247
+ 'moderate': 0,
1248
+ 'active': 0.10 if care_level in ['HIGH', 'MODERATE'] else 0
1249
+ }
1250
+ lifestyle_adjustment = lifestyle_adjustments[user_prefs.lifestyle_activity]
1251
+
1252
+ # 整合所有評分因素
1253
+ final_score = base_score + time_adjustment + temperament_adjustment + \
1254
+ health_adjustment + family_adjustment + lifestyle_adjustment
1255
+
1256
+ # 確保最終分數在合理範圍內
1257
+ return max(0.15, min(1.0, final_score))
1258
+
1259
 
1260
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
1261
  """
 
1365
  return max(0.1, min(1.0, health_score))
1366
 
1367
 
1368
+ # def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
1369
+ # """
1370
+ # 計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
1371
+ # """
1372
+ # if breed_name not in breed_noise_info:
1373
+ # return 0.5
1374
 
1375
+ # noise_info = breed_noise_info[breed_name]
1376
+ # noise_level = noise_info['noise_level'].lower()
1377
+ # noise_notes = noise_info['noise_notes'].lower()
1378
 
1379
+ # # 重新設計基礎噪音分數矩陣,考慮不同情境下的接受度
1380
+ # base_scores = {
1381
+ # 'low': {
1382
+ # 'low': 1.0, # 安靜的狗對低容忍完美匹配
1383
+ # 'medium': 0.95, # 安靜的狗對一般容忍很好
1384
+ # 'high': 0.90 # 安靜的狗對高容忍當然可以
1385
+ # },
1386
+ # 'medium': {
1387
+ # 'low': 0.60, # 一般吠叫對低容忍較困難
1388
+ # 'medium': 0.90, # 一般吠叫對一般容忍可接受
1389
+ # 'high': 0.95 # 一般吠叫對高容忍很好
1390
+ # },
1391
+ # 'high': {
1392
+ # 'low': 0.25, # 愛叫的狗對低容忍極不適合
1393
+ # 'medium': 0.65, # 愛叫的狗對一般容忍有挑戰
1394
+ # 'high': 0.90 # 愛叫的狗對高容忍可以接受
1395
+ # },
1396
+ # 'varies': {
1397
+ # 'low': 0.50, # 不確定的情況對低容忍風險較大
1398
+ # 'medium': 0.75, # 不確定的情況對一般容忍可嘗試
1399
+ # 'high': 0.85 # 不確定的情況對高容忍問題較小
1400
+ # }
1401
+ # }
1402
 
1403
+ # # 取得基礎分數
1404
+ # base_score = base_scores.get(noise_level, {'low': 0.6, 'medium': 0.75, 'high': 0.85})[user_prefs.noise_tolerance]
1405
 
1406
+ # # 吠叫原因評估,根據環境調整懲罰程度
1407
+ # barking_penalties = {
1408
+ # 'separation anxiety': {
1409
+ # 'apartment': -0.30, # 在公寓對鄰居影響更大
1410
+ # 'house_small': -0.25,
1411
+ # 'house_large': -0.20
1412
+ # },
1413
+ # 'excessive barking': {
1414
+ # 'apartment': -0.25,
1415
+ # 'house_small': -0.20,
1416
+ # 'house_large': -0.15
1417
+ # },
1418
+ # 'territorial': {
1419
+ # 'apartment': -0.20, # 在公寓更容易被觸發
1420
+ # 'house_small': -0.15,
1421
+ # 'house_large': -0.10
1422
+ # },
1423
+ # 'alert barking': {
1424
+ # 'apartment': -0.15, # 公寓環境刺激較多
1425
+ # 'house_small': -0.10,
1426
+ # 'house_large': -0.08
1427
+ # },
1428
+ # 'attention seeking': {
1429
+ # 'apartment': -0.15,
1430
+ # 'house_small': -0.12,
1431
+ # 'house_large': -0.10
1432
+ # }
1433
+ # }
1434
+
1435
+ # # 計算環境相關的吠叫懲罰
1436
+ # living_space = user_prefs.living_space
1437
+ # barking_penalty = 0
1438
+ # for trigger, penalties in barking_penalties.items():
1439
+ # if trigger in noise_notes:
1440
+ # barking_penalty += penalties.get(living_space, -0.15)
1441
+
1442
+ # # 特殊情況評估
1443
+ # special_adjustments = 0
1444
+ # if user_prefs.has_children:
1445
+ # # 孩童年齡相關調整
1446
+ # child_age_adjustments = {
1447
+ # 'toddler': {
1448
+ # 'high': -0.20, # 幼童對吵鬧更敏感
1449
+ # 'medium': -0.15,
1450
+ # 'low': -0.05
1451
+ # },
1452
+ # 'school_age': {
1453
+ # 'high': -0.15,
1454
+ # 'medium': -0.10,
1455
+ # 'low': -0.05
1456
+ # },
1457
+ # 'teenager': {
1458
+ # 'high': -0.10,
1459
+ # 'medium': -0.05,
1460
+ # 'low': -0.02
1461
+ # }
1462
+ # }
1463
+
1464
+ # # 根據孩童年齡和噪音等級調整
1465
+ # age_adj = child_age_adjustments.get(user_prefs.children_age,
1466
+ # child_age_adjustments['school_age'])
1467
+ # special_adjustments += age_adj.get(noise_level, -0.10)
1468
+
1469
+ # # 訓練性補償評估
1470
+ # trainability_bonus = 0
1471
+ # if 'responds well to training' in noise_notes:
1472
+ # trainability_bonus = 0.12
1473
+ # elif 'can be trained' in noise_notes:
1474
+ # trainability_bonus = 0.08
1475
+ # elif 'difficult to train' in noise_notes:
1476
+ # trainability_bonus = 0.02
1477
+
1478
+ # # 夜間吠叫特別考量
1479
+ # if 'night barking' in noise_notes or 'howls' in noise_notes:
1480
+ # if user_prefs.living_space == 'apartment':
1481
+ # special_adjustments -= 0.15
1482
+ # elif user_prefs.living_space == 'house_small':
1483
+ # special_adjustments -= 0.10
1484
+ # else:
1485
+ # special_adjustments -= 0.05
1486
+
1487
+ # # 計算最終分數,確保更大的分數範圍
1488
+ # final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1489
+ # return max(0.1, min(1.0, final_score))
1490
+
1491
+
1492
+ def calculate_noise_score(breed_info: dict, user_prefs: UserPreferences) -> float:
1493
+ """
1494
+ 計算品種噪音特性與使用者需求的匹配分數
1495
+
1496
+ 這個函數建立了一個細緻的噪音評估系統,考慮多個關鍵因素:
1497
+ 1. 品種的基本吠叫傾向
1498
+ 2. 居住環境對噪音的敏感度
1499
+ 3. 吠叫的情境和原因
1500
+ 4. 鄰居影響的考量
1501
+ 5. 家庭成員的噪音承受度
1502
+ 6. 訓練可能性的評估
1503
+
1504
+ 特別注意:
1505
+ - 公寓環境的嚴格標準
1506
+ - 有幼童時的特殊考量
1507
+ - 獨處時間的影響
1508
+ - 品種的可訓練性
1509
+
1510
+ Parameters:
1511
+ -----------
1512
+ breed_info: 包含品種特性的字典,包括吠叫傾向和訓練難度
1513
+ user_prefs: 使用者偏好設定,包含噪音容忍度和環境因素
1514
+
1515
+ Returns:
1516
+ --------
1517
+ float: 0.0-1.0 之間的匹配分數,分數越高表示噪音特性越符合需求
1518
+ """
1519
+
1520
+ # 提取基本資訊
1521
+ noise_level = breed_info.get('Noise Level', 'MODERATE').upper()
1522
+ barking_tendency = breed_info.get('Barking Tendency', 'MODERATE').upper()
1523
+ trainability = breed_info.get('Trainability', 'MODERATE').upper()
1524
+ temperament = breed_info.get('Temperament', '').lower()
1525
+
1526
+ # 基礎噪音評分矩陣 - 考慮環境和噪音容忍度
1527
+ base_noise_scores = {
1528
+ "LOW": {
1529
+ "apartment": {
1530
+ "low": 1.0, # 安靜的狗在公寓最理想
1531
+ "medium": 0.95,
1532
+ "high": 0.90
1533
+ },
1534
+ "house_small": {
1535
+ "low": 0.95,
1536
+ "medium": 0.90,
1537
+ "high": 0.85
1538
+ },
1539
+ "house_large": {
1540
+ "low": 0.90,
1541
+ "medium": 0.85,
1542
+ "high": 0.80 # 太安靜可能不夠警戒
1543
+ }
1544
  },
1545
+ "MODERATE": {
1546
+ "apartment": {
1547
+ "low": 0.60,
1548
+ "medium": 0.80,
1549
+ "high": 0.85
1550
+ },
1551
+ "house_small": {
1552
+ "low": 0.70,
1553
+ "medium": 0.85,
1554
+ "high": 0.90
1555
+ },
1556
+ "house_large": {
1557
+ "low": 0.75,
1558
+ "medium": 0.90,
1559
+ "high": 0.95
1560
+ }
1561
  },
1562
+ "HIGH": {
1563
+ "apartment": {
1564
+ "low": 0.20, # 吵鬧的狗在公寓極不適合
1565
+ "medium": 0.40,
1566
+ "high": 0.60
1567
+ },
1568
+ "house_small": {
1569
+ "low": 0.30,
1570
+ "medium": 0.50,
1571
+ "high": 0.70
1572
+ },
1573
+ "house_large": {
1574
+ "low": 0.40,
1575
+ "medium": 0.60,
1576
+ "high": 0.80
1577
+ }
1578
  }
1579
  }
1580
+
1581
+ # 取得基礎噪音分數
1582
+ base_score = base_noise_scores.get(noise_level, base_noise_scores["MODERATE"])\
1583
+ [user_prefs.living_space][user_prefs.noise_tolerance]
1584
+
1585
+ # 吠叫情境評估
1586
+ def evaluate_barking_context(temp: str, living_space: str) -> float:
1587
+ """評估不同情境下的吠叫問題嚴重度"""
1588
+ context_score = 0
1589
+
1590
+ # 不同吠叫原因的權重
1591
+ barking_contexts = {
1592
+ 'separation anxiety': {
1593
+ 'apartment': -0.25,
1594
+ 'house_small': -0.20,
1595
+ 'house_large': -0.15
 
1596
  },
1597
+ 'territorial': {
1598
+ 'apartment': -0.20,
1599
+ 'house_small': -0.15,
1600
+ 'house_large': -0.10
1601
+ },
1602
+ 'alert barking': {
1603
+ 'apartment': -0.15,
1604
+ 'house_small': -0.10,
1605
+ 'house_large': -0.05
1606
  },
1607
+ 'attention seeking': {
1608
+ 'apartment': -0.15,
1609
+ 'house_small': -0.10,
1610
+ 'house_large': -0.08
1611
  }
1612
  }
1613
 
1614
+ for context, penalties in barking_contexts.items():
1615
+ if context in temp:
1616
+ context_score += penalties[living_space]
1617
+
1618
+ return context_score
1619
+
1620
+ # 計算吠叫情境的影響
1621
+ barking_context_adjustment = evaluate_barking_context(temperament, user_prefs.living_space)
1622
+
1623
+ # 訓練可能性評估
1624
+ trainability_adjustments = {
1625
+ "HIGH": 0.10, # 容易訓練可以改善吠叫問題
1626
+ "MODERATE": 0.05,
1627
+ "LOW": -0.05 # 難以訓練則較難改善
1628
+ }
1629
+ trainability_adjustment = trainability_adjustments.get(trainability, 0)
1630
+
1631
+ # 家庭環境考量
1632
+ family_adjustment = 0
1633
+ if user_prefs.has_children:
1634
+ child_age_factors = {
1635
+ 'toddler': -0.20, # 幼童需要安靜環境
1636
+ 'school_age': -0.15,
1637
+ 'teenager': -0.10
1638
+ }
1639
+ family_adjustment = child_age_factors.get(user_prefs.children_age, -0.15)
1640
+
1641
+ # 根據噪音等級調整影響程度
1642
+ if noise_level == "HIGH":
1643
+ family_adjustment *= 1.5
1644
+ elif noise_level == "LOW":
1645
+ family_adjustment *= 0.5
1646
+
1647
+ # 獨處時間的影響
1648
+ alone_time_adjustment = 0
1649
+ if user_prefs.home_alone_time > 6:
1650
+ if 'separation anxiety' in temperament or noise_level == "HIGH":
1651
+ alone_time_adjustment = -0.15
1652
+ elif noise_level == "MODERATE":
1653
+ alone_time_adjustment = -0.10
1654
+
1655
+ # 鄰居影響評估(特別是公寓環境)
1656
+ neighbor_adjustment = 0
1657
+ if user_prefs.living_space == "apartment":
1658
+ if noise_level == "HIGH":
1659
+ neighbor_adjustment = -0.15
1660
+ elif noise_level == "MODERATE":
1661
+ neighbor_adjustment = -0.10
1662
+
1663
+ # 樓層因素
1664
+ if user_prefs.living_floor > 1:
1665
+ neighbor_adjustment -= min(0.10, (user_prefs.living_floor - 1) * 0.02)
1666
+
1667
+ # 整合所有評分因素
1668
+ final_score = base_score + barking_context_adjustment + trainability_adjustment + \
1669
+ family_adjustment + alone_time_adjustment + neighbor_adjustment
1670
+
1671
+ # 確保最終分數在合理範圍內
1672
+ return max(0.15, min(1.0, final_score))
1673
 
1674
 
1675
  # 1. 計算基礎分數
 
1764
  return min(0.2, adaptability_score)
1765
 
1766
 
1767
+ # def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1768
+ # """
1769
+ # 改進的品種相容性評分系統
1770
+ # 通過更細緻的特徵評估和動態權重調整,自然產生分數差異
1771
+ # """
1772
+ # # 評估關鍵特徵的匹配度,使用更極端的調整係數
1773
+ # def evaluate_key_features():
1774
+ # # 空間適配性評估
1775
+ # space_multiplier = 1.0
1776
+ # if user_prefs.living_space == 'apartment':
1777
+ # if breed_info['Size'] == 'Giant':
1778
+ # space_multiplier = 0.3 # 嚴重不適合
1779
+ # elif breed_info['Size'] == 'Large':
1780
+ # space_multiplier = 0.4 # 明顯不適合
1781
+ # elif breed_info['Size'] == 'Small':
1782
+ # space_multiplier = 1.4 # 明顯優勢
1783
 
1784
+ # # 運動需求評估
1785
+ # exercise_multiplier = 1.0
1786
+ # exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1787
+ # if exercise_needs == 'VERY HIGH':
1788
+ # if user_prefs.exercise_time < 60:
1789
+ # exercise_multiplier = 0.3 # 嚴重不足
1790
+ # elif user_prefs.exercise_time > 150:
1791
+ # exercise_multiplier = 1.5 # 完美匹配
1792
+ # elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150:
1793
+ # exercise_multiplier = 0.5 # 運動過度
1794
 
1795
+ # return space_multiplier, exercise_multiplier
1796
 
1797
+ # # 計算經驗匹配度
1798
+ # def evaluate_experience():
1799
+ # exp_multiplier = 1.0
1800
+ # care_level = breed_info.get('Care Level', 'MODERATE')
1801
 
1802
+ # if care_level == 'High':
1803
+ # if user_prefs.experience_level == 'beginner':
1804
+ # exp_multiplier = 0.4
1805
+ # elif user_prefs.experience_level == 'advanced':
1806
+ # exp_multiplier = 1.3
1807
+ # elif care_level == 'Low':
1808
+ # if user_prefs.experience_level == 'advanced':
1809
+ # exp_multiplier = 0.9 # 略微降低評分,因為可能不夠有挑戰性
1810
 
1811
+ # return exp_multiplier
1812
 
1813
+ # # 取得特徵調整係數
1814
+ # space_mult, exercise_mult = evaluate_key_features()
1815
+ # exp_mult = evaluate_experience()
1816
 
1817
+ # # 調整基礎分數
1818
+ # adjusted_scores = {
1819
+ # 'space': scores['space'] * space_mult,
1820
+ # 'exercise': scores['exercise'] * exercise_mult,
1821
+ # 'experience': scores['experience'] * exp_mult,
1822
+ # 'grooming': scores['grooming'],
1823
+ # 'health': scores['health'],
1824
+ # 'noise': scores['noise']
1825
+ # }
1826
 
1827
+ # # 計算加權平均,關鍵特徵佔更大權重
1828
+ # weights = {
1829
+ # 'space': 0.35,
1830
+ # 'exercise': 0.30,
1831
+ # 'experience': 0.20,
1832
+ # 'grooming': 0.15,
1833
+ # 'health': 0.10,
1834
+ # 'noise': 0.10
1835
+ # }
1836
 
1837
+ # # 動態調整權重
1838
+ # if user_prefs.living_space == 'apartment':
1839
+ # weights['space'] *= 1.5
1840
+ # weights['noise'] *= 1.3
1841
 
1842
+ # if abs(user_prefs.exercise_time - 120) > 60: # 運動時間極端情況
1843
+ # weights['exercise'] *= 1.4
1844
+
1845
+ # # 正規化權重
1846
+ # total_weight = sum(weights.values())
1847
+ # normalized_weights = {k: v/total_weight for k, v in weights.items()}
1848
 
1849
+ # # 計算最終分數
1850
+ # final_score = sum(adjusted_scores[k] * normalized_weights[k] for k in scores.keys())
1851
+
1852
+ # # 品種特性加成
1853
+ # breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
1854
+
1855
+ # # 整合最終分數,保持在0-1範圍內
1856
+ # return min(1.0, max(0.0, (final_score * 0.85) + (breed_bonus * 0.15)))
1857
 
 
 
1858
 
1859
+ def calculate_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1860
+ """
1861
+ 計算品種與使用者的整體相容性分數
1862
+
1863
+ 這是推薦系統的核心評分函數,負責:
1864
+ 1. 智能整合各面向評分
1865
+ 2. 動態調整評分權重
1866
+ 3. 處理關鍵條件的優先級
1867
+ 4. 產生最終的匹配分數
1868
+
1869
+ 評分策略:
1870
+ - 基礎分數:由各項指標的加權平均獲得
1871
+ - 動態權重:根據用戶情況動態調整各項權重
1872
+ - 關鍵條件:某些條件不滿足會顯著降低總分
1873
+ - 加成系統:特殊匹配會提供額外加分
1874
+
1875
+ Parameters:
1876
+ -----------
1877
+ scores: 包含各項評分的字典
1878
+ user_prefs: 使用者偏好設定
1879
+ breed_info: 品種特性信息
1880
+
1881
+ Returns:
1882
+ --------
1883
+ float: 60.0-95.0 之間的最終匹配分數
1884
+ """
1885
+ def calculate_dynamic_weights() -> dict:
1886
+ """計算動態權重分配"""
1887
+ # 基礎權重設定
1888
+ weights = {
1889
+ 'space': 0.20,
1890
+ 'exercise': 0.20,
1891
+ 'experience': 0.15,
1892
+ 'grooming': 0.15,
1893
+ 'health': 0.15,
1894
+ 'noise': 0.15
1895
+ }
1896
+
1897
+ # 公寓住戶權重調整
1898
+ if user_prefs.living_space == "apartment":
1899
+ weights['space'] *= 1.3
1900
+ weights['noise'] *= 1.3
1901
+ weights['exercise'] *= 0.8
1902
+
1903
+ # 有幼童時的權重調整
1904
+ if user_prefs.has_children and user_prefs.children_age == 'toddler':
1905
+ weights['experience'] *= 1.3
1906
+ weights['noise'] *= 1.2
1907
+ weights['health'] *= 1.2
1908
+
1909
+ # 新手飼主的權重調整
1910
+ if user_prefs.experience_level == 'beginner':
1911
+ weights['experience'] *= 1.4
1912
+ weights['health'] *= 1.2
1913
+ weights['grooming'] *= 1.2
1914
+
1915
+ # 健康敏感度的權重調整
1916
+ if user_prefs.health_sensitivity == 'high':
1917
+ weights['health'] *= 1.3
1918
+
1919
+ # 運動時間極端情況的權重調整
1920
+ if abs(user_prefs.exercise_time - 120) > 60:
1921
+ weights['exercise'] *= 1.3
1922
+
1923
+ # 正規化權重
1924
+ total = sum(weights.values())
1925
+ return {k: v/total for k, v in weights.items()}
1926
 
1927
+ def calculate_critical_factors() -> float:
1928
+ """評估關鍵因素的影響"""
1929
+ critical_score = 1.0
1930
+
1931
+ # 空間關鍵條件
1932
+ if user_prefs.living_space == "apartment":
1933
+ if breed_info['Size'] == 'Giant':
1934
+ critical_score *= 0.7
1935
+ elif breed_info['Size'] == 'Large':
1936
+ critical_score *= 0.8
1937
+
1938
+ # 運動需求關鍵條件
1939
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1940
+ if exercise_needs == 'VERY HIGH' and user_prefs.exercise_time < 60:
1941
+ critical_score *= 0.75
1942
+ elif exercise_needs == 'HIGH' and user_prefs.exercise_time < 45:
1943
+ critical_score *= 0.8
1944
+
1945
+ # 新手飼主關鍵條件
1946
+ if user_prefs.experience_level == 'beginner':
1947
+ if 'aggressive' in breed_info.get('Temperament', '').lower():
1948
+ critical_score *= 0.7
1949
+ elif 'dominant' in breed_info.get('Temperament', '').lower():
1950
+ critical_score *= 0.8
1951
+
1952
+ # 噪音關鍵條件
1953
+ if user_prefs.living_space == "apartment" and \
1954
+ breed_info.get('Noise Level', 'MODERATE').upper() == 'HIGH' and \
1955
+ user_prefs.noise_tolerance == 'low':
1956
+ critical_score *= 0.7
1957
+
1958
+ return critical_score
1959
 
1960
+ def calculate_bonus_factors() -> float:
1961
+ """計算額外加分因素"""
1962
+ bonus = 1.0
1963
+ temperament = breed_info.get('Temperament', '').lower()
1964
+
1965
+ # 完美匹配加分
1966
+ perfect_matches = 0
1967
+ for score in scores.values():
1968
+ if score > 0.9:
1969
+ perfect_matches += 1
1970
+
1971
+ if perfect_matches >= 3:
1972
+ bonus += 0.05
1973
+
1974
+ # 特殊匹配加分
1975
+ if user_prefs.has_children and 'good with children' in temperament:
1976
+ bonus += 0.03
1977
+
1978
+ if user_prefs.living_space == "apartment" and 'adaptable' in temperament:
1979
+ bonus += 0.03
1980
+
1981
+ if user_prefs.experience_level == 'beginner' and 'easy to train' in temperament:
1982
+ bonus += 0.03
1983
+
1984
+ return min(1.15, bonus)
1985
+
1986
+ # 計算動態權重
1987
+ weights = calculate_dynamic_weights()
1988
+
1989
+ # 計算基礎加權分數
1990
+ base_score = sum(scores[k] * weights[k] for k in scores.keys())
1991
+
1992
+ # 應用關鍵因素
1993
+ critical_factor = calculate_critical_factors()
1994
+
1995
+ # 計算加分
1996
+ bonus_factor = calculate_bonus_factors()
1997
+
1998
+ # 計算最終原始分數
1999
+ raw_score = base_score * critical_factor * bonus_factor
2000
+
2001
+ # 轉���為最終分數(60-95範圍)
2002
+ final_score = 60 + (raw_score * 35)
2003
+
2004
+ # 確保分數在合理範圍內並保留兩位小數
2005
+ return round(max(60.0, min(95.0, final_score)), 2)
2006
+
2007
+
2008
+ # def amplify_score_extreme(score: float) -> float:
2009
+ # """
2010
+ # 改進的分數轉換函數
2011
+ # 提供更大的分數範圍和更明顯的差異
2012
+
2013
+ # 轉換邏輯:
2014
+ # - 極差匹配 (0.0-0.3) -> 60-68%
2015
+ # - 較差匹配 (0.3-0.5) -> 68-75%
2016
+ # - 中等匹配 (0.5-0.7) -> 75-85%
2017
+ # - 良好匹配 (0.7-0.85) -> 85-92%
2018
+ # - 優秀匹配 (0.85-1.0) -> 92-95%
2019
+ # """
2020
+ # if score < 0.3:
2021
+ # # 極差匹配:快速線性增長
2022
+ # return 0.60 + (score / 0.3) * 0.08
2023
+ # elif score < 0.5:
2024
+ # # 較差匹配:緩慢增長
2025
+ # position = (score - 0.3) / 0.2
2026
+ # return 0.68 + position * 0.07
2027
+ # elif score < 0.7:
2028
+ # # 中等匹配:穩定線性增長
2029
+ # position = (score - 0.5) / 0.2
2030
+ # return 0.75 + position * 0.10
2031
+ # elif score < 0.85:
2032
+ # # 良好匹配:加速增長
2033
+ # position = (score - 0.7) / 0.15
2034
+ # return 0.85 + position * 0.07
2035
+ # else:
2036
+ # # 優秀匹配:最後衝刺
2037
+ # position = (score - 0.85) / 0.15
2038
+ # return 0.92 + position * 0.03
2039
+
2040
 
2041
  def amplify_score_extreme(score: float) -> float:
2042
  """
2043
+ 將原始相容性分數(0-1)轉換為最終評分(60-95)
2044
+
2045
+ 這個函數負責:
2046
+ 1. 將內部計算的原始分數轉換為更有意義的最終分數
2047
+ 2. 確保分數分布更自然且有區別性
2048
+ 3. 突出極佳和極差的匹配
2049
+ 4. 避免分數過度集中在中間區域
2050
+
2051
+ 轉換策略:
2052
+ - 極佳匹配(0.85-1.0):轉換為 90-95 分
2053
+ - 優良匹配(0.70-0.85):轉換為 85-90 分
2054
+ - 良好匹配(0.55-0.70):轉換為 75-85 分
2055
+ - 一般匹配(0.40-0.55):轉換為 70-75 分
2056
+ - 勉強匹配(0.25-0.40):轉換為 65-70 分
2057
+ - 不推薦匹配(0-0.25):轉換為 60-65 分
2058
+
2059
+ Parameters:
2060
+ -----------
2061
+ score: 原始相容性分數(0.0-1.0)
2062
+
2063
+ Returns:
2064
+ --------
2065
+ float: 轉換後的最終分數(60.0-95.0)
2066
  """
2067
+ # 使用分段函數進行更自然的轉換
2068
+ if score >= 0.85:
2069
+ # 極佳匹配:90-95分
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2070
  position = (score - 0.85) / 0.15
2071
+ return 90.0 + (position * 5.0)
2072
+ elif score >= 0.70:
2073
+ # 優良匹配:85-90分
2074
+ position = (score - 0.70) / 0.15
2075
+ return 85.0 + (position * 5.0)
2076
+ elif score >= 0.55:
2077
+ # 良好匹配:75-85分
2078
+ position = (score - 0.55) / 0.15
2079
+ return 75.0 + (position * 10.0)
2080
+ elif score >= 0.40:
2081
+ # 一般匹配:70-75分
2082
+ position = (score - 0.40) / 0.15
2083
+ return 70.0 + (position * 5.0)
2084
+ elif score >= 0.25:
2085
+ # 勉強匹配:65-70分
2086
+ position = (score - 0.25) / 0.15
2087
+ return 65.0 + (position * 5.0)
2088
+ else:
2089
+ # 不推薦匹配:60-65分
2090
+ position = score / 0.25
2091
+ return 60.0 + (position * 5.0)