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
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
|
+
|
|
3
|
+
from datetime import date as Date
|
|
4
|
+
import datetime
|
|
5
|
+
|
|
6
|
+
from .k_anonymity import _build_sensitive_meta_qi_queryset
|
|
7
|
+
from .fake import fake_name_with_similar_dob_and_gender
|
|
8
|
+
|
|
9
|
+
from endoreg_db.models import SensitiveMeta
|
|
10
|
+
|
|
11
|
+
def k_pseudonymize(
|
|
12
|
+
instance: SensitiveMeta,
|
|
13
|
+
*,
|
|
14
|
+
k_threshold: int = 3,
|
|
15
|
+
dob_year_tolerance: int = 3,
|
|
16
|
+
qi_subset: Optional[Tuple[str, ...]] = None,
|
|
17
|
+
locale: str = "de_DE",
|
|
18
|
+
seed: Optional[int] = None,
|
|
19
|
+
save: bool = True,
|
|
20
|
+
) -> Tuple[SensitiveMeta, int, bool]:
|
|
21
|
+
"""
|
|
22
|
+
Ensure a SensitiveMeta instance reaches at least `k_threshold` anonymity
|
|
23
|
+
for the given quasi-identifier subset by pseudonymizing patient
|
|
24
|
+
first_name, last_name and DOB if necessary.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
instance:
|
|
28
|
+
The SensitiveMeta instance to process.
|
|
29
|
+
k_threshold:
|
|
30
|
+
Minimal k for the chosen QI subset.
|
|
31
|
+
dob_year_tolerance:
|
|
32
|
+
Used both for k-anonymity DOB band and for Faker's DOB perturbation.
|
|
33
|
+
qi_subset:
|
|
34
|
+
Which QIs to use for k-anonymity check.
|
|
35
|
+
Elements from: {"first_name", "last_name", "center", "gender", "dob_band"}.
|
|
36
|
+
Default = all of them.
|
|
37
|
+
locale:
|
|
38
|
+
Faker locale for a realistic name.
|
|
39
|
+
seed:
|
|
40
|
+
Optional seed for reproducibility.
|
|
41
|
+
save:
|
|
42
|
+
If True, save the instance after pseudonymization.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
(instance, k_value_after, is_k_anonymous_after)
|
|
46
|
+
"""
|
|
47
|
+
if qi_subset is None:
|
|
48
|
+
qi_subset = tuple(QI_FLAGS)
|
|
49
|
+
|
|
50
|
+
# --- 1) Compute k for the requested subset BEFORE pseudonymization ---
|
|
51
|
+
use_first_name = "first_name" in qi_subset
|
|
52
|
+
use_last_name = "last_name" in qi_subset
|
|
53
|
+
use_center = "center" in qi_subset
|
|
54
|
+
use_gender = "gender" in qi_subset
|
|
55
|
+
use_dob_band = "dob_band" in qi_subset
|
|
56
|
+
|
|
57
|
+
qs_before = _build_sensitive_meta_qi_queryset(
|
|
58
|
+
instance,
|
|
59
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
60
|
+
include_self=True,
|
|
61
|
+
use_first_name=use_first_name,
|
|
62
|
+
use_last_name=use_last_name,
|
|
63
|
+
use_center=use_center,
|
|
64
|
+
use_gender=use_gender,
|
|
65
|
+
use_dob_band=use_dob_band,
|
|
66
|
+
)
|
|
67
|
+
k_before = qs_before.count()
|
|
68
|
+
|
|
69
|
+
if k_before >= k_threshold:
|
|
70
|
+
# Already sufficiently anonymous, nothing to do
|
|
71
|
+
return instance, k_before, True
|
|
72
|
+
|
|
73
|
+
# --- 2) Pseudonymize name + DOB using Faker ---
|
|
74
|
+
# Gender string for Faker
|
|
75
|
+
if instance.patient_gender and getattr(instance.patient_gender, "name", None):
|
|
76
|
+
gender_name = instance.patient_gender.name
|
|
77
|
+
else:
|
|
78
|
+
# Fallback if gender missing -> bias to 'male' but you can change that
|
|
79
|
+
gender_name = "male"
|
|
80
|
+
|
|
81
|
+
# Original DOB as date (fallback to today's date if missing)
|
|
82
|
+
if instance.patient_dob is not None:
|
|
83
|
+
orig_dob: Date = instance.patient_dob.date()
|
|
84
|
+
else:
|
|
85
|
+
orig_dob = Date.today()
|
|
86
|
+
|
|
87
|
+
first_name, last_name, fake_dob = fake_name_with_similar_dob_and_gender(
|
|
88
|
+
gender=gender_name,
|
|
89
|
+
dob=orig_dob,
|
|
90
|
+
year_tolerance=dob_year_tolerance,
|
|
91
|
+
locale=locale,
|
|
92
|
+
seed=seed,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Assign to instance (SensitiveMeta.patient_dob is a DateTimeField)
|
|
96
|
+
instance.patient_first_name = first_name
|
|
97
|
+
instance.patient_last_name = last_name
|
|
98
|
+
instance.patient_dob = datetime(
|
|
99
|
+
fake_dob.year, fake_dob.month, fake_dob.day
|
|
100
|
+
) # naive is usually fine for DOB
|
|
101
|
+
|
|
102
|
+
if save:
|
|
103
|
+
instance.save(update_fields=["patient_first_name", "patient_last_name", "patient_dob"])
|
|
104
|
+
|
|
105
|
+
# --- 3) Recompute k AFTER pseudonymization ---
|
|
106
|
+
qs_after = _build_sensitive_meta_qi_queryset(
|
|
107
|
+
instance,
|
|
108
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
109
|
+
include_self=True,
|
|
110
|
+
use_first_name=use_first_name,
|
|
111
|
+
use_last_name=use_last_name,
|
|
112
|
+
use_center=use_center,
|
|
113
|
+
use_gender=use_gender,
|
|
114
|
+
use_dob_band=use_dob_band,
|
|
115
|
+
)
|
|
116
|
+
k_after = qs_after.count()
|
|
117
|
+
is_k_anon_after = k_after >= k_threshold
|
|
118
|
+
|
|
119
|
+
logger.info(
|
|
120
|
+
"k_pseudonymize: SensitiveMeta pk=%s, subset=%s, k_before=%s, k_after=%s, threshold=%s",
|
|
121
|
+
instance.pk,
|
|
122
|
+
qi_subset,
|
|
123
|
+
k_before,
|
|
124
|
+
k_after,
|
|
125
|
+
k_threshold,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return instance, k_after, is_k_anon_after
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# endoreg_db/services/report_import_service.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
|
|
8
|
+
from endoreg_db.import_files.context.file_lock import file_lock
|
|
9
|
+
from endoreg_db.import_files.context.import_context import ImportContext
|
|
10
|
+
from endoreg_db.import_files.processing.report_processing.report_anonymization import (
|
|
11
|
+
ReportAnonymizer,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from endoreg_db.import_files.file_storage.create_report_file import (
|
|
15
|
+
create_or_retrieve_report_file,
|
|
16
|
+
)
|
|
17
|
+
from endoreg_db.import_files.file_storage.state_management import (
|
|
18
|
+
finalize_report_success,
|
|
19
|
+
finalize_failure,
|
|
20
|
+
mark_instance_processing_started,
|
|
21
|
+
)
|
|
22
|
+
from endoreg_db.import_files.context.validate_directories import validate_directories
|
|
23
|
+
|
|
24
|
+
from endoreg_db.import_files.file_storage.storage import create_sensitive_copy
|
|
25
|
+
from endoreg_db.models.media import RawPdfFile
|
|
26
|
+
from endoreg_db.utils.paths import (
|
|
27
|
+
SENSITIVE_REPORT_DIR,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ReportImportService:
|
|
35
|
+
"""
|
|
36
|
+
Service for importing and anonymizing report (PDF) files.
|
|
37
|
+
|
|
38
|
+
Responsibilities:
|
|
39
|
+
- Acquire file lock
|
|
40
|
+
- Create sensitive copy
|
|
41
|
+
- Create/reuse RawPdfFile (dedupe by hash) + history
|
|
42
|
+
- Run anonymization pipeline (primary + fallback)
|
|
43
|
+
- Finalize state and move anonymized file
|
|
44
|
+
- Cleanup on error
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self) -> None:
|
|
48
|
+
self.logger = logger
|
|
49
|
+
self.anonymizer = ReportAnonymizer()
|
|
50
|
+
self.processing_context: Optional[ImportContext] = None
|
|
51
|
+
self.current_report: Optional[RawPdfFile] = None
|
|
52
|
+
|
|
53
|
+
validate_directories()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def import_and_anonymize(
|
|
57
|
+
self,
|
|
58
|
+
file_path: Union[Path, str],
|
|
59
|
+
center_name: str,
|
|
60
|
+
retry: bool = False,
|
|
61
|
+
delete_source: bool = True,
|
|
62
|
+
) -> "RawPdfFile | None":
|
|
63
|
+
"""
|
|
64
|
+
Public entrypoint: wrap import_and_anonymize logic.
|
|
65
|
+
"""
|
|
66
|
+
# First, initialize import context. this will be updated during import and keep track of current paths, file type and center and processor.
|
|
67
|
+
ctx = ImportContext(
|
|
68
|
+
file_path=Path(file_path),
|
|
69
|
+
center_name=center_name,
|
|
70
|
+
delete_source=delete_source,
|
|
71
|
+
file_type="report"
|
|
72
|
+
)
|
|
73
|
+
self.logger.info("validating and preparing file")
|
|
74
|
+
if not ctx.file_path.exists():
|
|
75
|
+
raise FileNotFoundError(f"Video file not found: {file_path}")
|
|
76
|
+
|
|
77
|
+
ctx.sensitive_path = create_sensitive_copy(
|
|
78
|
+
ctx.file_path,
|
|
79
|
+
SENSITIVE_REPORT_DIR
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
with file_lock(ctx.file_path):
|
|
83
|
+
logger.info("Acquired file lock for %s", ctx.file_path)
|
|
84
|
+
|
|
85
|
+
# create or retrieve RawPdfFile + update history
|
|
86
|
+
ctx.current_report, needs_processing = create_or_retrieve_report_file(ctx)
|
|
87
|
+
ctx.current_report.get_or_create_state()
|
|
88
|
+
assert(ctx.current_report.state is not None)
|
|
89
|
+
ctx.current_report = ctx.current_report
|
|
90
|
+
|
|
91
|
+
ctx.retry = retry
|
|
92
|
+
# Retry is a forced overwrite of needs processing - therefore the retry will cause full deletion of processed files using finalize failure.
|
|
93
|
+
if retry and needs_processing and not ctx.current_report.state.anonymization_validated:
|
|
94
|
+
# ensure clean slate for forced reprocessing
|
|
95
|
+
finalize_failure(ctx)
|
|
96
|
+
ctx.current_report, needs_processing = create_or_retrieve_report_file(ctx)
|
|
97
|
+
assert(needs_processing is True)
|
|
98
|
+
elif not needs_processing and not retry:
|
|
99
|
+
return ctx.current_report
|
|
100
|
+
|
|
101
|
+
mark_instance_processing_started(ctx.current_report, ctx)
|
|
102
|
+
try:
|
|
103
|
+
# --- Anonymization with fallback ---
|
|
104
|
+
try:
|
|
105
|
+
ctx = self.anonymizer.anonymize_report(ctx)
|
|
106
|
+
logger.info(
|
|
107
|
+
"Primary report anonymization succeeded for %s",
|
|
108
|
+
ctx.file_path,
|
|
109
|
+
)
|
|
110
|
+
except Exception as primary_exc:
|
|
111
|
+
logger.exception(
|
|
112
|
+
"Primary report anonymization failed for %s: %s "
|
|
113
|
+
"- trying basic anonymization",
|
|
114
|
+
ctx.file_path,
|
|
115
|
+
primary_exc,
|
|
116
|
+
)
|
|
117
|
+
try:
|
|
118
|
+
ctx = self.anonymizer.anonymize_report(ctx)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"PDF Extraction failed for the second time. {e}")
|
|
121
|
+
raise
|
|
122
|
+
|
|
123
|
+
logger.info(
|
|
124
|
+
"Basic report anonymization succeeded for %s",
|
|
125
|
+
ctx.file_path,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# --- Finalize success: history + move anonymized file ---
|
|
129
|
+
finalize_report_success(ctx)
|
|
130
|
+
|
|
131
|
+
return ctx.current_report
|
|
132
|
+
|
|
133
|
+
except Exception as exc:
|
|
134
|
+
logger.exception(
|
|
135
|
+
"Report import/anonymization failed for %s: %s", ctx.file_path, exc
|
|
136
|
+
)
|
|
137
|
+
# mark failure in history
|
|
138
|
+
finalize_failure(ctx)
|
|
139
|
+
raise
|
|
140
|
+
|
|
141
|
+
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# endoreg_db/services/video_import.py
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional, Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from endoreg_db.import_files.context import (
|
|
8
|
+
ImportContext,
|
|
9
|
+
file_lock,
|
|
10
|
+
)
|
|
11
|
+
from endoreg_db.import_files.file_storage.state_management import (
|
|
12
|
+
finalize_failure,
|
|
13
|
+
finalize_video_success
|
|
14
|
+
)
|
|
15
|
+
from endoreg_db.import_files.file_storage.storage import create_sensitive_copy
|
|
16
|
+
from endoreg_db.import_files.file_storage.create_video_file import (
|
|
17
|
+
create_or_retrieve_video_file,
|
|
18
|
+
)
|
|
19
|
+
from endoreg_db.import_files.context.validate_directories import validate_directories
|
|
20
|
+
from endoreg_db.import_files.file_storage.state_management import (
|
|
21
|
+
mark_instance_processing_started,
|
|
22
|
+
)
|
|
23
|
+
from endoreg_db.models import VideoFile
|
|
24
|
+
from endoreg_db.import_files.processing.video_processing.video_anonymization import VideoAnonymizer
|
|
25
|
+
from endoreg_db.utils.paths import (
|
|
26
|
+
SENSITIVE_VIDEO_DIR,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class VideoImportService:
|
|
34
|
+
"""
|
|
35
|
+
Service for importing and anonymizing video files.
|
|
36
|
+
Uses a central video instance pattern for cleaner state management.
|
|
37
|
+
Responsibility:
|
|
38
|
+
Validate path
|
|
39
|
+
Move/copy raw file into stable storage
|
|
40
|
+
Create/attach VideoFile, VideoState, default SensitiveMeta
|
|
41
|
+
Mark a single clear state like state.import_completed = True or state.ready_for_anonymization = True
|
|
42
|
+
|
|
43
|
+
It does not:
|
|
44
|
+
Run frame cleaning
|
|
45
|
+
Run ML
|
|
46
|
+
Create processed_file
|
|
47
|
+
Decide fallback anonymization
|
|
48
|
+
|
|
49
|
+
These actions are delegated to the modules inside file_import
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
self.logger = logger
|
|
55
|
+
self.anonymizer = VideoAnonymizer()
|
|
56
|
+
self.processing_context: Optional[ImportContext] = None
|
|
57
|
+
self.current_video: Optional[VideoFile] = None
|
|
58
|
+
|
|
59
|
+
validate_directories()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def import_and_anonymize(
|
|
63
|
+
self,
|
|
64
|
+
file_path: Union[Path, str],
|
|
65
|
+
center_name: str,
|
|
66
|
+
processor_name: str,
|
|
67
|
+
retry:bool = False,
|
|
68
|
+
delete_source: bool = True,
|
|
69
|
+
) -> "VideoFile | None":
|
|
70
|
+
"""
|
|
71
|
+
Public entrypoint: wrap import_and_anonymize logic.
|
|
72
|
+
"""
|
|
73
|
+
# First, initialize import context. this will be updated during import and keep track of current paths, file type and center and processor.
|
|
74
|
+
ctx = ImportContext(
|
|
75
|
+
file_path=Path(file_path),
|
|
76
|
+
center_name=center_name,
|
|
77
|
+
processor_name=processor_name,
|
|
78
|
+
delete_source=delete_source,
|
|
79
|
+
file_type="video"
|
|
80
|
+
)
|
|
81
|
+
self.logger.info("validating and preparing file")
|
|
82
|
+
if not ctx.file_path.exists():
|
|
83
|
+
raise FileNotFoundError(f"Video file not found: {file_path}")
|
|
84
|
+
|
|
85
|
+
ctx.sensitive_path = create_sensitive_copy(
|
|
86
|
+
ctx.file_path,
|
|
87
|
+
SENSITIVE_VIDEO_DIR
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
with file_lock(ctx.file_path):
|
|
91
|
+
logger.info("Acquired file lock for %s", ctx.file_path)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# create or retrieve VideoFile + update history
|
|
95
|
+
ctx.current_video, needs_processing = (
|
|
96
|
+
create_or_retrieve_video_file(ctx)
|
|
97
|
+
)
|
|
98
|
+
ctx.current_video.get_or_create_state()
|
|
99
|
+
assert(ctx.current_video.state is not None)
|
|
100
|
+
ctx.current_video = ctx.current_video
|
|
101
|
+
|
|
102
|
+
ctx.retry = retry
|
|
103
|
+
# Retry is a forced overwrite of needs processing - therefore the retry will cause full deletion of processed files using finalize failure.
|
|
104
|
+
|
|
105
|
+
if retry and needs_processing and not ctx.current_video.state.anonymization_validated:
|
|
106
|
+
finalize_failure(ctx)
|
|
107
|
+
ctx.current_video, needs_processing = create_or_retrieve_video_file(ctx)
|
|
108
|
+
assert(needs_processing is True)
|
|
109
|
+
elif not needs_processing and not retry:
|
|
110
|
+
return ctx.current_video
|
|
111
|
+
|
|
112
|
+
mark_instance_processing_started(ctx.current_video, ctx)
|
|
113
|
+
try:
|
|
114
|
+
# --- Anonymization with fallback ---
|
|
115
|
+
try:
|
|
116
|
+
ctx = self.anonymizer.anonymize_video(ctx)
|
|
117
|
+
logger.info(
|
|
118
|
+
"Primary video anonymization succeeded for %s",
|
|
119
|
+
ctx.file_path,
|
|
120
|
+
)
|
|
121
|
+
except Exception as primary_exc:
|
|
122
|
+
logger.exception(
|
|
123
|
+
"Primary video anonymization failed for %s: %s "
|
|
124
|
+
"- trying basic anonymization",
|
|
125
|
+
ctx.file_path,
|
|
126
|
+
primary_exc,
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
ctx = self.anonymizer.anonymize_video(ctx)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
logger.error(f"Video Extraction failed for the second time. {e}")
|
|
132
|
+
raise
|
|
133
|
+
logger.info(
|
|
134
|
+
"Secondary video anonymization succeeded for %s",
|
|
135
|
+
ctx.file_path,
|
|
136
|
+
)
|
|
137
|
+
logger.info(f"Anonymized Video is located at: {ctx.anonymized_path}")
|
|
138
|
+
|
|
139
|
+
# --- Finalize success: history + move anonymized file ---
|
|
140
|
+
finalize_video_success(ctx)
|
|
141
|
+
|
|
142
|
+
return ctx.current_video
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
except Exception as exc:
|
|
146
|
+
logger.exception(
|
|
147
|
+
"Video import/anonymization failed for %s: %s", ctx.file_path, exc
|
|
148
|
+
)
|
|
149
|
+
finalize_failure(ctx)
|
|
150
|
+
raise
|
|
@@ -5,7 +5,7 @@ Django management command to create ModelMeta from Hugging Face model.
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from django.core.files.base import ContentFile
|
|
8
|
-
from django.core.management.base import BaseCommand
|
|
8
|
+
from django.core.management.base import BaseCommand, CommandError
|
|
9
9
|
from huggingface_hub import hf_hub_download
|
|
10
10
|
|
|
11
11
|
from endoreg_db.models import AiModel, LabelSet, ModelMeta
|
|
@@ -39,12 +39,19 @@ class Command(BaseCommand):
|
|
|
39
39
|
default="1",
|
|
40
40
|
help="Version for the model meta",
|
|
41
41
|
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--labelset_version",
|
|
44
|
+
type=int,
|
|
45
|
+
default=None,
|
|
46
|
+
help="LabelSet version; if omitted, the latest by name is used",
|
|
47
|
+
)
|
|
42
48
|
|
|
43
49
|
def handle(self, *args, **options):
|
|
44
50
|
model_id = options["model_id"]
|
|
45
51
|
model_name = options["model_name"]
|
|
46
52
|
labelset_name = options["labelset_name"]
|
|
47
53
|
version = options["meta_version"]
|
|
54
|
+
labelset_version = options.get("labelset_version")
|
|
48
55
|
|
|
49
56
|
self.stdout.write(f"Downloading model {model_id} from Hugging Face...")
|
|
50
57
|
|
|
@@ -52,7 +59,7 @@ class Command(BaseCommand):
|
|
|
52
59
|
# Download the model weights
|
|
53
60
|
weights_path = hf_hub_download(
|
|
54
61
|
repo_id=model_id,
|
|
55
|
-
filename="colo_segmentation_RegNetX800MF_base.
|
|
62
|
+
filename="colo_segmentation_RegNetX800MF_base.safetensors",
|
|
56
63
|
local_dir="/tmp",
|
|
57
64
|
)
|
|
58
65
|
self.stdout.write(f"Downloaded weights to: {weights_path}")
|
|
@@ -64,14 +71,17 @@ class Command(BaseCommand):
|
|
|
64
71
|
if created:
|
|
65
72
|
self.stdout.write(f"Created AI model: {ai_model.name}")
|
|
66
73
|
|
|
67
|
-
# Get labelset
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
# Get labelset (optionally by version); fail with non-zero exit
|
|
75
|
+
labelset_qs = LabelSet.objects.filter(name=labelset_name)
|
|
76
|
+
if labelset_version is not None:
|
|
77
|
+
labelset_qs = labelset_qs.filter(version=labelset_version)
|
|
78
|
+
labelset = labelset_qs.order_by("-version").first()
|
|
79
|
+
if labelset is None:
|
|
80
|
+
raise CommandError(
|
|
81
|
+
f"LabelSet '{labelset_name}'"
|
|
82
|
+
+ (f" v{labelset_version}" if labelset_version is not None else "")
|
|
83
|
+
+ " not found"
|
|
73
84
|
)
|
|
74
|
-
return
|
|
75
85
|
|
|
76
86
|
# Create ModelMeta
|
|
77
87
|
model_meta, created = ModelMeta.objects.get_or_create(
|
|
@@ -95,7 +105,7 @@ class Command(BaseCommand):
|
|
|
95
105
|
# Save the weights file to the model
|
|
96
106
|
with open(weights_path, "rb") as f:
|
|
97
107
|
model_meta.weights.save(
|
|
98
|
-
f"{model_name}_v{version}
|
|
108
|
+
f"{model_name}_v{version}.safetensors", ContentFile(f.read())
|
|
99
109
|
)
|
|
100
110
|
|
|
101
111
|
# Set as active meta
|
|
@@ -113,3 +123,4 @@ class Command(BaseCommand):
|
|
|
113
123
|
import traceback
|
|
114
124
|
|
|
115
125
|
traceback.print_exc()
|
|
126
|
+
raise CommandError("ModelMeta creation failed") from e
|