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,463 @@
|
|
|
1
|
+
from endoreg_db.models.state.processing_history.processing_history import (
|
|
2
|
+
ProcessingHistory,
|
|
3
|
+
)
|
|
4
|
+
from endoreg_db.utils.paths import ANONYM_REPORT_DIR, ANONYM_VIDEO_DIR
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import shutil
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Union
|
|
10
|
+
|
|
11
|
+
from django.db import transaction
|
|
12
|
+
|
|
13
|
+
from endoreg_db.import_files.context.import_context import ImportContext
|
|
14
|
+
from endoreg_db.models.media import RawPdfFile, VideoFile
|
|
15
|
+
from endoreg_db.models.state import RawPdfState, VideoState
|
|
16
|
+
from endoreg_db.utils import paths as path_utils
|
|
17
|
+
from endoreg_db.utils.file_operations import sha256_file
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_history_filename(ctx: ImportContext) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Prefer original_path.name if provided, otherwise fall back to file_path.name.
|
|
25
|
+
"""
|
|
26
|
+
if ctx.original_path is not None:
|
|
27
|
+
return ctx.original_path.name
|
|
28
|
+
# ctx.file_path is always present and already a Path in your tests
|
|
29
|
+
return Path(ctx.file_path).name
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _ensure_instance_state(
|
|
33
|
+
instance: Union[VideoFile, RawPdfFile],
|
|
34
|
+
) -> Optional[Union[RawPdfState, VideoState]]:
|
|
35
|
+
"""
|
|
36
|
+
Helper: ensure instance.state exists and return it.
|
|
37
|
+
Mirrors PdfImportService._ensure_state.
|
|
38
|
+
"""
|
|
39
|
+
if isinstance(instance, RawPdfFile):
|
|
40
|
+
state = getattr(instance, "state", None)
|
|
41
|
+
else:
|
|
42
|
+
state = getattr(instance, "state", None)
|
|
43
|
+
|
|
44
|
+
if state is not None:
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
if hasattr(instance, "get_or_create_state"):
|
|
48
|
+
state = instance.get_or_create_state()
|
|
49
|
+
instance.save()
|
|
50
|
+
return state
|
|
51
|
+
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def mark_instance_processing_started(
|
|
56
|
+
instance: Union[RawPdfFile, VideoFile],
|
|
57
|
+
ctx: ImportContext,
|
|
58
|
+
):
|
|
59
|
+
state = _ensure_instance_state(instance)
|
|
60
|
+
|
|
61
|
+
with transaction.atomic():
|
|
62
|
+
if state is not None:
|
|
63
|
+
# In the old code, processing_started was set earlier; we guard here
|
|
64
|
+
if not getattr(state, "processing_started", False) and hasattr(
|
|
65
|
+
state, "mark_processing_started"
|
|
66
|
+
):
|
|
67
|
+
state.mark_processing_started()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def finalize_report_success(
|
|
71
|
+
ctx: ImportContext,
|
|
72
|
+
) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Finalize a successful instance import/anonymization.
|
|
75
|
+
|
|
76
|
+
- Move anonymized Report from temp to canonical anonymized dir
|
|
77
|
+
- Update RawPdfFile.processed_file and .anonymized flag
|
|
78
|
+
- Mark RawPdfState as anonymized + sensitive_meta_processed
|
|
79
|
+
- Mark ProcessingHistory.success = True
|
|
80
|
+
"""
|
|
81
|
+
instance = ctx.current_report
|
|
82
|
+
if not isinstance(instance, RawPdfFile):
|
|
83
|
+
logger.warning("finalize_success called with unsaved instance")
|
|
84
|
+
return
|
|
85
|
+
if not instance.pk:
|
|
86
|
+
logger.warning("finalize_success called with unsaved instance")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
# --- Move anonymized path into final storage (if we have one) ---
|
|
90
|
+
final_path: Optional[Path] = None
|
|
91
|
+
if ctx.anonymized_path is None:
|
|
92
|
+
logger.warning(
|
|
93
|
+
"No anonymized_path for instance %s (hash=%s); skipping file move.",
|
|
94
|
+
instance.pk,
|
|
95
|
+
getattr(instance, "pdf_hash", None),
|
|
96
|
+
)
|
|
97
|
+
final_path = None
|
|
98
|
+
else:
|
|
99
|
+
pdf_hash = getattr(instance, "pdf_hash", None) or instance.pk
|
|
100
|
+
expected_final_path = ANONYM_REPORT_DIR / f"{pdf_hash}.pdf"
|
|
101
|
+
|
|
102
|
+
src = Path(ctx.anonymized_path)
|
|
103
|
+
|
|
104
|
+
logger.debug(
|
|
105
|
+
"finalize_report_success: src=%s (exists=%s, resolved=%s), expected_final=%s",
|
|
106
|
+
src,
|
|
107
|
+
src.exists(),
|
|
108
|
+
src.resolve(),
|
|
109
|
+
expected_final_path,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# If anonymizer already wrote to the final path, don't move
|
|
113
|
+
if src.resolve() == expected_final_path.resolve():
|
|
114
|
+
logger.info(
|
|
115
|
+
"Anonymizer output already at final path %s; skipping move.",
|
|
116
|
+
expected_final_path,
|
|
117
|
+
)
|
|
118
|
+
final_path = expected_final_path
|
|
119
|
+
else:
|
|
120
|
+
# Only move if the source actually exists
|
|
121
|
+
if not src.exists():
|
|
122
|
+
logger.error(
|
|
123
|
+
"Anonymized file %s does not exist; cannot move to %s",
|
|
124
|
+
src,
|
|
125
|
+
expected_final_path,
|
|
126
|
+
)
|
|
127
|
+
final_path = None
|
|
128
|
+
else:
|
|
129
|
+
ANONYM_REPORT_DIR.mkdir(parents=True, exist_ok=True)
|
|
130
|
+
if expected_final_path.exists():
|
|
131
|
+
expected_final_path.unlink()
|
|
132
|
+
shutil.move(str(src), str(expected_final_path))
|
|
133
|
+
final_path = expected_final_path
|
|
134
|
+
logger.info("Moved anonymized report to %s", final_path)
|
|
135
|
+
|
|
136
|
+
# Update FileField if we have a final path
|
|
137
|
+
if final_path is not None:
|
|
138
|
+
relative_name = path_utils.to_storage_relative(final_path)
|
|
139
|
+
current_name = getattr(instance.processed_file, "name", None)
|
|
140
|
+
if current_name != relative_name:
|
|
141
|
+
instance.processed_file.name = relative_name
|
|
142
|
+
logger.info("Updated processed_file to %s", relative_name)
|
|
143
|
+
|
|
144
|
+
# --- Update RawPdfState flags (mirrors _finalize_processing) ---
|
|
145
|
+
state = _ensure_instance_state(instance)
|
|
146
|
+
|
|
147
|
+
with transaction.atomic():
|
|
148
|
+
if state is not None:
|
|
149
|
+
if not getattr(state, "processing_started", False) and hasattr(
|
|
150
|
+
state, "mark_processing_started"
|
|
151
|
+
):
|
|
152
|
+
state.mark_processing_started()
|
|
153
|
+
|
|
154
|
+
# We consider text/meta extraction + anonymization done at this point
|
|
155
|
+
if hasattr(state, "mark_anonymized"):
|
|
156
|
+
state.mark_anonymized()
|
|
157
|
+
if hasattr(state, "mark_sensitive_meta_processed"):
|
|
158
|
+
state.mark_sensitive_meta_processed()
|
|
159
|
+
|
|
160
|
+
state.save()
|
|
161
|
+
|
|
162
|
+
instance.save()
|
|
163
|
+
|
|
164
|
+
# --- ProcessingHistory entry ---
|
|
165
|
+
try:
|
|
166
|
+
with transaction.atomic():
|
|
167
|
+
if not isinstance(ctx.file_hash, str):
|
|
168
|
+
ctx.file_hash = sha256_file(ctx.file_path)
|
|
169
|
+
ProcessingHistory.get_or_create_for_hash(
|
|
170
|
+
obj=instance,
|
|
171
|
+
file_hash=ctx.file_hash,
|
|
172
|
+
success=True,
|
|
173
|
+
)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.debug(
|
|
176
|
+
f"Saving not possible; %sskipping ProcessingHistory.{e}",
|
|
177
|
+
instance.pk,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def finalize_video_success(
|
|
182
|
+
ctx: ImportContext,
|
|
183
|
+
) -> None:
|
|
184
|
+
"""
|
|
185
|
+
Finalize a successful video import/anonymization.
|
|
186
|
+
|
|
187
|
+
- Move anonymized video from temp to canonical anonymized dir
|
|
188
|
+
- Update VideoFile.processed_file
|
|
189
|
+
- Mark VideoState as anonymized + sensitive_meta_processed
|
|
190
|
+
- Mark ProcessingHistory.success = True
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
instance = ctx.current_video
|
|
194
|
+
if not isinstance(instance, VideoFile):
|
|
195
|
+
logger.warning("finalize_video_success called with non-VideoFile instance")
|
|
196
|
+
return
|
|
197
|
+
if not instance.pk:
|
|
198
|
+
logger.warning("finalize_video_success called with unsaved instance")
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# --- Move anonymized path into final storage (if we have one) ---
|
|
202
|
+
final_path: Optional[Path] = None
|
|
203
|
+
|
|
204
|
+
if ctx.anonymized_path is None:
|
|
205
|
+
logger.warning(
|
|
206
|
+
"No anonymized_path for video instance %s (hash=%s); skipping file move.",
|
|
207
|
+
instance.pk,
|
|
208
|
+
getattr(instance, "video_hash", None),
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
# Use a stable naming convention: <video_hash>.mp4
|
|
212
|
+
video_hash = getattr(instance, "video_hash", None) or instance.pk
|
|
213
|
+
expected_final_path = ANONYM_VIDEO_DIR / f"{video_hash}.mp4"
|
|
214
|
+
|
|
215
|
+
src = Path(ctx.anonymized_path)
|
|
216
|
+
|
|
217
|
+
logger.debug(
|
|
218
|
+
"finalize_video_success: src=%s (exists=%s, resolved=%s), expected_final=%s",
|
|
219
|
+
src,
|
|
220
|
+
src.exists(),
|
|
221
|
+
src.resolve(),
|
|
222
|
+
expected_final_path,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# If anonymizer already wrote to the final path, don't move
|
|
226
|
+
try:
|
|
227
|
+
same_target = src.resolve() == expected_final_path.resolve()
|
|
228
|
+
except FileNotFoundError:
|
|
229
|
+
# src might not exist anymore
|
|
230
|
+
same_target = False
|
|
231
|
+
|
|
232
|
+
if same_target:
|
|
233
|
+
logger.info(
|
|
234
|
+
"Anonymizer output already at final video path %s; skipping move.",
|
|
235
|
+
expected_final_path,
|
|
236
|
+
)
|
|
237
|
+
final_path = expected_final_path
|
|
238
|
+
else:
|
|
239
|
+
if not src.exists():
|
|
240
|
+
logger.error(
|
|
241
|
+
"Anonymized video %s does not exist; cannot move to %s",
|
|
242
|
+
src,
|
|
243
|
+
expected_final_path,
|
|
244
|
+
)
|
|
245
|
+
final_path = None
|
|
246
|
+
else:
|
|
247
|
+
ANONYM_VIDEO_DIR.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
if expected_final_path.exists():
|
|
249
|
+
try:
|
|
250
|
+
expected_final_path.unlink()
|
|
251
|
+
except Exception as e:
|
|
252
|
+
logger.warning(
|
|
253
|
+
"Could not remove existing anonymized video %s: %s",
|
|
254
|
+
expected_final_path,
|
|
255
|
+
e,
|
|
256
|
+
)
|
|
257
|
+
shutil.move(str(src), str(expected_final_path))
|
|
258
|
+
final_path = expected_final_path
|
|
259
|
+
logger.info("Moved anonymized video to %s", final_path)
|
|
260
|
+
|
|
261
|
+
# Update FileField if we have a final path
|
|
262
|
+
if final_path is not None:
|
|
263
|
+
relative_name = path_utils.to_storage_relative(final_path)
|
|
264
|
+
current_name = getattr(instance.processed_file, "name", None)
|
|
265
|
+
if current_name != relative_name:
|
|
266
|
+
instance.processed_file.name = relative_name
|
|
267
|
+
logger.info("Updated video processed_file to %s", relative_name)
|
|
268
|
+
|
|
269
|
+
if not nuke_transcoding_dir():
|
|
270
|
+
logger.warning(
|
|
271
|
+
"Transcoding directory cleanup returned False after finalize_video_success; there may be leftover files."
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# --- Update VideoState flags (mirrors report) ---
|
|
275
|
+
state = _ensure_instance_state(instance)
|
|
276
|
+
|
|
277
|
+
with transaction.atomic():
|
|
278
|
+
if state is not None:
|
|
279
|
+
if not getattr(state, "processing_started", False) and hasattr(
|
|
280
|
+
state, "mark_processing_started"
|
|
281
|
+
):
|
|
282
|
+
state.mark_processing_started()
|
|
283
|
+
|
|
284
|
+
if hasattr(state, "mark_anonymized"):
|
|
285
|
+
state.mark_anonymized()
|
|
286
|
+
if hasattr(state, "mark_sensitive_meta_processed"):
|
|
287
|
+
state.mark_sensitive_meta_processed()
|
|
288
|
+
|
|
289
|
+
state.save()
|
|
290
|
+
|
|
291
|
+
instance.save()
|
|
292
|
+
|
|
293
|
+
# --- ProcessingHistory entry ---
|
|
294
|
+
try:
|
|
295
|
+
with transaction.atomic():
|
|
296
|
+
if not isinstance(ctx.file_hash, str):
|
|
297
|
+
ctx.file_hash = sha256_file(ctx.file_path)
|
|
298
|
+
ProcessingHistory.get_or_create_for_hash(
|
|
299
|
+
file_hash=ctx.file_hash,
|
|
300
|
+
success=True,
|
|
301
|
+
)
|
|
302
|
+
except Exception as e:
|
|
303
|
+
logger.debug(
|
|
304
|
+
"Saving not possible for video %s; skipping ProcessingHistory. Error: %s",
|
|
305
|
+
instance.pk,
|
|
306
|
+
e,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def finalize_failure(
|
|
311
|
+
ctx: ImportContext,
|
|
312
|
+
) -> None:
|
|
313
|
+
"""
|
|
314
|
+
Finalize a failed instance import/anonymization.
|
|
315
|
+
|
|
316
|
+
- Reset RawPdfState flags to "not processed"
|
|
317
|
+
- Mark ProcessingHistory.success = False
|
|
318
|
+
- Delete all associated files
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
if ctx.instance is None:
|
|
322
|
+
if isinstance(ctx.current_report, RawPdfFile):
|
|
323
|
+
ctx.instance = ctx.current_report
|
|
324
|
+
elif isinstance(ctx.current_video, VideoFile):
|
|
325
|
+
ctx.instance = ctx.current_video
|
|
326
|
+
else:
|
|
327
|
+
raise Exception
|
|
328
|
+
|
|
329
|
+
# History entry with success=False
|
|
330
|
+
if not isinstance(ctx.file_hash, str):
|
|
331
|
+
ctx.file_hash = sha256_file(ctx.file_path)
|
|
332
|
+
ProcessingHistory.get_or_create_for_hash(
|
|
333
|
+
file_hash=ctx.file_hash,
|
|
334
|
+
success=False,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# Reset state flags similar to _mark_processing_incomplete / _cleanup_on_error
|
|
338
|
+
state = _ensure_instance_state(ctx.instance)
|
|
339
|
+
|
|
340
|
+
if state is not None:
|
|
341
|
+
try:
|
|
342
|
+
state.mark_processing_not_started()
|
|
343
|
+
|
|
344
|
+
state.save()
|
|
345
|
+
logger.info(
|
|
346
|
+
"Reset instance state for failed processing (instance pk=%s)",
|
|
347
|
+
ctx.instance.pk,
|
|
348
|
+
)
|
|
349
|
+
except Exception as e:
|
|
350
|
+
logger.warning(
|
|
351
|
+
"Failed to reset State for instance %s: %s",
|
|
352
|
+
ctx.instance.pk,
|
|
353
|
+
e,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
try:
|
|
357
|
+
delete_associated_files(ctx)
|
|
358
|
+
except Exception as e:
|
|
359
|
+
logger.warning(f"There might be files remaining. {e}")
|
|
360
|
+
|
|
361
|
+
logger.error(
|
|
362
|
+
"File processing failed for %s - state reset, ready for retry.",
|
|
363
|
+
ctx.file_path,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def delete_associated_files(ctx: ImportContext) -> None:
|
|
368
|
+
"""
|
|
369
|
+
Best-effort cleanup of anonymized, sensitive and transcoding artefacts.
|
|
370
|
+
|
|
371
|
+
- Ensure ctx.original_path points to an existing import file; if not, try to restore
|
|
372
|
+
from ctx.sensitive_path into the appropriate IMPORT_*_DIR.
|
|
373
|
+
- Delete anonymized file (if any).
|
|
374
|
+
- Nuke transcoding directory.
|
|
375
|
+
- Delete sensitive file (if any).
|
|
376
|
+
|
|
377
|
+
This function should *not* raise on non-critical cleanup errors; it logs instead.
|
|
378
|
+
Only restoration of the original import file is treated as critical.
|
|
379
|
+
"""
|
|
380
|
+
|
|
381
|
+
# --- Delete anonymized file (best-effort) ---
|
|
382
|
+
if isinstance(ctx.anonymized_path, Path):
|
|
383
|
+
try:
|
|
384
|
+
if ctx.anonymized_path.exists():
|
|
385
|
+
ctx.anonymized_path.unlink()
|
|
386
|
+
logger.info("Deleted anonymized file %s", ctx.anonymized_path)
|
|
387
|
+
except Exception as e:
|
|
388
|
+
logger.error(
|
|
389
|
+
"Error when unlinking anonymized path %s: %s",
|
|
390
|
+
ctx.anonymized_path,
|
|
391
|
+
e,
|
|
392
|
+
exc_info=True,
|
|
393
|
+
)
|
|
394
|
+
finally:
|
|
395
|
+
ctx.anonymized_path = None
|
|
396
|
+
|
|
397
|
+
# --- Nuke transcoding directory (best-effort) ---
|
|
398
|
+
if not nuke_transcoding_dir():
|
|
399
|
+
logger.warning(
|
|
400
|
+
"Transcoding directory cleanup returned False; there may be leftover files."
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# --- Delete sensitive file (best-effort) ---
|
|
404
|
+
if isinstance(ctx.sensitive_path, Path):
|
|
405
|
+
try:
|
|
406
|
+
if ctx.sensitive_path.exists():
|
|
407
|
+
ctx.sensitive_path.unlink()
|
|
408
|
+
logger.info("Deleted sensitive file %s", ctx.sensitive_path)
|
|
409
|
+
except Exception as e:
|
|
410
|
+
logger.error(
|
|
411
|
+
"Error when unlinking sensitive path %s: %s",
|
|
412
|
+
ctx.sensitive_path,
|
|
413
|
+
e,
|
|
414
|
+
exc_info=True,
|
|
415
|
+
)
|
|
416
|
+
finally:
|
|
417
|
+
ctx.sensitive_path = None
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def nuke_transcoding_dir(transcoding_dir: Union[str, Path, None] = None) -> bool:
|
|
421
|
+
"""
|
|
422
|
+
Delete all files and subdirectories inside the transcoding directory.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
True if the directory was either empty / successfully cleaned,
|
|
426
|
+
False if something went wrong (error is logged).
|
|
427
|
+
"""
|
|
428
|
+
try:
|
|
429
|
+
if transcoding_dir is None:
|
|
430
|
+
transcoding_dir = path_utils.data_paths["transcoding"]
|
|
431
|
+
|
|
432
|
+
transcoding_dir = Path(transcoding_dir)
|
|
433
|
+
|
|
434
|
+
if not transcoding_dir.exists():
|
|
435
|
+
logger.info(
|
|
436
|
+
"Transcoding dir %s does not exist; nothing to clean.", transcoding_dir
|
|
437
|
+
)
|
|
438
|
+
return True
|
|
439
|
+
|
|
440
|
+
if not transcoding_dir.is_dir():
|
|
441
|
+
logger.error(
|
|
442
|
+
"Configured transcoding path %s is not a directory.", transcoding_dir
|
|
443
|
+
)
|
|
444
|
+
return False
|
|
445
|
+
|
|
446
|
+
for entry in transcoding_dir.iterdir():
|
|
447
|
+
try:
|
|
448
|
+
if entry.is_file() or entry.is_symlink():
|
|
449
|
+
entry.unlink()
|
|
450
|
+
elif entry.is_dir():
|
|
451
|
+
shutil.rmtree(entry)
|
|
452
|
+
except Exception as e:
|
|
453
|
+
logger.warning(
|
|
454
|
+
"Failed to remove entry %s in transcoding dir: %s", entry, e
|
|
455
|
+
)
|
|
456
|
+
# Continue trying to delete other entries
|
|
457
|
+
return True
|
|
458
|
+
|
|
459
|
+
except Exception as e:
|
|
460
|
+
logger.error(
|
|
461
|
+
"Unexpected error while nuking transcoding dir: %s", e, exc_info=True
|
|
462
|
+
)
|
|
463
|
+
return False
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from endoreg_db.models.media.video.create_from_file import (
|
|
4
|
+
atomic_copy_with_fallback,
|
|
5
|
+
atomic_move_with_fallback,
|
|
6
|
+
)
|
|
7
|
+
from endoreg_db.utils import transcode_videofile_if_required
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def ensure_dir(path: Path) -> None:
|
|
12
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_sensitive_copy(src: Path, sensitive_root: Path) -> Path:
|
|
16
|
+
"""
|
|
17
|
+
Create a sensitive copy of `src` in `sensitive_root`.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Path to the sensitive copy.
|
|
21
|
+
"""
|
|
22
|
+
ensure_dir(sensitive_root)
|
|
23
|
+
dest = sensitive_root / src.name
|
|
24
|
+
logger.info("Creating sensitive copy: %s -> %s", src, dest)
|
|
25
|
+
transcode_videofile_if_required(src, dest)
|
|
26
|
+
atomic_copy_with_fallback(src, dest)
|
|
27
|
+
return dest
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def move_to_anonymized(temp_path: Path, anonymized_root: Path) -> Path:
|
|
31
|
+
"""
|
|
32
|
+
Move a (temporary) anonymized file into the canonical anonymized root.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Final path inside anonymized_root.
|
|
36
|
+
"""
|
|
37
|
+
ensure_dir(anonymized_root)
|
|
38
|
+
dest = anonymized_root / temp_path.name
|
|
39
|
+
logger.info("Moving anonymized file: %s -> %s", temp_path, dest)
|
|
40
|
+
transcode_videofile_if_required(temp_path, dest)
|
|
41
|
+
atomic_move_with_fallback(temp_path, dest)
|
|
42
|
+
return dest
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# File Import and Anonymization
|
|
2
|
+
|
|
3
|
+
Endoreg-Db imports are guarded by a anonymization step, that is supposed to ensure most data is redacted from the input. Here, fake patients are generated to pseudonymize the sensitive information in the data. This ensures, that videos as well as pdfs are not distributed using sensitive data, and if they are by some accident it is harder to know what data is actually real.
|
|
4
|
+
|
|
5
|
+
The Import is handled by two orchestration files:
|
|
6
|
+
|
|
7
|
+
Report import service (RIS)
|
|
8
|
+
|
|
9
|
+
and
|
|
10
|
+
|
|
11
|
+
Video import Service (VIS)
|
|
12
|
+
|
|
13
|
+
The orchestration is abstracted out by the base import service (BIS), to ensure newly implemented data imports follow the same structure and to ensure tests run agnostically of the actual media being processed.
|
|
14
|
+
|
|
15
|
+
## Import Order of Execution
|
|
16
|
+
|
|
17
|
+
The Import starts, when files are dropped into the corresponding media import folders. The locations need to be passed to the import service logic. To ensure atomic processing without overwhelming the server or double processing on parallelization, a file lock is added to the files that are currently processed.
|
|
18
|
+
|
|
19
|
+
### File Lock
|
|
20
|
+
|
|
21
|
+
File Lock is implemented as a context manager. Per default, this means during the execution the files are marked by adding a additional .lock file path inside the folder. Once the code wrapped in the context manager of file lock stops execution, the .lock file is removed only after error processing. This ensures, the full pipeline is executed on each run even when interrupted.
|
|
22
|
+
https://book.pythontips.com/en/latest/context_managers.html
|
|
23
|
+
|
|
24
|
+
### Error Cleanup
|
|
25
|
+
|
|
26
|
+
The ErrorCleanup class is called from inside the file lock context manager to avoid leaving half processed files laying around. It passes file type to the class instance and then runs the correct processing logic.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from lx_anonymizer import ReportReader
|
|
7
|
+
from lx_anonymizer.sensitive_meta_interface import SensitiveMeta as LxSM
|
|
8
|
+
|
|
9
|
+
from endoreg_db.import_files.context import ImportContext
|
|
10
|
+
from endoreg_db.import_files.file_storage.sensitive_meta_storage import (
|
|
11
|
+
sensitive_meta_storage,
|
|
12
|
+
)
|
|
13
|
+
from endoreg_db.utils.paths import ANONYM_REPORT_DIR
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ReportAnonymizer:
|
|
20
|
+
def __init__(self):
|
|
21
|
+
self._report_reader_class = None
|
|
22
|
+
self._ensure_report_reading_available()
|
|
23
|
+
self.storage = False
|
|
24
|
+
|
|
25
|
+
def anonymize_report(self, ctx: ImportContext):
|
|
26
|
+
# Setup anonymized directory
|
|
27
|
+
anonymized_dir = ANONYM_REPORT_DIR
|
|
28
|
+
anonymized_dir.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
assert ctx.current_report is not None
|
|
30
|
+
# Generate output path for anonymized report
|
|
31
|
+
pdf_hash = ctx.current_report.pdf_hash
|
|
32
|
+
anonymized_output_path = anonymized_dir / f"{pdf_hash}.pdf"
|
|
33
|
+
self._report_reader_class = ReportReader()
|
|
34
|
+
|
|
35
|
+
assert isinstance(self._report_reader_class, ReportReader)
|
|
36
|
+
|
|
37
|
+
# Process with enhanced process_report method (returns 4-tuple now)
|
|
38
|
+
(
|
|
39
|
+
ctx.original_text,
|
|
40
|
+
ctx.anonymized_text,
|
|
41
|
+
extracted_metadata,
|
|
42
|
+
ctx.anonymized_path,
|
|
43
|
+
) = self._report_reader_class.process_report(
|
|
44
|
+
pdf_path=ctx.file_path,
|
|
45
|
+
create_anonymized_pdf=True,
|
|
46
|
+
anonymized_pdf_output_path=str(anonymized_output_path),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if ctx.anonymized_path:
|
|
50
|
+
logger.info(
|
|
51
|
+
"DEBUG: after anonymizer, ctx.anonymized_path=%s (exists=%s)",
|
|
52
|
+
ctx.anonymized_path,
|
|
53
|
+
isinstance(ctx.anonymized_path, str),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
sm = LxSM()
|
|
57
|
+
sm.safe_update(extracted_metadata)
|
|
58
|
+
|
|
59
|
+
self.storage = sensitive_meta_storage(sm, ctx.current_report)
|
|
60
|
+
return ctx
|
|
61
|
+
|
|
62
|
+
def _ensure_report_reading_available(self) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Ensure report reading modules are available by adding lx-anonymizer to path.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Tuple of (availability_flag, ReportReader_class)
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
# Try direct import first
|
|
72
|
+
from lx_anonymizer import ReportReader
|
|
73
|
+
|
|
74
|
+
logger.info("Successfully imported lx_anonymizer ReportReader module")
|
|
75
|
+
self._report_reader_available = True
|
|
76
|
+
self._report_reader_class = ReportReader
|
|
77
|
+
|
|
78
|
+
except ImportError:
|
|
79
|
+
# Optional: honor LX_ANONYMIZER_PATH=/abs/path/to/src
|
|
80
|
+
import importlib
|
|
81
|
+
|
|
82
|
+
extra = os.getenv("LX_ANONYMIZER_PATH")
|
|
83
|
+
if extra and extra not in sys.path and Path(extra).exists():
|
|
84
|
+
sys.path.insert(0, extra)
|
|
85
|
+
try:
|
|
86
|
+
mod = importlib.import_module("lx_anonymizer")
|
|
87
|
+
ReportReader = getattr(mod, "ReportReader")
|
|
88
|
+
logger.info(
|
|
89
|
+
"Imported lx_anonymizer.ReportReader via LX_ANONYMIZER_PATH"
|
|
90
|
+
)
|
|
91
|
+
self._report_reader_available = True
|
|
92
|
+
self._report_reader_class = ReportReader
|
|
93
|
+
except Exception as e:
|
|
94
|
+
logger.warning(
|
|
95
|
+
"Failed importing lx_anonymizer via LX_ANONYMIZER_PATH: %s", e
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
self._report_reader_available = False
|
|
99
|
+
self._report_reader_class = None
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# endoreg_db/import_files/processing/sensitive_meta_adapter.py
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
from lx_anonymizer.sensitive_meta_interface import SensitiveMeta as LxSensitiveMeta
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def normalize_lx_sensitive_meta(meta: LxSensitiveMeta) -> Dict[str, Any]:
|
|
8
|
+
"""
|
|
9
|
+
Convert lx_anonymizer.SensitiveMeta into a dict suitable for
|
|
10
|
+
endoreg_db SensitiveMeta.update_from_dict / create_from_dict.
|
|
11
|
+
|
|
12
|
+
- Renames fields where necessary (center -> center_name, patient_gender_name -> patient_gender)
|
|
13
|
+
- Drops None/blank values (your update logic already handles blanks carefully)
|
|
14
|
+
- Leaves dates as strings; your logic layer already parses them
|
|
15
|
+
"""
|
|
16
|
+
raw = meta.to_dict()
|
|
17
|
+
out: Dict[str, Any] = {}
|
|
18
|
+
|
|
19
|
+
# 1:1 fields (same names in model logic)
|
|
20
|
+
direct_keys = [
|
|
21
|
+
"file_path",
|
|
22
|
+
"patient_first_name",
|
|
23
|
+
"patient_last_name",
|
|
24
|
+
"patient_dob", # string; logic has parsing
|
|
25
|
+
"casenumber",
|
|
26
|
+
"examination_date", # string; logic has parsing
|
|
27
|
+
"examination_time", # string "HH:MM" is fine
|
|
28
|
+
"examiner_first_name",
|
|
29
|
+
"examiner_last_name",
|
|
30
|
+
"text",
|
|
31
|
+
"anonymized_text",
|
|
32
|
+
"endoscope_type",
|
|
33
|
+
"endoscope_sn",
|
|
34
|
+
]
|
|
35
|
+
for k in direct_keys:
|
|
36
|
+
v = raw.get(k)
|
|
37
|
+
if v not in (None, "", []):
|
|
38
|
+
out[k] = v
|
|
39
|
+
|
|
40
|
+
# Map patient_gender_name (interface) -> patient_gender (logic)
|
|
41
|
+
gender_name = raw.get("patient_gender_name")
|
|
42
|
+
if gender_name not in (None, ""):
|
|
43
|
+
# Your logic.update_* can handle strings for patient_gender
|
|
44
|
+
out["patient_gender"] = gender_name
|
|
45
|
+
|
|
46
|
+
# Map center (string) -> center_name (logic)
|
|
47
|
+
center_name = raw.get("center")
|
|
48
|
+
if center_name not in (None, ""):
|
|
49
|
+
out["center_name"] = center_name
|
|
50
|
+
|
|
51
|
+
return out
|