endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,58 +1,72 @@
|
|
|
1
1
|
# endoreg_db/services/anonymization.py
|
|
2
|
+
import logging
|
|
2
3
|
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
3
6
|
from django.db import transaction
|
|
4
|
-
|
|
5
|
-
from endoreg_db.models import
|
|
6
|
-
from endoreg_db.services.video_import import VideoImportService
|
|
7
|
-
from endoreg_db.services.
|
|
7
|
+
|
|
8
|
+
from endoreg_db.models import RawPdfFile, VideoFile
|
|
9
|
+
from endoreg_db.services.__old.video_import import VideoImportService
|
|
10
|
+
from endoreg_db.services.report_import import ReportImportService
|
|
8
11
|
from endoreg_db.utils.paths import STORAGE_DIR
|
|
9
|
-
import
|
|
12
|
+
from endoreg_db.utils.storage import ensure_local_file, file_exists
|
|
10
13
|
|
|
11
14
|
logger = logging.getLogger(__name__)
|
|
12
15
|
|
|
16
|
+
|
|
13
17
|
class AnonymizationService:
|
|
14
18
|
"""
|
|
15
19
|
Orchestrates long‑running anonymization tasks so the view only
|
|
16
20
|
does HTTP <-> Service translation.
|
|
17
21
|
"""
|
|
18
|
-
|
|
19
|
-
def __init__(self, project_root: Path = None):
|
|
22
|
+
|
|
23
|
+
def __init__(self, project_root: Optional[Path] = None):
|
|
20
24
|
"""
|
|
21
25
|
Initialize the AnonymizationService with service instances.
|
|
22
|
-
|
|
26
|
+
|
|
23
27
|
Args:
|
|
24
28
|
project_root: Path to the project root. If None, uses settings.BASE_DIR
|
|
25
29
|
"""
|
|
26
|
-
|
|
27
|
-
project_root = STORAGE_DIR
|
|
28
|
-
|
|
30
|
+
self.project_root: Path = project_root or STORAGE_DIR
|
|
29
31
|
self.video_service = VideoImportService()
|
|
30
|
-
self.pdf_service =
|
|
32
|
+
self.pdf_service = ReportImportService()
|
|
31
33
|
|
|
32
34
|
# ---------- READ ----------------------------------------------------
|
|
33
35
|
@staticmethod
|
|
34
36
|
def get_status(file_id: int):
|
|
35
37
|
"""
|
|
36
38
|
Retrieve the anonymization status and media type for a file by its ID.
|
|
37
|
-
|
|
39
|
+
|
|
38
40
|
Returns:
|
|
39
41
|
dict or None: A dictionary containing the file's media type and anonymization status if found, or None if no matching file exists.
|
|
40
42
|
"""
|
|
41
|
-
vf =
|
|
43
|
+
vf = (
|
|
44
|
+
VideoFile.objects.select_related("state", "sensitive_meta")
|
|
45
|
+
.filter(pk=file_id)
|
|
46
|
+
.first()
|
|
47
|
+
)
|
|
42
48
|
if vf:
|
|
43
49
|
return {
|
|
44
50
|
"mediaType": "video",
|
|
45
|
-
"anonymizationStatus": vf.state.anonymization_status
|
|
46
|
-
|
|
51
|
+
"anonymizationStatus": vf.state.anonymization_status
|
|
52
|
+
if vf.state
|
|
53
|
+
else "not_started",
|
|
54
|
+
"fileExists": file_exists(vf.raw_file),
|
|
47
55
|
"uuid": str(vf.uuid) if vf.uuid else None,
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
pdf =
|
|
58
|
+
pdf = (
|
|
59
|
+
RawPdfFile.objects.select_related("state", "sensitive_meta")
|
|
60
|
+
.filter(pk=file_id)
|
|
61
|
+
.first()
|
|
62
|
+
)
|
|
51
63
|
if pdf:
|
|
52
64
|
return {
|
|
53
65
|
"mediaType": "pdf",
|
|
54
|
-
"anonymizationStatus": pdf.state.anonymization_status
|
|
55
|
-
|
|
66
|
+
"anonymizationStatus": pdf.state.anonymization_status
|
|
67
|
+
if pdf.state
|
|
68
|
+
else "not_started",
|
|
69
|
+
"fileExists": file_exists(pdf.file),
|
|
56
70
|
"hash": pdf.pdf_hash,
|
|
57
71
|
}
|
|
58
72
|
return None
|
|
@@ -62,116 +76,129 @@ class AnonymizationService:
|
|
|
62
76
|
def start(self, file_id: int):
|
|
63
77
|
"""
|
|
64
78
|
Start anonymization process for a file by its ID.
|
|
65
|
-
|
|
79
|
+
|
|
66
80
|
Args:
|
|
67
81
|
file_id: The ID of the file to anonymize
|
|
68
|
-
|
|
82
|
+
|
|
69
83
|
Returns:
|
|
70
84
|
str or None: Media type if successful, None if file not found
|
|
71
85
|
"""
|
|
72
86
|
# Try VideoFile first
|
|
73
|
-
vf =
|
|
87
|
+
vf = (
|
|
88
|
+
VideoFile.objects.select_related(
|
|
89
|
+
"state", "sensitive_meta", "center", "video_meta__processor"
|
|
90
|
+
)
|
|
91
|
+
.filter(pk=file_id)
|
|
92
|
+
.first()
|
|
93
|
+
)
|
|
74
94
|
if vf:
|
|
75
95
|
try:
|
|
76
96
|
logger.info(f"Starting video anonymization for VideoFile ID: {file_id}")
|
|
77
|
-
|
|
97
|
+
|
|
78
98
|
# Check if already processed
|
|
79
99
|
if vf.state and vf.state.anonymized:
|
|
80
100
|
logger.info(f"VideoFile {file_id} already anonymized, skipping")
|
|
81
101
|
return "video"
|
|
82
|
-
|
|
102
|
+
|
|
83
103
|
# Get file path
|
|
84
104
|
file_path = vf.get_raw_file_path()
|
|
85
105
|
if not file_path or not Path(file_path).exists():
|
|
86
|
-
logger.error(
|
|
106
|
+
logger.error(
|
|
107
|
+
f"Raw file not found for VideoFile {file_id}: {file_path}"
|
|
108
|
+
)
|
|
87
109
|
return None
|
|
88
|
-
|
|
110
|
+
|
|
89
111
|
# Get processor name
|
|
90
112
|
processor_name = None
|
|
91
113
|
if vf.video_meta and vf.video_meta.processor:
|
|
92
114
|
processor_name = vf.video_meta.processor.name
|
|
93
|
-
elif hasattr(vf,
|
|
115
|
+
elif hasattr(vf, "processor") and vf.processor:
|
|
94
116
|
processor_name = vf.processor.name
|
|
95
|
-
|
|
117
|
+
|
|
96
118
|
# Get center name
|
|
97
119
|
center_name = vf.center.name if vf.center else "unknown_center"
|
|
98
|
-
|
|
120
|
+
|
|
99
121
|
# Mark as started
|
|
100
122
|
if vf.state:
|
|
101
123
|
vf.state.processing_started = True
|
|
102
124
|
vf.state.save(update_fields=["processing_started"])
|
|
103
|
-
|
|
125
|
+
|
|
104
126
|
# Use VideoImportService for anonymization
|
|
127
|
+
safe_processor_name = processor_name or "unknown_processor"
|
|
105
128
|
self.video_service.import_and_anonymize(
|
|
106
129
|
file_path=file_path,
|
|
107
130
|
center_name=center_name,
|
|
108
|
-
processor_name=
|
|
131
|
+
processor_name=safe_processor_name,
|
|
109
132
|
save_video=True,
|
|
110
|
-
delete_source=False
|
|
133
|
+
delete_source=False,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
logger.info(
|
|
137
|
+
f"Video anonymization completed for VideoFile ID: {file_id}"
|
|
111
138
|
)
|
|
112
|
-
|
|
113
|
-
logger.info(f"Video anonymization completed for VideoFile ID: {file_id}")
|
|
114
139
|
return "video"
|
|
115
|
-
|
|
140
|
+
|
|
116
141
|
except Exception as e:
|
|
117
142
|
logger.error(f"Failed to anonymize VideoFile {file_id}: {e}")
|
|
118
143
|
# Mark as failed if state exists
|
|
119
144
|
if vf.state:
|
|
120
|
-
vf.state.processing_started =
|
|
145
|
+
vf.state.processing_started = (
|
|
146
|
+
False # Mark processing as not started due to failure
|
|
147
|
+
)
|
|
121
148
|
vf.state.save(update_fields=["processing_started"])
|
|
122
149
|
raise
|
|
123
150
|
|
|
124
151
|
# Try RawPdfFile
|
|
125
|
-
pdf =
|
|
152
|
+
pdf = (
|
|
153
|
+
RawPdfFile.objects.select_related("state", "sensitive_meta", "center")
|
|
154
|
+
.filter(pk=file_id)
|
|
155
|
+
.first()
|
|
156
|
+
)
|
|
126
157
|
if pdf:
|
|
127
158
|
try:
|
|
128
|
-
logger.info(f"Starting
|
|
129
|
-
|
|
159
|
+
logger.info(f"Starting report processing for RawPdfFile ID: {file_id}")
|
|
160
|
+
|
|
130
161
|
# Check if already processed
|
|
131
|
-
if pdf.state and getattr(pdf.state,
|
|
162
|
+
if pdf.state and getattr(pdf.state, "anonymized", False):
|
|
132
163
|
logger.info(f"RawPdfFile {file_id} already processed, skipping")
|
|
133
164
|
return "pdf"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if not
|
|
137
|
-
logger.error(f"
|
|
165
|
+
|
|
166
|
+
file_field = pdf.file
|
|
167
|
+
if not file_field or not file_field.name:
|
|
168
|
+
logger.error(f"report file not found for RawPdfFile {file_id}")
|
|
138
169
|
return None
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
|
|
171
|
+
if not file_exists(file_field):
|
|
172
|
+
logger.error(
|
|
173
|
+
"report file missing from storage for RawPdfFile %s", file_id
|
|
174
|
+
)
|
|
143
175
|
return None
|
|
144
|
-
|
|
176
|
+
|
|
145
177
|
# Get center name
|
|
146
178
|
center_name = pdf.center.name if pdf.center else "unknown_center"
|
|
147
|
-
|
|
179
|
+
|
|
148
180
|
# Mark as started
|
|
149
181
|
if pdf.state:
|
|
150
182
|
pdf.state.processing_started = True
|
|
151
183
|
pdf.state.save(update_fields=["processing_started"])
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
file_path=file_path,
|
|
161
|
-
center_name=center_name,
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
logger.info(f"PDF processing completed for RawPdfFile ID: {file_id}")
|
|
184
|
+
|
|
185
|
+
with ensure_local_file(file_field) as local_path:
|
|
186
|
+
self.pdf_service.import_and_anonymize(
|
|
187
|
+
file_path=local_path,
|
|
188
|
+
center_name=center_name,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
logger.info(f"report processing completed for RawPdfFile ID: {file_id}")
|
|
165
192
|
return "pdf"
|
|
166
|
-
|
|
193
|
+
|
|
167
194
|
except Exception as e:
|
|
168
195
|
logger.error(f"Failed to process RawPdfFile {file_id}: {e}")
|
|
169
196
|
# Mark as failed if state exists
|
|
170
|
-
if pdf.state:
|
|
171
|
-
pdf.state.processing_failed = True
|
|
197
|
+
if pdf.state and hasattr(pdf.state, "processing_failed"):
|
|
172
198
|
pdf.state.save(update_fields=["processing_failed"])
|
|
173
|
-
elif pdf.sensitive_meta
|
|
174
|
-
pdf.sensitive_meta
|
|
199
|
+
elif pdf.sensitive_meta and hasattr(
|
|
200
|
+
pdf.sensitive_meta, "processing_failed"
|
|
201
|
+
):
|
|
175
202
|
pdf.sensitive_meta.save(update_fields=["processing_failed"])
|
|
176
203
|
raise
|
|
177
204
|
|
|
@@ -183,41 +210,53 @@ class AnonymizationService:
|
|
|
183
210
|
def validate(file_id: int):
|
|
184
211
|
vf = VideoFile.objects.select_related("state").filter(pk=file_id).first()
|
|
185
212
|
if vf:
|
|
186
|
-
vf.state.
|
|
213
|
+
state = vf.state or vf.get_or_create_state()
|
|
214
|
+
if hasattr(state, "mark_anonymization_validated"):
|
|
215
|
+
state.mark_anonymization_validated()
|
|
187
216
|
return "video"
|
|
188
217
|
|
|
189
218
|
pdf = RawPdfFile.objects.select_related("state").filter(pk=file_id).first()
|
|
190
219
|
if pdf:
|
|
191
|
-
pdf.state.
|
|
220
|
+
state = pdf.state or pdf.get_or_create_state()
|
|
221
|
+
if hasattr(state, "mark_anonymization_validated"):
|
|
222
|
+
state.mark_anonymization_validated()
|
|
192
223
|
return "pdf"
|
|
193
224
|
|
|
194
225
|
return None
|
|
195
|
-
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
196
228
|
def list_items():
|
|
197
229
|
video_files = VideoFile.objects.select_related("state").all()
|
|
198
|
-
pdf_files = RawPdfFile.objects.select_related(
|
|
230
|
+
pdf_files = RawPdfFile.objects.select_related(
|
|
231
|
+
"state"
|
|
232
|
+
).all() # was sensitive_meta
|
|
199
233
|
|
|
200
234
|
data = []
|
|
201
235
|
for vf in video_files:
|
|
202
|
-
data.append(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
236
|
+
data.append(
|
|
237
|
+
{
|
|
238
|
+
"id": vf.pk,
|
|
239
|
+
"mediaType": "video",
|
|
240
|
+
"anonymizationStatus": vf.state.anonymization_status
|
|
241
|
+
if vf.state
|
|
242
|
+
else "not_started",
|
|
243
|
+
"createdAt": vf.date_created,
|
|
244
|
+
"updatedAt": vf.date_modified,
|
|
245
|
+
}
|
|
246
|
+
)
|
|
211
247
|
|
|
212
248
|
for pdf in pdf_files:
|
|
213
|
-
data.append(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
249
|
+
data.append(
|
|
250
|
+
{
|
|
251
|
+
"id": pdf.pk,
|
|
252
|
+
"mediaType": "pdf",
|
|
253
|
+
"anonymizationStatus": pdf.state.anonymization_status
|
|
254
|
+
if pdf.state
|
|
255
|
+
else "not_started",
|
|
256
|
+
"createdAt": pdf.date_created,
|
|
257
|
+
"updatedAt": pdf.date_modified,
|
|
258
|
+
}
|
|
259
|
+
)
|
|
220
260
|
return data
|
|
221
261
|
|
|
222
|
-
|
|
223
262
|
return data
|
|
@@ -24,9 +24,10 @@ Architecture:
|
|
|
24
24
|
# services/lookup_service.py
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
import logging
|
|
28
|
+
from typing import Any, Dict, List, Optional
|
|
28
29
|
|
|
29
|
-
from django.db.models import Prefetch
|
|
30
|
+
from django.db.models import Prefetch, QuerySet
|
|
30
31
|
|
|
31
32
|
from endoreg_db.models.medical.examination import ExaminationRequirementSet
|
|
32
33
|
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
@@ -88,31 +89,43 @@ def load_patient_exam_for_eval(pk: int) -> PatientExamination:
|
|
|
88
89
|
)
|
|
89
90
|
|
|
90
91
|
|
|
91
|
-
def requirement_sets_for_patient_exam(
|
|
92
|
+
def requirement_sets_for_patient_exam(
|
|
93
|
+
pe: PatientExamination, user_tags: Optional[List[str]] = None
|
|
94
|
+
) -> QuerySet:
|
|
92
95
|
"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
This function resolves requirement sets through the examination's requirement set links.
|
|
96
|
-
It follows the relationship: PatientExamination → Examination → ExaminationRequirementSet → RequirementSet
|
|
96
|
+
Retrieve all RequirementSets linked to a PatientExamination's examination.
|
|
97
97
|
|
|
98
98
|
Args:
|
|
99
|
-
pe: PatientExamination instance
|
|
99
|
+
pe: PatientExamination instance
|
|
100
|
+
user_tags: Optional list of tag names to filter requirement sets
|
|
100
101
|
|
|
101
102
|
Returns:
|
|
102
|
-
|
|
103
|
+
QuerySet of RequirementSet instances
|
|
103
104
|
"""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
105
|
+
if not pe or not pe.examination:
|
|
106
|
+
from endoreg_db.models import RequirementSet
|
|
107
|
+
|
|
108
|
+
return RequirementSet.objects.none()
|
|
109
|
+
|
|
110
|
+
# Start with examination-linked requirement sets
|
|
111
|
+
req_sets = pe.examination.exam_reqset_links.select_related(
|
|
112
|
+
"requirement_set"
|
|
113
|
+
).values_list("requirement_set", flat=True)
|
|
114
|
+
|
|
115
|
+
from endoreg_db.models import RequirementSet
|
|
113
116
|
|
|
117
|
+
qs = RequirementSet.objects.filter(pk__in=req_sets)
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
# Apply tag filtering if provided
|
|
120
|
+
if user_tags:
|
|
121
|
+
qs = qs.filter(tags__name__in=user_tags).distinct()
|
|
122
|
+
|
|
123
|
+
return qs
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def build_initial_lookup(
|
|
127
|
+
pe: PatientExamination, user_tags: Optional[List[str]] = None
|
|
128
|
+
) -> Dict[str, Any]:
|
|
116
129
|
"""
|
|
117
130
|
Build the initial lookup dictionary for a patient examination.
|
|
118
131
|
|
|
@@ -135,14 +148,14 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
|
|
|
135
148
|
Dictionary containing initial lookup data with the following keys:
|
|
136
149
|
- patient_examination_id: ID of the patient examination
|
|
137
150
|
- requirement_sets: List of available requirement sets with metadata
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
151
|
+
- available_findings: List of finding IDs available for the examination
|
|
152
|
+
- required_findings: List of finding IDs that are required by defaults
|
|
153
|
+
- requirement_defaults: Default findings per requirement
|
|
154
|
+
- classification_choices: Available classification choices per requirement
|
|
155
|
+
- requirements_by_set: Empty dict (populated on selection)
|
|
156
|
+
- requirement_status: Empty dict (computed on evaluation)
|
|
157
|
+
- requirement_set_status: Empty dict (computed on evaluation)
|
|
158
|
+
- suggested_actions: Empty dict (computed on evaluation)
|
|
146
159
|
"""
|
|
147
160
|
# Available + required findings
|
|
148
161
|
available_findings = (
|
|
@@ -153,7 +166,7 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
|
|
|
153
166
|
required_findings: List[int] = [] # fill by scanning requirements below
|
|
154
167
|
|
|
155
168
|
# Requirement sets: ids + meta
|
|
156
|
-
rs_objs = requirement_sets_for_patient_exam(pe)
|
|
169
|
+
rs_objs = requirement_sets_for_patient_exam(pe, user_tags=user_tags)
|
|
157
170
|
requirement_sets = [
|
|
158
171
|
{
|
|
159
172
|
"id": rs.id,
|
|
@@ -189,20 +202,22 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
|
|
|
189
202
|
return {
|
|
190
203
|
"patient_examination_id": pe.id,
|
|
191
204
|
"requirement_sets": requirement_sets,
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"
|
|
205
|
+
"available_findings": available_findings,
|
|
206
|
+
"required_findings": required_findings,
|
|
207
|
+
"requirement_defaults": req_defaults,
|
|
208
|
+
"classification_choices": cls_choices,
|
|
196
209
|
# New fields for expanded lookup payload
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
210
|
+
"requirements_by_set": {}, # Will be populated when requirement sets are selected
|
|
211
|
+
"requirement_status": {}, # Status of each requirement (satisfied/unsatisfied)
|
|
212
|
+
"requirement_set_status": {}, # Status of each requirement set
|
|
213
|
+
"suggested_actions": {}, # Suggested actions to satisfy requirements
|
|
201
214
|
# You can add "selectedRequirementSetIds" as the user makes choices
|
|
202
215
|
}
|
|
203
216
|
|
|
204
217
|
|
|
205
|
-
def create_lookup_token_for_pe(
|
|
218
|
+
def create_lookup_token_for_pe(
|
|
219
|
+
pe_id: int, user_tags: Optional[List[str]] = None
|
|
220
|
+
) -> str:
|
|
206
221
|
"""
|
|
207
222
|
Create a lookup token for a patient examination.
|
|
208
223
|
|
|
@@ -220,7 +235,7 @@ def create_lookup_token_for_pe(pe_id: int) -> str:
|
|
|
220
235
|
Exception: For any other errors during initialization
|
|
221
236
|
"""
|
|
222
237
|
pe = load_patient_exam_for_eval(pe_id)
|
|
223
|
-
token = LookupStore().init(build_initial_lookup(pe))
|
|
238
|
+
token = LookupStore().init(build_initial_lookup(pe, user_tags=user_tags))
|
|
224
239
|
return token
|
|
225
240
|
|
|
226
241
|
|
|
@@ -245,18 +260,16 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
|
|
|
245
260
|
|
|
246
261
|
Returns:
|
|
247
262
|
Dictionary of updates containing:
|
|
248
|
-
-
|
|
249
|
-
-
|
|
250
|
-
-
|
|
251
|
-
-
|
|
252
|
-
-
|
|
253
|
-
-
|
|
263
|
+
- requirements_by_set: Requirements grouped by selected requirement sets
|
|
264
|
+
- requirement_status: Boolean status for each requirement
|
|
265
|
+
- requirement_set_status: Boolean status for each requirement set
|
|
266
|
+
- requirement_defaults: Default findings per requirement
|
|
267
|
+
- classification_choices: Available choices per requirement
|
|
268
|
+
- suggested_actions: UI actions to satisfy unsatisfied requirements
|
|
254
269
|
|
|
255
270
|
Raises:
|
|
256
271
|
ValueError: If lookup data is invalid or patient examination not found
|
|
257
272
|
"""
|
|
258
|
-
import logging
|
|
259
|
-
|
|
260
273
|
logger = logging.getLogger(__name__)
|
|
261
274
|
|
|
262
275
|
store = LookupStore(token=token)
|
|
@@ -383,12 +396,12 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
|
|
|
383
396
|
# if you implement server-side simulation later, adjust requirement_status with staged result here
|
|
384
397
|
|
|
385
398
|
updates = {
|
|
386
|
-
"
|
|
387
|
-
"
|
|
388
|
-
"
|
|
389
|
-
"
|
|
390
|
-
"
|
|
391
|
-
"
|
|
399
|
+
"requirements_by_set": requirements_by_set,
|
|
400
|
+
"requirement_status": requirement_status,
|
|
401
|
+
"requirement_set_status": set_status,
|
|
402
|
+
"requirement_defaults": req_defaults, # keep your existing key
|
|
403
|
+
"classification_choices": cls_choices, # keep your existing key
|
|
404
|
+
"suggested_actions": suggested_actions, # new
|
|
392
405
|
}
|
|
393
406
|
|
|
394
407
|
logger.debug(
|
|
@@ -173,8 +173,8 @@ class LookupStore:
|
|
|
173
173
|
# Check if required fields are present
|
|
174
174
|
required_fields = [
|
|
175
175
|
"patient_examination_id",
|
|
176
|
-
"
|
|
177
|
-
"
|
|
176
|
+
"requirements_by_set",
|
|
177
|
+
"requirement_status",
|
|
178
178
|
]
|
|
179
179
|
missing_fields = [field for field in required_fields if field not in data]
|
|
180
180
|
|