File size: 5,494 Bytes
9e50ae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2fb5cb5
9e50ae2
2fb5cb5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e50ae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""Confidence calculation and visualization utilities.

Provides normalized softmax confidence and color-coded badges"""
from typing import Tuple, List
import numpy as np
import torch
import torch.nn.functional as F


def calculate_softmax_confidence(logits: torch.Tensor) -> Tuple[np.ndarray, float, str, str]:
    """Calculate normalized confidence using softmax

    Args:

        logits: Raw model logits tensor

    Returns:

        Tuple of (probabilities, max_confidence, confidence_level, confidence_emoji)

    """
    # ===Apply softmax to get probabilities===
    probs_np = F.softmax(logits, dim=1).cpu().numpy().flatten()

    # ===Get maximum probability as confidence===
    max_confidence = float(np.max(probs_np))

    # ===Determine confidence level and emoji===
    if max_confidence >= 0.80:
        confidence_level = "HIGH"
        confidence_emoji = "🟒"
    elif max_confidence >= 0.60:
        confidence_level = "MEDIUM"
        confidence_emoji = "🟑"
    else:
        confidence_level = "LOW"
        confidence_emoji = "πŸ”΄"

    return probs_np, max_confidence, confidence_level, confidence_emoji


def get_confidence_badge(confidence: float) -> Tuple[str, str]:
    """Get confidence badge emoji and level description

    Args:

        confidence: Confidence value (0-1)

    Returns:

        Tuple of (emoji, level)

    """
    if confidence >= 0.80:
        return "🟒", "HIGH"
    elif confidence >= 0.60:
        return "🟑", "MEDIUM"
    else:
        return "πŸ”΄", "LOW"


def format_confidence_display(confidence: float, level: str, emoji: str) -> str:
    """

    Format confidence for display in UI



    Args:

        confidence: Confidence value (0-1)

        level: Confidence level (HIGH/MEDIUM/LOW)

        emoji: Confidence emoji



    Returns:

        Formatted confidence string

    """
    return f"{emoji} **{level}** ({confidence:.1%})"


def create_confidence_progress_html(

    probabilities: np.ndarray,

    labels: List[str],

    highlight_idx: int

) -> str:
    """

    Create HTML for confidence progress bars



    Args:

        probabilities: Array of class probabilities

        labels: List of class labels

        highlight_idx: Index of predicted class to highlight



    Returns:

        HTML string for progress bars

    """
    if len(probabilities) == 0 or len(labels) == 0:
        return "<p>No confidence data available</p>"

    html_parts = []

    for i, (prob, label) in enumerate(zip(probabilities, labels)):
        # ===Color based on whether this is the predicted class===
        if i == highlight_idx:
            if prob >= 0.80:
                color = "#22c55e"  # green-500
                text_color = "#ffffff"
            elif prob >= 0.60:
                color = "#eab308"  # yellow-500
                text_color = "#000000"
            else:
                color = "#ef4444"  # red-500
                text_color = "#ffffff"
        else:
            color = "#e5e7eb"  # gray-200
            text_color = "#6b7280"  # gray-500

        percentage = prob * 100

        html_parts.append(f"""

        <div style="margin-bottom: 8px;">

            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">

                <span style="font-size: 0.875rem; font-weight: 500; color: #374151;">{label}</span>

                <span style="font-size: 0.875rem; color: #6b7280;">{percentage:.1f}%</span>

            </div>

            <div style="width: 100%; background-color: #f3f4f6; border-radius: 0.375rem; height: 20px; overflow: hidden;">

                <div style="

                    width: {percentage}%; 

                    height: 100%; 

                    background-color: {color}; 

                    display: flex; 

                    align-items: center; 

                    justify-content: center;

                    transition: width 0.3s ease;

                ">

                    {f'<span style="color: {text_color}; font-size: 0.75rem; font-weight: 600;">{percentage:.1f}%</span>' if percentage > 20 else ''}

                </div>

            </div>

        </div>

        """)

    return f""" 

    <div style="padding: 16px; background-color: #f9fafb; border-radius: 0.5rem; border: 1px solid #e5e7eb;">

        <h4 style="margin: 0 0 12px 0; font-size: 1rem; color: #374151;">Confidence Breakdown</h4>

        {''.join(html_parts)}

    </div>

    """


def calculate_legacy_confidence(logits_list: List[float]) -> Tuple[float, str, str]:
    """

    Calculate confidence using legacy logit margin method for backward compatibility



    Args:

        logits_list: List of raw logits



    Returns:

        Tuple of (margin, confidence_level, confidence_emoji)

    """
    if len(logits_list) < 2:
        return 0.0, "LOW", "πŸ”΄"

    logits_array = np.array(logits_list)
    sorted_logits = np.sort(logits_array)[::-1]  # Descending order
    margin = sorted_logits[0] - sorted_logits[1]

    # ===Define thresholds for margin-based confidence===
    if margin >= 2.0:
        confidence_level = "HIGH"
        confidence_emoji = "🟒"
    elif margin >= 1.0:
        confidence_level = "MEDIUM"
        confidence_emoji = "🟑"
    else:
        confidence_level = "LOW"
        confidence_emoji = "πŸ”΄"

    return margin, confidence_level, confidence_emoji