endoreg-db 0.8.5.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/__init__.py +0 -0
- endoreg_db/admin.py +92 -0
- endoreg_db/api/serializers/finding_descriptions.py +0 -0
- endoreg_db/api/views/finding_descriptions.py +0 -0
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +18 -0
- 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/__init__.py +0 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +144 -0
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/ai_model_label/label/data.yaml +88 -0
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_type/data.yaml +7 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
- endoreg_db/data/case_template/rule_value/.init +0 -0
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
- endoreg_db/data/case_template/template/base.yaml +8 -0
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
- endoreg_db/data/case_template/tmp/_rule_value +13 -0
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
- endoreg_db/data/center/data.yaml +91 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +5 -0
- endoreg_db/data/disease/renal.yaml +5 -0
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
- endoreg_db/data/distribution/date/patient.yaml +7 -0
- endoreg_db/data/distribution/multiple_categorical/.init +0 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +11 -0
- endoreg_db/data/endoscopy_processor/data.yaml +50 -0
- endoreg_db/data/event/cardiology.yaml +15 -0
- endoreg_db/data/event/neurology.yaml +14 -0
- endoreg_db/data/event/surgery.yaml +13 -0
- endoreg_db/data/event/thrombembolism.yaml +20 -0
- endoreg_db/data/examination/examinations/data.yaml +72 -0
- endoreg_db/data/examination/time/data.yaml +48 -0
- endoreg_db/data/examination/time-type/data.yaml +8 -0
- endoreg_db/data/examination/type/data.yaml +17 -0
- 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 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +6 -0
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +37 -0
- endoreg_db/data/lab_value/coagulation.yaml +54 -0
- endoreg_db/data/lab_value/electrolytes.yaml +228 -0
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -0
- endoreg_db/data/lab_value/hematology.yaml +184 -0
- endoreg_db/data/lab_value/hormones.yaml +59 -0
- endoreg_db/data/lab_value/lipids.yaml +53 -0
- endoreg_db/data/lab_value/misc.yaml +76 -0
- endoreg_db/data/lab_value/renal_function.yaml +12 -0
- endoreg_db/data/log_type/data.yaml +57 -0
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/material/material.yaml +91 -0
- endoreg_db/data/medication/anticoagulation.yaml +65 -0
- endoreg_db/data/medication/tah.yaml +70 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -0
- endoreg_db/data/medication_indication_type/data.yaml +11 -0
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
- endoreg_db/data/medication_intake_time/base.yaml +31 -0
- endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
- endoreg_db/data/medication_schedule/ass.yaml +12 -0
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +59 -0
- endoreg_db/data/network_device_type/data.yaml +12 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
- endoreg_db/data/pdf_type/data.yaml +46 -0
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
- endoreg_db/data/profession/data.yaml +70 -0
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -0
- endoreg_db/data/requirement/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 -0
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift/m2.yaml +0 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
- endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
- endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
- endoreg_db/data/unit/concentration.yaml +115 -0
- endoreg_db/data/unit/data.yaml +17 -0
- endoreg_db/data/unit/length.yaml +31 -0
- endoreg_db/data/unit/misc.yaml +20 -0
- endoreg_db/data/unit/rate.yaml +6 -0
- endoreg_db/data/unit/time.yaml +48 -0
- endoreg_db/data/unit/volume.yaml +35 -0
- endoreg_db/data/unit/weight.yaml +38 -0
- endoreg_db/data/waste/data.yaml +12 -0
- endoreg_db/exceptions.py +19 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +5 -0
- 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 -0
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -0
- endoreg_db/forms/settings/__init__.py +8 -0
- endoreg_db/forms/unit.py +6 -0
- 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 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +192 -0
- endoreg_db/management/commands/load_center_data.py +68 -0
- endoreg_db/management/commands/load_contraindication_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_choices_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_data.py +41 -0
- endoreg_db/management/commands/load_disease_data.py +62 -0
- endoreg_db/management/commands/load_distribution_data.py +66 -0
- endoreg_db/management/commands/load_endoscope_data.py +68 -0
- endoreg_db/management/commands/load_event_data.py +41 -0
- endoreg_db/management/commands/load_examination_data.py +75 -0
- 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 +44 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +132 -0
- endoreg_db/management/commands/load_information_source.py +51 -0
- endoreg_db/management/commands/load_lab_value_data.py +50 -0
- endoreg_db/management/commands/load_medication_data.py +103 -0
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/load_organ_data.py +43 -0
- endoreg_db/management/commands/load_pdf_type_data.py +61 -0
- endoreg_db/management/commands/load_profession_data.py +44 -0
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/load_report_reader_flag_data.py +46 -0
- 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 +46 -0
- endoreg_db/management/commands/load_user_groups.py +28 -0
- endoreg_db/management/commands/register_ai_model.py +64 -0
- endoreg_db/management/commands/reset_celery_schedule.py +9 -0
- 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 -0
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +359 -0
- 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/administration/ai/model_type.py +41 -0
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/administration/case/case_template/__init__.py +15 -0
- endoreg_db/models/administration/case/case_template/case_template.py +125 -0
- endoreg_db/models/administration/case/case_template/case_template_rule.py +269 -0
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +86 -0
- endoreg_db/models/administration/case/case_template/case_template_type.py +26 -0
- endoreg_db/models/administration/center/__init__.py +13 -0
- 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/administration/person/names/first_name.py +18 -0
- endoreg_db/models/administration/person/names/last_name.py +19 -0
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/administration/person/person.py +31 -0
- 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/administration/product/product_weight.py +47 -0
- endoreg_db/models/administration/product/reference_product.py +130 -0
- 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 -0
- 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 -0
- 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 +613 -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/media/pdf/report_reader/report_reader_flag.py +20 -0
- 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 +699 -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/medical/hardware/endoscopy_processor.py +182 -0
- 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/medical/patient/patient_lab_value.py +222 -0
- 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/metadata/pdf_meta.py +89 -0
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +730 -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 -0
- 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/other/gender.py +27 -0
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +28 -0
- endoreg_db/models/other/resource.py +22 -0
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +33 -0
- endoreg_db/models/other/unit.py +32 -0
- endoreg_db/models/other/waste.py +27 -0
- 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/rule/rule.py +27 -0
- endoreg_db/models/rule/rule_applicator.py +224 -0
- endoreg_db/models/rule/rule_attribute_dtype.py +17 -0
- endoreg_db/models/rule/rule_type.py +20 -0
- endoreg_db/models/rule/ruleset.py +17 -0
- 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 +5 -0
- endoreg_db/queries/annotations/__init__.py +3 -0
- endoreg_db/queries/annotations/legacy.py +158 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- 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 +147 -0
- 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 +152 -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/misc/vop_patient_data.py +120 -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/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 +241 -0
- endoreg_db/services/lookup_store.py +122 -0
- endoreg_db/services/pdf_import.py +1159 -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 +1258 -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 +70 -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 +44 -0
- endoreg_db/urls/media.py +226 -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 -0
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/utils/ai/get.py +5 -0
- 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 +29 -0
- endoreg_db/utils/dataloader.py +175 -0
- 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 -0
- 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 -0
- 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 -0
- 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 -0
- 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 +272 -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 +386 -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 +11 -0
- endoreg_db/views/pdf/pdf_media.py +239 -0
- endoreg_db/views/pdf/pdf_stream_views.py +127 -0
- endoreg_db/views/pdf/reimport.py +161 -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 +483 -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 +61 -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 +329 -0
- endoreg_db/views/video/video_media.py +158 -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 -0
- endoreg_db-0.8.5.1.dist-info/METADATA +383 -0
- endoreg_db-0.8.5.1.dist-info/RECORD +794 -0
- endoreg_db-0.8.5.1.dist-info/WHEEL +4 -0
- endoreg_db-0.8.5.1.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# endoreg_db/services/anonymization.py
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from django.db import transaction
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from endoreg_db.models import VideoFile, RawPdfFile
|
|
6
|
+
from endoreg_db.services.video_import import VideoImportService
|
|
7
|
+
from endoreg_db.services.pdf_import import PdfImportService
|
|
8
|
+
from endoreg_db.utils.paths import STORAGE_DIR
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class AnonymizationService:
|
|
14
|
+
"""
|
|
15
|
+
Orchestrates long‑running anonymization tasks so the view only
|
|
16
|
+
does HTTP <-> Service translation.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, project_root: Path = None):
|
|
20
|
+
"""
|
|
21
|
+
Initialize the AnonymizationService with service instances.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
project_root: Path to the project root. If None, uses settings.BASE_DIR
|
|
25
|
+
"""
|
|
26
|
+
if project_root is None:
|
|
27
|
+
project_root = STORAGE_DIR
|
|
28
|
+
|
|
29
|
+
self.video_service = VideoImportService()
|
|
30
|
+
self.pdf_service = PdfImportService()
|
|
31
|
+
|
|
32
|
+
# ---------- READ ----------------------------------------------------
|
|
33
|
+
@staticmethod
|
|
34
|
+
def get_status(file_id: int):
|
|
35
|
+
"""
|
|
36
|
+
Retrieve the anonymization status and media type for a file by its ID.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
dict or None: A dictionary containing the file's media type and anonymization status if found, or None if no matching file exists.
|
|
40
|
+
"""
|
|
41
|
+
vf = VideoFile.objects.select_related("state", "sensitive_meta").filter(pk=file_id).first()
|
|
42
|
+
if vf:
|
|
43
|
+
return {
|
|
44
|
+
"mediaType": "video",
|
|
45
|
+
"anonymizationStatus": vf.state.anonymization_status if vf.state else "not_started",
|
|
46
|
+
"fileExists": bool(vf.raw_file and hasattr(vf.raw_file, 'path')),
|
|
47
|
+
"uuid": str(vf.uuid) if vf.uuid else None,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pdf = RawPdfFile.objects.select_related("state", "sensitive_meta").filter(pk=file_id).first()
|
|
51
|
+
if pdf:
|
|
52
|
+
return {
|
|
53
|
+
"mediaType": "pdf",
|
|
54
|
+
"anonymizationStatus": pdf.state.anonymization_status if pdf.state else "not_started",
|
|
55
|
+
"fileExists": bool(pdf.file and hasattr(pdf.file, 'path')),
|
|
56
|
+
"hash": pdf.pdf_hash,
|
|
57
|
+
}
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
# ---------- COMMANDS ------------------------------------------------
|
|
61
|
+
@transaction.atomic
|
|
62
|
+
def start(self, file_id: int):
|
|
63
|
+
"""
|
|
64
|
+
Start anonymization process for a file by its ID.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
file_id: The ID of the file to anonymize
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
str or None: Media type if successful, None if file not found
|
|
71
|
+
"""
|
|
72
|
+
# Try VideoFile first
|
|
73
|
+
vf = VideoFile.objects.select_related("state", "sensitive_meta", "center", "video_meta__processor").filter(pk=file_id).first()
|
|
74
|
+
if vf:
|
|
75
|
+
try:
|
|
76
|
+
logger.info(f"Starting video anonymization for VideoFile ID: {file_id}")
|
|
77
|
+
|
|
78
|
+
# Check if already processed
|
|
79
|
+
if vf.state and vf.state.anonymized:
|
|
80
|
+
logger.info(f"VideoFile {file_id} already anonymized, skipping")
|
|
81
|
+
return "video"
|
|
82
|
+
|
|
83
|
+
# Get file path
|
|
84
|
+
file_path = vf.get_raw_file_path()
|
|
85
|
+
if not file_path or not Path(file_path).exists():
|
|
86
|
+
logger.error(f"Raw file not found for VideoFile {file_id}: {file_path}")
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
# Get processor name
|
|
90
|
+
processor_name = None
|
|
91
|
+
if vf.video_meta and vf.video_meta.processor:
|
|
92
|
+
processor_name = vf.video_meta.processor.name
|
|
93
|
+
elif hasattr(vf, 'processor') and vf.processor:
|
|
94
|
+
processor_name = vf.processor.name
|
|
95
|
+
|
|
96
|
+
# Get center name
|
|
97
|
+
center_name = vf.center.name if vf.center else "unknown_center"
|
|
98
|
+
|
|
99
|
+
# Mark as started
|
|
100
|
+
if vf.state:
|
|
101
|
+
vf.state.processing_started = True
|
|
102
|
+
vf.state.save(update_fields=["processing_started"])
|
|
103
|
+
|
|
104
|
+
# Use VideoImportService for anonymization
|
|
105
|
+
self.video_service.import_and_anonymize(
|
|
106
|
+
file_path=file_path,
|
|
107
|
+
center_name=center_name,
|
|
108
|
+
processor_name=processor_name,
|
|
109
|
+
save_video=True,
|
|
110
|
+
delete_source=False
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
logger.info(f"Video anonymization completed for VideoFile ID: {file_id}")
|
|
114
|
+
return "video"
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(f"Failed to anonymize VideoFile {file_id}: {e}")
|
|
118
|
+
# Mark as failed if state exists
|
|
119
|
+
if vf.state:
|
|
120
|
+
vf.state.processing_started = False # Mark processing as not started due to failure
|
|
121
|
+
vf.state.save(update_fields=["processing_started"])
|
|
122
|
+
raise
|
|
123
|
+
|
|
124
|
+
# Try RawPdfFile
|
|
125
|
+
pdf = RawPdfFile.objects.select_related("state", "sensitive_meta", "center").filter(pk=file_id).first()
|
|
126
|
+
if pdf:
|
|
127
|
+
try:
|
|
128
|
+
logger.info(f"Starting PDF processing for RawPdfFile ID: {file_id}")
|
|
129
|
+
|
|
130
|
+
# Check if already processed
|
|
131
|
+
if pdf.state and getattr(pdf.state, 'anonymized', False):
|
|
132
|
+
logger.info(f"RawPdfFile {file_id} already processed, skipping")
|
|
133
|
+
return "pdf"
|
|
134
|
+
|
|
135
|
+
# Get file path
|
|
136
|
+
if not pdf.file or not hasattr(pdf.file, 'path'):
|
|
137
|
+
logger.error(f"PDF file not found for RawPdfFile {file_id}")
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
file_path = Path(pdf.file.path)
|
|
141
|
+
if not file_path.exists():
|
|
142
|
+
logger.error(f"PDF file does not exist: {file_path}")
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
# Get center name
|
|
146
|
+
center_name = pdf.center.name if pdf.center else "unknown_center"
|
|
147
|
+
|
|
148
|
+
# Mark as started
|
|
149
|
+
if pdf.state:
|
|
150
|
+
pdf.state.processing_started = True
|
|
151
|
+
pdf.state.save(update_fields=["processing_started"])
|
|
152
|
+
elif pdf.sensitive_meta:
|
|
153
|
+
pdf.sensitive_meta.anonymization_started = True
|
|
154
|
+
pdf.sensitive_meta.save(update_fields=["anonymization_started"])
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# Use PdfImportService for processing
|
|
158
|
+
# Use PdfImportService for processing
|
|
159
|
+
self.pdf_service.import_and_anonymize(
|
|
160
|
+
file_path=file_path,
|
|
161
|
+
center_name=center_name,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
logger.info(f"PDF processing completed for RawPdfFile ID: {file_id}")
|
|
165
|
+
return "pdf"
|
|
166
|
+
|
|
167
|
+
except Exception as e:
|
|
168
|
+
logger.error(f"Failed to process RawPdfFile {file_id}: {e}")
|
|
169
|
+
# Mark as failed if state exists
|
|
170
|
+
if pdf.state:
|
|
171
|
+
pdf.state.processing_failed = True
|
|
172
|
+
pdf.state.save(update_fields=["processing_failed"])
|
|
173
|
+
elif pdf.sensitive_meta:
|
|
174
|
+
pdf.sensitive_meta.processing_failed = True
|
|
175
|
+
pdf.sensitive_meta.save(update_fields=["processing_failed"])
|
|
176
|
+
raise
|
|
177
|
+
|
|
178
|
+
logger.warning(f"No file found with ID: {file_id}")
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
@transaction.atomic
|
|
183
|
+
def validate(file_id: int):
|
|
184
|
+
vf = VideoFile.objects.select_related("state").filter(pk=file_id).first()
|
|
185
|
+
if vf:
|
|
186
|
+
vf.state.mark_anonymization_validated()
|
|
187
|
+
return "video"
|
|
188
|
+
|
|
189
|
+
pdf = RawPdfFile.objects.select_related("state").filter(pk=file_id).first()
|
|
190
|
+
if pdf:
|
|
191
|
+
pdf.state.mark_anonymization_validated()
|
|
192
|
+
return "pdf"
|
|
193
|
+
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
def list_items():
|
|
197
|
+
video_files = VideoFile.objects.select_related("state").all()
|
|
198
|
+
pdf_files = RawPdfFile.objects.select_related("state").all() # was sensitive_meta
|
|
199
|
+
|
|
200
|
+
data = []
|
|
201
|
+
for vf in video_files:
|
|
202
|
+
data.append({
|
|
203
|
+
"id": vf.id,
|
|
204
|
+
"mediaType": "video",
|
|
205
|
+
"anonymizationStatus": vf.state.anonymization_status if vf.state else "not_started",
|
|
206
|
+
"createdAt": vf.date_created,
|
|
207
|
+
"updatedAt": vf.date_modified,
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
for pdf in pdf_files:
|
|
213
|
+
data.append({
|
|
214
|
+
"id": pdf.id,
|
|
215
|
+
"mediaType": "pdf",
|
|
216
|
+
"anonymizationStatus": pdf.state.anonymization_status if pdf.state else "not_started",
|
|
217
|
+
"createdAt": pdf.date_created,
|
|
218
|
+
"updatedAt": pdf.date_modified,
|
|
219
|
+
})
|
|
220
|
+
return data
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
return data
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# app/services/evaluation.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import Dict, List, Set, Tuple
|
|
4
|
+
from django.db.models import Prefetch
|
|
5
|
+
|
|
6
|
+
from endoreg_db.schemas.examination_evaluation import ExaminationEvalReport, RequirementSetEval, RequirementEval
|
|
7
|
+
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
8
|
+
from endoreg_db.models.requirement.requirement_set import RequirementSet
|
|
9
|
+
import endoreg_db.services.lookup_service
|
|
10
|
+
|
|
11
|
+
def _get_requirement_sets_for_exam(exam: PatientExamination) -> List[RequirementSet]:
|
|
12
|
+
"""
|
|
13
|
+
Decide how an examination maps to requirement sets.
|
|
14
|
+
Adjust this to your actual relation:
|
|
15
|
+
- maybe exam.type.requirement_sets
|
|
16
|
+
- or via information_sources
|
|
17
|
+
- or a direct M2M on Examination
|
|
18
|
+
"""
|
|
19
|
+
# The new loader prefetches via `examination.exam_reqset_links`.
|
|
20
|
+
# We extract the RequirementSet from each link.
|
|
21
|
+
sets = []
|
|
22
|
+
if hasattr(exam, "examination") and hasattr(exam.examination, "exam_reqset_links"):
|
|
23
|
+
for link in exam.examination.exam_reqset_links.all():
|
|
24
|
+
if hasattr(link, "requirement_set"):
|
|
25
|
+
sets.append(link.requirement_set)
|
|
26
|
+
return sets
|
|
27
|
+
|
|
28
|
+
def _eval_requirement(requirement, input_object, mode="loose") -> Tuple[bool, str | None]:
|
|
29
|
+
"""
|
|
30
|
+
Evaluate a single Requirement and return (bool, message).
|
|
31
|
+
The `message` can be None or contain a short explanation.
|
|
32
|
+
"""
|
|
33
|
+
ok = requirement.evaluate(input_object, mode=mode)
|
|
34
|
+
msg = None
|
|
35
|
+
# If your Requirement has a reason/explanation API, inject it here.
|
|
36
|
+
# Example: msg = requirement.last_reason if hasattr(requirement, "last_reason") else None
|
|
37
|
+
return ok, msg
|
|
38
|
+
|
|
39
|
+
def _reduce_bools(bools: List[bool], set_type_name: str | None) -> bool:
|
|
40
|
+
from endoreg_db.models.requirement.requirement_set import REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP
|
|
41
|
+
func = REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP.get(set_type_name or "all", all)
|
|
42
|
+
return bool(func(bools))
|
|
43
|
+
|
|
44
|
+
def _eval_set_tree(root: RequirementSet, input_object, visited: Set[int]) -> RequirementSetEval:
|
|
45
|
+
"""
|
|
46
|
+
Recursively evaluate a RequirementSet node and linked children.
|
|
47
|
+
Protect against cycles with visited set.
|
|
48
|
+
"""
|
|
49
|
+
if root.pk in visited:
|
|
50
|
+
# Cycle detected -> treat as already evaluated (neutral element for AND is True; but better: skip node)
|
|
51
|
+
# We skip to avoid infinite recursion; AND/OR exact treatment depends on your business semantics.
|
|
52
|
+
return RequirementSetEval(
|
|
53
|
+
id=root.pk,
|
|
54
|
+
name=root.name,
|
|
55
|
+
type=(root.requirement_set_type.name if root.requirement_set_type else None),
|
|
56
|
+
is_satisfied=True,
|
|
57
|
+
requirements=[],
|
|
58
|
+
linked_sets=[]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
visited.add(root.pk)
|
|
62
|
+
|
|
63
|
+
# Evaluate direct requirements
|
|
64
|
+
req_evals: List[RequirementEval] = []
|
|
65
|
+
for r in root.requirements.all():
|
|
66
|
+
ok, msg = _eval_requirement(r, input_object)
|
|
67
|
+
req_evals.append(
|
|
68
|
+
RequirementEval(
|
|
69
|
+
id=r.pk,
|
|
70
|
+
name=getattr(r, "name", f"Requirement {r.pk}"),
|
|
71
|
+
description=getattr(r, "description", None),
|
|
72
|
+
satisfied=ok,
|
|
73
|
+
message=msg,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Evaluate linked sets
|
|
78
|
+
child_evals: List[RequirementSetEval] = []
|
|
79
|
+
for child in root.links_to_sets.all():
|
|
80
|
+
child_evals.append(_eval_set_tree(child, input_object, visited))
|
|
81
|
+
|
|
82
|
+
# Combine booleans
|
|
83
|
+
bools = [re.satisfied for re in req_evals] + [ce.is_satisfied for ce in child_evals]
|
|
84
|
+
set_type_name = root.requirement_set_type.name if root.requirement_set_type else "all"
|
|
85
|
+
satisfied = _reduce_bools(bools, set_type_name)
|
|
86
|
+
|
|
87
|
+
return RequirementSetEval(
|
|
88
|
+
id=root.pk,
|
|
89
|
+
name=root.name,
|
|
90
|
+
type=set_type_name,
|
|
91
|
+
is_satisfied=satisfied,
|
|
92
|
+
requirements=req_evals,
|
|
93
|
+
linked_sets=child_evals,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def evaluate_examination(request: dict) -> ExaminationEvalReport:
|
|
99
|
+
"""
|
|
100
|
+
Communicates with: components/RequirementGenerator
|
|
101
|
+
Evaluates a PatientExamination by its Lookup. The frontend sends this structure:
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
requirement_set_ids: plainRequirementSetIds,
|
|
105
|
+
lookup_token: lookupToken,
|
|
106
|
+
patient_examination_id: patientExaminationId
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
And expects a response to be processed like this:
|
|
110
|
+
|
|
111
|
+
const response = await axiosInstance.post('/api/evaluate-requirements/', payload);
|
|
112
|
+
const results = response.data.results || [];
|
|
113
|
+
const summary = response.data.summary || {};
|
|
114
|
+
|
|
115
|
+
// Update evaluation results
|
|
116
|
+
plainRequirementSetIds.forEach((setId: number) => {
|
|
117
|
+
evaluationResults.value[setId] = results.filter((r: RequirementEvaluationResult) =>
|
|
118
|
+
summary[setId]?.requirements.includes(r.requirement_name)
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
"""
|
|
122
|
+
exam_id = request.get("patient_examination_id")
|
|
123
|
+
if not exam_id:
|
|
124
|
+
return ExaminationEvalReport(
|
|
125
|
+
examination_id=None,
|
|
126
|
+
summary={"is_satisfied": True, "failed_count": 0, "total_sets": 0},
|
|
127
|
+
sets=[],
|
|
128
|
+
errors=["No patient_examination_id provided in request."]
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Use the dedicated loader function from the lookup service.
|
|
132
|
+
exam = endoreg_db.services.lookup_service.load_patient_exam_for_eval(pk=exam_id)
|
|
133
|
+
|
|
134
|
+
# This object (exam) is the "input_object" for requirement.evaluate(...)
|
|
135
|
+
sets = _get_requirement_sets_for_exam(exam)
|
|
136
|
+
|
|
137
|
+
visited: Set[int] = set()
|
|
138
|
+
set_evals: List[RequirementSetEval] = [_eval_set_tree(s, exam, visited) for s in sets]
|
|
139
|
+
|
|
140
|
+
# Aggregate summary
|
|
141
|
+
overall = all(se.is_satisfied for se in set_evals) if set_evals else True
|
|
142
|
+
failed = sum(1 for se in set_evals if not se.is_satisfied)
|
|
143
|
+
|
|
144
|
+
return ExaminationEvalReport(
|
|
145
|
+
examination_id=exam.pk,
|
|
146
|
+
summary={"is_satisfied": overall, "failed_count": failed, "total_sets": len(set_evals)},
|
|
147
|
+
sets=set_evals,
|
|
148
|
+
errors=[], # fill with any global issues you detect
|
|
149
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# services/lookup_service.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import Dict, Any, List
|
|
4
|
+
from django.db.models import Prefetch
|
|
5
|
+
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
6
|
+
from endoreg_db.models.medical.examination import ExaminationRequirementSet
|
|
7
|
+
from endoreg_db.models.requirement.requirement_set import RequirementSet
|
|
8
|
+
from .lookup_store import LookupStore
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_patient_exam_for_eval(pk: int) -> PatientExamination:
|
|
12
|
+
"""
|
|
13
|
+
Fetch PatientExamination with everything needed for evaluation,
|
|
14
|
+
following the *Examination → ExaminationRequirementSet → RequirementSet* graph.
|
|
15
|
+
"""
|
|
16
|
+
return (
|
|
17
|
+
PatientExamination.objects
|
|
18
|
+
.select_related("patient", "examination")
|
|
19
|
+
.prefetch_related(
|
|
20
|
+
"patient_findings",
|
|
21
|
+
# Prefetch ERS groups on the Examination…
|
|
22
|
+
Prefetch(
|
|
23
|
+
"examination__exam_reqset_links",
|
|
24
|
+
queryset=ExaminationRequirementSet.objects.only("id", "name", "enabled_by_default"),
|
|
25
|
+
),
|
|
26
|
+
# …and the RequirementSets reachable via those ERS groups.
|
|
27
|
+
Prefetch(
|
|
28
|
+
"examination__exam_reqset_links__requirement_set",
|
|
29
|
+
queryset=(
|
|
30
|
+
RequirementSet.objects
|
|
31
|
+
.select_related("requirement_set_type")
|
|
32
|
+
.prefetch_related(
|
|
33
|
+
"requirements",
|
|
34
|
+
"links_to_sets",
|
|
35
|
+
"links_to_sets__requirements",
|
|
36
|
+
"links_to_sets__requirement_set_type",
|
|
37
|
+
)
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
.get(pk=pk)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def requirement_sets_for_patient_exam(pe: PatientExamination) -> List[RequirementSet]:
|
|
46
|
+
"""
|
|
47
|
+
Correctly resolve RequirementSets for a PE via ERS hub:
|
|
48
|
+
RequirementSet.objects.filter(reqset_exam_links__examinations=exam)
|
|
49
|
+
"""
|
|
50
|
+
exam = pe.examination
|
|
51
|
+
if not exam:
|
|
52
|
+
return []
|
|
53
|
+
return list(
|
|
54
|
+
RequirementSet.objects
|
|
55
|
+
.filter(reqset_exam_links__examinations=exam)
|
|
56
|
+
.select_related("requirement_set_type")
|
|
57
|
+
.prefetch_related("requirements")
|
|
58
|
+
.distinct()
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
|
|
62
|
+
"""
|
|
63
|
+
Build the initial lookup dict you will return to the client.
|
|
64
|
+
Keep keys small and stable; values must be JSON-serializable.
|
|
65
|
+
"""
|
|
66
|
+
# Available + required findings
|
|
67
|
+
available_findings = [f.id for f in pe.examination.get_available_findings()] if pe.examination else []
|
|
68
|
+
required_findings: List[int] = [] # fill by scanning requirements below
|
|
69
|
+
|
|
70
|
+
# Requirement sets: ids + meta
|
|
71
|
+
rs_objs = requirement_sets_for_patient_exam(pe)
|
|
72
|
+
requirement_sets = [
|
|
73
|
+
{
|
|
74
|
+
"id": rs.id,
|
|
75
|
+
"name": rs.name,
|
|
76
|
+
"type": rs.requirement_set_type.name if rs.requirement_set_type else "all",
|
|
77
|
+
}
|
|
78
|
+
for rs in rs_objs
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# Requirement-level defaults and classification choices (skeleton)
|
|
82
|
+
# You said: each Requirement can provide default findings and addable choices
|
|
83
|
+
req_defaults: Dict[str, Any] = {}
|
|
84
|
+
cls_choices: Dict[str, Any] = {}
|
|
85
|
+
|
|
86
|
+
for rs in rs_objs:
|
|
87
|
+
for req in rs.requirements.all():
|
|
88
|
+
# You’ll implement these helpers on Requirement
|
|
89
|
+
defaults = getattr(req, "default_findings", lambda pe: [])(pe)
|
|
90
|
+
choices = getattr(req, "classification_choices", lambda pe: [])(pe)
|
|
91
|
+
if defaults:
|
|
92
|
+
req_defaults[str(req.id)] = defaults # list of {finding_id, payload...}
|
|
93
|
+
required_findings.extend([d.get("finding_id") for d in defaults if "finding_id" in d])
|
|
94
|
+
if choices:
|
|
95
|
+
cls_choices[str(req.id)] = choices # list of {classification_id, label, ...}
|
|
96
|
+
|
|
97
|
+
# De-dup required
|
|
98
|
+
required_findings = sorted(set(required_findings))
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
"patient_examination_id": pe.id,
|
|
102
|
+
"requirement_sets": requirement_sets,
|
|
103
|
+
"availableFindings": available_findings,
|
|
104
|
+
"requiredFindings": required_findings,
|
|
105
|
+
"requirementDefaults": req_defaults,
|
|
106
|
+
"classificationChoices": cls_choices,
|
|
107
|
+
# New fields for expanded lookup payload
|
|
108
|
+
"requirementsBySet": {}, # Will be populated when requirement sets are selected
|
|
109
|
+
"requirementStatus": {}, # Status of each requirement (satisfied/unsatisfied)
|
|
110
|
+
"requirementSetStatus": {}, # Status of each requirement set
|
|
111
|
+
"suggestedActions": {}, # Suggested actions to satisfy requirements
|
|
112
|
+
# You can add "selectedRequirementSetIds" as the user makes choices
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
def create_lookup_token_for_pe(pe_id: int) -> str:
|
|
116
|
+
pe = load_patient_exam_for_eval(pe_id)
|
|
117
|
+
token = LookupStore().init(build_initial_lookup(pe))
|
|
118
|
+
return token
|
|
119
|
+
|
|
120
|
+
def recompute_lookup(token: str) -> Dict[str, Any]:
|
|
121
|
+
import logging
|
|
122
|
+
logger = logging.getLogger(__name__)
|
|
123
|
+
|
|
124
|
+
store = LookupStore(token=token)
|
|
125
|
+
|
|
126
|
+
# Simple reentrancy guard using data
|
|
127
|
+
data = store.get_all()
|
|
128
|
+
if data.get('_recomputing'):
|
|
129
|
+
logger.warning(f"Recompute already in progress for token {token}, skipping")
|
|
130
|
+
return {}
|
|
131
|
+
|
|
132
|
+
store.set('_recomputing', True)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
# First validate and attempt to recover corrupted data
|
|
136
|
+
validated_data = store.validate_and_recover_data(token)
|
|
137
|
+
if validated_data is None:
|
|
138
|
+
logger.error(f"No lookup data found for token {token}")
|
|
139
|
+
raise ValueError(f"No lookup data found for token {token}")
|
|
140
|
+
|
|
141
|
+
data = validated_data
|
|
142
|
+
logger.debug(f"Recomputing lookup for token {token}, data keys: {list(data.keys())}")
|
|
143
|
+
|
|
144
|
+
# Check if required data exists
|
|
145
|
+
if "patient_examination_id" not in data:
|
|
146
|
+
logger.error(f"Invalid lookup data for token {token}: missing patient_examination_id. Data: {data}")
|
|
147
|
+
raise ValueError(f"Invalid lookup data for token {token}: missing patient_examination_id")
|
|
148
|
+
|
|
149
|
+
if not data.get("patient_examination_id"):
|
|
150
|
+
logger.error(f"Invalid lookup data for token {token}: patient_examination_id is empty. Data: {data}")
|
|
151
|
+
raise ValueError(f"Invalid lookup data for token {token}: patient_examination_id is empty")
|
|
152
|
+
|
|
153
|
+
pe_id = data["patient_examination_id"]
|
|
154
|
+
logger.debug(f"Loading patient examination {pe_id} for token {token}")
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
pe = load_patient_exam_for_eval(pe_id)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.error(f"Failed to load patient examination {pe_id} for token {token}: {e}")
|
|
160
|
+
raise ValueError(f"Failed to load patient examination {pe_id}: {e}")
|
|
161
|
+
|
|
162
|
+
selected_rs_ids: List[int] = data.get("selectedRequirementSetIds", [])
|
|
163
|
+
logger.debug(f"Selected requirement set IDs for token {token}: {selected_rs_ids}")
|
|
164
|
+
|
|
165
|
+
rs_objs = [rs for rs in requirement_sets_for_patient_exam(pe) if rs.id in selected_rs_ids]
|
|
166
|
+
logger.debug(f"Found {len(rs_objs)} requirement set objects for token {token}")
|
|
167
|
+
|
|
168
|
+
# 1) requirements grouped by set (already prefetched in load func)
|
|
169
|
+
requirements_by_set = {
|
|
170
|
+
rs.id: [ {"id": r.id, "name": r.name} for r in rs.requirements.all() ]
|
|
171
|
+
for rs in rs_objs
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# 2) status per requirement + set status
|
|
175
|
+
requirement_status: Dict[str, bool] = {}
|
|
176
|
+
set_status: Dict[str, bool] = {}
|
|
177
|
+
for rs in rs_objs:
|
|
178
|
+
req_results = []
|
|
179
|
+
for r in rs.requirements.all():
|
|
180
|
+
ok = bool(r.evaluate(pe, mode="strict")) # or "loose" if you prefer
|
|
181
|
+
requirement_status[str(r.id)] = ok
|
|
182
|
+
req_results.append(ok)
|
|
183
|
+
set_status[str(rs.id)] = rs.eval_function(req_results) if rs.eval_function else all(req_results)
|
|
184
|
+
|
|
185
|
+
# 3) suggestions per requirement (defaults + classification choices you already expose)
|
|
186
|
+
suggested_actions: Dict[str, List[Dict[str, Any]]] = {}
|
|
187
|
+
req_defaults: Dict[str, Any] = {}
|
|
188
|
+
cls_choices: Dict[str, Any] = {}
|
|
189
|
+
|
|
190
|
+
for rs in rs_objs:
|
|
191
|
+
for r in rs.requirements.all():
|
|
192
|
+
defaults = getattr(r, "default_findings", lambda pe: [])(pe) # [{finding_id, payload...}]
|
|
193
|
+
choices = getattr(r, "classification_choices", lambda pe: [])(pe) # [{classification_id, label,...}]
|
|
194
|
+
if defaults:
|
|
195
|
+
req_defaults[str(r.id)] = defaults
|
|
196
|
+
if choices:
|
|
197
|
+
cls_choices[str(r.id)] = choices
|
|
198
|
+
|
|
199
|
+
if not requirement_status.get(str(r.id), False):
|
|
200
|
+
# turn default proposals into explicit UI actions
|
|
201
|
+
acts = []
|
|
202
|
+
for d in defaults or []:
|
|
203
|
+
acts.append({
|
|
204
|
+
"type": "add_finding",
|
|
205
|
+
"finding_id": d.get("finding_id"),
|
|
206
|
+
"classification_ids": d.get("classification_ids") or [],
|
|
207
|
+
"note": "default"
|
|
208
|
+
})
|
|
209
|
+
# If r expects patient edits, add an edit action hint
|
|
210
|
+
if "PatientExamination" in [m.__name__ for m in r.expected_models]:
|
|
211
|
+
acts.append({"type": "edit_patient", "fields": ["gender", "dob"]}) # example
|
|
212
|
+
if acts:
|
|
213
|
+
suggested_actions[str(r.id)] = acts
|
|
214
|
+
|
|
215
|
+
# 4) (optional) staged changes simulation hook (see §3)
|
|
216
|
+
# staged = data.get("staged", {})
|
|
217
|
+
# if you implement server-side simulation later, adjust requirement_status with staged result here
|
|
218
|
+
|
|
219
|
+
updates = {
|
|
220
|
+
"requirementsBySet": requirements_by_set,
|
|
221
|
+
"requirementStatus": requirement_status,
|
|
222
|
+
"requirementSetStatus": set_status,
|
|
223
|
+
"requirementDefaults": req_defaults, # keep your existing key
|
|
224
|
+
"classificationChoices": cls_choices, # keep your existing key
|
|
225
|
+
"suggestedActions": suggested_actions, # new
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
logger.debug(f"Updating store for token {token} with {len(updates)} update keys")
|
|
229
|
+
|
|
230
|
+
# Only write if changed (idempotent)
|
|
231
|
+
prev_derived = store.get_many(list(updates.keys()))
|
|
232
|
+
if prev_derived != updates:
|
|
233
|
+
store.set_many(updates) # <-- does NOT call recompute
|
|
234
|
+
logger.debug(f"Derived data changed, updated store for token {token}")
|
|
235
|
+
else:
|
|
236
|
+
logger.debug(f"Derived data unchanged, skipping store update for token {token}")
|
|
237
|
+
|
|
238
|
+
store.mark_recompute_done()
|
|
239
|
+
return updates
|
|
240
|
+
finally:
|
|
241
|
+
store.set('_recomputing', False)
|