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
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
import os
|
|
5
5
|
import uuid
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING, Optional, Union, cast
|
|
7
|
+
from typing import TYPE_CHECKING, Optional, Self, Union, cast
|
|
8
8
|
|
|
9
9
|
from django.core.files import File
|
|
10
10
|
from django.core.validators import FileExtensionValidator
|
|
@@ -13,10 +13,11 @@ from django.db.models import F
|
|
|
13
13
|
from django.db.models.fields.files import FieldFile
|
|
14
14
|
|
|
15
15
|
from endoreg_db.utils.calc_duration_seconds import _calc_duration_vf
|
|
16
|
+
from endoreg_db.utils.video.ffmpeg_wrapper import assemble_video_from_frames
|
|
16
17
|
|
|
17
18
|
from ...label import Label, LabelVideoSegment
|
|
18
19
|
from ...state import VideoState
|
|
19
|
-
from
|
|
20
|
+
from endoreg_db.utils.paths import ANONYM_VIDEO_DIR, SENSITIVE_VIDEO_DIR
|
|
20
21
|
|
|
21
22
|
# --- Import model-specific function modules ---
|
|
22
23
|
from .create_from_file import _create_from_file
|
|
@@ -25,6 +26,7 @@ from .pipe_2 import _pipe_2
|
|
|
25
26
|
from .video_file_ai import _extract_text_from_video_frames, _predict_video_pipeline
|
|
26
27
|
from .video_file_anonymize import (
|
|
27
28
|
_anonymize,
|
|
29
|
+
_censor_outside_frames,
|
|
28
30
|
_cleanup_raw_assets,
|
|
29
31
|
_create_anonymized_frame_files,
|
|
30
32
|
)
|
|
@@ -72,6 +74,8 @@ from .video_file_meta import (
|
|
|
72
74
|
logger = logging.getLogger(__name__) # Changed from "video_file"
|
|
73
75
|
|
|
74
76
|
if TYPE_CHECKING:
|
|
77
|
+
from django.db.models.fields.files import FieldFile
|
|
78
|
+
|
|
75
79
|
from endoreg_db.models import (
|
|
76
80
|
Center,
|
|
77
81
|
EndoscopyProcessor,
|
|
@@ -113,7 +117,7 @@ class VideoFile(models.Model):
|
|
|
113
117
|
objects = VideoQuerySet.as_manager()
|
|
114
118
|
|
|
115
119
|
raw_file = models.FileField(
|
|
116
|
-
upload_to=
|
|
120
|
+
upload_to=SENSITIVE_VIDEO_DIR.name, # Use .name for relative path
|
|
117
121
|
validators=[FileExtensionValidator(allowed_extensions=["mp4"])],
|
|
118
122
|
null=True,
|
|
119
123
|
blank=True,
|
|
@@ -142,45 +146,45 @@ class VideoFile(models.Model):
|
|
|
142
146
|
null=True,
|
|
143
147
|
blank=True,
|
|
144
148
|
related_name="video_file",
|
|
145
|
-
)
|
|
146
|
-
center = models.ForeignKey("Center", on_delete=models.PROTECT)
|
|
149
|
+
)
|
|
150
|
+
center = models.ForeignKey("Center", on_delete=models.PROTECT)
|
|
147
151
|
processor = models.ForeignKey(
|
|
148
152
|
"EndoscopyProcessor", on_delete=models.PROTECT, blank=True, null=True
|
|
149
|
-
)
|
|
153
|
+
)
|
|
150
154
|
video_meta = models.OneToOneField(
|
|
151
155
|
"VideoMeta",
|
|
152
156
|
on_delete=models.SET_NULL,
|
|
153
157
|
null=True,
|
|
154
158
|
blank=True,
|
|
155
159
|
related_name="video_file",
|
|
156
|
-
)
|
|
160
|
+
)
|
|
157
161
|
examination = models.ForeignKey(
|
|
158
162
|
"PatientExamination",
|
|
159
163
|
on_delete=models.SET_NULL,
|
|
160
164
|
blank=True,
|
|
161
165
|
null=True,
|
|
162
166
|
related_name="video_files",
|
|
163
|
-
)
|
|
167
|
+
)
|
|
164
168
|
patient = models.ForeignKey(
|
|
165
169
|
"Patient",
|
|
166
170
|
on_delete=models.SET_NULL,
|
|
167
171
|
blank=True,
|
|
168
172
|
null=True,
|
|
169
173
|
related_name="video_files",
|
|
170
|
-
)
|
|
174
|
+
)
|
|
171
175
|
ai_model_meta = models.ForeignKey(
|
|
172
176
|
"ModelMeta", on_delete=models.SET_NULL, blank=True, null=True
|
|
173
|
-
)
|
|
177
|
+
)
|
|
174
178
|
state = models.OneToOneField(
|
|
175
179
|
"VideoState",
|
|
176
180
|
on_delete=models.SET_NULL,
|
|
177
181
|
null=True,
|
|
178
182
|
blank=True,
|
|
179
183
|
related_name="video_file",
|
|
180
|
-
)
|
|
184
|
+
)
|
|
181
185
|
import_meta = models.OneToOneField(
|
|
182
186
|
"VideoImportMeta", on_delete=models.CASCADE, blank=True, null=True
|
|
183
|
-
)
|
|
187
|
+
)
|
|
184
188
|
|
|
185
189
|
original_file_name = models.CharField(max_length=255, blank=True, null=True)
|
|
186
190
|
uploaded_at = models.DateTimeField(auto_now_add=True)
|
|
@@ -206,17 +210,25 @@ class VideoFile(models.Model):
|
|
|
206
210
|
date_modified = models.DateTimeField(auto_now=True)
|
|
207
211
|
|
|
208
212
|
if TYPE_CHECKING:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
from django.db.models.manager import RelatedManager
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def label_video_segments(self) -> RelatedManager[LabelVideoSegment]: ...
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def frames(self) -> RelatedManager[Frame]: ...
|
|
220
|
+
|
|
221
|
+
center: models.ForeignKey["Center"]
|
|
222
|
+
processor: models.ForeignKey["EndoscopyProcessor | None"]
|
|
223
|
+
video_meta: models.OneToOneField["VideoMeta | None"]
|
|
224
|
+
examination: models.ForeignKey["PatientExamination | None"]
|
|
225
|
+
patient: models.ForeignKey["Patient | None"]
|
|
226
|
+
sensitive_meta: models.OneToOneField["SensitiveMeta | None"]
|
|
227
|
+
state: models.OneToOneField["VideoState | None"]
|
|
228
|
+
ai_model_meta: models.ForeignKey["ModelMeta | None"]
|
|
229
|
+
import_meta: models.OneToOneField["VideoImportMeta | None"]
|
|
230
|
+
raw_file = cast(FieldFile, raw_file)
|
|
231
|
+
processed_file = cast(FieldFile, processed_file)
|
|
220
232
|
|
|
221
233
|
@property
|
|
222
234
|
def ffmpeg_meta(self) -> "FFMpegMeta":
|
|
@@ -257,7 +269,10 @@ class VideoFile(models.Model):
|
|
|
257
269
|
assert _file is not None, self.NO_ACTIVE_FILE
|
|
258
270
|
if not _file or not _file.name:
|
|
259
271
|
raise ValueError(self.NO_FILE_ASSOCIATED)
|
|
260
|
-
|
|
272
|
+
url = getattr(_file, "url", None)
|
|
273
|
+
if not url:
|
|
274
|
+
raise ValueError("Active raw file URL could not be resolved.")
|
|
275
|
+
return str(url)
|
|
261
276
|
|
|
262
277
|
# Pipeline Functions
|
|
263
278
|
pipe_1 = _pipe_1
|
|
@@ -416,9 +431,34 @@ class VideoFile(models.Model):
|
|
|
416
431
|
)
|
|
417
432
|
|
|
418
433
|
if path is None:
|
|
419
|
-
raise ValueError(
|
|
434
|
+
raise ValueError(
|
|
435
|
+
"Active file path could not be resolved. VideoFile raw file is missing."
|
|
436
|
+
)
|
|
420
437
|
return path
|
|
421
438
|
|
|
439
|
+
@property
|
|
440
|
+
def active_file_url(self) -> str:
|
|
441
|
+
"""Return the URL of the active video file, if available."""
|
|
442
|
+
file_obj = self.active_file
|
|
443
|
+
if not isinstance(file_obj, FieldFile):
|
|
444
|
+
raise ValueError("Active file is not a valid Django FieldFile instance.")
|
|
445
|
+
try:
|
|
446
|
+
url = getattr(file_obj, "url", None)
|
|
447
|
+
except Exception as exc: # storage backends may raise when missing
|
|
448
|
+
logger.warning(
|
|
449
|
+
"Active file URL unavailable for video %s: %s",
|
|
450
|
+
self.uuid,
|
|
451
|
+
exc,
|
|
452
|
+
)
|
|
453
|
+
raise ValueError(
|
|
454
|
+
"Active file URL could not be resolved for this VideoFile."
|
|
455
|
+
) from exc
|
|
456
|
+
|
|
457
|
+
if not url:
|
|
458
|
+
raise ValueError("Active file URL is empty for this VideoFile.")
|
|
459
|
+
|
|
460
|
+
return str(url)
|
|
461
|
+
|
|
422
462
|
@classmethod
|
|
423
463
|
def create_from_file(
|
|
424
464
|
cls, file_path: Union[str, Path], center_name: str, **kwargs
|
|
@@ -478,11 +518,16 @@ class VideoFile(models.Model):
|
|
|
478
518
|
_delete_frames(self)
|
|
479
519
|
|
|
480
520
|
# Call the original delete method to remove the instance from the database
|
|
481
|
-
|
|
482
|
-
|
|
521
|
+
try:
|
|
522
|
+
active_path = self.active_file_path
|
|
523
|
+
logger.info(f"Deleting VideoFile: {self.uuid} - {active_path}")
|
|
524
|
+
|
|
525
|
+
except ValueError:
|
|
526
|
+
logger.info(f"Deleting VideoFile: {self.uuid} - No active file path found.")
|
|
527
|
+
active_path = None
|
|
483
528
|
|
|
484
529
|
# Delete associated files if they exist
|
|
485
|
-
if active_path.exists():
|
|
530
|
+
if active_path and active_path.exists():
|
|
486
531
|
active_path.unlink(missing_ok=True)
|
|
487
532
|
|
|
488
533
|
# Delete file storage
|
|
@@ -531,32 +576,19 @@ class VideoFile(models.Model):
|
|
|
531
576
|
**IMPORTANT:** Only the raw video is deleted. The processed (anonymized)
|
|
532
577
|
video is preserved as the final validated output.
|
|
533
578
|
"""
|
|
534
|
-
from datetime import date as dt_date
|
|
535
|
-
|
|
536
|
-
from endoreg_db.models import SensitiveMeta
|
|
537
|
-
|
|
538
|
-
if not self.sensitive_meta:
|
|
539
|
-
# CRITICAL FIX: Use create_from_dict with default patient data
|
|
540
|
-
default_data = {
|
|
541
|
-
"patient_first_name": "Patient",
|
|
542
|
-
"patient_last_name": "Unknown",
|
|
543
|
-
"patient_dob": dt_date(1990, 1, 1),
|
|
544
|
-
"examination_date": dt_date.today(),
|
|
545
|
-
"center": self.center,
|
|
546
|
-
}
|
|
547
|
-
self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
|
|
548
579
|
|
|
549
580
|
# CRITICAL FIX: Delete RAW video file, not the processed (anonymized) one
|
|
550
581
|
# CRITICAL: Update metadata BEFORE deleting raw video
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
582
|
+
if extracted_data_dict and self.sensitive_meta:
|
|
583
|
+
self.sensitive_meta.update_from_dict(extracted_data_dict)
|
|
584
|
+
else:
|
|
585
|
+
return False
|
|
555
586
|
|
|
556
587
|
# After validation and metadata update, only the anonymized video should remain
|
|
557
588
|
from .video_file_io import _get_raw_file_path
|
|
558
589
|
|
|
559
590
|
raw_path = _get_raw_file_path(self)
|
|
591
|
+
|
|
560
592
|
if raw_path and raw_path.exists():
|
|
561
593
|
logger.info(f"Deleting raw video file after validation: {raw_path}")
|
|
562
594
|
raw_path.unlink(missing_ok=True)
|
|
@@ -567,11 +599,14 @@ class VideoFile(models.Model):
|
|
|
567
599
|
f"Raw video deleted for {self.uuid}. Anonymized video preserved."
|
|
568
600
|
)
|
|
569
601
|
else:
|
|
570
|
-
logger.warning(
|
|
602
|
+
logger.warning(
|
|
603
|
+
"Raw video file not found for deletion during validation %s.",
|
|
604
|
+
self.uuid,
|
|
605
|
+
)
|
|
571
606
|
|
|
572
|
-
if sensitive_meta:
|
|
607
|
+
if self.sensitive_meta:
|
|
573
608
|
# Mark as processed after validation
|
|
574
|
-
self.get_or_create_state().
|
|
609
|
+
self.get_or_create_state().mark_anonymization_validated(save=True)
|
|
575
610
|
# Save the VideoFile instance to persist changes
|
|
576
611
|
self.save()
|
|
577
612
|
logger.info(
|
|
@@ -602,7 +637,6 @@ class VideoFile(models.Model):
|
|
|
602
637
|
# Create a new state if it doesn't exist
|
|
603
638
|
self.state = self.get_or_create_state()
|
|
604
639
|
|
|
605
|
-
self.sensitive_meta = self.get_or_create_sensitive_meta()
|
|
606
640
|
self.save()
|
|
607
641
|
# Initialize frames based on the video specs
|
|
608
642
|
self.initialize_frames()
|
|
@@ -626,6 +660,11 @@ class VideoFile(models.Model):
|
|
|
626
660
|
Mark this video's processing state as having its sensitive meta fully processed.
|
|
627
661
|
This proxies to the related VideoState and persists by default.
|
|
628
662
|
"""
|
|
663
|
+
sm = self.sensitive_meta
|
|
664
|
+
from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
|
|
665
|
+
|
|
666
|
+
if not isinstance(sm, SensitiveMeta):
|
|
667
|
+
raise AttributeError()
|
|
629
668
|
state = self.get_or_create_state()
|
|
630
669
|
state.mark_sensitive_meta_processed(save=save)
|
|
631
670
|
return self
|
|
@@ -635,8 +674,13 @@ class VideoFile(models.Model):
|
|
|
635
674
|
Mark the associated SensitiveMeta as verified by setting both DOB and names as verified.
|
|
636
675
|
Ensures the SensitiveMeta and its state exist.
|
|
637
676
|
"""
|
|
638
|
-
sm = self.
|
|
677
|
+
sm = self.sensitive_meta
|
|
639
678
|
# Use SensitiveMeta methods to update underlying SensitiveMetaState
|
|
679
|
+
from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
|
|
680
|
+
|
|
681
|
+
if not isinstance(sm, SensitiveMeta):
|
|
682
|
+
raise AttributeError()
|
|
683
|
+
|
|
640
684
|
sm.mark_dob_verified()
|
|
641
685
|
sm.mark_names_verified()
|
|
642
686
|
return self
|
|
@@ -675,65 +719,6 @@ class VideoFile(models.Model):
|
|
|
675
719
|
|
|
676
720
|
return state
|
|
677
721
|
|
|
678
|
-
def get_or_create_sensitive_meta(self) -> "SensitiveMeta":
|
|
679
|
-
"""
|
|
680
|
-
Retrieve the associated SensitiveMeta instance for this video, creating and assigning one if it does not exist.
|
|
681
|
-
|
|
682
|
-
**Two-Phase Patient Data Pattern:**
|
|
683
|
-
This method implements a two-phase approach to handle incomplete patient data:
|
|
684
|
-
|
|
685
|
-
**Phase 1: Initial Creation (with defaults)**
|
|
686
|
-
- Creates SensitiveMeta with default patient data to prevent hash calculation errors
|
|
687
|
-
- Default values: patient_first_name="Patient", patient_last_name="Unknown", patient_dob=1990-01-01
|
|
688
|
-
- Allows video import to proceed even without extracted patient data
|
|
689
|
-
- Temporary hash and pseudo-entities are created
|
|
690
|
-
|
|
691
|
-
**Phase 2: Update (with extracted data)**
|
|
692
|
-
- Real patient data is extracted later (e.g., from video OCR via lx_anonymizer)
|
|
693
|
-
- update_from_dict() is called with actual patient information
|
|
694
|
-
- Hash is recalculated automatically using real data
|
|
695
|
-
- Correct pseudo-entities are created/linked based on new hash
|
|
696
|
-
|
|
697
|
-
**Example workflow:**
|
|
698
|
-
```python
|
|
699
|
-
# Phase 1: Video creation
|
|
700
|
-
video = VideoFile.create_from_file_initialized(...)
|
|
701
|
-
video.initialize() # Calls this method
|
|
702
|
-
# → SensitiveMeta created with defaults
|
|
703
|
-
# → Hash: sha256("Patient Unknown 1990-01-01...")
|
|
704
|
-
|
|
705
|
-
# Phase 2: Frame cleaning extracts real data
|
|
706
|
-
extracted = {"patient_first_name": "Max", "patient_last_name": "Mustermann", ...}
|
|
707
|
-
video.sensitive_meta.update_from_dict(extracted)
|
|
708
|
-
# → Hash: sha256("Max Mustermann 1985-03-15...") (RECALCULATED)
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
Returns:
|
|
712
|
-
SensitiveMeta: The related SensitiveMeta instance.
|
|
713
|
-
|
|
714
|
-
See Also:
|
|
715
|
-
- sensitive_meta_logic.perform_save_logic() for hash calculation details
|
|
716
|
-
- sensitive_meta_logic.update_sensitive_meta_from_dict() for update mechanism
|
|
717
|
-
"""
|
|
718
|
-
from datetime import date as dt_date
|
|
719
|
-
|
|
720
|
-
from endoreg_db.models import SensitiveMeta
|
|
721
|
-
|
|
722
|
-
if self.sensitive_meta is None:
|
|
723
|
-
# Use create_from_dict with default patient data
|
|
724
|
-
# to prevent "First name is required to calculate patient hash" error
|
|
725
|
-
default_data = {
|
|
726
|
-
"patient_first_name": "Patient",
|
|
727
|
-
"patient_last_name": "Unknown",
|
|
728
|
-
"patient_dob": dt_date(1990, 1, 1),
|
|
729
|
-
"examination_date": dt_date.today(),
|
|
730
|
-
"center": self.center,
|
|
731
|
-
}
|
|
732
|
-
self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
|
|
733
|
-
self.save(update_fields=["sensitive_meta"])
|
|
734
|
-
# Do not mark state as processed here; it will be set after extraction/validation steps
|
|
735
|
-
return self.sensitive_meta
|
|
736
|
-
|
|
737
722
|
def get_outside_segments(
|
|
738
723
|
self, only_validated: bool = False
|
|
739
724
|
) -> models.QuerySet["LabelVideoSegment"]:
|
|
@@ -767,6 +752,82 @@ class VideoFile(models.Model):
|
|
|
767
752
|
)
|
|
768
753
|
return self.label_video_segments.none()
|
|
769
754
|
|
|
755
|
+
@classmethod
|
|
756
|
+
def create_video_without_outside_frames(
|
|
757
|
+
cls, instance: "VideoFile", only_validated: bool = False
|
|
758
|
+
) -> bool:
|
|
759
|
+
"""
|
|
760
|
+
Creates a new video by excluding frames that belong to 'outside' segments.
|
|
761
|
+
|
|
762
|
+
Parameters:
|
|
763
|
+
only_validated (bool): If True, only validated segments are considered for frame exclusion.
|
|
764
|
+
|
|
765
|
+
Returns:
|
|
766
|
+
VideoFile: A new VideoFile instance with the frames excluding those labeled as 'outside'.
|
|
767
|
+
"""
|
|
768
|
+
video = instance
|
|
769
|
+
|
|
770
|
+
if not video:
|
|
771
|
+
logger.warning(
|
|
772
|
+
"No processed video file available for VideoFile %s.", cls.uuid
|
|
773
|
+
)
|
|
774
|
+
return False
|
|
775
|
+
try:
|
|
776
|
+
extracted = video.extract_frames(
|
|
777
|
+
quality=2,
|
|
778
|
+
overwrite=False,
|
|
779
|
+
ext="jpg",
|
|
780
|
+
verbose=False,
|
|
781
|
+
from_processed=True,
|
|
782
|
+
)
|
|
783
|
+
assert extracted is True
|
|
784
|
+
except AssertionError:
|
|
785
|
+
extracted = video.extract_frames(
|
|
786
|
+
quality=2,
|
|
787
|
+
overwrite=False,
|
|
788
|
+
ext="jpg",
|
|
789
|
+
verbose=False,
|
|
790
|
+
from_processed=True,
|
|
791
|
+
)
|
|
792
|
+
assert extracted is True
|
|
793
|
+
try:
|
|
794
|
+
# Step 1: Get the "outside" labeled frames
|
|
795
|
+
censored = _censor_outside_frames(video)
|
|
796
|
+
frames = [instance.get_frame_dir_path()]
|
|
797
|
+
assert len(frames) != 0
|
|
798
|
+
fps = (
|
|
799
|
+
video.fps if video.fps else 120.0
|
|
800
|
+
) # Default to 30 FPS if fps is not set
|
|
801
|
+
assert censored is True
|
|
802
|
+
assert fps is not None
|
|
803
|
+
assert video.width is not None
|
|
804
|
+
assert video.height is not None
|
|
805
|
+
# assert isinstance(frames, list[Path]) #TODO improve TypeCheck
|
|
806
|
+
|
|
807
|
+
# Step 2: Reassemble the video with frames excluding the 'outside' labeled frames
|
|
808
|
+
output_video_path = Path(f"/path/to/output/{cls.uuid}_filtered.mp4")
|
|
809
|
+
fps = cls.fps if cls.fps else 30.0 # Default to 30 FPS if fps is not set
|
|
810
|
+
new_video_file = assemble_video_from_frames(
|
|
811
|
+
frames, output_video_path, fps, width=video.width, height=video.height
|
|
812
|
+
)
|
|
813
|
+
video.processed_file = new_video_file
|
|
814
|
+
return True
|
|
815
|
+
except AssertionError as ae:
|
|
816
|
+
logger.error(
|
|
817
|
+
f"Assertion error while creating video without 'outside' frames for VideoFile {cls.uuid}: {ae}",
|
|
818
|
+
exc_info=True,
|
|
819
|
+
)
|
|
820
|
+
return False
|
|
821
|
+
except Label.DoesNotExist:
|
|
822
|
+
logger.warning("Outside label not found in the database.")
|
|
823
|
+
return False
|
|
824
|
+
except Exception as e:
|
|
825
|
+
logger.error(
|
|
826
|
+
f"Error creating video without 'outside' frames for VideoFile {cls.uuid}: {e}",
|
|
827
|
+
exc_info=True,
|
|
828
|
+
)
|
|
829
|
+
return False
|
|
830
|
+
|
|
770
831
|
@classmethod
|
|
771
832
|
def get_all_videos(cls) -> models.QuerySet["VideoFile"]:
|
|
772
833
|
"""
|
|
@@ -809,7 +870,8 @@ class VideoFile(models.Model):
|
|
|
809
870
|
raise ValueError("FPS must be set and greater than zero.")
|
|
810
871
|
return frame_number / fps
|
|
811
872
|
|
|
812
|
-
|
|
873
|
+
@staticmethod
|
|
874
|
+
def get_video_by_pk(pk: int) -> "VideoFile":
|
|
813
875
|
"""
|
|
814
876
|
Retrieve a VideoFile instance by its primary key (ID).
|
|
815
877
|
|
|
@@ -822,4 +884,4 @@ class VideoFile(models.Model):
|
|
|
822
884
|
Raises:
|
|
823
885
|
VideoFile.DoesNotExist: If no VideoFile with the given ID exists.
|
|
824
886
|
"""
|
|
825
|
-
return
|
|
887
|
+
return VideoFile.objects.get(pk=video_id)
|