You are a Python programmer tasked with refactoring code. You are proficient in Python 3.12 and use modern features where appropriate. Your code is clear, easy to read, and free of unnecessary verbosity. You follow PEP 8, 20 and 257 to ensure high quality python code. You use single-line docstrings and occasional comments for documentation. Python 3.12 Code: import math
import re
from typing import Any, Union, Callable

from PySide6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLineEdit, QTextEdit, QScrollBar, QPushButton, QLabel, QFrame,
    QGridLayout
)
from PySide6.QtGui import QFont
from PySide6.QtCore import Qt

# -- Utility Functions --

def convert_angle(func: Callable[[float], float], x: float, use_degrees: bool) -> float:
    """Convert angle based on degree mode."""
    return func(math.radians(x) if use_degrees else x)

# -- Conversions Category --

def kg_to_lb(kg: float) -> float:
    """Convert kilograms to pounds."""
    return kg / 0.45359237

def lb_to_kg(lb: float) -> float:
    """Convert pounds to kilograms."""
    return lb * 0.45359237

# -- Text Category --

def capitalize_sentence(sentence: str) -> str:
    """Capitalize the first letter of each word in the sentence."""
    return ' '.join(word.capitalize() for word in sentence.split())

def remove_duplicates(text: str) -> str:
    """Remove duplicate words and empty lines from a string."""
    words = ' '.join(line.strip() for line in text.splitlines() if line.strip()).split()
    return ' '.join(dict.fromkeys(words))

# -- Processing --

def get_safe_globals(use_degrees: bool) -> dict:
    """Return a dictionary of safe globals for expression evaluation."""
    trig_funcs = {'sin', 'cos', 'tan', 'asin', 'acos', 'atan'}
    safe_globals = {
        "sqrt": math.sqrt,
        "log": math.log10,
        "ln": math.log,
        "pi": math.pi,
        "e": math.e,
        "lb": kg_to_lb,
        "kg": lb_to_kg,
        "capitalize": capitalize_sentence,
        "duplicates": remove_duplicates,
    }
    safe_globals.update({
        func: (lambda f: (lambda x, f=f: convert_angle(getattr(math, f), x, use_degrees)))(func)
        for func in trig_funcs.union({'asin', 'acos'})
    })
    return safe_globals

def preprocess_text_functions(expression: str) -> str:
    """Preprocess text functions to ensure proper quoting of arguments."""
    def add_quotes(match):
        func, args = match.groups()
        return f'{func}("{args}")' if func in ['capitalize', 'duplicates'] else match.group(0)
    return re.sub(r'\b(capitalize|duplicates)\(([^)]+)\)', add_quotes, expression)

def validate_inverse_trig(expression: str, safe_globals: dict) -> Union[str, None]:
    """Validate inputs for inverse trigonometric functions."""
    for func, arg in re.findall(r"(\b\w+\b)\(([^)]+)\)", expression):
        if func in ["asin", "acos"]:
            try:
                value = eval(arg, {"__builtins__": None}, safe_globals)
                if abs(value) > 1:
                    return f"Error: {func}(x) is undefined for |x| > 1"
            except Exception as e:
                return f"Error: {e}"
    return None

def safe_evaluate(expression: str, safe_globals: dict) -> Union[float, str]:
    """Safely evaluate the expression and format the result."""
    try:
        result = eval(expression, {"__builtins__": None}, safe_globals)
        if isinstance(result, float) and abs(result) < 1e-10:
            result = 0.0
        return round(result, 2) if isinstance(result, (int, float)) else result
    except Exception as e:
        return f"Error: {e}"

def evaluate_expression(expression: str, use_degrees: bool = False) -> Union[float, str]:
    """Safely evaluate a mathematical expression considering degree mode."""
    safe_globals = get_safe_globals(use_degrees)
    expression = expression.replace("^", "**")
    expression = preprocess_text_functions(expression)
    error = validate_inverse_trig(expression, safe_globals)
    return error or safe_evaluate(expression, safe_globals)

# -- GUI

class CalculatorGUI(QMainWindow):
    """PySide6-based Calculator with Degrees/Radians toggle and history."""

    def __init__(self):
        super().__init__()
        self.use_degrees = False
        self.setup_window()
        self.create_widgets()
        self.layout_widgets()

    def setup_window(self) -> None:
        """Configure the main application window."""
        self.setWindowTitle("Calculator")
        self.setGeometry(100, 100, 1280, 720)

    def create_widgets(self) -> None:
        """Initialize all GUI components."""
        font = QFont()
        font.setPointSize(12)
        font.setFamily('Literata')
        
        self.entry = QLineEdit()
        self.entry.setFont(font)
        self.entry.returnPressed.connect(self.calculate)
        self.entry.setPlaceholderText('Enter expression')

        self.history_text = QTextEdit()
        self.history_text.setFont(font)
        self.history_text.setReadOnly(True)

        self.scrollbar = QScrollBar(Qt.Vertical)
        self.history_text.setVerticalScrollBar(self.scrollbar)

        self.function_buttons = {
            "Functions": ["sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "log", "ln"],
            "Conversions": ["lb", "kg"],
            "Text": ["capitalize", "duplicates"],
            "Constants": ["pi", "e"]
        }
        self.function_frame = QFrame()
        self.create_function_buttons(font)

    def create_function_buttons(self, font: QFont) -> None:
        """Create buttons for inserting functions into the entry."""
        layout = QGridLayout()
        
        categories = [("Functions", 3), ("Conversions", 2), ("Text", 2), ("Constants", 2), ("Settings", 1)]
        starting_col = 0

        for category, col_span in categories:
            label = QLabel(category)
            label.setFont(font)
            layout.addWidget(label, 0, starting_col, 1, col_span, Qt.AlignCenter)

            buttons = self.function_buttons.get(category, [])
            if category == "Functions":
                for i, func in enumerate(buttons):
                    button = QPushButton(func)
                    button.setFont(font)
                    button.clicked.connect(lambda _, f=func: self.insert_function(f, False))
                    layout.addWidget(button, (i // 3) + 1, starting_col + (i % 3))
            
            elif category == "Settings":
                self.mode_button = QPushButton("Radians")
                self.mode_button.setFont(font)
                self.mode_button.clicked.connect(self.toggle_mode)
                layout.addWidget(self.mode_button, 1, starting_col, 1, 1)
            
            else:
                num_buttons = len(buttons)
                num_rows = math.ceil(num_buttons / col_span)

                for idx, func in enumerate(buttons):
                    button_text = f"{func}({'kg' if func == 'lb' else 'lb'})" if category == "Conversions" else func
                    button = QPushButton(button_text)
                    button.setFont(font)
                    button.clicked.connect(lambda _, f=func, c=(category == "Constants"): self.insert_function(f, c))
                    layout.addWidget(button, 1 + (idx // col_span), starting_col + (idx % col_span))

                for extra in range(col_span * num_rows - num_buttons):
                    layout.addWidget(QLabel(""), 1 + (extra // col_span), starting_col + (extra % col_span))

            starting_col += col_span

        self.function_frame.setLayout(layout)

    def layout_widgets(self) -> None:
        """Arrange widgets within the window."""
        central_widget = QWidget()
        main_layout = QVBoxLayout()
        
        main_layout.addWidget(self.entry)
        
        history_layout = QHBoxLayout()
        history_layout.addWidget(self.history_text)
        history_layout.addWidget(self.scrollbar)
        main_layout.addLayout(history_layout)
        
        main_layout.addWidget(self.function_frame)
        
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

    def toggle_mode(self) -> None:
        """Switch between Degrees and Radians modes."""
        self.use_degrees = not self.use_degrees
        self.mode_button.setText("Degrees" if self.use_degrees else "Radians")

    def insert_function(self, function: str, is_constant: bool = False) -> None:
        """Insert function or constant text into the expression entry."""
        current_text = self.entry.text()
        cursor_position = self.entry.cursorPosition()
        if is_constant:
            new_text = f"{current_text[:cursor_position]}{function}{current_text[cursor_position:]}"
            new_cursor_position = cursor_position + len(function)
        else:
            new_text = f"{current_text[:cursor_position]}{function}() {current_text[cursor_position:]}"
            new_cursor_position = cursor_position + len(function) + 1
        self.entry.setText(new_text)
        self.entry.setCursorPosition(new_cursor_position)
        self.entry.setFocus()

    def calculate(self) -> None:
        """Evaluate the expression and update history."""
        expression = self.entry.text().strip()
        if expression:
            result = evaluate_expression(expression, use_degrees=self.use_degrees)
            self.display_result(expression, result)
            self.entry.clear()

    def display_result(self, expression: str, result: Union[float, str]) -> None:
        """Append the calculation to the history log."""
        mode = "D" if self.use_degrees else "R"
        self.history_text.append(f"[{mode}] {expression} = {result}")
        self.history_text.verticalScrollBar().setValue(
            self.history_text.verticalScrollBar().maximum()
        )

def main() -> None:
    """Run the Calculator application."""  
    app = QApplication([])
    calculator = CalculatorGUI()
    calculator.show()
    app.exec()

if __name__ == "__main__":
    main()