endoreg-db 0.8.9.32__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/__init__.py +0 -0
- endoreg_db/_version.py +34 -0
- endoreg_db/admin.py +97 -0
- endoreg_db/api/serializers/finding_descriptions.py +0 -0
- endoreg_db/api/views/finding_descriptions.py +0 -0
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +17 -0
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/authz/auth.py +78 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +20 -0
- endoreg_db/authz/middleware.py +84 -0
- endoreg_db/authz/permissions.py +138 -0
- endoreg_db/authz/policy.py +224 -0
- endoreg_db/authz/settings.py +64 -0
- endoreg_db/authz/views_auth.py +70 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +99 -0
- endoreg_db/config/__init__.py +0 -0
- endoreg_db/config/env.py +106 -0
- endoreg_db/config/settings/__init__.py +6 -0
- endoreg_db/config/settings/base.py +148 -0
- endoreg_db/config/settings/case_gen.py +32 -0
- endoreg_db/config/settings/dev.py +108 -0
- endoreg_db/config/settings/keycloak.py +177 -0
- endoreg_db/config/settings/prod.py +66 -0
- endoreg_db/config/settings/test.py +72 -0
- endoreg_db/data/__init__.py +135 -0
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/ai_model_label/label/data.yaml +88 -0
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_type/data.yaml +7 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
- endoreg_db/data/case_template/rule_value/.init +0 -0
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
- endoreg_db/data/case_template/template/base.yaml +8 -0
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
- endoreg_db/data/case_template/tmp/_rule_value +13 -0
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
- endoreg_db/data/center/data.yaml +99 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +5 -0
- endoreg_db/data/disease/renal.yaml +5 -0
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
- endoreg_db/data/distribution/date/patient.yaml +7 -0
- endoreg_db/data/distribution/multiple_categorical/.init +0 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +11 -0
- endoreg_db/data/endoscopy_processor/data.yaml +50 -0
- endoreg_db/data/event/cardiology.yaml +15 -0
- endoreg_db/data/event/neurology.yaml +14 -0
- endoreg_db/data/event/surgery.yaml +13 -0
- endoreg_db/data/event/thrombembolism.yaml +20 -0
- 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 +172 -0
- endoreg_db/data/examination/time/data.yaml +48 -0
- endoreg_db/data/examination/time-type/data.yaml +5 -0
- endoreg_db/data/examination/type/data.yaml +17 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +359 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +90 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +97 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- 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/00_generic.yaml +15 -0
- endoreg_db/data/finding_classification_choice/00_generic_baseline.yaml +23 -0
- endoreg_db/data/finding_classification_choice/00_generic_complication.yaml +15 -0
- endoreg_db/data/finding_classification_choice/00_generic_histology.yaml +21 -0
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_bowel_preparation.yaml +49 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_generic.yaml +19 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_histology.yaml +20 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_location.yaml +248 -0
- 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/02_colonoscopy_polyp_morphology.yaml +75 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/00_generic.yaml +53 -0
- 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_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_type/data.yaml +39 -0
- endoreg_db/data/gender/data.yaml +42 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +6 -0
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +37 -0
- endoreg_db/data/lab_value/coagulation.yaml +54 -0
- endoreg_db/data/lab_value/electrolytes.yaml +228 -0
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -0
- endoreg_db/data/lab_value/hematology.yaml +184 -0
- endoreg_db/data/lab_value/hormones.yaml +59 -0
- endoreg_db/data/lab_value/lipids.yaml +53 -0
- endoreg_db/data/lab_value/misc.yaml +76 -0
- endoreg_db/data/lab_value/renal_function.yaml +12 -0
- endoreg_db/data/log_type/data.yaml +57 -0
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/material/material.yaml +91 -0
- endoreg_db/data/medication/anticoagulation.yaml +65 -0
- endoreg_db/data/medication/tah.yaml +70 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -0
- endoreg_db/data/medication_indication_type/data.yaml +11 -0
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
- endoreg_db/data/medication_intake_time/base.yaml +31 -0
- endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
- endoreg_db/data/medication_schedule/ass.yaml +12 -0
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +59 -0
- endoreg_db/data/network_device_type/data.yaml +12 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
- endoreg_db/data/pdf_type/data.yaml +46 -0
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
- endoreg_db/data/profession/data.yaml +70 -0
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -0
- 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/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement/old/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/old/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/old/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/old/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/old/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/old/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/old/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/old/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/old/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/old/gender.yaml +0 -0
- endoreg_db/data/requirement/old/lab_value.yaml +441 -0
- endoreg_db/data/requirement/old/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/_old/age.yaml +13 -0
- endoreg_db/data/requirement_operator/_old/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/_old/model_operators.yaml +96 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +65 -0
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set_type/data.yaml +41 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -0
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift/m2.yaml +0 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +32 -0
- endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
- endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
- endoreg_db/data/unit/concentration.yaml +115 -0
- endoreg_db/data/unit/data.yaml +17 -0
- endoreg_db/data/unit/length.yaml +31 -0
- endoreg_db/data/unit/misc.yaml +20 -0
- endoreg_db/data/unit/rate.yaml +6 -0
- endoreg_db/data/unit/time.yaml +48 -0
- endoreg_db/data/unit/volume.yaml +35 -0
- endoreg_db/data/unit/weight.yaml +38 -0
- endoreg_db/data/waste/data.yaml +12 -0
- endoreg_db/exceptions.py +24 -0
- endoreg_db/export/frames/export.py +6 -0
- endoreg_db/export/frames/export_frames_with_labels.py +616 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +4 -0
- endoreg_db/forms/examination_form.py +12 -0
- endoreg_db/forms/patient_finding_intervention_form.py +40 -0
- endoreg_db/forms/patient_form.py +23 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -0
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -0
- endoreg_db/forms/settings/__init__.py +11 -0
- endoreg_db/forms/unit.py +7 -0
- endoreg_db/helpers/__init__.py +0 -0
- endoreg_db/helpers/count_db.py +48 -0
- endoreg_db/helpers/data_loader.py +280 -0
- endoreg_db/helpers/default_objects.py +414 -0
- endoreg_db/helpers/download_segmentation_model.py +32 -0
- endoreg_db/helpers/interact.py +1 -0
- endoreg_db/helpers/test_video_helper.py +127 -0
- 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 +83 -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 +42 -0
- endoreg_db/import_files/context/validate_directories.py +57 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +99 -0
- endoreg_db/import_files/file_storage/create_video_file.py +104 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +42 -0
- endoreg_db/import_files/file_storage/state_management.py +463 -0
- endoreg_db/import_files/file_storage/storage.py +42 -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 +99 -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/pseudonymization/__init__.py +0 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +181 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +139 -0
- endoreg_db/import_files/pseudonymization/pseudonymize.py +0 -0
- endoreg_db/import_files/report_import_service.py +147 -0
- endoreg_db/import_files/video_import_service.py +154 -0
- endoreg_db/logger_conf.py +156 -0
- endoreg_db/management/__init__.py +1 -0
- endoreg_db/management/commands/__init__.py +1 -0
- endoreg_db/management/commands/anonymize_video.py +0 -0
- endoreg_db/management/commands/check_auth.py +132 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +177 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +419 -0
- endoreg_db/management/commands/export_frame_annot.py +196 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +206 -0
- endoreg_db/management/commands/fix_video_paths.py +186 -0
- endoreg_db/management/commands/import_report.py +361 -0
- endoreg_db/management/commands/list_routes.py +20 -0
- endoreg_db/management/commands/load_ai_model_data.py +83 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +60 -0
- endoreg_db/management/commands/load_base_db_data.py +63 -0
- endoreg_db/management/commands/load_center_data.py +68 -0
- endoreg_db/management/commands/load_contraindication_data.py +39 -0
- endoreg_db/management/commands/load_disease_classification_choices_data.py +38 -0
- endoreg_db/management/commands/load_disease_classification_data.py +38 -0
- endoreg_db/management/commands/load_disease_data.py +59 -0
- endoreg_db/management/commands/load_distribution_data.py +63 -0
- endoreg_db/management/commands/load_endoscope_data.py +58 -0
- endoreg_db/management/commands/load_event_data.py +39 -0
- endoreg_db/management/commands/load_examination_data.py +78 -0
- endoreg_db/management/commands/load_examination_indication_data.py +85 -0
- endoreg_db/management/commands/load_finding_data.py +115 -0
- endoreg_db/management/commands/load_gender_data.py +37 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +142 -0
- endoreg_db/management/commands/load_information_source.py +46 -0
- endoreg_db/management/commands/load_lab_value_data.py +52 -0
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_medication_data.py +104 -0
- endoreg_db/management/commands/load_name_data.py +36 -0
- endoreg_db/management/commands/load_organ_data.py +39 -0
- endoreg_db/management/commands/load_pdf_type_data.py +58 -0
- endoreg_db/management/commands/load_profession_data.py +40 -0
- endoreg_db/management/commands/load_qualification_data.py +56 -0
- endoreg_db/management/commands/load_report_reader_flag_data.py +40 -0
- endoreg_db/management/commands/load_requirement_data.py +207 -0
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +57 -0
- endoreg_db/management/commands/load_shift_data.py +57 -0
- endoreg_db/management/commands/load_tag_data.py +54 -0
- endoreg_db/management/commands/load_unit_data.py +40 -0
- endoreg_db/management/commands/load_user_groups.py +26 -0
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +70 -0
- endoreg_db/management/commands/setup_endoreg_db.py +459 -0
- endoreg_db/management/commands/start_filewatcher.py +115 -0
- endoreg_db/management/commands/storage_management.py +622 -0
- endoreg_db/management/commands/summarize_db_content.py +280 -0
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +189 -0
- endoreg_db/management/commands/video_validation.py +20 -0
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/migrations/0001_initial.py +1953 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +322 -0
- endoreg_db/models/administration/__init__.py +95 -0
- endoreg_db/models/administration/ai/__init__.py +9 -0
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +180 -0
- endoreg_db/models/administration/ai/model_type.py +42 -0
- endoreg_db/models/administration/case/__init__.py +5 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/administration/case/case_template/__init__.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_rule.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_type.py +3 -0
- endoreg_db/models/administration/center/__init__.py +13 -0
- endoreg_db/models/administration/center/center.py +85 -0
- endoreg_db/models/administration/center/center_product.py +67 -0
- endoreg_db/models/administration/center/center_resource.py +69 -0
- endoreg_db/models/administration/center/center_shift.py +94 -0
- endoreg_db/models/administration/center/center_waste.py +42 -0
- endoreg_db/models/administration/person/__init__.py +26 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +40 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +44 -0
- endoreg_db/models/administration/person/employee/employee_type.py +50 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +64 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/administration/person/names/first_name.py +20 -0
- endoreg_db/models/administration/person/names/last_name.py +20 -0
- endoreg_db/models/administration/person/patient/__init__.py +7 -0
- endoreg_db/models/administration/person/patient/patient.py +488 -0
- endoreg_db/models/administration/person/patient/patient_external_id.py +36 -0
- endoreg_db/models/administration/person/person.py +35 -0
- endoreg_db/models/administration/person/profession/__init__.py +28 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +41 -0
- endoreg_db/models/administration/product/__init__.py +15 -0
- endoreg_db/models/administration/product/product.py +106 -0
- endoreg_db/models/administration/product/product_group.py +41 -0
- endoreg_db/models/administration/product/product_material.py +60 -0
- endoreg_db/models/administration/product/product_weight.py +51 -0
- endoreg_db/models/administration/product/reference_product.py +147 -0
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +43 -0
- endoreg_db/models/administration/qualification/qualification_type.py +39 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +72 -0
- endoreg_db/models/administration/shift/shift.py +57 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +23 -0
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +85 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +61 -0
- endoreg_db/models/label/label.py +91 -0
- endoreg_db/models/label/label_set.py +68 -0
- endoreg_db/models/label/label_type.py +29 -0
- endoreg_db/models/label/label_video_segment/__init__.py +3 -0
- endoreg_db/models/label/label_video_segment/_create_from_video.py +42 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +611 -0
- endoreg_db/models/label/video_segmentation_label.py +35 -0
- endoreg_db/models/label/video_segmentation_labelset.py +28 -0
- endoreg_db/models/media/__init__.py +23 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +137 -0
- endoreg_db/models/media/pdf/__init__.py +12 -0
- endoreg_db/models/media/pdf/raw_pdf.py +764 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +85 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +46 -0
- endoreg_db/models/media/video/__init__.py +9 -0
- endoreg_db/models/media/video/create_from_file.py +402 -0
- endoreg_db/models/media/video/pipe_1.py +258 -0
- endoreg_db/models/media/video/pipe_2.py +129 -0
- endoreg_db/models/media/video/video_file.py +907 -0
- endoreg_db/models/media/video/video_file_ai.py +828 -0
- endoreg_db/models/media/video/video_file_anonymize.py +524 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +49 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +25 -0
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +126 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +233 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +36 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +13 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +24 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +40 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +44 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +30 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +205 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +228 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +107 -0
- endoreg_db/models/media/video/video_file_io.py +272 -0
- endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +58 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +62 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +183 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +198 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +178 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +105 -0
- endoreg_db/models/media/video/video_file_segments.py +317 -0
- endoreg_db/models/media/video/video_metadata.py +67 -0
- endoreg_db/models/media/video/video_processing.py +192 -0
- endoreg_db/models/medical/__init__.py +136 -0
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +29 -0
- endoreg_db/models/medical/disease.py +174 -0
- endoreg_db/models/medical/event.py +154 -0
- endoreg_db/models/medical/examination/__init__.py +20 -0
- endoreg_db/models/medical/examination/examination.py +183 -0
- endoreg_db/models/medical/examination/examination_indication.py +229 -0
- endoreg_db/models/medical/examination/examination_time.py +68 -0
- endoreg_db/models/medical/examination/examination_time_type.py +44 -0
- endoreg_db/models/medical/examination/examination_type.py +47 -0
- endoreg_db/models/medical/finding/__init__.py +20 -0
- endoreg_db/models/medical/finding/finding.py +113 -0
- endoreg_db/models/medical/finding/finding_classification.py +131 -0
- endoreg_db/models/medical/finding/finding_intervention.py +68 -0
- endoreg_db/models/medical/finding/finding_type.py +38 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +77 -0
- endoreg_db/models/medical/hardware/endoscopy_processor.py +182 -0
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +490 -0
- endoreg_db/models/medical/medication/__init__.py +23 -0
- endoreg_db/models/medical/medication/medication.py +45 -0
- endoreg_db/models/medical/medication/medication_indication.py +78 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +58 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +58 -0
- endoreg_db/models/medical/medication/medication_schedule.py +58 -0
- endoreg_db/models/medical/organ/__init__.py +38 -0
- endoreg_db/models/medical/patient/__init__.py +48 -0
- endoreg_db/models/medical/patient/medication_examples.py +56 -0
- endoreg_db/models/medical/patient/patient_disease.py +72 -0
- endoreg_db/models/medical/patient/patient_event.py +80 -0
- endoreg_db/models/medical/patient/patient_examination.py +280 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +57 -0
- endoreg_db/models/medical/patient/patient_finding.py +416 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +231 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +37 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +157 -0
- endoreg_db/models/medical/patient/patient_lab_value.py +247 -0
- endoreg_db/models/medical/patient/patient_medication.py +111 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +152 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +73 -0
- endoreg_db/models/medical/risk/risk_type.py +54 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/model_meta.py +266 -0
- endoreg_db/models/metadata/model_meta_logic.py +485 -0
- endoreg_db/models/metadata/pdf_meta.py +96 -0
- endoreg_db/models/metadata/sensitive_meta.py +345 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1161 -0
- endoreg_db/models/metadata/video_meta.py +459 -0
- endoreg_db/models/metadata/video_prediction_logic.py +232 -0
- endoreg_db/models/metadata/video_prediction_meta.py +319 -0
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +40 -0
- endoreg_db/models/other/distribution/__init__.py +46 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +22 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +163 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +50 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +211 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +23 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +110 -0
- endoreg_db/models/other/gender.py +32 -0
- endoreg_db/models/other/information_source.py +190 -0
- endoreg_db/models/other/material.py +34 -0
- endoreg_db/models/other/resource.py +24 -0
- endoreg_db/models/other/tag.py +32 -0
- endoreg_db/models/other/transport_route.py +40 -0
- endoreg_db/models/other/unit.py +40 -0
- endoreg_db/models/other/waste.py +28 -0
- endoreg_db/models/report/__init__.py +0 -0
- endoreg_db/models/report/images.py +0 -0
- endoreg_db/models/report/report.py +5 -0
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +792 -0
- endoreg_db/models/requirement/requirement_error.py +84 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +137 -0
- endoreg_db/models/requirement/requirement_operator.py +187 -0
- endoreg_db/models/requirement/requirement_set.py +327 -0
- endoreg_db/models/state/__init__.py +13 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/anonymization.py +30 -0
- endoreg_db/models/state/audit_ledger.py +155 -0
- endoreg_db/models/state/label_video_segment.py +31 -0
- endoreg_db/models/state/processing_history/__init__.py +3 -0
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +219 -0
- endoreg_db/models/state/sensitive_meta.py +50 -0
- endoreg_db/models/state/video.py +251 -0
- endoreg_db/models/upload_job.py +100 -0
- endoreg_db/models/utils.py +138 -0
- endoreg_db/queries/__init__.py +3 -0
- endoreg_db/queries/annotations/__init__.py +1 -0
- endoreg_db/queries/annotations/legacy.py +169 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- endoreg_db/root_urls.py +27 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +30 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +861 -0
- endoreg_db/serializers/__init__.py +104 -0
- endoreg_db/serializers/administration/__init__.py +13 -0
- endoreg_db/serializers/administration/ai/__init__.py +9 -0
- endoreg_db/serializers/administration/ai/active_model.py +12 -0
- endoreg_db/serializers/administration/ai/ai_model.py +20 -0
- endoreg_db/serializers/administration/ai/model_type.py +12 -0
- endoreg_db/serializers/administration/center.py +14 -0
- endoreg_db/serializers/administration/gender.py +11 -0
- endoreg_db/serializers/anonymization.py +77 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +45 -0
- endoreg_db/serializers/examination/dropdown.py +20 -0
- endoreg_db/serializers/examination_serializer.py +9 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +61 -0
- endoreg_db/serializers/finding_classification/__init__.py +7 -0
- endoreg_db/serializers/finding_classification/choice.py +19 -0
- endoreg_db/serializers/finding_classification/classification.py +11 -0
- endoreg_db/serializers/label_video_segment/__init__.py +9 -0
- endoreg_db/serializers/label_video_segment/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/label_video_segment/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +427 -0
- endoreg_db/serializers/meta/__init__.py +13 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +122 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +153 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +62 -0
- endoreg_db/serializers/meta/video_meta.py +39 -0
- endoreg_db/serializers/misc/__init__.py +14 -0
- endoreg_db/serializers/misc/file_overview.py +72 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +144 -0
- endoreg_db/serializers/misc/stats.py +35 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +74 -0
- endoreg_db/serializers/patient/__init__.py +12 -0
- endoreg_db/serializers/patient/patient.py +103 -0
- endoreg_db/serializers/patient/patient_dropdown.py +35 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +168 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +32 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +47 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +62 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +28 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +40 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +135 -0
- endoreg_db/serializers/pdf/__init__.py +3 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +101 -0
- endoreg_db/serializers/requirements/requirement_schema.py +20 -0
- endoreg_db/serializers/requirements/requirement_sets.py +99 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +301 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/video_file.py +283 -0
- endoreg_db/serializers/video/video_file_brief.py +14 -0
- endoreg_db/serializers/video/video_file_detail.py +96 -0
- endoreg_db/serializers/video/video_file_list.py +100 -0
- endoreg_db/serializers/video/video_processing_history.py +172 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +274 -0
- endoreg_db/services/examination_evaluation.py +172 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +424 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/pdf_import.py +0 -0
- endoreg_db/services/polling_coordinator.py +319 -0
- endoreg_db/services/pseudonym_service.py +94 -0
- endoreg_db/services/report_import.py +13 -0
- endoreg_db/services/segment_sync.py +171 -0
- endoreg_db/services/video_import.py +9 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls/__init__.py +56 -0
- endoreg_db/urls/ai.py +14 -0
- endoreg_db/urls/anonymization.py +78 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +34 -0
- endoreg_db/urls/examination.py +63 -0
- endoreg_db/urls/media.py +251 -0
- endoreg_db/urls/patient.py +23 -0
- endoreg_db/urls/requirements.py +15 -0
- endoreg_db/urls/root_urls.py +28 -0
- endoreg_db/urls/stats.py +54 -0
- endoreg_db/urls/upload.py +12 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +97 -0
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +6 -0
- endoreg_db/utils/ai/inference_dataset.py +51 -0
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +270 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +293 -0
- endoreg_db/utils/ai/preprocess.py +76 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +32 -0
- endoreg_db/utils/check_video_files.py +175 -0
- endoreg_db/utils/cropping.py +30 -0
- endoreg_db/utils/dataloader.py +285 -0
- endoreg_db/utils/dates.py +59 -0
- endoreg_db/utils/defaults/set_default_center.py +33 -0
- endoreg_db/utils/env.py +37 -0
- endoreg_db/utils/extract_specific_frames.py +87 -0
- endoreg_db/utils/file_operations.py +70 -0
- endoreg_db/utils/fix_video_path_direct.py +157 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +138 -0
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +237 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +82 -0
- endoreg_db/utils/ocr.py +195 -0
- endoreg_db/utils/operation_log.py +87 -0
- endoreg_db/utils/parse_and_generate_yaml.py +45 -0
- endoreg_db/utils/paths.py +159 -0
- endoreg_db/utils/permissions.py +160 -0
- endoreg_db/utils/pipelines/Readme.md +235 -0
- endoreg_db/utils/pipelines/__init__.py +0 -0
- endoreg_db/utils/pipelines/process_video_dir.py +144 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +22 -0
- endoreg_db/utils/product/sum_weights.py +20 -0
- endoreg_db/utils/pydantic_models/__init__.py +5 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/requirement_helpers.py +0 -0
- endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +678 -0
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +842 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +114 -0
- endoreg_db/utils/setup_config.py +196 -0
- endoreg_db/utils/storage.py +117 -0
- endoreg_db/utils/translation.py +31 -0
- endoreg_db/utils/uuid.py +5 -0
- endoreg_db/utils/validate_endo_roi.py +33 -0
- endoreg_db/utils/validate_subcategory_dict.py +93 -0
- endoreg_db/utils/validate_video_detailed.py +415 -0
- endoreg_db/utils/video/__init__.py +30 -0
- endoreg_db/utils/video/extract_frames.py +100 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +996 -0
- endoreg_db/utils/video/names.py +47 -0
- endoreg_db/utils/video/streaming_processor.py +386 -0
- endoreg_db/utils/video/video_splitter.py +105 -0
- endoreg_db/versioning.md +79 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +247 -0
- endoreg_db/views/__init__.py +157 -0
- endoreg_db/views/anonymization/__init__.py +31 -0
- endoreg_db/views/anonymization/media_management.py +486 -0
- endoreg_db/views/anonymization/overview.py +307 -0
- endoreg_db/views/anonymization/validate.py +310 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +146 -0
- endoreg_db/views/examination/__init__.py +30 -0
- endoreg_db/views/examination/examination.py +37 -0
- endoreg_db/views/examination/examination_manifest_cache.py +26 -0
- endoreg_db/views/examination/get_finding_classification_choices.py +62 -0
- endoreg_db/views/examination/get_finding_classifications.py +38 -0
- endoreg_db/views/examination/get_findings.py +39 -0
- endoreg_db/views/examination/get_instruments.py +19 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +116 -0
- endoreg_db/views/finding/get_classifications.py +14 -0
- endoreg_db/views/finding/get_interventions.py +17 -0
- endoreg_db/views/finding_classification/__init__.py +13 -0
- endoreg_db/views/finding_classification/base.py +0 -0
- endoreg_db/views/finding_classification/finding_classification.py +41 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +54 -0
- endoreg_db/views/media/__init__.py +32 -0
- endoreg_db/views/media/pdf_media.py +411 -0
- endoreg_db/views/media/sensitive_metadata.py +372 -0
- endoreg_db/views/media/video_media.py +275 -0
- endoreg_db/views/meta/__init__.py +7 -0
- endoreg_db/views/meta/sensitive_meta_list.py +102 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +74 -0
- endoreg_db/views/misc/__init__.py +29 -0
- endoreg_db/views/misc/center.py +14 -0
- endoreg_db/views/misc/csrf.py +8 -0
- endoreg_db/views/misc/gender.py +15 -0
- endoreg_db/views/misc/stats.py +255 -0
- endoreg_db/views/misc/upload_views.py +241 -0
- endoreg_db/views/patient/__init__.py +3 -0
- endoreg_db/views/patient/patient.py +253 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +141 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +58 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +72 -0
- endoreg_db/views/patient_examination/video.py +228 -0
- endoreg_db/views/patient_finding/__init__.py +7 -0
- endoreg_db/views/patient_finding/base.py +0 -0
- endoreg_db/views/patient_finding/patient_finding.py +71 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +291 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +75 -0
- endoreg_db/views/report/__init__.py +7 -0
- endoreg_db/views/report/reimport.py +177 -0
- endoreg_db/views/report/report_stream.py +191 -0
- endoreg_db/views/requirement/__init__.py +11 -0
- endoreg_db/views/requirement/evaluate.py +278 -0
- endoreg_db/views/requirement/lookup.py +380 -0
- endoreg_db/views/requirement/lookup_store.py +183 -0
- endoreg_db/views/requirement/requirement_utils.py +87 -0
- endoreg_db/views/requirement_lookup/lookup.py +0 -0
- endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
- endoreg_db/views/stats/__init__.py +13 -0
- endoreg_db/views/stats/stats_views.py +266 -0
- endoreg_db/views/video/__init__.py +49 -0
- endoreg_db/views/video/ai/__init__.py +8 -0
- endoreg_db/views/video/ai/label.py +159 -0
- endoreg_db/views/video/correction.py +529 -0
- endoreg_db/views/video/reimport.py +230 -0
- endoreg_db/views/video/segments_crud.py +709 -0
- endoreg_db/views/video/video_apply_mask.py +49 -0
- endoreg_db/views/video/video_correction.py +22 -0
- endoreg_db/views/video/video_download_processed.py +58 -0
- endoreg_db/views/video/video_examination_viewset.py +242 -0
- endoreg_db/views/video/video_metadata.py +101 -0
- endoreg_db/views/video/video_processing_history.py +25 -0
- endoreg_db/views/video/video_remove_frames.py +49 -0
- endoreg_db/views/video/video_stream.py +334 -0
- endoreg_db-0.8.9.32.dist-info/METADATA +404 -0
- endoreg_db-0.8.9.32.dist-info/RECORD +787 -0
- endoreg_db-0.8.9.32.dist-info/WHEEL +4 -0
- endoreg_db-0.8.9.32.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
from lx_anonymizer import FrameCleaner
|
|
6
|
+
from lx_anonymizer.sensitive_meta_interface import SensitiveMeta as LxSM
|
|
7
|
+
|
|
8
|
+
from endoreg_db.import_files.context import ImportContext
|
|
9
|
+
from endoreg_db.import_files.file_storage.sensitive_meta_storage import (
|
|
10
|
+
sensitive_meta_storage,
|
|
11
|
+
)
|
|
12
|
+
from endoreg_db.models import EndoscopyProcessor, VideoFile
|
|
13
|
+
from endoreg_db.utils.paths import ANONYM_VIDEO_DIR
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VideoAnonymizer:
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self._ensure_frame_cleaning_available()
|
|
19
|
+
self._frame_cleaning_available = None
|
|
20
|
+
self._frame_cleaning_class = None
|
|
21
|
+
self.storage = False
|
|
22
|
+
|
|
23
|
+
def anonymize_video(self, ctx: ImportContext):
|
|
24
|
+
# Setup anonymized directory
|
|
25
|
+
anonymized_dir = ANONYM_VIDEO_DIR
|
|
26
|
+
anonymized_dir.mkdir(parents=True, exist_ok=True)
|
|
27
|
+
assert ctx.current_video is not None
|
|
28
|
+
# Generate output path for anonymized report
|
|
29
|
+
|
|
30
|
+
video_hash = ctx.current_video.video_hash
|
|
31
|
+
anonymized_output_path = anonymized_dir / f"{video_hash}.mp4"
|
|
32
|
+
|
|
33
|
+
self._frame_cleaning_class = FrameCleaner()
|
|
34
|
+
|
|
35
|
+
assert isinstance(self._frame_cleaning_class, FrameCleaner)
|
|
36
|
+
endoscope_roi, endoscope_roi_nested = self._get_processor_roi_info(ctx)
|
|
37
|
+
# Process with enhanced process_report method (returns 4-tuple now)
|
|
38
|
+
ctx.anonymized_path, extracted_metadata = (
|
|
39
|
+
self._frame_cleaning_class.clean_video(
|
|
40
|
+
video_path=ctx.file_path,
|
|
41
|
+
endoscope_image_roi=endoscope_roi,
|
|
42
|
+
endoscope_data_roi_nested=endoscope_roi_nested,
|
|
43
|
+
output_path=anonymized_output_path,
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
sm = LxSM()
|
|
47
|
+
sm.safe_update(extracted_metadata)
|
|
48
|
+
|
|
49
|
+
self.storage = sensitive_meta_storage(sm, ctx.current_video)
|
|
50
|
+
return ctx
|
|
51
|
+
|
|
52
|
+
def _ensure_frame_cleaning_available(self):
|
|
53
|
+
"""
|
|
54
|
+
Ensure frame cleaning modules are available by adding lx-anonymizer to path.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Tuple of (availability_flag, FrameCleaner_class, ReportReader_class)
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
from lx_anonymizer import FrameCleaner
|
|
61
|
+
except Exception as e:
|
|
62
|
+
logger.warning(
|
|
63
|
+
f"Frame cleaning not available: {e} Please install or update lx_anonymizer."
|
|
64
|
+
)
|
|
65
|
+
raise
|
|
66
|
+
|
|
67
|
+
assert FrameCleaner is not None
|
|
68
|
+
self._frame_cleaning_class = FrameCleaner()
|
|
69
|
+
self._frame_cleaning_available = True
|
|
70
|
+
|
|
71
|
+
def _get_processor_roi_info(
|
|
72
|
+
self,
|
|
73
|
+
ctx: ImportContext,
|
|
74
|
+
) -> tuple[
|
|
75
|
+
dict[str, int | None] | None, dict[str, dict[str, int | None] | None] | None
|
|
76
|
+
]:
|
|
77
|
+
"""Get processor ROI information for masking and data extraction."""
|
|
78
|
+
endoscope_data_roi_nested = None
|
|
79
|
+
endoscope_image_roi = None
|
|
80
|
+
|
|
81
|
+
video = ctx.current_video
|
|
82
|
+
assert isinstance(video, VideoFile)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
processor_name = ctx.processor_name if ctx.processor_name else None
|
|
86
|
+
if processor_name:
|
|
87
|
+
pr = EndoscopyProcessor()
|
|
88
|
+
processor = pr.get_by_name(processor_name)
|
|
89
|
+
assert isinstance(processor, EndoscopyProcessor), (
|
|
90
|
+
"Processor is not of type EndoscopyProcessor"
|
|
91
|
+
)
|
|
92
|
+
endoscope_image_roi = processor.get_roi_endoscope_image()
|
|
93
|
+
endoscope_data_roi_nested = processor.get_sensitive_rois()
|
|
94
|
+
logger.info(
|
|
95
|
+
"Retrieved processor ROI information: endoscope_image_roi=%s",
|
|
96
|
+
endoscope_image_roi,
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
logger.warning(
|
|
100
|
+
"No processor found for video %s, proceeding without ROI masking",
|
|
101
|
+
video.video_hash,
|
|
102
|
+
)
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
logger.error("Failed to retrieve processor ROI information: %s", exc)
|
|
105
|
+
|
|
106
|
+
# IMPORTANT: return order must match clean_video signature
|
|
107
|
+
return endoscope_image_roi, endoscope_data_roi_nested
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from datetime import date, timedelta
|
|
2
|
+
from typing import Tuple, Optional
|
|
3
|
+
from faker import Faker
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def fake_name_with_similar_dob_and_gender(
|
|
8
|
+
gender: str,
|
|
9
|
+
dob: date,
|
|
10
|
+
*,
|
|
11
|
+
year_tolerance: int = 3,
|
|
12
|
+
locale: str = "de_DE",
|
|
13
|
+
seed: Optional[int] = None,
|
|
14
|
+
) -> Tuple[str, str, date]:
|
|
15
|
+
"""
|
|
16
|
+
Generate a fake name with the same gender and a similar date of birth.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
gender: "male" or "female"
|
|
20
|
+
dob: Original date of birth
|
|
21
|
+
year_tolerance: Maximum age difference in years
|
|
22
|
+
locale: Faker locale (default: German)
|
|
23
|
+
seed: Optional reproducible seed
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
(full_name, fake_dob)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
if gender not in {"male", "female"}:
|
|
30
|
+
raise ValueError("gender must be 'male' or 'female'")
|
|
31
|
+
|
|
32
|
+
fake = Faker(locale)
|
|
33
|
+
|
|
34
|
+
if seed is not None:
|
|
35
|
+
Faker.seed(seed)
|
|
36
|
+
random.seed(seed)
|
|
37
|
+
|
|
38
|
+
# --- Generate gender-safe name ---
|
|
39
|
+
if gender == "male":
|
|
40
|
+
first_name = fake.first_name_male()
|
|
41
|
+
else:
|
|
42
|
+
first_name = fake.first_name_female()
|
|
43
|
+
|
|
44
|
+
last_name = fake.last_name()
|
|
45
|
+
full_name = f"{first_name} {last_name}"
|
|
46
|
+
|
|
47
|
+
# --- Generate similar DOB ---
|
|
48
|
+
days_range = year_tolerance * 365
|
|
49
|
+
offset_days = random.randint(-days_range, days_range)
|
|
50
|
+
fake_dob = dob + timedelta(days=offset_days)
|
|
51
|
+
|
|
52
|
+
return first_name, last_name, fake_dob
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from endoreg_db.models import SensitiveMeta
|
|
2
|
+
import logging
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from typing import Tuple
|
|
5
|
+
|
|
6
|
+
from django.db.models import QuerySet
|
|
7
|
+
|
|
8
|
+
from itertools import combinations
|
|
9
|
+
from typing import Dict
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
QI_FLAGS = ["first_name", "last_name", "center", "gender", "dob_band"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_k_profile_for_instance(
|
|
18
|
+
instance: SensitiveMeta,
|
|
19
|
+
*,
|
|
20
|
+
dob_year_tolerance: int = 1,
|
|
21
|
+
include_self: bool = True,
|
|
22
|
+
) -> Dict[Tuple[str, ...], int]:
|
|
23
|
+
"""
|
|
24
|
+
For a given SensitiveMeta instance, compute k (equivalence class size)
|
|
25
|
+
for all non-empty subsets of the quasi-identifiers defined in QI_FLAGS.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
{
|
|
29
|
+
('first_name',): 12,
|
|
30
|
+
('center', 'gender'): 45,
|
|
31
|
+
('first_name', 'last_name', 'dob_band'): 3,
|
|
32
|
+
...
|
|
33
|
+
}
|
|
34
|
+
"""
|
|
35
|
+
result: Dict[Tuple[str, ...], int] = {}
|
|
36
|
+
|
|
37
|
+
for r in range(1, len(QI_FLAGS) + 1):
|
|
38
|
+
for subset in combinations(QI_FLAGS, r):
|
|
39
|
+
use_first_name = "first_name" in subset
|
|
40
|
+
use_last_name = "last_name" in subset
|
|
41
|
+
use_center = "center" in subset
|
|
42
|
+
use_gender = "gender" in subset
|
|
43
|
+
use_dob_band = "dob_band" in subset
|
|
44
|
+
|
|
45
|
+
qs = _build_sensitive_meta_qi_queryset(
|
|
46
|
+
instance,
|
|
47
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
48
|
+
include_self=include_self,
|
|
49
|
+
use_first_name=use_first_name,
|
|
50
|
+
use_last_name=use_last_name,
|
|
51
|
+
use_center=use_center,
|
|
52
|
+
use_gender=use_gender,
|
|
53
|
+
use_dob_band=use_dob_band,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
k_value = qs.count()
|
|
57
|
+
result[subset] = k_value
|
|
58
|
+
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_k_anonymity(pk, k=3):
|
|
63
|
+
"""
|
|
64
|
+
How anonymized is a patient?
|
|
65
|
+
Get the k value for how many patients can be matched to the current patients attributes.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
pk (_type_): _description_
|
|
69
|
+
k (int, optional): _description_. Defaults to 3.
|
|
70
|
+
"""
|
|
71
|
+
return get_k_anonymity_for_sensitive_meta(pk=pk, k=k, dob_year_tolerance=1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _build_sensitive_meta_qi_queryset(
|
|
75
|
+
instance: SensitiveMeta,
|
|
76
|
+
*,
|
|
77
|
+
dob_year_tolerance: int = 1,
|
|
78
|
+
include_self: bool = True,
|
|
79
|
+
use_first_name: bool = True,
|
|
80
|
+
use_last_name: bool = True,
|
|
81
|
+
use_center: bool = True,
|
|
82
|
+
use_gender: bool = True,
|
|
83
|
+
use_dob_band: bool = True,
|
|
84
|
+
) -> QuerySet[SensitiveMeta]:
|
|
85
|
+
"""
|
|
86
|
+
Build a queryset of SensitiveMeta records that are indistinguishable from
|
|
87
|
+
`instance` on the chosen quasi-identifiers:
|
|
88
|
+
|
|
89
|
+
- same center
|
|
90
|
+
- same patient_gender
|
|
91
|
+
- patient_dob within ±dob_year_tolerance years (approx via days)
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
instance: The SensitiveMeta instance we evaluate.
|
|
95
|
+
dob_year_tolerance: Allowed +- years around patient_dob.
|
|
96
|
+
include_self: Whether to include `instance` itself in the result.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
A Django QuerySet for further aggregation.
|
|
100
|
+
"""
|
|
101
|
+
qs = SensitiveMeta.objects.all()
|
|
102
|
+
|
|
103
|
+
if use_first_name and instance.patient_first_name is not None:
|
|
104
|
+
qs = qs.filter(patient_first_name=instance.patient_first_name)
|
|
105
|
+
|
|
106
|
+
if use_last_name and instance.patient_last_name is not None:
|
|
107
|
+
qs = qs.filter(patient_last_name=instance.patient_last_name)
|
|
108
|
+
# --- Center ---
|
|
109
|
+
if use_center and instance.center is not None:
|
|
110
|
+
if instance.center.pk is not None:
|
|
111
|
+
qs = qs.filter(center=instance.center.pk)
|
|
112
|
+
|
|
113
|
+
# --- Gender ---
|
|
114
|
+
if use_gender and instance.patient_gender is not None:
|
|
115
|
+
if instance.patient_gender.pk is not None:
|
|
116
|
+
qs = qs.filter(patient_gender_id=instance.patient_gender)
|
|
117
|
+
|
|
118
|
+
# --- DOB (approximate ±N years using days) ---
|
|
119
|
+
if use_dob_band and instance.patient_dob is not None:
|
|
120
|
+
days = dob_year_tolerance * 365
|
|
121
|
+
ref_date = instance.patient_dob.date()
|
|
122
|
+
start = ref_date - timedelta(days=days)
|
|
123
|
+
end = ref_date + timedelta(days=days)
|
|
124
|
+
qs = qs.filter(patient_dob__date__range=(start, end))
|
|
125
|
+
|
|
126
|
+
# --- Exclude self if requested ---
|
|
127
|
+
if not include_self and instance.pk is not None:
|
|
128
|
+
qs = qs.exclude(pk=instance.pk)
|
|
129
|
+
|
|
130
|
+
return qs
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def get_k_anonymity_for_sensitive_meta(
|
|
134
|
+
pk: int,
|
|
135
|
+
*,
|
|
136
|
+
k: int = 3,
|
|
137
|
+
dob_year_tolerance: int = 1,
|
|
138
|
+
) -> Tuple[int, bool]:
|
|
139
|
+
"""
|
|
140
|
+
Compute the k-anonymity (equivalence class size) for a SensitiveMeta record.
|
|
141
|
+
|
|
142
|
+
k-anonymity here is defined as the number of SensitiveMeta rows that share
|
|
143
|
+
the same quasi-identifiers as the given record:
|
|
144
|
+
|
|
145
|
+
- center
|
|
146
|
+
- patient_gender
|
|
147
|
+
- patient_dob within ±dob_year_tolerance years (approximate)
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
pk: Primary key of the SensitiveMeta instance to evaluate.
|
|
151
|
+
k: Desired anonymity threshold (e.g. 3 for 3-anonymity).
|
|
152
|
+
dob_year_tolerance: Allowed age window in years around patient_dob.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
(k_value, is_k_anonymous) where:
|
|
156
|
+
k_value = size of the equivalence class
|
|
157
|
+
is_k_anonymous = True if k_value >= k
|
|
158
|
+
"""
|
|
159
|
+
try:
|
|
160
|
+
sm = SensitiveMeta.objects.get(pk=pk)
|
|
161
|
+
except SensitiveMeta.DoesNotExist:
|
|
162
|
+
raise ValueError(f"SensitiveMeta with pk={pk} does not exist")
|
|
163
|
+
|
|
164
|
+
qs = _build_sensitive_meta_qi_queryset(
|
|
165
|
+
sm,
|
|
166
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
167
|
+
include_self=True,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
k_value = qs.count()
|
|
171
|
+
is_k_anon = k_value >= k
|
|
172
|
+
|
|
173
|
+
logger.info(
|
|
174
|
+
"k-anonymity for SensitiveMeta pk=%s -> k=%s (threshold=%s, dob_tol=%s years)",
|
|
175
|
+
pk,
|
|
176
|
+
k_value,
|
|
177
|
+
k,
|
|
178
|
+
dob_year_tolerance,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return k_value, is_k_anon
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from datetime import date as Date
|
|
5
|
+
|
|
6
|
+
from .k_anonymity import _build_sensitive_meta_qi_queryset
|
|
7
|
+
from .fake import fake_name_with_similar_dob_and_gender
|
|
8
|
+
|
|
9
|
+
from endoreg_db.models import SensitiveMeta
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def k_pseudonymize(
|
|
15
|
+
instance: SensitiveMeta,
|
|
16
|
+
*,
|
|
17
|
+
k_threshold: int = 3,
|
|
18
|
+
dob_year_tolerance: int = 3,
|
|
19
|
+
qi_subset: Optional[Tuple[str, ...]] = None,
|
|
20
|
+
locale: str = "de_DE",
|
|
21
|
+
seed: Optional[int] = None,
|
|
22
|
+
save: bool = True,
|
|
23
|
+
) -> Tuple[SensitiveMeta, int, bool]:
|
|
24
|
+
"""
|
|
25
|
+
Ensure a SensitiveMeta instance reaches at least `k_threshold` anonymity
|
|
26
|
+
for the given quasi-identifier subset by pseudonymizing patient
|
|
27
|
+
first_name, last_name and DOB if necessary.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
instance:
|
|
31
|
+
The SensitiveMeta instance to process.
|
|
32
|
+
k_threshold:
|
|
33
|
+
Minimal k for the chosen QI subset.
|
|
34
|
+
dob_year_tolerance:
|
|
35
|
+
Used both for k-anonymity DOB band and for Faker's DOB perturbation.
|
|
36
|
+
qi_subset:
|
|
37
|
+
Which QIs to use for k-anonymity check.
|
|
38
|
+
Elements from: {"first_name", "last_name", "center", "gender", "dob_band"}.
|
|
39
|
+
Default = all of them.
|
|
40
|
+
locale:
|
|
41
|
+
Faker locale for a realistic name.
|
|
42
|
+
seed:
|
|
43
|
+
Optional seed for reproducibility.
|
|
44
|
+
save:
|
|
45
|
+
If True, save the instance after pseudonymization.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
(instance, k_value_after, is_k_anonymous_after)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# --- 1) Compute k for the requested subset BEFORE pseudonymization ---
|
|
52
|
+
if qi_subset is None:
|
|
53
|
+
qi_subset = ("first_name", "last_name", "center", "gender", "dob_band")
|
|
54
|
+
# --- 1) Compute k for the requested subset BEFORE pseudonymization ---
|
|
55
|
+
use_first_name = "first_name" in qi_subset
|
|
56
|
+
use_last_name = "last_name" in qi_subset
|
|
57
|
+
use_center = "center" in qi_subset
|
|
58
|
+
use_gender = "gender" in qi_subset
|
|
59
|
+
use_dob_band = "dob_band" in qi_subset
|
|
60
|
+
use_first_name = "first_name" in qi_subset
|
|
61
|
+
use_last_name = "last_name" in qi_subset
|
|
62
|
+
use_center = "center" in qi_subset
|
|
63
|
+
use_gender = "gender" in qi_subset
|
|
64
|
+
use_dob_band = "dob_band" in qi_subset
|
|
65
|
+
|
|
66
|
+
qs_before = _build_sensitive_meta_qi_queryset(
|
|
67
|
+
instance,
|
|
68
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
69
|
+
include_self=True,
|
|
70
|
+
use_first_name=use_first_name,
|
|
71
|
+
use_last_name=use_last_name,
|
|
72
|
+
use_center=use_center,
|
|
73
|
+
use_gender=use_gender,
|
|
74
|
+
use_dob_band=use_dob_band,
|
|
75
|
+
)
|
|
76
|
+
k_before = qs_before.count()
|
|
77
|
+
|
|
78
|
+
if k_before >= k_threshold:
|
|
79
|
+
# Already sufficiently anonymous, nothing to do
|
|
80
|
+
return instance, k_before, True
|
|
81
|
+
|
|
82
|
+
# --- 2) Pseudonymize name + DOB using Faker ---
|
|
83
|
+
# Gender string for Faker
|
|
84
|
+
if instance.patient_gender and getattr(instance.patient_gender, "name", None):
|
|
85
|
+
gender_name = instance.patient_gender.name
|
|
86
|
+
else:
|
|
87
|
+
# Fallback if gender missing -> bias to 'male' but you can change that
|
|
88
|
+
gender_name = "male"
|
|
89
|
+
|
|
90
|
+
# Original DOB as date (fallback to today's date if missing)
|
|
91
|
+
if instance.patient_dob is not None:
|
|
92
|
+
orig_dob: Date = instance.patient_dob.date()
|
|
93
|
+
else:
|
|
94
|
+
orig_dob = Date.today()
|
|
95
|
+
|
|
96
|
+
first_name, last_name, fake_dob = fake_name_with_similar_dob_and_gender(
|
|
97
|
+
gender=gender_name,
|
|
98
|
+
dob=orig_dob,
|
|
99
|
+
year_tolerance=dob_year_tolerance,
|
|
100
|
+
locale=locale,
|
|
101
|
+
seed=seed,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Assign to instance (SensitiveMeta.patient_dob is a DateTimeField)
|
|
105
|
+
instance.patient_first_name = first_name
|
|
106
|
+
instance.patient_last_name = last_name
|
|
107
|
+
instance.patient_dob = Date(
|
|
108
|
+
fake_dob.year, fake_dob.month, fake_dob.day
|
|
109
|
+
) # naive is usually fine for DOB
|
|
110
|
+
|
|
111
|
+
if save:
|
|
112
|
+
instance.save(
|
|
113
|
+
update_fields=["patient_first_name", "patient_last_name", "patient_dob"]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# --- 3) Recompute k AFTER pseudonymization ---
|
|
117
|
+
qs_after = _build_sensitive_meta_qi_queryset(
|
|
118
|
+
instance,
|
|
119
|
+
dob_year_tolerance=dob_year_tolerance,
|
|
120
|
+
include_self=True,
|
|
121
|
+
use_first_name=use_first_name,
|
|
122
|
+
use_last_name=use_last_name,
|
|
123
|
+
use_center=use_center,
|
|
124
|
+
use_gender=use_gender,
|
|
125
|
+
use_dob_band=use_dob_band,
|
|
126
|
+
)
|
|
127
|
+
k_after = qs_after.count()
|
|
128
|
+
is_k_anon_after = k_after >= k_threshold
|
|
129
|
+
|
|
130
|
+
logger.info(
|
|
131
|
+
"k_pseudonymize: SensitiveMeta pk=%s, subset=%s, k_before=%s, k_after=%s, threshold=%s",
|
|
132
|
+
instance.pk,
|
|
133
|
+
qi_subset,
|
|
134
|
+
k_before,
|
|
135
|
+
k_after,
|
|
136
|
+
k_threshold,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return instance, k_after, is_k_anon_after
|
|
File without changes
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# endoreg_db/services/report_import_service.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
|
|
8
|
+
from endoreg_db.import_files.context.file_lock import file_lock
|
|
9
|
+
from endoreg_db.import_files.context.import_context import ImportContext
|
|
10
|
+
from endoreg_db.import_files.context.validate_directories import validate_directories
|
|
11
|
+
from endoreg_db.import_files.file_storage.create_report_file import (
|
|
12
|
+
create_or_retrieve_report_file,
|
|
13
|
+
)
|
|
14
|
+
from endoreg_db.import_files.file_storage.state_management import (
|
|
15
|
+
finalize_failure,
|
|
16
|
+
finalize_report_success,
|
|
17
|
+
mark_instance_processing_started,
|
|
18
|
+
)
|
|
19
|
+
from endoreg_db.import_files.file_storage.storage import create_sensitive_copy
|
|
20
|
+
from endoreg_db.import_files.processing.report_processing.report_anonymization import (
|
|
21
|
+
ReportAnonymizer,
|
|
22
|
+
)
|
|
23
|
+
from endoreg_db.models.media import RawPdfFile
|
|
24
|
+
from endoreg_db.utils.paths import SENSITIVE_REPORT_DIR
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ReportImportService:
|
|
30
|
+
"""
|
|
31
|
+
Service for importing and anonymizing report (report) files.
|
|
32
|
+
|
|
33
|
+
Responsibilities:
|
|
34
|
+
- Acquire file lock
|
|
35
|
+
- Create sensitive copy
|
|
36
|
+
- Create/reuse RawPdfFile (dedupe by hash) + history
|
|
37
|
+
- Run anonymization pipeline (primary + fallback)
|
|
38
|
+
- Finalize state and move anonymized file
|
|
39
|
+
- Cleanup on error
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self) -> None:
|
|
43
|
+
self.logger = logger
|
|
44
|
+
self.anonymizer = ReportAnonymizer()
|
|
45
|
+
self.processing_context: Optional[ImportContext] = None
|
|
46
|
+
self.current_report: Optional[RawPdfFile] = None
|
|
47
|
+
|
|
48
|
+
validate_directories()
|
|
49
|
+
|
|
50
|
+
def import_and_anonymize(
|
|
51
|
+
self,
|
|
52
|
+
file_path: Union[Path, str],
|
|
53
|
+
center_name: str,
|
|
54
|
+
retry: bool = False,
|
|
55
|
+
delete_source: bool = True,
|
|
56
|
+
) -> "RawPdfFile | None":
|
|
57
|
+
"""
|
|
58
|
+
Public entrypoint: wrap import_and_anonymize logic.
|
|
59
|
+
"""
|
|
60
|
+
# First, initialize import context. this will be updated during import and keep track of current paths, file type and center and processor.
|
|
61
|
+
ctx = ImportContext(
|
|
62
|
+
file_path=Path(file_path),
|
|
63
|
+
center_name=center_name,
|
|
64
|
+
delete_source=delete_source,
|
|
65
|
+
file_type="report",
|
|
66
|
+
original_path=Path(file_path),
|
|
67
|
+
)
|
|
68
|
+
self.logger.info("validating and preparing file")
|
|
69
|
+
if not ctx.file_path.exists():
|
|
70
|
+
raise FileNotFoundError(f"Video file not found: {file_path}")
|
|
71
|
+
|
|
72
|
+
ctx.sensitive_path = create_sensitive_copy(ctx.file_path, SENSITIVE_REPORT_DIR)
|
|
73
|
+
|
|
74
|
+
with file_lock(ctx.file_path):
|
|
75
|
+
logger.info("Acquired file lock for %s", ctx.file_path)
|
|
76
|
+
|
|
77
|
+
# create or retrieve RawPdfFile + update history
|
|
78
|
+
ctx.current_report, processed, needs_processing = (
|
|
79
|
+
create_or_retrieve_report_file(ctx)
|
|
80
|
+
)
|
|
81
|
+
ctx.current_report.get_or_create_state()
|
|
82
|
+
assert ctx.current_report.state is not None
|
|
83
|
+
ctx.current_report = ctx.current_report
|
|
84
|
+
|
|
85
|
+
if processed == True or retry == True:
|
|
86
|
+
ctx.retry = True
|
|
87
|
+
|
|
88
|
+
# Retry is a forced overwrite of needs processing - therefore the retry will cause full deletion of processed files using finalize failure.
|
|
89
|
+
if (
|
|
90
|
+
ctx.retry
|
|
91
|
+
and needs_processing
|
|
92
|
+
and not ctx.current_report.state.anonymization_validated
|
|
93
|
+
):
|
|
94
|
+
# ensure clean slate for forced reprocessing
|
|
95
|
+
finalize_failure(ctx)
|
|
96
|
+
ctx.current_report, processed, needs_processing = (
|
|
97
|
+
create_or_retrieve_report_file(ctx)
|
|
98
|
+
)
|
|
99
|
+
assert needs_processing is True
|
|
100
|
+
elif not needs_processing and not ctx.retry:
|
|
101
|
+
return ctx.current_report
|
|
102
|
+
else:
|
|
103
|
+
finalize_failure(ctx)
|
|
104
|
+
ctx.current_report, processed, needs_processing = (
|
|
105
|
+
create_or_retrieve_report_file(ctx)
|
|
106
|
+
)
|
|
107
|
+
assert needs_processing is True
|
|
108
|
+
|
|
109
|
+
mark_instance_processing_started(ctx.current_report, ctx)
|
|
110
|
+
try:
|
|
111
|
+
# --- Anonymization with fallback ---
|
|
112
|
+
try:
|
|
113
|
+
ctx = self.anonymizer.anonymize_report(ctx)
|
|
114
|
+
logger.info(
|
|
115
|
+
"Primary report anonymization succeeded for %s",
|
|
116
|
+
ctx.file_path,
|
|
117
|
+
)
|
|
118
|
+
except Exception as primary_exc:
|
|
119
|
+
logger.exception(
|
|
120
|
+
"Primary report anonymization failed for %s: %s "
|
|
121
|
+
"- trying basic anonymization",
|
|
122
|
+
ctx.file_path,
|
|
123
|
+
primary_exc,
|
|
124
|
+
)
|
|
125
|
+
try:
|
|
126
|
+
ctx = self.anonymizer.anonymize_report(ctx)
|
|
127
|
+
except Exception as e:
|
|
128
|
+
logger.error(f"report Extraction failed for the second time. {e}")
|
|
129
|
+
raise
|
|
130
|
+
|
|
131
|
+
logger.info(
|
|
132
|
+
"Basic report anonymization succeeded for %s",
|
|
133
|
+
ctx.file_path,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# --- Finalize success: history + move anonymized file ---
|
|
137
|
+
finalize_report_success(ctx)
|
|
138
|
+
|
|
139
|
+
return ctx.current_report
|
|
140
|
+
|
|
141
|
+
except Exception as exc:
|
|
142
|
+
logger.exception(
|
|
143
|
+
"Report import/anonymization failed for %s: %s", ctx.file_path, exc
|
|
144
|
+
)
|
|
145
|
+
# mark failure in history
|
|
146
|
+
finalize_failure(ctx)
|
|
147
|
+
raise
|