Fredrik Sitje commited on
Commit
47ec288
·
1 Parent(s): abc33c8

Include tooltips to the answers.

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +88 -0
src/streamlit_app.py CHANGED
@@ -75,10 +75,95 @@ ASSESSMENT_TO_SCORE = {
75
  "Irrelevant / NA": "NA"
76
  }
77
 
 
 
 
 
 
 
 
 
 
78
  def format_snake_case(text):
79
  """Convert snake_case to Title Case"""
80
  return ' '.join(word.capitalize() for word in text.split('_'))
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  def hash_password(password):
83
  """Hash a password using SHA256"""
84
  return hashlib.sha256(password.encode()).hexdigest()
@@ -762,6 +847,9 @@ elif st.session_state.logged_in:
762
  changes_info = [] # Store info about changes for display
763
  selected_values = {} # Store all selected values for validation
764
 
 
 
 
765
  for i, subcat in enumerate(category.subcategories):
766
  st.markdown(f"**Subcategory: {subcat.formatted_name}**")
767
 
 
75
  "Irrelevant / NA": "NA"
76
  }
77
 
78
+ # Score explanations from annotation guide
79
+ SCORE_EXPLANATIONS = {
80
+ "Perfect": "Only when truly flawless. The answer is legally accurate, well-stated, and appropriate for legal education. It correctly explains the legal principle, rule, or concept without any discernible errors or misleading statements.",
81
+ "Mostly correct": "One very small issue or slightly awkward phrasing. The answer is generally accurate but contains minor inaccuracies, imprecise language, or could be more precise. The core legal content is correct, but there are small issues that could be improved for educational purposes.",
82
+ "Noticeably flawed": "Clear error but main idea still ok. The answer contains significant errors that substantially affect its accuracy. While not completely wrong, there are important mistakes in legal reasoning, application of law, or factual statements that would confuse or mislead students.",
83
+ "Seriously wrong": "Hallucination, wrong format, meaningless, etc. The answer contains fundamental legal errors that completely misrepresent the law, legal principle, or legal concept. The answer would mislead a student and is factually wrong at its core.",
84
+ "Irrelevant / NA": "The answer explicitly indicates that the information is unknown, unavailable, or not relevant to the question. This is appropriate when the AI correctly identifies that it cannot provide an answer."
85
+ }
86
+
87
  def format_snake_case(text):
88
  """Convert snake_case to Title Case"""
89
  return ' '.join(word.capitalize() for word in text.split('_'))
90
 
91
+ def inject_tooltip_css():
92
+ """Inject CSS and JavaScript to add tooltips to radio button labels"""
93
+ tooltip_css_js = f"""
94
+ <style>
95
+ /* Tooltip container */
96
+ .stRadio > div > label {{
97
+ position: relative;
98
+ cursor: help;
99
+ }}
100
+
101
+ /* Tooltip text */
102
+ .stRadio > div > label[data-tooltip]:hover::after {{
103
+ content: attr(data-tooltip);
104
+ position: absolute;
105
+ left: 100%;
106
+ top: 50%;
107
+ transform: translateY(-50%);
108
+ margin-left: 10px;
109
+ padding: 8px 12px;
110
+ background-color: #333;
111
+ color: #fff;
112
+ border-radius: 4px;
113
+ white-space: normal;
114
+ width: 300px;
115
+ z-index: 1000;
116
+ font-size: 12px;
117
+ line-height: 1.4;
118
+ box-shadow: 0 2px 8px rgba(0,0,0,0.2);
119
+ pointer-events: none;
120
+ }}
121
+
122
+ /* Tooltip arrow */
123
+ .stRadio > div > label[data-tooltip]:hover::before {{
124
+ content: '';
125
+ position: absolute;
126
+ left: 100%;
127
+ top: 50%;
128
+ transform: translateY(-50%);
129
+ margin-left: 4px;
130
+ border: 6px solid transparent;
131
+ border-right-color: #333;
132
+ z-index: 1001;
133
+ pointer-events: none;
134
+ }}
135
+ </style>
136
+ <script>
137
+ (function() {{
138
+ // Wait for Streamlit to render radio buttons
139
+ function addTooltips() {{
140
+ const scoreExplanations = {json.dumps(SCORE_EXPLANATIONS)};
141
+ const radioLabels = document.querySelectorAll('.stRadio > div > label');
142
+
143
+ radioLabels.forEach(label => {{
144
+ const labelText = label.textContent.trim();
145
+ if (scoreExplanations[labelText]) {{
146
+ label.setAttribute('data-tooltip', scoreExplanations[labelText]);
147
+ label.style.cursor = 'help';
148
+ }}
149
+ }});
150
+ }}
151
+
152
+ // Run on page load
153
+ if (document.readyState === 'loading') {{
154
+ document.addEventListener('DOMContentLoaded', addTooltips);
155
+ }} else {{
156
+ addTooltips();
157
+ }}
158
+
159
+ // Also run after Streamlit reruns (using MutationObserver)
160
+ const observer = new MutationObserver(addTooltips);
161
+ observer.observe(document.body, {{ childList: true, subtree: true }});
162
+ }})();
163
+ </script>
164
+ """
165
+ st.markdown(tooltip_css_js, unsafe_allow_html=True)
166
+
167
  def hash_password(password):
168
  """Hash a password using SHA256"""
169
  return hashlib.sha256(password.encode()).hexdigest()
 
847
  changes_info = [] # Store info about changes for display
848
  selected_values = {} # Store all selected values for validation
849
 
850
+ # Inject tooltip CSS and JavaScript for score explanations
851
+ inject_tooltip_css()
852
+
853
  for i, subcat in enumerate(category.subcategories):
854
  st.markdown(f"**Subcategory: {subcat.formatted_name}**")
855