import json import os import shutil from pathlib import Path import xlsxwriter from benchmark.Datasets import Datasets from benchmark.ResultsBase import StubReport from benchmark.ResultsFiles import Benchmark, Excel, ReportDatasets from benchmark.Utils import Files, Folders from dotenv import dotenv_values from flask import ( Blueprint, current_app, redirect, render_template, request, send_file, url_for, ) from flask_login import current_user, login_required from .forms import RankingForm results = Blueprint("results", __name__, template_folder="templates") class AjaxResponse: def __init__(self, success, file_name, code=200): self.success = success self.file_name = file_name self.code = code def to_string(self): return ( json.dumps( { "success": self.success, "file": self.file_name, } ), self.code, {"ContentType": "application/json"}, ) @results.route("/select") @login_required def select(): # Get a list of files in a directory files = {} os.chdir(current_user.benchmark.folder) names = Files.get_all_results(hidden=False) for name in names: report = StubReport(os.path.join(Folders.results, name)) report.report() files[name] = { "duration": report.duration, "score": report.score, "title": report.title, } return render_template( "select.html", files=files, ) @results.route("/datasets") @login_required def datasets(): os.chdir(current_user.benchmark.folder) dt = Datasets() datos = [] for dataset in dt: datos.append(dt.get_attributes(dataset)) return render_template("datasets.html", datasets=datos) @results.route("/best/") @login_required def best(file_name): os.chdir(current_user.benchmark.folder) try: with open(os.path.join(Folders.results, file_name)) as f: data = json.load(f) except Exception as e: return render_template( "error.html", message=f"This best results file ({file_name}) has not been " "created yet! or...", error=str(e), back=url_for("results.select"), ) info = file_name.split("_") model = info[3].split(".")[0] title = f"Best results obtained with {model} on {info[2]}" return render_template("best.html", data=data, title=title) @results.route("/set_compare", methods=["POST"]) def set_compare(): compare = request.json["compare"] current_app.config.update(COMPARE=compare) return AjaxResponse(True, "Ok").to_string() @results.route("/report/") @login_required def report(file_name): os.chdir(current_user.benchmark.folder) back = request.args.get("url") or "" back_name = request.args.get("url_name") or "" app_config = dotenv_values(".env") try: with open(os.path.join(Folders.results, file_name)) as f: data = json.load(f) try: summary = process_data( file_name, current_app.config["COMPARE"], data ) except Exception as e: return render_template( "error.html", message=str(e), back=url_for("results.select") ) except Exception as e: return render_template( "error.html", message=f"This results file ({file_name}) has not been found!", error=str(e), back=url_for("results.select"), ) return render_template( "report.html", data=data, file=file_name, summary=summary, back=back, back_name=back_name, app_config=app_config, ) def process_data(file_name, compare, data): report = StubReport( os.path.join(Folders.results, file_name), compare=compare ) new_list = [] for result in data["results"]: symbol = report._compute_status(result["dataset"], result["score"]) result["symbol"] = symbol if symbol != " " else " " new_list.append(result) data["results"] = new_list # Compute summary with explanation of symbols summary = {} for key, value in report._compare_totals.items(): summary[key] = (report._status_meaning(key), value) return summary @results.route("/excel", methods=["post"]) @login_required def excel(): os.chdir(current_user.benchmark.folder) selected_files = request.json["selectedFiles"] if selected_files[0] == "datasets": # Create a list of datasets report = ReportDatasets(excel=True, output=False) report.report() return AjaxResponse(True, Files.datasets_report_excel).to_string() try: # create a spreadsheet with the selected files book = None for file_name in selected_files: file_name_result = os.path.join(Folders.results, file_name) if book is None: file_excel = os.path.join(Folders.excel, Files.be_list_excel) book = xlsxwriter.Workbook( file_excel, {"nan_inf_to_errors": True} ) excel = Excel( file_name=file_name_result, book=book, compare=current_app.config["COMPARE"], ) excel.report() except Exception as e: if book is not None: book.close() return AjaxResponse( False, "Could not create excel file, " + str(e) ).to_string() if book is not None: book.close() return AjaxResponse(True, Files.be_list_excel).to_string() @results.route("/download/") @login_required def download(file_name): os.chdir(current_user.benchmark.folder) src = os.path.join(current_user.benchmark.folder, Folders.excel, file_name) dest = os.path.join("static", "excel", file_name) os.chdir(current_app.root_path) shutil.copyfile(src, dest) return send_file(dest, as_attachment=True) @results.route("/dataset_report/") @login_required def dataset_report(dataset): # Get info of the results obtained for a dataset os.chdir(current_user.benchmark.folder) app_config = dotenv_values(".env") dt = Datasets() data = dt.get_attributes(dataset) names = Files.get_all_results(hidden=False) results = {} for name in names: try: with open(os.path.join(Folders.results, name)) as f: data = json.load(f) for result in data["results"]: if dataset == result["dataset"]: results[name] = result except Exception as e: return render_template( "error.html", message=f"Couldn't process file ({name})", error=str(e), back=url_for("results.dataset_report", dataset=dataset), ) return render_template( "dataset.html", dataset_name=dataset, results=results, app_config=app_config, ) @results.route("/ranking", methods=["GET", "POST"]) @login_required def ranking(): os.chdir(current_user.benchmark.folder) form = RankingForm() if form.validate_on_submit(): benchmark = Benchmark(score=form.score.data, visualize=False) try: benchmark.compile_results() benchmark.save_results() benchmark.report(tex_output=False) benchmark.exreport() benchmark.excel() except ValueError as e: return render_template( "error.html", message="Couldn't generate ranking", error=str(e) ) except KeyError as e: return render_template( "error.html", message="Couldn't generate ranking. It seems that there are " "partial results for some classifiers", error=f"Key not found {str(e)}", ) file_name = Path(benchmark.get_excel_file_name()).name return redirect(url_for("results.download", file_name=file_name)) return render_template("ranking.html", form=form)