evaluar-app.services.exercise_loader

  1## EXERCISES ROUTES
  2
  3from main import configure_logging
  4import re
  5import os
  6import pandas as pd
  7
  8logger = configure_logging()
  9
 10
 11
 12def preprocess_latex_for_mathjax(latex_content, exercise_id):
 13    """
 14    Preprocesses LaTeX content to make it compatible with MathJax and HTML rendering.
 15    This function performs the following transformations:
 16    - Replaces LaTeX emphasis commands (\emph{}, \textit{}, \textbf{}) with their corresponding HTML tags (<em>, <i>, <strong>).
 17    - Converts LaTeX enumerate environments (\begin{enumerate}, \end{enumerate}) to HTML ordered lists (<ol>, </ol>).
 18    - Converts LaTeX \item commands to HTML list items (<li>).
 19    - Ensures proper closing of list items by replacing consecutive <li> tags with properly formatted ones.
 20    - Converts LaTeX center environments (\begin{center}, \end{center}) to HTML div elements with center alignment.
 21    - Replaces a placeholder ("% FIGURA") with an HTML <img> tag for embedding an image, using the provided exercise ID to generate the image source path.
 22    Args:
 23        latex_content (str): The LaTeX content to preprocess.
 24        exercise_id (str): The ID of the exercise, used to generate the image source path.
 25    Returns:
 26        str: The preprocessed LaTeX content with HTML-compatible formatting.
 27    """
 28    # Reemplaza \emph{} con <em></em>
 29    latex_content = re.sub(r'\\emph\{(.*?)\}', r'<em>\1</em>', latex_content)
 30    
 31    # Reemplaza \textit{} con <i></i>
 32    latex_content = re.sub(r'\\textit\{(.*?)\}', r'<i>\1</i>', latex_content)
 33    
 34    # Reemplaza \textbf{} con <strong></strong>
 35    latex_content = re.sub(r'\\textbf\{(.*?)\}', r'<strong>\1</strong>', latex_content)
 36        
 37    # A robust solution would require actual LaTeX parsing
 38    latex_content = latex_content.replace(r'\begin{enumerate}', '<ol>')
 39    latex_content = latex_content.replace(r'\end{enumerate}', '</ol>')
 40    latex_content = latex_content.replace(r'\item', '<li>')
 41    # Close the list item
 42    latex_content = latex_content.replace(r'</li><li>', '</li>\n<li>')
 43    latex_content = latex_content.replace(r'\begin{center}', '<div style="text-align: center;">').replace(r'\end{center}', '</div>')
 44
 45    # Reemplaza el marcador con la etiqueta img HTML
 46    figure_placeholder = "% FIGURA"
 47    # img_html = f'<img src="/tikzpics/{exercise_id}.png" alt="Figura para el ejercicio {exercise_id}" />'
 48    img_html = f'<img src="/tikzpics/{exercise_id}.png" alt="Figura para el ejercicio {exercise_id}" style="max-width: 80%; height: auto; display: block; margin-left: auto; margin-right: auto;" />'
 49    latex_content = latex_content.replace(figure_placeholder, img_html)
 50
 51    return latex_content
 52
 53
 54
 55def get_exercise_content(filename, course='tda'):
 56    """
 57    Retrieves the content of an exercise file, processes it for rendering, and handles errors gracefully.
 58
 59    Args:
 60        filename (str): The name of the exercise file to be loaded. Expected format is 'ID.tex'.
 61        course (str, optional): The course directory where the exercise file is located. Defaults to 'tda'.
 62
 63    Returns:
 64        str: The processed content of the exercise file if successfully loaded, or an error message if the file
 65        is not found or another error occurs.
 66
 67    Logs:
 68        - Logs an info message when attempting to open the file.
 69        - Logs a debug message upon successfully reading the file content.
 70        - Logs an error message if the file is not found or if an unexpected error occurs.
 71
 72    Notes:
 73        - Assumes the exercise files are stored in a directory structure under 'exercises/{course}'.
 74        - Extracts the exercise ID from the filename by splitting on the '.' character.
 75        - Optionally preprocesses the LaTeX content for MathJax rendering using `preprocess_latex_for_mathjax`.
 76    """
 77    exercises_dir = os.path.join('exercises', course)
 78    filepath = os.path.join(exercises_dir, filename)
 79    logger.info(f"Attempting to open exercise file at path: {filepath}")
 80
 81    try:
 82        with open(filepath, 'r', encoding='utf-8') as file:
 83            content = file.read()
 84            logger.debug(f"Successfully read content from {filename}")
 85
 86            # Extrae el ID del ejercicio del nombre del archivo, asumiendo que el formato es 'ID.tex'
 87            exercise_id = filename.split('.')[0]
 88
 89            # Opcional: Preprocesamiento para el render con MathJax
 90            content = preprocess_latex_for_mathjax(content, exercise_id)
 91            return content
 92    except FileNotFoundError:
 93        logger.error(f"File {filename} not found in directory {exercises_dir}.")
 94        return "Exercise content not found."
 95    except Exception as e:
 96        logger.error(f"Unexpected error while reading {filepath}: {e}")
 97        return "An error occurred while fetching the exercise content."
 98    
 99
100
101def get_filename_from_exercise_id(exercise_id, course='tda'):
102    """
103    Retrieves the filename associated with a given exercise ID for a specific course.
104    Args:
105        exercise_id (int): The ID of the exercise to look up.
106        course (str, optional): The course name. Defaults to 'tda'.
107    Returns:
108        str: The filename corresponding to the given exercise ID.
109    Raises:
110        FileNotFoundError: If the index file for the specified course does not exist.
111        ValueError: If no exercise with the given ID is found in the course index.
112    """
113    index_path = os.path.join('exercises', course, 'index.csv')
114    if not os.path.exists(index_path):
115        raise FileNotFoundError(f"No index file found for course: {course}")
116
117    df = pd.read_csv(index_path)
118    match = df.loc[df['id'] == int(exercise_id), 'file']
119    
120    if match.empty:
121        raise ValueError(f"No exercise found with id {exercise_id} in course {course}")
122    
123    return match.values[0]
124
125
126def get_exercise_id_from_filename(filename, course='tda'):
127    """
128    Retrieves the exercise ID associated with a given filename from the course's index file.
129    Args:
130        filename (str): The name of the exercise file to look up.
131        course (str, optional): The course name to locate the index file. Defaults to 'tda'.
132    Returns:
133        int: The ID of the exercise corresponding to the given filename.
134    Raises:
135        FileNotFoundError: If the index file for the specified course does not exist.
136        ValueError: If no exercise with the given filename is found in the index file.
137    """
138    index_path = os.path.join('exercises', course, 'index.csv')
139    if not os.path.exists(index_path):
140        raise FileNotFoundError(f"No index file found for course: {course}")
141
142    df = pd.read_csv(index_path)
143    match = df.loc[df['file'] == filename, 'id']
144    
145    if match.empty:
146        raise ValueError(f"No exercise found with filename {filename} in course {course}")
147    
148    return match.values[0]
logger = <Logger main (INFO)>
def preprocess_latex_for_mathjax(latex_content, exercise_id):
15def preprocess_latex_for_mathjax(latex_content, exercise_id):
16    """
17    Preprocesses LaTeX content to make it compatible with MathJax and HTML rendering.
18    This function performs the following transformations:
19    - Replaces LaTeX emphasis commands (\emph{}, \textit{}, \textbf{}) with their corresponding HTML tags (<em>, <i>, <strong>).
20    - Converts LaTeX enumerate environments (\begin{enumerate}, \end{enumerate}) to HTML ordered lists (<ol>, </ol>).
21    - Converts LaTeX \item commands to HTML list items (<li>).
22    - Ensures proper closing of list items by replacing consecutive <li> tags with properly formatted ones.
23    - Converts LaTeX center environments (\begin{center}, \end{center}) to HTML div elements with center alignment.
24    - Replaces a placeholder ("% FIGURA") with an HTML <img> tag for embedding an image, using the provided exercise ID to generate the image source path.
25    Args:
26        latex_content (str): The LaTeX content to preprocess.
27        exercise_id (str): The ID of the exercise, used to generate the image source path.
28    Returns:
29        str: The preprocessed LaTeX content with HTML-compatible formatting.
30    """
31    # Reemplaza \emph{} con <em></em>
32    latex_content = re.sub(r'\\emph\{(.*?)\}', r'<em>\1</em>', latex_content)
33    
34    # Reemplaza \textit{} con <i></i>
35    latex_content = re.sub(r'\\textit\{(.*?)\}', r'<i>\1</i>', latex_content)
36    
37    # Reemplaza \textbf{} con <strong></strong>
38    latex_content = re.sub(r'\\textbf\{(.*?)\}', r'<strong>\1</strong>', latex_content)
39        
40    # A robust solution would require actual LaTeX parsing
41    latex_content = latex_content.replace(r'\begin{enumerate}', '<ol>')
42    latex_content = latex_content.replace(r'\end{enumerate}', '</ol>')
43    latex_content = latex_content.replace(r'\item', '<li>')
44    # Close the list item
45    latex_content = latex_content.replace(r'</li><li>', '</li>\n<li>')
46    latex_content = latex_content.replace(r'\begin{center}', '<div style="text-align: center;">').replace(r'\end{center}', '</div>')
47
48    # Reemplaza el marcador con la etiqueta img HTML
49    figure_placeholder = "% FIGURA"
50    # img_html = f'<img src="/tikzpics/{exercise_id}.png" alt="Figura para el ejercicio {exercise_id}" />'
51    img_html = f'<img src="/tikzpics/{exercise_id}.png" alt="Figura para el ejercicio {exercise_id}" style="max-width: 80%; height: auto; display: block; margin-left: auto; margin-right: auto;" />'
52    latex_content = latex_content.replace(figure_placeholder, img_html)
53
54    return latex_content

Preprocesses LaTeX content to make it compatible with MathJax and HTML rendering. This function performs the following transformations:

  • Replaces LaTeX emphasis commands (\emph{}, extit{}, extbf{}) with their corresponding HTML tags (, , ).
  • Converts LaTeX enumerate environments (egin{enumerate}, \end{enumerate}) to HTML ordered lists (
      ,
    ).
  • Converts LaTeX \item commands to HTML list items (
  • ).
  • Ensures proper closing of list items by replacing consecutive
  • tags with properly formatted ones.
  • Converts LaTeX center environments (egin{center}, \end{center}) to HTML div elements with center alignment.
  • Replaces a placeholder ("% FIGURA") with an HTML tag for embedding an image, using the provided exercise ID to generate the image source path. Args: latex_content (str): The LaTeX content to preprocess. exercise_id (str): The ID of the exercise, used to generate the image source path. Returns: str: The preprocessed LaTeX content with HTML-compatible formatting.
def get_exercise_content(filename, course='tda'):
 58def get_exercise_content(filename, course='tda'):
 59    """
 60    Retrieves the content of an exercise file, processes it for rendering, and handles errors gracefully.
 61
 62    Args:
 63        filename (str): The name of the exercise file to be loaded. Expected format is 'ID.tex'.
 64        course (str, optional): The course directory where the exercise file is located. Defaults to 'tda'.
 65
 66    Returns:
 67        str: The processed content of the exercise file if successfully loaded, or an error message if the file
 68        is not found or another error occurs.
 69
 70    Logs:
 71        - Logs an info message when attempting to open the file.
 72        - Logs a debug message upon successfully reading the file content.
 73        - Logs an error message if the file is not found or if an unexpected error occurs.
 74
 75    Notes:
 76        - Assumes the exercise files are stored in a directory structure under 'exercises/{course}'.
 77        - Extracts the exercise ID from the filename by splitting on the '.' character.
 78        - Optionally preprocesses the LaTeX content for MathJax rendering using `preprocess_latex_for_mathjax`.
 79    """
 80    exercises_dir = os.path.join('exercises', course)
 81    filepath = os.path.join(exercises_dir, filename)
 82    logger.info(f"Attempting to open exercise file at path: {filepath}")
 83
 84    try:
 85        with open(filepath, 'r', encoding='utf-8') as file:
 86            content = file.read()
 87            logger.debug(f"Successfully read content from {filename}")
 88
 89            # Extrae el ID del ejercicio del nombre del archivo, asumiendo que el formato es 'ID.tex'
 90            exercise_id = filename.split('.')[0]
 91
 92            # Opcional: Preprocesamiento para el render con MathJax
 93            content = preprocess_latex_for_mathjax(content, exercise_id)
 94            return content
 95    except FileNotFoundError:
 96        logger.error(f"File {filename} not found in directory {exercises_dir}.")
 97        return "Exercise content not found."
 98    except Exception as e:
 99        logger.error(f"Unexpected error while reading {filepath}: {e}")
100        return "An error occurred while fetching the exercise content."

Retrieves the content of an exercise file, processes it for rendering, and handles errors gracefully.

Args: filename (str): The name of the exercise file to be loaded. Expected format is 'ID.tex'. course (str, optional): The course directory where the exercise file is located. Defaults to 'tda'.

Returns: str: The processed content of the exercise file if successfully loaded, or an error message if the file is not found or another error occurs.

Logs: - Logs an info message when attempting to open the file. - Logs a debug message upon successfully reading the file content. - Logs an error message if the file is not found or if an unexpected error occurs.

Notes: - Assumes the exercise files are stored in a directory structure under 'exercises/{course}'. - Extracts the exercise ID from the filename by splitting on the '.' character. - Optionally preprocesses the LaTeX content for MathJax rendering using preprocess_latex_for_mathjax.

def get_filename_from_exercise_id(exercise_id, course='tda'):
104def get_filename_from_exercise_id(exercise_id, course='tda'):
105    """
106    Retrieves the filename associated with a given exercise ID for a specific course.
107    Args:
108        exercise_id (int): The ID of the exercise to look up.
109        course (str, optional): The course name. Defaults to 'tda'.
110    Returns:
111        str: The filename corresponding to the given exercise ID.
112    Raises:
113        FileNotFoundError: If the index file for the specified course does not exist.
114        ValueError: If no exercise with the given ID is found in the course index.
115    """
116    index_path = os.path.join('exercises', course, 'index.csv')
117    if not os.path.exists(index_path):
118        raise FileNotFoundError(f"No index file found for course: {course}")
119
120    df = pd.read_csv(index_path)
121    match = df.loc[df['id'] == int(exercise_id), 'file']
122    
123    if match.empty:
124        raise ValueError(f"No exercise found with id {exercise_id} in course {course}")
125    
126    return match.values[0]

Retrieves the filename associated with a given exercise ID for a specific course. Args: exercise_id (int): The ID of the exercise to look up. course (str, optional): The course name. Defaults to 'tda'. Returns: str: The filename corresponding to the given exercise ID. Raises: FileNotFoundError: If the index file for the specified course does not exist. ValueError: If no exercise with the given ID is found in the course index.

def get_exercise_id_from_filename(filename, course='tda'):
129def get_exercise_id_from_filename(filename, course='tda'):
130    """
131    Retrieves the exercise ID associated with a given filename from the course's index file.
132    Args:
133        filename (str): The name of the exercise file to look up.
134        course (str, optional): The course name to locate the index file. Defaults to 'tda'.
135    Returns:
136        int: The ID of the exercise corresponding to the given filename.
137    Raises:
138        FileNotFoundError: If the index file for the specified course does not exist.
139        ValueError: If no exercise with the given filename is found in the index file.
140    """
141    index_path = os.path.join('exercises', course, 'index.csv')
142    if not os.path.exists(index_path):
143        raise FileNotFoundError(f"No index file found for course: {course}")
144
145    df = pd.read_csv(index_path)
146    match = df.loc[df['file'] == filename, 'id']
147    
148    if match.empty:
149        raise ValueError(f"No exercise found with filename {filename} in course {course}")
150    
151    return match.values[0]

Retrieves the exercise ID associated with a given filename from the course's index file. Args: filename (str): The name of the exercise file to look up. course (str, optional): The course name to locate the index file. Defaults to 'tda'. Returns: int: The ID of the exercise corresponding to the given filename. Raises: FileNotFoundError: If the index file for the specified course does not exist. ValueError: If no exercise with the given filename is found in the index file.