DawnC commited on
Commit
533532a
·
1 Parent(s): 468e50e

Update breed_recommendation.py

Browse files
Files changed (1) hide show
  1. breed_recommendation.py +310 -98
breed_recommendation.py CHANGED
@@ -157,21 +157,6 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
157
  'scores': rec['scores']
158
  } for rec in recommendations]
159
 
160
- # # 保存到歷史記錄,也需要更新保存的偏好設定
161
- # history_component.save_search(
162
- # user_preferences={
163
- # 'living_space': args[0],
164
- # 'exercise_time': args[1],
165
- # 'grooming_commitment': args[2],
166
- # 'experience_level': args[3],
167
- # 'has_children': args[4],
168
- # 'noise_tolerance': args[5],
169
- # 'health_sensitivity': "medium",
170
- # 'barking_acceptance': args[5]
171
- # },
172
- # results=history_results
173
- # )
174
-
175
  history_component.save_search(
176
  user_preferences={
177
  'living_space': args[0],
@@ -198,6 +183,226 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
198
  return "Error getting recommendations"
199
 
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  def on_description_search(description: str):
202
  try:
203
  # 初始化匹配器
@@ -241,19 +446,28 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
241
 
242
  final_recommendations = []
243
 
244
- for smart_rec in breed_recommendations:
245
- breed_name = smart_rec['breed']
246
- breed_info = get_dog_description(breed_name)
247
- if not isinstance(breed_info, dict):
248
- continue
249
-
250
- # 獲取基礎分數
251
- base_score = smart_rec.get('base_score', 0.7)
252
- similarity = smart_rec.get('similarity', 0)
253
- is_preferred = smart_rec.get('is_preferred', False)
254
-
255
- bonus_reasons = []
256
- bonus_score = 0
 
 
 
 
 
 
 
 
 
257
 
258
  # 1. 尺寸評估
259
  size = breed_info.get('Size', '')
@@ -344,78 +558,76 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
344
  # 計算最終分數
345
  final_score = min(0.95, base_score + bonus_score)
346
 
347
- space_score = _calculate_space_compatibility(
348
- breed_info.get('Size', 'Medium'),
349
- user_prefs.living_space
350
- )
351
-
352
- exercise_score = _calculate_exercise_compatibility(
353
- breed_info.get('Exercise_Needs', 'Moderate'),
354
- user_prefs.exercise_time
355
- )
356
-
357
- grooming_score = _calculate_grooming_compatibility(
358
- breed_info.get('Grooming_Needs', 'Moderate'),
359
- user_prefs.grooming_commitment
360
- )
361
-
362
- experience_score = _calculate_experience_compatibility(
363
- breed_info.get('Care_Level', 'Moderate'),
364
- user_prefs.experience_level
365
- )
366
-
367
  scores = {
368
- 'overall': final_score,
369
- 'space': space_score,
370
- 'exercise': exercise_score,
371
- 'grooming': grooming_score,
372
- 'experience': experience_score,
373
- 'noise': smart_rec.get('scores', {}).get('noise', 0.0),
374
- 'health': smart_rec.get('health_score', 0.5),
375
- 'temperament': smart_rec.get('scores', {}).get('temperament', 0.0)
376
- }
377
-
378
-
379
- final_recommendations.append({
380
- 'rank': 0,
381
- 'breed': breed_name,
382
- 'scores': scores,
383
- 'base_score': round(base_score, 4),
384
- 'bonus_score': round(bonus_score, 4),
385
- 'final_score': round(final_score, 4),
386
- 'match_reason': ' • '.join(bonus_reasons) if bonus_reasons else "Standard match",
387
- 'info': breed_info,
388
- 'noise_info': breed_noise_info.get(breed_name, {}),
389
- 'health_info': breed_health_info.get(breed_name, {})
390
- })
391
-
392
- # 根據最終分數排序
393
- final_recommendations.sort(key=lambda x: (-x['final_score'], x['breed']))
394
-
395
- # 更新排名
396
- for i, rec in enumerate(final_recommendations, 1):
397
- rec['rank'] = i
398
-
399
- # 保存到歷史記錄
400
- history_results = [{
401
- 'breed': rec['breed'],
402
- 'rank': rec['rank'],
403
- 'final_score': rec['final_score']
404
- } for rec in final_recommendations[:10]]
405
-
406
- history_component.save_search(
407
- user_preferences=None,
408
- results=history_results,
409
- search_type="description",
410
- description=description
411
- )
412
-
413
- result = format_recommendation_html(final_recommendations, is_description_search=True)
414
- return [gr.update(value=result), gr.update(visible=False)]
415
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  except Exception as e:
417
- error_msg = f"Error processing your description. Details: {str(e)}"
418
- return [gr.update(value=error_msg), gr.update(visible=False)]
 
 
419
 
420
 
421
  def _calculate_space_compatibility(size: str, living_space: str) -> float:
 
157
  'scores': rec['scores']
158
  } for rec in recommendations]
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  history_component.save_search(
161
  user_preferences={
162
  'living_space': args[0],
 
183
  return "Error getting recommendations"
184
 
185
 
186
+ # def on_description_search(description: str):
187
+ # try:
188
+ # # 初始化匹配器
189
+ # matcher = SmartBreedMatcher(dog_data)
190
+ # breed_recommendations = matcher.match_user_preference(description, top_n=10)
191
+
192
+ # # 從描述中提取用戶偏好
193
+ # user_prefs = UserPreferences(
194
+ # living_space="apartment" if any(word in description.lower()
195
+ # for word in ["apartment", "flat", "condo"]) else "house_small",
196
+ # yard_access="no_yard" if any(word in description.lower()
197
+ # for word in ["apartment", "flat", "condo"]) else "private_yard",
198
+ # exercise_time=120 if any(word in description.lower()
199
+ # for word in ["active", "exercise", "running", "athletic", "high energy"]) else 60,
200
+ # exercise_type="active_training" if any(word in description.lower()
201
+ # for word in ["training", "running", "jogging", "hiking"]) else "moderate_activity",
202
+ # grooming_commitment="high" if any(word in description.lower()
203
+ # for word in ["grooming", "brush", "maintain"]) else "medium",
204
+ # experience_level="experienced" if any(word in description.lower()
205
+ # for word in ["experienced", "trained", "professional"]) else "intermediate",
206
+ # time_availability="flexible" if any(word in description.lower()
207
+ # for word in ["time", "available", "flexible", "home"]) else "moderate",
208
+ # has_children=any(word in description.lower()
209
+ # for word in ["children", "kids", "family", "child"]),
210
+ # children_age="school_age" if any(word in description.lower()
211
+ # for word in ["school", "elementary"]) else "teenager" if any(word in description.lower()
212
+ # for word in ["teen", "teenager"]) else "toddler" if any(word in description.lower()
213
+ # for word in ["baby", "toddler"]) else None,
214
+ # noise_tolerance="low" if any(word in description.lower()
215
+ # for word in ["quiet", "peaceful", "silent"]) else "medium",
216
+ # space_for_play=any(word in description.lower()
217
+ # for word in ["yard", "garden", "outdoor", "space"]),
218
+ # other_pets=any(word in description.lower()
219
+ # for word in ["other pets", "cats", "dogs"]),
220
+ # climate="moderate",
221
+ # health_sensitivity="high" if any(word in description.lower()
222
+ # for word in ["health", "medical", "sensitive"]) else "medium",
223
+ # barking_acceptance="low" if any(word in description.lower()
224
+ # for word in ["quiet", "no barking"]) else "medium"
225
+ # )
226
+
227
+ # final_recommendations = []
228
+
229
+ # for smart_rec in breed_recommendations:
230
+ # breed_name = smart_rec['breed']
231
+ # breed_info = get_dog_description(breed_name)
232
+ # if not isinstance(breed_info, dict):
233
+ # continue
234
+
235
+ # # 獲取基礎分數
236
+ # base_score = smart_rec.get('base_score', 0.7)
237
+ # similarity = smart_rec.get('similarity', 0)
238
+ # is_preferred = smart_rec.get('is_preferred', False)
239
+
240
+ # bonus_reasons = []
241
+ # bonus_score = 0
242
+
243
+ # # 1. 尺寸評估
244
+ # size = breed_info.get('Size', '')
245
+ # if size in ['Small', 'Tiny']:
246
+ # if "apartment" in description.lower():
247
+ # bonus_score += 0.05
248
+ # bonus_reasons.append("Suitable size for apartment (+5%)")
249
+ # else:
250
+ # bonus_score -= 0.25
251
+ # bonus_reasons.append("Size too small (-25%)")
252
+ # elif size == 'Medium':
253
+ # bonus_score += 0.15
254
+ # bonus_reasons.append("Ideal size (+15%)")
255
+ # elif size == 'Large':
256
+ # if "apartment" in description.lower():
257
+ # bonus_score -= 0.05
258
+ # bonus_reasons.append("May be too large for apartment (-5%)")
259
+ # elif size == 'Giant':
260
+ # bonus_score -= 0.20
261
+ # bonus_reasons.append("Size too large (-20%)")
262
+
263
+ # # 2. 運動需求評估
264
+ # exercise_needs = breed_info.get('Exercise_Needs', '')
265
+ # if any(word in description.lower() for word in ['active', 'energetic', 'running']):
266
+ # if exercise_needs in ['High', 'Very High']:
267
+ # bonus_score += 0.20
268
+ # bonus_reasons.append("Exercise needs match (+20%)")
269
+ # elif exercise_needs == 'Low':
270
+ # bonus_score -= 0.15
271
+ # bonus_reasons.append("Insufficient exercise level (-15%)")
272
+ # else:
273
+ # if exercise_needs == 'Moderate':
274
+ # bonus_score += 0.10
275
+ # bonus_reasons.append("Moderate exercise needs (+10%)")
276
+
277
+ # # 3. 美容需求評估
278
+ # grooming = breed_info.get('Grooming_Needs', '')
279
+ # if user_prefs.grooming_commitment == "high":
280
+ # if grooming == 'High':
281
+ # bonus_score += 0.10
282
+ # bonus_reasons.append("High grooming match (+10%)")
283
+ # else:
284
+ # if grooming == 'High':
285
+ # bonus_score -= 0.15
286
+ # bonus_reasons.append("High grooming needs (-15%)")
287
+ # elif grooming == 'Low':
288
+ # bonus_score += 0.10
289
+ # bonus_reasons.append("Low grooming needs (+10%)")
290
+
291
+ # # 4. 家庭適應性評估
292
+ # if user_prefs.has_children:
293
+ # if breed_info.get('Good_With_Children'):
294
+ # bonus_score += 0.15
295
+ # bonus_reasons.append("Excellent with children (+15%)")
296
+ # temperament = breed_info.get('Temperament', '').lower()
297
+ # if any(trait in temperament for trait in ['gentle', 'patient', 'friendly']):
298
+ # bonus_score += 0.05
299
+ # bonus_reasons.append("Family-friendly temperament (+5%)")
300
+
301
+ # # 5. 噪音評估
302
+ # if user_prefs.noise_tolerance == "low":
303
+ # noise_level = breed_noise_info.get(breed_name, {}).get('noise_level', 'Unknown')
304
+ # if noise_level == 'High':
305
+ # bonus_score -= 0.10
306
+ # bonus_reasons.append("High noise level (-10%)")
307
+ # elif noise_level == 'Low':
308
+ # bonus_score += 0.10
309
+ # bonus_reasons.append("Low noise level (+10%)")
310
+
311
+ # # 6. 健康考慮
312
+ # if user_prefs.health_sensitivity == "high":
313
+ # health_score = smart_rec.get('health_score', 0.5)
314
+ # if health_score > 0.8:
315
+ # bonus_score += 0.10
316
+ # bonus_reasons.append("Excellent health score (+10%)")
317
+ # elif health_score < 0.5:
318
+ # bonus_score -= 0.10
319
+ # bonus_reasons.append("Health concerns (-10%)")
320
+
321
+ # # 7. 品種偏好獎勵
322
+ # if is_preferred:
323
+ # bonus_score += 0.15
324
+ # bonus_reasons.append("Directly mentioned breed (+15%)")
325
+ # elif similarity > 0.8:
326
+ # bonus_score += 0.10
327
+ # bonus_reasons.append("Very similar to preferred breed (+10%)")
328
+
329
+ # # 計算最終分數
330
+ # final_score = min(0.95, base_score + bonus_score)
331
+
332
+ # space_score = _calculate_space_compatibility(
333
+ # breed_info.get('Size', 'Medium'),
334
+ # user_prefs.living_space
335
+ # )
336
+
337
+ # exercise_score = _calculate_exercise_compatibility(
338
+ # breed_info.get('Exercise_Needs', 'Moderate'),
339
+ # user_prefs.exercise_time
340
+ # )
341
+
342
+ # grooming_score = _calculate_grooming_compatibility(
343
+ # breed_info.get('Grooming_Needs', 'Moderate'),
344
+ # user_prefs.grooming_commitment
345
+ # )
346
+
347
+ # experience_score = _calculate_experience_compatibility(
348
+ # breed_info.get('Care_Level', 'Moderate'),
349
+ # user_prefs.experience_level
350
+ # )
351
+
352
+ # scores = {
353
+ # 'overall': final_score,
354
+ # 'space': space_score,
355
+ # 'exercise': exercise_score,
356
+ # 'grooming': grooming_score,
357
+ # 'experience': experience_score,
358
+ # 'noise': smart_rec.get('scores', {}).get('noise', 0.0),
359
+ # 'health': smart_rec.get('health_score', 0.5),
360
+ # 'temperament': smart_rec.get('scores', {}).get('temperament', 0.0)
361
+ # }
362
+
363
+
364
+ # final_recommendations.append({
365
+ # 'rank': 0,
366
+ # 'breed': breed_name,
367
+ # 'scores': scores,
368
+ # 'base_score': round(base_score, 4),
369
+ # 'bonus_score': round(bonus_score, 4),
370
+ # 'final_score': round(final_score, 4),
371
+ # 'match_reason': ' • '.join(bonus_reasons) if bonus_reasons else "Standard match",
372
+ # 'info': breed_info,
373
+ # 'noise_info': breed_noise_info.get(breed_name, {}),
374
+ # 'health_info': breed_health_info.get(breed_name, {})
375
+ # })
376
+
377
+ # # 根據最終分數排序
378
+ # final_recommendations.sort(key=lambda x: (-x['final_score'], x['breed']))
379
+
380
+ # # 更新排名
381
+ # for i, rec in enumerate(final_recommendations, 1):
382
+ # rec['rank'] = i
383
+
384
+ # # 保存到歷史記錄
385
+ # history_results = [{
386
+ # 'breed': rec['breed'],
387
+ # 'rank': rec['rank'],
388
+ # 'final_score': rec['final_score']
389
+ # } for rec in final_recommendations[:10]]
390
+
391
+ # history_component.save_search(
392
+ # user_preferences=None,
393
+ # results=history_results,
394
+ # search_type="description",
395
+ # description=description
396
+ # )
397
+
398
+ # result = format_recommendation_html(final_recommendations, is_description_search=True)
399
+ # return [gr.update(value=result), gr.update(visible=False)]
400
+
401
+ # except Exception as e:
402
+ # error_msg = f"Error processing your description. Details: {str(e)}"
403
+ # return [gr.update(value=error_msg), gr.update(visible=False)]
404
+
405
+
406
  def on_description_search(description: str):
407
  try:
408
  # 初始化匹配器
 
446
 
447
  final_recommendations = []
448
 
449
+ if not breed_recommendations:
450
+ print("No direct matches found, applying fallback logic")
451
+ # 使用 criteria 搜索的邏輯作為後備
452
+ recommendations = get_breed_recommendations(user_prefs, top_n=10)
453
+ if recommendations:
454
+ final_recommendations.extend(recommendations)
455
+ else:
456
+ # 保持原有的詳細評分系統
457
+ for smart_rec in breed_recommendations:
458
+ breed_name = smart_rec['breed']
459
+ breed_info = get_dog_description(breed_name)
460
+
461
+ if not isinstance(breed_info, dict):
462
+ continue
463
+
464
+ # 獲取基礎分數
465
+ base_score = smart_rec.get('base_score', 0.7)
466
+ similarity = smart_rec.get('similarity', 0)
467
+ is_preferred = smart_rec.get('is_preferred', False)
468
+
469
+ bonus_reasons = []
470
+ bonus_score = 0
471
 
472
  # 1. 尺寸評估
473
  size = breed_info.get('Size', '')
 
558
  # 計算最終分數
559
  final_score = min(0.95, base_score + bonus_score)
560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  scores = {
562
+ 'overall': final_score,
563
+ 'space': _calculate_space_compatibility(
564
+ breed_info.get('Size', 'Medium'),
565
+ user_prefs.living_space
566
+ ),
567
+ 'exercise': _calculate_exercise_compatibility(
568
+ breed_info.get('Exercise_Needs', 'Moderate'),
569
+ user_prefs.exercise_time
570
+ ),
571
+ 'grooming': _calculate_grooming_compatibility(
572
+ breed_info.get('Grooming_Needs', 'Moderate'),
573
+ user_prefs.grooming_commitment
574
+ ),
575
+ 'experience': _calculate_experience_compatibility(
576
+ breed_info.get('Care_Level', 'Moderate'),
577
+ user_prefs.experience_level
578
+ ),
579
+ 'noise': smart_rec.get('scores', {}).get('noise', 0.0),
580
+ 'health': smart_rec.get('health_score', 0.5),
581
+ 'temperament': smart_rec.get('scores', {}).get('temperament', 0.0)
582
+ }
583
+
584
+ final_recommendations.append({
585
+ 'rank': 0,
586
+ 'breed': breed_name,
587
+ 'scores': scores,
588
+ 'base_score': round(base_score, 4),
589
+ 'bonus_score': round(bonus_score, 4),
590
+ 'final_score': round(final_score, 4),
591
+ 'match_reason': ' • '.join(bonus_reasons) if bonus_reasons else "Standard match",
592
+ 'info': breed_info,
593
+ 'noise_info': breed_noise_info.get(breed_name, {}),
594
+ 'health_info': breed_health_info.get(breed_name, {})
595
+ })
596
+
597
+ # 排序並更新排名
598
+ if final_recommendations:
599
+ final_recommendations.sort(key=lambda x: (-x['final_score'], x['breed']))
600
+ for i, rec in enumerate(final_recommendations, 1):
601
+ rec['rank'] = i
602
+
603
+ # 保存搜索歷史
604
+ history_results = [{
605
+ 'breed': rec['breed'],
606
+ 'rank': rec['rank'],
607
+ 'overall_score': rec['final_score'],
608
+ 'base_score': rec['base_score'],
609
+ 'bonus_score': rec['bonus_score'],
610
+ 'scores': rec['scores']
611
+ } for rec in final_recommendations[:10]]
612
+
613
+ # 保存到歷史記錄
614
+ history_component.save_search(
615
+ user_preferences={'description': description},
616
+ results=history_results,
617
+ search_type="description"
618
+ )
619
+
620
+ # 返回結果
621
+ result = format_recommendation_html(final_recommendations, is_description_search=True)
622
+ return result
623
+
624
+ return "No matching breeds found. Please try a different description."
625
+
626
  except Exception as e:
627
+ print(f"Error in description search: {str(e)}")
628
+ import traceback
629
+ print(traceback.format_exc())
630
+ return "Error processing your description"
631
 
632
 
633
  def _calculate_space_compatibility(size: str, living_space: str) -> float: