import gradio as gr import sqlite3 from dog_database import get_dog_description from breed_health_info import breed_health_info from breed_noise_info import breed_noise_info def create_comparison_tab(dog_breeds, get_dog_description, breed_noise_info, breed_health_info): breed_display_mapping = { breed: breed.replace('_', ' ').title() for breed in dog_breeds} reversed_mapping = {v: k for k ,v in breed_display_mapping.items()} sorted_display_names = sorted(breed_display_mapping.values(), key=lambda x: x.lower()) with gr.TabItem("Breed Comparison"): gr.HTML("
Select two dog breeds to compare their characteristics and care requirements.
") with gr.Row(): breed1_dropdown = gr.Dropdown( choices=sorted_display_names, label="Select First Breed", value="Golden Retriever" ) breed2_dropdown = gr.Dropdown( choices=sorted_display_names, label="Select Second Breed", value="Border Collie" ) compare_btn = gr.Button("Compare Breeds") comparison_output = gr.HTML(label="Comparison Results") def format_noise_data(notes): characteristics = [] triggers = [] noise_level = "Moderate" # 預設值 if isinstance(notes, str): lines = notes.strip().split('\n') section = "" for line in lines: line = line.strip() if "Typical noise characteristics:" in line: section = "characteristics" elif "Barking triggers:" in line: section = "triggers" elif "Noise level:" in line: noise_level = line.split(':')[1].strip() elif line.startswith('•'): if section == "characteristics": characteristics.append(line[1:].strip()) elif section == "triggers": triggers.append(line[1:].strip()) return { 'characteristics': characteristics, 'triggers': triggers, 'noise_level': noise_level } def format_health_data(notes): considerations = [] screenings = [] if isinstance(notes, str): lines = notes.strip().split('\n') current_section = None for line in lines: line = line.strip() # 修正字串比對 if "Common breed-specific health considerations" in line: current_section = "considerations" elif "Recommended health screenings:" in line: current_section = "screenings" elif line.startswith('•'): item = line[1:].strip() if current_section == "considerations": considerations.append(item) elif current_section == "screenings": screenings.append(item) # 只有當真的沒有資料時才返回 "Information not available" if not considerations and not screenings: return { 'considerations': ["Information not available"], 'screenings': ["Information not available"] } return { 'considerations': considerations, 'screenings': screenings } def get_comparison_styles(): return """ .comparison-container { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; padding: 20px; } .breed-column { background: white; border-radius: 10px; padding: 24px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .section-title { font-size: 24px; color: #2D3748; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 2px solid #E2E8F0; } .info-section { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-bottom: 24px; } .info-item { position: relative; background: #F8FAFC; padding: 16px; border-radius: 8px; border: 1px solid #E2E8F0; } .info-label { display: flex; align-items: center; gap: 8px; color: #4A5568; font-size: 0.9em; margin-bottom: 4px; } .info-icon { cursor: help; background: #E2E8F0; width: 18px; height: 18px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; color: #4A5568; margin-left: 4px; } .info-icon:hover + .tooltip-content { display: block; } .tooltip-content { display: none; position: absolute; background: #2D3748; color: #FFFFFF; padding: 8px 12px; border-radius: 6px; font-size: 14px; line-height: 1.3; width: max-content; max-width: 280px; z-index: 1000; top: 0; /* 修改位置 */ left: 100%; margin-left: 10px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); white-space: normal; /* 允許文字換行 */ } .tooltip-content, .tooltip-content *, .tooltip-content strong, .tooltip-content li, .tooltip-content ul, .tooltip-content p, .tooltip-content span, .tooltip-content div { color: #FFFFFF !important; } .tooltip-content::before { content: ''; position: absolute; left: -6px; top: 14px; /* 配合上方位置調整 */ border-width: 6px; border-style: solid; border-color: transparent #2D3748 transparent transparent; } .tooltip-content strong { color: #FFFFFF; display: block; margin-bottom: 4px; font-weight: 600; } .tooltip-content ul { margin: 0; padding-left: 16px; color: #FFFFFF; } .tooltip-content * { color: #FFFFFF; } .tooltip-content li { margin-bottom: 2px; color: #FFFFFF; } .tooltip-content li::before { color: #FFFFFF !important; } .tooltip-content br { display: block; margin: 2px 0; } .info-value { color: #2D3748; font-weight: 500; } .characteristic-section { background: #F8FAFC; padding: 20px; border-radius: 8px; margin-bottom: 20px; } .subsection-title { font-size: 18px; color: #2D3748; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } .noise-level { background: #EDF2F7; padding: 16px; border-radius: 6px; margin: 16px 0; border: 1px solid #CBD5E0; } .level-label { color: #4A5568; font-size: 1.1em; font-weight: 500; margin-bottom: 8px; } .level-value { color: #2D3748; font-size: 1.2em; font-weight: 600; } .characteristics-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-top: 12px; } .characteristic-item { background: white; padding: 12px; border-radius: 6px; border: 1px solid #E2E8F0; color: #4A5568; } .health-insights { margin-top: 24px; } .health-grid { display: grid; grid-template-columns: 1fr; gap: 8px; } .health-item { background: white; padding: 12px; border-radius: 6px; border: 1px solid #E2E8F0; color: #E53E3E; } .screening-item { background: white; padding: 12px; border-radius: 6px; border: 1px solid #E2E8F0; color: #38A169; } .learn-more-btn { display: inline-block; margin-top: 20px; padding: 12px 24px; background: linear-gradient(90deg, #4299e1, #48bb78); color: white; text-decoration: none; border-radius: 6px; transition: all 0.3s ease; text-align: center; width: 100%; font-weight: 500; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .learn-more-btn:hover { background: linear-gradient(90deg, #4299e1, #48bb78); transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .info-disclaimer { margin-top: 24px; padding: 16px; background: #F7FAFC; border-radius: 8px; font-size: 0.9em; color: #4A5568; line-height: 1.5; border-left: 4px solid #4299E1; } @media (max-width: 768px) { .comparison-container { grid-template-columns: 1fr; } .info-section { grid-template-columns: 1fr; } .characteristics-grid { grid-template-columns: 1fr; } } """ def show_comparison(breed1_display, breed2_display): if not breed1_display or not breed2_display: return "Please select two breeds to compare" breed1 = reversed_mapping[breed1_display] breed2 = reversed_mapping[breed2_display] breed1_info = get_dog_description(breed1) breed2_info = get_dog_description(breed2) breed1_noise = breed_noise_info.get(breed1, {}) breed2_noise = breed_noise_info.get(breed2, {}) breed1_health = breed_health_info.get(breed1, {}) breed2_health = breed_health_info.get(breed2, {}) def create_info_item(label, value, tooltip_text=""): tooltip = f"""