""" Error Span with Typed Severity Layout Mark error spans in text, assign each an error type from a configurable taxonomy and a severity level. Computes an overall quality score. This is the MQM (Multidimensional Quality Metrics) annotation workflow. Research: Lommel et al. "Multidimensional Quality Metrics" (themqm.org); WMT 2024 ESA. """ import json import logging from .identifier_utils import ( safe_generate_layout, generate_element_identifier, generate_validation_attribute, escape_html_content, generate_layout_attributes ) logger = logging.getLogger(__name__) DEFAULT_SEVERITIES = [ {"name": "Minor", "weight": -1}, {"name": "Major", "weight": -5}, {"name": "Critical", "weight": -10}, ] DEFAULT_MAX_SCORE = 100 def generate_error_span_layout(annotation_scheme): """ Generate HTML for an Error Span with Typed Severity interface. Args: annotation_scheme (dict): Configuration including: - name: Schema identifier - description: Display description - error_types: List of {name, subtypes?} dicts - severities: List of {name, weight} dicts - show_score: Whether to show quality score - max_score: Maximum quality score Returns: tuple: (html_string, key_bindings) """ return safe_generate_layout(annotation_scheme, _generate_error_span_layout_internal) def _generate_error_span_layout_internal(annotation_scheme): schema_name = annotation_scheme['name'] description = annotation_scheme['description'] error_types = annotation_scheme.get('error_types', []) severities = annotation_scheme.get('severities', DEFAULT_SEVERITIES) show_score = annotation_scheme.get('show_score', True) max_score = annotation_scheme.get('max_score', DEFAULT_MAX_SCORE) if not error_types: raise ValueError(f"error_span schema '{schema_name}' requires 'error_types'") layout_attrs = generate_layout_attributes(annotation_scheme) validation = generate_validation_attribute(annotation_scheme) identifiers = generate_element_identifier(schema_name, schema_name, "hidden") # Serialize config for JS config_json = json.dumps({ 'error_types': error_types, 'severities': severities, 'max_score': max_score, 'show_score': show_score, }) # Build error type options HTML for the popup type_options = "" for et in error_types: subtypes = et.get('subtypes', []) if subtypes: type_options += f'' else: type_options += f'' # Build severity radio buttons for the popup severity_radios = "" for sev in severities: severity_radios += f""" """ score_display = "" if show_score: score_display = f"""