DawnC commited on
Commit
11269b9
1 Parent(s): 3260820

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +298 -400
scoring_calculation_system.py CHANGED
@@ -372,69 +372,117 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
372
  print("Missing Size information")
373
  raise KeyError("Size information missing")
374
 
 
375
  # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
376
- # """空間分數計算"""
377
- # # 基礎空間需求矩陣
378
  # base_scores = {
379
- # "Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90},
380
- # "Medium": {"apartment": 0.60, "house_small": 0.90, "house_large": 1.0},
381
- # "Large": {"apartment": 0.30, "house_small": 0.75, "house_large": 1.0},
382
- # "Giant": {"apartment": 0.15, "house_small": 0.55, "house_large": 1.0}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  # }
384
 
385
  # # 取得基礎分數
386
  # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
387
 
388
- # # 運動需求調整
389
  # exercise_adjustments = {
390
- # "Very High": -0.15 if living_space == "apartment" else 0,
391
- # "High": -0.10 if living_space == "apartment" else 0,
392
- # "Moderate": 0,
393
- # "Low": 0.05 if living_space == "apartment" else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  # }
395
 
396
- # adjustments = exercise_adjustments.get(exercise_needs.strip(), 0)
 
 
397
 
398
- # # 院子獎勵
399
- # if has_yard and size in ["Large", "Giant"]:
400
- # adjustments += 0.10
401
- # elif has_yard:
402
- # adjustments += 0.05
403
-
404
- # return min(1.0, max(0.1, base_score + adjustments))
 
 
 
 
 
 
405
 
406
  def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
407
- # 重新設計基礎分數矩陣
 
 
 
 
 
 
 
 
408
  base_scores = {
409
  "Small": {
410
- "apartment": 1.0, # 小型犬最適合公寓
411
- "house_small": 0.95, # 在大房子反而稍微降分
412
- "house_large": 0.85 # 可能浪費空間
413
  },
414
  "Medium": {
415
- "apartment": 0.45, # 中型犬在公寓明顯受限
416
- "house_small": 0.85,
417
- "house_large": 1.0
418
  },
419
  "Large": {
420
- "apartment": 0.15, # 大型犬在公寓極不適合
421
- "house_small": 0.60, # 在小房子仍然受限
422
- "house_large": 1.0
423
  },
424
  "Giant": {
425
- "apartment": 0.1, # 更嚴格的限制
426
- "house_small": 0.45,
427
- "house_large": 1.0
428
  }
429
  }
430
 
431
  # 取得基礎分數
432
  base_score = base_scores.get(size, base_scores["Medium"])[living_space]
433
 
434
- # 運動需求調整更明顯
435
  exercise_adjustments = {
436
  "Very High": {
437
- "apartment": -0.25, # 在公寓更嚴重的懲罰
438
  "house_small": -0.15,
439
  "house_large": -0.05
440
  },
@@ -449,74 +497,133 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
449
  "house_large": 0
450
  },
451
  "Low": {
452
- "apartment": 0.05,
453
  "house_small": 0,
454
- "house_large": 0
455
  }
456
  }
457
 
458
- # 根據空間類型獲取對應的運動調整
459
  adjustment = exercise_adjustments.get(exercise_needs,
460
  exercise_adjustments["Moderate"])[living_space]
461
 
462
- # 院子獎勵也要根據犬種大小調整
463
- yard_bonus = 0
464
  if has_yard:
465
- if size in ["Large", "Giant"]:
466
- yard_bonus = 0.20 if living_space != "apartment" else 0.10
467
- elif size == "Medium":
468
- yard_bonus = 0.15 if living_space != "apartment" else 0.08
469
- else:
470
- yard_bonus = 0.10 if living_space != "apartment" else 0.05
 
 
 
 
 
 
471
 
472
- final_score = base_score + adjustment + yard_bonus
473
- return min(1.0, max(0.1, final_score))
 
 
 
 
 
474
 
475
- def calculate_exercise_score(breed_needs: str, user_time: int) -> float:
476
- """運動需求計算"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  exercise_needs = {
478
- 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
479
- 'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
480
- 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90},
481
- 'LOW': {'min': 20, 'ideal': 30, 'max': 45},
482
- 'VARIES': {'min': 30, 'ideal': 60, 'max': 90}
483
  }
484
 
485
  breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
486
 
487
- # 計算匹配度
488
- if user_time >= breed_need['ideal']:
489
- if user_time > breed_need['max']:
490
- return 0.9 # 稍微降分,因為可能過度運動
491
- return 1.0
492
- elif user_time >= breed_need['min']:
493
- return 0.8 + (user_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.2
494
  else:
495
- return max(0.3, 0.8 * (user_time / breed_need['min']))
496
-
497
- # def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
498
- # """美容需求計算"""
499
- # # 基礎分數矩陣
500
- # base_scores = {
501
- # "High": {"low": 0.3, "medium": 0.7, "high": 1.0},
502
- # "Moderate": {"low": 0.5, "medium": 0.9, "high": 1.0},
503
- # "Low": {"low": 1.0, "medium": 0.95, "high": 0.8}
504
- # }
 
 
 
 
 
 
 
 
 
 
 
 
 
505
 
506
- # # 取得基礎分數
507
- # base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
508
 
509
- # # 體型影響調整
510
- # size_adjustments = {
511
- # "Large": {"low": -0.2, "medium": -0.1, "high": 0},
512
- # "Giant": {"low": -0.3, "medium": -0.15, "high": 0},
513
- # }
 
514
 
515
- # if breed_size in size_adjustments:
516
- # adjustment = size_adjustments[breed_size].get(user_commitment, 0)
517
- # base_score = max(0.2, base_score + adjustment)
518
-
519
- # return base_score
 
 
 
 
 
 
 
520
 
521
 
522
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
@@ -648,113 +755,6 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
648
 
649
  # 確保分數在有意義的範圍內,但允許更大的差異
650
  return max(0.1, min(1.0, final_score))
651
-
652
-
653
- # def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
654
- # """
655
- # 計算使用者經驗與品種需求的匹配分數
656
-
657
- # 參數說明:
658
- # care_level: 品種的照顧難度 ("High", "Moderate", "Low")
659
- # user_experience: 使用者經驗等級 ("beginner", "intermediate", "advanced")
660
- # temperament: 品種的性格特徵描述
661
-
662
- # 返回:
663
- # float: 0.2-1.0 之間的匹配分數
664
- # """
665
- # # 基礎分數矩陣 - 更大的分數差異來反映經驗重要性
666
- # base_scores = {
667
- # "High": {
668
- # "beginner": 0.12, # 降低起始分,反映高難度品種對新手的挑戰
669
- # "intermediate": 0.65, # 中級玩家可以應付,但仍有改善空間
670
- # "advanced": 1.0 # 資深者能完全勝任
671
- # },
672
- # "Moderate": {
673
- # "beginner": 0.35, # 適中難度對新手來說仍具挑戰
674
- # "intermediate": 0.82, # 中級玩家有很好的勝任能力
675
- # "advanced": 1.0 # 資深者完全勝任
676
- # },
677
- # "Low": {
678
- # "beginner": 0.72, # 低難度品種適合新手
679
- # "intermediate": 0.92, # 中級玩家幾乎完全勝任
680
- # "advanced": 1.0 # 資深者完全勝任
681
- # }
682
- # }
683
-
684
- # # 取得基礎分數
685
- # score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
686
-
687
- # # 性格特徵評估 - 根據經驗等級調整權重
688
- # temperament_lower = temperament.lower()
689
- # temperament_adjustments = 0.0
690
-
691
- # if user_experience == "beginner":
692
- # # 新手不適合的特徵 - 更嚴格的懲罰
693
- # difficult_traits = {
694
- # 'stubborn': -0.15, # 加重固執的懲罰
695
- # 'independent': -0.12, # 加重獨立性的懲罰
696
- # 'dominant': -0.12, # 加重支配性的懲罰
697
- # 'strong-willed': -0.10, # 加重強勢的懲罰
698
- # 'protective': -0.08, # 加重保護性的懲罰
699
- # 'aloof': -0.08, # 加重冷漠的懲罰
700
- # 'energetic': -0.06 # 輕微懲罰高能量
701
- # }
702
-
703
- # # 新手友善的特徵 - 提供更多獎勵
704
- # easy_traits = {
705
- # 'gentle': 0.08, # 增加溫和的獎勵
706
- # 'friendly': 0.08, # 增加友善的獎勵
707
- # 'eager to please': 0.08, # 增加順從的獎勵
708
- # 'patient': 0.06, # 獎勵耐心
709
- # 'adaptable': 0.06, # 獎勵適應性
710
- # 'calm': 0.05 # 獎勵冷靜
711
- # }
712
-
713
- # # 計算特徵調整
714
- # for trait, penalty in difficult_traits.items():
715
- # if trait in temperament_lower:
716
- # temperament_adjustments += penalty * 1.2 # 加重新手的懲罰
717
-
718
- # for trait, bonus in easy_traits.items():
719
- # if trait in temperament_lower:
720
- # temperament_adjustments += bonus
721
-
722
- # # 品種特殊調整
723
- # if any(term in temperament_lower for term in ['terrier', 'working', 'guard']):
724
- # temperament_adjustments -= 0.12 # 加重對特定類型品種的懲罰
725
-
726
- # elif user_experience == "intermediate":
727
- # # 中級玩家的調整更加平衡
728
- # moderate_traits = {
729
- # 'intelligent': 0.05, # 獎勵聰明
730
- # 'athletic': 0.04, # 獎勵運動能力
731
- # 'versatile': 0.04, # 獎勵多功能性
732
- # 'stubborn': -0.06, # 輕微懲罰固執
733
- # 'independent': -0.05, # 輕微懲罰獨立性
734
- # 'protective': -0.04 # 輕微懲罰保護性
735
- # }
736
-
737
- # for trait, adjustment in moderate_traits.items():
738
- # if trait in temperament_lower:
739
- # temperament_adjustments += adjustment
740
-
741
- # else: # advanced
742
- # # 資深玩家能夠應對挑戰性特徵
743
- # advanced_traits = {
744
- # 'stubborn': 0.04, # 反轉為優勢
745
- # 'independent': 0.04, # 反轉為優勢
746
- # 'intelligent': 0.05, # 獎勵聰明
747
- # 'protective': 0.04, # 獎勵保護性
748
- # 'strong-willed': 0.03 # 獎勵強勢
749
- # }
750
-
751
- # for trait, bonus in advanced_traits.items():
752
- # if trait in temperament_lower:
753
- # temperament_adjustments += bonus
754
-
755
- # # 確保最終分數在合理範圍內
756
- # final_score = max(0.2, min(1.0, score + temperament_adjustments))
757
- # return final_score
758
 
759
 
760
  def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
@@ -866,72 +866,6 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
866
 
867
  return final_score
868
 
869
-
870
- # def calculate_health_score(breed_name: str) -> float:
871
- # """計算品種健康分數"""
872
- # if breed_name not in breed_health_info:
873
- # return 0.5
874
-
875
- # health_notes = breed_health_info[breed_name]['health_notes'].lower()
876
-
877
- # # 嚴重健康問題(降低0.15分)
878
- # severe_conditions = [
879
- # 'hip dysplasia',
880
- # 'heart disease',
881
- # 'progressive retinal atrophy',
882
- # 'bloat',
883
- # 'epilepsy',
884
- # 'degenerative myelopathy',
885
- # 'von willebrand disease'
886
- # ]
887
-
888
- # # 中度健康問題(降低0.1分)
889
- # moderate_conditions = [
890
- # 'allergies',
891
- # 'eye problems',
892
- # 'joint problems',
893
- # 'hypothyroidism',
894
- # 'ear infections',
895
- # 'skin issues'
896
- # ]
897
-
898
- # # 輕微健康問題(降低0.05分)
899
- # minor_conditions = [
900
- # 'dental issues',
901
- # 'weight gain tendency',
902
- # 'minor allergies',
903
- # 'seasonal allergies'
904
- # ]
905
-
906
- # # 計算基礎健康分數
907
- # health_score = 1.0
908
-
909
- # # 根據問題嚴重程度扣分
910
- # severe_count = sum(1 for condition in severe_conditions if condition in health_notes)
911
- # moderate_count = sum(1 for condition in moderate_conditions if condition in health_notes)
912
- # minor_count = sum(1 for condition in minor_conditions if condition in health_notes)
913
-
914
- # health_score -= (severe_count * 0.15)
915
- # health_score -= (moderate_count * 0.1)
916
- # health_score -= (minor_count * 0.05)
917
-
918
- # # 壽命影響
919
- # try:
920
- # lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
921
- # years = float(lifespan.split('-')[0])
922
- # if years < 8:
923
- # health_score *= 0.9
924
- # elif years > 13:
925
- # health_score *= 1.1
926
- # except:
927
- # pass
928
-
929
- # # 特殊健康優勢
930
- # if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
931
- # health_score *= 1.1
932
-
933
- # return max(0.2, min(1.0, health_score))
934
-
935
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
936
  """
937
  計算品種健康分數,加強健康問題的影響力和與使用者敏感度的連結
@@ -1040,58 +974,6 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1040
  return max(0.1, min(1.0, health_score))
1041
 
1042
 
1043
- # def calculate_noise_score(breed_name: str, user_noise_tolerance: str) -> float:
1044
- # """計算品種噪音分數"""
1045
- # if breed_name not in breed_noise_info:
1046
- # return 0.5
1047
-
1048
- # noise_info = breed_noise_info[breed_name]
1049
- # noise_level = noise_info['noise_level'].lower()
1050
- # noise_notes = noise_info['noise_notes'].lower()
1051
-
1052
- # # 基礎噪音分數矩陣
1053
- # base_scores = {
1054
- # 'low': {'low': 1.0, 'medium': 0.9, 'high': 0.8},
1055
- # 'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.9},
1056
- # 'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0},
1057
- # 'varies': {'low': 0.6, 'medium': 0.8, 'high': 0.9}
1058
- # }
1059
-
1060
- # # 獲取基礎分數
1061
- # base_score = base_scores.get(noise_level, {'low': 0.7, 'medium': 0.8, 'high': 0.6})[user_noise_tolerance]
1062
-
1063
- # # 吠叫原因評估
1064
- # barking_reasons_penalty = 0
1065
- # problematic_triggers = [
1066
- # ('separation anxiety', -0.15),
1067
- # ('excessive barking', -0.12),
1068
- # ('territorial', -0.08),
1069
- # ('alert barking', -0.05),
1070
- # ('attention seeking', -0.05)
1071
- # ]
1072
-
1073
- # for trigger, penalty in problematic_triggers:
1074
- # if trigger in noise_notes:
1075
- # barking_reasons_penalty += penalty
1076
-
1077
- # # 可訓練性補償
1078
- # trainability_bonus = 0
1079
- # if 'responds well to training' in noise_notes:
1080
- # trainability_bonus = 0.1
1081
- # elif 'can be trained' in noise_notes:
1082
- # trainability_bonus = 0.05
1083
-
1084
- # # 特殊情況
1085
- # special_adjustments = 0
1086
- # if 'rarely barks' in noise_notes:
1087
- # special_adjustments += 0.1
1088
- # if 'howls' in noise_notes and user_noise_tolerance == 'low':
1089
- # special_adjustments -= 0.1
1090
-
1091
- # final_score = base_score + barking_reasons_penalty + trainability_bonus + special_adjustments
1092
-
1093
- # return max(0.2, min(1.0, final_score))
1094
-
1095
  def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
1096
  """
1097
  計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
@@ -1215,83 +1097,6 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1215
  final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1216
  return max(0.1, min(1.0, final_score))
1217
 
1218
-
1219
- # # 計算所有基礎分數
1220
- # scores = {
1221
- # 'space': calculate_space_score(
1222
- # breed_info['Size'],
1223
- # user_prefs.living_space,
1224
- # user_prefs.space_for_play,
1225
- # breed_info.get('Exercise Needs', 'Moderate')
1226
- # ),
1227
- # 'exercise': calculate_exercise_score(
1228
- # breed_info.get('Exercise Needs', 'Moderate'),
1229
- # user_prefs.exercise_time
1230
- # ),
1231
- # 'grooming': calculate_grooming_score(
1232
- # breed_info.get('Grooming Needs', 'Moderate'),
1233
- # user_prefs.grooming_commitment.lower(),
1234
- # breed_info['Size']
1235
- # ),
1236
- # 'experience': calculate_experience_score(
1237
- # breed_info.get('Care Level', 'Moderate'),
1238
- # user_prefs.experience_level,
1239
- # breed_info.get('Temperament', '')
1240
- # ),
1241
- # 'health': calculate_health_score(breed_info.get('Breed', '')),
1242
- # 'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance)
1243
- # }
1244
-
1245
-
1246
- # # 優化權重配置
1247
- # weights = {
1248
- # 'space': 0.28,
1249
- # 'exercise': 0.18,
1250
- # 'grooming': 0.12,
1251
- # 'experience': 0.22,
1252
- # 'health': 0.12,
1253
- # 'noise': 0.08
1254
- # }
1255
-
1256
- # # 計算加權總分
1257
- # weighted_score = sum(score * weights[category] for category, score in scores.items())
1258
-
1259
- # def amplify_score(score):
1260
- # """
1261
- # 優化分數放大函數,確保分數範圍合理且結果一致
1262
- # """
1263
- # # 基礎調整
1264
- # adjusted = (score - 0.35) * 1.8
1265
-
1266
- # # 使用 3.2 次方使曲線更平滑
1267
- # amplified = pow(adjusted, 3.2) / 5.8 + score
1268
-
1269
- # # 特別處理高分區間,確保不超過95%
1270
- # if amplified > 0.90:
1271
- # # 壓縮高分區間,確保最高到95%
1272
- # amplified = 0.90 + (amplified - 0.90) * 0.5
1273
-
1274
- # # 確保最終分數在合理範圍內(0.55-0.95)
1275
- # final_score = max(0.55, min(0.95, amplified))
1276
-
1277
- # # 四捨五入到小數點後第三位
1278
- # return round(final_score, 3)
1279
-
1280
- # final_score = amplify_score(weighted_score)
1281
-
1282
- # # 四捨五入所有分數
1283
- # scores = {k: round(v, 4) for k, v in scores.items()}
1284
- # scores['overall'] = round(final_score, 4)
1285
-
1286
- # return scores
1287
-
1288
- # except Exception as e:
1289
- # print(f"Error details: {str(e)}")
1290
- # print(f"breed_info: {breed_info}")
1291
- # # print(f"Error in calculate_compatibility_score: {str(e)}")
1292
- # return {k: 0.6 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}
1293
-
1294
- #
1295
  print("\n=== 開始計算品種相容性分數 ===")
1296
  print(f"處理品種: {breed_info.get('Breed', 'Unknown')}")
1297
  print(f"品種信息: {breed_info}")
@@ -1396,35 +1201,128 @@ def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences)
1396
 
1397
  return penalty
1398
 
1399
- # 計算權重和加權分數
1400
- def calculate_weighted_score(scores: dict) -> float:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1401
  """
1402
- 使用動態權重計算加權分數
 
 
 
 
 
1403
  """
 
1404
  base_weights = {
1405
- 'space': 0.28,
1406
- 'exercise': 0.18,
1407
- 'grooming': 0.12,
1408
- 'experience': 0.22,
1409
  'health': 0.12,
1410
- 'noise': 0.08
1411
  }
1412
 
 
 
 
 
 
 
 
 
 
 
 
1413
  # 根據居住環境調整權重
1414
  if user_prefs.living_space == 'apartment':
 
1415
  base_weights['space'] *= 1.2
 
 
 
 
 
 
1416
  base_weights['noise'] *= 1.2
1417
-
1418
- # 根據經驗等級調整權重
1419
- if user_prefs.experience_level == 'beginner':
1420
- base_weights['experience'] *= 1.3
1421
-
1422
  # 重新正規化權重
1423
  total_weight = sum(base_weights.values())
1424
  weights = {k: v/total_weight for k, v in base_weights.items()}
1425
 
1426
- # 計算加權分數
1427
- return sum(score * weights[category] for category, score in scores.items())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1428
 
1429
  # 計算最終分數
1430
  def calculate_final_score(base_score: float, penalty: float) -> float:
 
372
  print("Missing Size information")
373
  raise KeyError("Size information missing")
374
 
375
+
376
  # def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
377
+ # # 重新設計基礎分數矩陣
 
378
  # base_scores = {
379
+ # "Small": {
380
+ # "apartment": 1.0, # 小型犬最適合公寓
381
+ # "house_small": 0.95, # 在大房子反而稍微降分
382
+ # "house_large": 0.85 # 可能浪費空間
383
+ # },
384
+ # "Medium": {
385
+ # "apartment": 0.45, # 中型犬在公寓明顯受限
386
+ # "house_small": 0.85,
387
+ # "house_large": 1.0
388
+ # },
389
+ # "Large": {
390
+ # "apartment": 0.15, # 大型犬在公寓極不適合
391
+ # "house_small": 0.60, # 在小房子仍然受限
392
+ # "house_large": 1.0
393
+ # },
394
+ # "Giant": {
395
+ # "apartment": 0.1, # 更嚴格的限制
396
+ # "house_small": 0.45,
397
+ # "house_large": 1.0
398
+ # }
399
  # }
400
 
401
  # # 取得基礎分數
402
  # base_score = base_scores.get(size, base_scores["Medium"])[living_space]
403
 
404
+ # # 運動需求調整更明顯
405
  # exercise_adjustments = {
406
+ # "Very High": {
407
+ # "apartment": -0.25, # 在公寓更嚴重的懲罰
408
+ # "house_small": -0.15,
409
+ # "house_large": -0.05
410
+ # },
411
+ # "High": {
412
+ # "apartment": -0.20,
413
+ # "house_small": -0.10,
414
+ # "house_large": 0
415
+ # },
416
+ # "Moderate": {
417
+ # "apartment": -0.10,
418
+ # "house_small": -0.05,
419
+ # "house_large": 0
420
+ # },
421
+ # "Low": {
422
+ # "apartment": 0.05,
423
+ # "house_small": 0,
424
+ # "house_large": 0
425
+ # }
426
  # }
427
 
428
+ # # 根據空間類型獲取對應的運動調整
429
+ # adjustment = exercise_adjustments.get(exercise_needs,
430
+ # exercise_adjustments["Moderate"])[living_space]
431
 
432
+ # # 院子獎勵也要根據犬種大小調整
433
+ # yard_bonus = 0
434
+ # if has_yard:
435
+ # if size in ["Large", "Giant"]:
436
+ # yard_bonus = 0.20 if living_space != "apartment" else 0.10
437
+ # elif size == "Medium":
438
+ # yard_bonus = 0.15 if living_space != "apartment" else 0.08
439
+ # else:
440
+ # yard_bonus = 0.10 if living_space != "apartment" else 0.05
441
+
442
+ # final_score = base_score + adjustment + yard_bonus
443
+ # return min(1.0, max(0.1, final_score))
444
+
445
 
446
  def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
447
+ """
448
+ 優化的空間分數計算函數
449
+
450
+ 主要改進:
451
+ 1. 更均衡的基礎分數分配
452
+ 2. 更細緻的空間需求評估
453
+ 3. 強化運動需求與空間的關聯性
454
+ """
455
+ # 重新設計基礎分數矩陣,降低普遍分數以增加區別度
456
  base_scores = {
457
  "Small": {
458
+ "apartment": 0.85, # 降低滿分機會
459
+ "house_small": 0.80, # 小型犬不應在大空間得到太高分數
460
+ "house_large": 0.75 # 避免小型犬總是得到最高分
461
  },
462
  "Medium": {
463
+ "apartment": 0.45, # 維持對公寓環境的限制
464
+ "house_small": 0.75, # 適中的分數
465
+ "house_large": 0.85 # 給予合理的獎勵
466
  },
467
  "Large": {
468
+ "apartment": 0.15, # 加重對大型犬在公寓的限制
469
+ "house_small": 0.65, # 中等適合度
470
+ "house_large": 0.90 # 最適合的環境
471
  },
472
  "Giant": {
473
+ "apartment": 0.10, # 更嚴格的限制
474
+ "house_small": 0.45, # 顯著的空間限制
475
+ "house_large": 0.95 # 最理想的配對
476
  }
477
  }
478
 
479
  # 取得基礎分數
480
  base_score = base_scores.get(size, base_scores["Medium"])[living_space]
481
 
482
+ # 運動需求相關的調整更加動態
483
  exercise_adjustments = {
484
  "Very High": {
485
+ "apartment": -0.25, # 加重在受限空間的懲罰
486
  "house_small": -0.15,
487
  "house_large": -0.05
488
  },
 
497
  "house_large": 0
498
  },
499
  "Low": {
500
+ "apartment": 0.05, # 低運動需求在小空間反而有優勢
501
  "house_small": 0,
502
+ "house_large": -0.05 # 輕微降低評分,因為空間可能過大
503
  }
504
  }
505
 
506
+ # 根據空間類型獲取運動需求調整
507
  adjustment = exercise_adjustments.get(exercise_needs,
508
  exercise_adjustments["Moderate"])[living_space]
509
 
510
+ # 院子效益根據品種大小和運動需求動態調整
 
511
  if has_yard:
512
+ yard_bonus = {
513
+ "Giant": 0.20,
514
+ "Large": 0.15,
515
+ "Medium": 0.10,
516
+ "Small": 0.05
517
+ }.get(size, 0.10)
518
+
519
+ # 運動需求會影響院子的重要性
520
+ if exercise_needs in ["Very High", "High"]:
521
+ yard_bonus *= 1.2
522
+ elif exercise_needs == "Low":
523
+ yard_bonus *= 0.8
524
 
525
+ current_score = base_score + adjustment + yard_bonus
526
+ else:
527
+ current_score = base_score + adjustment
528
+
529
+ # 確保分數在合理範圍內,但避免極端值
530
+ return min(0.95, max(0.15, current_score))
531
+
532
 
533
+ # def calculate_exercise_score(breed_needs: str, user_time: int) -> float:
534
+ # """運動需求計算"""
535
+ # exercise_needs = {
536
+ # 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
537
+ # 'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
538
+ # 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90},
539
+ # 'LOW': {'min': 20, 'ideal': 30, 'max': 45},
540
+ # 'VARIES': {'min': 30, 'ideal': 60, 'max': 90}
541
+ # }
542
+
543
+ # breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
544
+
545
+ # # 計算匹配度
546
+ # if user_time >= breed_need['ideal']:
547
+ # if user_time > breed_need['max']:
548
+ # return 0.9 # 稍微降分,因為可能過度運動
549
+ # return 1.0
550
+ # elif user_time >= breed_need['min']:
551
+ # return 0.8 + (user_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.2
552
+ # else:
553
+ # return max(0.3, 0.8 * (user_time / breed_need['min']))
554
+
555
+
556
+ def calculate_exercise_score(breed_needs: str, user_prefs: UserPreferences) -> float:
557
+ """
558
+ 優化的運動需求評分系統
559
+
560
+ 改進:
561
+ 1. 考慮運動類型的匹配度
562
+ 2. 評估活動模式的適配性
563
+ 3. 加入品種特性考量
564
+ """
565
+ # 基礎運動需求評估
566
  exercise_needs = {
567
+ 'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180, 'intensity': 'high'},
568
+ 'HIGH': {'min': 90, 'ideal': 120, 'max': 150, 'intensity': 'moderate_high'},
569
+ 'MODERATE': {'min': 45, 'ideal': 60, 'max': 90, 'intensity': 'moderate'},
570
+ 'LOW': {'min': 20, 'ideal': 30, 'max': 45, 'intensity': 'low'},
571
+ 'VARIES': {'min': 30, 'ideal': 60, 'max': 90, 'intensity': 'moderate'}
572
  }
573
 
574
  breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
575
 
576
+ # 基礎時間匹配度計算
577
+ if user_prefs.exercise_time >= breed_need['ideal']:
578
+ time_score = 1.0 if user_prefs.exercise_time <= breed_need['max'] else 0.9
579
+ elif user_prefs.exercise_time >= breed_need['min']:
580
+ time_score = 0.7 + (user_prefs.exercise_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.3
 
 
581
  else:
582
+ time_score = max(0.3, 0.7 * (user_prefs.exercise_time / breed_need['min']))
583
+
584
+ # 運動類型匹配度評估
585
+ exercise_type_scores = {
586
+ 'light_walks': {
587
+ 'low': 1.0,
588
+ 'moderate': 0.8,
589
+ 'moderate_high': 0.5,
590
+ 'high': 0.3
591
+ },
592
+ 'moderate_activity': {
593
+ 'low': 0.7,
594
+ 'moderate': 1.0,
595
+ 'moderate_high': 0.8,
596
+ 'high': 0.6
597
+ },
598
+ 'active_training': {
599
+ 'low': 0.5,
600
+ 'moderate': 0.8,
601
+ 'moderate_high': 1.0,
602
+ 'high': 1.0
603
+ }
604
+ }
605
 
606
+ type_score = exercise_type_scores.get(user_prefs.exercise_type, exercise_type_scores['moderate_activity']).get(breed_need['intensity'], 0.7)
 
607
 
608
+ # 時間可用性調整
609
+ availability_multiplier = {
610
+ 'limited': 0.85, # 時間有限,可能影響運動品質
611
+ 'moderate': 1.0, # 標準參考點
612
+ 'flexible': 1.1 # 更靈活的時間安排有利於滿足狗狗需求
613
+ }.get(user_prefs.time_availability, 1.0)
614
 
615
+ # 環境因素考量
616
+ environment_bonus = 0
617
+ if user_prefs.yard_access != 'no_yard':
618
+ if breed_needs.strip().upper() in ['VERY HIGH', 'HIGH']:
619
+ environment_bonus = 0.1
620
+ else:
621
+ environment_bonus = 0.05
622
+
623
+ # 計算最終分數
624
+ final_score = (time_score * 0.5 + type_score * 0.3) * availability_multiplier + environment_bonus
625
+
626
+ return min(1.0, max(0.3, final_score))
627
 
628
 
629
  def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
 
755
 
756
  # 確保分數在有意義的範圍內,但允許更大的差異
757
  return max(0.1, min(1.0, final_score))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
 
759
 
760
  def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
 
866
 
867
  return final_score
868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
  def calculate_health_score(breed_name: str, user_prefs: UserPreferences) -> float:
870
  """
871
  計算品種健康分數,加強健康問題的影響力和與使用者敏感度的連結
 
974
  return max(0.1, min(1.0, health_score))
975
 
976
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
  def calculate_noise_score(breed_name: str, user_prefs: UserPreferences) -> float:
978
  """
979
  計算品種噪音分數,特別加強噪音程度與生活環境的關聯性評估
 
1097
  final_score = base_score + barking_penalty + special_adjustments + trainability_bonus
1098
  return max(0.1, min(1.0, final_score))
1099
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  print("\n=== 開始計算品種相容性分數 ===")
1101
  print(f"處理品種: {breed_info.get('Breed', 'Unknown')}")
1102
  print(f"品種信息: {breed_info}")
 
1201
 
1202
  return penalty
1203
 
1204
+ # # 計算權重和加權分數
1205
+ # def calculate_weighted_score(scores: dict) -> float:
1206
+ # """
1207
+ # 使用動態權重計算加權分數
1208
+ # """
1209
+ # base_weights = {
1210
+ # 'space': 0.28,
1211
+ # 'exercise': 0.18,
1212
+ # 'grooming': 0.12,
1213
+ # 'experience': 0.22,
1214
+ # 'health': 0.12,
1215
+ # 'noise': 0.08
1216
+ # }
1217
+
1218
+ # # 根據居住環境調整權重
1219
+ # if user_prefs.living_space == 'apartment':
1220
+ # base_weights['space'] *= 1.2
1221
+ # base_weights['noise'] *= 1.2
1222
+
1223
+ # # 根據經驗等級調整權重
1224
+ # if user_prefs.experience_level == 'beginner':
1225
+ # base_weights['experience'] *= 1.3
1226
+
1227
+ # # 重新正規化權重
1228
+ # total_weight = sum(base_weights.values())
1229
+ # weights = {k: v/total_weight for k, v in base_weights.items()}
1230
+
1231
+ # # 計算加權分數
1232
+ # return sum(score * weights[category] for category, score in scores.items())
1233
+
1234
+ def calculate_weighted_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1235
  """
1236
+ 優化的加權分數計算函數
1237
+
1238
+ 主要改進:
1239
+ 1. 動態權重調整
1240
+ 2. 品種特性加成
1241
+ 3. 更平衡的分數分配
1242
  """
1243
+ # 基礎權重設定
1244
  base_weights = {
1245
+ 'space': 0.25, # 稍微降低空間權重
1246
+ 'exercise': 0.20, # 提高運動權重
1247
+ 'grooming': 0.15, # 略微提高美容權重
1248
+ 'experience': 0.18, # 降低經驗權重,避免過度主導
1249
  'health': 0.12,
1250
+ 'noise': 0.10 # 提高噪音權重
1251
  }
1252
 
1253
+ # 根據使用者經驗調整權重
1254
+ if user_prefs.experience_level == 'beginner':
1255
+ # 新手更注重易照顧程度
1256
+ base_weights['experience'] *= 1.2
1257
+ base_weights['health'] *= 1.1
1258
+ base_weights['grooming'] *= 0.9
1259
+ elif user_prefs.experience_level == 'advanced':
1260
+ # 專家更注重運動和訓練潛力
1261
+ base_weights['exercise'] *= 1.2
1262
+ base_weights['experience'] *= 0.8
1263
+
1264
  # 根據居住環境調整權重
1265
  if user_prefs.living_space == 'apartment':
1266
+ base_weights['noise'] *= 1.3
1267
  base_weights['space'] *= 1.2
1268
+ elif user_prefs.living_space == 'house_large':
1269
+ base_weights['exercise'] *= 1.2
1270
+ base_weights['space'] *= 0.9
1271
+
1272
+ # 有孩童時的權重調整
1273
+ if user_prefs.has_children:
1274
  base_weights['noise'] *= 1.2
1275
+ base_weights['health'] *= 1.1
1276
+
 
 
 
1277
  # 重新正規化權重
1278
  total_weight = sum(base_weights.values())
1279
  weights = {k: v/total_weight for k, v in base_weights.items()}
1280
 
1281
+ # 計算基礎加權分數
1282
+ weighted_base = sum(score * weights[category] for category, score in scores.items())
1283
+
1284
+ # 計算品種特性加成
1285
+ breed_bonus = calculate_breed_characteristic_bonus(breed_info, user_prefs)
1286
+
1287
+ # 混合基礎分數和特性加成
1288
+ final_score = (weighted_base * 0.85) + (breed_bonus * 0.15)
1289
+
1290
+ return final_score
1291
+
1292
+ def calculate_breed_characteristic_bonus(breed_info: dict, user_prefs: UserPreferences) -> float:
1293
+ """
1294
+ 計算品種特性加成,增加品種多樣性
1295
+ """
1296
+ bonus = 0.0
1297
+ temperament = breed_info.get('Temperament', '').lower()
1298
+ description = breed_info.get('Description', '').lower()
1299
+
1300
+ # 品種類型加成
1301
+ breed_types = {
1302
+ 'working': {'keywords': ['working', 'guard', 'protection'], 'bonus': 0.05},
1303
+ 'companion': {'keywords': ['companion', 'friendly', 'affectionate'], 'bonus': 0.05},
1304
+ 'sporting': {'keywords': ['hunting', 'sporting', 'athletic'], 'bonus': 0.05},
1305
+ 'herding': {'keywords': ['herding', 'shepherd', 'cattle'], 'bonus': 0.05}
1306
+ }
1307
+
1308
+ # 根據使用場景給予特定加成
1309
+ for breed_type, info in breed_types.items():
1310
+ if any(keyword in description or keyword in temperament for keyword in info['keywords']):
1311
+ if user_prefs.has_children and breed_type == 'companion':
1312
+ bonus += info['bonus'] * 1.5
1313
+ elif user_prefs.exercise_type == 'active_training' and breed_type in ['working', 'sporting']:
1314
+ bonus += info['bonus'] * 1.3
1315
+ else:
1316
+ bonus += info['bonus']
1317
+
1318
+ # 特殊加成(增加多樣性)
1319
+ if 'rare' in description or 'unique' in description:
1320
+ bonus += 0.03
1321
+ if 'independent' in temperament and user_prefs.experience_level == 'advanced':
1322
+ bonus += 0.04
1323
+
1324
+ return min(0.15, bonus) # 限制最大加成
1325
+
1326
 
1327
  # 計算最終分數
1328
  def calculate_final_score(base_score: float, penalty: float) -> float: