I’ve reviewed the error and found that it stems from the missing import of AppliedUndef in your code. In SymPy, AppliedUndef lives in the sympy.core.function module. You can resolve the NameError by importing it before referencing it in your node_to_spelling dictionary. Here is a corrected example of how to structure the relevant code:


import logging
from latex2sympy import latex2sympy
from sympy import Add, Mul, Pow, sin, cos, tan, sqrt, log, exp, Integral, Derivative, Sum
from sympy.core.function import AppliedUndef  # <-- import the missing class

# Define how each node type or function should be spelled out
node_to_spelling = {
    Add: 'plus',
    Mul: 'times',
    Pow: 'to the power of',
    AppliedUndef: 'applied to',  # now resolved

    # Functions (common ones)
    sin: 'sine of',
    cos: 'cosine of',
    tan: 'tangent of',
    sqrt: 'square root of',
    log: 'logarithm of',
    exp: 'exponential of',
    Integral: 'the integral of',
    Sum: 'the summation of',
    Derivative: 'the derivative of',
}

def parse_math_expression(latex_math_string):
    """
    Parses a LaTeX mathematical string into a SymPy expression.
    """
    if not isinstance(latex_math_string, str) or not latex_math_string.strip():
        logging.warning("Received invalid or empty input for parsing.")
        return None

    logging.info(f"Attempting to parse LaTeX math string: '{latex_math_string[:100]}...'")

    try:
        return latex2sympy(latex_math_string)
    except Exception as e:
        logging.error(f"Error during parsing: {e}")
        return None

def spell_out_sympy_expression(expr):
    """
    Recursively spells out a SymPy expression into words.
    """
    from sympy import Symbol, Number, Function

    # Base cases
    if expr.is_Number:
        return str(expr)
    if expr.is_Symbol:
        return str(expr)
    if isinstance(expr, Number):
        return str(expr)

    # Operators and functions
    if isinstance(expr, Add):
        return ' plus '.join(spell_out_sympy_expression(arg) for arg in expr.args)
    if isinstance(expr, Mul):
        return ' times '.join(spell_out_sympy_expression(arg) for arg in expr.args)
    if isinstance(expr, Pow):
        base, exponent = expr.args
        return f"{spell_out_sympy_expression(base)} to the power of {spell_out_sympy_expression(exponent)}"
    if isinstance(expr, Function):
        func_type = type(expr)
        func_name = node_to_spelling.get(func_type, func_type.__name__)
        args_spelled = ' and '.join(spell_out_sympy_expression(arg) for arg in expr.args)
        return f"{func_name} {args_spelled}"

    return str(expr)

# Example usage
latex_math = r"\frac{-b \pm \sqrt{b^2-4ac}}{2a}"
sympy_expr = parse_math_expression(latex_math)
if sympy_expr:
    print(spell_out_sympy_expression(sympy_expr))

By adding from sympy.core.function import AppliedUndef, the NameError will be resolved. You can integrate this corrected import into your existing script so the node_to_spelling dictionary recognizes AppliedUndef correctly.