import markdown from pygments.formatters import HtmlFormatter import re import hashlib # def format_latex(text): # """ # Convert a Markdown string containing LaTeX formulas to HTML with MathML. # Handles: # - Inline math: $...$ or \( ... \) # - Display math: $$...$$ or \[ ... \] # Automatically converts `aligned` to `array` and wraps display formulas # in for spacing without breaking Markdown lists. # Args: # text (str): Markdown string with LaTeX. # convert (callable): Function that converts LaTeX string to MathML. # Returns: # str: HTML string with MathML replacing LaTeX. # """ # # Pattern for LaTeX delimiters # pattern = r'(\$\$.*?\$\$|\\\[.*?\\\]|\\\(.*?\\\)|\$.*?\$)' # def replace_latex(match): # latex_text = match.group() # # Determine delimiter type # is_display = False # if latex_text.startswith('$$') and latex_text.endswith('$$'): # latex_text_clean = latex_text[2:-2].strip() # is_display = True # elif latex_text.startswith(r'\[') and latex_text.endswith(r'\]'): # latex_text_clean = latex_text[2:-2].strip() # is_display = True # elif latex_text.startswith(r'\(') and latex_text.endswith(r'\)'): # latex_text_clean = latex_text[2:-2].strip() # elif latex_text.startswith('$') and latex_text.endswith('$'): # latex_text_clean = latex_text[1:-1].strip() # else: # latex_text_clean = latex_text.strip() # # Replace aligned -> array # latex_text_clean = re.sub( # r'\\begin\{aligned\}', r'\\begin{array}{l}', latex_text_clean # ) # latex_text_clean = re.sub( # r'\\end\{aligned\}', r'\\end{array}', latex_text_clean # ) # # Convert to MathML # try: # mathml = convert(latex_text_clean) # if is_display: # # Use span with display:block to preserve Markdown list numbering # mathml = f'{mathml}' # return mathml # except Exception as e: # print(f"Warning: failed to convert LaTeX: {latex_text_clean}\nError: {e}") # return latex_text_clean # # Replace all LaTeX with MathML # html_with_mathml = re.sub(pattern, replace_latex, text, flags=re.DOTALL) # return html_with_mathml def normalize_list_formatting(text): # Normalize indentation for nested lists and add spacing lines = text.split('\n') result = [] for i, line in enumerate(lines): # Skip empty lines if not line.strip(): result.append(line) continue # Check if this is a top-level list item (no leading spaces) is_top_level_list = re.match(r'^(\d+\.|[-*])\s+', line) # Check if this is a nested list item (indented with any amount of spaces) nested_match = re.match(r'^( +)([-*]|\d+\.)\s+', line) # Add blank line before top-level list items if previous line exists and isn't blank if is_top_level_list and i > 0 and lines[i-1].strip() != '': result.append('') # Normalize nested list indentation to 2 spaces per level if nested_match: indent_count = len(nested_match.group(1)) # Convert any indentation to proper 2-space indentation level = max(1, (indent_count + 1) // 2) # Calculate nesting level normalized_indent = ' ' * level # Use 2 spaces per level content = line.lstrip() result.append(normalized_indent + content) else: result.append(line) return '\n'.join(result) def format_history(history): """Format conversation history as HTML with side-by-side responses.""" # Generate Pygments CSS for BOTH light and dark themes light_css = HtmlFormatter(style='default').get_style_defs('.codehilite') dark_css = HtmlFormatter(style='monokai').get_style_defs('.codehilite') html = f'''
''' for turn in history: # User message - escape HTML but preserve line breaks user_msg = turn["user"].replace("&", "&").replace("<", "<").replace(">", ">") html += f'
You: {user_msg}
' # Determine opacity based on highlight opacity_a = "1.0" opacity_b = "1.0" border_a = "2px solid var(--block-border-color)" border_b = "2px solid var(--block-border-color)" if turn["highlight"] == "left": opacity_b = "0.3" border_a = "3px solid #4CAF50" elif turn["highlight"] == "right": opacity_a = "0.3" border_b = "3px solid #4CAF50" elif turn["highlight"] == "random_left_tie" or turn["highlight"] == "random_left_bad": opacity_b = "0.3" border_a = "3px solid #4C50AF" elif turn["highlight"] == "random_right_tie" or turn["highlight"] == "random_right_bad": opacity_a = "0.3" border_b = "3px solid #4C50AF" normalized_a = normalize_list_formatting(turn["response_a"]) response_a_html = markdown.markdown( normalized_a, extensions=['fenced_code', 'tables', 'codehilite', 'sane_lists'], extension_configs={'codehilite': {'guess_lang': True, 'linenums': False}} ) normalized_b = normalize_list_formatting(turn["response_b"]) response_b_html = markdown.markdown( normalized_b, extensions=['fenced_code', 'tables', 'codehilite', 'sane_lists'], extension_configs={'codehilite': {'guess_lang': True, 'linenums': False}} ) # Responses side by side html += f'''
Assistant A
{response_a_html}
Assistant B
{response_b_html}
''' if turn["highlight"] == "random_left_tie": html += '
(Note: you did not specify a preference for either assistant, so in subsequent turns, Assistant A will be used as context).
' elif turn["highlight"] == "random_right_tie": html += '
(Note: you did not specify a preference for either assistant, so in subsequent turns, Assistant B will be used as context).
' elif turn["highlight"] == "random_left_bad": html += '
(Note: even though you thought both assistants were bad, Assistant A will be used as context in subsequent turns).
' elif turn["highlight"] == "random_right_bad": html += '
(Note: even though you though both assistants were bad, Assistant B will be used as context in subsequent turns).
' html += '
' return html