Spaces:
Running
on
Zero
Running
on
Zero
from typing import Dict, List, Union, Any, Optional, Callable | |
from urllib.parse import quote | |
def get_akc_breeds_link(breed: str) -> str: | |
"""Generate AKC breed page URL with intelligent name handling.""" | |
breed_name = breed.lower() | |
breed_name = breed_name.replace('_', '-') | |
breed_name = breed_name.replace("'", '') | |
breed_name = breed_name.replace(" ", '-') | |
special_cases = { | |
'mexican-hairless': 'xoloitzcuintli', | |
'brabancon-griffon': 'brussels-griffon', | |
'bull-mastiff': 'bullmastiff', | |
'walker-hound': 'treeing-walker-coonhound' | |
} | |
breed_name = special_cases.get(breed_name, breed_name) | |
return f"https://www.akc.org/dog-breeds/{breed_name}/" | |
def get_color_scheme(is_single_dog: bool) -> Union[str, List[str]]: | |
"""Get color scheme for dog detection visualization.""" | |
single_dog_color = '#34C759' # 清爽的綠色作為單狗顏色 | |
color_list = [ | |
'#FF5733', # 珊瑚紅 | |
'#28A745', # 深綠色 | |
'#3357FF', # 寶藍色 | |
'#FF33F5', # 粉紫色 | |
'#FFB733', # 橙黃色 | |
'#33FFF5', # 青藍色 | |
'#A233FF', # 紫色 | |
'#FF3333', # 紅色 | |
'#33FFB7', # 青綠色 | |
'#FFE033' # 金黃色 | |
] | |
return single_dog_color if is_single_dog else color_list | |
def format_warning_html(message: str) -> str: | |
"""Format warning messages in a consistent style.""" | |
return f''' | |
<div class="dog-info-card"> | |
<div class="breed-info"> | |
<p class="warning-message"> | |
<span class="icon">⚠️</span> | |
{message} | |
</p> | |
</div> | |
</div> | |
''' | |
def format_error_message(color: str, index: int) -> str: | |
"""Format error message when confidence is too low.""" | |
return f''' | |
<div class="dog-info-card" style="border-left: 8px solid {color};"> | |
<div class="dog-info-header" style="background-color: {color}10;"> | |
<span class="dog-label" style="color: {color};">Dog {index}</span> | |
</div> | |
<div class="breed-info"> | |
<div class="warning-message"> | |
<span class="icon">⚠️</span> | |
The image is unclear or the breed is not in the dataset. Please upload a clearer image. | |
</div> | |
</div> | |
</div> | |
''' | |
def format_description_html(description: Dict[str, Any], breed: str) -> str: | |
"""Format basic breed description with tooltips.""" | |
if not isinstance(description, dict): | |
return f"<p>{description}</p>" | |
fields_order = [ | |
"Size", "Lifespan", "Temperament", "Exercise Needs", | |
"Grooming Needs", "Care Level", "Good with Children", | |
"Description" | |
] | |
html_parts = [] | |
for field in fields_order: | |
if field in description: | |
value = description[field] | |
tooltip_html = format_tooltip(field, value) | |
html_parts.append(f'<li style="margin-bottom: 10px;">{tooltip_html}</li>') | |
# Add any remaining fields | |
for key, value in description.items(): | |
if key not in fields_order and key != "Breed": | |
html_parts.append(f'<li style="margin-bottom: 10px;"><strong>{key}:</strong> {value}</li>') | |
return f'<ul style="list-style-type: none; padding-left: 0;">{" ".join(html_parts)}</ul>' | |
def format_tooltip(key: str, value: str) -> str: | |
"""Format tooltip with content for each field.""" | |
tooltip_contents = { | |
"Size": { | |
"title": "Size Categories", | |
"items": [ | |
"Small: Under 20 pounds", | |
"Medium: 20-60 pounds", | |
"Large: Over 60 pounds", | |
"Giant: Over 100 pounds", | |
"Varies: Depends on variety" | |
] | |
}, | |
"Exercise Needs": { | |
"title": "Exercise Needs", | |
"items": [ | |
"Low: Short walks and play sessions", | |
"Moderate: 1-2 hours of daily activity", | |
"High: Extensive exercise (2+ hours/day)", | |
"Very High: Constant activity and mental stimulation needed" | |
] | |
}, | |
"Grooming Needs": { | |
"title": "Grooming Requirements", | |
"items": [ | |
"Low: Basic brushing, occasional baths", | |
"Moderate: Weekly brushing, occasional grooming", | |
"High: Daily brushing, frequent professional grooming needed", | |
"Professional care recommended for all levels" | |
] | |
}, | |
"Care Level": { | |
"title": "Care Level Explained", | |
"items": [ | |
"Low: Basic care and attention needed", | |
"Moderate: Regular care and routine needed", | |
"High: Significant time and attention needed", | |
"Very High: Extensive care, training and attention required" | |
] | |
}, | |
"Good with Children": { | |
"title": "Child Compatibility", | |
"items": [ | |
"Yes: Excellent with kids, patient and gentle", | |
"Moderate: Good with older children", | |
"No: Better suited for adult households" | |
] | |
}, | |
"Lifespan": { | |
"title": "Average Lifespan", | |
"items": [ | |
"Short: 6-8 years", | |
"Average: 10-15 years", | |
"Long: 12-20 years", | |
"Varies by size: Larger breeds typically have shorter lifespans" | |
] | |
}, | |
"Temperament": { | |
"title": "Temperament Guide", | |
"items": [ | |
"Describes the dog's natural behavior and personality", | |
"Important for matching with owner's lifestyle", | |
"Can be influenced by training and socialization" | |
] | |
} | |
} | |
tooltip = tooltip_contents.get(key, {"title": key, "items": []}) | |
tooltip_content = "<br>".join([f"• {item}" for item in tooltip["items"]]) | |
return f''' | |
<span class="tooltip"> | |
<strong>{key}:</strong> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>{tooltip["title"]}:</strong><br> | |
{tooltip_content} | |
</span> | |
</span> {value} | |
''' | |
def format_single_dog_result(breed: str, description: Dict[str, Any], color: str = "#34C759") -> str: | |
"""Format single dog detection result into HTML.""" | |
return f''' | |
<div class="dog-info-card" style="border-left: 8px solid {color};"> | |
<div class="dog-info-header" style="background-color: {color}10;"> | |
<span class="dog-label" style="color: {color};"> | |
<span class="icon">🐾</span> {breed} | |
</span> | |
</div> | |
<div class="breed-info"> | |
<h2 class="section-title"> | |
<span class="icon">📋</span> BASIC INFORMATION | |
</h2> | |
<div class="info-section"> | |
<div class="info-item"> | |
<span class="tooltip tooltip-left"> | |
<span class="icon">📏</span> | |
<span class="label">Size:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Size Categories:</strong><br> | |
• Small: Under 20 pounds<br> | |
• Medium: 20-60 pounds<br> | |
• Large: Over 60 pounds<br> | |
• Giant: Over 100 pounds<br> | |
• Varies: Depends on variety | |
</span> | |
</span> | |
<span class="value">{description['Size']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">⏳</span> | |
<span class="label">Lifespan:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Average Lifespan:</strong><br> | |
• Short: 6-8 years<br> | |
• Average: 10-15 years<br> | |
• Long: 12-20 years<br> | |
• Varies by size: Larger breeds typically have shorter lifespans | |
</span> | |
</span> | |
<span class="value">{description['Lifespan']}</span> | |
</div> | |
</div> | |
<h2 class="section-title"> | |
<span class="icon">🐕</span> TEMPERAMENT & PERSONALITY | |
</h2> | |
<div class="temperament-section"> | |
<span class="tooltip"> | |
<span class="value">{description['Temperament']}</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Temperament Guide:</strong><br> | |
• Describes the dog's natural behavior and personality<br> | |
• Important for matching with owner's lifestyle<br> | |
• Can be influenced by training and socialization | |
</span> | |
</span> | |
</div> | |
<h2 class="section-title"> | |
<span class="icon">💪</span> CARE REQUIREMENTS | |
</h2> | |
<div class="care-section"> | |
<div class="info-item"> | |
<span class="tooltip tooltip-left"> | |
<span class="icon">🏃</span> | |
<span class="label">Exercise:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Exercise Needs:</strong><br> | |
• Low: Short walks and play sessions<br> | |
• Moderate: 1-2 hours of daily activity<br> | |
• High: Extensive exercise (2+ hours/day)<br> | |
• Very High: Constant activity and mental stimulation needed | |
</span> | |
</span> | |
<span class="value">{description['Exercise Needs']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">✂️</span> | |
<span class="label">Grooming:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Grooming Requirements:</strong><br> | |
• Low: Basic brushing, occasional baths<br> | |
• Moderate: Weekly brushing, occasional grooming<br> | |
• High: Daily brushing, frequent professional grooming needed<br> | |
• Professional care recommended for all levels | |
</span> | |
</span> | |
<span class="value">{description['Grooming Needs']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">⭐</span> | |
<span class="label">Care Level:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Care Level Explained:</strong><br> | |
• Low: Basic care and attention needed<br> | |
• Moderate: Regular care and routine needed<br> | |
• High: Significant time and attention needed<br> | |
• Very High: Extensive care, training and attention required | |
</span> | |
</span> | |
<span class="value">{description['Care Level']}</span> | |
</div> | |
</div> | |
<h2 class="section-title"> | |
<span class="icon">👨👩👧👦</span> FAMILY COMPATIBILITY | |
</h2> | |
<div class="family-section"> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon"></span> | |
<span class="label">Good with Children:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Child Compatibility:</strong><br> | |
• Yes: Excellent with kids, patient and gentle<br> | |
• Moderate: Good with older children<br> | |
• No: Better suited for adult households | |
</span> | |
</span> | |
<span class="value">{description['Good with Children']}</span> | |
</div> | |
</div> | |
<h2 class="section-title"> | |
<span class="icon">📝</span> | |
<span class="tooltip"> | |
DESCRIPTION | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>About This Description:</strong><br> | |
• Comprehensive breed overview<br> | |
• Personality and characteristics<br> | |
• Historical background<br> | |
• Typical behaviors and traits | |
</span> | |
</span> | |
</h2> | |
<div class="description-section"> | |
<p>{description.get('Description', '')}</p> | |
</div> | |
<div class="action-section"> | |
<a href="{get_akc_breeds_link(breed)}" target="_blank" class="akc-button"> | |
<span class="icon">🌐</span> | |
Learn more about {breed} on AKC website | |
</a> | |
</div> | |
</div> | |
</div> | |
''' | |
def format_multiple_breeds_result( | |
topk_breeds: List[str], | |
relative_probs: List[str], | |
color: str, | |
index: int, | |
get_dog_description: Callable | |
) -> str: | |
"""Format multiple breed predictions into HTML with complete information.""" | |
result = f''' | |
<div class="dog-info-card" style="border-left: 8px solid {color};"> | |
<div class="dog-info-header" style="background-color: {color}10;"> | |
<span class="dog-label" style="color: {color};">Dog {index+1}</span> | |
</div> | |
<div class="breed-info"> | |
<div class="model-uncertainty-note"> | |
<span class="icon">ℹ️</span> | |
Note: The model is showing some uncertainty in its predictions. | |
Here are the most likely breeds based on the available visual features. | |
</div> | |
<div class="breeds-list"> | |
''' | |
for j, (breed, prob) in enumerate(zip(topk_breeds, relative_probs)): | |
description = get_dog_description(breed) | |
result += f''' | |
<div class="breed-option uncertainty-mode"> | |
<div class="breed-header" style="background-color: {color}10;"> | |
<span class="option-number">Option {j+1}</span> | |
<span class="breed-name">{breed}</span> | |
<span class="confidence-badge" style="background-color: {color}20; color: {color};"> | |
Confidence: {prob} | |
</span> | |
</div> | |
<div class="breed-content"> | |
<div class="breed-info"> | |
<!-- BASIC INFORMATION --> | |
<h2 class="section-title"> | |
<span class="icon">📋</span> BASIC INFORMATION | |
</h2> | |
<div class="info-section"> | |
<div class="info-item"> | |
<span class="tooltip tooltip-left"> | |
<span class="icon">📏</span> | |
<span class="label">Size:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Size Categories:</strong><br> | |
• Small: Under 20 pounds<br> | |
• Medium: 20-60 pounds<br> | |
• Large: Over 60 pounds<br> | |
• Giant: Over 100 pounds<br> | |
• Varies: Depends on variety | |
</span> | |
</span> | |
<span class="value">{description['Size']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">⏳</span> | |
<span class="label">Lifespan:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Average Lifespan:</strong><br> | |
• Short: 6-8 years<br> | |
• Average: 10-15 years<br> | |
• Long: 12-20 years<br> | |
• Varies by size: Larger breeds typically have shorter lifespans | |
</span> | |
</span> | |
<span class="value">{description['Lifespan']}</span> | |
</div> | |
</div> | |
<!-- TEMPERAMENT & PERSONALITY --> | |
<h2 class="section-title"> | |
<span class="icon">🐕</span> TEMPERAMENT & PERSONALITY | |
</h2> | |
<div class="temperament-section"> | |
<span class="tooltip"> | |
<span class="value">{description['Temperament']}</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Temperament Guide:</strong><br> | |
• Describes the dog's natural behavior and personality<br> | |
• Important for matching with owner's lifestyle<br> | |
• Can be influenced by training and socialization | |
</span> | |
</span> | |
</div> | |
<!-- CARE REQUIREMENTS --> | |
<h2 class="section-title"> | |
<span class="icon">💪</span> CARE REQUIREMENTS | |
</h2> | |
<div class="care-section"> | |
<div class="info-item"> | |
<span class="tooltip tooltip-left"> | |
<span class="icon">🏃</span> | |
<span class="label">Exercise:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Exercise Needs:</strong><br> | |
• Low: Short walks and play sessions<br> | |
• Moderate: 1-2 hours of daily activity<br> | |
• High: Extensive exercise (2+ hours/day)<br> | |
• Very High: Constant activity and mental stimulation needed | |
</span> | |
</span> | |
<span class="value">{description['Exercise Needs']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">✂️</span> | |
<span class="label">Grooming:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Grooming Requirements:</strong><br> | |
• Low: Basic brushing, occasional baths<br> | |
• Moderate: Weekly brushing, occasional grooming<br> | |
• High: Daily brushing, frequent professional grooming needed<br> | |
• Professional care recommended for all levels | |
</span> | |
</span> | |
<span class="value">{description['Grooming Needs']}</span> | |
</div> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon">⭐</span> | |
<span class="label">Care Level:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Care Level Explained:</strong><br> | |
• Low: Basic care and attention needed<br> | |
• Moderate: Regular care and routine needed<br> | |
• High: Significant time and attention needed<br> | |
• Very High: Extensive care, training and attention required | |
</span> | |
</span> | |
<span class="value">{description['Care Level']}</span> | |
</div> | |
</div> | |
<!-- FAMILY COMPATIBILITY --> | |
<h2 class="section-title"> | |
<span class="icon">👨👩👧👦</span> FAMILY COMPATIBILITY | |
</h2> | |
<div class="family-section"> | |
<div class="info-item"> | |
<span class="tooltip"> | |
<span class="icon"></span> | |
<span class="label">Good with Children:</span> | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>Child Compatibility:</strong><br> | |
• Yes: Excellent with kids, patient and gentle<br> | |
• Moderate: Good with older children<br> | |
• No: Better suited for adult households | |
</span> | |
</span> | |
<span class="value">{description['Good with Children']}</span> | |
</div> | |
</div> | |
<!-- DESCRIPTION --> | |
<h2 class="section-title"> | |
<span class="icon">📝</span> | |
<span class="tooltip"> | |
DESCRIPTION | |
<span class="tooltip-icon">ⓘ</span> | |
<span class="tooltip-text"> | |
<strong>About This Description:</strong><br> | |
• Comprehensive breed overview<br> | |
• Personality and characteristics<br> | |
• Historical background<br> | |
• Typical behaviors and traits | |
</span> | |
</span> | |
</h2> | |
<div class="description-section"> | |
<p>{description.get('Description', '')}</p> | |
</div> | |
<!-- ACTION SECTION --> | |
<div class="action-section"> | |
<a href="{get_akc_breeds_link(breed)}" target="_blank" class="akc-button"> | |
<span class="icon">🌐</span> | |
Learn more about {breed} on AKC website | |
</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
''' | |
result += '</div></div></div>' | |
return result | |
def format_multi_dog_container(dogs_info: str) -> str: | |
"""Wrap multiple dog detection results in a container.""" | |
return f""" | |
<div class="dog-info-card"> | |
{dogs_info} | |
</div> | |
""" | |
def format_breed_details_html(description: Dict[str, Any], breed: str) -> str: | |
"""Format breed details for the show_details_html function.""" | |
return f""" | |
<div class="dog-info"> | |
<h2>{breed}</h2> | |
<div class="breed-details"> | |
{format_description_html(description, breed)} | |
<div class="action-section"> | |
<a href="{get_akc_breeds_link(breed)}" target="_blank" class="akc-button"> | |
<span class="icon">🌐</span> | |
Learn more about {breed} on AKC website | |
</a> | |
</div> | |
</div> | |
</div> | |
""" | |
def format_comparison_result(breed1: str, breed2: str, comparison_data: Dict) -> str: | |
"""Format breed comparison results into HTML.""" | |
return f""" | |
<div class="comparison-container"> | |
<div class="comparison-header"> | |
<h3>Comparison: {breed1} vs {breed2}</h3> | |
</div> | |
<div class="comparison-content"> | |
<div class="breed-column"> | |
<h4>{breed1}</h4> | |
{format_comparison_details(comparison_data[breed1])} | |
</div> | |
<div class="breed-column"> | |
<h4>{breed2}</h4> | |
{format_comparison_details(comparison_data[breed2])} | |
</div> | |
</div> | |
</div> | |
""" | |
def format_comparison_details(breed_data: Dict) -> str: | |
"""Format individual breed details for comparison.""" | |
original_data = breed_data.get('Original_Data', {}) | |
return f""" | |
<div class="comparison-details"> | |
<p><strong>Size:</strong> {original_data.get('Size', 'N/A')}</p> | |
<p><strong>Exercise Needs:</strong> {original_data.get('Exercise Needs', 'N/A')}</p> | |
<p><strong>Care Level:</strong> {original_data.get('Care Level', 'N/A')}</p> | |
<p><strong>Grooming Needs:</strong> {original_data.get('Grooming Needs', 'N/A')}</p> | |
<p><strong>Good with Children:</strong> {original_data.get('Good with Children', 'N/A')}</p> | |
<p><strong>Temperament:</strong> {original_data.get('Temperament', 'N/A')}</p> | |
</div> | |
""" | |
def format_header_html() -> str: | |
"""Format the application header HTML.""" | |
return """ | |
<header style='text-align: center; padding: 20px; margin-bottom: 20px;'> | |
<h1 style='font-size: 2.5em; margin-bottom: 10px; color: #2D3748;'> | |
🐾 PawMatch AI | |
</h1> | |
<h2 style='font-size: 1.2em; font-weight: normal; color: #4A5568; margin-top: 5px;'> | |
Your Smart Dog Breed Guide | |
</h2> | |
<div style='width: 50px; height: 3px; background: linear-gradient(90deg, #4299e1, #48bb78); margin: 15px auto;'></div> | |
<p style='color: #718096; font-size: 0.9em;'> | |
Powered by AI • Breed Recognition • Smart Matching • Companion Guide | |
</p> | |
</header> | |
""" | |