DawnC commited on
Commit
f036996
1 Parent(s): 80eb9ed

Update search_history.py

Browse files
Files changed (1) hide show
  1. search_history.py +108 -109
search_history.py CHANGED
@@ -3,36 +3,36 @@ import traceback
3
  from typing import Optional, Dict, List
4
  from history_manager import UserHistoryManager
5
 
6
- class SearchHistoryComponent:
7
- def __init__(self):
8
- """初始化搜索歷史組件"""
9
  self.history_manager = UserHistoryManager()
10
 
11
- def format_history_html(self, history_data: Optional[List[Dict]] = None) -> str:
12
- try:
13
- if history_data is None:
14
  history_data = self.history_manager.get_history()
15
 
16
- if not history_data:
17
- return """
18
  <div style='text-align: center; padding: 40px 20px;'>
19
  <p>No search history yet. Try making some breed recommendations!</p>
20
  </div>
21
  """
22
 
23
  html = "<div class='history-container'>"
24
-
25
  # 對歷史記錄進行反轉,最新的顯示在前面
26
- for entry in reversed(history_data):
27
- timestamp = entry.get('timestamp', 'Unknown time')
28
- search_type = entry.get('search_type', 'criteria')
29
- results = entry.get('results', [])
30
-
31
  # 顯示時間戳記和搜尋類型
32
  html += f"""
33
  <div class="history-entry">
34
  <div class="history-header" style="border-left: 4px solid #4299e1; padding-left: 10px;">
35
- <span class="timestamp">🕒 {timestamp}</span>
36
  <span class="search-type" style="color: #4299e1; font-weight: bold; margin-left: 10px;">
37
  Search History
38
  </span>
@@ -40,38 +40,38 @@ class SearchHistoryComponent:
40
  """
41
 
42
  # 顯示搜尋參數
43
- if search_type == "criteria":
44
- prefs = entry.get('preferences', {})
45
  html += f"""
46
  <div class="params-list" style="background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 16px;">
47
  <h4 style="margin-bottom: 12px;">Search Parameters:</h4>
48
  <ul style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;">
49
- <li>Living Space: {prefs.get('living_space', 'N/A')}</li>
50
- <li>Exercise Time: {prefs.get('exercise_time', 'N/A')} minutes</li>
51
- <li>Grooming: {prefs.get('grooming_commitment', 'N/A')}</li>
52
- <li>Size Preference: {prefs.get('size_preference', 'N/A')}</li>
53
- <li>Experience: {prefs.get('experience_level', 'N/A')}</li>
54
- <li>Children at Home: {"Yes" if prefs.get('has_children') else "No"}</li>
55
- <li>Noise Tolerance: {prefs.get('noise_tolerance', 'N/A')}</li>
56
  </ul>
57
  </div>
58
  """
59
 
60
  # 關鍵修改:確保結果部分始終顯示
61
- if results: # 只有在有結果時才顯示結果區域
62
  html += """
63
  <div class="results-list" style="margin-top: 16px;">
64
  <h4 style="margin-bottom: 12px;">Top 15 Breed Matches:</h4>
65
  <div class="breed-list">
66
  """
67
-
68
  # 顯示每個推薦結果
69
- for i, result in enumerate(results[:15], 1):
70
- breed = result.get('breed', 'Unknown breed')
71
- score = result.get('overall_score', 0) # 改用 overall_score
72
- if isinstance(score, (int, float)): # 確保分數是數字
73
- score = float(score) * 100 # 轉換為百分比
74
-
75
  html += f"""
76
  <div class="breed-item" style="margin-bottom: 8px;">
77
  <div class="breed-info" style="display: flex; align-items: center; justify-content: space-between; padding: 8px; background: #f8fafc; border-radius: 6px;">
@@ -81,106 +81,105 @@ class SearchHistoryComponent:
81
  </div>
82
  </div>
83
  """
84
-
85
  html += """
86
  </div>
87
  </div>
88
  """
89
 
90
- html += "</div>" # 關閉 history-entry div
91
-
92
- html += "</div>" # 關閉 history-container div
93
  return html
94
 
95
  except Exception as e:
96
- print(f"Error formatting history: {str(e)}")
97
- print(traceback.format_exc())
98
- return f"""
99
  <div style='text-align: center; padding: 20px; color: #dc2626;'>
100
  Error formatting history. Please try refreshing the page.
101
- <br>Error details: {str(e)}
102
  </div>
103
  """
104
 
105
- def clear_history(self) -> str:
106
- """清除所有搜尋歷史"""
107
- try:
108
  success = self.history_manager.clear_all_history()
109
- print(f"Clear history result: {success}")
110
  return self.format_history_html()
111
  except Exception as e:
112
- print(f"Error in clear_history: {str(e)}")
113
- print(traceback.format_exc())
114
- return "Error clearing history"
115
 
116
- def refresh_history(self) -> str:
117
  """刷新歷史記錄顯示"""
118
- try:
119
  return self.format_history_html()
120
  except Exception as e:
121
- print(f"Error in refresh_history: {str(e)}")
122
- return "Error refreshing history"
123
 
124
- def save_search(self, user_preferences: Optional[dict] = None,
125
- results: list = None,
126
- search_type: str = "criteria",
127
- description: str = None) -> bool:
128
  """
129
- 保存搜索結果到歷史記錄
130
  這個方法負責處理搜尋結果的保存,並確保只保存前15個最相關的推薦結果。
131
- 在保存之前,會處理結果數據確保格式正確且包含所需的所有資訊。
132
  Args:
133
- user_preferences: 使用者偏好設定 (僅用於criteria搜尋)
134
  包含所有搜尋條件如居住空間、運動時間等
135
  results: 推薦結果列表
136
  包含所有推薦的狗品種及其評分
137
- search_type: 搜尋類型 ("criteria" 或 "description")
138
  用於標識搜尋方式
139
- description: 使用者輸入的描述 (僅用於description搜尋)
140
  用於自然語言搜尋時的描述文本
141
-
142
  Returns:
143
  bool: 表示保存是否成功
144
  """
145
  # 首先確保結果不為空且為列表
146
- if results and isinstance(results, list):
147
  # 只取前15個結果
148
  processed_results = []
149
- for result in results[:15]: # 限制為前15個結果
150
- # 確保每個結果都包含必要的資訊
151
- if isinstance(result, dict):
152
  processed_result = {
153
- 'breed': result.get('breed', 'Unknown'),
154
- 'overall_score': result.get('overall_score', result.get('final_score', 0)),
155
- 'rank': result.get('rank', 0),
156
- 'base_score': result.get('base_score', 0),
157
- 'bonus_score': result.get('bonus_score', 0),
158
- 'scores': result.get('scores', {})
159
  }
160
  processed_results.append(processed_result)
161
- else:
162
  # 如果沒有結果,創建空列表
163
  processed_results = []
164
-
165
- # 調用 history_manager 的 save_history 方法保存處理過的結果
166
  return self.history_manager.save_history(
167
  user_preferences=user_preferences,
168
- results=processed_results, # 使用處理過的結果
169
- search_type='criteria'
170
  )
171
 
172
- def create_history_component():
173
- """只創建實例"""
174
  return SearchHistoryComponent()
175
 
176
- def create_history_tab(history_component: SearchHistoryComponent):
177
  """創建歷史紀錄的頁面
178
-
179
  Args:
180
- history_component:
181
  """
182
- with gr.TabItem("Recommendation Search History"):
183
- gr.HTML("""
184
  <style>
185
  .custom-btn {
186
  padding: 10px 20px !important;
@@ -194,50 +193,50 @@ def create_history_tab(history_component: SearchHistoryComponent):
194
  width: 100% !important;
195
  min-height: 42px !important;
196
  }
197
-
198
- /* Clear History 的按鈕 */
199
  .clear-btn {
200
  background: linear-gradient(135deg, #FF6B6B 0%, #FF9B8B 100%) !important;
201
  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.15) !important;
202
  }
203
-
204
  .clear-btn:hover {
205
  background: linear-gradient(135deg, #FF5252, #FF8B7B) !important;
206
  transform: translateY(-1px);
207
  }
208
-
209
  .clear-btn:active {
210
  transform: translateY(1px) scale(0.98);
211
  background: linear-gradient(135deg, #FF4242, #FF7B6B) !important;
212
  }
213
-
214
- /* Refresh 的按鈕 */
215
  .refresh-btn {
216
  background: linear-gradient(135deg, #4FB5E5 0%, #32CCBC 100%) !important;
217
  box-shadow: 0 2px 4px rgba(79, 181, 229, 0.15) !important;
218
  }
219
-
220
  .refresh-btn:hover {
221
  background: linear-gradient(135deg, #45A5D5, #2DBCAC) !important;
222
  transform: translateY(-1px);
223
  }
224
-
225
  .refresh-btn:active {
226
  transform: translateY(1px) scale(0.98);
227
  background: linear-gradient(135deg, #3B95C5, #28AC9C) !important;
228
  }
229
-
230
- /* 懸浮的效果 */
231
  .custom-btn:hover {
232
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
233
  }
234
-
235
- /* 點擊的效果 */
236
  .custom-btn:active {
237
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
238
  }
239
  </style>
240
-
241
  <div style='text-align: center; padding: 20px;'>
242
  <h3 style='
243
  color: #2D3748;
@@ -269,23 +268,23 @@ def create_history_tab(history_component: SearchHistoryComponent):
269
  </p>
270
  </div>
271
  </div>
272
- """)
273
 
274
  with gr.Row():
275
- with gr.Column(scale=4):
276
  history_display = gr.HTML()
277
- with gr.Row(equal_height=True):
278
- with gr.Column(scale=1):
279
  clear_history_btn = gr.Button(
280
- "🗑️ Clear History",
281
- variant="primary",
282
- elem_classes="custom-btn clear-btn"
283
  )
284
- with gr.Column(scale=1):
285
  refresh_btn = gr.Button(
286
- "🔄 Refresh",
287
- variant="primary",
288
- elem_classes="custom-btn refresh-btn"
289
  )
290
 
291
  history_display.value = history_component.format_history_html()
@@ -293,11 +292,11 @@ def create_history_tab(history_component: SearchHistoryComponent):
293
  clear_history_btn.click(
294
  fn=history_component.clear_history,
295
  outputs=[history_display],
296
- api_name="clear_history"
297
  )
298
 
299
  refresh_btn.click(
300
  fn=history_component.refresh_history,
301
  outputs=[history_display],
302
- api_name="refresh_history"
303
  )
 
3
  from typing import Optional, Dict, List
4
  from history_manager import UserHistoryManager
5
 
6
+ class SearchHistoryComponent :
7
+ def __init__ ( self ):
8
+ """初始化搜尋歷史組件"""
9
  self.history_manager = UserHistoryManager()
10
 
11
+ def format_history_html ( self, history_data: Optional [ List [ Dict ]] = None ) -> str :
12
+ try :
13
+ if history_data is None :
14
  history_data = self.history_manager.get_history()
15
 
16
+ if not history_data:
17
+ return """
18
  <div style='text-align: center; padding: 40px 20px;'>
19
  <p>No search history yet. Try making some breed recommendations!</p>
20
  </div>
21
  """
22
 
23
  html = "<div class='history-container'>"
24
+
25
  # 對歷史記錄進行反轉,最新的顯示在前面
26
+ for entry in reversed (history_data):
27
+ timestamp = entry.get( 'timestamp' , 'Unknown time' )
28
+ search_type = entry.get( 'search_type' , 'criteria' )
29
+ results = entry.get( 'results' , [])
30
+
31
  # 顯示時間戳記和搜尋類型
32
  html += f"""
33
  <div class="history-entry">
34
  <div class="history-header" style="border-left: 4px solid #4299e1; padding-left: 10px;">
35
+ <span class="timestamp">🕒 {timestamp} </span>
36
  <span class="search-type" style="color: #4299e1; font-weight: bold; margin-left: 10px;">
37
  Search History
38
  </span>
 
40
  """
41
 
42
  # 顯示搜尋參數
43
+ if search_type == "criteria" :
44
+ prefs = entry.get( 'preferences' , {})
45
  html += f"""
46
  <div class="params-list" style="background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 16px;">
47
  <h4 style="margin-bottom: 12px;">Search Parameters:</h4>
48
  <ul style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;">
49
+ <li>Living Space: {prefs.get( 'living_space' , 'N/A' )} </li>
50
+ <li>Exercise Time: {prefs.get( 'exercise_time' , 'N/A' )} minutes</li>
51
+ <li>Grooming: {prefs.get( 'grooming_commitment' , 'N/A' )} </li>
52
+ <li>Size Preference: {prefs.get( 'size_preference' , 'N/A' )} </li>
53
+ <li>Experience: {prefs.get( 'experience_level' , 'N/A' )} </li>
54
+ <li>Children at Home: { "Yes" if prefs.get( 'has_children' ) else "No" } </li>
55
+ <li>Noise Tolerance: {prefs.get( 'noise_tolerance' , 'N/A' )} </li>
56
  </ul>
57
  </div>
58
  """
59
 
60
  # 關鍵修改:確保結果部分始終顯示
61
+ if results: # 只有在有結果時才顯示結果區域
62
  html += """
63
  <div class="results-list" style="margin-top: 16px;">
64
  <h4 style="margin-bottom: 12px;">Top 15 Breed Matches:</h4>
65
  <div class="breed-list">
66
  """
67
+
68
  # 顯示每個推薦結果
69
+ for i, result in enumerate (results[: 15 ], 1 ):
70
+ breed = result.get( 'breed' , 'Unknown breed' )
71
+ score = result.get( 'overall_score' , 0 ) # 改用overall_score
72
+ if isinstance (score, ( int , float )): # 確保分數是數字
73
+ score = float (score) * 100 # 轉換為百分比
74
+
75
  html += f"""
76
  <div class="breed-item" style="margin-bottom: 8px;">
77
  <div class="breed-info" style="display: flex; align-items: center; justify-content: space-between; padding: 8px; background: #f8fafc; border-radius: 6px;">
 
81
  </div>
82
  </div>
83
  """
84
+
85
  html += """
86
  </div>
87
  </div>
88
  """
89
 
90
+ html += "</div>" # 關閉history-entry div
91
+
92
+ html += "</div>" # 關閉history-container div
93
  return html
94
 
95
  except Exception as e:
96
+ print ( f"Error formatting history: { str (e)} " )
97
+ print (traceback.format_exc())
98
+ return f"""
99
  <div style='text-align: center; padding: 20px; color: #dc2626;'>
100
  Error formatting history. Please try refreshing the page.
101
+ <br>Error details: { str (e)}
102
  </div>
103
  """
104
 
105
+ def clear_history ( self ) -> str :
106
+ """清除所有搜尋紀錄"""
107
+ try :
108
  success = self.history_manager.clear_all_history()
109
+ print ( f"Clear history result: {success} " )
110
  return self.format_history_html()
111
  except Exception as e:
112
+ print ( f"Error in clear_history: { str (e)} " )
113
+ print (traceback.format_exc())
114
+ return "Error clearing history"
115
 
116
+ def refresh_history ( self ) -> str :
117
  """刷新歷史記錄顯示"""
118
+ try :
119
  return self.format_history_html()
120
  except Exception as e:
121
+ print ( f"Error in refresh_history: { str (e)} " )
122
+ return "Error refreshing history"
123
 
124
+ def save_search ( self, user_preferences: Optional [ dict ] = None ,
125
+ results: list = None ,
126
+ search_type: str = "criteria" ,
127
+ description: str = None ) -> bool :
128
  """
129
+ 儲存搜尋結果到歷史記錄
130
  這個方法負責處理搜尋結果的保存,並確保只保存前15個最相關的推薦結果。
131
+ 在儲存之前,會處理結果資料確保格式正確且包含所需的所有資訊。
132
  Args:
133
+ user_preferences: 使用者偏好設定(僅用於criteria搜尋)
134
  包含所有搜尋條件如居住空間、運動時間等
135
  results: 推薦結果列表
136
  包含所有推薦的狗品種及其評分
137
+ search_type: 搜尋類型("criteria" 或"description")
138
  用於標識搜尋方式
139
+ description: 用戶輸入的描述(僅用於description搜尋)
140
  用於自然語言搜尋時的描述文本
141
+
142
  Returns:
143
  bool: 表示保存是否成功
144
  """
145
  # 首先確保結果不為空且為列表
146
+ if results and isinstance (results, list ):
147
  # 只取前15個結果
148
  processed_results = []
149
+ for result in results[: 15 ]: # 限制為前15個結果
150
+ # 確保每個結果都包含必要的信息
151
+ if isinstance (result, dict ):
152
  processed_result = {
153
+ 'breed' : result.get( 'breed' , 'Unknown' ),
154
+ 'overall_score' : result.get( 'overall_score' , result.get( 'final_score' , 0 )),
155
+ 'rank' : result.get( 'rank' , 0 ),
156
+ 'base_score' : result.get( 'base_score' , 0 ),
157
+ 'bonus_score' : result.get( 'bonus_score' , 0 ),
158
+ 'scores' : result.get( 'scores' , {})
159
  }
160
  processed_results.append(processed_result)
161
+ else :
162
  # 如果沒有結果,創建空列表
163
  processed_results = []
164
+
165
+ # 調用history_manager 的save_history 方法保存處理過的結果
166
  return self.history_manager.save_history(
167
  user_preferences=user_preferences,
168
+ results=processed_results, # 使用處理過的結果
169
+ search_type= 'criteria'
170
  )
171
 
172
+ def create_history_component ():
173
+ """只建立實例"""
174
  return SearchHistoryComponent()
175
 
176
+ def create_history_tab ( history_component: SearchHistoryComponent ):
177
  """創建歷史紀錄的頁面
 
178
  Args:
179
+ history_component:
180
  """
181
+ with gr.TabItem( "Recommendation Search History" ):
182
+ gr.HTML( """
183
  <style>
184
  .custom-btn {
185
  padding: 10px 20px !important;
 
193
  width: 100% !important;
194
  min-height: 42px !important;
195
  }
196
+
197
+ /* Clear History 的按鈕*/
198
  .clear-btn {
199
  background: linear-gradient(135deg, #FF6B6B 0%, #FF9B8B 100%) !important;
200
  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.15) !important;
201
  }
202
+
203
  .clear-btn:hover {
204
  background: linear-gradient(135deg, #FF5252, #FF8B7B) !important;
205
  transform: translateY(-1px);
206
  }
207
+
208
  .clear-btn:active {
209
  transform: translateY(1px) scale(0.98);
210
  background: linear-gradient(135deg, #FF4242, #FF7B6B) !important;
211
  }
212
+
213
+ /* Refresh 的按鈕*/
214
  .refresh-btn {
215
  background: linear-gradient(135deg, #4FB5E5 0%, #32CCBC 100%) !important;
216
  box-shadow: 0 2px 4px rgba(79, 181, 229, 0.15) !important;
217
  }
218
+
219
  .refresh-btn:hover {
220
  background: linear-gradient(135deg, #45A5D5, #2DBCAC) !important;
221
  transform: translateY(-1px);
222
  }
223
+
224
  .refresh-btn:active {
225
  transform: translateY(1px) scale(0.98);
226
  background: linear-gradient(135deg, #3B95C5, #28AC9C) !important;
227
  }
228
+
229
+ /* 懸浮的效果*/
230
  .custom-btn:hover {
231
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
232
  }
233
+
234
+ /* 點擊的效果*/
235
  .custom-btn:active {
236
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
237
  }
238
  </style>
239
+
240
  <div style='text-align: center; padding: 20px;'>
241
  <h3 style='
242
  color: #2D3748;
 
268
  </p>
269
  </div>
270
  </div>
271
+ """ )
272
 
273
  with gr.Row():
274
+ with gr.Column(scale= 4 ):
275
  history_display = gr.HTML()
276
+ with gr.Row(equal_height= True ):
277
+ with gr.Column(scale= 1 ):
278
  clear_history_btn = gr.Button(
279
+ "🗑️ Clear History" ,
280
+ variant= "primary" ,
281
+ elem_classes= "custom-btn clear-btn"
282
  )
283
+ with gr.Column(scale= 1 ):
284
  refresh_btn = gr.Button(
285
+ "🔄 Refresh" ,
286
+ variant= "primary" ,
287
+ elem_classes= "custom-btn refresh-btn"
288
  )
289
 
290
  history_display.value = history_component.format_history_html()
 
292
  clear_history_btn.click(
293
  fn=history_component.clear_history,
294
  outputs=[history_display],
295
+ api_name= "clear_history"
296
  )
297
 
298
  refresh_btn.click(
299
  fn=history_component.refresh_history,
300
  outputs=[history_display],
301
+ api_name= "refresh_history"
302
  )