endoreg-db 0.8.9.32__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/__init__.py +0 -0
- endoreg_db/_version.py +34 -0
- endoreg_db/admin.py +97 -0
- endoreg_db/api/serializers/finding_descriptions.py +0 -0
- endoreg_db/api/views/finding_descriptions.py +0 -0
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +17 -0
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/authz/auth.py +78 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +20 -0
- endoreg_db/authz/middleware.py +84 -0
- endoreg_db/authz/permissions.py +138 -0
- endoreg_db/authz/policy.py +224 -0
- endoreg_db/authz/settings.py +64 -0
- endoreg_db/authz/views_auth.py +70 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +99 -0
- endoreg_db/config/__init__.py +0 -0
- endoreg_db/config/env.py +106 -0
- endoreg_db/config/settings/__init__.py +6 -0
- endoreg_db/config/settings/base.py +148 -0
- endoreg_db/config/settings/case_gen.py +32 -0
- endoreg_db/config/settings/dev.py +108 -0
- endoreg_db/config/settings/keycloak.py +177 -0
- endoreg_db/config/settings/prod.py +66 -0
- endoreg_db/config/settings/test.py +72 -0
- endoreg_db/data/__init__.py +135 -0
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/ai_model_label/label/data.yaml +88 -0
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_type/data.yaml +7 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
- endoreg_db/data/case_template/rule_value/.init +0 -0
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
- endoreg_db/data/case_template/template/base.yaml +8 -0
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
- endoreg_db/data/case_template/tmp/_rule_value +13 -0
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
- endoreg_db/data/center/data.yaml +99 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +5 -0
- endoreg_db/data/disease/renal.yaml +5 -0
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
- endoreg_db/data/distribution/date/patient.yaml +7 -0
- endoreg_db/data/distribution/multiple_categorical/.init +0 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +11 -0
- endoreg_db/data/endoscopy_processor/data.yaml +50 -0
- endoreg_db/data/event/cardiology.yaml +15 -0
- endoreg_db/data/event/neurology.yaml +14 -0
- endoreg_db/data/event/surgery.yaml +13 -0
- endoreg_db/data/event/thrombembolism.yaml +20 -0
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +172 -0
- endoreg_db/data/examination/time/data.yaml +48 -0
- endoreg_db/data/examination/time-type/data.yaml +5 -0
- endoreg_db/data/examination/type/data.yaml +17 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +359 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +90 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +97 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/00_generic.yaml +15 -0
- endoreg_db/data/finding_classification_choice/00_generic_baseline.yaml +23 -0
- endoreg_db/data/finding_classification_choice/00_generic_complication.yaml +15 -0
- endoreg_db/data/finding_classification_choice/00_generic_histology.yaml +21 -0
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_bowel_preparation.yaml +49 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_generic.yaml +19 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_histology.yaml +20 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_location.yaml +248 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_morphology.yaml +75 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/00_generic.yaml +53 -0
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_type/data.yaml +39 -0
- endoreg_db/data/gender/data.yaml +42 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +6 -0
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +37 -0
- endoreg_db/data/lab_value/coagulation.yaml +54 -0
- endoreg_db/data/lab_value/electrolytes.yaml +228 -0
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -0
- endoreg_db/data/lab_value/hematology.yaml +184 -0
- endoreg_db/data/lab_value/hormones.yaml +59 -0
- endoreg_db/data/lab_value/lipids.yaml +53 -0
- endoreg_db/data/lab_value/misc.yaml +76 -0
- endoreg_db/data/lab_value/renal_function.yaml +12 -0
- endoreg_db/data/log_type/data.yaml +57 -0
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/material/material.yaml +91 -0
- endoreg_db/data/medication/anticoagulation.yaml +65 -0
- endoreg_db/data/medication/tah.yaml +70 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -0
- endoreg_db/data/medication_indication_type/data.yaml +11 -0
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
- endoreg_db/data/medication_intake_time/base.yaml +31 -0
- endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
- endoreg_db/data/medication_schedule/ass.yaml +12 -0
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +59 -0
- endoreg_db/data/network_device_type/data.yaml +12 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
- endoreg_db/data/pdf_type/data.yaml +46 -0
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
- endoreg_db/data/profession/data.yaml +70 -0
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -0
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement/old/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/old/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/old/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/old/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/old/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/old/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/old/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/old/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/old/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/old/gender.yaml +0 -0
- endoreg_db/data/requirement/old/lab_value.yaml +441 -0
- endoreg_db/data/requirement/old/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/_old/age.yaml +13 -0
- endoreg_db/data/requirement_operator/_old/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/_old/model_operators.yaml +96 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +65 -0
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set_type/data.yaml +41 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -0
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift/m2.yaml +0 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +32 -0
- endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
- endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
- endoreg_db/data/unit/concentration.yaml +115 -0
- endoreg_db/data/unit/data.yaml +17 -0
- endoreg_db/data/unit/length.yaml +31 -0
- endoreg_db/data/unit/misc.yaml +20 -0
- endoreg_db/data/unit/rate.yaml +6 -0
- endoreg_db/data/unit/time.yaml +48 -0
- endoreg_db/data/unit/volume.yaml +35 -0
- endoreg_db/data/unit/weight.yaml +38 -0
- endoreg_db/data/waste/data.yaml +12 -0
- endoreg_db/exceptions.py +24 -0
- endoreg_db/export/frames/export.py +6 -0
- endoreg_db/export/frames/export_frames_with_labels.py +616 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +4 -0
- endoreg_db/forms/examination_form.py +12 -0
- endoreg_db/forms/patient_finding_intervention_form.py +40 -0
- endoreg_db/forms/patient_form.py +23 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -0
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -0
- endoreg_db/forms/settings/__init__.py +11 -0
- endoreg_db/forms/unit.py +7 -0
- endoreg_db/helpers/__init__.py +0 -0
- endoreg_db/helpers/count_db.py +48 -0
- endoreg_db/helpers/data_loader.py +280 -0
- endoreg_db/helpers/default_objects.py +414 -0
- endoreg_db/helpers/download_segmentation_model.py +32 -0
- endoreg_db/helpers/interact.py +1 -0
- endoreg_db/helpers/test_video_helper.py +127 -0
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +83 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +42 -0
- endoreg_db/import_files/context/validate_directories.py +57 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +99 -0
- endoreg_db/import_files/file_storage/create_video_file.py +104 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +42 -0
- endoreg_db/import_files/file_storage/state_management.py +463 -0
- endoreg_db/import_files/file_storage/storage.py +42 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +99 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/pseudonymization/__init__.py +0 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +181 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +139 -0
- endoreg_db/import_files/pseudonymization/pseudonymize.py +0 -0
- endoreg_db/import_files/report_import_service.py +147 -0
- endoreg_db/import_files/video_import_service.py +154 -0
- endoreg_db/logger_conf.py +156 -0
- endoreg_db/management/__init__.py +1 -0
- endoreg_db/management/commands/__init__.py +1 -0
- endoreg_db/management/commands/anonymize_video.py +0 -0
- endoreg_db/management/commands/check_auth.py +132 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +177 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +419 -0
- endoreg_db/management/commands/export_frame_annot.py +196 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +206 -0
- endoreg_db/management/commands/fix_video_paths.py +186 -0
- endoreg_db/management/commands/import_report.py +361 -0
- endoreg_db/management/commands/list_routes.py +20 -0
- endoreg_db/management/commands/load_ai_model_data.py +83 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +60 -0
- endoreg_db/management/commands/load_base_db_data.py +63 -0
- endoreg_db/management/commands/load_center_data.py +68 -0
- endoreg_db/management/commands/load_contraindication_data.py +39 -0
- endoreg_db/management/commands/load_disease_classification_choices_data.py +38 -0
- endoreg_db/management/commands/load_disease_classification_data.py +38 -0
- endoreg_db/management/commands/load_disease_data.py +59 -0
- endoreg_db/management/commands/load_distribution_data.py +63 -0
- endoreg_db/management/commands/load_endoscope_data.py +58 -0
- endoreg_db/management/commands/load_event_data.py +39 -0
- endoreg_db/management/commands/load_examination_data.py +78 -0
- endoreg_db/management/commands/load_examination_indication_data.py +85 -0
- endoreg_db/management/commands/load_finding_data.py +115 -0
- endoreg_db/management/commands/load_gender_data.py +37 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +142 -0
- endoreg_db/management/commands/load_information_source.py +46 -0
- endoreg_db/management/commands/load_lab_value_data.py +52 -0
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_medication_data.py +104 -0
- endoreg_db/management/commands/load_name_data.py +36 -0
- endoreg_db/management/commands/load_organ_data.py +39 -0
- endoreg_db/management/commands/load_pdf_type_data.py +58 -0
- endoreg_db/management/commands/load_profession_data.py +40 -0
- endoreg_db/management/commands/load_qualification_data.py +56 -0
- endoreg_db/management/commands/load_report_reader_flag_data.py +40 -0
- endoreg_db/management/commands/load_requirement_data.py +207 -0
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +57 -0
- endoreg_db/management/commands/load_shift_data.py +57 -0
- endoreg_db/management/commands/load_tag_data.py +54 -0
- endoreg_db/management/commands/load_unit_data.py +40 -0
- endoreg_db/management/commands/load_user_groups.py +26 -0
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +70 -0
- endoreg_db/management/commands/setup_endoreg_db.py +459 -0
- endoreg_db/management/commands/start_filewatcher.py +115 -0
- endoreg_db/management/commands/storage_management.py +622 -0
- endoreg_db/management/commands/summarize_db_content.py +280 -0
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +189 -0
- endoreg_db/management/commands/video_validation.py +20 -0
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/migrations/0001_initial.py +1953 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +322 -0
- endoreg_db/models/administration/__init__.py +95 -0
- endoreg_db/models/administration/ai/__init__.py +9 -0
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +180 -0
- endoreg_db/models/administration/ai/model_type.py +42 -0
- endoreg_db/models/administration/case/__init__.py +5 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/administration/case/case_template/__init__.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_rule.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +3 -0
- endoreg_db/models/administration/case/case_template/case_template_type.py +3 -0
- endoreg_db/models/administration/center/__init__.py +13 -0
- endoreg_db/models/administration/center/center.py +85 -0
- endoreg_db/models/administration/center/center_product.py +67 -0
- endoreg_db/models/administration/center/center_resource.py +69 -0
- endoreg_db/models/administration/center/center_shift.py +94 -0
- endoreg_db/models/administration/center/center_waste.py +42 -0
- endoreg_db/models/administration/person/__init__.py +26 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +40 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +44 -0
- endoreg_db/models/administration/person/employee/employee_type.py +50 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +64 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/administration/person/names/first_name.py +20 -0
- endoreg_db/models/administration/person/names/last_name.py +20 -0
- endoreg_db/models/administration/person/patient/__init__.py +7 -0
- endoreg_db/models/administration/person/patient/patient.py +488 -0
- endoreg_db/models/administration/person/patient/patient_external_id.py +36 -0
- endoreg_db/models/administration/person/person.py +35 -0
- endoreg_db/models/administration/person/profession/__init__.py +28 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +41 -0
- endoreg_db/models/administration/product/__init__.py +15 -0
- endoreg_db/models/administration/product/product.py +106 -0
- endoreg_db/models/administration/product/product_group.py +41 -0
- endoreg_db/models/administration/product/product_material.py +60 -0
- endoreg_db/models/administration/product/product_weight.py +51 -0
- endoreg_db/models/administration/product/reference_product.py +147 -0
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +43 -0
- endoreg_db/models/administration/qualification/qualification_type.py +39 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +72 -0
- endoreg_db/models/administration/shift/shift.py +57 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +23 -0
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +85 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +61 -0
- endoreg_db/models/label/label.py +91 -0
- endoreg_db/models/label/label_set.py +68 -0
- endoreg_db/models/label/label_type.py +29 -0
- endoreg_db/models/label/label_video_segment/__init__.py +3 -0
- endoreg_db/models/label/label_video_segment/_create_from_video.py +42 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +611 -0
- endoreg_db/models/label/video_segmentation_label.py +35 -0
- endoreg_db/models/label/video_segmentation_labelset.py +28 -0
- endoreg_db/models/media/__init__.py +23 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +137 -0
- endoreg_db/models/media/pdf/__init__.py +12 -0
- endoreg_db/models/media/pdf/raw_pdf.py +764 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +85 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +46 -0
- endoreg_db/models/media/video/__init__.py +9 -0
- endoreg_db/models/media/video/create_from_file.py +402 -0
- endoreg_db/models/media/video/pipe_1.py +258 -0
- endoreg_db/models/media/video/pipe_2.py +129 -0
- endoreg_db/models/media/video/video_file.py +907 -0
- endoreg_db/models/media/video/video_file_ai.py +828 -0
- endoreg_db/models/media/video/video_file_anonymize.py +524 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +49 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +25 -0
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +126 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +233 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +36 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +13 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +24 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +40 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +44 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +30 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +205 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +228 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +107 -0
- endoreg_db/models/media/video/video_file_io.py +272 -0
- endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +58 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +62 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +183 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +198 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +178 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +105 -0
- endoreg_db/models/media/video/video_file_segments.py +317 -0
- endoreg_db/models/media/video/video_metadata.py +67 -0
- endoreg_db/models/media/video/video_processing.py +192 -0
- endoreg_db/models/medical/__init__.py +136 -0
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +29 -0
- endoreg_db/models/medical/disease.py +174 -0
- endoreg_db/models/medical/event.py +154 -0
- endoreg_db/models/medical/examination/__init__.py +20 -0
- endoreg_db/models/medical/examination/examination.py +183 -0
- endoreg_db/models/medical/examination/examination_indication.py +229 -0
- endoreg_db/models/medical/examination/examination_time.py +68 -0
- endoreg_db/models/medical/examination/examination_time_type.py +44 -0
- endoreg_db/models/medical/examination/examination_type.py +47 -0
- endoreg_db/models/medical/finding/__init__.py +20 -0
- endoreg_db/models/medical/finding/finding.py +113 -0
- endoreg_db/models/medical/finding/finding_classification.py +131 -0
- endoreg_db/models/medical/finding/finding_intervention.py +68 -0
- endoreg_db/models/medical/finding/finding_type.py +38 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +77 -0
- endoreg_db/models/medical/hardware/endoscopy_processor.py +182 -0
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +490 -0
- endoreg_db/models/medical/medication/__init__.py +23 -0
- endoreg_db/models/medical/medication/medication.py +45 -0
- endoreg_db/models/medical/medication/medication_indication.py +78 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +58 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +58 -0
- endoreg_db/models/medical/medication/medication_schedule.py +58 -0
- endoreg_db/models/medical/organ/__init__.py +38 -0
- endoreg_db/models/medical/patient/__init__.py +48 -0
- endoreg_db/models/medical/patient/medication_examples.py +56 -0
- endoreg_db/models/medical/patient/patient_disease.py +72 -0
- endoreg_db/models/medical/patient/patient_event.py +80 -0
- endoreg_db/models/medical/patient/patient_examination.py +280 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +57 -0
- endoreg_db/models/medical/patient/patient_finding.py +416 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +231 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +37 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +157 -0
- endoreg_db/models/medical/patient/patient_lab_value.py +247 -0
- endoreg_db/models/medical/patient/patient_medication.py +111 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +152 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +73 -0
- endoreg_db/models/medical/risk/risk_type.py +54 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/model_meta.py +266 -0
- endoreg_db/models/metadata/model_meta_logic.py +485 -0
- endoreg_db/models/metadata/pdf_meta.py +96 -0
- endoreg_db/models/metadata/sensitive_meta.py +345 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1161 -0
- endoreg_db/models/metadata/video_meta.py +459 -0
- endoreg_db/models/metadata/video_prediction_logic.py +232 -0
- endoreg_db/models/metadata/video_prediction_meta.py +319 -0
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +40 -0
- endoreg_db/models/other/distribution/__init__.py +46 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +22 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +163 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +50 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +211 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +23 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +110 -0
- endoreg_db/models/other/gender.py +32 -0
- endoreg_db/models/other/information_source.py +190 -0
- endoreg_db/models/other/material.py +34 -0
- endoreg_db/models/other/resource.py +24 -0
- endoreg_db/models/other/tag.py +32 -0
- endoreg_db/models/other/transport_route.py +40 -0
- endoreg_db/models/other/unit.py +40 -0
- endoreg_db/models/other/waste.py +28 -0
- endoreg_db/models/report/__init__.py +0 -0
- endoreg_db/models/report/images.py +0 -0
- endoreg_db/models/report/report.py +5 -0
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +792 -0
- endoreg_db/models/requirement/requirement_error.py +84 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +137 -0
- endoreg_db/models/requirement/requirement_operator.py +187 -0
- endoreg_db/models/requirement/requirement_set.py +327 -0
- endoreg_db/models/state/__init__.py +13 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/anonymization.py +30 -0
- endoreg_db/models/state/audit_ledger.py +155 -0
- endoreg_db/models/state/label_video_segment.py +31 -0
- endoreg_db/models/state/processing_history/__init__.py +3 -0
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +219 -0
- endoreg_db/models/state/sensitive_meta.py +50 -0
- endoreg_db/models/state/video.py +251 -0
- endoreg_db/models/upload_job.py +100 -0
- endoreg_db/models/utils.py +138 -0
- endoreg_db/queries/__init__.py +3 -0
- endoreg_db/queries/annotations/__init__.py +1 -0
- endoreg_db/queries/annotations/legacy.py +169 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- endoreg_db/root_urls.py +27 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +30 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +861 -0
- endoreg_db/serializers/__init__.py +104 -0
- endoreg_db/serializers/administration/__init__.py +13 -0
- endoreg_db/serializers/administration/ai/__init__.py +9 -0
- endoreg_db/serializers/administration/ai/active_model.py +12 -0
- endoreg_db/serializers/administration/ai/ai_model.py +20 -0
- endoreg_db/serializers/administration/ai/model_type.py +12 -0
- endoreg_db/serializers/administration/center.py +14 -0
- endoreg_db/serializers/administration/gender.py +11 -0
- endoreg_db/serializers/anonymization.py +77 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +45 -0
- endoreg_db/serializers/examination/dropdown.py +20 -0
- endoreg_db/serializers/examination_serializer.py +9 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +61 -0
- endoreg_db/serializers/finding_classification/__init__.py +7 -0
- endoreg_db/serializers/finding_classification/choice.py +19 -0
- endoreg_db/serializers/finding_classification/classification.py +11 -0
- endoreg_db/serializers/label_video_segment/__init__.py +9 -0
- endoreg_db/serializers/label_video_segment/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/label_video_segment/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +427 -0
- endoreg_db/serializers/meta/__init__.py +13 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +122 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +153 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +62 -0
- endoreg_db/serializers/meta/video_meta.py +39 -0
- endoreg_db/serializers/misc/__init__.py +14 -0
- endoreg_db/serializers/misc/file_overview.py +72 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +144 -0
- endoreg_db/serializers/misc/stats.py +35 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +74 -0
- endoreg_db/serializers/patient/__init__.py +12 -0
- endoreg_db/serializers/patient/patient.py +103 -0
- endoreg_db/serializers/patient/patient_dropdown.py +35 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +168 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +32 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +47 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +62 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +28 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +40 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +135 -0
- endoreg_db/serializers/pdf/__init__.py +3 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +101 -0
- endoreg_db/serializers/requirements/requirement_schema.py +20 -0
- endoreg_db/serializers/requirements/requirement_sets.py +99 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +301 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/video_file.py +283 -0
- endoreg_db/serializers/video/video_file_brief.py +14 -0
- endoreg_db/serializers/video/video_file_detail.py +96 -0
- endoreg_db/serializers/video/video_file_list.py +100 -0
- endoreg_db/serializers/video/video_processing_history.py +172 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +274 -0
- endoreg_db/services/examination_evaluation.py +172 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +424 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/pdf_import.py +0 -0
- endoreg_db/services/polling_coordinator.py +319 -0
- endoreg_db/services/pseudonym_service.py +94 -0
- endoreg_db/services/report_import.py +13 -0
- endoreg_db/services/segment_sync.py +171 -0
- endoreg_db/services/video_import.py +9 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls/__init__.py +56 -0
- endoreg_db/urls/ai.py +14 -0
- endoreg_db/urls/anonymization.py +78 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +34 -0
- endoreg_db/urls/examination.py +63 -0
- endoreg_db/urls/media.py +251 -0
- endoreg_db/urls/patient.py +23 -0
- endoreg_db/urls/requirements.py +15 -0
- endoreg_db/urls/root_urls.py +28 -0
- endoreg_db/urls/stats.py +54 -0
- endoreg_db/urls/upload.py +12 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +97 -0
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +6 -0
- endoreg_db/utils/ai/inference_dataset.py +51 -0
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +270 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +293 -0
- endoreg_db/utils/ai/preprocess.py +76 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +32 -0
- endoreg_db/utils/check_video_files.py +175 -0
- endoreg_db/utils/cropping.py +30 -0
- endoreg_db/utils/dataloader.py +285 -0
- endoreg_db/utils/dates.py +59 -0
- endoreg_db/utils/defaults/set_default_center.py +33 -0
- endoreg_db/utils/env.py +37 -0
- endoreg_db/utils/extract_specific_frames.py +87 -0
- endoreg_db/utils/file_operations.py +70 -0
- endoreg_db/utils/fix_video_path_direct.py +157 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +138 -0
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +237 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +82 -0
- endoreg_db/utils/ocr.py +195 -0
- endoreg_db/utils/operation_log.py +87 -0
- endoreg_db/utils/parse_and_generate_yaml.py +45 -0
- endoreg_db/utils/paths.py +159 -0
- endoreg_db/utils/permissions.py +160 -0
- endoreg_db/utils/pipelines/Readme.md +235 -0
- endoreg_db/utils/pipelines/__init__.py +0 -0
- endoreg_db/utils/pipelines/process_video_dir.py +144 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +22 -0
- endoreg_db/utils/product/sum_weights.py +20 -0
- endoreg_db/utils/pydantic_models/__init__.py +5 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/requirement_helpers.py +0 -0
- endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +678 -0
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +842 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +114 -0
- endoreg_db/utils/setup_config.py +196 -0
- endoreg_db/utils/storage.py +117 -0
- endoreg_db/utils/translation.py +31 -0
- endoreg_db/utils/uuid.py +5 -0
- endoreg_db/utils/validate_endo_roi.py +33 -0
- endoreg_db/utils/validate_subcategory_dict.py +93 -0
- endoreg_db/utils/validate_video_detailed.py +415 -0
- endoreg_db/utils/video/__init__.py +30 -0
- endoreg_db/utils/video/extract_frames.py +100 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +996 -0
- endoreg_db/utils/video/names.py +47 -0
- endoreg_db/utils/video/streaming_processor.py +386 -0
- endoreg_db/utils/video/video_splitter.py +105 -0
- endoreg_db/versioning.md +79 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +247 -0
- endoreg_db/views/__init__.py +157 -0
- endoreg_db/views/anonymization/__init__.py +31 -0
- endoreg_db/views/anonymization/media_management.py +486 -0
- endoreg_db/views/anonymization/overview.py +307 -0
- endoreg_db/views/anonymization/validate.py +310 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +146 -0
- endoreg_db/views/examination/__init__.py +30 -0
- endoreg_db/views/examination/examination.py +37 -0
- endoreg_db/views/examination/examination_manifest_cache.py +26 -0
- endoreg_db/views/examination/get_finding_classification_choices.py +62 -0
- endoreg_db/views/examination/get_finding_classifications.py +38 -0
- endoreg_db/views/examination/get_findings.py +39 -0
- endoreg_db/views/examination/get_instruments.py +19 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +116 -0
- endoreg_db/views/finding/get_classifications.py +14 -0
- endoreg_db/views/finding/get_interventions.py +17 -0
- endoreg_db/views/finding_classification/__init__.py +13 -0
- endoreg_db/views/finding_classification/base.py +0 -0
- endoreg_db/views/finding_classification/finding_classification.py +41 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +54 -0
- endoreg_db/views/media/__init__.py +32 -0
- endoreg_db/views/media/pdf_media.py +411 -0
- endoreg_db/views/media/sensitive_metadata.py +372 -0
- endoreg_db/views/media/video_media.py +275 -0
- endoreg_db/views/meta/__init__.py +7 -0
- endoreg_db/views/meta/sensitive_meta_list.py +102 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +74 -0
- endoreg_db/views/misc/__init__.py +29 -0
- endoreg_db/views/misc/center.py +14 -0
- endoreg_db/views/misc/csrf.py +8 -0
- endoreg_db/views/misc/gender.py +15 -0
- endoreg_db/views/misc/stats.py +255 -0
- endoreg_db/views/misc/upload_views.py +241 -0
- endoreg_db/views/patient/__init__.py +3 -0
- endoreg_db/views/patient/patient.py +253 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +141 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +58 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +72 -0
- endoreg_db/views/patient_examination/video.py +228 -0
- endoreg_db/views/patient_finding/__init__.py +7 -0
- endoreg_db/views/patient_finding/base.py +0 -0
- endoreg_db/views/patient_finding/patient_finding.py +71 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +291 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +75 -0
- endoreg_db/views/report/__init__.py +7 -0
- endoreg_db/views/report/reimport.py +177 -0
- endoreg_db/views/report/report_stream.py +191 -0
- endoreg_db/views/requirement/__init__.py +11 -0
- endoreg_db/views/requirement/evaluate.py +278 -0
- endoreg_db/views/requirement/lookup.py +380 -0
- endoreg_db/views/requirement/lookup_store.py +183 -0
- endoreg_db/views/requirement/requirement_utils.py +87 -0
- endoreg_db/views/requirement_lookup/lookup.py +0 -0
- endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
- endoreg_db/views/stats/__init__.py +13 -0
- endoreg_db/views/stats/stats_views.py +266 -0
- endoreg_db/views/video/__init__.py +49 -0
- endoreg_db/views/video/ai/__init__.py +8 -0
- endoreg_db/views/video/ai/label.py +159 -0
- endoreg_db/views/video/correction.py +529 -0
- endoreg_db/views/video/reimport.py +230 -0
- endoreg_db/views/video/segments_crud.py +709 -0
- endoreg_db/views/video/video_apply_mask.py +49 -0
- endoreg_db/views/video/video_correction.py +22 -0
- endoreg_db/views/video/video_download_processed.py +58 -0
- endoreg_db/views/video/video_examination_viewset.py +242 -0
- endoreg_db/views/video/video_metadata.py +101 -0
- endoreg_db/views/video/video_processing_history.py +25 -0
- endoreg_db/views/video/video_remove_frames.py +49 -0
- endoreg_db/views/video/video_stream.py +334 -0
- endoreg_db-0.8.9.32.dist-info/METADATA +404 -0
- endoreg_db-0.8.9.32.dist-info/RECORD +787 -0
- endoreg_db-0.8.9.32.dist-info/WHEEL +4 -0
- endoreg_db-0.8.9.32.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lookup Service Module
|
|
3
|
+
|
|
4
|
+
This module provides server-side evaluation and lookup functionality for patient examinations.
|
|
5
|
+
It handles requirement set evaluation, finding availability, and status computation for
|
|
6
|
+
medical examination workflows.
|
|
7
|
+
|
|
8
|
+
The lookup system uses a token-based approach where client sessions are stored in Django cache,
|
|
9
|
+
allowing for efficient state management and recomputation of derived data.
|
|
10
|
+
|
|
11
|
+
Key Components:
|
|
12
|
+
- PatientExamination loading with optimized prefetching
|
|
13
|
+
- Requirement set resolution and evaluation
|
|
14
|
+
- Status computation for requirements and requirement sets
|
|
15
|
+
- Suggested actions for unsatisfied requirements
|
|
16
|
+
- Cache-based session management
|
|
17
|
+
|
|
18
|
+
Architecture:
|
|
19
|
+
1. LookupStore: Handles cache-based session storage
|
|
20
|
+
2. lookup_service: Core business logic for evaluation
|
|
21
|
+
3. LookupViewSet: Django REST API endpoints
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# services/lookup_service.py
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import logging
|
|
28
|
+
from typing import Any, Dict, List, Optional
|
|
29
|
+
|
|
30
|
+
from django.db.models import Prefetch, QuerySet
|
|
31
|
+
|
|
32
|
+
from endoreg_db.models.medical.examination import ExaminationRequirementSet
|
|
33
|
+
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
34
|
+
from endoreg_db.models.requirement.requirement_set import RequirementSet
|
|
35
|
+
|
|
36
|
+
from .lookup_store import LookupStore
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def load_patient_exam_for_eval(pk: int) -> PatientExamination:
|
|
40
|
+
"""
|
|
41
|
+
Load a PatientExamination with all related data needed for evaluation.
|
|
42
|
+
|
|
43
|
+
This function performs optimized database queries to fetch a PatientExamination
|
|
44
|
+
along with all related objects required for requirement evaluation, including:
|
|
45
|
+
- Patient and examination details
|
|
46
|
+
- Patient findings
|
|
47
|
+
- Examination requirement sets and their requirements
|
|
48
|
+
- Nested requirement set relationships
|
|
49
|
+
|
|
50
|
+
The query uses select_related and prefetch_related to minimize database hits
|
|
51
|
+
and ensure all data is available for evaluation without additional queries.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
pk: Primary key of the PatientExamination to load
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
PatientExamination: Fully loaded instance with all related data prefetched
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
PatientExamination.DoesNotExist: If no examination exists with the given pk
|
|
61
|
+
"""
|
|
62
|
+
return (
|
|
63
|
+
PatientExamination.objects.select_related("patient", "examination")
|
|
64
|
+
.prefetch_related(
|
|
65
|
+
"patient_findings",
|
|
66
|
+
# Prefetch ERS groups on the Examination…
|
|
67
|
+
Prefetch(
|
|
68
|
+
"examination__exam_reqset_links",
|
|
69
|
+
queryset=ExaminationRequirementSet.objects.only(
|
|
70
|
+
"id", "name", "enabled_by_default"
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
# …and the RequirementSets reachable via those ERS groups.
|
|
74
|
+
Prefetch(
|
|
75
|
+
"examination__exam_reqset_links__requirement_set",
|
|
76
|
+
queryset=(
|
|
77
|
+
RequirementSet.objects.select_related(
|
|
78
|
+
"requirement_set_type"
|
|
79
|
+
).prefetch_related(
|
|
80
|
+
"requirements",
|
|
81
|
+
"links_to_sets",
|
|
82
|
+
"links_to_sets__requirements",
|
|
83
|
+
"links_to_sets__requirement_set_type",
|
|
84
|
+
)
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
.get(pk=pk)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def requirement_sets_for_patient_exam(
|
|
93
|
+
pe: PatientExamination, user_tags: Optional[List[str]] = None
|
|
94
|
+
) -> QuerySet:
|
|
95
|
+
"""
|
|
96
|
+
Retrieve all RequirementSets linked to a PatientExamination's examination.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
pe: PatientExamination instance
|
|
100
|
+
user_tags: Optional list of tag names to filter requirement sets
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
QuerySet of RequirementSet instances
|
|
104
|
+
"""
|
|
105
|
+
if not pe or not pe.examination:
|
|
106
|
+
from endoreg_db.models import RequirementSet
|
|
107
|
+
|
|
108
|
+
return RequirementSet.objects.none()
|
|
109
|
+
|
|
110
|
+
# Start with examination-linked requirement sets
|
|
111
|
+
req_sets = pe.examination.exam_reqset_links.select_related(
|
|
112
|
+
"requirement_set"
|
|
113
|
+
).values_list("requirement_set", flat=True)
|
|
114
|
+
|
|
115
|
+
from endoreg_db.models import RequirementSet
|
|
116
|
+
|
|
117
|
+
qs = RequirementSet.objects.filter(pk__in=req_sets)
|
|
118
|
+
|
|
119
|
+
# Apply tag filtering if provided
|
|
120
|
+
if user_tags:
|
|
121
|
+
qs = qs.filter(tags__name__in=user_tags).distinct()
|
|
122
|
+
|
|
123
|
+
return qs
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def build_initial_lookup(
|
|
127
|
+
pe: PatientExamination, user_tags: Optional[List[str]] = None
|
|
128
|
+
) -> Dict[str, Any]:
|
|
129
|
+
"""
|
|
130
|
+
Build the initial lookup dictionary for a patient examination.
|
|
131
|
+
|
|
132
|
+
This function creates the base lookup data structure that will be stored in cache
|
|
133
|
+
and used by the client for requirement evaluation. It includes:
|
|
134
|
+
|
|
135
|
+
- Available findings for the examination type
|
|
136
|
+
- Required findings based on requirement defaults
|
|
137
|
+
- Requirement sets metadata
|
|
138
|
+
- Default findings and classification choices per requirement
|
|
139
|
+
- Empty placeholders for dynamic data (status, suggestions, etc.)
|
|
140
|
+
|
|
141
|
+
The returned dictionary is JSON-serializable and contains stable keys that
|
|
142
|
+
won't change between versions.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
pe: PatientExamination instance to build lookup for
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Dictionary containing initial lookup data with the following keys:
|
|
149
|
+
- patient_examination_id: ID of the patient examination
|
|
150
|
+
- requirement_sets: List of available requirement sets with metadata
|
|
151
|
+
- available_findings: List of finding IDs available for the examination
|
|
152
|
+
- required_findings: List of finding IDs that are required by defaults
|
|
153
|
+
- requirement_defaults: Default findings per requirement
|
|
154
|
+
- classification_choices: Available classification choices per requirement
|
|
155
|
+
- requirements_by_set: Empty dict (populated on selection)
|
|
156
|
+
- requirement_status: Empty dict (computed on evaluation)
|
|
157
|
+
- requirement_set_status: Empty dict (computed on evaluation)
|
|
158
|
+
- suggested_actions: Empty dict (computed on evaluation)
|
|
159
|
+
"""
|
|
160
|
+
# Available + required findings
|
|
161
|
+
available_findings = (
|
|
162
|
+
[f.id for f in pe.examination.get_available_findings()]
|
|
163
|
+
if pe.examination
|
|
164
|
+
else []
|
|
165
|
+
)
|
|
166
|
+
required_findings: List[int] = [] # fill by scanning requirements below
|
|
167
|
+
|
|
168
|
+
# Requirement sets: ids + meta
|
|
169
|
+
rs_objs = requirement_sets_for_patient_exam(pe, user_tags=user_tags)
|
|
170
|
+
requirement_sets = [
|
|
171
|
+
{
|
|
172
|
+
"id": rs.id,
|
|
173
|
+
"name": rs.name,
|
|
174
|
+
"type": rs.requirement_set_type.name if rs.requirement_set_type else "all",
|
|
175
|
+
}
|
|
176
|
+
for rs in rs_objs
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
# Requirement-level defaults and classification choices (skeleton)
|
|
180
|
+
# You said: each Requirement can provide default findings and addable choices
|
|
181
|
+
req_defaults: Dict[str, Any] = {}
|
|
182
|
+
cls_choices: Dict[str, Any] = {}
|
|
183
|
+
|
|
184
|
+
for rs in rs_objs:
|
|
185
|
+
for req in rs.requirements.all():
|
|
186
|
+
# You’ll implement these helpers on Requirement
|
|
187
|
+
defaults = getattr(req, "default_findings", lambda pe: [])(pe)
|
|
188
|
+
choices = getattr(req, "classification_choices", lambda pe: [])(pe)
|
|
189
|
+
if defaults:
|
|
190
|
+
req_defaults[str(req.id)] = defaults # list of {finding_id, payload...}
|
|
191
|
+
required_findings.extend(
|
|
192
|
+
[d.get("finding_id") for d in defaults if "finding_id" in d]
|
|
193
|
+
)
|
|
194
|
+
if choices:
|
|
195
|
+
cls_choices[str(req.id)] = (
|
|
196
|
+
choices # list of {classification_id, label, ...}
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# De-dup required
|
|
200
|
+
required_findings = sorted(set(required_findings))
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
"patient_examination_id": pe.id,
|
|
204
|
+
"requirement_sets": requirement_sets,
|
|
205
|
+
"available_findings": available_findings,
|
|
206
|
+
"required_findings": required_findings,
|
|
207
|
+
"requirement_defaults": req_defaults,
|
|
208
|
+
"classification_choices": cls_choices,
|
|
209
|
+
# New fields for expanded lookup payload
|
|
210
|
+
"requirements_by_set": {}, # Will be populated when requirement sets are selected
|
|
211
|
+
"requirement_status": {}, # Status of each requirement (satisfied/unsatisfied)
|
|
212
|
+
"requirement_set_status": {}, # Status of each requirement set
|
|
213
|
+
"suggested_actions": {}, # Suggested actions to satisfy requirements
|
|
214
|
+
# You can add "selectedRequirementSetIds" as the user makes choices
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def create_lookup_token_for_pe(
|
|
219
|
+
pe_id: int, user_tags: Optional[List[str]] = None
|
|
220
|
+
) -> str:
|
|
221
|
+
"""
|
|
222
|
+
Create a lookup token for a patient examination.
|
|
223
|
+
|
|
224
|
+
This function initializes a new lookup session for the given patient examination
|
|
225
|
+
by building the initial lookup data and storing it in the cache via LookupStore.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
pe_id: Primary key of the PatientExamination
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
String token that can be used to access the lookup session
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
PatientExamination.DoesNotExist: If examination doesn't exist
|
|
235
|
+
Exception: For any other errors during initialization
|
|
236
|
+
"""
|
|
237
|
+
pe = load_patient_exam_for_eval(pe_id)
|
|
238
|
+
token = LookupStore().init(build_initial_lookup(pe, user_tags=user_tags))
|
|
239
|
+
return token
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def recompute_lookup(token: str) -> Dict[str, Any]:
|
|
243
|
+
"""
|
|
244
|
+
Recompute derived lookup data based on current patient examination state and user selections.
|
|
245
|
+
|
|
246
|
+
This function performs the core evaluation logic for the lookup system. It:
|
|
247
|
+
|
|
248
|
+
1. Validates and recovers corrupted lookup data
|
|
249
|
+
2. Loads the current PatientExamination state from database
|
|
250
|
+
3. Evaluates requirements against the current examination state
|
|
251
|
+
4. Computes status for individual requirements and requirement sets
|
|
252
|
+
5. Generates suggested actions for unsatisfied requirements
|
|
253
|
+
6. Updates the cache with new derived data (idempotent)
|
|
254
|
+
|
|
255
|
+
The function includes reentrancy protection to prevent concurrent recomputation
|
|
256
|
+
of the same token.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
token: Lookup session token
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
Dictionary of updates containing:
|
|
263
|
+
- requirements_by_set: Requirements grouped by selected requirement sets
|
|
264
|
+
- requirement_status: Boolean status for each requirement
|
|
265
|
+
- requirement_set_status: Boolean status for each requirement set
|
|
266
|
+
- requirement_defaults: Default findings per requirement
|
|
267
|
+
- classification_choices: Available choices per requirement
|
|
268
|
+
- suggested_actions: UI actions to satisfy unsatisfied requirements
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
ValueError: If lookup data is invalid or patient examination not found
|
|
272
|
+
"""
|
|
273
|
+
logger = logging.getLogger(__name__)
|
|
274
|
+
|
|
275
|
+
store = LookupStore(token=token)
|
|
276
|
+
|
|
277
|
+
# Simple reentrancy guard using data
|
|
278
|
+
data = store.get_all()
|
|
279
|
+
if data.get("_recomputing"):
|
|
280
|
+
logger.warning(f"Recompute already in progress for token {token}, skipping")
|
|
281
|
+
return {}
|
|
282
|
+
|
|
283
|
+
store.set("_recomputing", True)
|
|
284
|
+
|
|
285
|
+
try:
|
|
286
|
+
# First validate and attempt to recover corrupted data
|
|
287
|
+
validated_data = store.validate_and_recover_data(token)
|
|
288
|
+
if validated_data is None:
|
|
289
|
+
logger.error(f"No lookup data found for token {token}")
|
|
290
|
+
raise ValueError(f"No lookup data found for token {token}")
|
|
291
|
+
|
|
292
|
+
data = validated_data
|
|
293
|
+
logger.debug(
|
|
294
|
+
f"Recomputing lookup for token {token}, data keys: {list(data.keys())}"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Check if required data exists
|
|
298
|
+
if "patient_examination_id" not in data:
|
|
299
|
+
logger.error(
|
|
300
|
+
f"Invalid lookup data for token {token}: missing patient_examination_id. Data: {data}"
|
|
301
|
+
)
|
|
302
|
+
raise ValueError(
|
|
303
|
+
f"Invalid lookup data for token {token}: missing patient_examination_id"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
if not data.get("patient_examination_id"):
|
|
307
|
+
logger.error(
|
|
308
|
+
f"Invalid lookup data for token {token}: patient_examination_id is empty. Data: {data}"
|
|
309
|
+
)
|
|
310
|
+
raise ValueError(
|
|
311
|
+
f"Invalid lookup data for token {token}: patient_examination_id is empty"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
pe_id = data["patient_examination_id"]
|
|
315
|
+
logger.debug(f"Loading patient examination {pe_id} for token {token}")
|
|
316
|
+
|
|
317
|
+
try:
|
|
318
|
+
pe = load_patient_exam_for_eval(pe_id)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(
|
|
321
|
+
f"Failed to load patient examination {pe_id} for token {token}: {e}"
|
|
322
|
+
)
|
|
323
|
+
raise ValueError(f"Failed to load patient examination {pe_id}: {e}")
|
|
324
|
+
|
|
325
|
+
selected_rs_ids: List[int] = data.get("selectedRequirementSetIds", [])
|
|
326
|
+
logger.debug(
|
|
327
|
+
f"Selected requirement set IDs for token {token}: {selected_rs_ids}"
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
rs_objs = [
|
|
331
|
+
rs
|
|
332
|
+
for rs in requirement_sets_for_patient_exam(pe)
|
|
333
|
+
if rs.id in selected_rs_ids
|
|
334
|
+
]
|
|
335
|
+
logger.debug(f"Found {len(rs_objs)} requirement set objects for token {token}")
|
|
336
|
+
|
|
337
|
+
# 1) requirements grouped by set (already prefetched in load func)
|
|
338
|
+
requirements_by_set = {
|
|
339
|
+
rs.id: [{"id": r.id, "name": r.name} for r in rs.requirements.all()]
|
|
340
|
+
for rs in rs_objs
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
# 2) status per requirement + set status
|
|
344
|
+
requirement_status: Dict[str, bool] = {}
|
|
345
|
+
set_status: Dict[str, bool] = {}
|
|
346
|
+
for rs in rs_objs:
|
|
347
|
+
req_results = []
|
|
348
|
+
for r in rs.requirements.all():
|
|
349
|
+
ok = bool(r.evaluate(pe, mode="strict")) # or "loose" if you prefer
|
|
350
|
+
requirement_status[str(r.id)] = ok
|
|
351
|
+
req_results.append(ok)
|
|
352
|
+
set_status[str(rs.id)] = (
|
|
353
|
+
rs.eval_function(req_results) if rs.eval_function else all(req_results)
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# 3) suggestions per requirement (defaults + classification choices you already expose)
|
|
357
|
+
suggested_actions: Dict[str, List[Dict[str, Any]]] = {}
|
|
358
|
+
req_defaults: Dict[str, Any] = {}
|
|
359
|
+
cls_choices: Dict[str, Any] = {}
|
|
360
|
+
|
|
361
|
+
for rs in rs_objs:
|
|
362
|
+
for r in rs.requirements.all():
|
|
363
|
+
defaults = getattr(r, "default_findings", lambda pe: [])(
|
|
364
|
+
pe
|
|
365
|
+
) # [{finding_id, payload...}]
|
|
366
|
+
choices = getattr(r, "classification_choices", lambda pe: [])(
|
|
367
|
+
pe
|
|
368
|
+
) # [{classification_id, label,...}]
|
|
369
|
+
if defaults:
|
|
370
|
+
req_defaults[str(r.id)] = defaults
|
|
371
|
+
if choices:
|
|
372
|
+
cls_choices[str(r.id)] = choices
|
|
373
|
+
|
|
374
|
+
if not requirement_status.get(str(r.id), False):
|
|
375
|
+
# turn default proposals into explicit UI actions
|
|
376
|
+
acts = []
|
|
377
|
+
for d in defaults or []:
|
|
378
|
+
acts.append(
|
|
379
|
+
{
|
|
380
|
+
"type": "add_finding",
|
|
381
|
+
"finding_id": d.get("finding_id"),
|
|
382
|
+
"classification_ids": d.get("classification_ids") or [],
|
|
383
|
+
"note": "default",
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
# If r expects patient edits, add an edit action hint
|
|
387
|
+
if "PatientExamination" in [m.__name__ for m in r.expected_models]:
|
|
388
|
+
acts.append(
|
|
389
|
+
{"type": "edit_patient", "fields": ["gender", "dob"]}
|
|
390
|
+
) # example
|
|
391
|
+
if acts:
|
|
392
|
+
suggested_actions[str(r.id)] = acts
|
|
393
|
+
|
|
394
|
+
# 4) (optional) staged changes simulation hook (see §3)
|
|
395
|
+
# staged = data.get("staged", {})
|
|
396
|
+
# if you implement server-side simulation later, adjust requirement_status with staged result here
|
|
397
|
+
|
|
398
|
+
updates = {
|
|
399
|
+
"requirements_by_set": requirements_by_set,
|
|
400
|
+
"requirement_status": requirement_status,
|
|
401
|
+
"requirement_set_status": set_status,
|
|
402
|
+
"requirement_defaults": req_defaults, # keep your existing key
|
|
403
|
+
"classification_choices": cls_choices, # keep your existing key
|
|
404
|
+
"suggested_actions": suggested_actions, # new
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
logger.debug(
|
|
408
|
+
f"Updating store for token {token} with {len(updates)} update keys"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Only write if changed (idempotent)
|
|
412
|
+
prev_derived = store.get_many(list(updates.keys()))
|
|
413
|
+
if prev_derived != updates:
|
|
414
|
+
store.set_many(updates) # <-- does NOT call recompute
|
|
415
|
+
logger.debug(f"Derived data changed, updated store for token {token}")
|
|
416
|
+
else:
|
|
417
|
+
logger.debug(
|
|
418
|
+
f"Derived data unchanged, skipping store update for token {token}"
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
store.mark_recompute_done()
|
|
422
|
+
return updates
|
|
423
|
+
finally:
|
|
424
|
+
store.set("_recomputing", False)
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# services/lookup_store.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import uuid
|
|
5
|
+
from typing import Any, Dict, Iterable, Optional
|
|
6
|
+
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
from django.core.cache import cache
|
|
9
|
+
|
|
10
|
+
# Align TTL with Django cache TIMEOUT for consistency in tests and runtime
|
|
11
|
+
try:
|
|
12
|
+
DEFAULT_TTL_SECONDS = int(
|
|
13
|
+
settings.CACHES.get("default", {}).get("TIMEOUT", 60 * 30)
|
|
14
|
+
)
|
|
15
|
+
except Exception:
|
|
16
|
+
DEFAULT_TTL_SECONDS = 60 * 30 # 30 minutes fallback
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LookupStore:
|
|
20
|
+
"""
|
|
21
|
+
Server-side storage for lookup session data using Django cache.
|
|
22
|
+
|
|
23
|
+
This class manages token-based sessions for the lookup system, providing
|
|
24
|
+
a cache-backed storage layer that allows clients to maintain state across
|
|
25
|
+
multiple API requests. Each session is identified by a unique token and
|
|
26
|
+
stores derived lookup data including requirement evaluations, statuses,
|
|
27
|
+
and suggested actions.
|
|
28
|
+
|
|
29
|
+
Key features:
|
|
30
|
+
- Token-based session management with automatic UUID generation
|
|
31
|
+
- Django cache integration with configurable TTL
|
|
32
|
+
- Data validation and recovery for corrupted sessions
|
|
33
|
+
- Reentrancy protection for recomputation operations
|
|
34
|
+
- Atomic updates to prevent data corruption
|
|
35
|
+
|
|
36
|
+
The store uses Django's default cache backend and aligns TTL settings
|
|
37
|
+
with Django's cache configuration for consistency across environments.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, token: Optional[str] = None):
|
|
41
|
+
"""
|
|
42
|
+
Initialize a LookupStore instance with an optional token.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
token: Optional session token. If not provided, a new UUID token
|
|
46
|
+
will be generated automatically.
|
|
47
|
+
"""
|
|
48
|
+
self.token = token or uuid.uuid4().hex
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def cache_key(self) -> str:
|
|
52
|
+
"""
|
|
53
|
+
Generate the cache key for this lookup session.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Cache key string in format 'lookup:{token}'
|
|
57
|
+
"""
|
|
58
|
+
return f"lookup:{self.token}"
|
|
59
|
+
|
|
60
|
+
def init(
|
|
61
|
+
self, initial: Optional[Dict[str, Any]] = None, ttl: int = DEFAULT_TTL_SECONDS
|
|
62
|
+
) -> str:
|
|
63
|
+
"""
|
|
64
|
+
Initialize a new lookup session in cache.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
initial: Optional initial data dictionary to store
|
|
68
|
+
ttl: Time-to-live in seconds for the cache entry
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The session token for this lookup store
|
|
72
|
+
"""
|
|
73
|
+
cache.set(self.cache_key, initial or {}, ttl)
|
|
74
|
+
return self.token
|
|
75
|
+
|
|
76
|
+
def get_all(self) -> Dict[str, Any]:
|
|
77
|
+
"""
|
|
78
|
+
Retrieve all data for this lookup session.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Complete dictionary of stored lookup data, or empty dict if not found
|
|
82
|
+
"""
|
|
83
|
+
return cache.get(self.cache_key, {})
|
|
84
|
+
|
|
85
|
+
def get_many(self, keys: Iterable[str]) -> Dict[str, Any]:
|
|
86
|
+
"""
|
|
87
|
+
Retrieve multiple specific keys from the lookup session.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
keys: Iterable of key names to retrieve
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Dictionary containing only the requested keys and their values
|
|
94
|
+
"""
|
|
95
|
+
data = self.get_all()
|
|
96
|
+
return {k: data.get(k) for k in keys}
|
|
97
|
+
|
|
98
|
+
def set_many(self, updates: Dict[str, Any], ttl: int = DEFAULT_TTL_SECONDS) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Update multiple keys in the lookup session atomically.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
updates: Dictionary of key-value pairs to update
|
|
104
|
+
ttl: Time-to-live in seconds for the updated cache entry
|
|
105
|
+
"""
|
|
106
|
+
data = self.get_all()
|
|
107
|
+
data.update(updates)
|
|
108
|
+
cache.set(self.cache_key, data, ttl)
|
|
109
|
+
|
|
110
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
111
|
+
"""
|
|
112
|
+
Retrieve a single key from the lookup session.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
key: Key name to retrieve
|
|
116
|
+
default: Default value if key not found
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Value of the key, or default if not found
|
|
120
|
+
"""
|
|
121
|
+
return self.get_all().get(key, default)
|
|
122
|
+
|
|
123
|
+
def set(self, key: str, value: Any, ttl: int = DEFAULT_TTL_SECONDS) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Set a single key in the lookup session.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
key: Key name to set
|
|
129
|
+
value: Value to store
|
|
130
|
+
ttl: Time-to-live in seconds for the updated cache entry
|
|
131
|
+
"""
|
|
132
|
+
data = self.get_all()
|
|
133
|
+
data[key] = value
|
|
134
|
+
cache.set(self.cache_key, data, ttl)
|
|
135
|
+
|
|
136
|
+
def delete(self) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Delete the entire lookup session from cache.
|
|
139
|
+
"""
|
|
140
|
+
cache.delete(self.cache_key)
|
|
141
|
+
|
|
142
|
+
def patch(self, updates: Dict[str, Any], ttl: int = DEFAULT_TTL_SECONDS) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Update existing data with new values (alias for set_many).
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
updates: Dictionary of key-value pairs to update
|
|
148
|
+
ttl: Time-to-live in seconds for the updated cache entry
|
|
149
|
+
"""
|
|
150
|
+
data = self.get_all()
|
|
151
|
+
data.update(updates)
|
|
152
|
+
cache.set(self.cache_key, data, ttl)
|
|
153
|
+
|
|
154
|
+
def validate_and_recover_data(self, token):
|
|
155
|
+
"""
|
|
156
|
+
Validate stored lookup data and attempt recovery if corrupted.
|
|
157
|
+
|
|
158
|
+
Checks for required fields and attempts to recover missing data,
|
|
159
|
+
particularly the patient_examination_id. Logs warnings for missing
|
|
160
|
+
fields but does not trigger automatic recomputation to avoid loops.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
token: Session token for logging purposes
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Validated data dictionary, or None if no data exists
|
|
167
|
+
"""
|
|
168
|
+
data = self.get_all()
|
|
169
|
+
|
|
170
|
+
if not data:
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
# Check if required fields are present
|
|
174
|
+
required_fields = [
|
|
175
|
+
"patient_examination_id",
|
|
176
|
+
"requirements_by_set",
|
|
177
|
+
"requirement_status",
|
|
178
|
+
]
|
|
179
|
+
missing_fields = [field for field in required_fields if field not in data]
|
|
180
|
+
|
|
181
|
+
if missing_fields:
|
|
182
|
+
import logging
|
|
183
|
+
|
|
184
|
+
logger = logging.getLogger(__name__)
|
|
185
|
+
logger.warning(
|
|
186
|
+
f"Missing fields in lookup data for token {token}: {missing_fields}"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Try to recover patient_examination_id from token or related data
|
|
190
|
+
if "patient_examination_id" in missing_fields:
|
|
191
|
+
# Attempt to extract from token or find related examination
|
|
192
|
+
recovered_id = self._recover_patient_examination_id(token)
|
|
193
|
+
if recovered_id:
|
|
194
|
+
data["patient_examination_id"] = recovered_id
|
|
195
|
+
logger.info(
|
|
196
|
+
f"Recovered patient_examination_id {recovered_id} for token {token}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Do not automatically recompute here to avoid loops
|
|
200
|
+
# Recompute is only triggered by PATCH or explicit POST /recompute/
|
|
201
|
+
# For now, just return the data as is
|
|
202
|
+
|
|
203
|
+
return data
|
|
204
|
+
|
|
205
|
+
def _recover_patient_examination_id(self, token: str) -> Optional[str]:
|
|
206
|
+
"""
|
|
207
|
+
Attempt to recover the patient examination ID for corrupted sessions.
|
|
208
|
+
|
|
209
|
+
This is a placeholder implementation. In a real system, this might
|
|
210
|
+
query a database or another service to find the examination ID
|
|
211
|
+
associated with the token.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
token: Session token
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Recovered patient examination ID, or None if recovery fails
|
|
218
|
+
"""
|
|
219
|
+
# In a real implementation, you might query a database or another service.
|
|
220
|
+
# For now, we return None as recovery logic is not defined.
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
def should_recompute(self, token):
|
|
224
|
+
"""
|
|
225
|
+
Determine if recomputation is needed based on data freshness.
|
|
226
|
+
|
|
227
|
+
Checks the last recomputation timestamp and only allows recomputation
|
|
228
|
+
if more than 30 seconds have passed since the last one. This prevents
|
|
229
|
+
excessive recomputation while allowing for necessary updates.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
token: Session token (for future use)
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
True if recomputation should be performed, False otherwise
|
|
236
|
+
"""
|
|
237
|
+
data = self.get_all()
|
|
238
|
+
if not data:
|
|
239
|
+
return True
|
|
240
|
+
|
|
241
|
+
# Check if we have a last_recompute timestamp
|
|
242
|
+
last_recompute = data.get("_last_recompute")
|
|
243
|
+
if not last_recompute:
|
|
244
|
+
return True
|
|
245
|
+
|
|
246
|
+
# Only recompute if it's been more than 30 seconds since last recompute
|
|
247
|
+
# This prevents excessive recomputation while allowing for updates
|
|
248
|
+
from datetime import datetime, timedelta
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
last_recompute_time = datetime.fromisoformat(last_recompute)
|
|
252
|
+
return datetime.now() - last_recompute_time > timedelta(seconds=30)
|
|
253
|
+
except (ValueError, TypeError):
|
|
254
|
+
return True
|
|
255
|
+
|
|
256
|
+
def mark_recompute_done(self):
|
|
257
|
+
"""
|
|
258
|
+
Mark that recomputation has been completed by updating the timestamp.
|
|
259
|
+
|
|
260
|
+
Sets the _last_recompute field to the current timestamp in ISO format.
|
|
261
|
+
This timestamp is used by should_recompute() to determine if another
|
|
262
|
+
recomputation is needed.
|
|
263
|
+
"""
|
|
264
|
+
from datetime import datetime
|
|
265
|
+
|
|
266
|
+
self.set("_last_recompute", datetime.now().isoformat())
|