Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -435,6 +435,7 @@ async def predict(image):
|
|
435 |
image = Image.fromarray(image)
|
436 |
|
437 |
dogs = await detect_multiple_dogs(image)
|
|
|
438 |
single_dog_color = '#4A90E2' # ζεηθθ²
|
439 |
color_list = ['#4A90E2', '#34C759', '#007AFF', '#5856D6', '#5AC8FA', '#FFB246', '#9C6ADE']
|
440 |
annotated_image = image.copy()
|
@@ -470,6 +471,7 @@ async def predict(image):
|
|
470 |
top1_prob, topk_breeds, relative_probs = await predict_single_dog(cropped_image)
|
471 |
combined_confidence = detection_confidence * top1_prob
|
472 |
|
|
|
473 |
dogs_info += f'<div class="dog-info-card" style="border-left: 6px solid {color};">'
|
474 |
|
475 |
if combined_confidence < 0.15:
|
@@ -478,7 +480,10 @@ async def predict(image):
|
|
478 |
<span class="dog-label" style="color: {color};">Dog {i+1}</span>
|
479 |
</div>
|
480 |
<div class="breed-info">
|
481 |
-
<p class="warning-message">
|
|
|
|
|
|
|
482 |
</div>
|
483 |
'''
|
484 |
elif top1_prob >= 0.45:
|
@@ -486,46 +491,78 @@ async def predict(image):
|
|
486 |
description = get_dog_description(breed)
|
487 |
dogs_info += f'''
|
488 |
<div class="dog-info-header" style="background-color: {color}10;">
|
489 |
-
<span class="dog-label" style="color: {color};">
|
|
|
|
|
490 |
</div>
|
491 |
<div class="breed-info">
|
492 |
-
<
|
493 |
-
<
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
|
|
499 |
</div>
|
500 |
-
|
501 |
-
|
502 |
-
<
|
503 |
-
<
|
504 |
</div>
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
513 |
</div>
|
514 |
-
|
515 |
-
|
516 |
-
<
|
517 |
-
<
|
518 |
-
<span class="info-item"><strong>Good with Children:</strong> {description['Good with Children']}</span>
|
519 |
-
</div>
|
520 |
</div>
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
525 |
</div>
|
526 |
</div>
|
527 |
-
|
528 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
529 |
</div>
|
530 |
</div>
|
531 |
'''
|
@@ -536,23 +573,30 @@ async def predict(image):
|
|
536 |
</div>
|
537 |
<div class="breed-info">
|
538 |
<div class="model-uncertainty-note">
|
|
|
539 |
Note: The model is showing some uncertainty in its predictions.
|
540 |
Here are the most likely breeds based on the available visual features.
|
541 |
</div>
|
542 |
-
<
|
543 |
'''
|
544 |
|
545 |
for j, (breed, prob) in enumerate(zip(topk_breeds, relative_probs)):
|
546 |
description = get_dog_description(breed)
|
547 |
dogs_info += f'''
|
548 |
-
<div class="breed-
|
549 |
-
<div class="
|
550 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
551 |
{format_description_html(description, breed)}
|
552 |
</div>
|
553 |
</div>
|
554 |
'''
|
555 |
-
dogs_info += '</div>'
|
556 |
|
557 |
dogs_info += '</div>'
|
558 |
|
@@ -566,6 +610,7 @@ async def predict(image):
|
|
566 |
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
|
567 |
overflow: hidden;
|
568 |
transition: all 0.3s ease;
|
|
|
569 |
}}
|
570 |
|
571 |
.dog-info-card:hover {{
|
@@ -585,59 +630,109 @@ async def predict(image):
|
|
585 |
line-height: 1.6;
|
586 |
}}
|
587 |
|
588 |
-
.
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
margin-bottom: 12px;
|
596 |
-
font-weight: 600;
|
597 |
text-transform: uppercase;
|
598 |
letter-spacing: 0.5px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
599 |
}}
|
600 |
|
601 |
-
.
|
602 |
display: flex;
|
603 |
flex-wrap: wrap;
|
604 |
gap: 16px;
|
|
|
605 |
}}
|
606 |
|
607 |
.info-item {{
|
608 |
background: #f8f9fa;
|
609 |
-
padding:
|
610 |
-
border-radius:
|
611 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
612 |
}}
|
613 |
|
614 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
615 |
font-style: italic;
|
616 |
color: #444;
|
617 |
}}
|
618 |
|
619 |
-
.description {{
|
|
|
|
|
|
|
|
|
620 |
line-height: 1.8;
|
621 |
color: #444;
|
622 |
}}
|
623 |
|
624 |
-
.
|
625 |
margin-top: 24px;
|
626 |
-
|
627 |
-
border-top: 1px solid #e1e4e8;
|
628 |
}}
|
629 |
|
630 |
-
.akc-
|
631 |
-
|
|
|
|
|
|
|
|
|
|
|
632 |
text-decoration: none;
|
633 |
-
|
|
|
634 |
}}
|
635 |
|
636 |
-
.akc-
|
637 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
638 |
}}
|
639 |
|
640 |
.model-uncertainty-note {{
|
|
|
|
|
|
|
641 |
padding: 16px;
|
642 |
background-color: #f8f9fa;
|
643 |
border-left: 4px solid #6c757d;
|
@@ -646,6 +741,67 @@ async def predict(image):
|
|
646 |
font-style: italic;
|
647 |
border-radius: 4px;
|
648 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
649 |
</style>
|
650 |
{dogs_info}
|
651 |
"""
|
@@ -666,6 +822,9 @@ async def predict(image):
|
|
666 |
|
667 |
|
668 |
|
|
|
|
|
|
|
669 |
def show_details_html(choice, previous_output, initial_state):
|
670 |
if not choice:
|
671 |
return previous_output, gr.update(visible=True), initial_state
|
@@ -727,7 +886,7 @@ def format_description_html(description, breed):
|
|
727 |
with gr.Blocks() as iface:
|
728 |
gr.HTML("<h1 style='text-align: center;'>πΆ Dog Breed Classifier π</h1>")
|
729 |
gr.HTML("<p style='text-align: center;'>Upload a picture of a dog, and the model will predict its breed and provide detailed information!</p>")
|
730 |
-
gr.HTML("<p style='text-align: center; color: #666; font-size: 0.9em;'>Note:
|
731 |
|
732 |
|
733 |
with gr.Row():
|
|
|
435 |
image = Image.fromarray(image)
|
436 |
|
437 |
dogs = await detect_multiple_dogs(image)
|
438 |
+
# ζ΄ζεηι‘θ²η΅ε
|
439 |
single_dog_color = '#4A90E2' # ζεηθθ²
|
440 |
color_list = ['#4A90E2', '#34C759', '#007AFF', '#5856D6', '#5AC8FA', '#FFB246', '#9C6ADE']
|
441 |
annotated_image = image.copy()
|
|
|
471 |
top1_prob, topk_breeds, relative_probs = await predict_single_dog(cropped_image)
|
472 |
combined_confidence = detection_confidence * top1_prob
|
473 |
|
474 |
+
# ιε§θ³θ¨ε‘η
|
475 |
dogs_info += f'<div class="dog-info-card" style="border-left: 6px solid {color};">'
|
476 |
|
477 |
if combined_confidence < 0.15:
|
|
|
480 |
<span class="dog-label" style="color: {color};">Dog {i+1}</span>
|
481 |
</div>
|
482 |
<div class="breed-info">
|
483 |
+
<p class="warning-message">
|
484 |
+
<span class="icon">β οΈ</span>
|
485 |
+
The image is unclear or the breed is not in the dataset. Please upload a clearer image.
|
486 |
+
</p>
|
487 |
</div>
|
488 |
'''
|
489 |
elif top1_prob >= 0.45:
|
|
|
491 |
description = get_dog_description(breed)
|
492 |
dogs_info += f'''
|
493 |
<div class="dog-info-header" style="background-color: {color}10;">
|
494 |
+
<span class="dog-label" style="color: {color};">
|
495 |
+
<span class="icon">π</span> {breed}
|
496 |
+
</span>
|
497 |
</div>
|
498 |
<div class="breed-info">
|
499 |
+
<h2 class="section-title">
|
500 |
+
<span class="icon">π</span> BASIC INFORMATION
|
501 |
+
</h2>
|
502 |
+
<div class="info-section">
|
503 |
+
<div class="info-item">
|
504 |
+
<span class="icon">π</span>
|
505 |
+
<span class="label">Size:</span>
|
506 |
+
<span class="value">{description['Size']}</span>
|
507 |
</div>
|
508 |
+
<div class="info-item">
|
509 |
+
<span class="icon">β³</span>
|
510 |
+
<span class="label">Lifespan:</span>
|
511 |
+
<span class="value">{description['Lifespan']}</span>
|
512 |
</div>
|
513 |
+
</div>
|
514 |
+
|
515 |
+
<h2 class="section-title">
|
516 |
+
<span class="icon">π</span> TEMPERAMENT & PERSONALITY
|
517 |
+
</h2>
|
518 |
+
<div class="temperament-section">
|
519 |
+
<span class="value">{description['Temperament']}</span>
|
520 |
+
</div>
|
521 |
+
|
522 |
+
<h2 class="section-title">
|
523 |
+
<span class="icon">πͺ</span> CARE REQUIREMENTS
|
524 |
+
</h2>
|
525 |
+
<div class="care-section">
|
526 |
+
<div class="info-item">
|
527 |
+
<span class="icon">π</span>
|
528 |
+
<span class="label">Exercise:</span>
|
529 |
+
<span class="value">{description['Exercise Needs']}</span>
|
530 |
+
</div>
|
531 |
+
<div class="info-item">
|
532 |
+
<span class="icon">βοΈ</span>
|
533 |
+
<span class="label">Grooming:</span>
|
534 |
+
<span class="value">{description['Grooming Needs']}</span>
|
535 |
</div>
|
536 |
+
<div class="info-item">
|
537 |
+
<span class="icon">β</span>
|
538 |
+
<span class="label">Care Level:</span>
|
539 |
+
<span class="value">{description['Care Level']}</span>
|
|
|
|
|
540 |
</div>
|
541 |
+
</div>
|
542 |
+
|
543 |
+
<h2 class="section-title">
|
544 |
+
<span class="icon">π¨βπ©βπ§βπ¦</span> FAMILY COMPATIBILITY
|
545 |
+
</h2>
|
546 |
+
<div class="family-section">
|
547 |
+
<div class="info-item">
|
548 |
+
<span class="icon">πΆ</span>
|
549 |
+
<span class="label">Good with Children:</span>
|
550 |
+
<span class="value">{description['Good with Children']}</span>
|
551 |
</div>
|
552 |
</div>
|
553 |
+
|
554 |
+
<h2 class="section-title">
|
555 |
+
<span class="icon">π</span> DESCRIPTION
|
556 |
+
</h2>
|
557 |
+
<div class="description-section">
|
558 |
+
<p>{description.get('Description', '')}</p>
|
559 |
+
</div>
|
560 |
+
|
561 |
+
<div class="action-section">
|
562 |
+
<a href="{get_akc_breeds_link(breed)}" target="_blank" class="akc-button">
|
563 |
+
<span class="icon">π</span>
|
564 |
+
Learn more about {breed} on AKC website
|
565 |
+
</a>
|
566 |
</div>
|
567 |
</div>
|
568 |
'''
|
|
|
573 |
</div>
|
574 |
<div class="breed-info">
|
575 |
<div class="model-uncertainty-note">
|
576 |
+
<span class="icon">βΉοΈ</span>
|
577 |
Note: The model is showing some uncertainty in its predictions.
|
578 |
Here are the most likely breeds based on the available visual features.
|
579 |
</div>
|
580 |
+
<div class="breeds-list">
|
581 |
'''
|
582 |
|
583 |
for j, (breed, prob) in enumerate(zip(topk_breeds, relative_probs)):
|
584 |
description = get_dog_description(breed)
|
585 |
dogs_info += f'''
|
586 |
+
<div class="breed-option">
|
587 |
+
<div class="breed-header">
|
588 |
+
<span class="option-number">Option {j+1}</span>
|
589 |
+
<span class="breed-name">{breed}</span>
|
590 |
+
<span class="confidence-badge" style="background-color: {color}20; color: {color};">
|
591 |
+
Confidence: {prob}
|
592 |
+
</span>
|
593 |
+
</div>
|
594 |
+
<div class="breed-content">
|
595 |
{format_description_html(description, breed)}
|
596 |
</div>
|
597 |
</div>
|
598 |
'''
|
599 |
+
dogs_info += '</div></div>'
|
600 |
|
601 |
dogs_info += '</div>'
|
602 |
|
|
|
610 |
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
|
611 |
overflow: hidden;
|
612 |
transition: all 0.3s ease;
|
613 |
+
background: white;
|
614 |
}}
|
615 |
|
616 |
.dog-info-card:hover {{
|
|
|
630 |
line-height: 1.6;
|
631 |
}}
|
632 |
|
633 |
+
.section-title {{
|
634 |
+
font-size: 1.2em;
|
635 |
+
font-weight: 700;
|
636 |
+
color: #2c3e50;
|
637 |
+
margin: 28px 0 16px 0;
|
638 |
+
padding-bottom: 8px;
|
639 |
+
border-bottom: 2px solid #e1e4e8;
|
|
|
|
|
640 |
text-transform: uppercase;
|
641 |
letter-spacing: 0.5px;
|
642 |
+
display: flex;
|
643 |
+
align-items: center;
|
644 |
+
gap: 8px;
|
645 |
+
}}
|
646 |
+
|
647 |
+
.icon {{
|
648 |
+
font-size: 1.2em;
|
649 |
+
display: inline-flex;
|
650 |
+
align-items: center;
|
651 |
+
justify-content: center;
|
652 |
}}
|
653 |
|
654 |
+
.info-section, .care-section, .family-section {{
|
655 |
display: flex;
|
656 |
flex-wrap: wrap;
|
657 |
gap: 16px;
|
658 |
+
margin-bottom: 20px;
|
659 |
}}
|
660 |
|
661 |
.info-item {{
|
662 |
background: #f8f9fa;
|
663 |
+
padding: 12px 16px;
|
664 |
+
border-radius: 8px;
|
665 |
+
display: flex;
|
666 |
+
align-items: center;
|
667 |
+
gap: 8px;
|
668 |
+
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
669 |
+
}}
|
670 |
+
|
671 |
+
.label {{
|
672 |
+
color: #666;
|
673 |
+
font-weight: 600;
|
674 |
}}
|
675 |
|
676 |
+
.value {{
|
677 |
+
color: #2c3e50;
|
678 |
+
}}
|
679 |
+
|
680 |
+
.temperament-section {{
|
681 |
+
background: #f8f9fa;
|
682 |
+
padding: 16px;
|
683 |
+
border-radius: 8px;
|
684 |
+
margin-bottom: 20px;
|
685 |
font-style: italic;
|
686 |
color: #444;
|
687 |
}}
|
688 |
|
689 |
+
.description-section {{
|
690 |
+
background: #f8f9fa;
|
691 |
+
padding: 16px;
|
692 |
+
border-radius: 8px;
|
693 |
+
margin: 20px 0;
|
694 |
line-height: 1.8;
|
695 |
color: #444;
|
696 |
}}
|
697 |
|
698 |
+
.action-section {{
|
699 |
margin-top: 24px;
|
700 |
+
text-align: center;
|
|
|
701 |
}}
|
702 |
|
703 |
+
.akc-button {{
|
704 |
+
display: inline-flex;
|
705 |
+
align-items: center;
|
706 |
+
padding: 12px 24px;
|
707 |
+
background-color: #4A90E2;
|
708 |
+
color: white;
|
709 |
+
border-radius: 8px;
|
710 |
text-decoration: none;
|
711 |
+
gap: 8px;
|
712 |
+
transition: all 0.3s ease;
|
713 |
}}
|
714 |
|
715 |
+
.akc-button:hover {{
|
716 |
+
background-color: #357ABD;
|
717 |
+
transform: translateY(-1px);
|
718 |
+
}}
|
719 |
+
|
720 |
+
.warning-message {{
|
721 |
+
display: flex;
|
722 |
+
align-items: center;
|
723 |
+
gap: 8px;
|
724 |
+
color: #ff3b30;
|
725 |
+
font-weight: 500;
|
726 |
+
margin: 0;
|
727 |
+
padding: 16px;
|
728 |
+
background: #fff5f5;
|
729 |
+
border-radius: 8px;
|
730 |
}}
|
731 |
|
732 |
.model-uncertainty-note {{
|
733 |
+
display: flex;
|
734 |
+
align-items: center;
|
735 |
+
gap: 12px;
|
736 |
padding: 16px;
|
737 |
background-color: #f8f9fa;
|
738 |
border-left: 4px solid #6c757d;
|
|
|
741 |
font-style: italic;
|
742 |
border-radius: 4px;
|
743 |
}}
|
744 |
+
|
745 |
+
.breeds-list {{
|
746 |
+
display: flex;
|
747 |
+
flex-direction: column;
|
748 |
+
gap: 20px;
|
749 |
+
}}
|
750 |
+
|
751 |
+
.breed-option {{
|
752 |
+
background: white;
|
753 |
+
border: 1px solid #e1e4e8;
|
754 |
+
border-radius: 8px;
|
755 |
+
overflow: hidden;
|
756 |
+
}}
|
757 |
+
|
758 |
+
.breed-header {{
|
759 |
+
display: flex;
|
760 |
+
align-items: center;
|
761 |
+
padding: 16px;
|
762 |
+
background: #f8f9fa;
|
763 |
+
gap: 12px;
|
764 |
+
border-bottom: 1px solid #e1e4e8;
|
765 |
+
}}
|
766 |
+
|
767 |
+
.option-number {{
|
768 |
+
font-weight: 600;
|
769 |
+
color: #666;
|
770 |
+
padding: 4px 8px;
|
771 |
+
background: #e1e4e8;
|
772 |
+
border-radius: 4px;
|
773 |
+
}}
|
774 |
+
|
775 |
+
.breed-name {{
|
776 |
+
font-size: 1.1em;
|
777 |
+
font-weight: bold;
|
778 |
+
color: #2c3e50;
|
779 |
+
flex-grow: 1;
|
780 |
+
}}
|
781 |
+
|
782 |
+
.confidence-badge {{
|
783 |
+
padding: 4px 12px;
|
784 |
+
border-radius: 20px;
|
785 |
+
font-size: 0.9em;
|
786 |
+
font-weight: 500;
|
787 |
+
}}
|
788 |
+
|
789 |
+
.breed-content {{
|
790 |
+
padding: 20px;
|
791 |
+
}}
|
792 |
+
|
793 |
+
ul {{
|
794 |
+
padding-left: 0;
|
795 |
+
margin: 0;
|
796 |
+
list-style-type: none;
|
797 |
+
}}
|
798 |
+
|
799 |
+
li {{
|
800 |
+
margin-bottom: 8px;
|
801 |
+
display: flex;
|
802 |
+
align-items: center;
|
803 |
+
gap: 8px;
|
804 |
+
}}
|
805 |
</style>
|
806 |
{dogs_info}
|
807 |
"""
|
|
|
822 |
|
823 |
|
824 |
|
825 |
+
|
826 |
+
|
827 |
+
|
828 |
def show_details_html(choice, previous_output, initial_state):
|
829 |
if not choice:
|
830 |
return previous_output, gr.update(visible=True), initial_state
|
|
|
886 |
with gr.Blocks() as iface:
|
887 |
gr.HTML("<h1 style='text-align: center;'>πΆ Dog Breed Classifier π</h1>")
|
888 |
gr.HTML("<p style='text-align: center;'>Upload a picture of a dog, and the model will predict its breed and provide detailed information!</p>")
|
889 |
+
gr.HTML("<p style='text-align: center; color: #666; font-size: 0.9em;'>Note: The model's predictions may not always be 100% accurate, and it is recommended to use the results as a reference.</p>")
|
890 |
|
891 |
|
892 |
with gr.Row():
|