diff --git a/cope2n-api/fwd_api/api/accuracy_view.py b/cope2n-api/fwd_api/api/accuracy_view.py index 9fb9268..67c9ae4 100755 --- a/cope2n-api/fwd_api/api/accuracy_view.py +++ b/cope2n-api/fwd_api/api/accuracy_view.py @@ -75,10 +75,10 @@ class AccuracyViewSet(viewsets.ViewSet): type=OpenApiTypes.STR, ), OpenApiParameter( - name='redemption_id', + name='with_redemption_id', location=OpenApiParameter.QUERY, description='Specific redemption id', - type=OpenApiTypes.STR, + type=OpenApiTypes.BOOL, ), OpenApiParameter( name='page', @@ -94,6 +94,13 @@ class AccuracyViewSet(viewsets.ViewSet): type=OpenApiTypes.INT, required=False ), + OpenApiParameter( + name='max_accuracy', + location=OpenApiParameter.QUERY, + description='Return requests with acccuracy smaller than this number', + type=OpenApiTypes.FLOAT, + required=False + ), ], responses=None, tags=['Accuracy'] ) @@ -105,10 +112,11 @@ class AccuracyViewSet(viewsets.ViewSet): page_number = int(request.GET.get('page', 1)) page_size = int(request.GET.get('page_size', 10)) request_id = request.GET.get('request_id', None) - redemption_id = request.GET.get('redemption_id', None) + with_redemption_id = request.GET.get('with_redemption_id', True) is_reviewed = request.GET.get('is_reviewed', None) include_test = request.GET.get('includes_test', False) - subsidiary = request.data.get("subsidiary", "all") + subsidiary = request.GET.get("subsidiary", "all") + max_accuracy = float(request.GET.get("max_accuracy", 100)) subsidiary = map_subsidiary_long_to_short(subsidiary) base_query = Q(status=200) @@ -131,8 +139,17 @@ class AccuracyViewSet(viewsets.ViewSet): if request_id: base_query &= Q(request_id=request_id) - if redemption_id: - base_query &= Q(redemption_id=redemption_id) + if isinstance(with_redemption_id, str): + with_redemption_id = True if with_redemption_id=="true" else False + if with_redemption_id: + base_query &= Q(redemption_id__isnull=False) + else: + base_query &= Q(redemption_id__isnull=True) + elif isinstance(with_redemption_id, bool): + if with_redemption_id: + base_query &= Q(redemption_id__isnull=False) + else: + base_query &= Q(redemption_id__isnull=True) if isinstance(include_test, str): include_test = True if include_test=="true" else False if not include_test: @@ -148,8 +165,14 @@ class AccuracyViewSet(viewsets.ViewSet): elif is_reviewed == "all": pass if isinstance(subsidiary, str): - if subsidiary and subsidiary.lower().replace(" ", "")!="all": - base_query &= Q(redemption_id__startswith=subsidiary) + if subsidiary.lower() != "seao": + if subsidiary not in list(settings.SUBS.keys()): + raise InvalidException(excArgs="subsidiary") + if subsidiary and subsidiary.lower().replace(" ", "")!="all": + base_query &= Q(redemption_id__startswith=map_subsidiary_long_to_short(subsidiary)) + + if isinstance(max_accuracy, float): + base_query &= Q(raw_accuracy__lt=(max_accuracy/100)) | Q(raw_accuracy__isnull=True) subscription_requests = SubscriptionRequest.objects.filter(base_query).order_by('created_at') @@ -159,38 +182,38 @@ class AccuracyViewSet(viewsets.ViewSet): page = paginator.get_page(page_number) data = [] - for request in page: + for rq in page: imeis = [] purchase_date = [] retailer = "" try: - if request.reviewed_result is not None: - imeis = request.reviewed_result.get("imei_number", []) - purchase_date = request.reviewed_result.get("purchase_date", []) - retailer = request.reviewed_result.get("retailername", "") - elif request.feedback_result is not None : - imeis = request.feedback_result.get("imei_number", []) - purchase_date = request.feedback_result.get("purchase_date", []) - retailer = request.feedback_result.get("retailername", "") - elif request.predict_result is not None: - if request.predict_result.get("status", 404) == 200: - imeis = request.predict_result.get("content", {}).get("document", [])[0].get("content", [])[3].get("value", []) - purchase_date = request.predict_result.get("content", {}).get("document", [])[0].get("content", [])[2].get("value", []) - retailer = request.predict_result.get("content", {}).get("document", [])[0].get("content", [])[0].get("value", []) + if rq.reviewed_result is not None: + imeis = rq.reviewed_result.get("imei_number", []) + purchase_date = rq.reviewed_result.get("purchase_date", []) + retailer = rq.reviewed_result.get("retailername", "") + elif rq.feedback_result is not None : + imeis = rq.feedback_result.get("imei_number", []) + purchase_date = rq.feedback_result.get("purchase_date", []) + retailer = rq.feedback_result.get("retailername", "") + elif rq.predict_result is not None: + if rq.predict_result.get("status", 404) == 200: + imeis = rq.predict_result.get("content", {}).get("document", [])[0].get("content", [])[3].get("value", []) + purchase_date = rq.predict_result.get("content", {}).get("document", [])[0].get("content", [])[2].get("value", []) + retailer = rq.predict_result.get("content", {}).get("document", [])[0].get("content", [])[0].get("value", []) except Exception as e: print(f"[ERROR]: {e}") - print(f"[ERROR]: {request}") + print(f"[ERROR]: {rq}") data.append({ - 'RequestID': request.request_id, - 'RedemptionID': request.redemption_id, + 'RequestID': rq.request_id, + 'RedemptionID': rq.redemption_id, 'IMEIs': imeis, 'Purchase Date': purchase_date, 'Retailer': retailer, - 'Client Request Time (ms)': request.client_request_time, - 'Server Processing Time (ms)': request.preprocessing_time + request.ai_inference_time, - 'Is Reviewed': request.is_reviewed, + 'Client Request Time (ms)': rq.client_request_time, + 'Server Processing Time (ms)': rq.preprocessing_time + rq.ai_inference_time, + 'Is Reviewed': rq.is_reviewed, # 'Is Bad Quality': request.is_bad_image_quality, - 'created_at': request.created_at.isoformat() + 'created_at': rq.created_at.isoformat() }) response = { @@ -791,7 +814,7 @@ class AccuracyViewSet(viewsets.ViewSet): for subscription_request_file in subscription_request_files: if subscription_request_file.doc_type == 'invoice': - subscription_request_file.reviewed_result = reviewed_result + subscription_request_file.reviewed_result = copy.deepcopy(reviewed_result) subscription_request_file.reviewed_result['imei_number'] = [] elif subscription_request_file.doc_type == 'imei': subscription_request_file.reviewed_result = { @@ -822,6 +845,10 @@ class AccuracyViewSet(viewsets.ViewSet): 'type': 'string', 'default': '''"Sample reason"''', }, + 'solution': { + 'type': 'string', + 'default': '''"Sample Solution"''', + }, }, }, }, @@ -846,13 +873,17 @@ class AccuracyViewSet(viewsets.ViewSet): if "reason" not in data: raise InvalidException(excArgs=f'reason') + if "solution" not in data: + raise InvalidException(excArgs=f'solution') reason = data["reason"] + solution = data["solution"] is_available = False for subscription_request_file in subscription_request_files: if subscription_request_file.file_name.split(".")[0] == request_image_id: subscription_request_file.reason = reason + subscription_request_file.counter_measures = solution subscription_request_file.save() is_available = True if not is_available: 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 9c919de..5ffd09b 100755 --- a/cope2n-api/fwd_api/celery_worker/process_report_tasks.py +++ b/cope2n-api/fwd_api/celery_worker/process_report_tasks.py @@ -110,7 +110,7 @@ def create_accuracy_report(report_id, **kwargs): if request.status != 200 or not (request.reviewed_result or request.feedback_result): # Failed requests or lack of reviewed_result/feedback_result continue - request_att, _report_files = calculate_a_request(report, request) + request_att, _report_files, _att = calculate_a_request(report, request) report_files += _report_files report_engine.add(request, _report_files, report) request.feedback_accuracy = {"imei_number": mean_list(request_att["acc"]["feedback"].get("imei_number", [None])), @@ -123,6 +123,24 @@ def create_accuracy_report(report_id, **kwargs): "retailername": mean_list(request_att["acc"]["reviewed"].get("retailername", [None])), "sold_to_party": mean_list(request_att["acc"]["reviewed"].get("sold_to_party", [None])), "invoice_no": mean_list(request_att["acc"]["reviewed"].get("invoice_no", [None]))} + rq_accuracy = {"feedback": [], + "reviewed": []} + + for t in _att["acc"].keys(): + for cl in _att["acc"][t].keys(): + rq_accuracy[t] += _att["acc"][t][cl] + + # for rpf in _report_files: + # for cl in rpf.feedback_accuracy.keys(): + # rq_accuracy["feedback"] += rpf.feedback_accuracy[cl] + # for cl in rpf.reviewed_accuracy.keys(): + # rq_accuracy["reviewed"] += rpf.reviewed_accuracy[cl] + + if len(rq_accuracy["reviewed"]) > 0: + request.raw_accuracy = mean_list(rq_accuracy["reviewed"]) + elif len(rq_accuracy["feedback"]) > 0: + request.raw_accuracy = mean_list(rq_accuracy["feedback"]) + request.save() number_images += request_att["total_images"] number_bad_images += request_att["bad_images"] diff --git a/cope2n-api/fwd_api/migrations/0189_subscriptionrequest_accuracy.py b/cope2n-api/fwd_api/migrations/0189_subscriptionrequest_accuracy.py new file mode 100644 index 0000000..d03c36b --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0189_subscriptionrequest_accuracy.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2024-04-09 07:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0188_subscriptionrequest_subsidiary'), + ] + + operations = [ + migrations.AddField( + model_name='subscriptionrequest', + name='accuracy', + field=models.FloatField(default=None, null=True), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0190_rename_accuracy_subscriptionrequest_raw_accuracy.py b/cope2n-api/fwd_api/migrations/0190_rename_accuracy_subscriptionrequest_raw_accuracy.py new file mode 100644 index 0000000..839a524 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0190_rename_accuracy_subscriptionrequest_raw_accuracy.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2024-04-09 08:55 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0189_subscriptionrequest_accuracy'), + ] + + operations = [ + migrations.RenameField( + model_name='subscriptionrequest', + old_name='accuracy', + new_name='raw_accuracy', + ), + ] diff --git a/cope2n-api/fwd_api/models/SubscriptionRequest.py b/cope2n-api/fwd_api/models/SubscriptionRequest.py index 871b2f0..c8de868 100755 --- a/cope2n-api/fwd_api/models/SubscriptionRequest.py +++ b/cope2n-api/fwd_api/models/SubscriptionRequest.py @@ -24,6 +24,7 @@ class SubscriptionRequest(models.Model): feedback_accuracy = models.JSONField(null=True) reviewed_accuracy = models.JSONField(null=True) + raw_accuracy = models.FloatField(default=None, null=True) ai_inference_profile = models.JSONField(null=True) preprocessing_time = models.FloatField(default=-1) diff --git a/cope2n-api/fwd_api/utils/accuracy.py b/cope2n-api/fwd_api/utils/accuracy.py index 05811f2..cc07a03 100755 --- a/cope2n-api/fwd_api/utils/accuracy.py +++ b/cope2n-api/fwd_api/utils/accuracy.py @@ -828,7 +828,6 @@ def calculate_a_request(report, request): report_files = [] for image in images: status, att = calculate_subcription_file(image) - att["acc"]["feedback"], fb_max_indexes = acc_maximize_list_values(att["acc"]["feedback"]) att["acc"]["reviewed"], rv_max_indexes = acc_maximize_list_values(att["acc"]["reviewed"]) @@ -873,6 +872,21 @@ def calculate_a_request(report, request): reason = image.reason counter_measure = image.counter_measures + if att["is_bad_image"] or image.reason in settings.ACC_EXCLUDE_RESEASONS: + if image.reason in settings.ACC_EXCLUDE_RESEASONS: + # if image.reason in settings.ACC_EXCLUDE_RESEASONS: + # print(f"[DEBUG]: {image.reason}") + # TODO: Exclude bad image accuracy from average accuracy + _att["avg_acc"] = None + for t in _att["acc"].keys(): + for k in _att["acc"][t].keys(): + _att["acc"][t][k] = [] + else: + if request_att["time_cost"].get(image.doc_type, None): + request_att["time_cost"][image.doc_type].append(image.processing_time) + else: + request_att["time_cost"][image.doc_type] = [image.processing_time] + new_report_file = ReportFile(report=report, subsidiary=_sub, correspond_request_id=request.request_id, @@ -882,9 +896,9 @@ def calculate_a_request(report, request): predict_result=image.predict_result, feedback_result=image.feedback_result, reviewed_result=reviewed_result, - feedback_accuracy=att["acc"]["feedback"], - reviewed_accuracy=att["acc"]["reviewed"], - acc=att["avg_acc"], + feedback_accuracy=_att["acc"]["feedback"], + reviewed_accuracy=_att["acc"]["reviewed"], + acc=_att["avg_acc"], is_bad_image=att["is_bad_image"], is_reviewed= review_status_map(att["is_reviewed"]), time_cost=image.processing_time, @@ -894,22 +908,12 @@ def calculate_a_request(report, request): review_status=att["is_reviewed"], ) report_files.append(new_report_file) - - if att["is_bad_image"] or image.reason in settings.ACC_EXCLUDE_RESEASONS: - if att["is_bad_image"]: - request_att["bad_image_list"].append(image.file_name) - # if image.reason in settings.ACC_EXCLUDE_RESEASONS: - # print(f"[DEBUG]: {image.reason}") - # TODO: Exclude bad image accuracy from average accuracy + if att["is_bad_image"]: + request_att["bad_image_list"].append(image.file_name) _att["avg_acc"] = None for t in _att["acc"].keys(): for k in _att["acc"][t].keys(): _att["acc"][t][k] = [] - else: - if request_att["time_cost"].get(image.doc_type, None): - request_att["time_cost"][image.doc_type].append(image.processing_time) - else: - request_att["time_cost"][image.doc_type] = [image.processing_time] try: request_att["acc"]["feedback"]["imei_number"] += _att["acc"]["feedback"]["imei_number"] @@ -938,7 +942,7 @@ def calculate_a_request(report, request): print(f"[ERROR]: failed to calculate request: {request.request_id} - request_file: {image.file_name} because of {e}") continue - return request_att, report_files + return request_att, report_files, att def calculate_subcription_file(subcription_request_file): att = {"acc": {"feedback": {}, @@ -968,7 +972,7 @@ def calculate_subcription_file(subcription_request_file): avg_reviewed = calculate_avg_accuracy(att["acc"], "reviewed", valid_keys) avg_feedback = calculate_avg_accuracy(att["acc"], "feedback", valid_keys) - + if avg_feedback is not None or avg_reviewed is not None: avg_acc = 0 if avg_feedback is not None: