endoreg-db 0.6.0__py3-none-any.whl → 0.6.2__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/case_generator/__init__.py +0 -0
- endoreg_db/case_generator/case_generator.py +159 -0
- endoreg_db/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/case_generator/utils.py +30 -0
- endoreg_db/data/__init__.py +118 -0
- endoreg_db/data/agl_service/data.yaml +19 -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-set/data.yaml +21 -0
- endoreg_db/data/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +5 -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 +90 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +6 -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 +47 -0
- endoreg_db/data/event/cardiology.yaml +28 -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 +66 -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 +5 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/finding/data.yaml +141 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +138 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_location_classification/colonoscopy.yaml +46 -0
- endoreg_db/data/finding_location_classification_choice/colonoscopy.yaml +240 -0
- endoreg_db/data/finding_morphology_classification/colonoscopy.yaml +48 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_circularity_default.yaml +34 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_nice.yaml +20 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_paris.yaml +65 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_planarity_default.yaml +56 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_surface_intact_default.yaml +39 -0
- endoreg_db/data/finding_morphology_classification_choice/colonoscopy_size.yaml +57 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +30 -0
- endoreg_db/data/gender/data.yaml +35 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/medication.yaml +6 -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 +33 -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 +51 -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 +29 -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/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +19 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -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 +92 -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 +13 -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/forms/__init__.py +5 -0
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +19 -0
- endoreg_db/forms/patient_form.py +26 -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/management/__init__.py +0 -0
- endoreg_db/management/commands/__init__.py +0 -0
- endoreg_db/management/commands/_load_model_template.py +41 -0
- endoreg_db/management/commands/delete_all.py +18 -0
- endoreg_db/management/commands/fetch_legacy_image_dataset.py +32 -0
- endoreg_db/management/commands/fix_auth_permission.py +20 -0
- endoreg_db/management/commands/load_active_model_data.py +45 -0
- endoreg_db/management/commands/load_ai_model_data.py +79 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +178 -0
- endoreg_db/management/commands/load_center_data.py +43 -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 +65 -0
- endoreg_db/management/commands/load_finding_data.py +171 -0
- endoreg_db/management/commands/load_g_play_data.py +113 -0
- endoreg_db/management/commands/load_gender_data.py +44 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +133 -0
- endoreg_db/management/commands/load_information_source.py +45 -0
- endoreg_db/management/commands/load_lab_value_data.py +50 -0
- endoreg_db/management/commands/load_logging_data.py +39 -0
- endoreg_db/management/commands/load_lx_data.py +64 -0
- endoreg_db/management/commands/load_medication_data.py +103 -0
- endoreg_db/management/commands/load_medication_indication_data.py +63 -0
- endoreg_db/management/commands/load_medication_indication_type_data.py +41 -0
- endoreg_db/management/commands/load_medication_intake_time_data.py +41 -0
- endoreg_db/management/commands/load_medication_schedule_data.py +55 -0
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/load_network_data.py +57 -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_report_reader_flag_data.py +46 -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/migrations/0001_initial.py +2045 -0
- endoreg_db/migrations/0002_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0003_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0004_alter_rawvideofile_file_alter_video_file.py +25 -0
- endoreg_db/migrations/0005_rawvideofile_frame_count_and_more.py +33 -0
- endoreg_db/migrations/0006_frame_extracted_rawframe_extracted.py +23 -0
- endoreg_db/migrations/0007_rename_pseudo_patient_video_patient_and_more.py +24 -0
- endoreg_db/migrations/0008_remove_reportfile_patient_examination_and_more.py +48 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +376 -0
- endoreg_db/models/ai_model/__init__.py +4 -0
- endoreg_db/models/ai_model/active_model.py +9 -0
- endoreg_db/models/ai_model/ai_model.py +103 -0
- endoreg_db/models/ai_model/lightning/__init__.py +3 -0
- endoreg_db/models/ai_model/lightning/inference_dataset.py +53 -0
- endoreg_db/models/ai_model/lightning/multilabel_classification_net.py +155 -0
- endoreg_db/models/ai_model/lightning/postprocess.py +53 -0
- endoreg_db/models/ai_model/lightning/predict.py +172 -0
- endoreg_db/models/ai_model/lightning/prediction_visualizer.py +55 -0
- endoreg_db/models/ai_model/lightning/preprocess.py +68 -0
- endoreg_db/models/ai_model/lightning/run_visualizer.py +21 -0
- endoreg_db/models/ai_model/model_meta.py +250 -0
- endoreg_db/models/ai_model/model_type.py +36 -0
- endoreg_db/models/ai_model/utils.py +8 -0
- endoreg_db/models/annotation/__init__.py +32 -0
- endoreg_db/models/annotation/anonymized_image_annotation.py +115 -0
- endoreg_db/models/annotation/binary_classification_annotation_task.py +117 -0
- endoreg_db/models/annotation/image_classification.py +86 -0
- endoreg_db/models/annotation/video_segmentation_annotation.py +52 -0
- endoreg_db/models/annotation/video_segmentation_labelset.py +20 -0
- endoreg_db/models/case/__init__.py +1 -0
- endoreg_db/models/case/case.py +34 -0
- endoreg_db/models/case_template/__init__.py +15 -0
- endoreg_db/models/case_template/case_template.py +125 -0
- endoreg_db/models/case_template/case_template_rule.py +276 -0
- endoreg_db/models/case_template/case_template_rule_value.py +88 -0
- endoreg_db/models/case_template/case_template_type.py +28 -0
- endoreg_db/models/center/__init__.py +11 -0
- endoreg_db/models/center/center.py +51 -0
- endoreg_db/models/center/center_product.py +33 -0
- endoreg_db/models/center/center_resource.py +33 -0
- endoreg_db/models/center/center_waste.py +16 -0
- endoreg_db/models/contraindication/__init__.py +21 -0
- endoreg_db/models/data_file/__init__.py +39 -0
- endoreg_db/models/data_file/base_classes/__init__.py +7 -0
- endoreg_db/models/data_file/base_classes/abstract_frame.py +100 -0
- endoreg_db/models/data_file/base_classes/abstract_pdf.py +136 -0
- endoreg_db/models/data_file/base_classes/abstract_video.py +807 -0
- endoreg_db/models/data_file/base_classes/frame_helpers.py +17 -0
- endoreg_db/models/data_file/base_classes/prepare_bulk_frames.py +19 -0
- endoreg_db/models/data_file/base_classes/utils.py +80 -0
- endoreg_db/models/data_file/frame.py +29 -0
- endoreg_db/models/data_file/import_classes/__init__.py +18 -0
- endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +35 -0
- endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +28 -0
- endoreg_db/models/data_file/import_classes/processing_functions/video.py +260 -0
- endoreg_db/models/data_file/import_classes/raw_pdf.py +260 -0
- endoreg_db/models/data_file/import_classes/raw_video.py +288 -0
- endoreg_db/models/data_file/metadata/__init__.py +13 -0
- endoreg_db/models/data_file/metadata/pdf_meta.py +74 -0
- endoreg_db/models/data_file/metadata/sensitive_meta.py +290 -0
- endoreg_db/models/data_file/metadata/video_meta.py +199 -0
- endoreg_db/models/data_file/report_file.py +56 -0
- endoreg_db/models/data_file/video/__init__.py +11 -0
- endoreg_db/models/data_file/video/import_meta.py +25 -0
- endoreg_db/models/data_file/video/video.py +196 -0
- endoreg_db/models/data_file/video_segment.py +214 -0
- endoreg_db/models/disease.py +79 -0
- endoreg_db/models/emission/__init__.py +5 -0
- endoreg_db/models/emission/emission_factor.py +85 -0
- endoreg_db/models/event.py +73 -0
- endoreg_db/models/examination/__init__.py +9 -0
- endoreg_db/models/examination/examination.py +67 -0
- endoreg_db/models/examination/examination_indication.py +170 -0
- endoreg_db/models/examination/examination_time.py +53 -0
- endoreg_db/models/examination/examination_time_type.py +48 -0
- endoreg_db/models/examination/examination_type.py +40 -0
- endoreg_db/models/finding/__init__.py +11 -0
- endoreg_db/models/finding/finding.py +75 -0
- endoreg_db/models/finding/finding_intervention.py +60 -0
- endoreg_db/models/finding/finding_location_classification.py +94 -0
- endoreg_db/models/finding/finding_morphology_classification.py +89 -0
- endoreg_db/models/finding/finding_type.py +22 -0
- endoreg_db/models/hardware/__init__.py +2 -0
- endoreg_db/models/hardware/endoscope.py +60 -0
- endoreg_db/models/hardware/endoscopy_processor.py +155 -0
- endoreg_db/models/information_source.py +29 -0
- endoreg_db/models/label/__init__.py +1 -0
- endoreg_db/models/label/label.py +112 -0
- endoreg_db/models/laboratory/__init__.py +1 -0
- endoreg_db/models/laboratory/lab_value.py +111 -0
- endoreg_db/models/logging/__init__.py +11 -0
- endoreg_db/models/logging/agl_service.py +19 -0
- endoreg_db/models/logging/base.py +22 -0
- endoreg_db/models/logging/log_type.py +23 -0
- endoreg_db/models/logging/network_device.py +27 -0
- endoreg_db/models/lx/__init__.py +4 -0
- endoreg_db/models/lx/client.py +57 -0
- endoreg_db/models/lx/identity.py +34 -0
- endoreg_db/models/lx/permission.py +18 -0
- endoreg_db/models/lx/user.py +16 -0
- endoreg_db/models/medication/__init__.py +19 -0
- endoreg_db/models/medication/medication.py +33 -0
- endoreg_db/models/medication/medication_indication.py +50 -0
- endoreg_db/models/medication/medication_indication_type.py +34 -0
- endoreg_db/models/medication/medication_intake_time.py +26 -0
- endoreg_db/models/medication/medication_schedule.py +37 -0
- endoreg_db/models/network/__init__.py +9 -0
- endoreg_db/models/network/agl_service.py +38 -0
- endoreg_db/models/network/network_device.py +58 -0
- endoreg_db/models/network/network_device_type.py +23 -0
- endoreg_db/models/organ/__init__.py +38 -0
- endoreg_db/models/other/__init__.py +23 -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 +91 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +97 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/distribution.py +5 -0
- endoreg_db/models/other/material.py +20 -0
- endoreg_db/models/other/resource.py +18 -0
- endoreg_db/models/other/transport_route.py +22 -0
- endoreg_db/models/other/waste.py +20 -0
- endoreg_db/models/patient/__init__.py +24 -0
- endoreg_db/models/patient/patient_examination.py +182 -0
- endoreg_db/models/patient/patient_finding.py +143 -0
- endoreg_db/models/patient/patient_finding_intervention.py +26 -0
- endoreg_db/models/patient/patient_finding_location.py +120 -0
- endoreg_db/models/patient/patient_finding_morphology.py +166 -0
- endoreg_db/models/permissions/__init__.py +44 -0
- endoreg_db/models/persons/__init__.py +34 -0
- endoreg_db/models/persons/examiner/__init__.py +2 -0
- endoreg_db/models/persons/examiner/examiner.py +60 -0
- endoreg_db/models/persons/examiner/examiner_type.py +2 -0
- endoreg_db/models/persons/first_name.py +18 -0
- endoreg_db/models/persons/gender.py +22 -0
- endoreg_db/models/persons/last_name.py +20 -0
- endoreg_db/models/persons/patient/__init__.py +8 -0
- endoreg_db/models/persons/patient/patient.py +389 -0
- endoreg_db/models/persons/patient/patient_disease.py +22 -0
- endoreg_db/models/persons/patient/patient_event.py +52 -0
- endoreg_db/models/persons/patient/patient_examination_indication.py +32 -0
- endoreg_db/models/persons/patient/patient_lab_sample.py +108 -0
- endoreg_db/models/persons/patient/patient_lab_value.py +197 -0
- endoreg_db/models/persons/patient/patient_medication.py +59 -0
- endoreg_db/models/persons/patient/patient_medication_schedule.py +88 -0
- endoreg_db/models/persons/person.py +31 -0
- endoreg_db/models/persons/portal_user_information.py +27 -0
- endoreg_db/models/prediction/__init__.py +8 -0
- endoreg_db/models/prediction/image_classification.py +51 -0
- endoreg_db/models/prediction/video_prediction_meta.py +306 -0
- endoreg_db/models/product/__init__.py +14 -0
- endoreg_db/models/product/product.py +110 -0
- endoreg_db/models/product/product_group.py +27 -0
- endoreg_db/models/product/product_material.py +28 -0
- endoreg_db/models/product/product_weight.py +38 -0
- endoreg_db/models/product/reference_product.py +115 -0
- endoreg_db/models/questionnaires/__init__.py +114 -0
- endoreg_db/models/quiz/__init__.py +9 -0
- endoreg_db/models/quiz/quiz_answer.py +41 -0
- endoreg_db/models/quiz/quiz_question.py +54 -0
- endoreg_db/models/report_reader/__init__.py +7 -0
- endoreg_db/models/report_reader/report_reader_config.py +53 -0
- endoreg_db/models/report_reader/report_reader_flag.py +20 -0
- endoreg_db/models/rules/__init__.py +5 -0
- endoreg_db/models/rules/rule.py +24 -0
- endoreg_db/models/rules/rule_applicator.py +224 -0
- endoreg_db/models/rules/rule_attribute_dtype.py +19 -0
- endoreg_db/models/rules/rule_type.py +22 -0
- endoreg_db/models/rules/ruleset.py +19 -0
- endoreg_db/models/unit.py +22 -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/get/__init__.py +6 -0
- endoreg_db/queries/get/annotation.py +0 -0
- endoreg_db/queries/get/center.py +42 -0
- endoreg_db/queries/get/model.py +13 -0
- endoreg_db/queries/get/patient.py +14 -0
- endoreg_db/queries/get/patient_examination.py +20 -0
- endoreg_db/queries/get/prediction.py +0 -0
- endoreg_db/queries/get/report_file.py +33 -0
- endoreg_db/queries/get/video.py +31 -0
- endoreg_db/queries/get/video_import_meta.py +0 -0
- endoreg_db/queries/get/video_prediction_meta.py +0 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- endoreg_db/serializers/__init__.py +10 -0
- endoreg_db/serializers/ai_model.py +19 -0
- endoreg_db/serializers/annotation.py +14 -0
- endoreg_db/serializers/center.py +11 -0
- endoreg_db/serializers/examination.py +33 -0
- endoreg_db/serializers/frame.py +9 -0
- endoreg_db/serializers/hardware.py +21 -0
- endoreg_db/serializers/label.py +22 -0
- endoreg_db/serializers/patient.py +33 -0
- endoreg_db/serializers/prediction.py +10 -0
- endoreg_db/serializers/raw_video_meta_validation.py +13 -0
- endoreg_db/serializers/report_file.py +7 -0
- endoreg_db/serializers/video.py +20 -0
- endoreg_db/serializers/video_segmentation.py +492 -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/utils/__init__.py +36 -0
- endoreg_db/utils/cropping.py +29 -0
- endoreg_db/utils/dataloader.py +118 -0
- endoreg_db/utils/dates.py +39 -0
- endoreg_db/utils/file_operations.py +30 -0
- endoreg_db/utils/hashs.py +152 -0
- endoreg_db/utils/legacy_ocr.py +201 -0
- endoreg_db/utils/names.py +74 -0
- endoreg_db/utils/ocr.py +190 -0
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -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/video/__init__.py +13 -0
- endoreg_db/utils/video/extract_frames.py +121 -0
- endoreg_db/utils/video/transcode_videofile.py +111 -0
- endoreg_db/views/__init__.py +2 -0
- endoreg_db/views/csrf.py +7 -0
- endoreg_db/views/patient_views.py +90 -0
- endoreg_db/views/raw_video_meta_validation_views.py +38 -0
- endoreg_db/views/report_views.py +96 -0
- endoreg_db/views/video_segmentation_views.py +149 -0
- endoreg_db/views/views_for_timeline.py +46 -0
- {endoreg_db-0.6.0.dist-info → endoreg_db-0.6.2.dist-info}/METADATA +14 -4
- endoreg_db-0.6.2.dist-info/RECORD +420 -0
- {endoreg_db-0.6.0.dist-info → endoreg_db-0.6.2.dist-info}/WHEEL +1 -2
- endoreg_db-0.6.0.dist-info/RECORD +0 -11
- endoreg_db-0.6.0.dist-info/top_level.txt +0 -1
- {endoreg_db-0.6.0.dist-info → endoreg_db-0.6.2.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'''Model for date value distribution'''
|
|
2
|
+
|
|
3
|
+
from datetime import date, timedelta
|
|
4
|
+
from django.db import models
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .base_value_distribution import BaseValueDistribution
|
|
8
|
+
|
|
9
|
+
class DateValueDistributionManager(models.Manager):
|
|
10
|
+
'''Object manager for DateValueDistribution'''
|
|
11
|
+
def get_by_natural_key(self, name):
|
|
12
|
+
'''Retrieve a DateValueDistribution by its natural key.'''
|
|
13
|
+
return self.get(name=name)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DateValueDistribution(BaseValueDistribution):
|
|
17
|
+
"""
|
|
18
|
+
Assign date values based on specified distribution.
|
|
19
|
+
Expects distribution_type (uniform, normal) and mode (date, timedelta) and based on this either
|
|
20
|
+
date_min, date_max, date_mean, date_std_dev or
|
|
21
|
+
timedelta_days_min, timedelta_days_max, timedelta_days_mean, timedelta_days_std_dev
|
|
22
|
+
"""
|
|
23
|
+
objects = DateValueDistributionManager()
|
|
24
|
+
name = models.CharField(max_length=100)
|
|
25
|
+
name_de = models.CharField(max_length=100, blank=True, null=True)
|
|
26
|
+
name_en = models.CharField(max_length=100, blank=True, null=True)
|
|
27
|
+
description = models.TextField(blank=True, null=True)
|
|
28
|
+
DISTRIBUTION_CHOICES = [
|
|
29
|
+
('uniform', 'Uniform'),
|
|
30
|
+
('normal', 'Normal'),
|
|
31
|
+
]
|
|
32
|
+
MODE_CHOICES = [
|
|
33
|
+
('date', 'Date'),
|
|
34
|
+
('timedelta', 'Timedelta'),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
distribution_type = models.CharField(max_length=20, choices=DISTRIBUTION_CHOICES)
|
|
38
|
+
mode = models.CharField(max_length=20, choices=MODE_CHOICES)
|
|
39
|
+
|
|
40
|
+
# Date-related fields
|
|
41
|
+
date_min = models.DateField(blank=True, null=True)
|
|
42
|
+
date_max = models.DateField(blank=True, null=True)
|
|
43
|
+
date_mean = models.DateField(blank=True, null=True)
|
|
44
|
+
date_std_dev = models.IntegerField(blank=True, null=True) # Standard deviation in days
|
|
45
|
+
|
|
46
|
+
# Timedelta-related fields
|
|
47
|
+
timedelta_days_min = models.IntegerField(blank=True, null=True)
|
|
48
|
+
timedelta_days_max = models.IntegerField(blank=True, null=True)
|
|
49
|
+
timedelta_days_mean = models.IntegerField(blank=True, null=True)
|
|
50
|
+
timedelta_days_std_dev = models.IntegerField(blank=True, null=True)
|
|
51
|
+
|
|
52
|
+
def generate_value(self):
|
|
53
|
+
if self.mode == 'date':
|
|
54
|
+
return self._generate_date_value()
|
|
55
|
+
elif self.mode == 'timedelta':
|
|
56
|
+
return self._generate_timedelta_value()
|
|
57
|
+
else:
|
|
58
|
+
raise ValueError("Unsupported mode")
|
|
59
|
+
|
|
60
|
+
def _generate_date_value(self):
|
|
61
|
+
#UNTESTED
|
|
62
|
+
if self.distribution_type == 'uniform':
|
|
63
|
+
start_date = self.date_min.toordinal()
|
|
64
|
+
end_date = self.date_max.toordinal()
|
|
65
|
+
random_ordinal = np.random.randint(start_date, end_date)
|
|
66
|
+
return date.fromordinal(random_ordinal)
|
|
67
|
+
elif self.distribution_type == 'normal':
|
|
68
|
+
mean_ordinal = self.date_mean.toordinal()
|
|
69
|
+
std_dev_days = self.date_std_dev
|
|
70
|
+
random_ordinal = int(np.random.normal(mean_ordinal, std_dev_days))
|
|
71
|
+
random_ordinal = np.clip(random_ordinal, self.date_min.toordinal(), self.date_max.toordinal())
|
|
72
|
+
return date.fromordinal(random_ordinal)
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError("Unsupported distribution type")
|
|
75
|
+
|
|
76
|
+
def _generate_timedelta_value(self):
|
|
77
|
+
if self.distribution_type == 'uniform':
|
|
78
|
+
random_days = np.random.randint(self.timedelta_days_min, self.timedelta_days_max + 1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
elif self.distribution_type == 'normal':
|
|
82
|
+
random_days = int(np.random.normal(self.timedelta_days_mean, self.timedelta_days_std_dev))
|
|
83
|
+
random_days = np.clip(random_days, self.timedelta_days_min, self.timedelta_days_max)
|
|
84
|
+
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("Unsupported distribution type")
|
|
87
|
+
|
|
88
|
+
current_date = date.today()
|
|
89
|
+
generated_date = current_date - timedelta(days=random_days)
|
|
90
|
+
print(generated_date)
|
|
91
|
+
return(generated_date)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
import numpy as np
|
|
3
|
+
from .base_value_distribution import BaseValueDistribution
|
|
4
|
+
|
|
5
|
+
class MultipleCategoricalValueDistributionManager(models.Manager):
|
|
6
|
+
def get_by_natural_key(self, name):
|
|
7
|
+
return self.get(name=name)
|
|
8
|
+
|
|
9
|
+
class MultipleCategoricalValueDistribution(BaseValueDistribution):
|
|
10
|
+
"""
|
|
11
|
+
Multiple categorical value distribution model.
|
|
12
|
+
Assigns a specific number or varying number of values based on probabilities.
|
|
13
|
+
"""
|
|
14
|
+
objects = MultipleCategoricalValueDistributionManager()
|
|
15
|
+
categories = models.JSONField() # { "category": "probability", ... }
|
|
16
|
+
min_count = models.IntegerField()
|
|
17
|
+
max_count = models.IntegerField()
|
|
18
|
+
count_distribution_type = models.CharField(max_length=20, choices=[('uniform', 'Uniform'), ('normal', 'Normal')])
|
|
19
|
+
count_mean = models.FloatField(null=True, blank=True)
|
|
20
|
+
count_std_dev = models.FloatField(null=True, blank=True)
|
|
21
|
+
|
|
22
|
+
def generate_value(self):
|
|
23
|
+
if self.count_distribution_type == 'uniform':
|
|
24
|
+
count = np.random.randint(self.min_count, self.max_count + 1)
|
|
25
|
+
elif self.count_distribution_type == 'normal':
|
|
26
|
+
count = int(np.random.normal(self.count_mean, self.count_std_dev))
|
|
27
|
+
count = np.clip(count, self.min_count, self.max_count)
|
|
28
|
+
else:
|
|
29
|
+
raise ValueError("Unsupported count distribution type")
|
|
30
|
+
|
|
31
|
+
categories, probabilities = zip(*self.categories.items())
|
|
32
|
+
return list(np.random.choice(categories, size=count, p=probabilities))
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'''Model for numeric value distribution'''
|
|
2
|
+
|
|
3
|
+
from django.db import models
|
|
4
|
+
import numpy as np
|
|
5
|
+
from .base_value_distribution import BaseValueDistribution
|
|
6
|
+
from scipy.stats import skewnorm
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NumericValueDistributionManager(models.Manager):
|
|
10
|
+
'''Object manager for NumericValueDistribution'''
|
|
11
|
+
def get_by_natural_key(self, name):
|
|
12
|
+
'''Retrieve a NumericValueDistribution by its natural key.'''
|
|
13
|
+
return self.get(name=name)
|
|
14
|
+
|
|
15
|
+
class NumericValueDistribution(BaseValueDistribution):
|
|
16
|
+
"""
|
|
17
|
+
Numeric value distribution model.
|
|
18
|
+
Supports uniform, normal, and skewed normal distributions with hard limits.
|
|
19
|
+
"""
|
|
20
|
+
objects = NumericValueDistributionManager()
|
|
21
|
+
DISTRIBUTION_CHOICES = [
|
|
22
|
+
('uniform', 'Uniform'),
|
|
23
|
+
('normal', 'Normal'),
|
|
24
|
+
('skewed_normal', 'Skewed Normal'),
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
distribution_type = models.CharField(max_length=20, choices=DISTRIBUTION_CHOICES)
|
|
28
|
+
min_descriptor = models.CharField(
|
|
29
|
+
max_length=20
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
max_descriptor = models.CharField(
|
|
33
|
+
max_length=20
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def generate_value(self, lab_value, patient):
|
|
37
|
+
'''Generate a value based on the distribution rules.'''
|
|
38
|
+
#FIXME
|
|
39
|
+
from endoreg_db.models import LabValue, Patient
|
|
40
|
+
assert isinstance(patient, Patient)
|
|
41
|
+
assert isinstance(lab_value, LabValue)
|
|
42
|
+
default_normal_range_dict = lab_value.get_normal_range(patient.age(), patient.gender)
|
|
43
|
+
assert isinstance(default_normal_range_dict, dict)
|
|
44
|
+
if self.distribution_type == 'uniform':
|
|
45
|
+
assert self.min_descriptor and self.max_descriptor
|
|
46
|
+
assert "min" in default_normal_range_dict and "max" in default_normal_range_dict
|
|
47
|
+
value = self._generate_value_uniform(default_normal_range_dict)
|
|
48
|
+
|
|
49
|
+
return value
|
|
50
|
+
|
|
51
|
+
elif self.distribution_type == 'normal':
|
|
52
|
+
value = np.random.normal(self.mean, self.std_dev)
|
|
53
|
+
return np.clip(value, self.min_value, self.max_value)
|
|
54
|
+
elif self.distribution_type == 'skewed_normal':
|
|
55
|
+
value = skewnorm.rvs(a=self.skewness, loc=self.mean, scale=self.std_dev)
|
|
56
|
+
return np.clip(value, self.min_value, self.max_value)
|
|
57
|
+
else:
|
|
58
|
+
raise ValueError("Unsupported distribution type")
|
|
59
|
+
|
|
60
|
+
def parse_value_descriptor(self, value_descriptor:str):
|
|
61
|
+
'''Parse the value descriptor string into a dict with a lambda function.'''
|
|
62
|
+
# strings of shape f"{value_key}_{operator}_{value}"
|
|
63
|
+
# extract value_key, operator, value
|
|
64
|
+
value_key, operator, value = value_descriptor.split("_")
|
|
65
|
+
value = float(value)
|
|
66
|
+
|
|
67
|
+
operator_functions = {
|
|
68
|
+
"+": lambda x: x + value,
|
|
69
|
+
"-": lambda x: x - value,
|
|
70
|
+
"x": lambda x: x * value,
|
|
71
|
+
"/": lambda x: x / value,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {value_key: operator_functions[operator]}
|
|
75
|
+
|
|
76
|
+
# create dict with {value_key: lambda x: x operator value}
|
|
77
|
+
|
|
78
|
+
def _generate_value_uniform(self, default_normal_range_dict:dict):
|
|
79
|
+
value_function_dict = self.parse_value_descriptor(
|
|
80
|
+
self.min_descriptor
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
_ = self.parse_value_descriptor(
|
|
84
|
+
self.max_descriptor
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
value_function_dict.update(_)
|
|
88
|
+
|
|
89
|
+
result_dict = {
|
|
90
|
+
key: value_function(default_normal_range_dict[key])
|
|
91
|
+
for key, value_function in value_function_dict.items()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# generate value
|
|
95
|
+
return np.random.uniform(result_dict["min"], result_dict["max"])
|
|
96
|
+
|
|
97
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
import numpy as np
|
|
3
|
+
from .base_value_distribution import BaseValueDistribution
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SingleCategoricalValueDistributionManager(models.Manager):
|
|
7
|
+
def get_by_natural_key(self, name):
|
|
8
|
+
return self.get(name=name)
|
|
9
|
+
|
|
10
|
+
class SingleCategoricalValueDistribution(BaseValueDistribution):
|
|
11
|
+
"""
|
|
12
|
+
Single categorical value distribution model.
|
|
13
|
+
Assigns a single value based on specified probabilities.
|
|
14
|
+
"""
|
|
15
|
+
objects = SingleCategoricalValueDistributionManager()
|
|
16
|
+
categories = models.JSONField() # { "category": "probability", ... }
|
|
17
|
+
|
|
18
|
+
def generate_value(self):
|
|
19
|
+
categories, probabilities = zip(*self.categories.items())
|
|
20
|
+
return np.random.choice(categories, p=probabilities)
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class MaterialManager(models.Manager):
|
|
4
|
+
def get_by_natural_key(self, name):
|
|
5
|
+
return self.get(name=name)
|
|
6
|
+
|
|
7
|
+
class Material(models.Model):
|
|
8
|
+
objects = MaterialManager()
|
|
9
|
+
|
|
10
|
+
name = models.CharField(max_length=255)
|
|
11
|
+
name_de = models.CharField(max_length=255, null=True)
|
|
12
|
+
name_en = models.CharField(max_length=255, null=True)
|
|
13
|
+
emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
|
|
14
|
+
|
|
15
|
+
def natural_key(self):
|
|
16
|
+
return (self.name,)
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
result = f"{self.name} - EmissionFactor: {self.emission_factor}"
|
|
20
|
+
return result
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class ResourceManager(models.Manager):
|
|
4
|
+
def get_by_natural_key(self, name):
|
|
5
|
+
return self.get(name=name)
|
|
6
|
+
|
|
7
|
+
class Resource(models.Model):
|
|
8
|
+
objects = ResourceManager()
|
|
9
|
+
|
|
10
|
+
name = models.CharField(max_length=255)
|
|
11
|
+
name_de = models.CharField(max_length=255, null=True)
|
|
12
|
+
name_en = models.CharField(max_length=255, null=True)
|
|
13
|
+
|
|
14
|
+
def natural_key(self):
|
|
15
|
+
return (self.name,)
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return self.name
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class TransportRouteManager(models.Manager):
|
|
4
|
+
def get_by_natural_key(self, name):
|
|
5
|
+
return self.get(name=name)
|
|
6
|
+
|
|
7
|
+
class TransportRoute(models.Model):
|
|
8
|
+
objects = TransportRouteManager()
|
|
9
|
+
|
|
10
|
+
distance = models.FloatField()
|
|
11
|
+
name = models.CharField(max_length=255)
|
|
12
|
+
name_de = models.CharField(max_length=255, null=True)
|
|
13
|
+
name_en = models.CharField(max_length=255, null=True)
|
|
14
|
+
emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
|
|
15
|
+
unit = models.ForeignKey("Unit", on_delete=models.SET_NULL, null=True)
|
|
16
|
+
|
|
17
|
+
def natural_key(self):
|
|
18
|
+
return (self.name,)
|
|
19
|
+
|
|
20
|
+
def __str__(self):
|
|
21
|
+
result = f"{self.name} ({self.distance} {self.unit}) - {self.emission_factor}"
|
|
22
|
+
return result
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class WasteManager(models.Manager):
|
|
4
|
+
def get_by_natural_key(self, name):
|
|
5
|
+
return self.get(name=name)
|
|
6
|
+
|
|
7
|
+
class Waste(models.Model):
|
|
8
|
+
objects = WasteManager()
|
|
9
|
+
|
|
10
|
+
name = models.CharField(max_length=255)
|
|
11
|
+
name_de = models.CharField(max_length=255, null=True)
|
|
12
|
+
name_en = models.CharField(max_length=255, null=True)
|
|
13
|
+
# emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
|
|
14
|
+
|
|
15
|
+
def natural_key(self):
|
|
16
|
+
return (self.name,)
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return self.name
|
|
20
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .patient_examination import PatientExamination
|
|
2
|
+
from .patient_finding import (
|
|
3
|
+
PatientFinding
|
|
4
|
+
)
|
|
5
|
+
from .patient_finding_location import (
|
|
6
|
+
PatientFindingLocation
|
|
7
|
+
)
|
|
8
|
+
from .patient_finding_morphology import (
|
|
9
|
+
PatientFindingMorphology
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from .patient_finding_intervention import (
|
|
13
|
+
PatientFindingIntervention
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# TODO Migrate to persons/patient
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"PatientExamination",
|
|
20
|
+
"PatientFinding",
|
|
21
|
+
"PatientFindingLocation",
|
|
22
|
+
"PatientFindingMorphology",
|
|
23
|
+
"PatientFindingIntervention"
|
|
24
|
+
]
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
# Serializer located in serializers/examination.py
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PatientExamination(models.Model):
|
|
10
|
+
patient = models.ForeignKey(
|
|
11
|
+
"Patient", on_delete=models.CASCADE, related_name="patient_examinations"
|
|
12
|
+
)
|
|
13
|
+
examination = models.ForeignKey(
|
|
14
|
+
"Examination", on_delete=models.CASCADE, null=True, blank=True
|
|
15
|
+
)
|
|
16
|
+
video = models.OneToOneField(
|
|
17
|
+
"Video",
|
|
18
|
+
on_delete=models.CASCADE,
|
|
19
|
+
null=True,
|
|
20
|
+
blank=True,
|
|
21
|
+
related_name="patient_examination",
|
|
22
|
+
)
|
|
23
|
+
date_start = models.DateField(null=True, blank=True)
|
|
24
|
+
date_end = models.DateField(null=True, blank=True)
|
|
25
|
+
hash = models.CharField(max_length=255, unique=True)
|
|
26
|
+
|
|
27
|
+
# report_files
|
|
28
|
+
class Meta:
|
|
29
|
+
verbose_name = "Patient Examination"
|
|
30
|
+
verbose_name_plural = "Patient Examinations"
|
|
31
|
+
ordering = ["patient", "examination", "date_start"]
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def get_or_create_pseudo_patient_examination_by_hash(
|
|
35
|
+
cls,
|
|
36
|
+
patient_hash: str,
|
|
37
|
+
examination_hash: str,
|
|
38
|
+
examination_name: Optional[str] = None,
|
|
39
|
+
):
|
|
40
|
+
from endoreg_db.models import Patient, Examination
|
|
41
|
+
|
|
42
|
+
created = False
|
|
43
|
+
|
|
44
|
+
if PatientExamination.objects.filter(
|
|
45
|
+
patient__patient_hash=patient_hash, hash=examination_hash
|
|
46
|
+
).exists():
|
|
47
|
+
return PatientExamination.objects.get(
|
|
48
|
+
patient__patient_hash=patient_hash, hash=examination_hash
|
|
49
|
+
), created
|
|
50
|
+
|
|
51
|
+
patient, created = Patient.get_or_create_pseudo_patient_by_hash(patient_hash)
|
|
52
|
+
if examination_name is not None:
|
|
53
|
+
examination = Examination.objects.get(name=examination_name)
|
|
54
|
+
else:
|
|
55
|
+
examination = None
|
|
56
|
+
|
|
57
|
+
patient_examination = cls.objects.create(
|
|
58
|
+
patient=patient, examination=examination, hash=examination_hash
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
patient_examination.save()
|
|
62
|
+
|
|
63
|
+
created = True
|
|
64
|
+
return patient_examination, created
|
|
65
|
+
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return f"{self.patient} - {self.examination} - {self.date_start}"
|
|
68
|
+
|
|
69
|
+
# override save method to make sure that the hash is always set,
|
|
70
|
+
# if none is existing generate an unique string
|
|
71
|
+
|
|
72
|
+
def generate_default_hash(self):
|
|
73
|
+
# create random hash
|
|
74
|
+
import random
|
|
75
|
+
import string
|
|
76
|
+
|
|
77
|
+
_hash = "DEFAULT_HASH_" + "".join(
|
|
78
|
+
random.choices(string.ascii_uppercase + string.digits, k=10)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return _hash
|
|
82
|
+
|
|
83
|
+
def save(self, *args, **kwargs):
|
|
84
|
+
if not self.hash:
|
|
85
|
+
self.hash = self.generate_default_hash()
|
|
86
|
+
super().save(*args, **kwargs)
|
|
87
|
+
|
|
88
|
+
def get_patient_age_at_examination(self) -> int:
|
|
89
|
+
"""
|
|
90
|
+
Returns the patient's age at the time of the examination.
|
|
91
|
+
"""
|
|
92
|
+
from endoreg_db.models import Patient
|
|
93
|
+
from datetime import datetime
|
|
94
|
+
|
|
95
|
+
patient: Patient = self.patient
|
|
96
|
+
dob = patient.get_dob()
|
|
97
|
+
date_start = self.date_start
|
|
98
|
+
return (date_start - dob).days // 365
|
|
99
|
+
|
|
100
|
+
def get_available_findings(self):
|
|
101
|
+
"""
|
|
102
|
+
Returns all findings that are associated with the examination of this patient examination.
|
|
103
|
+
"""
|
|
104
|
+
from endoreg_db.models import Finding, Examination
|
|
105
|
+
|
|
106
|
+
examination: Examination = self.examination
|
|
107
|
+
findings: List[Finding] = [_ for _ in examination.get_available_findings()]
|
|
108
|
+
return findings
|
|
109
|
+
|
|
110
|
+
def get_findings(self):
|
|
111
|
+
"""
|
|
112
|
+
Returns all findings that are associated with this patient examination.
|
|
113
|
+
"""
|
|
114
|
+
from endoreg_db.models import PatientFinding
|
|
115
|
+
|
|
116
|
+
patient_findings: List[PatientFinding] = [
|
|
117
|
+
_ for _ in self.patient_findings.all()
|
|
118
|
+
]
|
|
119
|
+
return patient_findings
|
|
120
|
+
|
|
121
|
+
def get_indications(self):
|
|
122
|
+
"""
|
|
123
|
+
Returns all indications that are associated with this patient examination.
|
|
124
|
+
"""
|
|
125
|
+
from endoreg_db.models import PatientExaminationIndication
|
|
126
|
+
|
|
127
|
+
indications: List[PatientExaminationIndication] = [
|
|
128
|
+
_ for _ in self.indications.all()
|
|
129
|
+
]
|
|
130
|
+
return indications
|
|
131
|
+
|
|
132
|
+
def get_indication_choices(self):
|
|
133
|
+
"""
|
|
134
|
+
Returns all indication choices that are associated with this patient examination.
|
|
135
|
+
"""
|
|
136
|
+
from endoreg_db.models import ExaminationIndicationClassificationChoice
|
|
137
|
+
|
|
138
|
+
choices: List[ExaminationIndicationClassificationChoice] = [
|
|
139
|
+
_.indication_choice for _ in self.get_indications()
|
|
140
|
+
]
|
|
141
|
+
return choices
|
|
142
|
+
|
|
143
|
+
def create_finding(self, finding):
|
|
144
|
+
"""
|
|
145
|
+
Adds a finding to this patient examination.
|
|
146
|
+
"""
|
|
147
|
+
from endoreg_db.models import Finding, Examination, PatientFinding
|
|
148
|
+
|
|
149
|
+
examination: Examination = self.examination
|
|
150
|
+
assert examination
|
|
151
|
+
|
|
152
|
+
finding: Finding
|
|
153
|
+
|
|
154
|
+
patient_finding = PatientFinding.objects.create(
|
|
155
|
+
patient_examination=self, finding=finding
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
patient_finding.save()
|
|
159
|
+
|
|
160
|
+
return patient_finding
|
|
161
|
+
|
|
162
|
+
def find_matching_video_from_patient(self):
|
|
163
|
+
"""
|
|
164
|
+
Finds a video for this patient examination based on the patient's videos.
|
|
165
|
+
For this, the videos date must be the same as the report file's date.
|
|
166
|
+
#TODO add more criteria for matching: Examination type
|
|
167
|
+
"""
|
|
168
|
+
videos = self.patient.video_set.filter(
|
|
169
|
+
date=self.report_file.date, patient_examination__isnull=True
|
|
170
|
+
)
|
|
171
|
+
if videos:
|
|
172
|
+
if len(videos) > 1:
|
|
173
|
+
print(
|
|
174
|
+
f"Warning: Found more than one video for patient {self.patient} on date {self.report_file.date}. Choosing the first one."
|
|
175
|
+
)
|
|
176
|
+
return videos[0]
|
|
177
|
+
else:
|
|
178
|
+
videos = self.patient.video_set.filter(patient_examination__isnull=True)
|
|
179
|
+
if len(videos) == 1:
|
|
180
|
+
return videos[0]
|
|
181
|
+
|
|
182
|
+
return None
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
class PatientFinding(models.Model):
|
|
5
|
+
patient_examination = models.ForeignKey('PatientExamination', on_delete=models.CASCADE, related_name='patient_findings')
|
|
6
|
+
finding = models.ForeignKey('Finding', on_delete=models.CASCADE, related_name='patient_findings')
|
|
7
|
+
locations = models.ManyToManyField(
|
|
8
|
+
'PatientFindingLocation',
|
|
9
|
+
blank=True,
|
|
10
|
+
related_name='patient_findings'
|
|
11
|
+
)
|
|
12
|
+
morphologies = models.ManyToManyField(
|
|
13
|
+
'PatientFindingMorphology',
|
|
14
|
+
blank=True,
|
|
15
|
+
related_name='patient_findings'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Meta:
|
|
20
|
+
verbose_name = 'Patient Finding'
|
|
21
|
+
verbose_name_plural = 'Patient Findings'
|
|
22
|
+
ordering = ['patient_examination', 'finding']
|
|
23
|
+
|
|
24
|
+
def __str__(self):
|
|
25
|
+
return f"{self.patient_examination} - {self.finding}"
|
|
26
|
+
|
|
27
|
+
# functions to get all associated location and morphology choices
|
|
28
|
+
def get_locations(self):
|
|
29
|
+
"""
|
|
30
|
+
Returns all location choices that are associated with this patient finding.
|
|
31
|
+
"""
|
|
32
|
+
from endoreg_db.models import PatientFindingLocation
|
|
33
|
+
locations:List[PatientFindingLocation] = [_ for _ in self.locations.all()]
|
|
34
|
+
return locations
|
|
35
|
+
|
|
36
|
+
def get_morphologies(self):
|
|
37
|
+
"""
|
|
38
|
+
Returns all morphology choices that are associated with this patient finding.
|
|
39
|
+
"""
|
|
40
|
+
from endoreg_db.models import PatientFindingMorphology
|
|
41
|
+
morphologies:List[PatientFindingMorphology] = [_ for _ in self.morphologies.all()]
|
|
42
|
+
return morphologies
|
|
43
|
+
|
|
44
|
+
def add_morphology_choice(self, morphology_choice, morphology_classification):
|
|
45
|
+
"""
|
|
46
|
+
Adds a morphology choice to this patient finding morphology.
|
|
47
|
+
"""
|
|
48
|
+
from endoreg_db.models import (
|
|
49
|
+
FindingMorphologyClassificationChoice,
|
|
50
|
+
FindingMorphologyClassification,
|
|
51
|
+
PatientFindingMorphology
|
|
52
|
+
)
|
|
53
|
+
morphology_choice: FindingMorphologyClassificationChoice
|
|
54
|
+
morphology_classification: FindingMorphologyClassification
|
|
55
|
+
|
|
56
|
+
patient_finding_morphology = PatientFindingMorphology.objects.create(
|
|
57
|
+
morphology_classification=morphology_classification,
|
|
58
|
+
morphology_choice=morphology_choice
|
|
59
|
+
)
|
|
60
|
+
patient_finding_morphology.save()
|
|
61
|
+
|
|
62
|
+
self.morphologies.add(patient_finding_morphology)
|
|
63
|
+
self.save()
|
|
64
|
+
|
|
65
|
+
return patient_finding_morphology
|
|
66
|
+
|
|
67
|
+
def add_intervention(self, intervention, state="pending", date=None):
|
|
68
|
+
"""
|
|
69
|
+
Adds an intervention to this patient finding.
|
|
70
|
+
"""
|
|
71
|
+
from endoreg_db.models import PatientFindingIntervention
|
|
72
|
+
patient_finding_intervention = PatientFindingIntervention.objects.create(
|
|
73
|
+
patient_finding=self,
|
|
74
|
+
intervention=intervention,
|
|
75
|
+
state = state,
|
|
76
|
+
date = date
|
|
77
|
+
)
|
|
78
|
+
patient_finding_intervention.save()
|
|
79
|
+
|
|
80
|
+
return patient_finding_intervention
|
|
81
|
+
|
|
82
|
+
def add_location_choice(self, location_choice, location_classification):
|
|
83
|
+
"""
|
|
84
|
+
Adds a location choice to this patient finding location.
|
|
85
|
+
"""
|
|
86
|
+
from endoreg_db.models import (
|
|
87
|
+
FindingLocationClassificationChoice,
|
|
88
|
+
FindingLocationClassification,
|
|
89
|
+
PatientFindingLocation
|
|
90
|
+
)
|
|
91
|
+
location_choice: FindingLocationClassificationChoice
|
|
92
|
+
location_classification: FindingLocationClassification
|
|
93
|
+
|
|
94
|
+
patient_finding_location = PatientFindingLocation.objects.create(
|
|
95
|
+
location_classification=location_classification,
|
|
96
|
+
location_choice=location_choice
|
|
97
|
+
)
|
|
98
|
+
patient_finding_location.save()
|
|
99
|
+
|
|
100
|
+
self.locations.add(patient_finding_location)
|
|
101
|
+
self.save()
|
|
102
|
+
|
|
103
|
+
return patient_finding_location
|
|
104
|
+
|
|
105
|
+
def get_interventions(self):
|
|
106
|
+
"""
|
|
107
|
+
Returns all interventions that are associated with this patient finding.
|
|
108
|
+
"""
|
|
109
|
+
from endoreg_db.models import PatientFindingIntervention
|
|
110
|
+
interventions:List[PatientFindingIntervention] = [_ for _ in self.interventions.all()]
|
|
111
|
+
return interventions
|
|
112
|
+
|
|
113
|
+
def set_random_location(
|
|
114
|
+
self, location_classification
|
|
115
|
+
):
|
|
116
|
+
"""
|
|
117
|
+
Sets a random location for this finding based on the location classification.
|
|
118
|
+
"""
|
|
119
|
+
from endoreg_db.models import (
|
|
120
|
+
FindingLocationClassificationChoice,
|
|
121
|
+
FindingLocationClassification,
|
|
122
|
+
PatientFindingLocation
|
|
123
|
+
)
|
|
124
|
+
import random
|
|
125
|
+
from typing import List
|
|
126
|
+
location_classification:FindingLocationClassification
|
|
127
|
+
|
|
128
|
+
# assert location_classification in self.finding.location_classifications.all()
|
|
129
|
+
|
|
130
|
+
location_choices:List[FindingLocationClassificationChoice] = location_classification.choices.all()
|
|
131
|
+
location_choice = random.choice(location_choices)
|
|
132
|
+
|
|
133
|
+
patient_finding_location = PatientFindingLocation.objects.create(
|
|
134
|
+
location_classification=location_classification,
|
|
135
|
+
location_choice=location_choice
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self.locations.add(patient_finding_location)
|
|
139
|
+
self.save()
|
|
140
|
+
|
|
141
|
+
return patient_finding_location
|
|
142
|
+
|
|
143
|
+
|