endoreg-db 0.8.8.9__py3-none-any.whl → 0.8.9.10__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/admin.py +10 -5
- endoreg_db/apps.py +4 -7
- endoreg_db/authz/auth.py +1 -0
- endoreg_db/authz/backends.py +1 -1
- endoreg_db/authz/management/commands/list_routes.py +2 -0
- endoreg_db/authz/middleware.py +8 -7
- endoreg_db/authz/permissions.py +21 -10
- endoreg_db/authz/policy.py +14 -19
- endoreg_db/authz/views_auth.py +14 -10
- endoreg_db/codemods/rename_datetime_fields.py +8 -1
- endoreg_db/exceptions.py +5 -2
- endoreg_db/forms/__init__.py +0 -1
- endoreg_db/forms/examination_form.py +4 -3
- endoreg_db/forms/patient_finding_intervention_form.py +30 -8
- endoreg_db/forms/patient_form.py +9 -13
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/settings/__init__.py +4 -1
- endoreg_db/forms/unit.py +2 -1
- endoreg_db/helpers/count_db.py +17 -14
- endoreg_db/helpers/default_objects.py +2 -1
- endoreg_db/helpers/download_segmentation_model.py +4 -3
- endoreg_db/helpers/interact.py +0 -5
- endoreg_db/helpers/test_video_helper.py +33 -25
- endoreg_db/import_files/__init__.py +1 -1
- endoreg_db/import_files/context/__init__.py +1 -1
- endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
- endoreg_db/import_files/context/ensure_center.py +4 -4
- endoreg_db/import_files/context/file_lock.py +3 -3
- endoreg_db/import_files/context/import_context.py +11 -12
- endoreg_db/import_files/context/validate_directories.py +1 -0
- endoreg_db/import_files/file_storage/create_report_file.py +57 -34
- endoreg_db/import_files/file_storage/create_video_file.py +64 -35
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
- endoreg_db/import_files/file_storage/state_management.py +146 -83
- endoreg_db/import_files/file_storage/storage.py +5 -1
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
- endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
- endoreg_db/import_files/report_import_service.py +36 -30
- endoreg_db/import_files/video_import_service.py +27 -23
- endoreg_db/logger_conf.py +56 -40
- endoreg_db/management/__init__.py +1 -1
- endoreg_db/management/commands/__init__.py +1 -1
- endoreg_db/management/commands/check_auth.py +45 -38
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
- endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
- endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
- endoreg_db/management/commands/fix_video_paths.py +75 -54
- endoreg_db/management/commands/import_report.py +1 -3
- endoreg_db/management/commands/list_routes.py +2 -0
- endoreg_db/management/commands/load_ai_model_data.py +8 -2
- endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
- endoreg_db/management/commands/load_center_data.py +3 -3
- endoreg_db/management/commands/load_distribution_data.py +35 -38
- endoreg_db/management/commands/load_endoscope_data.py +0 -3
- endoreg_db/management/commands/load_examination_data.py +20 -4
- endoreg_db/management/commands/load_finding_data.py +18 -3
- endoreg_db/management/commands/load_gender_data.py +17 -24
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
- endoreg_db/management/commands/load_information_source.py +0 -3
- endoreg_db/management/commands/load_lab_value_data.py +14 -3
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_name_data.py +1 -2
- endoreg_db/management/commands/load_pdf_type_data.py +4 -8
- endoreg_db/management/commands/load_profession_data.py +0 -1
- endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
- endoreg_db/management/commands/load_requirement_data.py +6 -2
- endoreg_db/management/commands/load_unit_data.py +0 -4
- endoreg_db/management/commands/load_user_groups.py +5 -7
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +22 -16
- endoreg_db/management/commands/setup_endoreg_db.py +110 -32
- endoreg_db/management/commands/storage_management.py +14 -8
- endoreg_db/management/commands/summarize_db_content.py +154 -63
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +82 -50
- endoreg_db/management/commands/video_validation.py +4 -6
- endoreg_db/migrations/0001_initial.py +112 -63
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +8 -0
- endoreg_db/models/administration/ai/active_model.py +5 -5
- endoreg_db/models/administration/ai/ai_model.py +41 -18
- endoreg_db/models/administration/ai/model_type.py +1 -0
- endoreg_db/models/administration/case/case.py +22 -22
- endoreg_db/models/administration/center/__init__.py +5 -5
- endoreg_db/models/administration/center/center.py +6 -2
- endoreg_db/models/administration/center/center_resource.py +18 -4
- endoreg_db/models/administration/center/center_shift.py +3 -1
- endoreg_db/models/administration/center/center_waste.py +6 -2
- endoreg_db/models/administration/person/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/employee_type.py +3 -1
- endoreg_db/models/administration/person/examiner/__init__.py +1 -1
- endoreg_db/models/administration/person/examiner/examiner.py +10 -2
- endoreg_db/models/administration/person/names/first_name.py +6 -4
- endoreg_db/models/administration/person/names/last_name.py +4 -3
- endoreg_db/models/administration/person/patient/__init__.py +1 -1
- endoreg_db/models/administration/person/patient/patient.py +0 -1
- endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
- endoreg_db/models/administration/person/person.py +1 -1
- endoreg_db/models/administration/product/__init__.py +7 -6
- endoreg_db/models/administration/product/product.py +6 -2
- endoreg_db/models/administration/product/product_group.py +9 -7
- endoreg_db/models/administration/product/product_material.py +9 -2
- endoreg_db/models/administration/product/reference_product.py +64 -15
- endoreg_db/models/administration/qualification/qualification.py +3 -1
- endoreg_db/models/administration/shift/shift.py +3 -1
- endoreg_db/models/administration/shift/shift_type.py +12 -4
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +1 -1
- endoreg_db/models/label/label.py +10 -2
- endoreg_db/models/label/label_set.py +3 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
- endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
- endoreg_db/models/media/__init__.py +12 -5
- endoreg_db/models/media/frame/__init__.py +1 -1
- endoreg_db/models/media/frame/frame.py +34 -8
- endoreg_db/models/media/pdf/__init__.py +2 -1
- endoreg_db/models/media/pdf/raw_pdf.py +11 -4
- endoreg_db/models/media/pdf/report_file.py +6 -2
- endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
- endoreg_db/models/media/video/create_from_file.py +20 -41
- endoreg_db/models/media/video/pipe_1.py +75 -30
- endoreg_db/models/media/video/pipe_2.py +37 -12
- endoreg_db/models/media/video/video_file.py +36 -24
- endoreg_db/models/media/video/video_file_ai.py +235 -70
- endoreg_db/models/media/video/video_file_anonymize.py +240 -65
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
- endoreg_db/models/media/video/video_file_io.py +85 -33
- endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
- endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
- endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
- endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
- endoreg_db/models/media/video/video_file_segments.py +118 -27
- endoreg_db/models/media/video/video_metadata.py +25 -6
- endoreg_db/models/media/video/video_processing.py +54 -15
- endoreg_db/models/medical/__init__.py +3 -13
- endoreg_db/models/medical/contraindication/__init__.py +3 -1
- endoreg_db/models/medical/disease.py +18 -6
- endoreg_db/models/medical/event.py +6 -2
- endoreg_db/models/medical/examination/__init__.py +5 -1
- endoreg_db/models/medical/examination/examination.py +22 -6
- endoreg_db/models/medical/examination/examination_indication.py +23 -7
- endoreg_db/models/medical/examination/examination_time.py +6 -2
- endoreg_db/models/medical/finding/__init__.py +3 -1
- endoreg_db/models/medical/finding/finding.py +37 -12
- endoreg_db/models/medical/finding/finding_classification.py +27 -8
- endoreg_db/models/medical/finding/finding_intervention.py +19 -6
- endoreg_db/models/medical/finding/finding_type.py +3 -1
- endoreg_db/models/medical/hardware/__init__.py +1 -1
- endoreg_db/models/medical/hardware/endoscope.py +14 -2
- endoreg_db/models/medical/laboratory/__init__.py +1 -1
- endoreg_db/models/medical/laboratory/lab_value.py +139 -39
- endoreg_db/models/medical/medication/__init__.py +7 -3
- endoreg_db/models/medical/medication/medication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
- endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
- endoreg_db/models/medical/medication/medication_schedule.py +3 -1
- endoreg_db/models/medical/patient/__init__.py +2 -10
- endoreg_db/models/medical/patient/medication_examples.py +3 -14
- endoreg_db/models/medical/patient/patient_disease.py +17 -5
- endoreg_db/models/medical/patient/patient_event.py +12 -4
- endoreg_db/models/medical/patient/patient_examination.py +52 -15
- endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
- endoreg_db/models/medical/patient/patient_finding.py +105 -29
- endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
- endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
- endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
- endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
- endoreg_db/models/medical/patient/patient_medication.py +25 -7
- endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
- endoreg_db/models/metadata/model_meta.py +40 -12
- endoreg_db/models/metadata/model_meta_logic.py +51 -16
- endoreg_db/models/metadata/sensitive_meta.py +65 -28
- endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
- endoreg_db/models/metadata/video_meta.py +146 -39
- endoreg_db/models/metadata/video_prediction_logic.py +70 -21
- endoreg_db/models/metadata/video_prediction_meta.py +80 -27
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +10 -10
- endoreg_db/models/other/distribution/__init__.py +9 -7
- endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
- endoreg_db/models/other/emission/__init__.py +1 -1
- endoreg_db/models/other/emission/emission_factor.py +9 -3
- endoreg_db/models/other/information_source.py +15 -5
- endoreg_db/models/other/material.py +3 -1
- endoreg_db/models/other/transport_route.py +3 -1
- endoreg_db/models/other/unit.py +6 -2
- endoreg_db/models/report/report.py +0 -1
- endoreg_db/models/requirement/requirement.py +84 -27
- endoreg_db/models/requirement/requirement_error.py +5 -6
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
- endoreg_db/models/requirement/requirement_operator.py +28 -8
- endoreg_db/models/requirement/requirement_set.py +34 -11
- endoreg_db/models/state/__init__.py +1 -0
- endoreg_db/models/state/audit_ledger.py +9 -2
- endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +0 -1
- endoreg_db/models/state/video.py +2 -3
- endoreg_db/models/utils.py +4 -2
- endoreg_db/queries/__init__.py +2 -6
- endoreg_db/queries/annotations/__init__.py +1 -3
- endoreg_db/queries/annotations/legacy.py +37 -26
- endoreg_db/root_urls.py +3 -4
- endoreg_db/schemas/examination_evaluation.py +3 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
- endoreg_db/serializers/__init__.py +2 -8
- endoreg_db/serializers/administration/__init__.py +1 -2
- endoreg_db/serializers/administration/ai/__init__.py +0 -1
- endoreg_db/serializers/administration/ai/active_model.py +3 -1
- endoreg_db/serializers/administration/ai/ai_model.py +5 -3
- endoreg_db/serializers/administration/ai/model_type.py +3 -1
- endoreg_db/serializers/administration/center.py +7 -2
- endoreg_db/serializers/administration/gender.py +4 -2
- endoreg_db/serializers/anonymization.py +13 -13
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
- endoreg_db/serializers/examination/__init__.py +1 -1
- endoreg_db/serializers/examination/base.py +12 -13
- endoreg_db/serializers/examination/dropdown.py +6 -7
- endoreg_db/serializers/examination_serializer.py +3 -6
- endoreg_db/serializers/finding/__init__.py +1 -1
- endoreg_db/serializers/finding/finding.py +14 -7
- endoreg_db/serializers/finding_classification/__init__.py +3 -3
- endoreg_db/serializers/finding_classification/choice.py +3 -3
- endoreg_db/serializers/finding_classification/classification.py +2 -4
- endoreg_db/serializers/label_video_segment/__init__.py +5 -3
- endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
- endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
- endoreg_db/serializers/meta/__init__.py +1 -2
- endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
- endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
- endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
- endoreg_db/serializers/misc/__init__.py +2 -2
- endoreg_db/serializers/misc/file_overview.py +11 -7
- endoreg_db/serializers/misc/stats.py +10 -8
- endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
- endoreg_db/serializers/misc/upload_job.py +32 -29
- endoreg_db/serializers/patient/__init__.py +2 -1
- endoreg_db/serializers/patient/patient.py +32 -15
- endoreg_db/serializers/patient/patient_dropdown.py +11 -3
- endoreg_db/serializers/patient_examination/__init__.py +1 -1
- endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
- endoreg_db/serializers/patient_finding/__init__.py +1 -1
- endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
- endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
- endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
- endoreg_db/serializers/pdf/__init__.py +1 -3
- endoreg_db/serializers/requirements/requirement_schema.py +1 -6
- endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
- endoreg_db/serializers/video/__init__.py +2 -2
- endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
- endoreg_db/serializers/video/video_file_brief.py +6 -2
- endoreg_db/serializers/video/video_file_detail.py +36 -23
- endoreg_db/serializers/video/video_file_list.py +4 -2
- endoreg_db/serializers/video/video_processing_history.py +54 -50
- endoreg_db/services/__init__.py +1 -1
- endoreg_db/services/anonymization.py +2 -2
- endoreg_db/services/examination_evaluation.py +40 -17
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/polling_coordinator.py +101 -70
- endoreg_db/services/pseudonym_service.py +27 -22
- endoreg_db/services/report_import.py +6 -3
- endoreg_db/services/segment_sync.py +75 -59
- endoreg_db/services/video_import.py +6 -7
- endoreg_db/urls/__init__.py +2 -2
- endoreg_db/urls/ai.py +7 -25
- endoreg_db/urls/anonymization.py +61 -15
- endoreg_db/urls/auth.py +4 -4
- endoreg_db/urls/classification.py +4 -9
- endoreg_db/urls/examination.py +27 -18
- endoreg_db/urls/media.py +27 -34
- endoreg_db/urls/patient.py +11 -7
- endoreg_db/urls/requirements.py +3 -1
- endoreg_db/urls/root_urls.py +2 -3
- endoreg_db/urls/stats.py +24 -16
- endoreg_db/urls/upload.py +3 -11
- endoreg_db/utils/__init__.py +14 -15
- endoreg_db/utils/ai/__init__.py +1 -1
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +2 -1
- endoreg_db/utils/ai/inference_dataset.py +14 -15
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
- endoreg_db/utils/ai/predict.py +4 -4
- endoreg_db/utils/ai/preprocess.py +19 -11
- endoreg_db/utils/calc_duration_seconds.py +4 -4
- endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
- endoreg_db/utils/check_video_files.py +74 -47
- endoreg_db/utils/cropping.py +10 -9
- endoreg_db/utils/dataloader.py +11 -3
- endoreg_db/utils/dates.py +3 -4
- endoreg_db/utils/defaults/set_default_center.py +7 -6
- endoreg_db/utils/env.py +6 -2
- endoreg_db/utils/extract_specific_frames.py +24 -9
- endoreg_db/utils/file_operations.py +30 -18
- endoreg_db/utils/fix_video_path_direct.py +57 -41
- endoreg_db/utils/frame_anonymization_utils.py +157 -157
- endoreg_db/utils/hashs.py +3 -18
- endoreg_db/utils/links/requirement_link.py +96 -52
- endoreg_db/utils/ocr.py +30 -25
- endoreg_db/utils/operation_log.py +61 -0
- endoreg_db/utils/parse_and_generate_yaml.py +12 -13
- endoreg_db/utils/paths.py +6 -6
- endoreg_db/utils/permissions.py +40 -24
- endoreg_db/utils/pipelines/process_video_dir.py +50 -26
- endoreg_db/utils/product/sum_emissions.py +5 -3
- endoreg_db/utils/product/sum_weights.py +4 -2
- endoreg_db/utils/pydantic_models/__init__.py +3 -4
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
- endoreg_db/utils/setup_config.py +21 -5
- endoreg_db/utils/storage.py +3 -1
- endoreg_db/utils/translation.py +19 -15
- endoreg_db/utils/uuid.py +1 -0
- endoreg_db/utils/validate_endo_roi.py +12 -4
- endoreg_db/utils/validate_subcategory_dict.py +26 -24
- endoreg_db/utils/validate_video_detailed.py +207 -149
- endoreg_db/utils/video/__init__.py +7 -3
- endoreg_db/utils/video/extract_frames.py +30 -18
- endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
- endoreg_db/utils/video/names.py +11 -6
- endoreg_db/utils/video/streaming_processor.py +175 -101
- endoreg_db/utils/video/video_splitter.py +30 -19
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
- endoreg_db/views/__init__.py +0 -20
- endoreg_db/views/anonymization/__init__.py +6 -2
- endoreg_db/views/anonymization/media_management.py +2 -6
- endoreg_db/views/anonymization/overview.py +34 -1
- endoreg_db/views/anonymization/validate.py +79 -18
- endoreg_db/views/auth/__init__.py +1 -1
- endoreg_db/views/auth/keycloak.py +16 -14
- endoreg_db/views/examination/__init__.py +12 -15
- endoreg_db/views/examination/examination.py +5 -5
- endoreg_db/views/examination/examination_manifest_cache.py +5 -5
- endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
- endoreg_db/views/examination/get_finding_classifications.py +9 -7
- endoreg_db/views/examination/get_findings.py +8 -10
- endoreg_db/views/examination/get_instruments.py +3 -2
- endoreg_db/views/examination/get_interventions.py +1 -1
- endoreg_db/views/finding/__init__.py +2 -2
- endoreg_db/views/finding/finding.py +58 -54
- endoreg_db/views/finding/get_classifications.py +1 -1
- endoreg_db/views/finding/get_interventions.py +1 -1
- endoreg_db/views/finding_classification/__init__.py +5 -5
- endoreg_db/views/finding_classification/finding_classification.py +5 -6
- endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
- endoreg_db/views/media/__init__.py +13 -13
- endoreg_db/views/media/pdf_media.py +9 -9
- endoreg_db/views/media/sensitive_metadata.py +10 -7
- endoreg_db/views/media/video_media.py +4 -4
- endoreg_db/views/meta/__init__.py +1 -1
- endoreg_db/views/meta/sensitive_meta_list.py +20 -22
- endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
- endoreg_db/views/misc/__init__.py +6 -34
- endoreg_db/views/misc/center.py +2 -1
- endoreg_db/views/misc/csrf.py +2 -1
- endoreg_db/views/misc/gender.py +2 -1
- endoreg_db/views/misc/stats.py +141 -106
- endoreg_db/views/patient/__init__.py +1 -3
- endoreg_db/views/patient/patient.py +141 -99
- endoreg_db/views/patient_examination/__init__.py +5 -5
- endoreg_db/views/patient_examination/patient_examination.py +43 -42
- endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
- endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
- endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
- endoreg_db/views/patient_examination/video.py +114 -80
- endoreg_db/views/patient_finding/__init__.py +1 -1
- endoreg_db/views/patient_finding/patient_finding.py +17 -10
- endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
- endoreg_db/views/patient_finding_classification/__init__.py +1 -1
- endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
- endoreg_db/views/report/reimport.py +1 -1
- endoreg_db/views/report/report_stream.py +5 -8
- endoreg_db/views/requirement/__init__.py +2 -1
- endoreg_db/views/requirement/evaluate.py +7 -9
- endoreg_db/views/requirement/lookup.py +2 -3
- endoreg_db/views/requirement/lookup_store.py +0 -1
- endoreg_db/views/requirement/requirement_utils.py +2 -4
- endoreg_db/views/stats/__init__.py +4 -4
- endoreg_db/views/stats/stats_views.py +152 -115
- endoreg_db/views/video/__init__.py +18 -27
- endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
- endoreg_db/views/{ai → video/ai}/label.py +20 -16
- endoreg_db/views/video/correction.py +5 -6
- endoreg_db/views/video/reimport.py +134 -99
- endoreg_db/views/video/segments_crud.py +134 -44
- endoreg_db/views/video/video_apply_mask.py +13 -12
- endoreg_db/views/video/video_correction.py +2 -1
- endoreg_db/views/video/video_download_processed.py +15 -15
- endoreg_db/views/video/video_meta_stats.py +7 -6
- endoreg_db/views/video/video_processing_history.py +3 -2
- endoreg_db/views/video/video_remove_frames.py +13 -12
- endoreg_db/views/video/video_stream.py +110 -82
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +436 -433
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +0 -119
- endoreg_db/management/commands/import_fallback_video.py +0 -203
- endoreg_db/management/commands/import_video.py +0 -422
- endoreg_db/management/commands/import_video_with_classification.py +0 -367
- endoreg_db/models/media/processing_history/processing_history.py +0 -96
- endoreg_db/serializers/label/__init__.py +0 -7
- endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
- endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
- endoreg_db/services/__old/pdf_import.py +0 -1487
- endoreg_db/services/__old/video_import.py +0 -1306
- endoreg_db/tasks/upload_tasks.py +0 -216
- endoreg_db/tasks/video_ingest.py +0 -161
- endoreg_db/tasks/video_processing_tasks.py +0 -327
- endoreg_db/views/misc/translation.py +0 -182
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -27,7 +27,11 @@ def _convert_sequences_to_db_segments(
|
|
|
27
27
|
"""
|
|
28
28
|
from ...label import Label, LabelVideoSegment # Local import for models
|
|
29
29
|
|
|
30
|
-
logger.info(
|
|
30
|
+
logger.info(
|
|
31
|
+
"Converting sequences to LabelVideoSegments for video %s, prediction meta %s",
|
|
32
|
+
video.video_hash,
|
|
33
|
+
video_prediction_meta.pk,
|
|
34
|
+
)
|
|
31
35
|
created_count = 0
|
|
32
36
|
skipped_count = 0
|
|
33
37
|
error_count = 0
|
|
@@ -45,14 +49,21 @@ def _convert_sequences_to_db_segments(
|
|
|
45
49
|
try:
|
|
46
50
|
label = Label.objects.get(name=label_name) # require pre-existing label
|
|
47
51
|
except Exception as e:
|
|
48
|
-
logger.error(
|
|
52
|
+
logger.error(
|
|
53
|
+
"Could not get or create Label '%s': %s", label_name, e, exc_info=True
|
|
54
|
+
)
|
|
49
55
|
error_count += len(sequence_list)
|
|
50
56
|
continue
|
|
51
57
|
|
|
52
58
|
segments_to_create = []
|
|
53
59
|
for start_frame, end_frame in sequence_list:
|
|
54
60
|
if start_frame > end_frame or start_frame < 0:
|
|
55
|
-
logger.warning(
|
|
61
|
+
logger.warning(
|
|
62
|
+
"Skipping invalid sequence for label '%s': start=%d, end=%d",
|
|
63
|
+
label_name,
|
|
64
|
+
start_frame,
|
|
65
|
+
end_frame,
|
|
66
|
+
)
|
|
56
67
|
skipped_count += 1
|
|
57
68
|
continue
|
|
58
69
|
|
|
@@ -68,19 +79,34 @@ def _convert_sequences_to_db_segments(
|
|
|
68
79
|
|
|
69
80
|
if segments_to_create:
|
|
70
81
|
try:
|
|
71
|
-
LabelVideoSegment.objects.bulk_create(
|
|
82
|
+
LabelVideoSegment.objects.bulk_create(
|
|
83
|
+
segments_to_create, ignore_conflicts=True
|
|
84
|
+
)
|
|
72
85
|
created_count += len(segments_to_create)
|
|
73
|
-
logger.debug(
|
|
86
|
+
logger.debug(
|
|
87
|
+
"Bulk created %d segments for label '%s'",
|
|
88
|
+
len(segments_to_create),
|
|
89
|
+
label_name,
|
|
90
|
+
)
|
|
74
91
|
except Exception as e:
|
|
75
|
-
logger.error(
|
|
92
|
+
logger.error(
|
|
93
|
+
"Error bulk creating segments for label '%s': %s",
|
|
94
|
+
label_name,
|
|
95
|
+
e,
|
|
96
|
+
exc_info=True,
|
|
97
|
+
)
|
|
76
98
|
error_count += len(segments_to_create)
|
|
77
99
|
|
|
78
|
-
newly_created_segments = LabelVideoSegment.objects.filter(
|
|
100
|
+
newly_created_segments = LabelVideoSegment.objects.filter(
|
|
101
|
+
video_file=video,
|
|
102
|
+
prediction_meta=video_prediction_meta,
|
|
103
|
+
label__name__in=processed_labels,
|
|
104
|
+
)
|
|
79
105
|
|
|
80
106
|
logger.info(
|
|
81
107
|
"Attempting to create state objects for %d potentially new segments (Video: %s, PredictionMeta: %s)",
|
|
82
108
|
newly_created_segments.count(),
|
|
83
|
-
video.
|
|
109
|
+
video.video_hash,
|
|
84
110
|
video_prediction_meta.pk,
|
|
85
111
|
)
|
|
86
112
|
|
|
@@ -90,12 +116,18 @@ def _convert_sequences_to_db_segments(
|
|
|
90
116
|
if created:
|
|
91
117
|
state_created_count += 1
|
|
92
118
|
except Exception as e:
|
|
93
|
-
logger.error(
|
|
119
|
+
logger.error(
|
|
120
|
+
"Failed to get or create state for segment %s (Video: %s): %s",
|
|
121
|
+
segment.pk,
|
|
122
|
+
video.video_hash,
|
|
123
|
+
e,
|
|
124
|
+
exc_info=True,
|
|
125
|
+
)
|
|
94
126
|
state_error_count += 1
|
|
95
127
|
|
|
96
128
|
logger.info(
|
|
97
129
|
"LabelVideoSegment conversion finished for video %s. Segments Created: %d, Skipped: %d, Errors: %d. States Created: %d, State Errors: %d",
|
|
98
|
-
video.
|
|
130
|
+
video.video_hash,
|
|
99
131
|
created_count,
|
|
100
132
|
skipped_count,
|
|
101
133
|
error_count,
|
|
@@ -122,7 +154,9 @@ def _sequences_to_label_video_segments(
|
|
|
122
154
|
)
|
|
123
155
|
|
|
124
156
|
|
|
125
|
-
def _get_outside_segments(
|
|
157
|
+
def _get_outside_segments(
|
|
158
|
+
video: "VideoFile", outside_label_name: str = "outside"
|
|
159
|
+
) -> "QuerySet[LabelVideoSegment]":
|
|
126
160
|
"""Gets LabelVideoSegments marked with the 'outside' label."""
|
|
127
161
|
from ...label import Label, LabelVideoSegment # Local import for models
|
|
128
162
|
|
|
@@ -133,29 +167,52 @@ def _get_outside_segments(video: "VideoFile", outside_label_name: str = "outside
|
|
|
133
167
|
logger.warning("Label '%s' not found in the database.", outside_label_name)
|
|
134
168
|
return LabelVideoSegment.objects.none()
|
|
135
169
|
except AttributeError:
|
|
136
|
-
logger.error(
|
|
170
|
+
logger.error(
|
|
171
|
+
"VideoFile instance does not have 'label_video_segments' related manager."
|
|
172
|
+
)
|
|
137
173
|
return LabelVideoSegment.objects.none()
|
|
138
174
|
except Exception as e:
|
|
139
|
-
logger.error(
|
|
175
|
+
logger.error(
|
|
176
|
+
"Error getting '%s' segments for video %s: %s",
|
|
177
|
+
outside_label_name,
|
|
178
|
+
video.video_hash,
|
|
179
|
+
e,
|
|
180
|
+
exc_info=True,
|
|
181
|
+
)
|
|
140
182
|
return LabelVideoSegment.objects.none()
|
|
141
183
|
|
|
142
184
|
|
|
143
|
-
def _get_outside_frame_numbers(
|
|
185
|
+
def _get_outside_frame_numbers(
|
|
186
|
+
video: "VideoFile", outside_label_name: str = "outside"
|
|
187
|
+
) -> Set[int]:
|
|
144
188
|
"""
|
|
145
189
|
Gets a set of frame numbers corresponding to segments labeled as 'outside'.
|
|
146
190
|
"""
|
|
147
191
|
outside_segments = _get_outside_segments(video, outside_label_name)
|
|
148
192
|
frame_numbers = set()
|
|
149
193
|
for segment in outside_segments:
|
|
150
|
-
frame_numbers.update(
|
|
194
|
+
frame_numbers.update(
|
|
195
|
+
range(segment.start_frame_number, segment.end_frame_number + 1)
|
|
196
|
+
)
|
|
151
197
|
if frame_numbers:
|
|
152
|
-
logger.info(
|
|
198
|
+
logger.info(
|
|
199
|
+
"Found %d frame numbers marked as '%s' for video %s.",
|
|
200
|
+
len(frame_numbers),
|
|
201
|
+
outside_label_name,
|
|
202
|
+
video.video_hash,
|
|
203
|
+
)
|
|
153
204
|
else:
|
|
154
|
-
logger.info(
|
|
205
|
+
logger.info(
|
|
206
|
+
"No frame numbers marked as '%s' found for video %s.",
|
|
207
|
+
outside_label_name,
|
|
208
|
+
video.video_hash,
|
|
209
|
+
)
|
|
155
210
|
return frame_numbers
|
|
156
211
|
|
|
157
212
|
|
|
158
|
-
def _get_outside_frames(
|
|
213
|
+
def _get_outside_frames(
|
|
214
|
+
video: "VideoFile", outside_label_name: str = "outside"
|
|
215
|
+
) -> "QuerySet[Frame]":
|
|
159
216
|
"""
|
|
160
217
|
Gets a QuerySet of all unique Frame objects that fall within any segment
|
|
161
218
|
labeled with the specified 'outside_label_name'.
|
|
@@ -168,7 +225,10 @@ def _get_outside_frames(video: "VideoFile", outside_label_name: str = "outside")
|
|
|
168
225
|
|
|
169
226
|
q_objects: Q | None = None
|
|
170
227
|
for segment in outside_segments:
|
|
171
|
-
clause = Q(
|
|
228
|
+
clause = Q(
|
|
229
|
+
frame_number__gte=segment.start_frame_number,
|
|
230
|
+
frame_number__lt=segment.end_frame_number,
|
|
231
|
+
)
|
|
172
232
|
q_objects = clause if q_objects is None else q_objects | clause
|
|
173
233
|
|
|
174
234
|
if q_objects is None:
|
|
@@ -177,11 +237,18 @@ def _get_outside_frames(video: "VideoFile", outside_label_name: str = "outside")
|
|
|
177
237
|
try:
|
|
178
238
|
return video.frames.filter(q_objects).distinct().order_by("frame_number")
|
|
179
239
|
except Exception as e:
|
|
180
|
-
logger.error(
|
|
240
|
+
logger.error(
|
|
241
|
+
"Error filtering outside frames for video %s: %s",
|
|
242
|
+
video.video_hash,
|
|
243
|
+
e,
|
|
244
|
+
exc_info=True,
|
|
245
|
+
)
|
|
181
246
|
return Frame.objects.none()
|
|
182
247
|
|
|
183
248
|
|
|
184
|
-
def _get_outside_frame_paths(
|
|
249
|
+
def _get_outside_frame_paths(
|
|
250
|
+
video: "VideoFile", outside_label_name: str = "outside"
|
|
251
|
+
) -> List["Path"]:
|
|
185
252
|
"""Gets the file paths of frames that fall within 'outside' segments."""
|
|
186
253
|
from pathlib import Path # Local import
|
|
187
254
|
|
|
@@ -191,16 +258,28 @@ def _get_outside_frame_paths(video: "VideoFile", outside_label_name: str = "outs
|
|
|
191
258
|
try:
|
|
192
259
|
frame_paths.append(Path(frame.relative_path))
|
|
193
260
|
except Exception as e:
|
|
194
|
-
logger.warning(
|
|
261
|
+
logger.warning(
|
|
262
|
+
"Could not get path for frame %s (Number: %d): %s",
|
|
263
|
+
frame.pk,
|
|
264
|
+
frame.frame_number,
|
|
265
|
+
e,
|
|
266
|
+
)
|
|
195
267
|
ic(f"Could not get path for frame {frame.pk}: {e}")
|
|
196
268
|
|
|
197
|
-
logger.info(
|
|
269
|
+
logger.info(
|
|
270
|
+
"Found %d frame paths within '%s' segments for video %s",
|
|
271
|
+
len(frame_paths),
|
|
272
|
+
outside_label_name,
|
|
273
|
+
video.video_hash,
|
|
274
|
+
)
|
|
198
275
|
return frame_paths
|
|
199
276
|
|
|
200
277
|
|
|
201
278
|
def _label_segments_to_frame_annotations(video: "VideoFile"):
|
|
202
279
|
"""Generates frame annotations based on existing LabelVideoSegments."""
|
|
203
|
-
logger.info(
|
|
280
|
+
logger.info(
|
|
281
|
+
"Generating frame annotations from segments for video %s", video.video_hash
|
|
282
|
+
)
|
|
204
283
|
processed_count = 0
|
|
205
284
|
try:
|
|
206
285
|
for lvs in video.label_video_segments.all():
|
|
@@ -210,7 +289,19 @@ def _label_segments_to_frame_annotations(video: "VideoFile"):
|
|
|
210
289
|
lvs.generate_annotations()
|
|
211
290
|
processed_count += 1
|
|
212
291
|
except Exception as e:
|
|
213
|
-
logger.error(
|
|
214
|
-
|
|
292
|
+
logger.error(
|
|
293
|
+
"Error generating annotations for segment %s (Video %s): %s",
|
|
294
|
+
lvs.pk,
|
|
295
|
+
video.video_hash,
|
|
296
|
+
e,
|
|
297
|
+
)
|
|
298
|
+
logger.info(
|
|
299
|
+
"Processed %d segments for frame annotations for video %s",
|
|
300
|
+
processed_count,
|
|
301
|
+
video.video_hash,
|
|
302
|
+
)
|
|
215
303
|
except AttributeError:
|
|
216
|
-
logger.error(
|
|
304
|
+
logger.error(
|
|
305
|
+
"Could not generate frame annotations for video %s. 'label_video_segments' related manager not found.",
|
|
306
|
+
video.video_hash,
|
|
307
|
+
)
|
|
@@ -18,15 +18,34 @@ class VideoMetadata(models.Model):
|
|
|
18
18
|
and provides metrics for the correction UI.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
video = models.OneToOneField(
|
|
21
|
+
video = models.OneToOneField(
|
|
22
|
+
VideoFile,
|
|
23
|
+
on_delete=models.CASCADE,
|
|
24
|
+
related_name="metadata",
|
|
25
|
+
help_text="Video file this metadata belongs to",
|
|
26
|
+
)
|
|
22
27
|
|
|
23
28
|
# Analysis Results
|
|
24
|
-
sensitive_frame_count = models.IntegerField(
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
sensitive_frame_count = models.IntegerField(
|
|
30
|
+
null=True,
|
|
31
|
+
blank=True,
|
|
32
|
+
help_text="Number of frames detected as containing sensitive information",
|
|
33
|
+
)
|
|
34
|
+
sensitive_ratio = models.FloatField(
|
|
35
|
+
null=True,
|
|
36
|
+
blank=True,
|
|
37
|
+
help_text="Ratio of sensitive frames to total frames (0.0-1.0)",
|
|
38
|
+
)
|
|
39
|
+
sensitive_frame_ids = models.TextField(
|
|
40
|
+
null=True,
|
|
41
|
+
blank=True,
|
|
42
|
+
help_text="JSON array of sensitive frame indices (0-based)",
|
|
43
|
+
)
|
|
27
44
|
|
|
28
45
|
# Metadata
|
|
29
|
-
analyzed_at = models.DateTimeField(
|
|
46
|
+
analyzed_at = models.DateTimeField(
|
|
47
|
+
auto_now=True, help_text="Timestamp of last analysis"
|
|
48
|
+
)
|
|
30
49
|
|
|
31
50
|
class Meta:
|
|
32
51
|
db_table = "video_metadata"
|
|
@@ -34,7 +53,7 @@ class VideoMetadata(models.Model):
|
|
|
34
53
|
verbose_name_plural = "Video Metadata"
|
|
35
54
|
|
|
36
55
|
def __str__(self):
|
|
37
|
-
return f"Metadata for {self.video.
|
|
56
|
+
return f"Metadata for {self.video.video_hash} ({self.sensitive_frame_count or 0} sensitive frames)"
|
|
38
57
|
|
|
39
58
|
@property
|
|
40
59
|
def has_analysis(self) -> bool:
|
|
@@ -53,26 +53,57 @@ class VideoProcessingHistory(models.Model):
|
|
|
53
53
|
(STATUS_CANCELLED, "Cancelled"),
|
|
54
54
|
]
|
|
55
55
|
|
|
56
|
-
video = models.ForeignKey(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
video = models.ForeignKey(
|
|
57
|
+
VideoFile,
|
|
58
|
+
on_delete=models.CASCADE,
|
|
59
|
+
related_name="processing_history",
|
|
60
|
+
help_text="Video file this operation was performed on",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
operation = models.CharField(
|
|
64
|
+
max_length=50,
|
|
65
|
+
choices=OPERATION_CHOICES,
|
|
66
|
+
help_text="Type of processing operation",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
status = models.CharField(
|
|
70
|
+
max_length=20,
|
|
71
|
+
choices=STATUS_CHOICES,
|
|
72
|
+
default=STATUS_PENDING,
|
|
73
|
+
help_text="Current status of the operation",
|
|
74
|
+
)
|
|
61
75
|
|
|
62
76
|
# Configuration & Results
|
|
63
|
-
config = models.JSONField(
|
|
77
|
+
config = models.JSONField(
|
|
78
|
+
default=dict,
|
|
79
|
+
help_text="Operation configuration (mask settings, frame list, etc.)",
|
|
80
|
+
)
|
|
64
81
|
|
|
65
|
-
output_file = models.CharField(
|
|
82
|
+
output_file = models.CharField(
|
|
83
|
+
max_length=500,
|
|
84
|
+
blank=True,
|
|
85
|
+
help_text="Path to output file (relative to MEDIA_ROOT)",
|
|
86
|
+
)
|
|
66
87
|
|
|
67
|
-
details = models.TextField(
|
|
88
|
+
details = models.TextField(
|
|
89
|
+
blank=True, help_text="Additional details or error messages"
|
|
90
|
+
)
|
|
68
91
|
|
|
69
92
|
# Celery Integration
|
|
70
|
-
task_id = models.CharField(
|
|
93
|
+
task_id = models.CharField(
|
|
94
|
+
max_length=100, blank=True, help_text="Celery task ID for progress tracking"
|
|
95
|
+
)
|
|
71
96
|
|
|
72
97
|
# Timestamps
|
|
73
|
-
created_at = models.DateTimeField(
|
|
98
|
+
created_at = models.DateTimeField(
|
|
99
|
+
auto_now_add=True, help_text="When the operation was started"
|
|
100
|
+
)
|
|
74
101
|
|
|
75
|
-
completed_at = models.DateTimeField(
|
|
102
|
+
completed_at = models.DateTimeField(
|
|
103
|
+
null=True,
|
|
104
|
+
blank=True,
|
|
105
|
+
help_text="When the operation completed (success or failure)",
|
|
106
|
+
)
|
|
76
107
|
|
|
77
108
|
class Meta:
|
|
78
109
|
db_table = "video_processing_history"
|
|
@@ -89,9 +120,11 @@ class VideoProcessingHistory(models.Model):
|
|
|
89
120
|
operation_display = getattr(self, "get_operation_display", None)
|
|
90
121
|
status_display = getattr(self, "get_status_display", None)
|
|
91
122
|
|
|
92
|
-
operation =
|
|
123
|
+
operation = (
|
|
124
|
+
operation_display() if callable(operation_display) else self.operation
|
|
125
|
+
)
|
|
93
126
|
status = status_display() if callable(status_display) else self.status
|
|
94
|
-
return f"{operation} on {self.video.
|
|
127
|
+
return f"{operation} on {self.video.video_hash} - {status}"
|
|
95
128
|
|
|
96
129
|
def mark_running(self, save=True):
|
|
97
130
|
"""Mark operation as running."""
|
|
@@ -130,7 +163,9 @@ class VideoProcessingHistory(models.Model):
|
|
|
130
163
|
if details:
|
|
131
164
|
self.details = details
|
|
132
165
|
if save:
|
|
133
|
-
self.save(
|
|
166
|
+
self.save(
|
|
167
|
+
update_fields=["status", "completed_at", "output_file", "details"]
|
|
168
|
+
)
|
|
134
169
|
|
|
135
170
|
def mark_failure(self, error_message, save=True):
|
|
136
171
|
"""Mark operation as failed."""
|
|
@@ -150,4 +185,8 @@ class VideoProcessingHistory(models.Model):
|
|
|
150
185
|
@property
|
|
151
186
|
def is_complete(self) -> bool:
|
|
152
187
|
"""Check if operation is in a terminal state."""
|
|
153
|
-
return self.status in [
|
|
188
|
+
return self.status in [
|
|
189
|
+
self.STATUS_SUCCESS,
|
|
190
|
+
self.STATUS_FAILURE,
|
|
191
|
+
self.STATUS_CANCELLED,
|
|
192
|
+
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from .disease import
|
|
2
|
-
from .event import
|
|
1
|
+
from .disease import Disease, DiseaseClassification, DiseaseClassificationChoice
|
|
2
|
+
from .event import Event, EventClassification, EventClassificationChoice
|
|
3
3
|
|
|
4
4
|
from .contraindication import Contraindication
|
|
5
5
|
from .examination import (
|
|
@@ -72,15 +72,12 @@ __all__ = [
|
|
|
72
72
|
"Disease",
|
|
73
73
|
"DiseaseClassification",
|
|
74
74
|
"DiseaseClassificationChoice",
|
|
75
|
-
|
|
76
75
|
# Event
|
|
77
76
|
"Event",
|
|
78
77
|
"EventClassification",
|
|
79
78
|
"EventClassificationChoice",
|
|
80
|
-
|
|
81
79
|
# Contraindication
|
|
82
80
|
"Contraindication",
|
|
83
|
-
|
|
84
81
|
# Examination
|
|
85
82
|
"Examination",
|
|
86
83
|
"ExaminationRequirementSet",
|
|
@@ -90,7 +87,6 @@ __all__ = [
|
|
|
90
87
|
"ExaminationIndicationClassification",
|
|
91
88
|
"ExaminationTime",
|
|
92
89
|
"ExaminationTimeType",
|
|
93
|
-
|
|
94
90
|
# Finding
|
|
95
91
|
"Finding",
|
|
96
92
|
"FindingClassificationType",
|
|
@@ -100,7 +96,6 @@ __all__ = [
|
|
|
100
96
|
"FindingMorphologyClassification",
|
|
101
97
|
"FindingIntervention",
|
|
102
98
|
"FindingInterventionType",
|
|
103
|
-
|
|
104
99
|
# Patient
|
|
105
100
|
## Disease
|
|
106
101
|
"PatientDisease",
|
|
@@ -120,14 +115,11 @@ __all__ = [
|
|
|
120
115
|
## Medication
|
|
121
116
|
"PatientMedication",
|
|
122
117
|
"PatientMedicationSchedule",
|
|
123
|
-
|
|
124
118
|
# Organ
|
|
125
119
|
"Organ",
|
|
126
|
-
|
|
127
120
|
# Risk
|
|
128
121
|
"Risk",
|
|
129
122
|
"RiskType",
|
|
130
|
-
|
|
131
123
|
# Medication
|
|
132
124
|
"Medication",
|
|
133
125
|
"MedicationManager",
|
|
@@ -135,12 +127,10 @@ __all__ = [
|
|
|
135
127
|
"MedicationIntakeTime",
|
|
136
128
|
"MedicationIndicationType",
|
|
137
129
|
"MedicationIndication",
|
|
138
|
-
|
|
139
130
|
# Hardware
|
|
140
131
|
"Endoscope",
|
|
141
132
|
"EndoscopeType",
|
|
142
133
|
"EndoscopyProcessor",
|
|
143
|
-
|
|
144
134
|
# Laboratory
|
|
145
135
|
"LabValue",
|
|
146
|
-
]
|
|
136
|
+
]
|
|
@@ -18,7 +18,9 @@ class Contraindication(models.Model):
|
|
|
18
18
|
from endoreg_db.models import FindingIntervention
|
|
19
19
|
|
|
20
20
|
@property
|
|
21
|
-
def contraindicating_finding_interventions(
|
|
21
|
+
def contraindicating_finding_interventions(
|
|
22
|
+
self,
|
|
23
|
+
) -> "models.manager.RelatedManager[FindingIntervention]": ...
|
|
22
24
|
|
|
23
25
|
def natural_key(self):
|
|
24
26
|
return (self.name,)
|
|
@@ -38,7 +38,9 @@ class Disease(models.Model):
|
|
|
38
38
|
if TYPE_CHECKING:
|
|
39
39
|
|
|
40
40
|
@property
|
|
41
|
-
def disease_classifications(
|
|
41
|
+
def disease_classifications(
|
|
42
|
+
self,
|
|
43
|
+
) -> models.QuerySet["DiseaseClassification"]: ...
|
|
42
44
|
|
|
43
45
|
@property
|
|
44
46
|
def patient_diseases(self) -> models.QuerySet["PatientDisease"]: ...
|
|
@@ -58,7 +60,9 @@ class Disease(models.Model):
|
|
|
58
60
|
Returns:
|
|
59
61
|
List[DiseaseClassification]: A list of related disease classification objects.
|
|
60
62
|
"""
|
|
61
|
-
classifications: List[DiseaseClassification] = [
|
|
63
|
+
classifications: List[DiseaseClassification] = [
|
|
64
|
+
_ for _ in self.disease_classifications.all()
|
|
65
|
+
]
|
|
62
66
|
return classifications
|
|
63
67
|
|
|
64
68
|
|
|
@@ -85,7 +89,9 @@ class DiseaseClassification(models.Model):
|
|
|
85
89
|
|
|
86
90
|
name = models.CharField(max_length=255, unique=True)
|
|
87
91
|
|
|
88
|
-
disease = models.ForeignKey(
|
|
92
|
+
disease = models.ForeignKey(
|
|
93
|
+
Disease, on_delete=models.CASCADE, related_name="disease_classifications"
|
|
94
|
+
)
|
|
89
95
|
|
|
90
96
|
objects = DiseaseClassificationManager()
|
|
91
97
|
|
|
@@ -93,7 +99,9 @@ class DiseaseClassification(models.Model):
|
|
|
93
99
|
disease: models.ForeignKey["Disease"]
|
|
94
100
|
|
|
95
101
|
@property
|
|
96
|
-
def disease_classification_choices(
|
|
102
|
+
def disease_classification_choices(
|
|
103
|
+
self,
|
|
104
|
+
) -> models.manager.RelatedManager["DiseaseClassificationChoice"]: ...
|
|
97
105
|
|
|
98
106
|
def natural_key(self):
|
|
99
107
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -110,7 +118,9 @@ class DiseaseClassification(models.Model):
|
|
|
110
118
|
Returns:
|
|
111
119
|
List[DiseaseClassificationChoice]: A list of related disease classification choices.
|
|
112
120
|
"""
|
|
113
|
-
choices: List[DiseaseClassificationChoice] = [
|
|
121
|
+
choices: List[DiseaseClassificationChoice] = [
|
|
122
|
+
_ for _ in self.disease_classification_choices.all()
|
|
123
|
+
]
|
|
114
124
|
return choices
|
|
115
125
|
|
|
116
126
|
|
|
@@ -151,7 +161,9 @@ class DiseaseClassificationChoice(models.Model):
|
|
|
151
161
|
disease_classification: models.ForeignKey["DiseaseClassification"]
|
|
152
162
|
|
|
153
163
|
@property
|
|
154
|
-
def patient_diseases(
|
|
164
|
+
def patient_diseases(
|
|
165
|
+
self,
|
|
166
|
+
) -> models.manager.RelatedManager["PatientDisease"]: ...
|
|
155
167
|
|
|
156
168
|
def natural_key(self):
|
|
157
169
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -93,7 +93,9 @@ class EventClassification(models.Model):
|
|
|
93
93
|
event: models.ForeignKey["Event"]
|
|
94
94
|
|
|
95
95
|
@property
|
|
96
|
-
def event_classification_choices(
|
|
96
|
+
def event_classification_choices(
|
|
97
|
+
self,
|
|
98
|
+
) -> models.QuerySet["EventClassificationChoice"]: ...
|
|
97
99
|
|
|
98
100
|
def natural_key(self):
|
|
99
101
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -105,7 +107,9 @@ class EventClassification(models.Model):
|
|
|
105
107
|
|
|
106
108
|
def get_choices(self) -> List["EventClassificationChoice"]:
|
|
107
109
|
"""Retrieves all choices associated with this classification."""
|
|
108
|
-
choices: List[EventClassificationChoice] = [
|
|
110
|
+
choices: List[EventClassificationChoice] = [
|
|
111
|
+
_ for _ in self.event_classification_choices.all()
|
|
112
|
+
]
|
|
109
113
|
return choices
|
|
110
114
|
|
|
111
115
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
from .examination import Examination, ExaminationRequirementSet
|
|
2
|
-
from .examination_indication import
|
|
2
|
+
from .examination_indication import (
|
|
3
|
+
ExaminationIndication,
|
|
4
|
+
ExaminationIndicationClassification,
|
|
5
|
+
ExaminationIndicationClassificationChoice,
|
|
6
|
+
)
|
|
3
7
|
from .examination_time import ExaminationTime
|
|
4
8
|
from .examination_time_type import ExaminationTimeType
|
|
5
9
|
from .examination_type import ExaminationType
|
|
@@ -53,18 +53,34 @@ class Examination(models.Model):
|
|
|
53
53
|
objects = ExaminationManager()
|
|
54
54
|
|
|
55
55
|
if TYPE_CHECKING:
|
|
56
|
-
from endoreg_db.models import
|
|
56
|
+
from endoreg_db.models import (
|
|
57
|
+
ExaminationIndication,
|
|
58
|
+
ExaminationTime,
|
|
59
|
+
Finding,
|
|
60
|
+
FindingClassification,
|
|
61
|
+
InformationSource,
|
|
62
|
+
)
|
|
57
63
|
|
|
58
|
-
indications = cast(
|
|
59
|
-
|
|
64
|
+
indications = cast(
|
|
65
|
+
"models.manager.RelatedManager[ExaminationIndication]", indications
|
|
66
|
+
)
|
|
67
|
+
examination_times = cast(
|
|
68
|
+
"models.manager.RelatedManager[ExaminationTime]", examination_times
|
|
69
|
+
)
|
|
60
70
|
findings = cast("models.manager.RelatedManager[Finding]", findings)
|
|
61
|
-
information_sources = cast(
|
|
71
|
+
information_sources = cast(
|
|
72
|
+
"models.manager.RelatedManager[InformationSource]", information_sources
|
|
73
|
+
)
|
|
62
74
|
|
|
63
75
|
@property
|
|
64
|
-
def finding_classifications(
|
|
76
|
+
def finding_classifications(
|
|
77
|
+
self,
|
|
78
|
+
) -> "models.manager.RelatedManager[FindingClassification]": ...
|
|
65
79
|
|
|
66
80
|
@property
|
|
67
|
-
def exam_reqset_links(
|
|
81
|
+
def exam_reqset_links(
|
|
82
|
+
self,
|
|
83
|
+
) -> "models.manager.RelatedManager[ExaminationRequirementSet]": ...
|
|
68
84
|
|
|
69
85
|
@property
|
|
70
86
|
def links(self) -> "RequirementLinks":
|