endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Video Metadata Serializer
|
|
3
|
-
|
|
4
|
-
Serializes VideoMetadata model for API responses.
|
|
5
|
-
Created as part of Phase 1.1: Video Correction API Endpoints.
|
|
6
|
-
"""
|
|
7
|
-
from rest_framework import serializers
|
|
8
|
-
from endoreg_db.models.media.video import VideoMetadata
|
|
9
|
-
import json
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class VideoMetadataSerializer(serializers.ModelSerializer):
|
|
13
|
-
"""
|
|
14
|
-
Serializer for VideoMetadata model.
|
|
15
|
-
|
|
16
|
-
Provides analysis results (sensitive frame count, ratio, frame IDs)
|
|
17
|
-
for the correction UI.
|
|
18
|
-
"""
|
|
19
|
-
sensitive_frame_ids_list = serializers.SerializerMethodField()
|
|
20
|
-
sensitive_percentage = serializers.ReadOnlyField()
|
|
21
|
-
has_analysis = serializers.ReadOnlyField()
|
|
22
|
-
|
|
23
|
-
class Meta:
|
|
24
|
-
model = VideoMetadata
|
|
25
|
-
fields = [
|
|
26
|
-
'id',
|
|
27
|
-
'video',
|
|
28
|
-
'sensitive_frame_count',
|
|
29
|
-
'sensitive_ratio',
|
|
30
|
-
'sensitive_frame_ids',
|
|
31
|
-
'sensitive_frame_ids_list',
|
|
32
|
-
'sensitive_percentage',
|
|
33
|
-
'has_analysis',
|
|
34
|
-
'analyzed_at',
|
|
35
|
-
]
|
|
36
|
-
read_only_fields = ['id', 'analyzed_at']
|
|
37
|
-
|
|
38
|
-
def get_sensitive_frame_ids_list(self, obj) -> list:
|
|
39
|
-
"""
|
|
40
|
-
Parse sensitive_frame_ids from JSON string to Python list.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
list: Frame indices (0-based), or empty list if no analysis
|
|
44
|
-
"""
|
|
45
|
-
if not obj.sensitive_frame_ids:
|
|
46
|
-
return []
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
return json.loads(obj.sensitive_frame_ids)
|
|
50
|
-
except (json.JSONDecodeError, TypeError):
|
|
51
|
-
return []
|
|
52
|
-
|
|
53
|
-
def validate_sensitive_frame_ids(self, value):
|
|
54
|
-
"""
|
|
55
|
-
Validate that sensitive_frame_ids is a valid JSON array.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
value: JSON string representing frame IDs
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
str: Validated JSON string
|
|
62
|
-
|
|
63
|
-
Raises:
|
|
64
|
-
ValidationError: If value is not valid JSON or not an array
|
|
65
|
-
"""
|
|
66
|
-
if not value:
|
|
67
|
-
return value
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
parsed = json.loads(value)
|
|
71
|
-
if not isinstance(parsed, list):
|
|
72
|
-
raise serializers.ValidationError(
|
|
73
|
-
"sensitive_frame_ids must be a JSON array"
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# Validate all elements are integers
|
|
77
|
-
if not all(isinstance(x, int) for x in parsed):
|
|
78
|
-
raise serializers.ValidationError(
|
|
79
|
-
"All frame IDs must be integers"
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
return value
|
|
83
|
-
except json.JSONDecodeError:
|
|
84
|
-
raise serializers.ValidationError(
|
|
85
|
-
"sensitive_frame_ids must be valid JSON"
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
def validate_sensitive_ratio(self, value):
|
|
89
|
-
"""
|
|
90
|
-
Validate that sensitive_ratio is between 0.0 and 1.0.
|
|
91
|
-
|
|
92
|
-
Args:
|
|
93
|
-
value: Ratio value
|
|
94
|
-
|
|
95
|
-
Returns:
|
|
96
|
-
float: Validated ratio
|
|
97
|
-
|
|
98
|
-
Raises:
|
|
99
|
-
ValidationError: If value is outside valid range
|
|
100
|
-
"""
|
|
101
|
-
if value is not None and (value < 0.0 or value > 1.0):
|
|
102
|
-
raise serializers.ValidationError(
|
|
103
|
-
"sensitive_ratio must be between 0.0 and 1.0"
|
|
104
|
-
)
|
|
105
|
-
return value
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
from ast import List
|
|
2
|
-
import pickle
|
|
3
|
-
from endoreg_db.models import Requirement, Examination, PatientExamination
|
|
4
|
-
from endoreg_db.serializers import PatientExaminationSerializer, ExaminationSerializer, FindingClassificationSerializer, RequirementSerializer
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class LookupService:
|
|
8
|
-
def __init__(self, db_session):
|
|
9
|
-
self.db_session = db_session
|
|
10
|
-
self.hexdict = int()
|
|
11
|
-
|
|
12
|
-
def hash_lookup(self, key, value):
|
|
13
|
-
"""
|
|
14
|
-
Store a key-value pair in the lookup dictionary.
|
|
15
|
-
"""
|
|
16
|
-
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
17
|
-
lookup_dict[key] = value
|
|
18
|
-
self.hexdict = pickle.dumps(dict).hex()
|
|
19
|
-
return True
|
|
20
|
-
def hash_retrieve(self, key):
|
|
21
|
-
"""
|
|
22
|
-
Retrieve a value by key from the lookup dictionary.
|
|
23
|
-
"""
|
|
24
|
-
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
25
|
-
return lookup_dict.get(key, None)
|
|
26
|
-
|
|
27
|
-
def hash_add_key_value(self, key, value):
|
|
28
|
-
"""
|
|
29
|
-
Add a key-value pair to the lookup dictionary.
|
|
30
|
-
"""
|
|
31
|
-
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
32
|
-
lookup_dict[key] = value
|
|
33
|
-
self.hexdict = pickle.dumps(lookup_dict).hex()
|
|
34
|
-
return True
|
|
35
|
-
|
|
36
|
-
def hash_dehash(self):
|
|
37
|
-
"""
|
|
38
|
-
Retrieve the entire lookup dictionary.
|
|
39
|
-
"""
|
|
40
|
-
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
41
|
-
return lookup_dict
|
|
42
|
-
|
|
43
|
-
def fetch_examination_dict(self, patient_id, tags: List[str] = None):
|
|
44
|
-
"""
|
|
45
|
-
Fetch examinations for a given patient ID, optionally filtered by tags.
|
|
46
|
-
"""
|
|
47
|
-
query = self.db_session.query(Examination).filter(Examination.patient_id == patient_id)
|
|
48
|
-
if tags:
|
|
49
|
-
query = query.filter(Examination.tags.any(Examination.tags.in_(tags)))
|
|
50
|
-
examinations = query.all()
|
|
51
|
-
return [ExaminationSerializer(exam).data for exam in examinations]
|
|
52
|
-
|
|
53
|
-
def fetch_patient_examination_by_id(self, patient_id, examination_id):
|
|
54
|
-
"""
|
|
55
|
-
Fetch a patient examination object from the database by its ID.
|
|
56
|
-
"""
|
|
57
|
-
return self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
|
|
58
|
-
|
|
59
|
-
def fetch_patient_examinations(self, patient_id):
|
|
60
|
-
"""
|
|
61
|
-
Fetch all patient examinations for a given patient ID.
|
|
62
|
-
"""
|
|
63
|
-
examinations = self.db_session.query(PatientExamination).filter(PatientExamination.patient_id == patient_id).all()
|
|
64
|
-
return [PatientExaminationSerializer(exam).data for exam in examinations]
|
|
65
|
-
|
|
66
|
-
def fetch_findings_by_patient_examination(self, patient_examination_id):
|
|
67
|
-
"""
|
|
68
|
-
Fetch findings associated with a given patient examination ID.
|
|
69
|
-
"""
|
|
70
|
-
patient_examination = self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
|
|
71
|
-
if not patient_examination:
|
|
72
|
-
return []
|
|
73
|
-
return [finding.serialize() for finding in patient_examination.findings]
|
|
74
|
-
|
|
75
|
-
def fetch_classifications_by_finding(self, finding_id):
|
|
76
|
-
"""
|
|
77
|
-
Fetch classifications associated with a given finding ID.
|
|
78
|
-
"""
|
|
79
|
-
finding = self.db_session.query(Finding).filter(Finding.id == finding_id).first()
|
|
80
|
-
if not finding:
|
|
81
|
-
return []
|
|
82
|
-
return [classification.serialize() for classification in finding.classifications]
|
|
83
|
-
|
|
84
|
-
def fetch_default_finding_classification(self):
|
|
85
|
-
"""
|
|
86
|
-
Fetch the default finding classification from the database.
|
|
87
|
-
"""
|
|
88
|
-
return self.db_session.query(FindingClassification).filter(FindingClassification.is_default == True).first()
|
|
89
|
-
|
|
90
|
-
def fetch_finding_classification_choice_by_requirement(self, requirement_id):
|
|
91
|
-
"""
|
|
92
|
-
Retrieve finding classification choices based on the provided requirement ID.
|
|
93
|
-
"""
|
|
94
|
-
requirement = self.get_requirement_by_id(requirement_id)
|
|
95
|
-
if not requirement:
|
|
96
|
-
return []
|
|
97
|
-
return [choice.serialize() for choice in requirement.finding_classification_choices]
|
|
98
|
-
|
|
99
|
-
def fetch_requirement_choices_by_requirement(self, requirement_id):
|
|
100
|
-
"""
|
|
101
|
-
Retrieve requirement choices based on the provided requirement ID.
|
|
102
|
-
"""
|
|
103
|
-
requirement = self.get_requirement_by_id(requirement_id)
|
|
104
|
-
if not requirement:
|
|
105
|
-
return []
|
|
106
|
-
return [choice.serialize() for choice in requirement.requirement_choices]
|
|
107
|
-
|
|
108
|
-
def available_finding_classification_choices_by_finding_classification(self, finding_classification):
|
|
109
|
-
"""
|
|
110
|
-
Retrieve available finding classification choices based on the provided finding classification.
|
|
111
|
-
"""
|
|
112
|
-
return self.db_session.query(FindingClassificationChoice).filter(
|
|
113
|
-
FindingClassificationChoice.finding_classification_id == finding_classification.id
|
|
114
|
-
).all()
|
|
115
|
-
|
|
116
|
-
def get_requirement_by_id(self, requirement_id):
|
|
117
|
-
"""
|
|
118
|
-
Fetch a requirement object from the database by its ID.
|
|
119
|
-
"""
|
|
120
|
-
return self.db_session.query(Requirement).filter(Requirement.id == requirement_id).first()
|
|
121
|
-
|
|
122
|
-
def get_all_requirements_for_requirement_sets(self, requirement_set_ids: List[int]):
|
|
123
|
-
"""
|
|
124
|
-
Fetch all requirements associated with the given requirement set IDs.
|
|
125
|
-
"""
|
|
126
|
-
return self.db_session.query(Requirement).filter(Requirement.requirement_set_id.in_(requirement_set_ids)).all()
|
|
127
|
-
|
|
128
|
-
def get_all_requirement_sets_for_examination(self, examination_id):
|
|
129
|
-
"""
|
|
130
|
-
Fetch all requirement sets associated with the given examination ID.
|
|
131
|
-
"""
|
|
132
|
-
examination = self.db_session.query(Examination).filter(Examination.id == examination_id).first()
|
|
133
|
-
if not examination:
|
|
134
|
-
return []
|
|
135
|
-
return [req_set.serialize() for req_set in examination.requirement_sets]
|
|
136
|
-
|
|
137
|
-
def serialize_requirement(self, requirement):
|
|
138
|
-
"""
|
|
139
|
-
Serialize a requirement object to a byte stream.
|
|
140
|
-
"""
|
|
141
|
-
return pickle.dumps(requirement)
|
|
142
|
-
|
|
143
|
-
def deserialize_requirement(self, serialized_requirement):
|
|
144
|
-
"""
|
|
145
|
-
Deserialize a byte stream back to a requirement object.
|
|
146
|
-
"""
|
|
147
|
-
return pickle.loads(serialized_requirement)
|
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
from django.db import transaction
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
import logging
|
|
4
|
-
import shutil
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
|
-
from endoreg_db.models import VideoFile, AnonymizationTask
|
|
9
|
-
from endoreg_db.exceptions import InsufficientStorageError
|
|
10
|
-
# from endoreg_db.models.media.video.create_from_file import check_storage_capacity
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class StorageAwareVideoProcessor:
|
|
16
|
-
"""
|
|
17
|
-
Enhanced video processor with built-in storage management and automatic cleanup.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
def __init__(self, auto_cleanup: bool = True, min_free_space_gb: float = 10.0):
|
|
21
|
-
self.auto_cleanup = auto_cleanup
|
|
22
|
-
self.min_free_space_gb = min_free_space_gb
|
|
23
|
-
|
|
24
|
-
def check_and_ensure_storage(self, required_space_estimate: int = None) -> bool:
|
|
25
|
-
"""
|
|
26
|
-
Check storage capacity and perform cleanup if needed.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
required_space_estimate: Estimated space needed in bytes
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
True if enough space is available, False otherwise
|
|
33
|
-
|
|
34
|
-
Raises:
|
|
35
|
-
InsufficientStorageError: If space cannot be freed
|
|
36
|
-
"""
|
|
37
|
-
try:
|
|
38
|
-
# Get current storage stats
|
|
39
|
-
total, used, free = shutil.disk_usage('/')
|
|
40
|
-
free_gb = free / (1024**3)
|
|
41
|
-
usage_percent = (used / total) * 100
|
|
42
|
-
|
|
43
|
-
logger.info(f"Storage check: {free_gb:.1f}GB free ({usage_percent:.1f}% used)")
|
|
44
|
-
|
|
45
|
-
# Check if we need emergency cleanup
|
|
46
|
-
needs_cleanup = (
|
|
47
|
-
usage_percent >= 95.0 or
|
|
48
|
-
free_gb < self.min_free_space_gb or
|
|
49
|
-
(required_space_estimate and free < required_space_estimate * 1.2)
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
if needs_cleanup and self.auto_cleanup:
|
|
53
|
-
logger.warning(f"Storage critically low ({usage_percent:.1f}%), performing automatic cleanup")
|
|
54
|
-
self._perform_emergency_cleanup()
|
|
55
|
-
|
|
56
|
-
# Re-check after cleanup
|
|
57
|
-
total, used, free = shutil.disk_usage('/')
|
|
58
|
-
free_gb = free / (1024**3)
|
|
59
|
-
usage_percent = (used / total) * 100
|
|
60
|
-
|
|
61
|
-
if usage_percent >= 98.0:
|
|
62
|
-
raise InsufficientStorageError(
|
|
63
|
-
f"Storage critically low even after cleanup: {usage_percent:.1f}% used, "
|
|
64
|
-
f"only {free_gb:.1f}GB free",
|
|
65
|
-
required_space=required_space_estimate or int(self.min_free_space_gb * 1024**3),
|
|
66
|
-
available_space=free
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
return True
|
|
70
|
-
|
|
71
|
-
except Exception as e:
|
|
72
|
-
logger.error(f"Storage check failed: {e}")
|
|
73
|
-
raise
|
|
74
|
-
|
|
75
|
-
def _perform_emergency_cleanup(self) -> int:
|
|
76
|
-
"""
|
|
77
|
-
Perform emergency storage cleanup.
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
Bytes freed
|
|
81
|
-
"""
|
|
82
|
-
total_freed = 0
|
|
83
|
-
|
|
84
|
-
try:
|
|
85
|
-
# 1. Clean up extracted frames for completed videos
|
|
86
|
-
frames_freed = self._cleanup_completed_video_frames()
|
|
87
|
-
total_freed += frames_freed
|
|
88
|
-
|
|
89
|
-
# 2. Clean up upload cache older than 1 day
|
|
90
|
-
uploads_freed = self._cleanup_old_uploads(max_age_hours=24)
|
|
91
|
-
total_freed += uploads_freed
|
|
92
|
-
|
|
93
|
-
# 3. Clean up large log files
|
|
94
|
-
logs_freed = self._cleanup_large_logs()
|
|
95
|
-
total_freed += logs_freed
|
|
96
|
-
|
|
97
|
-
# 4. Clean up temporary files
|
|
98
|
-
temp_freed = self._cleanup_temp_files()
|
|
99
|
-
total_freed += temp_freed
|
|
100
|
-
|
|
101
|
-
logger.info(f"Emergency cleanup completed: {total_freed / (1024**3):.2f}GB freed")
|
|
102
|
-
|
|
103
|
-
except Exception as e:
|
|
104
|
-
logger.error(f"Emergency cleanup failed: {e}")
|
|
105
|
-
|
|
106
|
-
return total_freed
|
|
107
|
-
|
|
108
|
-
def _cleanup_completed_video_frames(self) -> int:
|
|
109
|
-
"""Clean up frames for videos that have completed processing."""
|
|
110
|
-
total_freed = 0
|
|
111
|
-
|
|
112
|
-
try:
|
|
113
|
-
from django.conf import settings
|
|
114
|
-
frames_dir = Path(settings.BASE_DIR).parent / 'storage' / 'frames'
|
|
115
|
-
|
|
116
|
-
if not frames_dir.exists():
|
|
117
|
-
return 0
|
|
118
|
-
|
|
119
|
-
# Find videos with completed anonymization
|
|
120
|
-
completed_videos = VideoFile.objects.filter(
|
|
121
|
-
anonymization_tasks__status='done'
|
|
122
|
-
).distinct()
|
|
123
|
-
|
|
124
|
-
for video in completed_videos:
|
|
125
|
-
# Find frame directories for this video
|
|
126
|
-
video_frame_dirs = list(frames_dir.glob(f"*{video.uuid}*"))
|
|
127
|
-
|
|
128
|
-
for frame_dir in video_frame_dirs:
|
|
129
|
-
if frame_dir.is_dir():
|
|
130
|
-
try:
|
|
131
|
-
# Calculate directory size
|
|
132
|
-
dir_size = sum(
|
|
133
|
-
f.stat().st_size for f in frame_dir.rglob('*') if f.is_file()
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
# Remove the directory
|
|
137
|
-
shutil.rmtree(frame_dir, ignore_errors=True)
|
|
138
|
-
total_freed += dir_size
|
|
139
|
-
|
|
140
|
-
logger.info(f"Cleaned frames for {video.uuid}: {dir_size / (1024**2):.1f}MB")
|
|
141
|
-
|
|
142
|
-
except Exception as e:
|
|
143
|
-
logger.warning(f"Failed to clean frames for {video.uuid}: {e}")
|
|
144
|
-
|
|
145
|
-
except Exception as e:
|
|
146
|
-
logger.error(f"Frame cleanup failed: {e}")
|
|
147
|
-
|
|
148
|
-
return total_freed
|
|
149
|
-
|
|
150
|
-
def _cleanup_old_uploads(self, max_age_hours: int = 24) -> int:
|
|
151
|
-
"""Clean up old upload cache files."""
|
|
152
|
-
total_freed = 0
|
|
153
|
-
|
|
154
|
-
try:
|
|
155
|
-
from django.conf import settings
|
|
156
|
-
uploads_dir = Path(settings.BASE_DIR).parent / 'storage' / 'uploads'
|
|
157
|
-
|
|
158
|
-
if not uploads_dir.exists():
|
|
159
|
-
return 0
|
|
160
|
-
|
|
161
|
-
cutoff_time = datetime.now().timestamp() - (max_age_hours * 3600)
|
|
162
|
-
|
|
163
|
-
for file_path in uploads_dir.rglob('*'):
|
|
164
|
-
if file_path.is_file():
|
|
165
|
-
try:
|
|
166
|
-
if file_path.stat().st_mtime < cutoff_time:
|
|
167
|
-
file_size = file_path.stat().st_size
|
|
168
|
-
file_path.unlink()
|
|
169
|
-
total_freed += file_size
|
|
170
|
-
|
|
171
|
-
except Exception as e:
|
|
172
|
-
logger.warning(f"Failed to clean upload file {file_path}: {e}")
|
|
173
|
-
|
|
174
|
-
except Exception as e:
|
|
175
|
-
logger.error(f"Upload cleanup failed: {e}")
|
|
176
|
-
|
|
177
|
-
return total_freed
|
|
178
|
-
|
|
179
|
-
def _cleanup_large_logs(self, max_size_mb: int = 50) -> int:
|
|
180
|
-
"""Clean up large log files by truncating them."""
|
|
181
|
-
total_freed = 0
|
|
182
|
-
|
|
183
|
-
try:
|
|
184
|
-
from django.conf import settings
|
|
185
|
-
project_root = Path(settings.BASE_DIR).parent
|
|
186
|
-
max_size_bytes = max_size_mb * 1024 * 1024
|
|
187
|
-
|
|
188
|
-
for log_file in project_root.rglob('*.log'):
|
|
189
|
-
try:
|
|
190
|
-
if log_file.stat().st_size > max_size_bytes:
|
|
191
|
-
original_size = log_file.stat().st_size
|
|
192
|
-
|
|
193
|
-
# Truncate the log file
|
|
194
|
-
with open(log_file, 'w') as f:
|
|
195
|
-
f.write(f"# Log truncated at {datetime.now()} due to size limit\n")
|
|
196
|
-
|
|
197
|
-
total_freed += original_size
|
|
198
|
-
logger.info(f"Truncated log {log_file}: {original_size / (1024**2):.1f}MB")
|
|
199
|
-
|
|
200
|
-
except Exception as e:
|
|
201
|
-
logger.warning(f"Failed to truncate log {log_file}: {e}")
|
|
202
|
-
|
|
203
|
-
except Exception as e:
|
|
204
|
-
logger.error(f"Log cleanup failed: {e}")
|
|
205
|
-
|
|
206
|
-
return total_freed
|
|
207
|
-
|
|
208
|
-
def _cleanup_temp_files(self) -> int:
|
|
209
|
-
"""Clean up temporary files."""
|
|
210
|
-
total_freed = 0
|
|
211
|
-
|
|
212
|
-
try:
|
|
213
|
-
temp_patterns = [
|
|
214
|
-
'/tmp/tmp*',
|
|
215
|
-
'/tmp/temp*',
|
|
216
|
-
'/tmp/django*',
|
|
217
|
-
'/tmp/ffmpeg*',
|
|
218
|
-
]
|
|
219
|
-
|
|
220
|
-
for pattern in temp_patterns:
|
|
221
|
-
import glob
|
|
222
|
-
for temp_file in glob.glob(pattern):
|
|
223
|
-
try:
|
|
224
|
-
temp_path = Path(temp_file)
|
|
225
|
-
if temp_path.is_file():
|
|
226
|
-
file_size = temp_path.stat().st_size
|
|
227
|
-
temp_path.unlink()
|
|
228
|
-
total_freed += file_size
|
|
229
|
-
|
|
230
|
-
except Exception as e:
|
|
231
|
-
logger.warning(f"Failed to clean temp file {temp_file}: {e}")
|
|
232
|
-
|
|
233
|
-
except Exception as e:
|
|
234
|
-
logger.error(f"Temp file cleanup failed: {e}")
|
|
235
|
-
|
|
236
|
-
return total_freed
|
|
237
|
-
|
|
238
|
-
def process_video_with_storage_management(
|
|
239
|
-
self,
|
|
240
|
-
video_file: VideoFile,
|
|
241
|
-
cleanup_frames_after: bool = True,
|
|
242
|
-
progress_callback: Optional[callable] = None
|
|
243
|
-
) -> bool:
|
|
244
|
-
"""
|
|
245
|
-
Process a video with automatic storage management.
|
|
246
|
-
|
|
247
|
-
Args:
|
|
248
|
-
video_file: VideoFile instance to process
|
|
249
|
-
cleanup_frames_after: Whether to clean up frames after processing
|
|
250
|
-
progress_callback: Optional progress callback function
|
|
251
|
-
|
|
252
|
-
Returns:
|
|
253
|
-
True if processing succeeded, False otherwise
|
|
254
|
-
"""
|
|
255
|
-
try:
|
|
256
|
-
# Estimate required space (rough calculation)
|
|
257
|
-
video_size = 0
|
|
258
|
-
if video_file.raw_file and hasattr(video_file.raw_file, 'size'):
|
|
259
|
-
video_size = video_file.raw_file.size
|
|
260
|
-
|
|
261
|
-
# Estimate: frames ~= 3x video size, processing ~= 2x video size
|
|
262
|
-
estimated_space_needed = video_size * 5
|
|
263
|
-
|
|
264
|
-
# Check storage before starting
|
|
265
|
-
self.check_and_ensure_storage(estimated_space_needed)
|
|
266
|
-
|
|
267
|
-
# Update task status
|
|
268
|
-
task = self._get_or_create_task(video_file)
|
|
269
|
-
task.start_processing()
|
|
270
|
-
|
|
271
|
-
if progress_callback:
|
|
272
|
-
progress_callback(10, "Starting video processing...")
|
|
273
|
-
|
|
274
|
-
# Run the actual video processing pipeline
|
|
275
|
-
success = video_file.pipe_1(
|
|
276
|
-
model_name="image_multilabel_classification_colonoscopy_default",
|
|
277
|
-
delete_frames_after=cleanup_frames_after
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
if success:
|
|
281
|
-
if progress_callback:
|
|
282
|
-
progress_callback(90, "Processing completed, cleaning up...")
|
|
283
|
-
|
|
284
|
-
# Mark as completed
|
|
285
|
-
task.mark_completed("Video processing completed successfully")
|
|
286
|
-
|
|
287
|
-
# Additional cleanup if requested
|
|
288
|
-
if cleanup_frames_after:
|
|
289
|
-
self._cleanup_video_frames(video_file)
|
|
290
|
-
|
|
291
|
-
if progress_callback:
|
|
292
|
-
progress_callback(100, "Processing completed successfully")
|
|
293
|
-
|
|
294
|
-
logger.info(f"Video processing completed successfully: {video_file.uuid}")
|
|
295
|
-
return True
|
|
296
|
-
|
|
297
|
-
task.mark_failed("Video processing pipeline failed")
|
|
298
|
-
logger.error(f"Video processing failed: {video_file.uuid}")
|
|
299
|
-
return False
|
|
300
|
-
|
|
301
|
-
except InsufficientStorageError as e:
|
|
302
|
-
logger.error(f"Storage error during video processing: {e}")
|
|
303
|
-
task = self._get_or_create_task(video_file)
|
|
304
|
-
task.mark_failed(f"Insufficient storage: {e}")
|
|
305
|
-
return False
|
|
306
|
-
|
|
307
|
-
except Exception as e:
|
|
308
|
-
logger.error(f"Video processing failed: {e}")
|
|
309
|
-
task = self._get_or_create_task(video_file)
|
|
310
|
-
task.mark_failed(f"Processing error: {e}")
|
|
311
|
-
return False
|
|
312
|
-
|
|
313
|
-
def _get_or_create_task(self, video_file: VideoFile) -> AnonymizationTask:
|
|
314
|
-
"""Get or create an anonymization task for the video."""
|
|
315
|
-
task, created = AnonymizationTask.objects.get_or_create(
|
|
316
|
-
video_file=video_file,
|
|
317
|
-
defaults={
|
|
318
|
-
'status': 'not_started',
|
|
319
|
-
'progress': 0,
|
|
320
|
-
'message': 'Initializing...'
|
|
321
|
-
}
|
|
322
|
-
)
|
|
323
|
-
return task
|
|
324
|
-
|
|
325
|
-
def _cleanup_video_frames(self, video_file: VideoFile):
|
|
326
|
-
"""Clean up frames for a specific video."""
|
|
327
|
-
try:
|
|
328
|
-
from django.conf import settings
|
|
329
|
-
frames_dir = Path(settings.BASE_DIR).parent / 'storage' / 'frames'
|
|
330
|
-
|
|
331
|
-
# Find frame directories for this video
|
|
332
|
-
video_frame_dirs = list(frames_dir.glob(f"*{video_file.uuid}*"))
|
|
333
|
-
|
|
334
|
-
for frame_dir in video_frame_dirs:
|
|
335
|
-
if frame_dir.is_dir():
|
|
336
|
-
shutil.rmtree(frame_dir, ignore_errors=True)
|
|
337
|
-
logger.info(f"Cleaned up frames for video {video_file.uuid}")
|
|
338
|
-
|
|
339
|
-
except Exception as e:
|
|
340
|
-
logger.warning(f"Failed to clean up frames for {video_file.uuid}: {e}")
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
# Global instance for easy access
|
|
344
|
-
storage_aware_processor = StorageAwareVideoProcessor()
|
endoreg_db/urls/files.py
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
from django.urls import path
|
|
2
|
-
|
|
3
|
-
from endoreg_db.views.label_video_segment.validate import (
|
|
4
|
-
LabelVideoSegmentValidateView,
|
|
5
|
-
BulkSegmentValidateView,
|
|
6
|
-
VideoSegmentValidationCompleteView
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
url_patterns = [
|
|
10
|
-
# Einzelne Segment-Validierung
|
|
11
|
-
# POST /api/label-video-segment/<int:segment_id>/validate/
|
|
12
|
-
path(
|
|
13
|
-
'label-video-segment/<int:segment_id>/validate/',
|
|
14
|
-
LabelVideoSegmentValidateView.as_view(),
|
|
15
|
-
name='label_video_segment_validate'
|
|
16
|
-
),
|
|
17
|
-
|
|
18
|
-
# Bulk-Validierung mehrerer Segmente
|
|
19
|
-
# POST /api/label-video-segments/validate-bulk/
|
|
20
|
-
path(
|
|
21
|
-
'label-video-segments/validate-bulk/',
|
|
22
|
-
BulkSegmentValidateView.as_view(),
|
|
23
|
-
name='label_video_segments_validate_bulk'
|
|
24
|
-
),
|
|
25
|
-
|
|
26
|
-
# Alle Segmente eines Videos als validiert markieren
|
|
27
|
-
# POST /api/videos/<int:video_id>/segments/validate-complete/
|
|
28
|
-
path(
|
|
29
|
-
'videos/<int:video_id>/segments/validate-complete/',
|
|
30
|
-
VideoSegmentValidationCompleteView.as_view(),
|
|
31
|
-
name='video_segments_validate_complete'
|
|
32
|
-
),
|
|
33
|
-
]
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
from django.urls import path
|
|
2
|
-
from endoreg_db.views import (
|
|
3
|
-
create_video_segment_annotation,
|
|
4
|
-
update_label_video_segment,
|
|
5
|
-
SensitiveMetaDetailView,
|
|
6
|
-
video_segments_view,
|
|
7
|
-
video_segment_detail_view,
|
|
8
|
-
get_lvs_by_name_and_video_id
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
url_patterns = [
|
|
14
|
-
path(
|
|
15
|
-
"lvs/by-label-name/<str:label_name>/by-video-id/<int:video_id>/",
|
|
16
|
-
get_lvs_by_name_and_video_id,
|
|
17
|
-
name='get_lvs_by_name_and_video_id'
|
|
18
|
-
),
|
|
19
|
-
path(
|
|
20
|
-
'annotations/',
|
|
21
|
-
create_video_segment_annotation,
|
|
22
|
-
name='create_annotation'
|
|
23
|
-
),
|
|
24
|
-
path(
|
|
25
|
-
'annotations/<int:annotation_id>/',
|
|
26
|
-
update_label_video_segment,
|
|
27
|
-
name='update_annotation'
|
|
28
|
-
),
|
|
29
|
-
path(
|
|
30
|
-
'save-anonymization-annotation-video/<int:annotation_id>/',
|
|
31
|
-
SensitiveMetaDetailView.as_view(),
|
|
32
|
-
name='save_anonymization_annotation_video'
|
|
33
|
-
),
|
|
34
|
-
# Label Video Segment API endpoints
|
|
35
|
-
path(
|
|
36
|
-
'video-segments/',
|
|
37
|
-
video_segments_view,
|
|
38
|
-
name='video_segments'
|
|
39
|
-
),
|
|
40
|
-
path(
|
|
41
|
-
'video-segments/<int:segment_id>/',
|
|
42
|
-
video_segment_detail_view,
|
|
43
|
-
name='video_segment_detail'
|
|
44
|
-
),
|
|
45
|
-
|
|
46
|
-
]
|