endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# endoreg_db/views/media_management.py
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
5
7
|
from django.db import transaction
|
|
6
8
|
from django.db.models import Q
|
|
9
|
+
from django.utils import timezone
|
|
7
10
|
from numpy import delete
|
|
8
11
|
from rest_framework import status
|
|
9
12
|
from rest_framework.decorators import api_view, permission_classes
|
|
10
13
|
from rest_framework.response import Response
|
|
11
14
|
from rest_framework.views import APIView
|
|
12
|
-
from django.utils import timezone
|
|
13
|
-
from datetime import timedelta
|
|
14
15
|
|
|
15
|
-
from endoreg_db.models import
|
|
16
|
+
from endoreg_db.models import RawPdfFile, VideoFile, VideoState
|
|
16
17
|
from endoreg_db.utils.permissions import DEBUG_PERMISSIONS
|
|
17
18
|
|
|
18
19
|
logger = logging.getLogger(__name__)
|
|
@@ -21,10 +22,12 @@ logger = logging.getLogger(__name__)
|
|
|
21
22
|
# Media Cleanup and Management API
|
|
22
23
|
# ---------------------------------------------------------------------------
|
|
23
24
|
|
|
25
|
+
|
|
24
26
|
class MediaManagementView(APIView):
|
|
25
27
|
"""
|
|
26
28
|
Comprehensive Media Management API for cleanup and maintenance operations
|
|
27
29
|
"""
|
|
30
|
+
|
|
28
31
|
permission_classes = DEBUG_PERMISSIONS
|
|
29
32
|
|
|
30
33
|
def get(self, request):
|
|
@@ -38,8 +41,8 @@ class MediaManagementView(APIView):
|
|
|
38
41
|
except Exception as e:
|
|
39
42
|
logger.error(f"Error getting media status overview: {e}")
|
|
40
43
|
return Response(
|
|
41
|
-
{"error": "Failed to get status overview"},
|
|
42
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
44
|
+
{"error": "Failed to get status overview"},
|
|
45
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
def delete(self, request):
|
|
@@ -47,10 +50,10 @@ class MediaManagementView(APIView):
|
|
|
47
50
|
DELETE /api/media-management/cleanup/
|
|
48
51
|
Cleanup unfinished, failed, or stale media processing entries
|
|
49
52
|
"""
|
|
50
|
-
cleanup_type = request.query_params.get(
|
|
51
|
-
force = request.query_params.get(
|
|
52
|
-
media_type = request.query_params.get(
|
|
53
|
-
file_id = request.query_params.get(
|
|
53
|
+
cleanup_type = request.query_params.get("type", "unfinished")
|
|
54
|
+
force = request.query_params.get("force", "false").lower() == "true"
|
|
55
|
+
media_type = request.query_params.get("file_type", "all")
|
|
56
|
+
file_id = request.query_params.get("file_id", None)
|
|
54
57
|
|
|
55
58
|
try:
|
|
56
59
|
result = self._perform_cleanup(cleanup_type, force, media_type, file_id)
|
|
@@ -59,40 +62,40 @@ class MediaManagementView(APIView):
|
|
|
59
62
|
except Exception as e:
|
|
60
63
|
logger.error(f"Error during media cleanup: {e}")
|
|
61
64
|
return Response(
|
|
62
|
-
{"error": "Cleanup operation failed"},
|
|
63
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
65
|
+
{"error": "Cleanup operation failed"},
|
|
66
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
64
67
|
)
|
|
65
68
|
|
|
66
69
|
def _get_status_overview(self) -> Dict[str, Any]:
|
|
67
70
|
"""Get comprehensive status overview"""
|
|
68
71
|
video_stats = self._get_video_stats()
|
|
69
72
|
pdf_stats = self._get_pdf_stats()
|
|
70
|
-
|
|
73
|
+
|
|
71
74
|
# Stale processing detection (older than 2 hours)
|
|
72
75
|
stale_threshold = timezone.now() - timedelta(hours=2)
|
|
73
76
|
# Use VideoState boolean fields instead of non-existent name field
|
|
74
77
|
stale_videos = VideoFile.objects.filter(
|
|
75
78
|
uploaded_at__lt=stale_threshold,
|
|
76
79
|
state__frames_extracted=True,
|
|
77
|
-
state__sensitive_meta_processed=False
|
|
80
|
+
state__sensitive_meta_processed=False,
|
|
78
81
|
).count()
|
|
79
|
-
|
|
82
|
+
|
|
80
83
|
return {
|
|
81
84
|
"videos": video_stats,
|
|
82
85
|
"pdfs": pdf_stats,
|
|
83
86
|
"cleanup_opportunities": {
|
|
84
87
|
"stale_processing": stale_videos,
|
|
85
88
|
"failed_videos": video_stats["failed"],
|
|
86
|
-
"unfinished_total": video_stats["unfinished"] + pdf_stats["unfinished"]
|
|
89
|
+
"unfinished_total": video_stats["unfinished"] + pdf_stats["unfinished"],
|
|
87
90
|
},
|
|
88
91
|
"total_files": video_stats["total"] + pdf_stats["total"],
|
|
89
|
-
"timestamp": timezone.now().isoformat()
|
|
92
|
+
"timestamp": timezone.now().isoformat(),
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
def _get_video_stats(self) -> Dict[str, int]:
|
|
93
96
|
"""Get video file statistics using VideoState boolean fields"""
|
|
94
|
-
videos = VideoFile.objects.select_related(
|
|
95
|
-
|
|
97
|
+
videos = VideoFile.objects.select_related("state").all()
|
|
98
|
+
|
|
96
99
|
stats = {
|
|
97
100
|
"total": videos.count(),
|
|
98
101
|
"not_started": 0,
|
|
@@ -100,39 +103,42 @@ class MediaManagementView(APIView):
|
|
|
100
103
|
"done": 0,
|
|
101
104
|
"failed": 0,
|
|
102
105
|
"validated": 0,
|
|
103
|
-
"unfinished": 0
|
|
106
|
+
"unfinished": 0,
|
|
104
107
|
}
|
|
105
|
-
|
|
108
|
+
|
|
106
109
|
for video in videos:
|
|
107
110
|
if not video.state:
|
|
108
111
|
stats["not_started"] += 1
|
|
109
112
|
stats["unfinished"] += 1
|
|
110
113
|
continue
|
|
111
|
-
|
|
114
|
+
|
|
112
115
|
# Use the anonymization_status property
|
|
113
116
|
video_status = video.state.anonymization_status
|
|
114
|
-
|
|
115
|
-
if video_status.value ==
|
|
117
|
+
|
|
118
|
+
if video_status.value == "not_started":
|
|
116
119
|
stats["not_started"] += 1
|
|
117
120
|
stats["unfinished"] += 1
|
|
118
|
-
elif video_status.value in [
|
|
121
|
+
elif video_status.value in [
|
|
122
|
+
"extracting_frames",
|
|
123
|
+
"processing_anonymization",
|
|
124
|
+
]:
|
|
119
125
|
stats["processing"] += 1
|
|
120
126
|
stats["unfinished"] += 1
|
|
121
|
-
elif video_status.value ==
|
|
127
|
+
elif video_status.value == "done_processing_anonymization":
|
|
122
128
|
stats["done"] += 1
|
|
123
|
-
elif video_status.value ==
|
|
129
|
+
elif video_status.value == "failed":
|
|
124
130
|
stats["failed"] += 1
|
|
125
131
|
stats["unfinished"] += 1
|
|
126
|
-
elif video_status.value ==
|
|
132
|
+
elif video_status.value == "validated":
|
|
127
133
|
stats["validated"] += 1
|
|
128
134
|
else:
|
|
129
135
|
stats["unfinished"] += 1
|
|
130
136
|
return stats
|
|
131
137
|
|
|
132
138
|
def _get_pdf_stats(self) -> Dict[str, int]:
|
|
133
|
-
"""Get
|
|
139
|
+
"""Get report file statistics"""
|
|
134
140
|
pdfs = RawPdfFile.objects.all()
|
|
135
|
-
|
|
141
|
+
|
|
136
142
|
stats = {
|
|
137
143
|
"total": pdfs.count(),
|
|
138
144
|
"not_started": 0,
|
|
@@ -140,14 +146,18 @@ class MediaManagementView(APIView):
|
|
|
140
146
|
"done": 0,
|
|
141
147
|
"failed": 0,
|
|
142
148
|
"validated": 0,
|
|
143
|
-
"unfinished": 0
|
|
149
|
+
"unfinished": 0,
|
|
144
150
|
}
|
|
145
|
-
|
|
151
|
+
|
|
146
152
|
for pdf in pdfs:
|
|
147
|
-
#
|
|
153
|
+
# report status logic based on anonymized_text presence and validation
|
|
148
154
|
has_anonymized = bool(pdf.anonymized_text and pdf.anonymized_text.strip())
|
|
149
|
-
is_validated =
|
|
150
|
-
|
|
155
|
+
is_validated = (
|
|
156
|
+
getattr(pdf.sensitive_meta, "is_verified", False)
|
|
157
|
+
if pdf.sensitive_meta
|
|
158
|
+
else False
|
|
159
|
+
)
|
|
160
|
+
|
|
151
161
|
if not has_anonymized:
|
|
152
162
|
stats["not_started"] += 1
|
|
153
163
|
stats["unfinished"] += 1
|
|
@@ -157,22 +167,24 @@ class MediaManagementView(APIView):
|
|
|
157
167
|
stats["done"] += 1
|
|
158
168
|
else:
|
|
159
169
|
stats["unfinished"] += 1
|
|
160
|
-
|
|
170
|
+
|
|
161
171
|
return stats
|
|
162
172
|
|
|
163
|
-
def _perform_cleanup(
|
|
173
|
+
def _perform_cleanup(
|
|
174
|
+
self, cleanup_type: str, force: bool, media_type: str, file_id: int
|
|
175
|
+
) -> Dict[str, Any]:
|
|
164
176
|
"""Perform the actual cleanup operations"""
|
|
165
|
-
|
|
177
|
+
|
|
166
178
|
result = {
|
|
167
179
|
"cleanup_type": cleanup_type,
|
|
168
180
|
"force": force,
|
|
169
181
|
"removed_items": [],
|
|
170
|
-
"summary": {}
|
|
182
|
+
"summary": {},
|
|
171
183
|
}
|
|
172
|
-
|
|
173
|
-
if media_type not in [
|
|
184
|
+
|
|
185
|
+
if media_type not in ["video", "pdf", "all"]:
|
|
174
186
|
raise ValueError(f"Unknown media type: {media_type}")
|
|
175
|
-
|
|
187
|
+
|
|
176
188
|
if file_id is not None:
|
|
177
189
|
try:
|
|
178
190
|
file_id = int(file_id)
|
|
@@ -181,81 +193,92 @@ class MediaManagementView(APIView):
|
|
|
181
193
|
|
|
182
194
|
video_file_obj = None
|
|
183
195
|
pdf_file_obj = None
|
|
184
|
-
|
|
185
|
-
if media_type == 'video':
|
|
186
|
-
video_file_obj = VideoFile.get_video_by_id(self, video_id=file_id) if file_id else None
|
|
187
|
-
elif media_type == 'pdf':
|
|
188
|
-
pdf_file_obj = RawPdfFile.get_pdf_by_id(file_id) if file_id else None
|
|
189
196
|
|
|
197
|
+
if media_type == "video":
|
|
198
|
+
video_file_obj = (
|
|
199
|
+
VideoFile.get_video_by_pk(pk=file_id) if file_id else None
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
elif media_type == "pdf":
|
|
203
|
+
pdf_file_obj = RawPdfFile.get_pdf_by_pk(pk=file_id) if file_id else None
|
|
190
204
|
|
|
191
205
|
with transaction.atomic():
|
|
192
206
|
if video_file_obj:
|
|
193
207
|
video_file_obj.delete()
|
|
194
208
|
if pdf_file_obj:
|
|
195
209
|
pdf_file_obj.delete()
|
|
196
|
-
|
|
197
|
-
if cleanup_type ==
|
|
210
|
+
|
|
211
|
+
if cleanup_type == "unfinished":
|
|
198
212
|
result.update(self._cleanup_unfinished_media(force))
|
|
199
|
-
elif cleanup_type ==
|
|
213
|
+
elif cleanup_type == "failed":
|
|
200
214
|
result.update(self._cleanup_failed_media(force))
|
|
201
|
-
elif cleanup_type ==
|
|
215
|
+
elif cleanup_type == "stale":
|
|
202
216
|
result.update(self._cleanup_stale_processing(force))
|
|
203
|
-
elif cleanup_type ==
|
|
217
|
+
elif cleanup_type == "all":
|
|
204
218
|
unfinished = self._cleanup_unfinished_media(force)
|
|
205
219
|
failed = self._cleanup_failed_media(force)
|
|
206
220
|
stale = self._cleanup_stale_processing(force)
|
|
207
|
-
|
|
221
|
+
|
|
208
222
|
result["removed_items"] = (
|
|
209
|
-
unfinished.get("removed_items", [])
|
|
210
|
-
failed.get("removed_items", [])
|
|
211
|
-
stale.get("removed_items", [])
|
|
223
|
+
unfinished.get("removed_items", [])
|
|
224
|
+
+ failed.get("removed_items", [])
|
|
225
|
+
+ stale.get("removed_items", [])
|
|
212
226
|
)
|
|
213
227
|
result["summary"] = {
|
|
214
228
|
"unfinished": unfinished.get("summary", {}),
|
|
215
229
|
"failed": failed.get("summary", {}),
|
|
216
|
-
"stale": stale.get("summary", {})
|
|
230
|
+
"stale": stale.get("summary", {}),
|
|
217
231
|
}
|
|
218
232
|
else:
|
|
219
233
|
raise ValueError(f"Unknown cleanup type: {cleanup_type}")
|
|
220
|
-
|
|
234
|
+
|
|
221
235
|
return result
|
|
222
236
|
|
|
223
237
|
def _cleanup_unfinished_media(self, force: bool) -> Dict[str, Any]:
|
|
224
238
|
"""Remove unfinished media processing entries"""
|
|
225
239
|
removed_videos = []
|
|
226
240
|
removed_pdfs = []
|
|
227
|
-
|
|
241
|
+
|
|
228
242
|
# Find unfinished videos using VideoState boolean fields
|
|
229
|
-
unfinished_videos = VideoFile.objects.select_related(
|
|
230
|
-
|
|
243
|
+
unfinished_videos = VideoFile.objects.select_related("state").all()
|
|
244
|
+
|
|
231
245
|
for video in unfinished_videos:
|
|
232
246
|
if not video.state:
|
|
233
247
|
if force: # Only remove videos without state if force=True
|
|
234
|
-
removed_videos.append(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
248
|
+
removed_videos.append(
|
|
249
|
+
{
|
|
250
|
+
"id": video.id,
|
|
251
|
+
"type": "video",
|
|
252
|
+
"filename": video.original_file_name,
|
|
253
|
+
"status": "no_state",
|
|
254
|
+
"uploaded_at": video.uploaded_at.isoformat(),
|
|
255
|
+
}
|
|
256
|
+
)
|
|
241
257
|
video.delete()
|
|
242
258
|
continue
|
|
243
|
-
|
|
259
|
+
|
|
244
260
|
video_status = video.state.anonymization_status
|
|
245
|
-
is_unfinished = video_status.value in [
|
|
246
|
-
|
|
261
|
+
is_unfinished = video_status.value in [
|
|
262
|
+
"not_started",
|
|
263
|
+
"extracting_frames",
|
|
264
|
+
"processing_anonymization",
|
|
265
|
+
"failed",
|
|
266
|
+
]
|
|
267
|
+
|
|
247
268
|
# Remove unfinished videos
|
|
248
|
-
if is_unfinished and (force or video_status.value !=
|
|
249
|
-
removed_videos.append(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
269
|
+
if is_unfinished and (force or video_status.value != "not_started"):
|
|
270
|
+
removed_videos.append(
|
|
271
|
+
{
|
|
272
|
+
"id": video.id,
|
|
273
|
+
"type": "video",
|
|
274
|
+
"filename": video.original_file_name,
|
|
275
|
+
"status": video_status.value,
|
|
276
|
+
"uploaded_at": video.uploaded_at.isoformat(),
|
|
277
|
+
}
|
|
278
|
+
)
|
|
256
279
|
if force:
|
|
257
280
|
video.delete()
|
|
258
|
-
|
|
281
|
+
|
|
259
282
|
# Return the results
|
|
260
283
|
return {
|
|
261
284
|
"removed_items": removed_videos + removed_pdfs,
|
|
@@ -263,29 +286,31 @@ class MediaManagementView(APIView):
|
|
|
263
286
|
"videos_removed": len(removed_videos),
|
|
264
287
|
"pdfs_removed": len(removed_pdfs),
|
|
265
288
|
"total_removed": len(removed_videos) + len(removed_pdfs),
|
|
266
|
-
"dry_run": not force
|
|
267
|
-
}
|
|
289
|
+
"dry_run": not force,
|
|
290
|
+
},
|
|
268
291
|
}
|
|
269
292
|
|
|
270
293
|
def _cleanup_failed_media(self, force: bool) -> Dict[str, Any]:
|
|
271
294
|
"""Remove failed media processing entries"""
|
|
272
295
|
removed_items = []
|
|
273
|
-
|
|
296
|
+
|
|
274
297
|
# Find failed videos using VideoState boolean fields
|
|
275
|
-
failed_videos = VideoFile.objects.select_related(
|
|
276
|
-
|
|
298
|
+
failed_videos = VideoFile.objects.select_related("state").all()
|
|
299
|
+
|
|
277
300
|
for video in failed_videos:
|
|
278
|
-
if video.state and video.state.anonymization_status.value ==
|
|
279
|
-
removed_items.append(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
301
|
+
if video.state and video.state.anonymization_status.value == "failed":
|
|
302
|
+
removed_items.append(
|
|
303
|
+
{
|
|
304
|
+
"id": video.id,
|
|
305
|
+
"type": "video",
|
|
306
|
+
"filename": video.original_file_name,
|
|
307
|
+
"status": "failed",
|
|
308
|
+
"uploaded_at": video.uploaded_at.isoformat(),
|
|
309
|
+
}
|
|
310
|
+
)
|
|
286
311
|
if force:
|
|
287
312
|
video.delete()
|
|
288
|
-
|
|
313
|
+
|
|
289
314
|
if force:
|
|
290
315
|
# Count actual deletions
|
|
291
316
|
videos_deleted = len([v for v in removed_items if v["type"] == "video"])
|
|
@@ -294,8 +319,8 @@ class MediaManagementView(APIView):
|
|
|
294
319
|
"summary": {
|
|
295
320
|
"videos_removed": videos_deleted,
|
|
296
321
|
"total_removed": videos_deleted,
|
|
297
|
-
"dry_run": False
|
|
298
|
-
}
|
|
322
|
+
"dry_run": False,
|
|
323
|
+
},
|
|
299
324
|
}
|
|
300
325
|
else:
|
|
301
326
|
return {
|
|
@@ -303,33 +328,40 @@ class MediaManagementView(APIView):
|
|
|
303
328
|
"summary": {
|
|
304
329
|
"videos_removed": len(removed_items),
|
|
305
330
|
"total_removed": len(removed_items),
|
|
306
|
-
"dry_run": True
|
|
307
|
-
}
|
|
331
|
+
"dry_run": True,
|
|
332
|
+
},
|
|
308
333
|
}
|
|
309
334
|
|
|
310
335
|
def _cleanup_stale_processing(self, force: bool) -> Dict[str, Any]:
|
|
311
336
|
"""Remove stale processing entries (older than 2 hours)"""
|
|
312
337
|
stale_threshold = timezone.now() - timedelta(hours=2)
|
|
313
338
|
removed_items = []
|
|
314
|
-
|
|
339
|
+
|
|
315
340
|
# Find stale videos using VideoState boolean fields
|
|
316
341
|
stale_videos = VideoFile.objects.filter(
|
|
317
342
|
uploaded_at__lt=stale_threshold,
|
|
318
343
|
state__frames_extracted=True,
|
|
319
|
-
state__sensitive_meta_processed=False
|
|
320
|
-
).select_related(
|
|
321
|
-
|
|
344
|
+
state__sensitive_meta_processed=False,
|
|
345
|
+
).select_related("state")
|
|
346
|
+
|
|
322
347
|
for video in stale_videos:
|
|
323
|
-
video_status =
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
348
|
+
video_status = (
|
|
349
|
+
video.state.anonymization_status if video.state else "no_state"
|
|
350
|
+
)
|
|
351
|
+
removed_items.append(
|
|
352
|
+
{
|
|
353
|
+
"id": video.id,
|
|
354
|
+
"type": "video",
|
|
355
|
+
"filename": video.original_file_name,
|
|
356
|
+
"status": f"stale_{video_status.value if hasattr(video_status, 'value') else video_status}",
|
|
357
|
+
"uploaded_at": video.uploaded_at.isoformat(),
|
|
358
|
+
"stale_duration_hours": (
|
|
359
|
+
timezone.now() - video.uploaded_at
|
|
360
|
+
).total_seconds()
|
|
361
|
+
/ 3600,
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
|
|
333
365
|
if force:
|
|
334
366
|
videos_deleted = stale_videos.delete()[0]
|
|
335
367
|
return {
|
|
@@ -337,8 +369,8 @@ class MediaManagementView(APIView):
|
|
|
337
369
|
"summary": {
|
|
338
370
|
"stale_videos_removed": videos_deleted,
|
|
339
371
|
"total_removed": videos_deleted,
|
|
340
|
-
"dry_run": False
|
|
341
|
-
}
|
|
372
|
+
"dry_run": False,
|
|
373
|
+
},
|
|
342
374
|
}
|
|
343
375
|
else:
|
|
344
376
|
return {
|
|
@@ -346,12 +378,12 @@ class MediaManagementView(APIView):
|
|
|
346
378
|
"summary": {
|
|
347
379
|
"stale_videos_removed": len(removed_items),
|
|
348
380
|
"total_removed": len(removed_items),
|
|
349
|
-
"dry_run": True
|
|
350
|
-
}
|
|
381
|
+
"dry_run": True,
|
|
382
|
+
},
|
|
351
383
|
}
|
|
352
384
|
|
|
353
385
|
|
|
354
|
-
@api_view([
|
|
386
|
+
@api_view(["DELETE"])
|
|
355
387
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
356
388
|
def force_remove_media(request, file_id: int):
|
|
357
389
|
"""
|
|
@@ -364,43 +396,44 @@ def force_remove_media(request, file_id: int):
|
|
|
364
396
|
video = VideoFile.objects.get(id=file_id)
|
|
365
397
|
filename = video.original_file_name
|
|
366
398
|
video.delete()
|
|
367
|
-
|
|
368
|
-
return Response(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
399
|
+
|
|
400
|
+
return Response(
|
|
401
|
+
{
|
|
402
|
+
"detail": f"Video file '{filename}' (ID: {file_id}) removed successfully",
|
|
403
|
+
"file_type": "video",
|
|
404
|
+
"file_id": file_id,
|
|
405
|
+
}
|
|
406
|
+
)
|
|
373
407
|
except VideoFile.DoesNotExist:
|
|
374
408
|
pass
|
|
375
|
-
|
|
409
|
+
|
|
376
410
|
# Try to find and delete from RawPdfFile
|
|
377
411
|
try:
|
|
378
412
|
pdf = RawPdfFile.objects.get(id=file_id)
|
|
379
|
-
filename = getattr(pdf.file,
|
|
413
|
+
filename = getattr(pdf.file, "name", "Unknown")
|
|
380
414
|
pdf.delete()
|
|
381
|
-
|
|
382
|
-
return Response(
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
415
|
+
|
|
416
|
+
return Response(
|
|
417
|
+
{
|
|
418
|
+
"detail": f"report file '{filename}' (ID: {file_id}) removed successfully",
|
|
419
|
+
"file_type": "pdf",
|
|
420
|
+
"file_id": file_id,
|
|
421
|
+
}
|
|
422
|
+
)
|
|
387
423
|
except RawPdfFile.DoesNotExist:
|
|
388
424
|
pass
|
|
389
|
-
|
|
390
|
-
return Response(
|
|
391
|
-
|
|
392
|
-
status=status.HTTP_404_NOT_FOUND
|
|
393
|
-
)
|
|
394
|
-
|
|
425
|
+
|
|
426
|
+
return Response({"detail": "File not found"}, status=status.HTTP_404_NOT_FOUND)
|
|
427
|
+
|
|
395
428
|
except Exception as e:
|
|
396
429
|
logger.error(f"Error force removing media {file_id}: {e}")
|
|
397
430
|
return Response(
|
|
398
|
-
{"error": "Force removal failed"},
|
|
399
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
431
|
+
{"error": "Force removal failed"},
|
|
432
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
400
433
|
)
|
|
401
434
|
|
|
402
435
|
|
|
403
|
-
@api_view([
|
|
436
|
+
@api_view(["POST"])
|
|
404
437
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
405
438
|
def reset_processing_status(request, file_id: int):
|
|
406
439
|
"""
|
|
@@ -411,44 +444,47 @@ def reset_processing_status(request, file_id: int):
|
|
|
411
444
|
# Try VideoFile first
|
|
412
445
|
try:
|
|
413
446
|
video = VideoFile.objects.get(id=file_id)
|
|
414
|
-
|
|
447
|
+
|
|
415
448
|
# Reset to 'not_started' state
|
|
416
|
-
not_started_state, created = VideoState.objects.get_or_create(
|
|
449
|
+
not_started_state, created = VideoState.objects.get_or_create(
|
|
450
|
+
name="not_started"
|
|
451
|
+
)
|
|
417
452
|
video.state = not_started_state
|
|
418
453
|
video.save()
|
|
419
|
-
|
|
420
|
-
return Response(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
454
|
+
|
|
455
|
+
return Response(
|
|
456
|
+
{
|
|
457
|
+
"detail": "Video file status reset to 'not_started'",
|
|
458
|
+
"file_type": "video",
|
|
459
|
+
"file_id": file_id,
|
|
460
|
+
"new_status": "not_started",
|
|
461
|
+
}
|
|
462
|
+
)
|
|
426
463
|
except VideoFile.DoesNotExist:
|
|
427
464
|
pass
|
|
428
|
-
|
|
429
|
-
#
|
|
465
|
+
|
|
466
|
+
# report files don't have state, but we can clear anonymized_text
|
|
430
467
|
try:
|
|
431
468
|
pdf = RawPdfFile.objects.get(id=file_id)
|
|
432
469
|
pdf.anonymized_text = ""
|
|
433
470
|
pdf.save()
|
|
434
|
-
|
|
435
|
-
return Response(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
471
|
+
|
|
472
|
+
return Response(
|
|
473
|
+
{
|
|
474
|
+
"detail": "report file processing reset",
|
|
475
|
+
"file_type": "pdf",
|
|
476
|
+
"file_id": file_id,
|
|
477
|
+
"new_status": "not_started",
|
|
478
|
+
}
|
|
479
|
+
)
|
|
441
480
|
except RawPdfFile.DoesNotExist:
|
|
442
481
|
pass
|
|
443
|
-
|
|
444
|
-
return Response(
|
|
445
|
-
|
|
446
|
-
status=status.HTTP_404_NOT_FOUND
|
|
447
|
-
)
|
|
448
|
-
|
|
482
|
+
|
|
483
|
+
return Response({"detail": "File not found"}, status=status.HTTP_404_NOT_FOUND)
|
|
484
|
+
|
|
449
485
|
except Exception as e:
|
|
450
486
|
logger.error(f"Error resetting status for media {file_id}: {e}")
|
|
451
487
|
return Response(
|
|
452
|
-
{"error": "Status reset failed"},
|
|
453
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
488
|
+
{"error": "Status reset failed"},
|
|
489
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
454
490
|
)
|