endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +8 -31
- endoreg_db/data/_examples/disease.yaml +55 -0
- endoreg_db/data/_examples/disease_classification.yaml +13 -0
- endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
- endoreg_db/data/_examples/event.yaml +64 -0
- endoreg_db/data/_examples/examination.yaml +72 -0
- endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/_examples/finding/complication.yaml +16 -0
- endoreg_db/data/_examples/finding/data.yaml +105 -0
- endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
- endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
- endoreg_db/data/_examples/finding/outcome.yaml +12 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/_examples/finding_type/data.yaml +43 -0
- endoreg_db/data/_examples/requirement/age.yaml +26 -0
- endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/_examples/requirement/gender.yaml +25 -0
- endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
- endoreg_db/data/_examples/requirement/medication.yaml +93 -0
- endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
- endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
- endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
- endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
- 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 +178 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +5 -2
- endoreg_db/helpers/data_loader.py +1 -1
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +1 -1
- endoreg_db/management/commands/init_default_ai_model.py +1 -1
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +2 -1
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_requirement_data.py +60 -31
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/setup_endoreg_db.py +14 -10
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/migrations/0001_initial.py +1799 -1300
- endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
- endoreg_db/migrations/_old/0001_initial.py +1857 -0
- endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
- endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
- endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
- endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
- endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
- endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
- endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +103 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +7 -8
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +249 -177
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +48 -56
- endoreg_db/models/media/video/pipe_1.py +30 -33
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +359 -204
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +109 -62
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +17 -18
- endoreg_db/models/medical/examination/examination_indication.py +26 -25
- endoreg_db/models/medical/examination/examination_time.py +16 -6
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +38 -39
- endoreg_db/models/medical/finding/finding_classification.py +37 -48
- endoreg_db/models/medical/finding/finding_intervention.py +27 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +20 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +1 -5
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +139 -18
- endoreg_db/models/metadata/pdf_meta.py +19 -24
- endoreg_db/models/metadata/sensitive_meta.py +102 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +383 -43
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +25 -25
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/requirement/requirement.py +580 -272
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +36 -33
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +46 -47
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +40 -46
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +58 -53
- endoreg_db/models/upload_job.py +32 -55
- endoreg_db/models/utils.py +1 -2
- endoreg_db/root_urls.py +21 -2
- endoreg_db/serializers/__init__.py +26 -57
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/meta/report_meta.py +1 -1
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/__init__.py +1 -1
- endoreg_db/serializers/misc/file_overview.py +33 -91
- endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/anonymization.py +75 -73
- endoreg_db/services/lookup_service.py +256 -73
- endoreg_db/services/lookup_store.py +174 -30
- endoreg_db/services/pdf_import.py +711 -310
- endoreg_db/services/storage_aware_video_processor.py +140 -114
- endoreg_db/services/video_import.py +266 -117
- endoreg_db/urls/__init__.py +27 -27
- endoreg_db/urls/label_video_segments.py +2 -0
- endoreg_db/urls/media.py +108 -66
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +88 -16
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +5 -12
- endoreg_db/views/anonymization/media_management.py +198 -163
- endoreg_db/views/anonymization/overview.py +4 -1
- endoreg_db/views/anonymization/validate.py +174 -40
- endoreg_db/views/media/__init__.py +2 -0
- endoreg_db/views/media/pdf_media.py +131 -150
- endoreg_db/views/media/sensitive_metadata.py +46 -6
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/media/video_segments.py +187 -260
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/pdf/__init__.py +5 -8
- endoreg_db/views/pdf/pdf_stream.py +186 -0
- endoreg_db/views/pdf/pdf_stream_views.py +0 -127
- endoreg_db/views/pdf/reimport.py +86 -91
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +186 -288
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +0 -4
- endoreg_db/views/video/correction.py +2 -2
- endoreg_db/views/video/video_examination_viewset.py +202 -289
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +350 -255
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/views/pdf/pdf_media.py +0 -239
- endoreg_db/views/report/__init__.py +0 -9
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/video_media.py +0 -158
- endoreg_db/views.py +0 -0
- /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
- /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
- /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
1
4
|
import torch
|
|
2
5
|
from torchvision import models
|
|
3
6
|
import torch.nn as nn
|
|
4
7
|
from pytorch_lightning import LightningModule
|
|
5
8
|
import numpy as np
|
|
9
|
+
from safetensors.torch import load_file
|
|
6
10
|
from sklearn.metrics import precision_score, recall_score, f1_score
|
|
7
11
|
|
|
12
|
+
try: # Torchvision >= 0.13 exposes explicit weight enums
|
|
13
|
+
from torchvision.models import EfficientNet_B4_Weights, RegNet_X_800MF_Weights
|
|
14
|
+
except ImportError: # pragma: no cover - compatibility with older torchvision
|
|
15
|
+
EfficientNet_B4_Weights = None
|
|
16
|
+
RegNet_X_800MF_Weights = None
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
8
20
|
METRICS_ON_STEP = False
|
|
9
21
|
|
|
10
22
|
|
|
@@ -41,6 +53,29 @@ def calculate_metrics(pred, target, threshold=0.5):
|
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
|
|
56
|
+
def _load_torchvision_backbone(factory, *, weights_enum=None, load_pretrained=False):
|
|
57
|
+
"""Instantiate a torchvision model without triggering unwanted downloads."""
|
|
58
|
+
if weights_enum is not None:
|
|
59
|
+
try:
|
|
60
|
+
weights = weights_enum.DEFAULT if load_pretrained else None
|
|
61
|
+
return factory(weights=weights)
|
|
62
|
+
except (TypeError, AttributeError):
|
|
63
|
+
# Fall back to legacy keyword on older torchvision versions
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
return factory(pretrained=load_pretrained)
|
|
68
|
+
except TypeError:
|
|
69
|
+
# Newer torchvision versions removed the pretrained kwarg; call without hints
|
|
70
|
+
try:
|
|
71
|
+
return factory()
|
|
72
|
+
except Exception as exc: # pragma: no cover - surfaced to caller for visibility
|
|
73
|
+
raise RuntimeError(
|
|
74
|
+
"Failed to instantiate torchvision backbone with load_pretrained="
|
|
75
|
+
f"{load_pretrained}."
|
|
76
|
+
) from exc
|
|
77
|
+
|
|
78
|
+
|
|
44
79
|
class MultiLabelClassificationNet(LightningModule):
|
|
45
80
|
def __init__(
|
|
46
81
|
self,
|
|
@@ -49,26 +84,40 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
49
84
|
weight_decay=0.001,
|
|
50
85
|
pos_weight=2,
|
|
51
86
|
model_type="EfficientNetB4",
|
|
87
|
+
load_imagenet_weights: bool = False,
|
|
88
|
+
track_hparams: bool = True,
|
|
52
89
|
):
|
|
53
90
|
super().__init__()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
self.
|
|
91
|
+
if track_hparams:
|
|
92
|
+
self.save_hyperparameters()
|
|
93
|
+
if labels is None:
|
|
94
|
+
raise ValueError("labels must be provided to initialize MultiLabelClassificationNet")
|
|
95
|
+
|
|
96
|
+
self.model_type = model_type
|
|
97
|
+
self.labels = list(labels)
|
|
98
|
+
self.n_classes = len(self.labels)
|
|
99
|
+
self.val_preds: list[np.ndarray] = []
|
|
100
|
+
self.val_targets: list[np.ndarray] = []
|
|
60
101
|
self.pos_weight = pos_weight
|
|
61
102
|
self.weight_decay = weight_decay
|
|
62
103
|
self.lr = lr
|
|
63
104
|
self.sigm = nn.Sigmoid()
|
|
64
105
|
|
|
65
106
|
if model_type == "EfficientNetB4":
|
|
66
|
-
self.model =
|
|
107
|
+
self.model = _load_torchvision_backbone(
|
|
108
|
+
models.efficientnet_b4,
|
|
109
|
+
weights_enum=EfficientNet_B4_Weights,
|
|
110
|
+
load_pretrained=load_imagenet_weights,
|
|
111
|
+
)
|
|
67
112
|
num_ftrs = self.model.classifier[1].in_features
|
|
68
113
|
self.model.classifier[1] = nn.Linear(num_ftrs, len(labels))
|
|
69
114
|
|
|
70
115
|
elif model_type == "RegNetX800MF":
|
|
71
|
-
self.model =
|
|
116
|
+
self.model = _load_torchvision_backbone(
|
|
117
|
+
models.regnet_x_800mf,
|
|
118
|
+
weights_enum=RegNet_X_800MF_Weights,
|
|
119
|
+
load_pretrained=load_imagenet_weights,
|
|
120
|
+
)
|
|
72
121
|
num_ftrs = self.model.fc.in_features
|
|
73
122
|
self.model.fc = nn.Linear(num_ftrs, len(labels))
|
|
74
123
|
|
|
@@ -78,10 +127,47 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
78
127
|
|
|
79
128
|
@classmethod
|
|
80
129
|
def load_from_checkpoint(cls, checkpoint_path, *args, **kwargs):
|
|
81
|
-
|
|
130
|
+
path = Path(checkpoint_path)
|
|
131
|
+
suffix = path.suffix.lower()
|
|
132
|
+
|
|
133
|
+
if suffix == ".safetensors":
|
|
134
|
+
map_location = kwargs.pop("map_location", "cpu")
|
|
135
|
+
strict = kwargs.pop("strict", True)
|
|
136
|
+
labels = kwargs.pop("labels", None)
|
|
137
|
+
if not labels:
|
|
138
|
+
raise ValueError("labels must be provided when loading .safetensors checkpoints")
|
|
139
|
+
model_type = kwargs.pop("model_type", None) or "EfficientNetB4"
|
|
140
|
+
load_imagenet = kwargs.pop("load_imagenet_weights", False)
|
|
141
|
+
|
|
142
|
+
device = torch.device(map_location) if map_location is not None else torch.device("cpu")
|
|
143
|
+
if isinstance(device, torch.device):
|
|
144
|
+
device_hint = f"{device.type}:{device.index}" if device.index is not None else device.type
|
|
145
|
+
else:
|
|
146
|
+
device_hint = device
|
|
147
|
+
|
|
148
|
+
state_dict = load_file(path, device=device_hint)
|
|
149
|
+
|
|
150
|
+
instance = cls(
|
|
151
|
+
labels=labels,
|
|
152
|
+
model_type=model_type,
|
|
153
|
+
load_imagenet_weights=load_imagenet,
|
|
154
|
+
track_hparams=False,
|
|
155
|
+
*args,
|
|
156
|
+
**kwargs,
|
|
157
|
+
)
|
|
158
|
+
missing, unexpected = instance.load_state_dict(state_dict, strict=strict)
|
|
159
|
+
|
|
160
|
+
if missing:
|
|
161
|
+
logger.warning("Missing parameters when loading %s: %s", path, missing)
|
|
162
|
+
if unexpected:
|
|
163
|
+
logger.warning("Unexpected parameters when loading %s: %s", path, unexpected)
|
|
164
|
+
|
|
165
|
+
instance.to(device)
|
|
166
|
+
return instance
|
|
167
|
+
|
|
168
|
+
return super(MultiLabelClassificationNet, cls).load_from_checkpoint(
|
|
82
169
|
checkpoint_path, *args, **kwargs
|
|
83
170
|
)
|
|
84
|
-
return instance
|
|
85
171
|
|
|
86
172
|
def forward(self, x): # pylint: disable=arguments-differ
|
|
87
173
|
x = self.model(x)
|
|
@@ -113,18 +199,24 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
113
199
|
|
|
114
200
|
def validation_epoch_end(self, _outputs):
|
|
115
201
|
"""Called at the end of validation to aggregate outputs"""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
metrics = calculate_metrics(
|
|
120
|
-
for key,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
202
|
+
val_preds_np = np.concatenate(self.val_preds)
|
|
203
|
+
val_targets_np = np.concatenate(self.val_targets)
|
|
204
|
+
|
|
205
|
+
metrics = calculate_metrics(val_preds_np, val_targets_np, threshold=0.5)
|
|
206
|
+
for key, metric_value in metrics.items():
|
|
207
|
+
if isinstance(metric_value, np.ndarray):
|
|
208
|
+
processed_value = metric_value.tolist()
|
|
209
|
+
elif isinstance(metric_value, (list, tuple)):
|
|
210
|
+
processed_value = list(metric_value)
|
|
211
|
+
else:
|
|
212
|
+
processed_value = float(metric_value)
|
|
213
|
+
|
|
214
|
+
if isinstance(processed_value, list):
|
|
215
|
+
for i, single_value in enumerate(processed_value):
|
|
124
216
|
name = "val/" + f"{key}/{self.labels[i]}"
|
|
125
217
|
self.log(
|
|
126
218
|
name,
|
|
127
|
-
|
|
219
|
+
float(single_value),
|
|
128
220
|
on_epoch=True,
|
|
129
221
|
on_step=METRICS_ON_STEP,
|
|
130
222
|
prog_bar=False,
|
|
@@ -132,7 +224,11 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
132
224
|
else:
|
|
133
225
|
name = "val/" + f"{key}"
|
|
134
226
|
self.log(
|
|
135
|
-
name,
|
|
227
|
+
name,
|
|
228
|
+
float(processed_value),
|
|
229
|
+
on_epoch=True,
|
|
230
|
+
on_step=METRICS_ON_STEP,
|
|
231
|
+
prog_bar=True,
|
|
136
232
|
)
|
|
137
233
|
|
|
138
234
|
self.val_preds = []
|
endoreg_db/utils/dataloader.py
CHANGED
|
@@ -3,7 +3,6 @@ import yaml
|
|
|
3
3
|
from django.core.exceptions import ObjectDoesNotExist
|
|
4
4
|
from django.db import OperationalError, transaction
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
def load_model_data_from_yaml(command, model_name, metadata, verbose):
|
|
8
7
|
"""
|
|
9
8
|
Load model data from YAML files.
|
|
@@ -20,6 +19,7 @@ def load_model_data_from_yaml(command, model_name, metadata, verbose):
|
|
|
20
19
|
dir_path = metadata["dir"]
|
|
21
20
|
foreign_keys = metadata["foreign_keys"]
|
|
22
21
|
foreign_key_models = metadata["foreign_key_models"]
|
|
22
|
+
validators = metadata.get("validators", [])
|
|
23
23
|
|
|
24
24
|
_files = [f for f in os.listdir(dir_path) if f.endswith(".yaml")]
|
|
25
25
|
# sort
|
|
@@ -29,12 +29,18 @@ def load_model_data_from_yaml(command, model_name, metadata, verbose):
|
|
|
29
29
|
yaml_data = yaml.safe_load(file)
|
|
30
30
|
|
|
31
31
|
load_data_with_foreign_keys(
|
|
32
|
-
command, model, yaml_data, foreign_keys, foreign_key_models, verbose
|
|
32
|
+
command, model, yaml_data, foreign_keys, foreign_key_models, validators, verbose
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def load_data_with_foreign_keys(
|
|
37
|
-
command,
|
|
37
|
+
command,
|
|
38
|
+
model,
|
|
39
|
+
yaml_data,
|
|
40
|
+
foreign_keys,
|
|
41
|
+
foreign_key_models,
|
|
42
|
+
validators,
|
|
43
|
+
verbose,
|
|
38
44
|
):
|
|
39
45
|
"""
|
|
40
46
|
Load YAML data into Django model instances with FK and M2M support.
|
|
@@ -52,13 +58,34 @@ def load_data_with_foreign_keys(
|
|
|
52
58
|
yaml_data: A list of dictionaries representing YAML entries.
|
|
53
59
|
foreign_keys: A list of foreign key field names to process from each entry.
|
|
54
60
|
foreign_key_models: The corresponding Django model classes for each foreign key.
|
|
61
|
+
validators: A sequence of callables invoked before persisting each entry. Each
|
|
62
|
+
validator receives a shallow copy of the entry's field dictionary along with
|
|
63
|
+
the original entry and model for context.
|
|
55
64
|
verbose: If True, prints detailed output and warnings during processing.
|
|
56
65
|
"""
|
|
57
66
|
for entry in yaml_data:
|
|
58
|
-
|
|
67
|
+
raw_fields = entry.get("fields", {})
|
|
68
|
+
|
|
69
|
+
for validator in validators:
|
|
70
|
+
validator(dict(raw_fields), entry=entry, model=model)
|
|
71
|
+
|
|
72
|
+
fields = dict(raw_fields)
|
|
59
73
|
name = fields.pop("name", None)
|
|
60
74
|
|
|
61
75
|
|
|
76
|
+
if getattr(model, "_meta", None) and model._meta.model_name == "requirement":
|
|
77
|
+
requirement_types = fields.get("requirement_types", [])
|
|
78
|
+
operators = fields.get("operators", [])
|
|
79
|
+
|
|
80
|
+
if not requirement_types:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"Requirement '{name}' must define at least one requirement_types entry."
|
|
83
|
+
)
|
|
84
|
+
if not operators:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"Requirement '{name}' must define at least one operators entry."
|
|
87
|
+
)
|
|
88
|
+
|
|
62
89
|
####################
|
|
63
90
|
#TODO REMOVE AFTER TRANSLATION SUPPORT IS ADDED
|
|
64
91
|
SKIP_NAMES=[
|
|
@@ -73,7 +100,7 @@ def load_data_with_foreign_keys(
|
|
|
73
100
|
for skip_name in SKIP_NAMES:
|
|
74
101
|
if skip_name in fields:
|
|
75
102
|
fields.pop(skip_name)
|
|
76
|
-
########################
|
|
103
|
+
# ########################
|
|
77
104
|
|
|
78
105
|
m2m_relationships = {} # Store many-to-many relationships
|
|
79
106
|
# print(entry)
|
|
@@ -113,19 +140,60 @@ def load_data_with_foreign_keys(
|
|
|
113
140
|
related_objects.append(obj)
|
|
114
141
|
m2m_relationships[fk_field] = related_objects
|
|
115
142
|
else: # Single foreign key relationship
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
if (
|
|
144
|
+
model.__name__ == "ModelMeta"
|
|
145
|
+
and fk_field == "labelset"
|
|
146
|
+
):
|
|
147
|
+
labelset_version = fields.pop("labelset_version", None)
|
|
148
|
+
|
|
149
|
+
if isinstance(target_keys, (tuple, list)):
|
|
150
|
+
labelset_name = target_keys[0] if target_keys else None
|
|
151
|
+
if len(target_keys) > 1 and labelset_version in (None, ""):
|
|
152
|
+
labelset_version = target_keys[1]
|
|
153
|
+
else:
|
|
154
|
+
labelset_name = target_keys
|
|
155
|
+
|
|
156
|
+
if not labelset_name:
|
|
157
|
+
if verbose:
|
|
158
|
+
command.stdout.write(
|
|
159
|
+
command.style.WARNING("LabelSet name missing for ModelMeta entry")
|
|
123
160
|
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
queryset = fk_model.objects.filter(name=labelset_name)
|
|
164
|
+
if labelset_version not in (None, "", -1):
|
|
165
|
+
try:
|
|
166
|
+
version_value = int(labelset_version)
|
|
167
|
+
except (TypeError, ValueError):
|
|
168
|
+
version_value = labelset_version
|
|
169
|
+
queryset = queryset.filter(version=version_value)
|
|
170
|
+
|
|
171
|
+
obj = queryset.order_by("-version").first()
|
|
172
|
+
if obj is None:
|
|
173
|
+
if verbose:
|
|
174
|
+
command.stdout.write(
|
|
175
|
+
command.style.WARNING(
|
|
176
|
+
f"LabelSet '{labelset_name}' (version={labelset_version}) not found"
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
continue
|
|
180
|
+
fields[fk_field] = obj
|
|
181
|
+
else:
|
|
182
|
+
try:
|
|
183
|
+
obj = fk_model.objects.get_by_natural_key(target_keys)
|
|
184
|
+
except ObjectDoesNotExist:
|
|
185
|
+
if verbose:
|
|
186
|
+
command.stdout.write(
|
|
187
|
+
command.style.WARNING(
|
|
188
|
+
f"{fk_model.__name__} with key {target_keys} not found"
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
continue
|
|
192
|
+
fields[fk_field] = obj
|
|
127
193
|
|
|
128
194
|
# Create or update the main object (avoid update_or_create to prevent SQLite locks)
|
|
195
|
+
version_value = fields.get("version")
|
|
196
|
+
|
|
129
197
|
def _save_instance():
|
|
130
198
|
if name is None:
|
|
131
199
|
# Try to find an existing object by all provided fields
|
|
@@ -136,7 +204,11 @@ def load_data_with_foreign_keys(
|
|
|
136
204
|
else:
|
|
137
205
|
created = False
|
|
138
206
|
else:
|
|
139
|
-
|
|
207
|
+
lookup_kwargs = {"name": name}
|
|
208
|
+
if model.__name__ == "LabelSet" and version_value is not None:
|
|
209
|
+
lookup_kwargs["version"] = version_value
|
|
210
|
+
|
|
211
|
+
obj = model.objects.filter(**lookup_kwargs).first()
|
|
140
212
|
if obj is None:
|
|
141
213
|
obj = model.objects.create(name=name, **fields)
|
|
142
214
|
created = True
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from endoreg_db.models.administration.center import center
|
|
3
|
+
|
|
4
|
+
# Start process with interactive pipes
|
|
5
|
+
proc = subprocess.Popen(
|
|
6
|
+
["python3", "-i"], # or your target program
|
|
7
|
+
stdin=subprocess.PIPE,
|
|
8
|
+
stdout=subprocess.PIPE,
|
|
9
|
+
stderr=subprocess.STDOUT,
|
|
10
|
+
text=True,
|
|
11
|
+
bufsize=1
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
proc.stdin.write("print('Trying to extract...')\n")
|
|
15
|
+
proc.stdin.flush()
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
subprocess.run(["python", "manage.py", "load_center_data"], check=True)
|
|
19
|
+
proc.stdout.write("print('found center')")
|
|
20
|
+
except subprocess.CalledProcessError as e:
|
|
21
|
+
proc.stdout.write("print('Didn't find center. Please add it to endoreg_db luxnix or via export DEFAULT_CENTER")
|
|
22
|
+
# """
|
|
23
|
+
# Future Implementation using dialogue
|
|
24
|
+
#"""
|
|
25
|
+
# # Send commands as if from terminal
|
|
26
|
+
# proc.stdin.write("print('You dont have a default center set up yet. Please enter one here.')\n\nprint('Rule: use_this_format_and_connect_words_with_underscore')")
|
|
27
|
+
# proc.stdin.flush()
|
|
28
|
+
|
|
29
|
+
# # Read responses
|
|
30
|
+
# for _ in range(3):
|
|
31
|
+
# line = proc.stdout.readline()
|
|
32
|
+
# print("Selected >>", line.strip())
|
endoreg_db/utils/names.py
CHANGED
|
@@ -55,22 +55,28 @@ def create_mock_patient_name(gender: str) -> tuple[str, str]:
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
def guess_name_gender(name: str) -> str:
|
|
58
|
-
"""
|
|
59
|
-
Guesses the gender for a given name by using a gender detector and retrieving the corresponding Gender model instance.
|
|
60
|
-
Parameters:
|
|
61
|
-
name (str): The name for which the gender is to be determined.
|
|
62
|
-
Returns:
|
|
63
|
-
Gender: The Gender object corresponding to the detected gender name.
|
|
64
|
-
Raises:
|
|
65
|
-
Gender.DoesNotExist: If no Gender object matching the detected gender is found.
|
|
66
|
-
Exception: For any other exceptions that occur during gender detection or database lookup.
|
|
67
|
-
"""
|
|
58
|
+
"""Return a normalized gender slug (male|female|unknown) for the given name.
|
|
68
59
|
|
|
69
|
-
|
|
60
|
+
Uses :mod:`gender_guesser` to infer gender without touching the database. All
|
|
61
|
+
detector outputs are mapped onto our canonical slugs so callers can perform
|
|
62
|
+
their own model lookups or fall back safely.
|
|
63
|
+
"""
|
|
70
64
|
|
|
71
65
|
detector = gender_detector.Detector(case_sensitive=False)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
try:
|
|
67
|
+
detected = detector.get_gender(name or "")
|
|
68
|
+
except Exception: # pragma: no cover - defensive, detector is pure-Python
|
|
69
|
+
detected = None
|
|
70
|
+
|
|
71
|
+
if not detected:
|
|
72
|
+
return "unknown"
|
|
73
|
+
|
|
74
|
+
normalized = detected.lower()
|
|
75
|
+
if normalized in {"male", "mostly_male"}:
|
|
76
|
+
return "male"
|
|
77
|
+
if normalized in {"female", "mostly_female"}:
|
|
78
|
+
return "female"
|
|
79
|
+
|
|
80
|
+
# gender-guesser returns "andy" for androgynous names and "unknown" for
|
|
81
|
+
# unrecognised inputs – both should map to our "unknown" slug.
|
|
82
|
+
return "unknown"
|
endoreg_db/utils/permissions.py
CHANGED
|
@@ -7,7 +7,7 @@ the DEBUG setting and other environment configurations.
|
|
|
7
7
|
|
|
8
8
|
from django.conf import settings
|
|
9
9
|
from rest_framework.permissions import IsAuthenticated, AllowAny, BasePermission
|
|
10
|
-
from rest_framework.decorators import permission_classes as drf_permission_classes
|
|
10
|
+
#from rest_framework.decorators import permission_classes as drf_permission_classes
|
|
11
11
|
from functools import wraps
|
|
12
12
|
import logging
|
|
13
13
|
import os
|
|
@@ -50,6 +50,7 @@ def dynamic_permission_classes(force_auth=None):
|
|
|
50
50
|
- None: Use environment-based logic (default)
|
|
51
51
|
"""
|
|
52
52
|
def decorator(view_func):
|
|
53
|
+
from rest_framework.decorators import permission_classes as drf_permission_classes
|
|
53
54
|
@wraps(view_func)
|
|
54
55
|
def wrapper(*args, **kwargs):
|
|
55
56
|
return view_func(*args, **kwargs)
|
|
@@ -20,7 +20,7 @@ DEFAULT_DIR = Path(__file__).resolve().parent.parent.parent.parent / "data/study
|
|
|
20
20
|
CENTER_NAME = os.environ.get("CENTER_NAME", "university_hospital_wuerzburg")
|
|
21
21
|
ENDOSCOPY_PROCESSOR_NAME = os.environ.get("ENDOSCOPY_PROCESSOR_NAME", "olympus_cv_1500")
|
|
22
22
|
MODEL_NAME = "image_multilabel_classification_colonoscopy_default"
|
|
23
|
-
MODEL_WEIGHTS_PATH = "./tests/assets/colo_segmentation_RegNetX800MF_6.
|
|
23
|
+
MODEL_WEIGHTS_PATH = "./tests/assets/colo_segmentation_RegNetX800MF_6.safetensors"
|
|
24
24
|
ic(DEFAULT_DIR)
|
|
25
25
|
|
|
26
26
|
|