From e1568e25a4acc7360feba7d45b0d4329d88db807 Mon Sep 17 00:00:00 2001 From: "johan.ocampo" Date: Thu, 19 Dec 2024 17:37:54 -0500 Subject: [PATCH] views.py documented --- .vscode/settings.json | 5 + flow/views.py | 332 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 337 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9163ef8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "docwriter.style": "Auto-detect", + "docwriter.progress.trackFunctions": false, + "docwriter.language": "Spanish" +} \ No newline at end of file diff --git a/flow/views.py b/flow/views.py index 731212d..a3c7b58 100644 --- a/flow/views.py +++ b/flow/views.py @@ -26,14 +26,50 @@ django.setup() # Helper function to make safe filenames def get_safe_filename(name): + """ + Generate a safe filename by replacing unsafe characters with underscores. + + This function takes a string `name` and replaces any character that is not + a letter (a-z, A-Z), digit (0-9), underscore (_), or hyphen (-) with an + underscore (_). It also strips any leading or trailing whitespace from the + resulting string. + + Args: + name (str): The original filename string. + + Returns: + str: A safe filename string with unsafe characters replaced by underscores. + """ return re.sub(r'[^a-zA-Z0-9_-]', '_', name).strip() # Vista para renderizar la página principal def create_tabs_flow(request): + """ + Handles the creation of tabs flow view. + + Args: + request (HttpRequest): The HTTP request object. + + Returns: + HttpResponse: The rendered 'flow.html' template. + """ return render(request, 'flow.html') # Vista para listar todas las pestañas existentes def list_tabs(request): + """ + List all tabs by reading JSON files from the data directory. + + This function searches for files in the 'flow/data' directory that match the pattern 'tab__.json'. + It extracts the tab ID and tab name from the filename and reads the 'tabName' from the JSON content. + If 'tabName' is not present in the JSON content, it defaults to 'Pestaña '. + + Args: + request: The HTTP request object. + + Returns: + JsonResponse: A JSON response containing a list of tabs with their names and IDs. + """ data_dir = os.path.join(settings.BASE_DIR, 'flow', 'data') tabs = [] @@ -58,6 +94,24 @@ def list_tabs(request): # Función para crear y guardar archivos de texto desde el contenido del node3 @csrf_exempt def save_tts(request): + """ + Handles the saving of Text-to-Speech (TTS) data from a POST request and generates a Python AGI script for Asterisk. + Args: + request (HttpRequest): The HTTP request object containing the TTS data in JSON format. + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + The function performs the following steps: + 1. Checks if the request method is POST. If not, returns an error response. + 2. Parses the JSON data from the request body. + 3. Extracts necessary fields such as tabId, tabName, nodeId, nodeType, title, content, and audioFile. + 4. Formats the audio file name based on nodeId and title. + 5. Constructs the file path for the Python AGI script. + 6. Generates the content of the AGI script, including functions for handling calls, recording audio, detecting audio, and consulting Claude. + 7. Writes the generated script to the specified file path. + 8. Sets the appropriate file permissions and ownership. + 9. Returns a success response with the file path if the operation is successful. + 10. Returns an error response if any exceptions occur during the process. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -293,6 +347,28 @@ if __name__ == "__main__": # Vista para guardar datos de la pestaña @csrf_exempt def save_tab_data(request): + """ + Guarda los datos de una pestaña en un archivo JSON y extrae condiciones específicas para guardarlas en otro archivo JSON. + + Args: + request (HttpRequest): La solicitud HTTP que contiene los datos de la pestaña. + + Returns: + JsonResponse: Una respuesta JSON indicando el éxito o el error de la operación. + + Raises: + JsonResponse: Si ocurre un error durante el procesamiento de los datos. + + El cuerpo de la solicitud debe contener un JSON con los siguientes campos: + - tabId (str): El ID de la pestaña. + - tabName (str): El nombre de la pestaña. + - nodes (list): Una lista de nodos que pertenecen a la pestaña. + - connections (list): Una lista de conexiones entre los nodos. + + El archivo JSON se guarda en la ruta: /flow/data/tab__.json + + Además, se extraen las condiciones de los nodos de tipo 'node3' y se guardan en otro archivo JSON en la ruta: /home/Flow_IA/IVR/tab__conditions.json + """ if request.method != 'POST': return JsonResponse({'error': 'Solo se permiten solicitudes POST'}, status=405) @@ -449,6 +525,31 @@ def save_tab_data(request): # Vista para cargar los datos de una pestaña específica def load_tab_data(request, tab_id): + """ + Load data for a specific tab from a JSON file. + + This function searches for a JSON file corresponding to the given tab_id + in the 'flow/data' directory. If found, it loads the data from the file, + ensures that nodes of type 'node1', 'node3', and 'node4' do not have an + 'audioFile' attribute, and returns the data as a JSON response. If no + matching file is found, it returns a default response with an empty list + of nodes and connections, and a tab name based on the tab_id. + + Args: + request (HttpRequest): The HTTP request object. + tab_id (int): The ID of the tab to load data for. + + Returns: + JsonResponse: A JSON response containing the tab data or an error message. + + Raises: + Exception: If an error occurs while loading the data. + + Notes: + - For nodes of type 'node4', there is no 'receivedString' attribute, + but there is an 'extensionNumber' attribute that should be handled + correctly. + """ try: data_dir = os.path.join(settings.BASE_DIR, 'flow', 'data') # Buscar el archivo JSON correspondiente a la tab_id @@ -477,6 +578,27 @@ def load_tab_data(request, tab_id): # Nueva Vista para eliminar archivos de Node3 cuando se actualiza @csrf_exempt def delete_files(request): + """ + Handle the deletion of text files associated with a specific node in a tab. + + This view function processes POST requests to delete text files based on the provided + tab ID, node ID, node type, and old title. It only processes nodes of type "node3". + + Args: + request (HttpRequest): The HTTP request object containing the request data. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the file deletion + operation. Possible status codes are: + - 200: Node type does not have files to delete. + - 400: Incomplete data provided. + - 405: Request method is not POST. + - 500: An internal server error occurred. + + Raises: + Exception: If any error occurs during the file deletion process, it is caught and + returned in the JSON response. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -516,6 +638,29 @@ def delete_files(request): # Vista para subir audio para Node2 @csrf_exempt def upload_audio(request): + """ + Handles the upload of an audio file via a POST request. + + Args: + request (HttpRequest): The HTTP request object containing POST data and files. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the upload process. + + The function performs the following steps: + 1. Checks if the request method is POST. If not, returns a 405 error. + 2. Extracts 'tabId', 'nodeId', 'nodeType', 'title', and 'audioFile' from the POST data. + 3. Validates that all required data is present. If not, returns a 400 error. + 4. Ensures the 'nodeType' is 'node2'. If not, returns a 400 error. + 5. Creates necessary directories for storing the audio file. + 6. Generates a unique filename for the audio file using 'title', 'nodeType', and 'nodeId'. + 7. Saves the uploaded audio file to the specified directory. + 8. Copies the saved audio file to the Asterisk recordings directory. + 9. Generates a URL for the saved audio file. + 10. Returns a JSON response with the URL of the saved audio file and the path in the Asterisk directory. + + If any exception occurs during the process, returns a 500 error with the exception message. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -571,6 +716,31 @@ def upload_audio(request): # Vista para eliminar audio de Node2 y Node6 @csrf_exempt def delete_audio(request): + """ + Handle the deletion of an audio file based on the provided request. + + This view function processes POST requests to delete an audio file associated with a specific node type. + It only processes requests for nodes of type "node2" or "node6". + + Args: + request (HttpRequest): The HTTP request object containing the request data. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + + The request body should contain the following JSON fields: + - tabId (str): The ID of the tab. + - nodeId (str): The ID of the node. + - nodeType (str): The type of the node (must be "node2" or "node6"). + - oldAudioFile (str): The path to the old audio file to be deleted. + + Possible JSON responses: + - {'status': 'error', 'message': 'Solo se permiten solicitudes POST'} (HTTP 405) + - {'status': 'error', 'message': 'Datos incompletos'} (HTTP 400) + - {'status': 'error', 'message': 'Este endpoint solo es para node2 o node6'} (HTTP 400) + - {'status': 'success', 'message': 'Archivo de audio eliminado correctamente'} (HTTP 200) + - {'status': 'error', 'message': str(e)} (HTTP 500) + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -602,6 +772,35 @@ def delete_audio(request): # Vista para renombrar audio de Node2 y Node6 @csrf_exempt def rename_audio(request): + """ + Renames the audio file associated with node2 or node6. + + This view handles POST requests to rename an audio file based on the provided data. + It processes the request only if the node type is either "node2" or "node6". + The renamed file is also copied to the Asterisk directory. + + Args: + request (HttpRequest): The HTTP request object containing the POST data. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + + POST Data: + - tabId (str): The ID of the tab. + - nodeId (str): The ID of the node. + - nodeType (str): The type of the node (must be "node2" or "node6"). + - oldTitle (str): The old title of the audio file. + - newTitle (str): The new title of the audio file. + - currentAudioFile (str): The current audio file name. + + JSON Response: + - status (str): The status of the operation ("success" or "error"). + - message (str, optional): The error message if the operation failed. + - newAudioFile (str, optional): The URL of the new audio file if the operation succeeded. + + Raises: + Exception: If any error occurs during the process, a JSON response with status 500 is returned. + """ """ Renombra el archivo de audio asociado a node2 o node6. """ @@ -663,6 +862,22 @@ def rename_audio(request): # Vista para renombrar una pestaña @csrf_exempt def rename_tab(request): + + """ + Args: + request (HttpRequest): La solicitud HTTP que debe ser de tipo POST y contener un cuerpo JSON con 'tabId' y 'newTabName'. + + Returns: + JsonResponse: Una respuesta JSON con el estado de la operación. Puede ser: + - {'status': 'success', 'message': 'Pestaña renombrada exitosamente'} en caso de éxito. + - {'status': 'error', 'message': 'Solo se permiten solicitudes POST'} si el método de la solicitud no es POST. + - {'status': 'error', 'message': 'Datos incompletos'} si faltan 'tabId' o 'newTabName' en el cuerpo de la solicitud. + - {'status': 'error', 'message': 'Archivo de pestaña no encontrado'} si no se encuentra un archivo correspondiente a 'tabId'. + - {'status': 'error', 'message': str(e)} si ocurre cualquier otra excepción durante el proceso. + + Raises: + Exception: Cualquier excepción que ocurra durante el proceso será capturada y su mensaje será incluido en la respuesta JSON. + """ """ Renombra una pestaña específica. """ @@ -713,6 +928,30 @@ def rename_tab(request): # Vista para actualizar Node1 (título y extensión) @csrf_exempt def update_node1(request): + """ + Updates the title and extension number of a specific node1. + + Args: + request (HttpRequest): The HTTP request object containing the data to update the node. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the update operation. + + Raises: + Exception: If any error occurs during the update process. + + The function performs the following steps: + 1. Checks if the request method is POST. If not, returns a 405 error. + 2. Parses the request body to extract the necessary data. + 3. Validates the presence of required data fields. + 4. Creates a backup of the Asterisk configuration file and appends new extension configuration. + 5. Searches for the corresponding JSON file for the tab and updates the node's title and extension number. + 6. Saves the updated JSON file. + 7. Returns a success response if the update is successful, or an error response if any step fails. + + Note: + This endpoint is specifically for updating nodes of type "node1". + """ """ Actualiza el título y número de extensión de un node1 específico. """ @@ -786,6 +1025,34 @@ exten => {new_extension},n,Hangup() # Vista para eliminar un nodo @csrf_exempt def delete_node(request): + """ + Handle the deletion of a node and its connections from a tab. + + This view function processes a POST request to delete a node identified by its ID from a specified tab. + It also handles the deletion of associated files if the node type requires it. + + Args: + request (HttpRequest): The HTTP request object containing the POST data. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + + The expected JSON payload in the request body should contain: + - tabId (str): The ID of the tab. + - nodeId (str): The ID of the node to be deleted. + - nodeType (str): The type of the node. + + Possible responses: + - 200 OK: Node and its connections were successfully deleted. + - 400 Bad Request: Missing or incomplete data in the request. + - 404 Not Found: Tab file or node not found. + - 405 Method Not Allowed: Request method is not POST. + - 500 Internal Server Error: An unexpected error occurred during processing. + + Node type-specific behavior: + - node3: Deletes associated text files. + - node2, node6: Deletes associated audio files. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -852,6 +1119,25 @@ def delete_node(request): # Vista para eliminar una pestaña @csrf_exempt def delete_tab(request): + """ + Handle the deletion of a tab. + + This view function processes a POST request to delete a tab by its ID and name. + It performs the following actions: + - Validates that the request method is POST. + - Parses the request body to extract the tab ID and name. + - Deletes the corresponding tab data file. + - Deletes associated media files (audio and text files). + - Deletes the conditions JSON file related to the tab. + + Args: + request (HttpRequest): The HTTP request object. + + Returns: + JsonResponse: A JSON response indicating the result of the operation. + - On success: {'status': 'success', 'message': 'Pestaña eliminada exitosamente'} + - On error: {'status': 'error', 'message': 'Error message'} with appropriate HTTP status code. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -893,6 +1179,29 @@ def delete_tab(request): # Vista para actualizar Node4 @csrf_exempt def update_node4(request): + """ + Handle POST requests to update the extension number of a node4 in a tab's JSON file. + + Args: + request (HttpRequest): The HTTP request object containing the POST data. + + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + + The request body should contain a JSON object with the following keys: + - tabId (str): The ID of the tab. + - tabName (str): The name of the tab. + - nodeId (str): The ID of the node to be updated. + - nodeType (str): The type of the node (should be "node4"). + - extensionNumber (int): The new extension number for the node. + + Possible responses: + - 200 OK: If the node4 is successfully updated. + - 400 Bad Request: If the request data is incomplete or the node type is not "node4". + - 404 Not Found: If the tab file or the node4 is not found. + - 405 Method Not Allowed: If the request method is not POST. + - 500 Internal Server Error: If an unexpected error occurs during processing. + """ if request.method != 'POST': return JsonResponse({'status': 'error', 'message': 'Solo se permiten solicitudes POST'}, status=405) @@ -945,6 +1254,29 @@ def update_node4(request): # Vista para generar audios por medio del TTS @csrf_exempt def tts_module(request, language="es"): + """ + Generates an audio file from text using TTS and saves it in the corresponding directory. + Args: + request (HttpRequest): The HTTP request object containing the POST data. + language (str, optional): The language code for TTS. Defaults to "es". + Returns: + JsonResponse: A JSON response indicating the success or failure of the operation. + The function performs the following steps: + 1. Checks if the request method is POST. + 2. Parses the JSON data from the request body. + 3. Validates the presence of required data fields: tabId, title, text, nodeId, and nodeType. + 4. Creates the necessary directories for storing the audio file. + 5. Generates a unique filename for the audio file using the nodeId and title. + 6. Converts the text to speech using the specified language. + 7. Adjusts the speed of the audio. + 8. Converts the audio to WAV format at 8000 kHz. + 9. Saves the audio file in the specified directory. + 10. Copies the audio file to the Asterisk sounds directory. + 11. Generates the URL for the saved audio file. + 12. Returns a JSON response with the status and URL of the saved audio file. + Raises: + Exception: If any error occurs during the process, a JSON response with the error message is returned. + """ """ Genera un archivo de audio a partir de un texto utilizando TTS y lo guarda en el directorio correspondiente. """