endoreg-db 0.3.6__py3-none-any.whl → 0.8.6.1__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/admin.py +92 -3
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +18 -6
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +92 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +144 -65
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/{label → ai_model_label}/label/data.yaml +88 -62
- 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/{label → ai_model_label}/label-type/data.yaml +6 -6
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/{model_type → ai_model_type}/data.yaml +6 -6
- 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 -167
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +7 -7
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +8 -8
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +22 -22
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +18 -18
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +18 -18
- endoreg_db/data/case_template/rule/19_create_patient.yaml +16 -16
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -35
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +58 -58
- endoreg_db/data/case_template/template/base.yaml +7 -7
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +2 -2
- endoreg_db/data/case_template/tmp/_rule_value +13 -13
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -21
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +9 -9
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +6 -6
- endoreg_db/data/center/data.yaml +90 -59
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -144
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -48
- 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 -37
- endoreg_db/data/disease/hepatology.yaml +4 -4
- endoreg_db/data/disease/misc.yaml +5 -6
- endoreg_db/data/disease/renal.yaml +4 -4
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -6
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +5 -5
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -41
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +19 -19
- endoreg_db/data/distribution/date/patient.yaml +6 -6
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +6 -6
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -132
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +10 -10
- endoreg_db/data/endoscopy_processor/data.yaml +50 -45
- endoreg_db/data/event/cardiology.yaml +15 -28
- endoreg_db/data/event/neurology.yaml +13 -13
- endoreg_db/data/event/surgery.yaml +12 -12
- endoreg_db/data/event/thrombembolism.yaml +19 -19
- endoreg_db/data/examination/examinations/data.yaml +72 -66
- endoreg_db/data/examination/time/data.yaml +47 -47
- endoreg_db/data/examination/time-type/data.yaml +7 -7
- endoreg_db/data/examination/type/data.yaml +17 -5
- endoreg_db/data/examination_indication/endoscopy.yaml +424 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +160 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- endoreg_db/data/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/finding/complication.yaml +16 -0
- endoreg_db/data/finding/data.yaml +105 -0
- endoreg_db/data/finding/examination_setting.yaml +16 -0
- endoreg_db/data/finding/medication_related.yaml +18 -0
- endoreg_db/data/finding/outcome.yaml +12 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +43 -0
- endoreg_db/data/gender/data.yaml +42 -18
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -30
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +5 -5
- 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 -31
- endoreg_db/data/lab_value/coagulation.yaml +54 -49
- endoreg_db/data/lab_value/electrolytes.yaml +228 -190
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -121
- endoreg_db/data/lab_value/hematology.yaml +184 -169
- endoreg_db/data/lab_value/hormones.yaml +59 -53
- endoreg_db/data/lab_value/lipids.yaml +53 -44
- endoreg_db/data/lab_value/misc.yaml +76 -30
- endoreg_db/data/lab_value/renal_function.yaml +12 -11
- 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/medication/anticoagulation.yaml +64 -64
- endoreg_db/data/medication/tah.yaml +69 -69
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -120
- endoreg_db/data/medication_indication_type/data.yaml +10 -10
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +40 -40
- endoreg_db/data/medication_intake_time/base.yaml +30 -30
- endoreg_db/data/medication_schedule/apixaban.yaml +94 -94
- endoreg_db/data/medication_schedule/ass.yaml +12 -12
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -26
- 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 +5 -5
- endoreg_db/data/pdf_type/data.yaml +46 -28
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -66
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -33
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -308
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -88
- endoreg_db/data/profession/data.yaml +70 -70
- 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 -55
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -26
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -19
- endoreg_db/data/requirement/age.yaml +26 -0
- endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/gender.yaml +25 -0
- endoreg_db/data/requirement/lab_value.yaml +441 -0
- endoreg_db/data/requirement/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/age.yaml +13 -0
- endoreg_db/data/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +52 -0
- endoreg_db/data/requirement_set_type/data.yaml +20 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -15
- 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 +11 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -12
- endoreg_db/data/unit/concentration.yaml +115 -92
- endoreg_db/data/unit/data.yaml +17 -17
- endoreg_db/data/unit/length.yaml +30 -30
- endoreg_db/data/unit/misc.yaml +19 -19
- endoreg_db/data/unit/rate.yaml +5 -5
- endoreg_db/data/unit/time.yaml +48 -13
- endoreg_db/data/unit/volume.yaml +35 -35
- endoreg_db/data/unit/weight.yaml +37 -37
- endoreg_db/data/waste/data.yaml +11 -11
- endoreg_db/exceptions.py +19 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +5 -3
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +18 -0
- endoreg_db/forms/patient_form.py +27 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -23
- endoreg_db/forms/settings/__init__.py +8 -8
- endoreg_db/forms/unit.py +5 -5
- endoreg_db/helpers/__init__.py +0 -0
- endoreg_db/helpers/count_db.py +45 -0
- endoreg_db/helpers/data_loader.py +208 -0
- endoreg_db/helpers/default_objects.py +378 -0
- endoreg_db/helpers/download_segmentation_model.py +31 -0
- endoreg_db/helpers/interact.py +6 -0
- endoreg_db/helpers/test_video_helper.py +119 -0
- endoreg_db/logger_conf.py +140 -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 +125 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +115 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
- endoreg_db/management/commands/fix_video_paths.py +165 -0
- endoreg_db/management/commands/import_fallback_video.py +203 -0
- endoreg_db/management/commands/import_report.py +298 -0
- endoreg_db/management/commands/import_video.py +423 -0
- endoreg_db/management/commands/import_video_with_classification.py +367 -0
- endoreg_db/management/commands/init_default_ai_model.py +112 -0
- endoreg_db/management/commands/load_ai_model_data.py +77 -45
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +192 -128
- endoreg_db/management/commands/load_center_data.py +68 -43
- endoreg_db/management/commands/{load_medication_intake_time_data.py → load_contraindication_data.py} +40 -40
- endoreg_db/management/commands/load_disease_classification_choices_data.py +40 -40
- endoreg_db/management/commands/load_disease_classification_data.py +40 -40
- endoreg_db/management/commands/load_disease_data.py +61 -39
- endoreg_db/management/commands/load_distribution_data.py +65 -65
- endoreg_db/management/commands/{load_endoscope_type_data.py → load_endoscope_data.py} +67 -44
- endoreg_db/management/commands/load_event_data.py +40 -40
- endoreg_db/management/commands/load_examination_data.py +74 -74
- endoreg_db/management/commands/load_examination_indication_data.py +86 -0
- endoreg_db/management/commands/load_finding_data.py +128 -0
- endoreg_db/management/commands/load_gender_data.py +43 -43
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +131 -132
- endoreg_db/management/commands/load_information_source.py +50 -44
- endoreg_db/management/commands/load_lab_value_data.py +49 -49
- endoreg_db/management/commands/load_medication_data.py +103 -41
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/{load_medication_indication_type_data.py → load_organ_data.py} +42 -40
- endoreg_db/management/commands/load_pdf_type_data.py +60 -60
- endoreg_db/management/commands/load_profession_data.py +43 -43
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +45 -45
- endoreg_db/management/commands/load_requirement_data.py +180 -0
- endoreg_db/management/commands/load_risk_data.py +56 -0
- endoreg_db/management/commands/load_shift_data.py +60 -0
- endoreg_db/management/commands/load_tag_data.py +57 -0
- endoreg_db/management/commands/load_unit_data.py +45 -45
- endoreg_db/management/commands/load_user_groups.py +28 -28
- endoreg_db/management/commands/register_ai_model.py +64 -65
- endoreg_db/management/commands/reset_celery_schedule.py +9 -9
- endoreg_db/management/commands/setup_endoreg_db.py +381 -0
- endoreg_db/management/commands/start_filewatcher.py +106 -0
- endoreg_db/management/commands/storage_management.py +548 -0
- endoreg_db/management/commands/summarize_db_content.py +189 -0
- endoreg_db/management/commands/validate_video.py +204 -0
- endoreg_db/management/commands/validate_video_files.py +161 -0
- endoreg_db/management/commands/video_validation.py +22 -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 +1857 -582
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/models/__init__.py +359 -74
- endoreg_db/models/administration/__init__.py +116 -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 +156 -0
- endoreg_db/models/{ai_model → administration/ai}/model_type.py +41 -26
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +15 -6
- endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +125 -81
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +269 -276
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +86 -73
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +26 -28
- endoreg_db/models/{center → administration/center}/__init__.py +13 -4
- endoreg_db/models/administration/center/center.py +67 -0
- endoreg_db/models/administration/center/center_product.py +64 -0
- endoreg_db/models/administration/center/center_resource.py +49 -0
- endoreg_db/models/administration/center/center_shift.py +88 -0
- endoreg_db/models/administration/center/center_waste.py +30 -0
- endoreg_db/models/administration/permissions/__init__.py +44 -0
- endoreg_db/models/administration/person/__init__.py +24 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +35 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
- endoreg_db/models/administration/person/employee/employee_type.py +42 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +54 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/{persons → administration/person/names}/first_name.py +18 -18
- endoreg_db/models/{persons → administration/person/names}/last_name.py +18 -19
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/{persons → administration/person}/person.py +31 -31
- endoreg_db/models/administration/person/profession/__init__.py +24 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
- endoreg_db/models/administration/product/__init__.py +14 -0
- endoreg_db/models/administration/product/product.py +97 -0
- endoreg_db/models/administration/product/product_group.py +39 -0
- endoreg_db/models/administration/product/product_material.py +54 -0
- endoreg_db/models/{product → administration/product}/product_weight.py +47 -26
- endoreg_db/models/{product → administration/product}/reference_product.py +130 -99
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +37 -0
- endoreg_db/models/administration/qualification/qualification_type.py +35 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +69 -0
- endoreg_db/models/administration/shift/shift.py +51 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/label/__init__.py +24 -1
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +84 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
- endoreg_db/models/label/label.py +83 -84
- endoreg_db/models/label/label_set.py +53 -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 +41 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
- endoreg_db/models/label/video_segmentation_label.py +31 -0
- endoreg_db/models/label/video_segmentation_labelset.py +27 -0
- endoreg_db/models/media/__init__.py +16 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +111 -0
- endoreg_db/models/media/pdf/__init__.py +11 -0
- endoreg_db/models/media/pdf/raw_pdf.py +757 -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 +77 -0
- endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +19 -19
- endoreg_db/models/media/video/__init__.py +8 -0
- endoreg_db/models/media/video/create_from_file.py +358 -0
- endoreg_db/models/media/video/pipe_1.py +213 -0
- endoreg_db/models/media/video/pipe_2.py +105 -0
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file.py +825 -0
- endoreg_db/models/media/video/video_file_ai.py +443 -0
- endoreg_db/models/media/video/video_file_anonymize.py +349 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -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 +104 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +141 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/media/video/video_file_io.py +168 -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 +45 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
- endoreg_db/models/media/video/video_file_segments.py +209 -0
- endoreg_db/models/media/video/video_metadata.py +65 -0
- endoreg_db/models/media/video/video_processing.py +152 -0
- endoreg_db/models/medical/__init__.py +146 -0
- endoreg_db/models/medical/contraindication/__init__.py +17 -0
- endoreg_db/models/medical/disease.py +156 -0
- endoreg_db/models/medical/event.py +137 -0
- endoreg_db/models/medical/examination/__init__.py +9 -0
- endoreg_db/models/medical/examination/examination.py +148 -0
- endoreg_db/models/medical/examination/examination_indication.py +278 -0
- endoreg_db/models/medical/examination/examination_time.py +49 -0
- endoreg_db/models/medical/examination/examination_time_type.py +41 -0
- endoreg_db/models/medical/examination/examination_type.py +48 -0
- endoreg_db/models/medical/finding/__init__.py +18 -0
- endoreg_db/models/medical/finding/finding.py +96 -0
- endoreg_db/models/medical/finding/finding_classification.py +142 -0
- endoreg_db/models/medical/finding/finding_intervention.py +52 -0
- endoreg_db/models/medical/finding/finding_type.py +35 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +65 -0
- endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +182 -143
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +419 -0
- endoreg_db/models/medical/medication/__init__.py +19 -0
- endoreg_db/models/medical/medication/medication.py +31 -0
- endoreg_db/models/medical/medication/medication_indication.py +50 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +39 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +44 -0
- endoreg_db/models/medical/medication/medication_schedule.py +45 -0
- endoreg_db/models/medical/organ/__init__.py +35 -0
- endoreg_db/models/medical/patient/__init__.py +56 -0
- endoreg_db/models/medical/patient/medication_examples.py +38 -0
- endoreg_db/models/medical/patient/patient_disease.py +63 -0
- endoreg_db/models/medical/patient/patient_event.py +75 -0
- endoreg_db/models/medical/patient/patient_examination.py +249 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +44 -0
- endoreg_db/models/medical/patient/patient_finding.py +357 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +40 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
- endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +222 -176
- endoreg_db/models/medical/patient/patient_medication.py +104 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +72 -0
- endoreg_db/models/medical/risk/risk_type.py +51 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/metadata/model_meta.py +206 -0
- endoreg_db/models/metadata/model_meta_logic.py +343 -0
- endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +89 -70
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1048 -0
- endoreg_db/models/metadata/video_meta.py +332 -0
- endoreg_db/models/metadata/video_prediction_logic.py +190 -0
- endoreg_db/models/metadata/video_prediction_meta.py +270 -0
- endoreg_db/models/other/__init__.py +40 -5
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +125 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +94 -0
- endoreg_db/models/{persons → other}/gender.py +27 -22
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +28 -16
- endoreg_db/models/other/resource.py +21 -17
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +33 -21
- endoreg_db/models/{unit.py → other/unit.py} +32 -22
- endoreg_db/models/other/waste.py +27 -20
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +767 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +95 -0
- endoreg_db/models/requirement/requirement_operator.py +176 -0
- endoreg_db/models/requirement/requirement_set.py +287 -0
- endoreg_db/models/rule/__init__.py +13 -0
- endoreg_db/models/{rules → rule}/rule.py +27 -24
- endoreg_db/models/{rules → rule}/rule_applicator.py +224 -224
- endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +16 -18
- endoreg_db/models/{rules → rule}/rule_type.py +19 -21
- endoreg_db/models/{rules → rule}/ruleset.py +17 -19
- endoreg_db/models/state/__init__.py +12 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/audit_ledger.py +150 -0
- endoreg_db/models/state/label_video_segment.py +22 -0
- endoreg_db/models/state/raw_pdf.py +187 -0
- endoreg_db/models/state/sensitive_meta.py +46 -0
- endoreg_db/models/state/video.py +232 -0
- endoreg_db/models/upload_job.py +99 -0
- endoreg_db/models/utils.py +135 -0
- endoreg_db/queries/__init__.py +4 -4
- endoreg_db/queries/annotations/__init__.py +2 -2
- endoreg_db/queries/annotations/legacy.py +158 -159
- endoreg_db/renames.yml +8 -0
- endoreg_db/root_urls.py +9 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +27 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
- endoreg_db/serializers/__init__.py +118 -10
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +223 -0
- endoreg_db/serializers/_old/raw_video_meta_validation.py +179 -0
- endoreg_db/serializers/_old/video.py +71 -0
- endoreg_db/serializers/administration/__init__.py +14 -0
- endoreg_db/serializers/administration/ai/__init__.py +10 -0
- endoreg_db/serializers/administration/ai/active_model.py +10 -0
- endoreg_db/serializers/administration/ai/ai_model.py +18 -0
- endoreg_db/serializers/administration/ai/model_type.py +10 -0
- endoreg_db/serializers/administration/center.py +9 -0
- endoreg_db/serializers/administration/gender.py +9 -0
- endoreg_db/serializers/anonymization.py +69 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +46 -0
- endoreg_db/serializers/examination/dropdown.py +21 -0
- endoreg_db/serializers/examination_serializer.py +12 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +54 -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 +13 -0
- endoreg_db/serializers/label/__init__.py +7 -0
- endoreg_db/serializers/label/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/__init__.py +7 -0
- endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
- endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
- endoreg_db/serializers/meta/__init__.py +19 -0
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
- endoreg_db/serializers/meta/report_meta.py +53 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -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 +182 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +120 -0
- endoreg_db/serializers/misc/stats.py +33 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +71 -0
- endoreg_db/serializers/patient/__init__.py +11 -0
- endoreg_db/serializers/patient/patient.py +86 -0
- endoreg_db/serializers/patient/patient_dropdown.py +27 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
- endoreg_db/serializers/pdf/__init__.py +5 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
- endoreg_db/serializers/report/__init__.py +9 -0
- endoreg_db/serializers/report/mixins.py +45 -0
- endoreg_db/serializers/report/report.py +105 -0
- endoreg_db/serializers/report/report_list.py +22 -0
- endoreg_db/serializers/report/secure_file_url.py +26 -0
- endoreg_db/serializers/requirements/requirement_schema.py +25 -0
- endoreg_db/serializers/requirements/requirement_sets.py +29 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/segmentation.py +263 -0
- endoreg_db/serializers/video/video_file_brief.py +10 -0
- endoreg_db/serializers/video/video_file_detail.py +83 -0
- endoreg_db/serializers/video/video_file_list.py +67 -0
- endoreg_db/serializers/video/video_metadata.py +105 -0
- endoreg_db/serializers/video/video_processing_history.py +153 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +223 -0
- endoreg_db/services/examination_evaluation.py +149 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +411 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/pdf_import.py +1382 -0
- endoreg_db/services/polling_coordinator.py +288 -0
- endoreg_db/services/pseudonym_service.py +89 -0
- endoreg_db/services/requirements_object.py +147 -0
- endoreg_db/services/segment_sync.py +155 -0
- endoreg_db/services/storage_aware_video_processor.py +344 -0
- endoreg_db/services/video_import.py +1259 -0
- endoreg_db/tasks/upload_tasks.py +207 -0
- endoreg_db/tasks/video_ingest.py +157 -0
- endoreg_db/tasks/video_processing_tasks.py +327 -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 +83 -0
- endoreg_db/urls/anonymization.py +32 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +39 -0
- endoreg_db/urls/examination.py +54 -0
- endoreg_db/urls/files.py +6 -0
- endoreg_db/urls/label_video_segment_validate.py +33 -0
- endoreg_db/urls/label_video_segments.py +46 -0
- endoreg_db/urls/media.py +227 -0
- endoreg_db/urls/patient.py +19 -0
- endoreg_db/urls/report.py +48 -0
- endoreg_db/urls/requirements.py +13 -0
- endoreg_db/urls/sensitive_meta.py +0 -0
- endoreg_db/urls/stats.py +46 -0
- endoreg_db/urls/upload.py +20 -0
- endoreg_db/urls/video.py +61 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +88 -1
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +5 -8
- endoreg_db/utils/ai/inference_dataset.py +52 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +159 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +291 -0
- endoreg_db/utils/ai/preprocess.py +68 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +0 -0
- endoreg_db/utils/case_generator/case_generator.py +159 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/utils/case_generator/utils.py +30 -0
- endoreg_db/utils/check_video_files.py +148 -0
- endoreg_db/utils/cropping.py +28 -28
- endoreg_db/utils/dataloader.py +175 -92
- endoreg_db/utils/dates.py +60 -0
- endoreg_db/utils/env.py +33 -0
- endoreg_db/utils/extract_specific_frames.py +72 -0
- endoreg_db/utils/file_operations.py +58 -30
- endoreg_db/utils/fix_video_path_direct.py +141 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +153 -34
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +193 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +76 -0
- endoreg_db/utils/ocr.py +190 -197
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/paths.py +95 -0
- endoreg_db/utils/permissions.py +143 -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 +120 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +20 -0
- endoreg_db/utils/product/sum_weights.py +18 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -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/lab_value_operators.py +578 -0
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
- endoreg_db/utils/setup_config.py +177 -0
- endoreg_db/utils/translation.py +27 -0
- endoreg_db/utils/uuid.py +4 -4
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/validate_video_detailed.py +357 -0
- endoreg_db/utils/video/__init__.py +26 -0
- endoreg_db/utils/video/extract_frames.py +88 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +835 -0
- endoreg_db/utils/video/names.py +42 -0
- endoreg_db/utils/video/streaming_processor.py +312 -0
- endoreg_db/utils/video/video_splitter.py +94 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
- endoreg_db/views/__init__.py +275 -0
- endoreg_db/views/anonymization/__init__.py +27 -0
- endoreg_db/views/anonymization/media_management.py +454 -0
- endoreg_db/views/anonymization/overview.py +216 -0
- endoreg_db/views/anonymization/validate.py +107 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +113 -0
- endoreg_db/views/examination/__init__.py +33 -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 +59 -0
- endoreg_db/views/examination/get_finding_classifications.py +36 -0
- endoreg_db/views/examination/get_findings.py +41 -0
- endoreg_db/views/examination/get_instruments.py +18 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +112 -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 +42 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
- endoreg_db/views/label/__init__.py +5 -0
- endoreg_db/views/label/label.py +15 -0
- endoreg_db/views/label_video_segment/__init__.py +16 -0
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
- endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
- endoreg_db/views/label_video_segment/validate.py +226 -0
- endoreg_db/views/media/__init__.py +45 -0
- endoreg_db/views/media/pdf_media.py +388 -0
- endoreg_db/views/media/segments.py +71 -0
- endoreg_db/views/media/sensitive_metadata.py +314 -0
- endoreg_db/views/media/video_media.py +272 -0
- endoreg_db/views/media/video_segments.py +524 -0
- endoreg_db/views/meta/__init__.py +15 -0
- endoreg_db/views/meta/available_files_list.py +146 -0
- endoreg_db/views/meta/report_meta.py +53 -0
- endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
- endoreg_db/views/meta/sensitive_meta_list.py +104 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
- endoreg_db/views/misc/__init__.py +63 -0
- endoreg_db/views/misc/center.py +13 -0
- endoreg_db/views/misc/csrf.py +7 -0
- endoreg_db/views/misc/gender.py +14 -0
- endoreg_db/views/misc/secure_file_serving_view.py +80 -0
- endoreg_db/views/misc/secure_file_url_view.py +84 -0
- endoreg_db/views/misc/secure_url_validate.py +79 -0
- endoreg_db/views/misc/stats.py +220 -0
- endoreg_db/views/misc/translation.py +182 -0
- endoreg_db/views/misc/upload_views.py +240 -0
- endoreg_db/views/patient/__init__.py +5 -0
- endoreg_db/views/patient/patient.py +210 -0
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +140 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
- endoreg_db/views/patient_examination/video.py +194 -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 +64 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
- endoreg_db/views/patient_finding_location/__init__.py +5 -0
- endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
- endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
- endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
- endoreg_db/views/pdf/__init__.py +8 -0
- endoreg_db/views/pdf/pdf_stream.py +187 -0
- endoreg_db/views/pdf/reimport.py +177 -0
- endoreg_db/views/report/__init__.py +9 -0
- endoreg_db/views/report/report_list.py +112 -0
- endoreg_db/views/report/report_with_secure_url.py +28 -0
- endoreg_db/views/report/start_examination.py +7 -0
- endoreg_db/views/requirement/__init__.py +10 -0
- endoreg_db/views/requirement/evaluate.py +279 -0
- endoreg_db/views/requirement/lookup.py +367 -0
- endoreg_db/views/requirement/lookup_store.py +252 -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 +229 -0
- endoreg_db/views/video/__init__.py +59 -0
- endoreg_db/views/video/correction.py +530 -0
- endoreg_db/views/video/reimport.py +195 -0
- endoreg_db/views/video/segmentation.py +274 -0
- endoreg_db/views/video/task_status.py +49 -0
- endoreg_db/views/video/timeline.py +46 -0
- endoreg_db/views/video/video_analyze.py +52 -0
- endoreg_db/views/video/video_apply_mask.py +48 -0
- endoreg_db/views/video/video_correction.py +21 -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_meta.py +29 -0
- endoreg_db/views/video/video_processing_history.py +24 -0
- endoreg_db/views/video/video_remove_frames.py +48 -0
- endoreg_db/views/video/video_stream.py +306 -0
- endoreg_db/views.py +0 -3
- endoreg_db-0.8.6.1.dist-info/METADATA +383 -0
- endoreg_db-0.8.6.1.dist-info/RECORD +793 -0
- {endoreg_db-0.3.6.dist-info → endoreg_db-0.8.6.1.dist-info}/WHEEL +1 -1
- {endoreg_db-0.3.6.dist-info → endoreg_db-0.8.6.1.dist-info/licenses}/LICENSE +674 -674
- endoreg_db/data/active_model/data.yaml +0 -3
- endoreg_db/data/label/label-set/data.yaml +0 -18
- endoreg_db/management/commands/_load_model_template.py +0 -41
- endoreg_db/management/commands/delete_all.py +0 -18
- endoreg_db/management/commands/delete_legacy_images.py +0 -19
- endoreg_db/management/commands/delete_legacy_videos.py +0 -17
- endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
- endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
- endoreg_db/management/commands/fix_auth_permission.py +0 -20
- endoreg_db/management/commands/import_legacy_images.py +0 -94
- endoreg_db/management/commands/import_legacy_videos.py +0 -76
- endoreg_db/management/commands/load_active_model_data.py +0 -45
- endoreg_db/management/commands/load_endoscopy_processor_data.py +0 -45
- endoreg_db/management/commands/load_g_play_data.py +0 -113
- endoreg_db/management/commands/load_label_data.py +0 -67
- endoreg_db/management/commands/load_medication_indication_data.py +0 -63
- endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
- endoreg_db/migrations/0002_rawvideofile.py +0 -26
- endoreg_db/migrations/0003_rawvideofile_frames_required.py +0 -18
- endoreg_db/migrations/0004_rename_hash_rawvideofile_video_hash.py +0 -18
- endoreg_db/migrations/0005_ffmpegmeta_remove_videoimportmeta_center_and_more.py +0 -56
- endoreg_db/migrations/0006_rawvideofile_center_alter_videometa_processor.py +0 -25
- endoreg_db/migrations/0007_rawvideofile_processor.py +0 -19
- endoreg_db/migrations/0008_rename_frames_required_rawvideofile_state_frames_required.py +0 -18
- endoreg_db/migrations/0009_sensitivemeta_rawvideofile_sensitive_meta.py +0 -31
- endoreg_db/migrations/0010_rename_endoscope_serial_number_sensitivemeta_endoscope_sn.py +0 -18
- endoreg_db/migrations/0011_rawvideofile_state_sensitive_data_retrieved.py +0 -18
- endoreg_db/migrations/0012_rawvideofile_prediction_dir_and_more.py +0 -109
- endoreg_db/migrations/0013_rawpdffile.py +0 -31
- endoreg_db/migrations/0014_pdftype_alter_rawpdffile_file_pdfmeta.py +0 -38
- endoreg_db/migrations/0015_rename_report_processed_rawpdffile_state_report_processed_and_more.py +0 -31
- endoreg_db/migrations/0016_rawpdffile_state_report_processing_required.py +0 -18
- endoreg_db/migrations/0017_firstname_lastname_center_first_names_and_more.py +0 -37
- endoreg_db/migrations/0018_reportreaderflag_reportreaderconfig.py +0 -37
- endoreg_db/migrations/0019_pdftype_cut_off_above_lines_and_more.py +0 -42
- endoreg_db/migrations/0020_rename_endoscopy_info_line_pdftype_endoscope_info_line.py +0 -18
- endoreg_db/migrations/0021_alter_pdftype_endoscope_info_line.py +0 -19
- endoreg_db/migrations/0022_alter_pdftype_endoscope_info_line.py +0 -19
- endoreg_db/migrations/0023_ttoquestionnaire_alter_pdftype_endoscope_info_line.py +0 -59
- endoreg_db/migrations/0024_remove_ttoquestionnaire_infections_and_more.py +0 -27
- endoreg_db/migrations/0025_event_alter_rawpdffile_file_patientevent.py +0 -42
- endoreg_db/migrations/0026_disease_diseaseclassification_and_more.py +0 -166
- endoreg_db/migrations/0027_labvalue_abbreviation_labvalue_default_normal_range_and_more.py +0 -38
- endoreg_db/migrations/0028_alter_unit_abbreviation.py +0 -18
- endoreg_db/migrations/0029_medicationintaketime_and_more.py +0 -75
- endoreg_db/migrations/0030_medicationindicationtype_and_more.py +0 -101
- endoreg_db/migrations/0031_rename_adapt_to_liver_function_medication_adapt_to_age_and_more.py +0 -38
- endoreg_db/migrations/0032_alter_medicationschedule_therapy_duration_d.py +0 -18
- endoreg_db/migrations/0033_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0034_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0035_alter_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0036_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0037_alter_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0038_emissionfactor_material_product_productgroup_and_more.py +0 -164
- endoreg_db/migrations/0039_referenceproduct_name.py +0 -19
- endoreg_db/migrations/0040_quizanswertype_quizquestiontype_quizquestion_and_more.py +0 -50
- endoreg_db/migrations/0041_gender_patientmedication_medication_indication_and_more.py +0 -40
- endoreg_db/migrations/0042_casetemplateruletype_casetemplaterulevalue_and_more.py +0 -74
- endoreg_db/migrations/0043_casetemplatetype_name_de_casetemplatetype_name_en.py +0 -23
- endoreg_db/migrations/0044_casetemplateruletype_name_de_and_more.py +0 -23
- endoreg_db/migrations/0045_casetemplaterulevalue_value_type.py +0 -19
- endoreg_db/migrations/0046_casetemplaterulevalue_target_field.py +0 -18
- endoreg_db/migrations/0047_casetemplaterule_target_model.py +0 -18
- endoreg_db/migrations/0048_remove_casetemplaterule_chained_rules_and_more.py +0 -22
- endoreg_db/migrations/0049_remove_casetemplaterule_rule_values.py +0 -17
- endoreg_db/migrations/0050_casetemplaterule_rule_values.py +0 -18
- endoreg_db/migrations/0051_remove_casetemplaterule_calling_rules_and_more.py +0 -27
- endoreg_db/migrations/0052_rename_case_template_type_casetemplate_template_type.py +0 -18
- endoreg_db/migrations/0053_patientlabsampletype_patientlabsample_and_more.py +0 -38
- endoreg_db/migrations/0054_multiplecategoricalvaluedistribution_and_more.py +0 -69
- endoreg_db/migrations/0055_remove_casetemplaterule_rule_values_and_more.py +0 -59
- endoreg_db/migrations/0056_datevaluedistribution_and_more.py +0 -32
- endoreg_db/migrations/0057_remove_datevaluedistribution_max_date_and_more.py +0 -72
- endoreg_db/migrations/0058_datevaluedistribution_description_and_more.py +0 -28
- endoreg_db/migrations/0059_casetemplaterule_rule_values.py +0 -18
- endoreg_db/migrations/0060_labvalue__default_date_value_distribution_and_more.py +0 -44
- endoreg_db/migrations/0061_remove_patientlabvalue_date_patientlabvalue_datetime.py +0 -24
- endoreg_db/migrations/0062_labvalue_numeric_precision.py +0 -18
- endoreg_db/migrations/0063_alter_labvalue_numeric_precision.py +0 -18
- endoreg_db/migrations/0064_casetemplaterule_extra_parameters_and_more.py +0 -23
- endoreg_db/migrations/0065_rename__date_value_distribution_casetemplaterule_date_value_distribution_and_more.py +0 -58
- endoreg_db/migrations/0066_alter_patientlabvalue_patient_and_more.py +0 -29
- endoreg_db/migrations/0067_alter_medicationindication_indication_type.py +0 -19
- endoreg_db/models/ai_model/__init__.py +0 -3
- endoreg_db/models/ai_model/active_model.py +0 -9
- endoreg_db/models/ai_model/model_meta.py +0 -24
- endoreg_db/models/annotation/__init__.py +0 -2
- endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -80
- endoreg_db/models/annotation/image_classification.py +0 -27
- endoreg_db/models/center/center.py +0 -25
- endoreg_db/models/center/center_product.py +0 -34
- endoreg_db/models/center/center_resource.py +0 -19
- endoreg_db/models/center/center_waste.py +0 -11
- endoreg_db/models/data_file/__init__.py +0 -6
- endoreg_db/models/data_file/base_classes/__init__.py +0 -2
- endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -51
- endoreg_db/models/data_file/base_classes/abstract_video.py +0 -201
- endoreg_db/models/data_file/frame.py +0 -45
- endoreg_db/models/data_file/import_classes/__init__.py +0 -32
- endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
- endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
- endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
- endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -188
- endoreg_db/models/data_file/import_classes/raw_video.py +0 -343
- endoreg_db/models/data_file/metadata/__init__.py +0 -3
- endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -31
- endoreg_db/models/data_file/metadata/video_meta.py +0 -133
- endoreg_db/models/data_file/report_file.py +0 -89
- endoreg_db/models/data_file/video/__init__.py +0 -7
- endoreg_db/models/data_file/video/import_meta.py +0 -25
- endoreg_db/models/data_file/video/video.py +0 -25
- endoreg_db/models/data_file/video_segment.py +0 -107
- endoreg_db/models/disease.py +0 -56
- endoreg_db/models/emission/__init__.py +0 -1
- endoreg_db/models/emission/emission_factor.py +0 -20
- endoreg_db/models/event.py +0 -22
- endoreg_db/models/examination/__init__.py +0 -4
- endoreg_db/models/examination/examination.py +0 -26
- endoreg_db/models/examination/examination_time.py +0 -27
- endoreg_db/models/examination/examination_time_type.py +0 -24
- endoreg_db/models/examination/examination_type.py +0 -18
- endoreg_db/models/hardware/__init__.py +0 -2
- endoreg_db/models/hardware/endoscope.py +0 -44
- endoreg_db/models/information_source.py +0 -29
- endoreg_db/models/laboratory/__init__.py +0 -1
- endoreg_db/models/laboratory/lab_value.py +0 -102
- endoreg_db/models/legacy_data/__init__.py +0 -3
- endoreg_db/models/legacy_data/image.py +0 -34
- endoreg_db/models/medication/__init__.py +0 -1
- endoreg_db/models/medication/medication.py +0 -148
- endoreg_db/models/other/distribution.py +0 -215
- endoreg_db/models/patient_examination/__init__.py +0 -35
- endoreg_db/models/permissions/__init__.py +0 -44
- endoreg_db/models/persons/__init__.py +0 -7
- endoreg_db/models/persons/examiner/__init__.py +0 -2
- endoreg_db/models/persons/examiner/examiner.py +0 -16
- endoreg_db/models/persons/examiner/examiner_type.py +0 -2
- endoreg_db/models/persons/patient/__init__.py +0 -8
- endoreg_db/models/persons/patient/case/case.py +0 -30
- endoreg_db/models/persons/patient/patient.py +0 -216
- endoreg_db/models/persons/patient/patient_disease.py +0 -16
- endoreg_db/models/persons/patient/patient_event.py +0 -22
- endoreg_db/models/persons/patient/patient_lab_sample.py +0 -106
- endoreg_db/models/persons/patient/patient_medication.py +0 -44
- endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -28
- endoreg_db/models/persons/portal_user_information.py +0 -27
- endoreg_db/models/prediction/__init__.py +0 -2
- endoreg_db/models/prediction/image_classification.py +0 -37
- endoreg_db/models/prediction/video_prediction_meta.py +0 -244
- endoreg_db/models/product/__init__.py +0 -5
- endoreg_db/models/product/product.py +0 -97
- endoreg_db/models/product/product_group.py +0 -19
- endoreg_db/models/product/product_material.py +0 -24
- endoreg_db/models/questionnaires/__init__.py +0 -114
- endoreg_db/models/quiz/__init__.py +0 -2
- endoreg_db/models/quiz/quiz_answer.py +0 -41
- endoreg_db/models/quiz/quiz_question.py +0 -54
- endoreg_db/models/report_reader/__init__.py +0 -2
- endoreg_db/models/report_reader/report_reader_config.py +0 -53
- endoreg_db/models/rules/__init__.py +0 -5
- endoreg_db/queries/get/__init__.py +0 -6
- endoreg_db/queries/get/center.py +0 -42
- endoreg_db/queries/get/model.py +0 -13
- endoreg_db/queries/get/patient.py +0 -14
- endoreg_db/queries/get/patient_examination.py +0 -20
- endoreg_db/queries/get/report_file.py +0 -33
- endoreg_db/queries/get/video.py +0 -31
- endoreg_db/serializers/ai_model.py +0 -19
- endoreg_db/serializers/annotation.py +0 -17
- endoreg_db/serializers/center.py +0 -11
- endoreg_db/serializers/examination.py +0 -33
- endoreg_db/serializers/frame.py +0 -13
- endoreg_db/serializers/hardware.py +0 -21
- endoreg_db/serializers/label.py +0 -22
- endoreg_db/serializers/patient.py +0 -10
- endoreg_db/serializers/prediction.py +0 -15
- endoreg_db/serializers/report_file.py +0 -7
- endoreg_db/serializers/video.py +0 -27
- endoreg_db/tests.py +0 -3
- endoreg_db/utils/legacy_ocr.py +0 -201
- endoreg_db/utils/video_metadata.py +0 -87
- endoreg_db-0.3.6.dist-info/METADATA +0 -33
- endoreg_db-0.3.6.dist-info/RECORD +0 -357
- /endoreg_db/{models/persons/patient/case/__init__.py → api/serializers/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/annotation.py → api/views/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/prediction.py → config/__init__.py} +0 -0
- /endoreg_db/{queries/get/video_import_meta.py → data/case_template/rule_value/.init} +0 -0
- /endoreg_db/{queries/get/video_prediction_meta.py → data/distribution/multiple_categorical/.init} +0 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
# models/data_file/import_classes/raw_pdf.py
|
|
2
|
+
# django db model "RawPdf"
|
|
3
|
+
# Class to store raw pdf file using django file field
|
|
4
|
+
# Class contains classmethod to create object from pdf file
|
|
5
|
+
# objects contains methods to extract text, extract metadata from text and anonymize text from pdf file uzing agl_report_reader.ReportReader class
|
|
6
|
+
# ------------------------------------------------------------------------------
|
|
7
|
+
import os
|
|
8
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
9
|
+
|
|
10
|
+
from django.core.exceptions import ValidationError
|
|
11
|
+
from django.core.files import File
|
|
12
|
+
from django.core.validators import FileExtensionValidator
|
|
13
|
+
from django.db import models
|
|
14
|
+
from numpy import isin # Import Django File
|
|
15
|
+
|
|
16
|
+
from endoreg_db.utils.file_operations import get_uuid_filename
|
|
17
|
+
from endoreg_db.utils.hashs import get_pdf_hash
|
|
18
|
+
from endoreg_db.utils.paths import PDF_DIR, RAW_PDF_DIR
|
|
19
|
+
|
|
20
|
+
# Use the specific paths from the centralized paths module
|
|
21
|
+
from ...utils import PDF_DIR
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from endoreg_db.models.administration.person import (
|
|
25
|
+
Examiner,
|
|
26
|
+
Patient,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from ...administration import Center
|
|
30
|
+
from ...medical.patient import PatientExamination
|
|
31
|
+
from ...metadata.pdf_meta import PdfType
|
|
32
|
+
from ...state import RawPdfState
|
|
33
|
+
from .report_file import AnonymExaminationReport
|
|
34
|
+
|
|
35
|
+
# setup logging to pdf_import.log
|
|
36
|
+
import logging
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
from ...metadata import SensitiveMeta
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger("raw_pdf")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RawPdfFile(models.Model):
|
|
45
|
+
# Fields from AbstractPdfFile
|
|
46
|
+
pdf_hash = models.CharField(max_length=255, unique=True)
|
|
47
|
+
pdf_type = models.ForeignKey(
|
|
48
|
+
"PdfType",
|
|
49
|
+
on_delete=models.SET_NULL,
|
|
50
|
+
blank=True,
|
|
51
|
+
null=True,
|
|
52
|
+
)
|
|
53
|
+
center = models.ForeignKey(
|
|
54
|
+
"Center",
|
|
55
|
+
on_delete=models.SET_NULL,
|
|
56
|
+
blank=True,
|
|
57
|
+
null=True,
|
|
58
|
+
) # type: ignore
|
|
59
|
+
examination = models.ForeignKey(
|
|
60
|
+
"PatientExamination",
|
|
61
|
+
on_delete=models.SET_NULL,
|
|
62
|
+
blank=True,
|
|
63
|
+
null=True,
|
|
64
|
+
related_name="raw_pdf_files",
|
|
65
|
+
) # type: ignore
|
|
66
|
+
examiner = models.ForeignKey(
|
|
67
|
+
"Examiner",
|
|
68
|
+
on_delete=models.SET_NULL,
|
|
69
|
+
blank=True,
|
|
70
|
+
null=True,
|
|
71
|
+
) # type: ignore
|
|
72
|
+
text = models.TextField(blank=True, null=True)
|
|
73
|
+
date_created = models.DateTimeField(auto_now_add=True)
|
|
74
|
+
date_modified = models.DateTimeField(auto_now=True)
|
|
75
|
+
anonymized = models.BooleanField(
|
|
76
|
+
default=False, help_text="True if the PDF has been anonymized."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Fields specific to RawPdfFile (keeping existing related_names)
|
|
80
|
+
file = models.FileField(
|
|
81
|
+
# Use the relative path from the specific PDF_DIR
|
|
82
|
+
upload_to=PDF_DIR.name,
|
|
83
|
+
validators=[FileExtensionValidator(allowed_extensions=["pdf"])],
|
|
84
|
+
) # type: ignore
|
|
85
|
+
|
|
86
|
+
anonymized_file = models.FileField(
|
|
87
|
+
upload_to=PDF_DIR.name,
|
|
88
|
+
validators=[FileExtensionValidator(allowed_extensions=["pdf"])],
|
|
89
|
+
null=True,
|
|
90
|
+
blank=True,
|
|
91
|
+
) # type: ignore
|
|
92
|
+
|
|
93
|
+
state = models.OneToOneField(
|
|
94
|
+
"RawPdfState",
|
|
95
|
+
on_delete=models.SET_NULL,
|
|
96
|
+
blank=True,
|
|
97
|
+
null=True,
|
|
98
|
+
related_name="raw_pdf_file",
|
|
99
|
+
) # type: ignore
|
|
100
|
+
|
|
101
|
+
objects = models.Manager()
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def uuid(self):
|
|
105
|
+
"""
|
|
106
|
+
Compatibility property - returns pdf_hash as UUID-like identifier.
|
|
107
|
+
|
|
108
|
+
Note: RawPdfFile uses pdf_hash instead of UUID for identification.
|
|
109
|
+
This property exists for API backward compatibility.
|
|
110
|
+
"""
|
|
111
|
+
return self.pdf_hash
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def file_path(self) -> Path | None:
|
|
115
|
+
"""
|
|
116
|
+
Returns the file path of the stored PDF file if available; otherwise, returns None.
|
|
117
|
+
"""
|
|
118
|
+
from django.db.models.fields.files import FieldFile
|
|
119
|
+
|
|
120
|
+
# assert self.file has path attribute
|
|
121
|
+
assert isinstance(self.file, FieldFile)
|
|
122
|
+
if self.file and self.file.name:
|
|
123
|
+
try:
|
|
124
|
+
return Path(self.file.path)
|
|
125
|
+
except (ValueError, AttributeError, NotImplementedError):
|
|
126
|
+
return None
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
def set_file_path(self, file_path: Path):
|
|
130
|
+
"""
|
|
131
|
+
Sets the file path of the stored PDF file.
|
|
132
|
+
"""
|
|
133
|
+
self.file = File(file_path) # type: ignore
|
|
134
|
+
self.save(update_fields=["file"])
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def anonymized_file_path(self) -> Path | None:
|
|
138
|
+
"""
|
|
139
|
+
Returns the file path of the anonymized PDF file if available; otherwise, returns None.
|
|
140
|
+
"""
|
|
141
|
+
if self.anonymized_file and self.anonymized_file.name:
|
|
142
|
+
try:
|
|
143
|
+
return Path(self.anonymized_file.path)
|
|
144
|
+
except (ValueError, AttributeError, NotImplementedError):
|
|
145
|
+
return None
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def set_anonymized_file_path(self, file_path: Path):
|
|
149
|
+
"""
|
|
150
|
+
Sets the file path of the anonymized PDF file.
|
|
151
|
+
"""
|
|
152
|
+
self.anonymized_file = File(file_path) # type: ignore
|
|
153
|
+
self.save(update_fields=["anonymized_file"])
|
|
154
|
+
|
|
155
|
+
def get_raw_file_path(self) -> Optional[Path]:
|
|
156
|
+
"""
|
|
157
|
+
Get the path to the raw PDF file, searching common locations.
|
|
158
|
+
|
|
159
|
+
This method attempts to find the original raw PDF file by checking:
|
|
160
|
+
1. Direct hash-based path in raw_pdfs/
|
|
161
|
+
2. Scanning raw_pdfs/ directory for files matching the hash
|
|
162
|
+
3. Checking the file field if it exists
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Path to raw file if it exists, None otherwise
|
|
166
|
+
"""
|
|
167
|
+
from django.conf import settings
|
|
168
|
+
|
|
169
|
+
# Check if file field already points to a valid file
|
|
170
|
+
if self.file and self.file.name:
|
|
171
|
+
try:
|
|
172
|
+
file_path = Path(self.file.path)
|
|
173
|
+
if file_path.exists():
|
|
174
|
+
logger.debug(f"Found raw PDF via file field: {file_path}")
|
|
175
|
+
return file_path
|
|
176
|
+
except (ValueError, AttributeError, NotImplementedError):
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
# Define potential raw directories
|
|
180
|
+
raw_dirs = [
|
|
181
|
+
PDF_DIR / "sensitive", # Files might be in sensitive dir
|
|
182
|
+
Path(settings.BASE_DIR) / "data" / "raw_pdfs",
|
|
183
|
+
Path(settings.BASE_DIR) / "data" / "pdfs" / "raw",
|
|
184
|
+
PDF_DIR, # General PDF directory
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
# Check direct hash-based name in each directory
|
|
188
|
+
for raw_dir in raw_dirs:
|
|
189
|
+
if not raw_dir.exists():
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
hash_path = raw_dir / f"{self.pdf_hash}.pdf"
|
|
193
|
+
if hash_path.exists():
|
|
194
|
+
logger.debug(f"Found raw PDF at: {hash_path}")
|
|
195
|
+
return hash_path
|
|
196
|
+
|
|
197
|
+
# Scan directories for matching hash
|
|
198
|
+
for raw_dir in raw_dirs:
|
|
199
|
+
if not raw_dir.exists():
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
for file_path in raw_dir.glob("*.pdf"):
|
|
203
|
+
try:
|
|
204
|
+
file_hash = get_pdf_hash(file_path)
|
|
205
|
+
if file_hash == self.pdf_hash:
|
|
206
|
+
logger.debug(f"Found matching PDF by hash: {file_path}")
|
|
207
|
+
return file_path
|
|
208
|
+
except Exception as e:
|
|
209
|
+
logger.debug(f"Error checking {file_path}: {e}")
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
logger.warning(f"No raw file found for PDF hash: {self.pdf_hash}")
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def file_url(self):
|
|
217
|
+
"""
|
|
218
|
+
Returns the URL of the stored PDF file if available; otherwise, returns None.
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
return self.file.url if self.file and self.file.name else None
|
|
222
|
+
except (ValueError, AttributeError):
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def anonymized_file_url(self):
|
|
227
|
+
"""
|
|
228
|
+
Returns the URL of the stored PDF file if available; otherwise, returns None.
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
return (
|
|
232
|
+
self.anonymized_file.url
|
|
233
|
+
if self.anonymized_file and self.anonymized_file.name
|
|
234
|
+
else None
|
|
235
|
+
)
|
|
236
|
+
except (ValueError, AttributeError):
|
|
237
|
+
return None
|
|
238
|
+
|
|
239
|
+
patient = models.ForeignKey(
|
|
240
|
+
"Patient",
|
|
241
|
+
on_delete=models.SET_NULL,
|
|
242
|
+
blank=True,
|
|
243
|
+
null=True,
|
|
244
|
+
related_name="raw_pdf_files",
|
|
245
|
+
) # type: ignore
|
|
246
|
+
sensitive_meta = models.ForeignKey(
|
|
247
|
+
"SensitiveMeta",
|
|
248
|
+
on_delete=models.SET_NULL,
|
|
249
|
+
related_name="raw_pdf_files",
|
|
250
|
+
null=True,
|
|
251
|
+
blank=True,
|
|
252
|
+
) # type: ignore
|
|
253
|
+
state_report_processing_required = models.BooleanField(default=True)
|
|
254
|
+
state_report_processed = models.BooleanField(default=False)
|
|
255
|
+
raw_meta = models.JSONField(blank=True, null=True)
|
|
256
|
+
anonym_examination_report = models.OneToOneField(
|
|
257
|
+
"AnonymExaminationReport",
|
|
258
|
+
on_delete=models.SET_NULL,
|
|
259
|
+
blank=True,
|
|
260
|
+
null=True,
|
|
261
|
+
related_name="raw_pdf_file",
|
|
262
|
+
) # type: ignore
|
|
263
|
+
anonymized_text = models.TextField(blank=True, null=True)
|
|
264
|
+
|
|
265
|
+
# Type hinting is needed, improve and use correct django types
|
|
266
|
+
if TYPE_CHECKING:
|
|
267
|
+
file: Optional[Union[models.FieldFile, models.FileField]]
|
|
268
|
+
anonymized_file: Optional[Union[models.FieldFile, models.FileField]]
|
|
269
|
+
pdf_type: Optional[models.ForeignKey]
|
|
270
|
+
examination: Optional[models.ForeignKey["PatientExamination"]]
|
|
271
|
+
examiner: Optional[models.ForeignKey["Examiner"]]
|
|
272
|
+
patient: Optional[models.ForeignKey["Patient"]]
|
|
273
|
+
center: Optional[models.ForeignKey["Center"]]
|
|
274
|
+
anonym_examination_report: Optional[
|
|
275
|
+
models.OneToOneField["AnonymExaminationReport"]
|
|
276
|
+
]
|
|
277
|
+
sensitive_meta: Optional[models.ForeignKey["SensitiveMeta"]]
|
|
278
|
+
state: Optional[models.ForeignKey["RawPdfState"]]
|
|
279
|
+
|
|
280
|
+
def __str__(self):
|
|
281
|
+
"""
|
|
282
|
+
Return a string representation of the RawPdfFile, including its PDF hash, type, and center.
|
|
283
|
+
"""
|
|
284
|
+
str_repr = f"{self.pdf_hash} ({self.pdf_type}, {self.center})"
|
|
285
|
+
return str_repr
|
|
286
|
+
|
|
287
|
+
def delete(self, *args, **kwargs):
|
|
288
|
+
"""
|
|
289
|
+
Deletes the RawPdfFile instance from the database and removes the associated file from storage if it exists.
|
|
290
|
+
|
|
291
|
+
This method ensures that the physical PDF file is deleted from the file system after the database record is removed. Logs warnings or errors if the file cannot be found or deleted.
|
|
292
|
+
"""
|
|
293
|
+
# Call the original delete method first to remove DB record
|
|
294
|
+
if self.file:
|
|
295
|
+
try:
|
|
296
|
+
if self.file_path:
|
|
297
|
+
os.remove(Path(self.file_path))
|
|
298
|
+
logger.info("Original file removed: %s", self.file)
|
|
299
|
+
except Exception as e:
|
|
300
|
+
logger.warning(
|
|
301
|
+
f"Could not get file path for {self.file.name} before deletion: {e}"
|
|
302
|
+
)
|
|
303
|
+
if self.anonymized_file:
|
|
304
|
+
try:
|
|
305
|
+
if self.anonymized_file_path:
|
|
306
|
+
os.remove(Path(self.anonymized_file_path))
|
|
307
|
+
logger.info(
|
|
308
|
+
"Anonymized file removed: %s", self.anonymized_file.name
|
|
309
|
+
)
|
|
310
|
+
except OSError as e:
|
|
311
|
+
logger.error(
|
|
312
|
+
"Error removing anonymized file %s: %s",
|
|
313
|
+
self.anonymized_file.name,
|
|
314
|
+
e,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
super().delete(*args, **kwargs)
|
|
318
|
+
|
|
319
|
+
def validate_metadata_annotation(
|
|
320
|
+
self, extracted_data_dict: Optional[dict] = None
|
|
321
|
+
) -> bool:
|
|
322
|
+
"""
|
|
323
|
+
Validate the metadata of the RawPdf instance.
|
|
324
|
+
|
|
325
|
+
Called after annotation in the frontend, this method deletes the associated active file, updates the sensitive meta data with the user annotated data.
|
|
326
|
+
It also ensures the video file is properly saved after the metadata update.
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
if not self.sensitive_meta:
|
|
330
|
+
logger.error("No sensitive meta data associated with this PDF file.")
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
if not extracted_data_dict:
|
|
334
|
+
logger.error("No extracted data provided for validation.")
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
# Update sensitive meta with the provided data
|
|
338
|
+
self.sensitive_meta.update_from_dict(extracted_data_dict)
|
|
339
|
+
|
|
340
|
+
# Save the sensitive meta to ensure changes are persisted
|
|
341
|
+
self.sensitive_meta.save()
|
|
342
|
+
|
|
343
|
+
# Save the RawPdfFile instance to ensure all changes are saved
|
|
344
|
+
self.save()
|
|
345
|
+
|
|
346
|
+
logger.info(f"Metadata for PDF {self.pk} validated and updated successfully.")
|
|
347
|
+
|
|
348
|
+
if self.file_path:
|
|
349
|
+
try:
|
|
350
|
+
os.unlink(self.file_path) # Delete the original file if it exists
|
|
351
|
+
except OSError as e:
|
|
352
|
+
logger.error(f"Error removing original file {self.file_path}: {e}")
|
|
353
|
+
|
|
354
|
+
if self.anonymized_file_path:
|
|
355
|
+
try:
|
|
356
|
+
os.unlink(self.anonymized_file_path)
|
|
357
|
+
except OSError as e:
|
|
358
|
+
logger.error(
|
|
359
|
+
f"Error removing anonymized file {self.anonymized_file_path}: {e}"
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
self.save() # Save the model to persist the cleared file fields
|
|
363
|
+
|
|
364
|
+
logger.info(f"Files for PDF {self.pk} deleted successfully.")
|
|
365
|
+
return True
|
|
366
|
+
|
|
367
|
+
@classmethod
|
|
368
|
+
def create_from_file_initialized(
|
|
369
|
+
cls,
|
|
370
|
+
file_path: Path,
|
|
371
|
+
center_name: str,
|
|
372
|
+
delete_source: bool = True,
|
|
373
|
+
):
|
|
374
|
+
"""
|
|
375
|
+
Creates a RawPdfFile instance from a file and center name, ensuring an associated RawPdfState exists.
|
|
376
|
+
|
|
377
|
+
Parameters:
|
|
378
|
+
file_path (Path): Path to the source PDF file.
|
|
379
|
+
center_name (str): Name of the center to associate with the PDF.
|
|
380
|
+
delete_source (bool): Whether to delete the source file after processing. Defaults to True.
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
RawPdfFile: The created or retrieved RawPdfFile instance with an associated RawPdfState.
|
|
384
|
+
"""
|
|
385
|
+
raw_pdf = cls.create_from_file(
|
|
386
|
+
file_path=file_path,
|
|
387
|
+
center_name=center_name,
|
|
388
|
+
delete_source=delete_source,
|
|
389
|
+
)
|
|
390
|
+
_state = raw_pdf.get_or_create_state()
|
|
391
|
+
|
|
392
|
+
return raw_pdf
|
|
393
|
+
|
|
394
|
+
@classmethod
|
|
395
|
+
def create_from_file(
|
|
396
|
+
cls,
|
|
397
|
+
file_path: Path,
|
|
398
|
+
center_name,
|
|
399
|
+
save=True, # Parameter kept for compatibility, but save now happens internally
|
|
400
|
+
delete_source=True,
|
|
401
|
+
):
|
|
402
|
+
"""
|
|
403
|
+
Creates or retrieves a RawPdfFile instance from a given PDF file path and center name.
|
|
404
|
+
|
|
405
|
+
If a RawPdfFile with the same PDF hash already exists, verifies the file exists in storage and restores it if missing. Otherwise, creates a new RawPdfFile, assigns the file, and saves it to storage. Optionally deletes the source file after processing.
|
|
406
|
+
|
|
407
|
+
Parameters:
|
|
408
|
+
file_path (Path): Path to the source PDF file.
|
|
409
|
+
center_name (str): Name of the center to associate with the file.
|
|
410
|
+
save (bool, optional): Deprecated; saving occurs internally.
|
|
411
|
+
delete_source (bool, optional): Whether to delete the source file after processing (default True).
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
RawPdfFile: The created or retrieved RawPdfFile instance.
|
|
415
|
+
|
|
416
|
+
Raises:
|
|
417
|
+
FileNotFoundError: If the source file does not exist.
|
|
418
|
+
Center.DoesNotExist: If the specified center is not found.
|
|
419
|
+
ValueError: If the PDF hash cannot be calculated.
|
|
420
|
+
IOError: If the file fails to save to storage.
|
|
421
|
+
"""
|
|
422
|
+
from endoreg_db.models.administration import Center
|
|
423
|
+
|
|
424
|
+
if not file_path.exists():
|
|
425
|
+
logger.error(f"Source file does not exist: {file_path}")
|
|
426
|
+
raise FileNotFoundError(f"Source file not found: {file_path}")
|
|
427
|
+
|
|
428
|
+
# 1. Calculate hash from source file
|
|
429
|
+
try:
|
|
430
|
+
pdf_hash = get_pdf_hash(file_path)
|
|
431
|
+
logger.info(pdf_hash)
|
|
432
|
+
except Exception as e:
|
|
433
|
+
logger.error(f"Could not calculate hash for {file_path}: {e}")
|
|
434
|
+
raise ValueError(f"Could not calculate hash for {file_path}") from e
|
|
435
|
+
|
|
436
|
+
# 2. Check if record with this hash already exists
|
|
437
|
+
existing_pdf_file = cls.objects.filter(pdf_hash=pdf_hash).first()
|
|
438
|
+
if existing_pdf_file:
|
|
439
|
+
logger.warning(
|
|
440
|
+
"RawPdfFile with hash %s already exists (ID: %s)",
|
|
441
|
+
pdf_hash,
|
|
442
|
+
existing_pdf_file.pk,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Verify physical file exists for the existing record
|
|
446
|
+
try:
|
|
447
|
+
if existing_pdf_file is not None and isinstance(existing_pdf_file, cls):
|
|
448
|
+
# Use storage API to check existence
|
|
449
|
+
_file = existing_pdf_file.file
|
|
450
|
+
assert _file is not None
|
|
451
|
+
if not _file.storage.exists(_file.name):
|
|
452
|
+
logger.warning(
|
|
453
|
+
"File for existing RawPdfFile %s not found in storage at %s. Attempting to restore from source %s",
|
|
454
|
+
pdf_hash,
|
|
455
|
+
_file.name,
|
|
456
|
+
file_path,
|
|
457
|
+
)
|
|
458
|
+
# Re-save the file from the source to potentially fix it
|
|
459
|
+
with file_path.open("rb") as f:
|
|
460
|
+
django_file = File(
|
|
461
|
+
f, name=Path(_file.name).name
|
|
462
|
+
) # Use existing name if possible
|
|
463
|
+
existing_pdf_file.file = django_file # type: ignore
|
|
464
|
+
existing_pdf_file.save(
|
|
465
|
+
update_fields=["file"]
|
|
466
|
+
) # Only update file field
|
|
467
|
+
else:
|
|
468
|
+
pass
|
|
469
|
+
# logger.debug("File for existing RawPdfFile %s already exists in storage.", pdf_hash)
|
|
470
|
+
except Exception as e:
|
|
471
|
+
logger.error(
|
|
472
|
+
"Error verifying/restoring file for existing record %s: %s",
|
|
473
|
+
pdf_hash,
|
|
474
|
+
e,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# Delete the source temp file if requested
|
|
478
|
+
if delete_source:
|
|
479
|
+
try:
|
|
480
|
+
file_path.unlink()
|
|
481
|
+
# logger.info("Deleted source file %s after finding existing record.", file_path)
|
|
482
|
+
except OSError as e:
|
|
483
|
+
logger.error("Error deleting source file %s: %s", file_path, e)
|
|
484
|
+
|
|
485
|
+
return existing_pdf_file
|
|
486
|
+
|
|
487
|
+
# --- Create new record if not existing ---
|
|
488
|
+
assert center_name is not None, "center_name is required"
|
|
489
|
+
try:
|
|
490
|
+
center = Center.objects.get(name=center_name)
|
|
491
|
+
except Center.DoesNotExist:
|
|
492
|
+
logger.error(f"Center with name '{center_name}' not found.")
|
|
493
|
+
raise
|
|
494
|
+
|
|
495
|
+
# Generate a unique filename (e.g., using UUID)
|
|
496
|
+
new_file_name, _uuid = get_uuid_filename(file_path)
|
|
497
|
+
logger.info(f"Generated new filename: {new_file_name}")
|
|
498
|
+
|
|
499
|
+
# Create model instance via manager so creation can be intercepted/mocked during tests
|
|
500
|
+
try:
|
|
501
|
+
with file_path.open("rb") as f:
|
|
502
|
+
django_file = File(f, name=new_file_name)
|
|
503
|
+
raw_pdf = cls.objects.create(
|
|
504
|
+
pdf_hash=pdf_hash,
|
|
505
|
+
center=center,
|
|
506
|
+
file=django_file,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
_file = raw_pdf.file
|
|
510
|
+
assert _file is not None
|
|
511
|
+
logger.info(
|
|
512
|
+
"Created and saved new RawPdfFile %s with file %s",
|
|
513
|
+
raw_pdf.pk,
|
|
514
|
+
_file.name,
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
if not _file.storage.exists(_file.name):
|
|
518
|
+
logger.error(
|
|
519
|
+
"File was not saved correctly to storage path %s after model save.",
|
|
520
|
+
_file.name,
|
|
521
|
+
)
|
|
522
|
+
raise IOError(
|
|
523
|
+
f"File not found at expected storage path after save: {_file.name}"
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
try:
|
|
527
|
+
logger.info("File saved to absolute path: %s", _file.path)
|
|
528
|
+
except NotImplementedError:
|
|
529
|
+
logger.info(
|
|
530
|
+
"File saved to storage path: %s (Absolute path not available from storage)",
|
|
531
|
+
_file.name,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
except Exception as e:
|
|
535
|
+
logger.error(
|
|
536
|
+
"Error processing or saving file %s for new record: %s", file_path, e
|
|
537
|
+
)
|
|
538
|
+
raise
|
|
539
|
+
|
|
540
|
+
# Delete source file *after* successful save and verification
|
|
541
|
+
if delete_source:
|
|
542
|
+
try:
|
|
543
|
+
file_path.unlink()
|
|
544
|
+
logger.info(
|
|
545
|
+
"Deleted source file %s after creating new record.", file_path
|
|
546
|
+
)
|
|
547
|
+
except OSError as e:
|
|
548
|
+
logger.error("Error deleting source file %s: %s", file_path, e)
|
|
549
|
+
|
|
550
|
+
# raw_pdf.save() # unnecessary?
|
|
551
|
+
return raw_pdf
|
|
552
|
+
|
|
553
|
+
def save(self, *args, **kwargs):
|
|
554
|
+
# Ensure hash is calculated before the first save if possible and not already set
|
|
555
|
+
# This is primarily a fallback if instance created manually without using create_from_file
|
|
556
|
+
"""
|
|
557
|
+
Saves the RawPdfFile instance, ensuring the PDF hash is set and related fields are derived from metadata.
|
|
558
|
+
|
|
559
|
+
If the PDF hash is missing, attempts to calculate it from the file before saving. Validates that the file has a `.pdf` extension. If related fields such as patient, examination, center, or examiner are unset but available in the associated sensitive metadata, they are populated accordingly before saving.
|
|
560
|
+
"""
|
|
561
|
+
if not self.pk and not self.pdf_hash and self.file:
|
|
562
|
+
try:
|
|
563
|
+
file_path = Path(self.file.path).resolve()
|
|
564
|
+
if not file_path.exists():
|
|
565
|
+
raise FileNotFoundError(f"File path does not exist: {file_path}")
|
|
566
|
+
# Read from the file object before it's saved by storage
|
|
567
|
+
self.file.open("rb") # Ensure file is open
|
|
568
|
+
self.file.seek(0) # Go to beginning
|
|
569
|
+
self.pdf_hash = get_pdf_hash(
|
|
570
|
+
file_path
|
|
571
|
+
) # Assuming get_pdf_hash can handle file obj
|
|
572
|
+
self.file.seek(0) # Reset position
|
|
573
|
+
self.file.close() # Close after reading
|
|
574
|
+
logger.info(f"Calculated hash during pre-save for {self.file.name}")
|
|
575
|
+
except Exception as e:
|
|
576
|
+
logger.warning(
|
|
577
|
+
"Could not calculate hash before initial save for %s: %s",
|
|
578
|
+
self.file.name,
|
|
579
|
+
e,
|
|
580
|
+
)
|
|
581
|
+
# Ensure file is closed if opened
|
|
582
|
+
if hasattr(self.file, "closed") and not self.file.closed:
|
|
583
|
+
self.file.close()
|
|
584
|
+
|
|
585
|
+
if self.file and not self.file.name.endswith(".pdf"):
|
|
586
|
+
raise ValidationError("Only PDF files are allowed")
|
|
587
|
+
|
|
588
|
+
# If hash is still missing after potential creation logic (e.g., direct instantiation)
|
|
589
|
+
# and the file exists in storage, try calculating it from storage path.
|
|
590
|
+
# This is less ideal as it requires the file to be saved first.
|
|
591
|
+
if (
|
|
592
|
+
not self.pdf_hash
|
|
593
|
+
and self.pk
|
|
594
|
+
and self.file
|
|
595
|
+
and self.file.storage.exists(self.file.name)
|
|
596
|
+
):
|
|
597
|
+
try:
|
|
598
|
+
file_path = Path(self.file.path).resolve()
|
|
599
|
+
if not file_path.exists():
|
|
600
|
+
raise FileNotFoundError(f"File path does not exist: {file_path}")
|
|
601
|
+
logger.warning(
|
|
602
|
+
f"Hash missing for saved file {self.file.name}. Recalculating."
|
|
603
|
+
)
|
|
604
|
+
with self.file.storage.open(self.file.name, "rb") as f:
|
|
605
|
+
self.pdf_hash = get_pdf_hash(
|
|
606
|
+
file_path
|
|
607
|
+
) # Assuming get_pdf_hash handles file obj
|
|
608
|
+
# No need to save again just for hash unless update_fields is used carefully
|
|
609
|
+
# Let the main super().save() handle saving the hash if it changed
|
|
610
|
+
except Exception as e:
|
|
611
|
+
logger.error(
|
|
612
|
+
"Could not calculate hash during save for existing file %s: %s",
|
|
613
|
+
self.file.name,
|
|
614
|
+
e,
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
# Derive related fields from sensitive_meta if available
|
|
618
|
+
if not self.patient and self.sensitive_meta:
|
|
619
|
+
self.patient = self.sensitive_meta.pseudo_patient
|
|
620
|
+
if not self.examination and self.sensitive_meta:
|
|
621
|
+
self.examination = self.sensitive_meta.pseudo_examination
|
|
622
|
+
if not self.center and self.sensitive_meta:
|
|
623
|
+
self.center = self.sensitive_meta.center
|
|
624
|
+
# TODO Outdated?
|
|
625
|
+
# if not self.examiner and self.sensitive_meta and hasattr(self.sensitive_meta, 'pseudo_examiner'):
|
|
626
|
+
# self.examiner = self.sensitive_meta.pseudo_examiner
|
|
627
|
+
|
|
628
|
+
super().save(*args, **kwargs)
|
|
629
|
+
|
|
630
|
+
def get_or_create_state(self) -> "RawPdfState":
|
|
631
|
+
"""
|
|
632
|
+
Retrieve the associated RawPdfState for this RawPdfFile, creating and linking a new one if none exists.
|
|
633
|
+
|
|
634
|
+
Returns:
|
|
635
|
+
RawPdfState: The existing or newly created RawPdfState instance linked to this RawPdfFile.
|
|
636
|
+
"""
|
|
637
|
+
from endoreg_db.models.state import RawPdfState
|
|
638
|
+
|
|
639
|
+
if self.state:
|
|
640
|
+
return self.state
|
|
641
|
+
|
|
642
|
+
# Create a new RawPdfState instance directly and assign it
|
|
643
|
+
state = RawPdfState()
|
|
644
|
+
state.save()
|
|
645
|
+
self.state = state
|
|
646
|
+
self.save(update_fields=["state"]) # Save the RawPdfFile to link the state
|
|
647
|
+
logger.info("Created new RawPdfState for RawPdfFile %s", self.pk)
|
|
648
|
+
return state
|
|
649
|
+
|
|
650
|
+
def verify_existing_file(self, fallback_file):
|
|
651
|
+
# This method might still be useful if called explicitly, but create_from_file now handles restoration
|
|
652
|
+
# Ensure fallback_file is a Path object.
|
|
653
|
+
"""
|
|
654
|
+
Checks if the stored PDF file exists in storage and attempts to restore it from a fallback file path if missing.
|
|
655
|
+
|
|
656
|
+
Parameters:
|
|
657
|
+
fallback_file: Path or string representing the fallback file location to restore from if the stored file is missing.
|
|
658
|
+
"""
|
|
659
|
+
if not isinstance(fallback_file, Path):
|
|
660
|
+
fallback_file = Path(fallback_file)
|
|
661
|
+
|
|
662
|
+
_file = self.file
|
|
663
|
+
assert _file is not None
|
|
664
|
+
try:
|
|
665
|
+
if not _file.field.storage.exists(_file.name):
|
|
666
|
+
logger.warning(
|
|
667
|
+
f"File missing at storage path {_file.name}. Attempting copy from fallback {fallback_file}"
|
|
668
|
+
)
|
|
669
|
+
if fallback_file.exists():
|
|
670
|
+
with fallback_file.open("rb") as f:
|
|
671
|
+
# Use save method which handles storage backend
|
|
672
|
+
_file.save(
|
|
673
|
+
Path(_file.name).name, File(f), save=True
|
|
674
|
+
) # Re-save the file content
|
|
675
|
+
logger.info(
|
|
676
|
+
f"Successfully restored file from fallback {fallback_file} to {_file.name}"
|
|
677
|
+
)
|
|
678
|
+
else:
|
|
679
|
+
logger.error(f"Fallback file {fallback_file} does not exist.")
|
|
680
|
+
except Exception as e:
|
|
681
|
+
logger.error(f"Error during verify_existing_file for {_file.name}: {e}")
|
|
682
|
+
|
|
683
|
+
def process_file(self, text, anonymized_text, report_meta, verbose):
|
|
684
|
+
self.text = text
|
|
685
|
+
self.anonymized_text = anonymized_text
|
|
686
|
+
|
|
687
|
+
assert self.center is not None, "Center must be set before processing file"
|
|
688
|
+
|
|
689
|
+
report_meta["center_name"] = self.center.name
|
|
690
|
+
if not self.sensitive_meta:
|
|
691
|
+
# Pass the original report_meta with date objects to SensitiveMeta logic
|
|
692
|
+
sensitive_meta = SensitiveMeta.create_from_dict(report_meta)
|
|
693
|
+
self.sensitive_meta = sensitive_meta
|
|
694
|
+
else:
|
|
695
|
+
sensitive_meta = self.sensitive_meta
|
|
696
|
+
# Pass the original report_meta with date objects to SensitiveMeta logic
|
|
697
|
+
sensitive_meta.update_from_dict(report_meta)
|
|
698
|
+
|
|
699
|
+
# For storing in raw_meta (JSONField), dates need to be strings.
|
|
700
|
+
# Create a serializable version of report_meta for raw_meta.
|
|
701
|
+
import copy
|
|
702
|
+
from datetime import date, datetime
|
|
703
|
+
|
|
704
|
+
serializable_report_meta = copy.deepcopy(report_meta)
|
|
705
|
+
for key, value in serializable_report_meta.items():
|
|
706
|
+
if isinstance(value, (datetime, date)):
|
|
707
|
+
serializable_report_meta[key] = value.isoformat()
|
|
708
|
+
|
|
709
|
+
self.raw_meta = serializable_report_meta # Assign the version with string dates
|
|
710
|
+
|
|
711
|
+
sensitive_meta.save() # Save SensitiveMeta first
|
|
712
|
+
self.save() # Then save RawPdfFile
|
|
713
|
+
|
|
714
|
+
return text, anonymized_text, report_meta
|
|
715
|
+
|
|
716
|
+
def get_report_reader_config(self):
|
|
717
|
+
from warnings import warn
|
|
718
|
+
|
|
719
|
+
from ...administration import Center
|
|
720
|
+
from ...metadata.pdf_meta import PdfType
|
|
721
|
+
|
|
722
|
+
_center = self.center
|
|
723
|
+
assert _center is not None, "Center must be set to get report reader config"
|
|
724
|
+
|
|
725
|
+
if not self.pdf_type:
|
|
726
|
+
warn("PdfType not set, using default settings")
|
|
727
|
+
pdf_type = PdfType.default_pdf_type()
|
|
728
|
+
else:
|
|
729
|
+
pdf_type: PdfType = self.pdf_type
|
|
730
|
+
center: Center = _center
|
|
731
|
+
if pdf_type.endoscope_info_line:
|
|
732
|
+
endoscope_info_line = pdf_type.endoscope_info_line.value
|
|
733
|
+
|
|
734
|
+
else:
|
|
735
|
+
endoscope_info_line = None
|
|
736
|
+
settings_dict = {
|
|
737
|
+
"locale": "de_DE",
|
|
738
|
+
"employee_first_names": [_.name for _ in center.first_names.all()],
|
|
739
|
+
"employee_last_names": [_.name for _ in center.last_names.all()],
|
|
740
|
+
"text_date_format": "%d.%m.%Y",
|
|
741
|
+
"flags": {
|
|
742
|
+
"patient_info_line": pdf_type.patient_info_line.value,
|
|
743
|
+
"endoscope_info_line": endoscope_info_line,
|
|
744
|
+
"examiner_info_line": pdf_type.examiner_info_line.value,
|
|
745
|
+
"cut_off_below": [_.value for _ in pdf_type.cut_off_below_lines.all()],
|
|
746
|
+
"cut_off_above": [_.value for _ in pdf_type.cut_off_above_lines.all()],
|
|
747
|
+
},
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return settings_dict
|
|
751
|
+
|
|
752
|
+
@staticmethod
|
|
753
|
+
def get_pdf_by_id(pdf_id: int) -> "RawPdfFile":
|
|
754
|
+
try:
|
|
755
|
+
return RawPdfFile.objects.get(pk=pdf_id)
|
|
756
|
+
except RawPdfFile.DoesNotExist:
|
|
757
|
+
raise ValueError(f"PDF with ID {pdf_id} does not exist.")
|