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
|
@@ -4,20 +4,24 @@ including versioning, configuration, and associated weights files.
|
|
|
4
4
|
Logic is primarily handled in model_meta_logic.py.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from typing import
|
|
8
|
-
# Removed shutil import, now in logic
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Type, cast
|
|
9
8
|
|
|
10
|
-
from django.db import models
|
|
11
9
|
from django.core.validators import FileExtensionValidator
|
|
10
|
+
|
|
11
|
+
# Removed shutil import, now in logic
|
|
12
|
+
from django.db import models
|
|
13
|
+
|
|
12
14
|
# Removed torch import, now in logic
|
|
13
15
|
# from torch import nn
|
|
16
|
+
from ..utils import WEIGHTS_DIR
|
|
14
17
|
|
|
15
|
-
from ..utils import WEIGHTS_DIR, STORAGE_DIR
|
|
16
18
|
# Import logic functions
|
|
17
19
|
from . import model_meta_logic as logic
|
|
18
20
|
|
|
19
21
|
if TYPE_CHECKING:
|
|
20
|
-
from
|
|
22
|
+
from django.db.models.fields.files import FieldFile
|
|
23
|
+
|
|
24
|
+
from endoreg_db.models import AiModel, LabelSet # pylint: disable=import-outside-toplevel
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class ModelMetaManager(models.Manager):
|
|
@@ -26,7 +30,24 @@ class ModelMetaManager(models.Manager):
|
|
|
26
30
|
|
|
27
31
|
Provides methods for retrieving ModelMeta instances using natural keys.
|
|
28
32
|
"""
|
|
29
|
-
|
|
33
|
+
|
|
34
|
+
def get_by_natural_key(self, name: str, version: str, model_name: str) -> "ModelMeta":
|
|
35
|
+
"""
|
|
36
|
+
Retrieves a ModelMeta instance using its natural key.
|
|
37
|
+
|
|
38
|
+
This method returns the ModelMeta whose name, version, and associated model's name
|
|
39
|
+
match the provided natural key. It is primarily used to support Django's natural key
|
|
40
|
+
serialization during data import/export and deserialization processes.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
name: The name of the ModelMeta.
|
|
44
|
+
version: The version identifier of the ModelMeta.
|
|
45
|
+
model_name: The name of the associated AiModel.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
The ModelMeta object corresponding to the given natural key.
|
|
49
|
+
"""
|
|
50
|
+
return self.get(name=name, version=version, model__name=model_name)
|
|
30
51
|
|
|
31
52
|
|
|
32
53
|
class ModelMeta(models.Model):
|
|
@@ -50,7 +71,6 @@ class ModelMeta(models.Model):
|
|
|
50
71
|
on_delete=models.CASCADE,
|
|
51
72
|
related_name="metadata_versions",
|
|
52
73
|
help_text="The base AI model architecture this metadata belongs to.",
|
|
53
|
-
|
|
54
74
|
)
|
|
55
75
|
|
|
56
76
|
# --- Model Configuration ---
|
|
@@ -60,15 +80,13 @@ class ModelMeta(models.Model):
|
|
|
60
80
|
related_name="model_metadata",
|
|
61
81
|
help_text="The set of labels this model version predicts.",
|
|
62
82
|
)
|
|
63
|
-
activation = models.CharField(
|
|
64
|
-
max_length=50, default="sigmoid", help_text="Output activation function (e.g., 'sigmoid', 'softmax', 'none')."
|
|
65
|
-
)
|
|
83
|
+
activation = models.CharField(max_length=50, default="sigmoid", help_text="Output activation function (e.g., 'sigmoid', 'softmax', 'none').")
|
|
66
84
|
weights = models.FileField(
|
|
67
85
|
upload_to=WEIGHTS_DIR.name, # Use .name for relative path
|
|
68
|
-
validators=[FileExtensionValidator(allowed_extensions=["
|
|
86
|
+
validators=[FileExtensionValidator(allowed_extensions=["safetensors", "pth", "pt"])],
|
|
69
87
|
null=True,
|
|
70
88
|
blank=True,
|
|
71
|
-
help_text="Path to the model weights file (.
|
|
89
|
+
help_text="Path to the model weights file (.safetensors), relative to MEDIA_ROOT.",
|
|
72
90
|
)
|
|
73
91
|
|
|
74
92
|
# --- Normalization and Input Shape ---
|
|
@@ -84,9 +102,7 @@ class ModelMeta(models.Model):
|
|
|
84
102
|
)
|
|
85
103
|
size_x = models.IntegerField(default=716, help_text="Expected input image width.")
|
|
86
104
|
size_y = models.IntegerField(default=716, help_text="Expected input image height.")
|
|
87
|
-
axes = models.CharField(
|
|
88
|
-
max_length=10, default="2,0,1", help_text="Comma-separated target axis order (e.g., '2,0,1' for CHW)."
|
|
89
|
-
)
|
|
105
|
+
axes = models.CharField(max_length=10, default="2,0,1", help_text="Comma-separated target axis order (e.g., '2,0,1' for CHW).")
|
|
90
106
|
|
|
91
107
|
# --- Inference Parameters ---
|
|
92
108
|
batchsize = models.IntegerField(default=16, help_text="Default batch size for inference.")
|
|
@@ -96,17 +112,21 @@ class ModelMeta(models.Model):
|
|
|
96
112
|
description = models.TextField(blank=True, null=True, help_text="Optional description.")
|
|
97
113
|
date_created = models.DateTimeField(auto_now_add=True)
|
|
98
114
|
|
|
99
|
-
|
|
100
115
|
objects = ModelMetaManager()
|
|
101
116
|
|
|
102
117
|
# --- Type Hinting for Related Fields ---
|
|
103
118
|
if TYPE_CHECKING:
|
|
104
|
-
labelset: "LabelSet"
|
|
105
|
-
model: "AiModel" # Corrected from ai_model to match field name
|
|
119
|
+
labelset: models.ForeignKey["LabelSet"]
|
|
120
|
+
model: models.ForeignKey["AiModel"] # Corrected from ai_model to match field name
|
|
121
|
+
weights = cast(FieldFile, weights)
|
|
106
122
|
|
|
107
123
|
class Meta:
|
|
108
124
|
"""Metadata options for the ModelMeta model."""
|
|
109
|
-
|
|
125
|
+
|
|
126
|
+
unique_together = (("name", "version", "model"),)
|
|
127
|
+
ordering = ["-date_created"]
|
|
128
|
+
verbose_name = "Model Metadata"
|
|
129
|
+
verbose_name_plural = "Model Metadata"
|
|
110
130
|
|
|
111
131
|
@classmethod
|
|
112
132
|
def create_from_file(
|
|
@@ -115,6 +135,7 @@ class ModelMeta(models.Model):
|
|
|
115
135
|
model_name: str,
|
|
116
136
|
labelset_name: str,
|
|
117
137
|
weights_file: str,
|
|
138
|
+
labelset_version: Optional[int | str] = None,
|
|
118
139
|
requested_version: Optional[str] = None,
|
|
119
140
|
bump_if_exists: bool = False,
|
|
120
141
|
**kwargs: Any,
|
|
@@ -124,23 +145,34 @@ class ModelMeta(models.Model):
|
|
|
124
145
|
"""
|
|
125
146
|
# Delegate to logic function, passing the class (cls)
|
|
126
147
|
return logic.create_from_file_logic(
|
|
127
|
-
cls,
|
|
128
|
-
|
|
148
|
+
cls,
|
|
149
|
+
meta_name,
|
|
150
|
+
model_name,
|
|
151
|
+
labelset_name,
|
|
152
|
+
weights_file,
|
|
153
|
+
labelset_version=labelset_version,
|
|
154
|
+
requested_version=requested_version,
|
|
155
|
+
bump_if_exists=bump_if_exists,
|
|
156
|
+
**kwargs,
|
|
129
157
|
)
|
|
130
|
-
|
|
158
|
+
|
|
131
159
|
@classmethod
|
|
132
160
|
def setup_default_from_huggingface(
|
|
133
161
|
cls: Type["ModelMeta"],
|
|
134
162
|
model_id: str = "wg-lux/colo_segmentation_RegNetX800MF_base",
|
|
135
163
|
labelset_name: Optional[str] = None,
|
|
164
|
+
labelset_version: Optional[int | str] = None,
|
|
136
165
|
) -> "ModelMeta":
|
|
137
166
|
"""
|
|
138
167
|
Downloads a pretrained model from Hugging Face and initializes ModelMeta automatically.
|
|
139
168
|
"""
|
|
140
169
|
# If labelset_name is not provided, handle default logic here if needed
|
|
141
|
-
return logic.setup_default_from_huggingface_logic(
|
|
142
|
-
|
|
143
|
-
|
|
170
|
+
return logic.setup_default_from_huggingface_logic(
|
|
171
|
+
cls,
|
|
172
|
+
model_id=model_id,
|
|
173
|
+
labelset_name=labelset_name,
|
|
174
|
+
labelset_version=labelset_version,
|
|
175
|
+
)
|
|
144
176
|
|
|
145
177
|
@classmethod
|
|
146
178
|
def get_latest_version_number(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> int:
|
|
@@ -150,9 +182,8 @@ class ModelMeta(models.Model):
|
|
|
150
182
|
# Delegate to logic function
|
|
151
183
|
return logic.get_latest_version_number_logic(cls, meta_name, model_name)
|
|
152
184
|
|
|
153
|
-
|
|
154
185
|
@staticmethod
|
|
155
|
-
def get_activation_function(activation_name: str)
|
|
186
|
+
def get_activation_function(activation_name: str):
|
|
156
187
|
"""
|
|
157
188
|
Retrieves a PyTorch activation function using external logic.
|
|
158
189
|
"""
|
|
@@ -166,12 +197,12 @@ class ModelMeta(models.Model):
|
|
|
166
197
|
# Delegate to logic function
|
|
167
198
|
return logic.get_inference_dataset_config_logic(self)
|
|
168
199
|
|
|
169
|
-
def natural_key(self) -> Tuple[str, str]:
|
|
200
|
+
def natural_key(self) -> Tuple[str, str, str]:
|
|
170
201
|
"""
|
|
171
202
|
Returns the natural key for serialization.
|
|
172
203
|
"""
|
|
173
204
|
# Assuming natural key is based on name and version, linked to model name
|
|
174
|
-
return (self.name, self.version, self.model.natural_key())
|
|
205
|
+
return (self.name, self.version, self.model.natural_key()[0])
|
|
175
206
|
|
|
176
207
|
def __str__(self) -> str:
|
|
177
208
|
"""String representation of the ModelMeta instance."""
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import shutil
|
|
2
2
|
from logging import getLogger
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Optional, Type
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Iterable, Optional, Type
|
|
5
5
|
|
|
6
|
-
from django.core.files import File
|
|
7
6
|
from django.db import transaction
|
|
8
7
|
from huggingface_hub import hf_hub_download
|
|
9
8
|
|
|
@@ -19,6 +18,13 @@ if TYPE_CHECKING:
|
|
|
19
18
|
from .model_meta import ModelMeta # Import ModelMeta for type hinting
|
|
20
19
|
|
|
21
20
|
|
|
21
|
+
def _get_model_meta_class():
|
|
22
|
+
"""Lazy import to avoid circular imports"""
|
|
23
|
+
from .model_meta import ModelMeta
|
|
24
|
+
|
|
25
|
+
return ModelMeta
|
|
26
|
+
|
|
27
|
+
|
|
22
28
|
def get_latest_version_number_logic(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> int:
|
|
23
29
|
"""
|
|
24
30
|
Finds the highest numerical version for a given meta_name and model_name.
|
|
@@ -55,6 +61,7 @@ def create_from_file_logic(
|
|
|
55
61
|
model_name: str,
|
|
56
62
|
labelset_name: str,
|
|
57
63
|
weights_file: str,
|
|
64
|
+
labelset_version: Optional[int | str] = None,
|
|
58
65
|
requested_version: Optional[str] = None,
|
|
59
66
|
bump_if_exists: bool = False,
|
|
60
67
|
**kwargs: Any,
|
|
@@ -70,10 +77,23 @@ def create_from_file_logic(
|
|
|
70
77
|
except AiModel.DoesNotExist as exc:
|
|
71
78
|
raise ValueError(f"AiModel with name '{model_name}' not found.") from exc
|
|
72
79
|
|
|
80
|
+
labelset_qs = LabelSet.objects.filter(name=labelset_name)
|
|
81
|
+
if labelset_version not in (None, "", -1):
|
|
82
|
+
try:
|
|
83
|
+
version_value = int(labelset_version)
|
|
84
|
+
except (TypeError, ValueError):
|
|
85
|
+
version_value = labelset_version
|
|
86
|
+
labelset_qs = labelset_qs.filter(version=version_value)
|
|
87
|
+
|
|
73
88
|
try:
|
|
74
|
-
label_set =
|
|
89
|
+
label_set = labelset_qs.get()
|
|
75
90
|
except LabelSet.DoesNotExist as exc:
|
|
76
|
-
raise ValueError(f"LabelSet with
|
|
91
|
+
raise ValueError(f"LabelSet '{labelset_name}' with version '{labelset_version}' not found.") from exc
|
|
92
|
+
except LabelSet.MultipleObjectsReturned:
|
|
93
|
+
# Prefer the highest version when duplicates remain and no explicit version requested
|
|
94
|
+
label_set = labelset_qs.order_by("-version").first()
|
|
95
|
+
if not label_set:
|
|
96
|
+
raise ValueError(f"LabelSet '{labelset_name}' could not be resolved.")
|
|
77
97
|
|
|
78
98
|
# --- Determine Version ---
|
|
79
99
|
target_version: str
|
|
@@ -165,16 +185,92 @@ def get_activation_function_logic(activation_name: str):
|
|
|
165
185
|
|
|
166
186
|
|
|
167
187
|
# Placeholder for get_inference_dataset_config_logic
|
|
188
|
+
def _normalise_scalar_sequence(value: Any) -> str | None:
|
|
189
|
+
"""Serialise sequence-like values into the canonical comma-separated form."""
|
|
190
|
+
|
|
191
|
+
if value in (None, ""):
|
|
192
|
+
return None
|
|
193
|
+
if isinstance(value, str):
|
|
194
|
+
return value
|
|
195
|
+
if isinstance(value, (list, tuple)):
|
|
196
|
+
return ",".join(str(item) for item in value)
|
|
197
|
+
return str(value)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _parse_float_sequence(value: Any, *, fallback: Iterable[float]) -> list[float]:
|
|
201
|
+
"""Coerce stored normalisation strings/iterables to float lists."""
|
|
202
|
+
|
|
203
|
+
if value in (None, ""):
|
|
204
|
+
return list(fallback)
|
|
205
|
+
|
|
206
|
+
tokens: Iterable[Any]
|
|
207
|
+
if isinstance(value, str):
|
|
208
|
+
tokens = [tok.strip() for tok in value.split(",") if tok.strip()]
|
|
209
|
+
elif isinstance(value, (list, tuple)):
|
|
210
|
+
tokens = value
|
|
211
|
+
else:
|
|
212
|
+
tokens = [value]
|
|
213
|
+
|
|
214
|
+
parsed: list[float] = []
|
|
215
|
+
for token in tokens:
|
|
216
|
+
try:
|
|
217
|
+
parsed.append(float(token))
|
|
218
|
+
except (TypeError, ValueError):
|
|
219
|
+
logger.warning("Failed to parse normalisation value %r; using fallback", token)
|
|
220
|
+
return list(fallback)
|
|
221
|
+
|
|
222
|
+
return parsed or list(fallback)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _parse_axes(axes_value: str | Iterable[Any]) -> list[int]:
|
|
226
|
+
"""Normalise stored axis notation to integer indices.
|
|
227
|
+
|
|
228
|
+
Historic metadata mixes numeric strings ("2,0,1") with symbolic tokens
|
|
229
|
+
("CHW", "HWC"). The inference code ultimately expects a list of integers,
|
|
230
|
+
so we coerce common symbolic forms to their numeric equivalents and fall
|
|
231
|
+
back to sequential indices when the format is unknown.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
if not axes_value:
|
|
235
|
+
return [0, 1, 2]
|
|
236
|
+
|
|
237
|
+
if isinstance(axes_value, str):
|
|
238
|
+
token_source = axes_value.strip()
|
|
239
|
+
if "," in token_source:
|
|
240
|
+
tokens = [token.strip() for token in token_source.split(",") if token.strip()]
|
|
241
|
+
else:
|
|
242
|
+
tokens = [char for char in token_source if char.strip()]
|
|
243
|
+
else:
|
|
244
|
+
tokens = [str(token).strip() for token in axes_value if str(token).strip()]
|
|
245
|
+
|
|
246
|
+
symbol_map = {"C": 0, "H": 1, "W": 2}
|
|
247
|
+
parsed_axes: list[int] = []
|
|
248
|
+
|
|
249
|
+
for idx, token in enumerate(tokens):
|
|
250
|
+
normalised = token.upper()
|
|
251
|
+
if normalised.lstrip("+-").isdigit():
|
|
252
|
+
parsed_axes.append(int(normalised))
|
|
253
|
+
elif normalised in symbol_map:
|
|
254
|
+
parsed_axes.append(symbol_map[normalised])
|
|
255
|
+
else:
|
|
256
|
+
logger.warning("Unknown axes token '%s'; defaulting to index order", token)
|
|
257
|
+
parsed_axes.append(idx)
|
|
258
|
+
|
|
259
|
+
return parsed_axes or [0, 1, 2]
|
|
260
|
+
|
|
261
|
+
|
|
168
262
|
def get_inference_dataset_config_logic(model_meta: "ModelMeta") -> dict:
|
|
169
263
|
# This would typically extract relevant fields from model_meta
|
|
170
264
|
# for configuring a dataset during inference
|
|
265
|
+
DEFAULT_MEAN = (0.45211223, 0.27139644, 0.19264949)
|
|
266
|
+
DEFAULT_STD = (0.31418097, 0.21088019, 0.16059452)
|
|
267
|
+
|
|
171
268
|
return {
|
|
172
|
-
"mean":
|
|
173
|
-
"std":
|
|
174
|
-
"size_y": model_meta.size_y
|
|
175
|
-
"size_x": model_meta.size_x
|
|
176
|
-
"axes":
|
|
177
|
-
# Add other relevant config like normalization type, etc.
|
|
269
|
+
"mean": _parse_float_sequence(model_meta.mean, fallback=DEFAULT_MEAN),
|
|
270
|
+
"std": _parse_float_sequence(model_meta.std, fallback=DEFAULT_STD),
|
|
271
|
+
"size_y": int(model_meta.size_y) if model_meta.size_y else 716,
|
|
272
|
+
"size_x": int(model_meta.size_x) if model_meta.size_x else 716,
|
|
273
|
+
"axes": _parse_axes(model_meta.axes),
|
|
178
274
|
}
|
|
179
275
|
|
|
180
276
|
|
|
@@ -294,21 +390,45 @@ def infer_default_model_meta_from_hf(model_id: str) -> dict[str, Any]:
|
|
|
294
390
|
}
|
|
295
391
|
|
|
296
392
|
|
|
297
|
-
def setup_default_from_huggingface_logic(
|
|
393
|
+
def setup_default_from_huggingface_logic(
|
|
394
|
+
cls,
|
|
395
|
+
model_id: str,
|
|
396
|
+
labelset_name: str | None = None,
|
|
397
|
+
labelset_version: Optional[int | str] = None,
|
|
398
|
+
):
|
|
298
399
|
"""
|
|
299
400
|
Downloads model weights from Hugging Face and auto-fills ModelMeta fields.
|
|
300
401
|
"""
|
|
301
402
|
meta = infer_default_model_meta_from_hf(model_id)
|
|
302
403
|
|
|
303
|
-
# Download weights
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
404
|
+
# Download safetensor weights; raise a clear error if unavailable
|
|
405
|
+
try:
|
|
406
|
+
weights_path = hf_hub_download(
|
|
407
|
+
repo_id=model_id,
|
|
408
|
+
filename="colo_segmentation_RegNetX800MF_base.safetensors",
|
|
409
|
+
local_dir=WEIGHTS_DIR,
|
|
410
|
+
)
|
|
411
|
+
except Exception as exc: # pragma: no cover - network errors
|
|
412
|
+
raise RuntimeError("Failed to download safetensor weights from Hugging Face; ensure the repository provides a .safetensors artifact.") from exc
|
|
309
413
|
|
|
310
414
|
ai_model, _ = AiModel.objects.get_or_create(name=meta["name"])
|
|
311
|
-
|
|
415
|
+
if not labelset_name:
|
|
416
|
+
labelset = LabelSet.objects.first()
|
|
417
|
+
if not labelset:
|
|
418
|
+
raise ValueError("No labelset found and no labelset_name provided")
|
|
419
|
+
else:
|
|
420
|
+
labelset_qs = LabelSet.objects.filter(name=labelset_name)
|
|
421
|
+
if labelset_version not in (None, "", -1):
|
|
422
|
+
try:
|
|
423
|
+
version_value = int(labelset_version)
|
|
424
|
+
except (TypeError, ValueError):
|
|
425
|
+
version_value = labelset_version
|
|
426
|
+
labelset_qs = labelset_qs.filter(version=version_value)
|
|
427
|
+
labelset = labelset_qs.order_by("-version").first()
|
|
428
|
+
if not labelset:
|
|
429
|
+
raise ValueError(f"LabelSet '{labelset_name}' with version '{labelset_version}' not found.")
|
|
430
|
+
|
|
431
|
+
ModelMeta = _get_model_meta_class()
|
|
312
432
|
model_meta = ModelMeta.objects.filter(name=meta["name"], model=ai_model).first()
|
|
313
433
|
if model_meta:
|
|
314
434
|
logger.info(f"ModelMeta {meta['name']} for model {ai_model.name} already exists. Skipping creation.")
|
|
@@ -319,6 +439,7 @@ def setup_default_from_huggingface_logic(cls, model_id: str, labelset_name: str
|
|
|
319
439
|
meta_name=meta["name"],
|
|
320
440
|
model_name=ai_model.name,
|
|
321
441
|
labelset_name=labelset.name,
|
|
442
|
+
labelset_version=labelset.version,
|
|
322
443
|
weights_file=weights_path,
|
|
323
444
|
activation=meta["activation"],
|
|
324
445
|
mean=meta["mean"],
|
|
@@ -1,48 +1,44 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import TYPE_CHECKING, cast
|
|
2
|
+
|
|
2
3
|
from django.core.files import File
|
|
3
|
-
from
|
|
4
|
+
from django.db import models
|
|
4
5
|
|
|
5
6
|
if TYPE_CHECKING:
|
|
6
7
|
from ..media.pdf.report_reader.report_reader_flag import ReportReaderFlag
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
class PdfType(models.Model):
|
|
9
11
|
"""
|
|
10
12
|
Defines a specific type or format of PDF report, linking to flags used for parsing.
|
|
11
13
|
|
|
12
14
|
Used to configure how different PDF report layouts are processed.
|
|
13
15
|
"""
|
|
16
|
+
|
|
14
17
|
name = models.CharField(max_length=255)
|
|
15
18
|
|
|
16
|
-
patient_info_line = models.ForeignKey(
|
|
17
|
-
"ReportReaderFlag",
|
|
18
|
-
related_name="pdf_type_patient_info_line",
|
|
19
|
-
on_delete=models.CASCADE
|
|
20
|
-
)
|
|
19
|
+
patient_info_line = models.ForeignKey("ReportReaderFlag", related_name="pdf_type_patient_info_line", on_delete=models.CASCADE)
|
|
21
20
|
endoscope_info_line = models.ForeignKey(
|
|
22
21
|
"ReportReaderFlag",
|
|
23
|
-
related_name="pdf_type_endoscopy_info_line",
|
|
22
|
+
related_name="pdf_type_endoscopy_info_line",
|
|
24
23
|
on_delete=models.CASCADE,
|
|
25
24
|
)
|
|
26
|
-
examiner_info_line = models.ForeignKey(
|
|
27
|
-
"ReportReaderFlag",
|
|
28
|
-
related_name="pdf_type_examiner_info_line",
|
|
29
|
-
on_delete=models.CASCADE
|
|
30
|
-
)
|
|
25
|
+
examiner_info_line = models.ForeignKey("ReportReaderFlag", related_name="pdf_type_examiner_info_line", on_delete=models.CASCADE)
|
|
31
26
|
cut_off_above_lines = models.ManyToManyField(
|
|
32
27
|
"ReportReaderFlag",
|
|
33
|
-
related_name="pdf_type_cut_off_above_lines",
|
|
28
|
+
related_name="pdf_type_cut_off_above_lines",
|
|
34
29
|
)
|
|
35
30
|
cut_off_below_lines = models.ManyToManyField(
|
|
36
31
|
"ReportReaderFlag",
|
|
37
|
-
related_name="pdf_type_cut_off_below_lines",
|
|
32
|
+
related_name="pdf_type_cut_off_below_lines",
|
|
38
33
|
)
|
|
39
34
|
|
|
40
35
|
if TYPE_CHECKING:
|
|
41
|
-
patient_info_line: "ReportReaderFlag"
|
|
42
|
-
endoscope_info_line: "ReportReaderFlag"
|
|
43
|
-
examiner_info_line: "ReportReaderFlag"
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
patient_info_line: models.ForeignKey["ReportReaderFlag"]
|
|
37
|
+
endoscope_info_line: models.ForeignKey["ReportReaderFlag"]
|
|
38
|
+
examiner_info_line: models.ForeignKey["ReportReaderFlag"]
|
|
39
|
+
|
|
40
|
+
cut_off_above_lines = cast(models.manager.RelatedManager["ReportReaderFlag"], cut_off_above_lines)
|
|
41
|
+
cut_off_below_lines = cast(models.manager.RelatedManager["ReportReaderFlag"], cut_off_below_lines)
|
|
46
42
|
|
|
47
43
|
def __str__(self):
|
|
48
44
|
"""Returns a string summary of the PDF type and its associated flags."""
|
|
@@ -53,7 +49,7 @@ class PdfType(models.Model):
|
|
|
53
49
|
summary += f"\nExaminer Info Line: {self.examiner_info_line.value}"
|
|
54
50
|
summary += f"\nCut Off Above Lines: {[_.value for _ in self.cut_off_above_lines.all()]}"
|
|
55
51
|
summary += f"\nCut Off Below Lines: {[_.value for _ in self.cut_off_below_lines.all()]}"
|
|
56
|
-
|
|
52
|
+
|
|
57
53
|
return summary
|
|
58
54
|
|
|
59
55
|
@classmethod
|
|
@@ -61,18 +57,17 @@ class PdfType(models.Model):
|
|
|
61
57
|
"""Returns a default PdfType instance, typically used as a fallback."""
|
|
62
58
|
return PdfType.objects.get(name="ukw-endoscopy-examination-report-generic")
|
|
63
59
|
|
|
60
|
+
|
|
64
61
|
class PdfMeta(models.Model):
|
|
65
62
|
"""
|
|
66
63
|
Stores metadata associated with a specific PDF document file.
|
|
67
64
|
"""
|
|
65
|
+
|
|
68
66
|
pdf_type = models.ForeignKey(PdfType, on_delete=models.CASCADE)
|
|
69
67
|
date = models.DateField()
|
|
70
68
|
time = models.TimeField()
|
|
71
69
|
pdf_hash = models.CharField(max_length=255, unique=True)
|
|
72
70
|
|
|
73
|
-
if TYPE_CHECKING:
|
|
74
|
-
pdf_type: "PdfType"
|
|
75
|
-
|
|
76
71
|
def __str__(self):
|
|
77
72
|
"""Returns the PDF hash as its string representation."""
|
|
78
73
|
return str(self.pdf_hash)
|