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]
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.
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.
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.
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.