diff --git a/.gitignore b/.gitignore index 52a2e06..451c961 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ cope2n-ai-fi/Dockerfile_old_work cope2n-api/public/SBT_report_20240122.csv Jan.csv *.csv +cope2n-api/reviewed/date.xlsx +cope2n-api/reviewed/retailer.xlsx diff --git a/cope2n-ai-fi/modules/sdsvkvu b/cope2n-ai-fi/modules/sdsvkvu index b6d4fab..d01de31 160000 --- a/cope2n-ai-fi/modules/sdsvkvu +++ b/cope2n-ai-fi/modules/sdsvkvu @@ -1 +1 @@ -Subproject commit b6d4fab46f7f8689dd6b050cfbff2faa6a6f3fec +Subproject commit d01de312ab86db554ffa2f1b01396ef8d56b78ed diff --git a/cope2n-api/fwd/settings.py b/cope2n-api/fwd/settings.py index dd5801c..9bdaf69 100755 --- a/cope2n-api/fwd/settings.py +++ b/cope2n-api/fwd/settings.py @@ -224,6 +224,8 @@ OVERVIEW_REFRESH_INTERVAL = 2 OVERVIEW_REPORT_ROOT = "overview" OVERVIEW_REPORT_DURATION = ["30d", "7d"] +ACC_EXCLUDE_RESEASONS = ["Invalid Input", "Handwritten information", "handwritten"] + SUBS = { "SEAU": "AU", "SESP": "SG", diff --git a/cope2n-api/fwd_api/api/accuracy_view.py b/cope2n-api/fwd_api/api/accuracy_view.py index 88a0d24..87b608f 100644 --- a/cope2n-api/fwd_api/api/accuracy_view.py +++ b/cope2n-api/fwd_api/api/accuracy_view.py @@ -382,7 +382,7 @@ class AccuracyViewSet(viewsets.ViewSet): for key in acc_keys: fb = report.feedback_accuracy.get(key, 0) if report.feedback_accuracy else 0 rv = report.reviewed_accuracy.get(key, 0) if report.reviewed_accuracy else 0 - acc[key] = max([fb, rv]) + acc[key] = report.combined_accuracy.get(key, 0) if report.combined_accuracy else max([fb, rv]) data.append({ "ID": report.id, "Created Date": report.created_at, diff --git a/cope2n-api/fwd_api/celery_worker/internal_task.py b/cope2n-api/fwd_api/celery_worker/internal_task.py index 23abef9..53d2277 100755 --- a/cope2n-api/fwd_api/celery_worker/internal_task.py +++ b/cope2n-api/fwd_api/celery_worker/internal_task.py @@ -14,7 +14,7 @@ from ..utils import file as FileUtils from ..utils import process as ProcessUtil from ..utils import s3 as S3Util from ..utils.accuracy import validate_feedback_file -from fwd_api.constant.common import ProcessType +from fwd_api.constant.common import FileCategory import csv import json import copy @@ -114,6 +114,9 @@ def process_csv_feedback(csv_file_path, feedback_id): for k, v in sub_rq.ai_inference_profile.items(): time_cost[k.split("_")[0]].append(v["inference"][1][0] - v["inference"][0] + (v["postprocess"][1]-v["postprocess"][0])) for i, image in enumerate(images): + if image.file_category != FileCategory.Origin.value: + # skip break files, which are not responsible for storing data + continue _predict_result = copy.deepcopy(predict_result_to_ready(sub_rq.predict_result)) _feedback_result = copy.deepcopy(sub_rq.feedback_result) _reviewed_result = copy.deepcopy(sub_rq.reviewed_result) @@ -128,12 +131,10 @@ def process_csv_feedback(csv_file_path, feedback_id): _predict_result["imei_number"] = [] if _feedback_result: _feedback_result["imei_number"] = [] - else: - None + if _reviewed_result: _reviewed_result["imei_number"] = [] - else: - None + else: try: _predict_result = {"retailername": None, "sold_to_party": None, "purchase_date": [], "imei_number": [_predict_result["imei_number"][image.index_in_request]]} diff --git a/cope2n-api/fwd_api/celery_worker/process_report_tasks.py b/cope2n-api/fwd_api/celery_worker/process_report_tasks.py index 2436eb5..52578a1 100644 --- a/cope2n-api/fwd_api/celery_worker/process_report_tasks.py +++ b/cope2n-api/fwd_api/celery_worker/process_report_tasks.py @@ -4,7 +4,7 @@ from fwd_api.models import SubscriptionRequest, Report, ReportFile from fwd_api.celery_worker.worker import app from ..utils import s3 as S3Util from ..utils.accuracy import update_temp_accuracy, IterAvg, calculate_and_save_subcription_file, count_transactions, extract_report_detail_list, calculate_a_request, ReportAccumulateByRequest -from ..utils.file import dict2xlsx, save_workbook_file, save_report_to_S3 +from ..utils.file import dict2xlsx, save_workbook_file, save_report_to_S3, save_images_to_csv_briefly from ..utils import time_stuff from ..utils.redis import RedisUtils from django.utils import timezone @@ -187,8 +187,6 @@ def make_a_report_2(report_id, query_set): base_query &= Q(is_reviewed=True) elif query_set["is_reviewed"] == "not reviewed": base_query &= Q(is_reviewed=False) - # elif query_set["is_reviewed"] == "all": - # pass errors = [] # Create a placeholder to fill @@ -197,12 +195,17 @@ def make_a_report_2(report_id, query_set): "retailername": IterAvg(), "sold_to_party": IterAvg(),}, "reviewed" :{"imei_number": IterAvg(), + "purchase_date": IterAvg(), + "retailername": IterAvg(), + "sold_to_party": IterAvg(),}, + "acumulated":{"imei_number": IterAvg(), "purchase_date": IterAvg(), "retailername": IterAvg(), "sold_to_party": IterAvg(),} } # {"imei": {"acc": 0.1, count: 1}, ...} time_cost = {"invoice": IterAvg(), "imei": IterAvg()} + bad_image_list = [] number_images = 0 number_bad_images = 0 # TODO: Multithreading @@ -232,8 +235,10 @@ def make_a_report_2(report_id, query_set): request.save() number_images += request_att["total_images"] number_bad_images += request_att["bad_images"] + bad_image_list += request_att["bad_image_list"] update_temp_accuracy(accuracy["feedback"], request_att["acc"]["feedback"], keys=["imei_number", "purchase_date", "retailername", "sold_to_party"]) update_temp_accuracy(accuracy["reviewed"], request_att["acc"]["reviewed"], keys=["imei_number", "purchase_date", "retailername", "sold_to_party"]) + update_temp_accuracy(accuracy["acumulated"], request_att["acc"]["acumulated"], keys=["imei_number", "purchase_date", "retailername", "sold_to_party"]) time_cost["imei"].add(request_att["time_cost"].get("imei", [])) time_cost["invoice"].add(request_att["time_cost"].get("invoice", [])) @@ -259,8 +264,9 @@ def make_a_report_2(report_id, query_set): report.number_invoice_transaction = transaction_att.get("invoice", 0) acumulated_acc = {"feedback": {}, - "reviewed": {}} - for acc_type in ["feedback", "reviewed"]: + "reviewed": {}, + "acumulated": {}} + for acc_type in ["feedback", "reviewed", "acumulated"]: avg_acc = IterAvg() for key in ["imei_number", "purchase_date", "retailername", "sold_to_party"]: acumulated_acc[acc_type][key] = accuracy[acc_type][key]() @@ -270,10 +276,13 @@ def make_a_report_2(report_id, query_set): report.feedback_accuracy = acumulated_acc["feedback"] report.reviewed_accuracy = acumulated_acc["reviewed"] + report.combined_accuracy = acumulated_acc["acumulated"] report.errors = "|".join(errors) report.status = "Ready" report.save() + # Save a list of bad images to csv file for debugging + save_images_to_csv_briefly(report.report_id, bad_image_list) # Saving a xlsx file data = extract_report_detail_list(report_files, lower=True) data_workbook = dict2xlsx(data, _type='report_detail') diff --git a/cope2n-api/fwd_api/management/commands/migrate-csv-new-col-index.py b/cope2n-api/fwd_api/management/commands/migrate-csv-new-col-index.py new file mode 100644 index 0000000..4270a59 --- /dev/null +++ b/cope2n-api/fwd_api/management/commands/migrate-csv-new-col-index.py @@ -0,0 +1,166 @@ +# myapp/management/commands/mycustomcommand.py +from django.core.management.base import BaseCommand +from tqdm import tqdm +from fwd_api.models import SubscriptionRequestFile, SubscriptionRequest +from fwd_api.utils.accuracy import predict_result_to_ready +import traceback +import copy +import csv + +class Command(BaseCommand): + help = 'Refactor database for image level' + + def add_arguments(self, parser): + # Add your command-line arguments here + parser.add_argument('test', type=str, help='Value for the argument') + + def process_request(self, request, predict_result, user_feedback, reviewed_result): + if len(request.request_id.split(".")[0].split("_")) < 2: + return + + request_feedback = copy.deepcopy(request.feedback_result) + request_review = copy.deepcopy(request.reviewed_result) + + if not request_feedback: + request_feedback = { + "request_id": request.request_id, + "imei_number": [], + "retailername": "", + "purchase_date": "", + "sold_to_party": "" + } + + if not request_review: + request_review = { + "request_id": request.request_id, + "imei_number": [], + "retailername": "", + "purchase_date": "", + "sold_to_party": "" + } + + images = SubscriptionRequestFile.objects.filter(request=request) + is_match = False + try: + for i, image in enumerate(images): + if not request.predict_result: + raise KeyError(f"Key predict_result not found in {request.request_id}") + if request.predict_result.get("status", 200) != 200: + raise AttributeError(f"Failed request: {request.request_id}") + + for field in ['retailername', 'purchase_date', 'imei_number']: + # if image.feedback_result[field] is not None: + # print(f"image.feedback_result[field] is not None is not None - field: {field}") + # else: + # print("image.feedback_result[field] is None") + + # if image.feedback_result[field] == user_feedback: + # print("image.feedback_result[field] == user_feedback") + # else: + # print(f"NOT image.feedback_result[field] == user_feedback - field: {field} - image.feedback_result[field]:{image.feedback_result[field]} - user_feedback:{user_feedback}") + + # if (field == 'imei_number' and len(image.feedback_result[field]) > 0 and image.feedback_result[field][0] == user_feedback): + # print("(field == 'imei_number' and len(image.feedback_result[field]) > 0 and image.feedback_result[field][0] == user_feedback)") + # else: + # print(f"NOT (field == 'imei_number' and len(image.feedback_result[field]) > 0 and image.feedback_result[field][0] == user_feedback) - field: {field}") + + # if image.feedback_result[field] is not None and ((field == 'imei_number' and len(image.feedback_result[field]) > 0 and image.feedback_result[field][0] == user_feedback) or image.feedback_result[field] == user_feedback): + is_match = True + + if field == 'imei_number': + if not reviewed_result == request_review: + request_review["imei_number"].append(reviewed_result) + if not user_feedback == request_feedback: + request_feedback["imei_number"].append(user_feedback) + else: + if not reviewed_result == request_review: + request_review[field] = reviewed_result + if not user_feedback == request_feedback: + request_feedback[field] = user_feedback + + _predict_result = copy.deepcopy(predict_result_to_ready(request.predict_result)) + _feedback_result = copy.deepcopy(request.feedback_result) + _reviewed_result = copy.deepcopy(request.reviewed_result) + + if not _feedback_result: + _feedback_result = { + "imei_number": [], + "retailername": "", + "purchase_date": "", + "sold_to_party": "" + } + if not _reviewed_result: + _reviewed_result = { + "imei_number": [], + "retailername": "", + "purchase_date": "", + "sold_to_party": "" + } + + if image.doc_type == "invoice": + _predict_result[field] = predict_result + _predict_result["imei_number"] = [] + if _feedback_result: + _feedback_result[field] = user_feedback + _feedback_result["imei_number"] = [] + else: + None + if _reviewed_result: + _reviewed_result[field] = reviewed_result + _reviewed_result["imei_number"] = [] + else: + None + else: + _predict_result = { + "retailername": None, + "sold_to_party": None, + "purchase_date": [], + "imei_number": [predict_result] + } + _feedback_result = { + "retailername": None, + "sold_to_party": None, + "purchase_date": None, + "imei_number": [user_feedback] + } if _feedback_result else None + _reviewed_result = { + "retailername": None, + "sold_to_party": None, + "purchase_date": None, + "imei_number": [reviewed_result] + } if _reviewed_result else None + image.predict_result = _predict_result + image.feedback_result = _feedback_result + image.reviewed_result = _reviewed_result + image.save() + # request.feedback_result = request_feedback + request.reviewed_result = request_review + request.feedback_result["request_id"] = request.request_id + request.reviewed_result["request_id"] = request.request_id + request.is_reviewed = True + request.save() + + except Exception as e: + self.stdout.write(self.style.ERROR(f"Request: {request.request_id} failed with {e}")) + print(traceback.format_exc()) + + if not is_match: + print("FAIL =====>", "image.feedback_result: ", image.feedback_result, "| predict_result: ", predict_result, " | user_feedback: ", user_feedback, "| reviewed_result: ", reviewed_result) + + def handle(self, *args, **options): + test = options['test'] + #open csv file + with open(test, 'r') as csvfile: + reader = csv.reader(csvfile) + index = 0 + for row in reader: + if index != 0: + request = SubscriptionRequest.objects.filter(request_id=row[0]).first() + if not request: + # print("Not found ====>", row) + continue + else: + self.process_request(request, row[4], row[3], row[5]) + index += 1 + + self.stdout.write(self.style.SUCCESS('Sample Django management command executed successfully!')) diff --git a/cope2n-api/fwd_api/migrations/0182_report_combined_accuracy.py b/cope2n-api/fwd_api/migrations/0182_report_combined_accuracy.py new file mode 100644 index 0000000..1514ec0 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0182_report_combined_accuracy.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2024-02-18 05:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0181_reportfile_subsidiary'), + ] + + operations = [ + migrations.AddField( + model_name='report', + name='combined_accuracy', + field=models.JSONField(null=True), + ), + ] diff --git a/cope2n-api/fwd_api/models/Report.py b/cope2n-api/fwd_api/models/Report.py index 92a2755..05236cb 100644 --- a/cope2n-api/fwd_api/models/Report.py +++ b/cope2n-api/fwd_api/models/Report.py @@ -38,4 +38,5 @@ class Report(models.Model): average_client_time = models.JSONField(null=True) # {"invoice": 0.1, "imei": 0.1} feedback_accuracy = models.JSONField(null=True) - reviewed_accuracy = models.JSONField(null=True) \ No newline at end of file + reviewed_accuracy = models.JSONField(null=True) + combined_accuracy = models.JSONField(null=True) \ No newline at end of file diff --git a/cope2n-api/fwd_api/models/SubscriptionRequestFile.py b/cope2n-api/fwd_api/models/SubscriptionRequestFile.py index 93d62f5..4055b48 100755 --- a/cope2n-api/fwd_api/models/SubscriptionRequestFile.py +++ b/cope2n-api/fwd_api/models/SubscriptionRequestFile.py @@ -31,4 +31,4 @@ class SubscriptionRequestFile(models.Model): reviewed_result = models.JSONField(null=True) feedback_accuracy = models.JSONField(null=True) - reviewed_accuracy = models.JSONField(null=True) \ No newline at end of file + reviewed_accuracy = models.JSONField(null=True) diff --git a/cope2n-api/fwd_api/utils/accuracy.py b/cope2n-api/fwd_api/utils/accuracy.py index 2eeece0..11b2d9f 100644 --- a/cope2n-api/fwd_api/utils/accuracy.py +++ b/cope2n-api/fwd_api/utils/accuracy.py @@ -5,7 +5,7 @@ import copy from typing import Any from .ocr_utils.ocr_metrics import eval_ocr_metric from .ocr_utils.sbt_report import post_processing_str -import uuid +from fwd_api.constant.common import FileCategory from fwd_api.models import SubscriptionRequest, SubscriptionRequestFile, ReportFile from ..celery_worker.client_connector import c_connector from ..utils.file import dict2xlsx, save_workbook_file, save_report_to_S3 @@ -172,21 +172,21 @@ class ReportAccumulateByRequest: day_data["num_invoice"] += 1 if doc_type == "invoice" else 0 day_data["report_files"].append(report_file) - if sum([len(report_file.reviewed_accuracy[x]) for x in report_file.reviewed_accuracy.keys() if "_count" not in x]) > 0 : - day_data["average_accuracy_rate"]["imei"].add(report_file.reviewed_accuracy.get("imei_number", 0)) - day_data["average_accuracy_rate"]["purchase_date"].add(report_file.reviewed_accuracy.get("purchase_date", 0)) - day_data["average_accuracy_rate"]["retailer_name"].add(report_file.reviewed_accuracy.get("retailername", 0)) - day_data["average_accuracy_rate"]["sold_to_party"].add(report_file.reviewed_accuracy.get("sold_to_party", 0)) + if sum([len(report_file.reviewed_accuracy[x]) for x in report_file.reviewed_accuracy.keys() if "_count" not in x]) > 0: + day_data["average_accuracy_rate"]["imei"].add(report_file.reviewed_accuracy.get("imei_number", [])) + day_data["average_accuracy_rate"]["purchase_date"].add(report_file.reviewed_accuracy.get("purchase_date", [])) + day_data["average_accuracy_rate"]["retailer_name"].add(report_file.reviewed_accuracy.get("retailername", [])) + day_data["average_accuracy_rate"]["sold_to_party"].add(report_file.reviewed_accuracy.get("sold_to_party", [])) elif sum([len(report_file.feedback_accuracy[x]) for x in report_file.feedback_accuracy.keys() if "_count" not in x]) > 0: - day_data["average_accuracy_rate"]["imei"].add(report_file.feedback_accuracy.get("imei_number", 0)) - day_data["average_accuracy_rate"]["purchase_date"].add(report_file.feedback_accuracy.get("purchase_date", 0)) - day_data["average_accuracy_rate"]["retailer_name"].add(report_file.feedback_accuracy.get("retailername", 0)) - day_data["average_accuracy_rate"]["sold_to_party"].add(report_file.feedback_accuracy.get("sold_to_party", 0)) + day_data["average_accuracy_rate"]["imei"].add(report_file.feedback_accuracy.get("imei_number", [])) + day_data["average_accuracy_rate"]["purchase_date"].add(report_file.feedback_accuracy.get("purchase_date", [])) + day_data["average_accuracy_rate"]["retailer_name"].add(report_file.feedback_accuracy.get("retailername", [])) + day_data["average_accuracy_rate"]["sold_to_party"].add(report_file.feedback_accuracy.get("sold_to_party", [])) for key in ["imei_number", "purchase_date", "retailername", "sold_to_party"]: - day_data["feedback_accuracy"][key].add(report_file.feedback_accuracy.get(key, 0)) + day_data["feedback_accuracy"][key].add(report_file.feedback_accuracy.get(key, [])) for key in ["imei_number", "purchase_date", "retailername", "sold_to_party"]: - day_data["reviewed_accuracy"][key].add(report_file.reviewed_accuracy.get(key, 0)) + day_data["reviewed_accuracy"][key].add(report_file.reviewed_accuracy.get(key, [])) if not day_data["average_processing_time"].get(report_file.doc_type, None): print(f"[WARM]: Weird doctype: {report_file.doc_type}") @@ -196,14 +196,14 @@ class ReportAccumulateByRequest: return day_data def add(self, request, report_files): - this_month = request.created_at.strftime("%Y%m") - this_day = request.created_at.strftime("%Y%m%d") + this_month = timezone.localtime(request.created_at).strftime("%Y%m") + this_day = timezone.localtime(request.created_at).strftime("%Y%m%d") if not self.data.get(this_month, None): self.data[this_month] = [copy.deepcopy(self.total_format), {}] - self.data[this_month][0]["extraction_date"] = "Subtotal (" + request.created_at.strftime("%Y-%m") + ")" + self.data[this_month][0]["extraction_date"] = "Subtotal (" + timezone.localtime(request.created_at).strftime("%Y-%m") + ")" if not self.data[this_month][1].get(this_day, None): self.data[this_month][1][this_day] = copy.deepcopy(self.day_format)[0] - self.data[this_month][1][this_day]['extraction_date'] = request.created_at.strftime("%Y-%m-%d") + self.data[this_month][1][this_day]['extraction_date'] = timezone.localtime(request.created_at).strftime("%Y-%m-%d") usage = self.count_transactions_within_day(this_day) self.data[this_month][1][this_day]["usage"]["imei"] = usage.get("imei", 0) self.data[this_month][1][this_day]["usage"]["invoice"] = usage.get("invoice", 0) @@ -625,14 +625,14 @@ def align_fine_result(ready_predict, fine_result): # print(f"[DEBUG]: fine_result: {fine_result}") # print(f"[DEBUG]: ready_predict: {ready_predict}") if fine_result: - if isinstance(ready_predict["purchase_date"], str): - ready_predict["purchase_date"] = [ready_predict["purchase_date"]] - # ready_predict.save() if fine_result["purchase_date"] and len(ready_predict["purchase_date"]) == 0: ready_predict["purchase_date"] = [None] if fine_result["retailername"] and not ready_predict["retailername"]: ready_predict["retailername"] = [None] - fine_result["purchase_date"] = [fine_result["purchase_date"] for _ in range(len(ready_predict["purchase_date"]))] + # if ready_predict["retailername"] and not fine_result["retailername"]: + # fine_result["retailername"] = [None] + fine_result["purchase_date"] = [fine_result["purchase_date"] for _ in range(len(ready_predict["purchase_date"]))] + # fine_result["retailername"] = None if len(ready_predict["purchase_date"]))] # else: # fine_result = {} # for key in ready_predict.keys(): @@ -668,6 +668,12 @@ def calculate_accuracy(key_name, inference, target): target[key_name] = [] else: target[key_name] = [target[key_name]] + # Realign lenght for mis predicted/feedback/reivew result + if len(target[key_name]) == 0 and len(inference[key_name]) > 0: + target[key_name] = [None for _ in range(len(inference[key_name]))] + elif len(inference[key_name]) == 0 and len(target[key_name]) > 0: + target[key_name] = [None for _ in range(len(inference[key_name]))] + for i, v in enumerate(inference[key_name]): # TODO: target[key_name][i] is None, "" x = post_processing_str(key_name, inference[key_name][i], is_gt=False) @@ -777,6 +783,11 @@ def calculate_a_request(report, request): "sold_to_party": [], }, "reviewed": {"imei_number": [], + "purchase_date": [], + "retailername": [], + "sold_to_party": [], + }, + "acumulated":{"imei_number": [], "purchase_date": [], "retailername": [], "sold_to_party": [], @@ -784,10 +795,15 @@ def calculate_a_request(report, request): "err": [], "time_cost": {}, "total_images": 0, - "bad_images": 0} - images = SubscriptionRequestFile.objects.filter(request=request) + "bad_images": 0, + "bad_image_list": [], + } + images = SubscriptionRequestFile.objects.filter(request=request, file_category=FileCategory.Origin.value) report_files = [] for image in images: + if image.reason in settings.ACC_EXCLUDE_RESEASONS: + continue + status, att = calculate_subcription_file(image) if status != 200: continue @@ -805,6 +821,8 @@ def calculate_a_request(report, request): _sub = map_subsidiary_short_to_long(request.redemption_id[:2]) else: print(f"[WARM]: empty redemption_id, check request: {request.request_id}") + if att["is_bad_image"]: + request_att["bad_image_list"].append(image.file_name) new_report_file = ReportFile(report=report, subsidiary=_sub, correspond_request_id=request.request_id, @@ -838,11 +856,16 @@ def calculate_a_request(report, request): request_att["acc"]["reviewed"]["retailername"] += att["acc"]["reviewed"]["retailername"] request_att["acc"]["reviewed"]["sold_to_party"] += att["acc"]["reviewed"]["sold_to_party"] + request_att["acc"]["acumulated"]["imei_number"] += att["acc"]["reviewed"]["imei_number"] if att["acc"]["reviewed"]["imei_number"] else att["acc"]["feedback"]["imei_number"] + request_att["acc"]["acumulated"]["purchase_date"] += att["acc"]["reviewed"]["purchase_date"] if att["acc"]["reviewed"]["purchase_date"] else att["acc"]["feedback"]["purchase_date"] + request_att["acc"]["acumulated"]["retailername"] += att["acc"]["reviewed"]["retailername"] if att["acc"]["reviewed"]["retailername"] else att["acc"]["feedback"]["retailername"] + request_att["acc"]["acumulated"]["sold_to_party"] += att["acc"]["reviewed"]["sold_to_party"] if att["acc"]["reviewed"]["sold_to_party"] else att["acc"]["feedback"]["sold_to_party"] + request_att["bad_images"] += int(att["is_bad_image"]) request_att["total_images"] += 1 request_att["err"] += att["err"] except Exception as e: - print(e) + print(f"[ERROR]: failed to calculate request: {request.request_id} - request_file: {image.file_name} because of {e}") continue return request_att, report_files @@ -870,11 +893,20 @@ def calculate_subcription_file(subcription_request_file): att["acc"]["reviewed"][key_name], _ = calculate_accuracy(key_name, inference_result, reviewed_result) except Exception as e: att["err"].append(str(e)) + # print(f"[DEBUG]: predict_result: {subcription_request_file.predict_result}") # print(f"[DEBUG]: e: {e} -key_name: {key_name}") + subcription_request_file.feedback_accuracy = att["acc"]["feedback"] + subcription_request_file.reviewed_accuracy = att["acc"]["reviewed"] + subcription_request_file.save() avg_reviewed = calculate_avg_accuracy(att["acc"], "reviewed", ["retailername", "sold_to_party", "purchase_date", "imei_number"]) avg_feedback = calculate_avg_accuracy(att["acc"], "feedback", ["retailername", "sold_to_party", "purchase_date", "imei_number"]) if avg_feedback is not None or avg_reviewed is not None: - avg_acc = max([x for x in [avg_feedback, avg_reviewed] if x is not None]) + avg_acc = 0 + if avg_feedback is not None: + avg_acc = avg_feedback + if avg_reviewed is not None: + avg_acc = avg_reviewed + if avg_acc < BAD_THRESHOLD: att["is_bad_image"] = True # exclude bad images @@ -947,6 +979,12 @@ def calculate_attributions(request): # for one request, return in order return acc, data, time_cost, image_quality_num, error +def mean_list(l): + l = [x for x in l if x is not None] + if len(l) == 0: + return 0 + return sum(l)/len(l) + def shadow_report(report_id, query): c_connector.make_a_report_2( (report_id, query)) \ No newline at end of file diff --git a/cope2n-api/fwd_api/utils/file.py b/cope2n-api/fwd_api/utils/file.py index 024461e..5eeef41 100644 --- a/cope2n-api/fwd_api/utils/file.py +++ b/cope2n-api/fwd_api/utils/file.py @@ -250,6 +250,37 @@ def save_file_with_path(file_name: str, file: TemporaryUploadedFile, quality, fo raise ServiceUnavailableException() return file_path +def save_images_to_csv_briefly(id, image_filenames): + # columns = ["request_id", "file_name", "predict_result", "feedback_result", "reviewed_result", "feedback_accuracy", "reviewed_accuracy"] + columns = ["request_id", "file_name", "predict_result", "feedback_result", "reviewed_result", "feedback_accuracy", "reviewed_accuracy"] + + # get the SubcriptionRequestFile list + images = SubscriptionRequestFile.objects.filter(file_name__in=image_filenames) + # Create a CSV writer object + folder_path = os.path.join(settings.MEDIA_ROOT, "report", id) + file_path = os.path.join(folder_path, "bad_images.csv") + os.makedirs(folder_path, exist_ok = True) + + csv_file = open(file_path, "w", newline="") + csv_writer = csv.DictWriter(csv_file, fieldnames=columns) + csv_writer.writeheader() + + # Write data to the CSV file + for subscription_request_file in images: + row = { + "request_id": subscription_request_file.request.request_id, + "file_name" : subscription_request_file.file_name, + "predict_result": subscription_request_file.predict_result, + "feedback_result": subscription_request_file.feedback_result, + "reviewed_result": subscription_request_file.reviewed_result, + # "feedback_accuracy": subscription_request_file.feedback_accuracy, + # "reviewed_accuracy": subscription_request_file.reviewed_accuracy, + } + csv_writer.writerow(row) + # Close the CSV file + csv_file.close() + # save to S3 + save_report_to_S3(id, file_path) def resize_and_save_file(file_name: str, rq: SubscriptionRequest, file: TemporaryUploadedFile, quality: int): try: diff --git a/cope2n-api/scripts/script.py b/cope2n-api/scripts/script.py index e25ad22..a906a44 100644 --- a/cope2n-api/scripts/script.py +++ b/cope2n-api/scripts/script.py @@ -15,8 +15,8 @@ login_token = None # Define the login credentials login_credentials = { 'username': 'sbt', - 'password': '7Eg4AbWIXDnufgn' - # 'password': 'abc' + # 'password': '7Eg4AbWIXDnufgn' + 'password': 'abc' } # Define the command to call the update API diff --git a/cope2n-fe/package-lock.json b/cope2n-fe/package-lock.json index aa23e73..d24b175 100644 --- a/cope2n-fe/package-lock.json +++ b/cope2n-fe/package-lock.json @@ -13,6 +13,7 @@ "@ant-design/plots": "^1.2.3", "@ant-design/pro-layout": "^7.10.3", "@babel/core": "^7.13.10", + "@cyntler/react-doc-viewer": "^1.14.1", "@tanstack/react-query": "^4.20.4", "antd": "^5.4.0", "axios": "^1.2.2", @@ -2613,6 +2614,123 @@ "node": ">=10" } }, + "node_modules/@cyntler/react-doc-viewer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@cyntler/react-doc-viewer/-/react-doc-viewer-1.14.1.tgz", + "integrity": "sha512-1LiYewtiLM6FZgkJmlAiibv3zeiDinII+WKjViLeaD7O9yP+F9TqYyYSTR05crZODltzHenn/Tcx9YesV9tKtA==", + "dependencies": { + "@types/mustache": "^4.2.3", + "@types/papaparse": "^5.3.9", + "mustache": "^4.2.0", + "papaparse": "^5.4.1", + "react-pdf": "7.5.0", + "styled-components": "^6.0.8" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "react": ">=16.13.1", + "react-dom": ">=16.13.1" + } + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/react-pdf": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.5.0.tgz", + "integrity": "sha512-hX7SfQGd9T6pdd3H5HcR1VzrRCehkhnBh/tsyz9GO9cXrYHgoxupboVL2VCQpBBSak+/UQSMCj+3JTOdheuwwQ==", + "dependencies": { + "clsx": "^2.0.0", + "make-cancellable-promise": "^1.3.1", + "make-event-props": "^1.6.0", + "merge-refs": "^1.2.1", + "pdfjs-dist": "3.11.174", + "prop-types": "^15.6.2", + "tiny-invariant": "^1.0.0", + "tiny-warning": "^1.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/styled-components": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz", + "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==", + "dependencies": { + "@emotion/is-prop-valid": "1.2.1", + "@emotion/unitless": "0.8.0", + "@types/stylis": "4.2.0", + "css-to-react-native": "3.2.0", + "csstype": "3.1.2", + "postcss": "8.4.31", + "shallowequal": "1.1.0", + "stylis": "4.3.1", + "tslib": "2.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/@cyntler/react-doc-viewer/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, "node_modules/@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", @@ -3580,6 +3698,59 @@ "node": ">= 0.4" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/@messageformat/parser": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", @@ -4456,6 +4627,11 @@ "@types/lodash": "*" } }, + "node_modules/@types/mustache": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.2.5.tgz", + "integrity": "sha512-PLwiVvTBg59tGFL/8VpcGvqOu3L4OuveNvPi0EYbWchRdEVP++yRUXJPFl+CApKEq13017/4Nf7aQ5lTtHUNsA==" + }, "node_modules/@types/node": { "version": "18.19.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.12.tgz", @@ -4464,6 +4640,14 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -4482,13 +4666,13 @@ "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.2.48", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4508,7 +4692,7 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true + "devOptional": true }, "node_modules/@types/semver": { "version": "7.5.6", @@ -4516,6 +4700,11 @@ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "node_modules/@types/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" + }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", @@ -5074,6 +5263,12 @@ "resolved": "https://registry.npmjs.org/@yiiran/get-file-type/-/get-file-type-1.0.3.tgz", "integrity": "sha512-NPXIjasI3phA5sGTrEIdJ/DZlO7HG0NnoPmHXdxOkREyojt5ktw0UWhGRySffpO2SsW9VCUQdVgxyoOdnI+Uxg==" }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -5121,6 +5316,18 @@ "node": ">=0.8" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -5185,7 +5392,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -5303,6 +5510,25 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -5870,6 +6096,21 @@ } ] }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -5954,6 +6195,15 @@ "fsevents": "~2.3.1" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -6041,6 +6291,14 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/codepage": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", @@ -6062,6 +6320,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", @@ -6107,6 +6374,12 @@ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", "dev": true }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, "node_modules/contour_plot": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", @@ -6354,6 +6627,18 @@ "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-equal": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", @@ -6445,6 +6730,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -6459,6 +6750,15 @@ "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -7606,6 +7906,36 @@ "node": ">=10" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7664,6 +7994,26 @@ "integrity": "sha512-zgllBYwfHR5P3CncJiGbGVPpa3iFYW1yuPaIv8DiTVRrcg5/6uETNL5zvIoKflG1aifXVUZTlIroDehw4WygGA==", "dev": true }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7928,6 +8278,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -7968,6 +8324,19 @@ "void-elements": "3.1.0" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/hyperformula": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/hyperformula/-/hyperformula-2.6.1.tgz", @@ -8409,7 +8778,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -9238,6 +9607,29 @@ "node": ">=12" } }, + "node_modules/make-cancellable-promise": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", + "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -9245,6 +9637,14 @@ "dev": true, "peer": true }, + "node_modules/make-event-props": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", + "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, "node_modules/make-plural": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", @@ -9282,6 +9682,22 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/merge-refs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz", + "integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9338,6 +9754,18 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9357,11 +9785,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, + "devOptional": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -9412,17 +9880,30 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -9454,6 +9935,26 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "peer": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gettext": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.0.tgz", @@ -9468,6 +9969,21 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -9477,6 +9993,18 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/numbro": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/numbro/-/numbro-2.1.2.tgz", @@ -9833,8 +10361,7 @@ "node_modules/papaparse": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", - "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", - "dev": true + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -9911,17 +10438,30 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pdfast": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/pdfast/-/pdfast-0.2.0.tgz", "integrity": "sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==" }, "node_modules/pdfjs-dist": { - "version": "2.10.377", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.10.377.tgz", - "integrity": "sha512-i0jRShtvgfsVQUNCoFYH4SVhPO3U0yhtiFLfZ0RR0B+68N+Vnwq+8B3cjWjLEwWGh8wg1XQ/sYMYKUlHn/Qpsw==", - "peerDependencies": { - "worker-loader": "^3.0.7" + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" } }, "node_modules/picocolors": { @@ -10922,6 +11462,14 @@ "xlsx": "^0.18.5" } }, + "node_modules/react-office-viewer/node_modules/pdfjs-dist": { + "version": "2.10.377", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.10.377.tgz", + "integrity": "sha512-i0jRShtvgfsVQUNCoFYH4SVhPO3U0yhtiFLfZ0RR0B+68N+Vnwq+8B3cjWjLEwWGh8wg1XQ/sYMYKUlHn/Qpsw==", + "peerDependencies": { + "worker-loader": "^3.0.7" + } + }, "node_modules/react-office-viewer/node_modules/react": { "version": "16.14.0", "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", @@ -11001,7 +11549,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, + "devOptional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -11226,7 +11774,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -11486,6 +12034,12 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, "node_modules/set-function-length": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", @@ -11562,7 +12116,38 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "devOptional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } }, "node_modules/size-sensor": { "version": "1.0.2", @@ -11591,7 +12176,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -11635,7 +12219,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, + "devOptional": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -11655,7 +12239,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "devOptional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -11669,7 +12253,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "devOptional": true }, "node_modules/string.prototype.matchall": { "version": "4.0.10", @@ -11737,7 +12321,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "devOptional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -11898,6 +12482,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/terser": { "version": "5.27.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", @@ -12001,6 +12608,16 @@ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", "optional": true }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -12038,6 +12655,12 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -12618,10 +13241,16 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, "node_modules/webpack": { - "version": "5.90.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", - "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.2.tgz", + "integrity": "sha512-ziXu8ABGr0InCMEYFnHrYweinHK2PWrMqnwdHk2oK3rRhv/1B+2FnfwYv5oD+RrknK/Pp/Hmyvu+eAsaMYhzCw==", "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -12696,6 +13325,16 @@ "node": ">=4.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -12785,6 +13424,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", diff --git a/cope2n-fe/package.json b/cope2n-fe/package.json index 9213a6b..c7e2006 100644 --- a/cope2n-fe/package.json +++ b/cope2n-fe/package.json @@ -27,26 +27,27 @@ }, "dependencies": { "@ant-design/colors": "^6.0.0", - "@ant-design/icons": "^4.8.0", - "@ant-design/plots": "^1.2.3", - "@ant-design/pro-layout": "^7.10.3", - "@babel/core": "^7.13.10", - "@tanstack/react-query": "^4.20.4", - "antd": "^5.4.0", - "axios": "^1.2.2", - "chart.js": "^4.4.1", - "history": "^5.3.0", - "lodash-es": "^4.17.21", - "mousetrap": "^1.6.5", - "process": "^0.11.10", - "react": "^18.2.0", - "react-chartjs-2": "^5.2.0", - "react-dom": "^18.2.0", - "react-json-view-lite": "^1.2.1", - "react-office-viewer": "^1.0.4", - "react-router-dom": "^6.6.1", - "styled-components": "^5.3.6", - "uuid": "^9.0.0" + "@ant-design/icons": "^4.8.0", + "@ant-design/plots": "^1.2.3", + "@ant-design/pro-layout": "^7.10.3", + "@babel/core": "^7.13.10", + "@cyntler/react-doc-viewer": "^1.14.1", + "@tanstack/react-query": "^4.20.4", + "antd": "^5.4.0", + "axios": "^1.2.2", + "chart.js": "^4.4.1", + "history": "^5.3.0", + "lodash-es": "^4.17.21", + "mousetrap": "^1.6.5", + "process": "^0.11.10", + "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", + "react-dom": "^18.2.0", + "react-json-view-lite": "^1.2.1", + "react-office-viewer": "^1.0.4", + "react-router-dom": "^6.6.1", + "styled-components": "^5.3.6", + "uuid": "^9.0.0" }, "devDependencies": { "@babel/plugin-syntax-jsx": "^7.12.13", diff --git a/cope2n-fe/public/dummy.pdf b/cope2n-fe/public/dummy.pdf new file mode 100644 index 0000000..774c2ea Binary files /dev/null and b/cope2n-fe/public/dummy.pdf differ diff --git a/cope2n-fe/src/components/left-menu/index.tsx b/cope2n-fe/src/components/left-menu/index.tsx index 09c5e95..d0390dc 100644 --- a/cope2n-fe/src/components/left-menu/index.tsx +++ b/cope2n-fe/src/components/left-menu/index.tsx @@ -1,4 +1,4 @@ -import { AppstoreOutlined, BarChartOutlined, RotateRightOutlined } from '@ant-design/icons'; +import { AppstoreOutlined, BarChartOutlined, RotateRightOutlined, FileSearchOutlined } from '@ant-design/icons'; import { t } from '@lingui/macro'; import { Menu, MenuProps } from 'antd'; import React from 'react'; @@ -34,8 +34,8 @@ function LeftMenu() { const generalSubItems = [ getItem(t`Dashboard`, '/dashboard', ), - // getItem(t`Reviews`, '/reviews', ), getItem(t`Reports`, '/reports', ), + // getItem(t`Review`, '/reviews', ), getItem(t`Inference`, '/inference', ), // getItem(t`Users`, '/users', ), ]; diff --git a/cope2n-fe/src/components/report-detail/report-overview-table.tsx b/cope2n-fe/src/components/report-detail/report-overview-table.tsx index 544a750..ab5fd25 100644 --- a/cope2n-fe/src/components/report-detail/report-overview-table.tsx +++ b/cope2n-fe/src/components/report-detail/report-overview-table.tsx @@ -69,7 +69,8 @@ const columns: TableColumnsType = [ width: '130px', className: 'hide-border-right', render: (_, record) => { - return {record.snImeiTC + record.invoiceTC}; + const value = record.snImeiTC + record.invoiceTC; + return {value ? value : '-'}; }, }, { @@ -81,12 +82,20 @@ const columns: TableColumnsType = [ key: 'snImeiTC', width: '50px', className: 'show-border-left', + render: (_, record) => { + const value = record.snImeiTC; + return {value ? value : '-'}; + }, }, { title: 'Invoice', dataIndex: 'invoiceTC', key: 'invoiceTC', width: '50px', + render: (_, record) => { + const value = record.invoiceTC; + return {value ? value : '-'}; + }, }, ], }, diff --git a/cope2n-fe/src/pages/reviews/index.tsx b/cope2n-fe/src/pages/reviews/index.tsx index 91de596..616fb15 100644 --- a/cope2n-fe/src/pages/reviews/index.tsx +++ b/cope2n-fe/src/pages/reviews/index.tsx @@ -1,5 +1,181 @@ -function Reviews() { - return Reviews; -} +import { t } from '@lingui/macro'; +import { Button, message, Upload, Input, Table } from 'antd'; +import { SbtPageHeader } from 'components/page-header'; +import { useState } from 'react'; +import { Layout } from 'antd'; +import FileViewer from '@cyntler/react-doc-viewer'; +const { Sider, Content } = Layout; -export default Reviews; +const siderStyle: React.CSSProperties = { + backgroundColor: '#fafafa', + padding: 10, + width: 200, +}; + + +const fileList = [ + { + name: "invoice.pdf", + url: "/dummpy.pdf", + type: "invoice", + isBadQuality: false, + }, + { + name: "invoice.pdf", + url: "/dummpy.pdf", + type: "imei", + isBadQuality: true, + } +] + +const dataSource = [ + { + key: '1', + value: 'Mike', + }, + { + key: '2', + value: 'Mike', + }, + { + key: '3', + value: 'Mike', + }, +]; + +const columns = [ + { + title: 'Key', + dataIndex: 'key', + key: 'key', + }, + { + title: 'Predicted', + dataIndex: 'value', + key: 'value', + }, + { + title: 'Submitted', + dataIndex: 'value', + key: 'value', + }, + { + title: 'Revised', + dataIndex: 'value', + key: 'value', + }, +]; + + +const FileCard = ({ file, isSelected, onClick }) => { + return ( + + + {file.type.toUpperCase()} + {file.name} + + + ); + +}; + +const InferencePage = () => { + const [selectedFileId, setSelectedFileId] = useState(0); + const selectFileByIndex = (index) => { + setSelectedFileId(index); + }; + + return ( + <> + {/* */} + + + + + + + {fileList.map((file, index) => ( + { + setSelectedFileId(index); + } + } /> + ))} + + + + Overview + + + + + + + Confirm result + + + + + > + ); +}; + +export default InferencePage; diff --git a/deploy_images.sh b/deploy_images.sh index df4360f..648d6ba 100755 --- a/deploy_images.sh +++ b/deploy_images.sh @@ -6,7 +6,7 @@ tag=$1 echo "[INFO] Tag received from Python: $tag" -# echo "[INFO] Updating everything the remote..." +echo "[INFO] Updating everything the remote..." git submodule update --recursive --remote echo "[INFO] Pushing AI image with tag: $tag..." diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index f6d8386..932f381 100755 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -174,8 +174,8 @@ services: - ./cope2n-api:/app working_dir: /app - # command: sh -c "celery -A fwd_api.celery_worker.worker worker -l INFO -c 5" - command: bash -c "tail -f > /dev/null" + command: sh -c "celery -A fwd_api.celery_worker.worker worker -l INFO -c 5" + # command: bash -c "tail -f > /dev/null" # Back-end persistent db-sbt: