DawnC commited on
Commit
de532fe
1 Parent(s): 4f9ae1f

Update breed_recommendation.py

Browse files
Files changed (1) hide show
  1. breed_recommendation.py +458 -77
breed_recommendation.py CHANGED
@@ -7,11 +7,256 @@ from scoring_calculation_system import UserPreferences, calculate_compatibility_
7
  from recommendation_html_format import format_recommendation_html, get_breed_recommendations
8
  from search_history import create_history_tab, create_history_component
9
 
10
- def create_recommendation_tab(UserPreferences, get_breed_recommendations, format_recommendation_html, history_component):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  with gr.TabItem("Breed Recommendation"):
13
  with gr.Tabs():
14
  with gr.Tab("Find by Criteria"):
 
15
  gr.HTML("""
16
  <div style='
17
  text-align: center;
@@ -72,6 +317,122 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
72
  </div>
73
  """)
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  with gr.Row():
76
  with gr.Column():
77
  living_space = gr.Radio(
@@ -103,7 +464,6 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
103
  value="moderate_activity"
104
  )
105
 
106
-
107
  grooming_commitment = gr.Radio(
108
  choices=["low", "medium", "high"],
109
  label="Grooming commitment level",
@@ -135,7 +495,7 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
135
  choices=["toddler", "school_age", "teenager"],
136
  label="Children's Age Group",
137
  info="Helps match with age-appropriate breeds",
138
- visible=False # 默認隱藏,只在has_children=True時顯示
139
  )
140
 
141
  noise_tolerance = gr.Radio(
@@ -144,7 +504,8 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
144
  info="Some breeds are more vocal than others",
145
  value="medium"
146
  )
147
-
 
148
  def update_children_age_visibility(has_children):
149
  return gr.update(visible=has_children)
150
 
@@ -154,88 +515,108 @@ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format
154
  outputs=children_age
155
  )
156
 
157
- get_recommendations_btn = gr.Button("Find My Perfect Match! 🔍", variant="primary")
158
-
 
 
 
 
 
159
  recommendation_output = gr.HTML(
160
  label="Breed Recommendations",
161
- visible=True, # 確保可見性
162
- elem_id="recommendation-output"
163
  )
164
 
165
- def on_find_match_click(*args):
166
- try:
167
- user_prefs = UserPreferences(
168
- living_space=args[0],
169
- yard_access=args[1],
170
- exercise_time=args[2],
171
- exercise_type=args[3],
172
- grooming_commitment=args[4],
173
- experience_level=args[5],
174
- time_availability=args[6],
175
- has_children=args[7],
176
- children_age=args[8] if args[7] else None,
177
- noise_tolerance=args[9],
178
- space_for_play=True if args[0] != "apartment" else False,
179
- other_pets=False,
180
- climate="moderate",
181
- health_sensitivity="medium",
182
- barking_acceptance=args[9]
183
- )
184
 
185
- recommendations = get_breed_recommendations(user_prefs, top_n=10)
186
-
187
- history_results = [{
188
- 'breed': rec['breed'],
189
- 'rank': rec['rank'],
190
- 'overall_score': rec['final_score'],
191
- 'base_score': rec['base_score'],
192
- 'bonus_score': rec['bonus_score'],
193
- 'scores': rec['scores']
194
- } for rec in recommendations]
195
-
196
- history_component.save_search(
197
- user_preferences={
198
- 'living_space': args[0],
199
- 'yard_access': args[1],
200
- 'exercise_time': args[2],
201
- 'exercise_type': args[3],
202
- 'grooming_commitment': args[4],
203
- 'experience_level': args[5],
204
- 'time_availability': args[6],
205
- 'has_children': args[7],
206
- 'children_age': args[8] if args[7] else None,
207
- 'noise_tolerance': args[9],
208
- 'search_type': 'Criteria'
209
- },
210
- results=history_results
211
- )
212
 
213
- return format_recommendation_html(recommendations, is_description_search=False)
 
214
 
215
- except Exception as e:
216
- print(f"Error in find match: {str(e)}")
217
- import traceback
218
- print(traceback.format_exc())
219
- return "Error getting recommendations"
220
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- get_recommendations_btn.click(
223
- fn=on_find_match_click,
224
- inputs=[
225
- living_space,
226
- yard_access,
227
- exercise_time,
228
- exercise_type,
229
- grooming_commitment,
230
- experience_level,
231
- time_availability,
232
- has_children,
233
- children_age,
234
- noise_tolerance
235
- ],
236
- outputs=recommendation_output
237
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
 
 
239
  return {
240
  'living_space': living_space,
241
  'exercise_time': exercise_time,
 
7
  from recommendation_html_format import format_recommendation_html, get_breed_recommendations
8
  from search_history import create_history_tab, create_history_component
9
 
10
+ # def create_recommendation_tab(UserPreferences, get_breed_recommendations, format_recommendation_html, history_component):
11
+
12
+ # with gr.TabItem("Breed Recommendation"):
13
+ # with gr.Tabs():
14
+ # with gr.Tab("Find by Criteria"):
15
+ # gr.HTML("""
16
+ # <div style='
17
+ # text-align: center;
18
+ # position: relative;
19
+ # padding: 20px 0;
20
+ # margin: 15px 0;
21
+ # background: linear-gradient(to right, rgba(66, 153, 225, 0.1), rgba(72, 187, 120, 0.1));
22
+ # border-radius: 10px;
23
+ # '>
24
+ # <!-- BETA 標籤 -->
25
+ # <div style='
26
+ # position: absolute;
27
+ # top: 10px;
28
+ # right: 20px;
29
+ # background: linear-gradient(90deg, #4299e1, #48bb78);
30
+ # color: white;
31
+ # padding: 4px 12px;
32
+ # border-radius: 15px;
33
+ # font-size: 0.85em;
34
+ # font-weight: 600;
35
+ # letter-spacing: 1px;
36
+ # box-shadow: 0 2px 4px rgba(0,0,0,0.1);
37
+ # '>BETA</div>
38
+
39
+ # <!-- 主標題 -->
40
+ # <p style='
41
+ # font-size: 1.2em;
42
+ # margin: 0;
43
+ # padding: 0 20px;
44
+ # line-height: 1.5;
45
+ # background: linear-gradient(90deg, #4299e1, #48bb78);
46
+ # -webkit-background-clip: text;
47
+ # -webkit-text-fill-color: transparent;
48
+ # font-weight: 600;
49
+ # '>
50
+ # Tell us about your lifestyle, and we'll recommend the perfect dog breeds for you!
51
+ # </p>
52
+
53
+ # <!-- 提示訊息 -->
54
+ # <div style='
55
+ # margin-top: 15px;
56
+ # padding: 10px 20px;
57
+ # background: linear-gradient(to right, rgba(66, 153, 225, 0.15), rgba(72, 187, 120, 0.15));
58
+ # border-radius: 8px;
59
+ # font-size: 0.9em;
60
+ # color: #2D3748;
61
+ # display: flex;
62
+ # align-items: center;
63
+ # justify-content: center;
64
+ # gap: 8px;
65
+ # '>
66
+ # <span style="font-size: 1.2em;">🔬</span>
67
+ # <span style="
68
+ # letter-spacing: 0.3px;
69
+ # line-height: 1.4;
70
+ # "><strong>Beta Feature:</strong> Our matching algorithm is continuously improving. Results are for reference only.</span>
71
+ # </div>
72
+ # </div>
73
+ # """)
74
+
75
+ # with gr.Row():
76
+ # with gr.Column():
77
+ # living_space = gr.Radio(
78
+ # choices=["apartment", "house_small", "house_large"],
79
+ # label="What type of living space do you have?",
80
+ # info="Choose your current living situation",
81
+ # value="apartment"
82
+ # )
83
+
84
+ # yard_access = gr.Radio(
85
+ # choices=["no_yard", "shared_yard", "private_yard"],
86
+ # label="Yard Access Type",
87
+ # info="Available outdoor space",
88
+ # value="no_yard"
89
+ # )
90
+
91
+ # exercise_time = gr.Slider(
92
+ # minimum=0,
93
+ # maximum=180,
94
+ # value=60,
95
+ # label="Daily exercise time (minutes)",
96
+ # info="Consider walks, play time, and training"
97
+ # )
98
+
99
+ # exercise_type = gr.Radio(
100
+ # choices=["light_walks", "moderate_activity", "active_training"],
101
+ # label="Exercise Style",
102
+ # info="What kind of activities do you prefer?",
103
+ # value="moderate_activity"
104
+ # )
105
+
106
+
107
+ # grooming_commitment = gr.Radio(
108
+ # choices=["low", "medium", "high"],
109
+ # label="Grooming commitment level",
110
+ # info="Low: monthly, Medium: weekly, High: daily",
111
+ # value="medium"
112
+ # )
113
+
114
+ # with gr.Column():
115
+ # experience_level = gr.Radio(
116
+ # choices=["beginner", "intermediate", "advanced"],
117
+ # label="Dog ownership experience",
118
+ # info="Be honest - this helps find the right match",
119
+ # value="beginner"
120
+ # )
121
+
122
+ # time_availability = gr.Radio(
123
+ # choices=["limited", "moderate", "flexible"],
124
+ # label="Time Availability",
125
+ # info="Time available for dog care daily",
126
+ # value="moderate"
127
+ # )
128
+
129
+ # has_children = gr.Checkbox(
130
+ # label="Have children at home",
131
+ # info="Helps recommend child-friendly breeds"
132
+ # )
133
+
134
+ # children_age = gr.Radio(
135
+ # choices=["toddler", "school_age", "teenager"],
136
+ # label="Children's Age Group",
137
+ # info="Helps match with age-appropriate breeds",
138
+ # visible=False # 默認隱藏,只在has_children=True時顯示
139
+ # )
140
+
141
+ # noise_tolerance = gr.Radio(
142
+ # choices=["low", "medium", "high"],
143
+ # label="Noise tolerance level",
144
+ # info="Some breeds are more vocal than others",
145
+ # value="medium"
146
+ # )
147
+
148
+ # def update_children_age_visibility(has_children):
149
+ # return gr.update(visible=has_children)
150
+
151
+ # has_children.change(
152
+ # fn=update_children_age_visibility,
153
+ # inputs=has_children,
154
+ # outputs=children_age
155
+ # )
156
+
157
+ # get_recommendations_btn = gr.Button("Find My Perfect Match! 🔍", variant="primary")
158
+
159
+ # recommendation_output = gr.HTML(
160
+ # label="Breed Recommendations",
161
+ # visible=True, # 確保可見性
162
+ # elem_id="recommendation-output"
163
+ # )
164
+
165
+ # def on_find_match_click(*args):
166
+ # try:
167
+ # user_prefs = UserPreferences(
168
+ # living_space=args[0],
169
+ # yard_access=args[1],
170
+ # exercise_time=args[2],
171
+ # exercise_type=args[3],
172
+ # grooming_commitment=args[4],
173
+ # experience_level=args[5],
174
+ # time_availability=args[6],
175
+ # has_children=args[7],
176
+ # children_age=args[8] if args[7] else None,
177
+ # noise_tolerance=args[9],
178
+ # space_for_play=True if args[0] != "apartment" else False,
179
+ # other_pets=False,
180
+ # climate="moderate",
181
+ # health_sensitivity="medium",
182
+ # barking_acceptance=args[9]
183
+ # )
184
+
185
+ # recommendations = get_breed_recommendations(user_prefs, top_n=10)
186
+
187
+ # history_results = [{
188
+ # 'breed': rec['breed'],
189
+ # 'rank': rec['rank'],
190
+ # 'overall_score': rec['final_score'],
191
+ # 'base_score': rec['base_score'],
192
+ # 'bonus_score': rec['bonus_score'],
193
+ # 'scores': rec['scores']
194
+ # } for rec in recommendations]
195
+
196
+ # history_component.save_search(
197
+ # user_preferences={
198
+ # 'living_space': args[0],
199
+ # 'yard_access': args[1],
200
+ # 'exercise_time': args[2],
201
+ # 'exercise_type': args[3],
202
+ # 'grooming_commitment': args[4],
203
+ # 'experience_level': args[5],
204
+ # 'time_availability': args[6],
205
+ # 'has_children': args[7],
206
+ # 'children_age': args[8] if args[7] else None,
207
+ # 'noise_tolerance': args[9],
208
+ # 'search_type': 'Criteria'
209
+ # },
210
+ # results=history_results
211
+ # )
212
+
213
+ # return format_recommendation_html(recommendations, is_description_search=False)
214
+
215
+ # except Exception as e:
216
+ # print(f"Error in find match: {str(e)}")
217
+ # import traceback
218
+ # print(traceback.format_exc())
219
+ # return "Error getting recommendations"
220
+
221
+
222
+ # get_recommendations_btn.click(
223
+ # fn=on_find_match_click,
224
+ # inputs=[
225
+ # living_space,
226
+ # yard_access,
227
+ # exercise_time,
228
+ # exercise_type,
229
+ # grooming_commitment,
230
+ # experience_level,
231
+ # time_availability,
232
+ # has_children,
233
+ # children_age,
234
+ # noise_tolerance
235
+ # ],
236
+ # outputs=recommendation_output
237
+ # )
238
 
239
+ # return {
240
+ # 'living_space': living_space,
241
+ # 'exercise_time': exercise_time,
242
+ # 'grooming_commitment': grooming_commitment,
243
+ # 'experience_level': experience_level,
244
+ # 'has_children': has_children,
245
+ # 'noise_tolerance': noise_tolerance,
246
+ # 'get_recommendations_btn': get_recommendations_btn,
247
+ # 'recommendation_output': recommendation_output,
248
+ # }
249
+
250
+
251
+ def create_recommendation_tab(UserPreferences, get_breed_recommendations, format_recommendation_html, history_component):
252
+ """
253
+ 創建狗品種推薦頁面的主要函數
254
+ 包含用戶輸入界面、推薦結果顯示和 loading 狀態
255
+ """
256
  with gr.TabItem("Breed Recommendation"):
257
  with gr.Tabs():
258
  with gr.Tab("Find by Criteria"):
259
+ # 頁面頂部的介紹性內容
260
  gr.HTML("""
261
  <div style='
262
  text-align: center;
 
317
  </div>
318
  """)
319
 
320
+ # 添加 Loading 狀態顯示
321
+ loading_html = gr.HTML("""
322
+ <div id="loading-status" style="
323
+ text-align: center;
324
+ margin: 30px 0;
325
+ opacity: 0;
326
+ transition: opacity 0.3s ease-in-out;
327
+ ">
328
+ <div style="
329
+ display: inline-flex;
330
+ flex-direction: column;
331
+ align-items: center;
332
+ gap: 15px;
333
+ padding: 25px;
334
+ background: linear-gradient(to right, rgba(66, 153, 225, 0.1), rgba(72, 187, 120, 0.1));
335
+ border-radius: 12px;
336
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
337
+ ">
338
+ <!-- 可愛的狗狗圖示 -->
339
+ <div style="font-size: 40px;">🐕</div>
340
+
341
+ <!-- 載入中主要訊息 -->
342
+ <div style="
343
+ color: #2D3748;
344
+ font-size: 1.2em;
345
+ font-weight: 500;
346
+ margin-bottom: 5px;
347
+ ">Sniffing out your perfect match...</div>
348
+
349
+ <!-- 有趣的載入訊息 -->
350
+ <div id="loading-message" style="
351
+ color: #4A5568;
352
+ font-size: 0.95em;
353
+ font-style: italic;
354
+ ">Checking all the good boys and girls...</div>
355
+
356
+ <!-- 載入動畫 -->
357
+ <div style="
358
+ display: flex;
359
+ gap: 8px;
360
+ margin-top: 10px;
361
+ ">
362
+ <div class="paw" style="
363
+ width: 12px;
364
+ height: 12px;
365
+ background: #4299e1;
366
+ border-radius: 50%;
367
+ animation: pawAnimation 1s infinite;
368
+ animation-delay: 0s;
369
+ "></div>
370
+ <div class="paw" style="
371
+ width: 12px;
372
+ height: 12px;
373
+ background: #4299e1;
374
+ border-radius: 50%;
375
+ animation: pawAnimation 1s infinite;
376
+ animation-delay: 0.2s;
377
+ "></div>
378
+ <div class="paw" style="
379
+ width: 12px;
380
+ height: 12px;
381
+ background: #4299e1;
382
+ border-radius: 50%;
383
+ animation: pawAnimation 1s infinite;
384
+ animation-delay: 0.4s;
385
+ "></div>
386
+ </div>
387
+ </div>
388
+ </div>
389
+
390
+ <style>
391
+ @keyframes pawAnimation {
392
+ 0% { transform: translateY(0); }
393
+ 50% { transform: translateY(-10px); }
394
+ 100% { transform: translateY(0); }
395
+ }
396
+
397
+ #loading-status {
398
+ display: none;
399
+ }
400
+
401
+ #loading-status.visible {
402
+ display: block;
403
+ opacity: 1;
404
+ }
405
+ </style>
406
+
407
+ <script>
408
+ // 有趣的載入訊息列表
409
+ const messages = [
410
+ "Checking all the good boys and girls...",
411
+ "Fetching the perfect matches...",
412
+ "Calculating belly rub compatibility...",
413
+ "Analyzing tail wag frequencies...",
414
+ "Measuring treat enthusiasm levels...",
415
+ "Evaluating walkies requirements...",
416
+ "Consulting our canine experts...",
417
+ "Counting tennis balls...",
418
+ "Reviewing park visit preferences...",
419
+ "Assessing cuddle potential..."
420
+ ];
421
+
422
+ // 定期更新載入訊息
423
+ function updateLoadingMessage() {
424
+ const messageElement = document.getElementById('loading-message');
425
+ if (messageElement) {
426
+ const randomMessage = messages[Math.floor(Math.random() * messages.length)];
427
+ messageElement.textContent = randomMessage;
428
+ }
429
+ }
430
+
431
+ setInterval(updateLoadingMessage, 2000);
432
+ </script>
433
+ """, visible=False)
434
+
435
+ # 用戶輸入區域
436
  with gr.Row():
437
  with gr.Column():
438
  living_space = gr.Radio(
 
464
  value="moderate_activity"
465
  )
466
 
 
467
  grooming_commitment = gr.Radio(
468
  choices=["low", "medium", "high"],
469
  label="Grooming commitment level",
 
495
  choices=["toddler", "school_age", "teenager"],
496
  label="Children's Age Group",
497
  info="Helps match with age-appropriate breeds",
498
+ visible=False
499
  )
500
 
501
  noise_tolerance = gr.Radio(
 
504
  info="Some breeds are more vocal than others",
505
  value="medium"
506
  )
507
+
508
+ # 控制 children_age 顯示邏輯
509
  def update_children_age_visibility(has_children):
510
  return gr.update(visible=has_children)
511
 
 
515
  outputs=children_age
516
  )
517
 
518
+ # 推薦按鈕
519
+ get_recommendations_btn = gr.Button(
520
+ "Find My Perfect Match! 🔍",
521
+ variant="primary"
522
+ )
523
+
524
+ # 推薦結果顯示區域
525
  recommendation_output = gr.HTML(
526
  label="Breed Recommendations",
527
+ visible=True,
528
+ elem_id="recommendation-output"
529
  )
530
 
531
+ # 處理推薦請求的函數
532
+ def on_find_match_click(*args):
533
+ try:
534
+ # 顯示 loading 狀態
535
+ yield loading_html.update(visible=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
 
537
+ # 創建用戶偏好對象
538
+ user_prefs = UserPreferences(
539
+ living_space=args[0],
540
+ yard_access=args[1],
541
+ exercise_time=args[2],
542
+ exercise_type=args[3],
543
+ grooming_commitment=args[4],
544
+ experience_level=args[5],
545
+ time_availability=args[6],
546
+ has_children=args[7],
547
+ children_age=args[8] if args[7] else None,
548
+ noise_tolerance=args[9],
549
+ space_for_play=True if args[0] != "apartment" else False,
550
+ other_pets=False,
551
+ climate="moderate",
552
+ health_sensitivity="medium",
553
+ barking_acceptance=args[9]
554
+ )
 
 
 
 
 
 
 
 
 
555
 
556
+ # 獲取推薦結果
557
+ recommendations = get_breed_recommendations(user_prefs, top_n=10)
558
 
559
+ # 儲存搜尋歷史
560
+ history_results = [{
561
+ 'breed': rec['breed'],
562
+ 'rank': rec['rank'],
563
+ 'overall_score': rec['final_score'],
564
+ 'base_score': rec['base_score'],
565
+ 'bonus_score': rec['bonus_score'],
566
+ 'scores': rec['scores']
567
+ } for rec in recommendations]
568
+
569
+ history_component.save_search(
570
+ user_preferences={
571
+ 'living_space': args[0],
572
+ 'yard_access': args[1],
573
+ 'exercise_time': args[2],
574
+ 'exercise_type': args[3],
575
+ 'grooming_commitment': args[4],
576
+ 'experience_level': args[5],
577
+ 'time_availability': args[6],
578
+ 'has_children': args[7],
579
+ 'children_age': args[8] if args[7] else None,
580
+ 'noise_tolerance': args[9],
581
+ 'search_type': 'Criteria'
582
+ },
583
+ results=history_results
584
+ )
585
 
586
+ # 隱藏 loading 狀態並返回結果
587
+ return [
588
+ loading_html.update(visible=False),
589
+ format_recommendation_html(recommendations, is_description_search=False)
590
+ ]
591
+
592
+ except Exception as e:
593
+ print(f"Error in find match: {str(e)}")
594
+ import traceback
595
+ print(traceback.format_exc())
596
+ return [
597
+ loading_html.update(visible=False),
598
+ "Oops! Something went wrong while finding your perfect match. Please try again!"
599
+ ]
600
+
601
+ # 設置按鈕點擊事件
602
+ get_recommendations_btn.click(
603
+ fn=on_find_match_click,
604
+ inputs=[
605
+ living_space,
606
+ yard_access,
607
+ exercise_time,
608
+ exercise_type,
609
+ grooming_commitment,
610
+ experience_level,
611
+ time_availability,
612
+ has_children,
613
+ children_age,
614
+ noise_tolerance
615
+ ],
616
+ outputs=[loading_html, recommendation_output]
617
+ )
618
 
619
+ # 返回頁面組件
620
  return {
621
  'living_space': living_space,
622
  'exercise_time': exercise_time,