import gradio as gr import traceback from typing import Optional, Dict, List from history_manager import UserHistoryManager class SearchHistoryComponent: def __init__(self): """初始化搜索歷史組件""" self.history_manager = UserHistoryManager() def format_history_html(self, history_data: Optional[List[Dict]] = None) -> str: try: if history_data is None: history_data = self.history_manager.get_history() if not history_data: return """ <div style='text-align: center; padding: 40px 20px;'> <p>No search history yet. Try making some breed recommendations!</p> </div> """ html = "<div class='history-container'>" # 對歷史記錄進行反轉,最新的顯示在前面 for entry in reversed(history_data): timestamp = entry.get('timestamp', 'Unknown time') search_type = entry.get('search_type', 'criteria') results = entry.get('results', []) # 確保我們有結果資料 # 顯示時間戳記和搜尋類型 html += f""" <div class="history-entry"> <div class="history-header" style="border-left: 4px solid #4299e1; padding-left: 10px;"> <span class="timestamp">🕒 {timestamp}</span> <span class="search-type" style="color: #4299e1; font-weight: bold; margin-left: 10px;"> Search History </span> </div> """ # 顯示搜尋參數 if search_type == "criteria": prefs = entry.get('preferences', {}) html += f""" <div class="params-list" style="background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 16px;"> <h4 style="margin-bottom: 12px;">Search Parameters:</h4> <ul style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;"> <li>Living Space: {prefs.get('living_space', 'N/A')}</li> <li>Exercise Time: {prefs.get('exercise_time', 'N/A')} minutes</li> <li>Grooming: {prefs.get('grooming_commitment', 'N/A')}</li> <li>Experience: {prefs.get('experience_level', 'N/A')}</li> <li>Children at Home: {"Yes" if prefs.get('has_children') else "No"}</li> <li>Noise Tolerance: {prefs.get('noise_tolerance', 'N/A')}</li> </ul> </div> """ # 關鍵修改:確保結果部分始終顯示 if results: # 只有在有結果時才顯示結果區域 html += """ <div class="results-list" style="margin-top: 16px;"> <h4 style="margin-bottom: 12px;">Top 10 Breed Matches:</h4> <div class="breed-list"> """ # 顯示每個推薦結果 for i, result in enumerate(results[:10], 1): breed = result.get('breed', 'Unknown breed') score = result.get('overall_score', 0) # 改用 overall_score if isinstance(score, (int, float)): # 確保分數是數字 score = float(score) * 100 # 轉換為百分比 html += f""" <div class="breed-item" style="margin-bottom: 8px;"> <div class="breed-info" style="display: flex; align-items: center; justify-content: space-between; padding: 8px; background: #f8fafc; border-radius: 6px;"> <span class="breed-rank" style="background: linear-gradient(135deg, #4299e1, #48bb78); color: white; padding: 4px 10px; border-radius: 6px; font-weight: 600; min-width: 40px; text-align: center;">#{i}</span> <span class="breed-name" style="font-weight: 500; color: #2D3748; margin: 0 12px;">{breed.replace('_', ' ')}</span> <span class="breed-score" style="background: #F0FFF4; color: #48BB78; padding: 4px 8px; border-radius: 4px; font-weight: 600;">{score:.1f}%</span> </div> </div> """ html += """ </div> </div> """ html += "</div>" # 關閉 history-entry div html += "</div>" # 關閉 history-container div return html except Exception as e: print(f"Error formatting history: {str(e)}") print(traceback.format_exc()) return f""" <div style='text-align: center; padding: 20px; color: #dc2626;'> Error formatting history. Please try refreshing the page. <br>Error details: {str(e)} </div> """ def clear_history(self) -> str: """清除所有搜尋歷史""" try: success = self.history_manager.clear_all_history() print(f"Clear history result: {success}") return self.format_history_html() except Exception as e: print(f"Error in clear_history: {str(e)}") print(traceback.format_exc()) return "Error clearing history" def refresh_history(self) -> str: """刷新歷史記錄顯示""" try: return self.format_history_html() except Exception as e: print(f"Error in refresh_history: {str(e)}") return "Error refreshing history" def save_search(self, user_preferences: Optional[dict] = None, results: list = None, search_type: str = "criteria", description: str = None) -> bool: """保存搜索結果 Args: user_preferences: 使用者偏好設定 (僅用於criteria搜尋) results: 推薦結果列表 search_type: 搜尋類型 ("criteria" 或 "description") description: 使用者輸入的描述 (僅用於description搜尋) """ return self.history_manager.save_history( user_preferences=user_preferences, results=results, search_type='criteria', ) def create_history_component(): """只創建實例""" return SearchHistoryComponent() def create_history_tab(history_component: SearchHistoryComponent): """創建歷史紀錄的頁面 Args: history_component: """ with gr.TabItem("Recommendation Search History"): gr.HTML(""" <div style='text-align: center; padding: 20px;'> <h3 style=' color: #2D3748; margin-bottom: 10px; font-size: 1.5em; background: linear-gradient(90deg, #4299e1, #48bb78); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600; '>Search History</h3> <div style=' text-align: center; padding: 20px 0; margin: 15px 0; background: linear-gradient(to right, rgba(66, 153, 225, 0.1), rgba(72, 187, 120, 0.1)); border-radius: 10px; '> <p style=' font-size: 1.2em; margin: 0; padding: 0 20px; line-height: 1.5; background: linear-gradient(90deg, #4299e1, #48bb78); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600; '> View your previous breed recommendations and search preferences </p> </div> </div> """) with gr.Row(): with gr.Column(scale=4): history_display = gr.HTML() with gr.Row(): with gr.Column(scale=1): clear_history_btn = gr.Button( "🗑️ Clear History", variant="secondary", size="sm" ) with gr.Column(scale=1): refresh_btn = gr.Button( "🔄 Refresh", variant="secondary", size="sm" ) history_display.value = history_component.format_history_html() clear_history_btn.click( fn=history_component.clear_history, outputs=[history_display], api_name="clear_history" ) refresh_btn.click( fn=history_component.refresh_history, outputs=[history_display], api_name="refresh_history" )