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
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
# See Pipe 1 video file function.
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
Management command to import a video file into the database.
|
|
6
|
-
This command is designed to be run from the command line and takes various arguments
|
|
7
|
-
to specify the video file, center name, and other options.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from django.core.management import BaseCommand
|
|
11
|
-
from django.core.files.base import ContentFile
|
|
12
|
-
from django.db import connection
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
from endoreg_db.models import VideoFile
|
|
15
|
-
from endoreg_db.models.administration.center import Center
|
|
16
|
-
from endoreg_db.models.medical.hardware import EndoscopyProcessor
|
|
17
|
-
# #FIXME
|
|
18
|
-
# from endoreg_db.management.commands import validate_video
|
|
19
|
-
|
|
20
|
-
from endoreg_db.utils.video.ffmpeg_wrapper import check_ffmpeg_availability # ADDED
|
|
21
|
-
|
|
22
|
-
import logging
|
|
23
|
-
logger = logging.getLogger(__name__)
|
|
24
|
-
|
|
25
|
-
# Import frame cleaning functionality - simplified approach
|
|
26
|
-
FRAME_CLEANING_AVAILABLE = False
|
|
27
|
-
|
|
28
|
-
# Try to import lx_anonymizer using the existing working import method from create_from_file
|
|
29
|
-
try:
|
|
30
|
-
# Check if we can find the lx-anonymizer directory
|
|
31
|
-
current_file = Path(__file__)
|
|
32
|
-
endoreg_db_root = current_file.parent.parent.parent.parent
|
|
33
|
-
lx_anonymizer_path = endoreg_db_root / "lx-anonymizer"
|
|
34
|
-
|
|
35
|
-
if lx_anonymizer_path.exists():
|
|
36
|
-
# Add to Python path temporarily
|
|
37
|
-
import sys
|
|
38
|
-
if str(lx_anonymizer_path) not in sys.path:
|
|
39
|
-
sys.path.insert(0, str(lx_anonymizer_path))
|
|
40
|
-
|
|
41
|
-
# Try simple import
|
|
42
|
-
from lx_anonymizer import FrameCleaner, ReportReader
|
|
43
|
-
|
|
44
|
-
FRAME_CLEANING_AVAILABLE = True
|
|
45
|
-
logger.debug("Successfully imported lx_anonymizer modules")
|
|
46
|
-
|
|
47
|
-
# Remove from path to avoid conflicts
|
|
48
|
-
if str(lx_anonymizer_path) in sys.path:
|
|
49
|
-
sys.path.remove(str(lx_anonymizer_path))
|
|
50
|
-
|
|
51
|
-
except Exception as e:
|
|
52
|
-
logger.debug(f"Frame cleaning not available: {e}")
|
|
53
|
-
FRAME_CLEANING_AVAILABLE = False
|
|
54
|
-
|
|
55
|
-
IMPORT_MODELS = [
|
|
56
|
-
VideoFile.__name__,
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
IMPORT_METADATA = {
|
|
60
|
-
VideoFile.__name__: {
|
|
61
|
-
"uuid": VideoFile.uuid,
|
|
62
|
-
"raw_file": VideoFile.raw_file,
|
|
63
|
-
"processed_file": VideoFile.processed_file,
|
|
64
|
-
"foreign_keys": [],
|
|
65
|
-
"foreign_key_models": [],
|
|
66
|
-
},
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
class Command(BaseCommand):
|
|
70
|
-
help = """
|
|
71
|
-
Creates a new VideoFile object in the database.
|
|
72
|
-
1. Validates the existence of the specified center and processor
|
|
73
|
-
2. Checks that the video file is saved and anonymized
|
|
74
|
-
3. Creates or updates a ModelMeta entry with the specified parameters
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
def add_arguments(self, parser):
|
|
78
|
-
|
|
79
|
-
"""
|
|
80
|
-
Adds command-line arguments for the video import management command.
|
|
81
|
-
|
|
82
|
-
Defines options for specifying the video file path, associated center and processor names, directory roots for frames and videos, deletion and saving behavior, model path, segmentation usage, and verbosity.
|
|
83
|
-
"""
|
|
84
|
-
parser.add_argument(
|
|
85
|
-
"--verbose",
|
|
86
|
-
action="store_true",
|
|
87
|
-
help="Display verbose output",
|
|
88
|
-
)
|
|
89
|
-
parser.add_argument(
|
|
90
|
-
"--",
|
|
91
|
-
type=str,
|
|
92
|
-
default="university_hospital_wuerzburg",
|
|
93
|
-
help="Name of the center to associate with video",
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
# add the path to the video file
|
|
97
|
-
parser.add_argument(
|
|
98
|
-
"video_file",
|
|
99
|
-
type=Path,
|
|
100
|
-
help="Path to the video file to import",
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
# frame dir parent
|
|
104
|
-
parser.add_argument(
|
|
105
|
-
"--frame_dir_root",
|
|
106
|
-
type=str,
|
|
107
|
-
default="~/test-data/raw_frame_dir",
|
|
108
|
-
help="Path to the frame directory",
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
# video dir
|
|
112
|
-
parser.add_argument(
|
|
113
|
-
"--video_dir_root",
|
|
114
|
-
type=str,
|
|
115
|
-
default="~/test-data/raw_video_dir",
|
|
116
|
-
help="Path to the video directory",
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# delete source
|
|
120
|
-
parser.add_argument(
|
|
121
|
-
"--delete_source",
|
|
122
|
-
action="store_true",
|
|
123
|
-
default=False,
|
|
124
|
-
help="Delete the source video file after importing",
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
# save video file
|
|
128
|
-
parser.add_argument(
|
|
129
|
-
"--save_video_file",
|
|
130
|
-
action="store_true",
|
|
131
|
-
default=True,
|
|
132
|
-
help="Save the video file to the video directory",
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
# model_path
|
|
136
|
-
parser.add_argument(
|
|
137
|
-
"--model_name",
|
|
138
|
-
type=str,
|
|
139
|
-
default="image_multilabel_classification_colonoscopy_default",
|
|
140
|
-
help="AiModel Name",
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
#
|
|
144
|
-
parser.add_argument(
|
|
145
|
-
"--segmentation",
|
|
146
|
-
action="store_true",
|
|
147
|
-
help="Whether to use segmentation",
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
parser.add_argument(
|
|
151
|
-
"--processor_name",
|
|
152
|
-
type=str,
|
|
153
|
-
default="olympus_cv_1500",
|
|
154
|
-
help="Name of the processor to associate with video",
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
def handle(self, *args, **options):
|
|
158
|
-
|
|
159
|
-
"""
|
|
160
|
-
Imports a video file into the database, associating it with a specified medical center and endoscopy processor, and optionally applies AI-based segmentation.
|
|
161
|
-
|
|
162
|
-
Checks for required dependencies, loads reference data, validates the existence of the specified center and processor, and processes the video file. If segmentation is enabled, retrieves the latest segmentation model metadata. Handles interactive processor selection if multiple are available, creates a new `VideoFile` entry, and invokes the processing pipeline. Can optionally delete the source file or save the video to a specified directory. Reports the outcome of the import and processing steps.
|
|
163
|
-
"""
|
|
164
|
-
try: # ADDED
|
|
165
|
-
check_ffmpeg_availability() # ADDED
|
|
166
|
-
self.stdout.write(self.style.SUCCESS("FFMPEG is available")) # ADDED
|
|
167
|
-
except FileNotFoundError as e: # ADDED
|
|
168
|
-
self.stderr.write(self.style.ERROR(str(e))) # ADDED
|
|
169
|
-
# Decide if the command should exit or if FFMPEG is optional for some operations
|
|
170
|
-
# For this command, it seems FFMPEG is critical for VideoFile.pipe_1 and VideoFile.create_from_file
|
|
171
|
-
return # ADDED
|
|
172
|
-
|
|
173
|
-
self.stdout.write(f"Current database: {connection.alias}")
|
|
174
|
-
self.stdout.write(self.style.SUCCESS("Starting video import..."))
|
|
175
|
-
|
|
176
|
-
# Should not be invoked here but in a previous db setup step
|
|
177
|
-
# load_gender_data()
|
|
178
|
-
# load_disease_data()
|
|
179
|
-
# load_event_data()
|
|
180
|
-
# load_information_source()
|
|
181
|
-
# load_examination_data()
|
|
182
|
-
# load_center_data()
|
|
183
|
-
# load_endoscope_data()
|
|
184
|
-
|
|
185
|
-
segmentation = options["segmentation"]
|
|
186
|
-
|
|
187
|
-
verbose = options["verbose"]
|
|
188
|
-
center_name = options["center_name"]
|
|
189
|
-
video_file = options["video_file"]
|
|
190
|
-
frame_dir_root = options["frame_dir_root"]
|
|
191
|
-
delete_source = options["delete_source"]
|
|
192
|
-
save_video_file = options["save_video_file"]
|
|
193
|
-
model_name = options["model_name"]
|
|
194
|
-
processor_name = options["processor_name"]
|
|
195
|
-
video_file = Path(video_file).expanduser()
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
assert isinstance(delete_source, bool), "delete_source must be a boolean"
|
|
199
|
-
assert isinstance(save_video_file, bool), "save_video_file must be a boolean"
|
|
200
|
-
assert isinstance(verbose, bool), "verbose must be a boolean"
|
|
201
|
-
assert isinstance(center_name, str), "center_name must be a string"
|
|
202
|
-
assert isinstance(video_file, Path), "video_file must be a Path"
|
|
203
|
-
assert isinstance(frame_dir_root, str), "frame_dir_root must be a string"
|
|
204
|
-
# Assert Center exists -> Does not exist methods are deprecated
|
|
205
|
-
try:
|
|
206
|
-
center = Center.objects.get(name=center_name)
|
|
207
|
-
self.stdout.write(self.style.SUCCESS(f"Using center: {center.name}"))
|
|
208
|
-
except Center.DoesNotExist:
|
|
209
|
-
self.stdout.write(self.style.ERROR(f"Center not found: {center_name}"))
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
# Assert Processor Exists
|
|
213
|
-
if processor_name is None:
|
|
214
|
-
processors_qs = center.endoscopy_processors.all()
|
|
215
|
-
proc_count = processors_qs.count()
|
|
216
|
-
if proc_count == 0:
|
|
217
|
-
raise AssertionError(
|
|
218
|
-
f"No processors linked to '{center.name}' and no processor called '{processor_name}' exists. "
|
|
219
|
-
"Fallback from default Processor applied."
|
|
220
|
-
)
|
|
221
|
-
elif proc_count == 1:
|
|
222
|
-
processor = processors_qs.first()
|
|
223
|
-
else:
|
|
224
|
-
|
|
225
|
-
processor = self._choose_processor_interactively(processors_qs)
|
|
226
|
-
self.stdout.write(self.style.SUCCESS(f"Using processor: {processor.name}"))
|
|
227
|
-
|
|
228
|
-
else:
|
|
229
|
-
processor = EndoscopyProcessor.objects.get(name=processor_name)
|
|
230
|
-
|
|
231
|
-
cns = processor.centers.values_list("name", flat=True)
|
|
232
|
-
if center_name not in cns:
|
|
233
|
-
self.stdout.write(
|
|
234
|
-
self.style.ERROR(
|
|
235
|
-
f"Processor '{processor_name}' is not linked to center '{center_name}'."
|
|
236
|
-
)
|
|
237
|
-
)
|
|
238
|
-
return
|
|
239
|
-
|
|
240
|
-
if not Path(video_file).exists():
|
|
241
|
-
self.stdout.write(self.style.ERROR(f"Video file not found: {video_file} saving unsuccessful."))
|
|
242
|
-
return AssertionError(f"Video file not found: {video_file}")
|
|
243
|
-
|
|
244
|
-
# Create VideoFile instance first
|
|
245
|
-
video_file_obj = VideoFile.create_from_file_initialized(
|
|
246
|
-
file_path=video_file,
|
|
247
|
-
center_name=center_name,
|
|
248
|
-
processor_name=processor_name,
|
|
249
|
-
delete_source=delete_source,
|
|
250
|
-
save_video_file=save_video_file, # Add this line
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
if not video_file_obj:
|
|
254
|
-
self.stdout.write(self.style.ERROR("Failed to create VideoFile instance"))
|
|
255
|
-
return
|
|
256
|
-
|
|
257
|
-
self.stdout.write(self.style.SUCCESS(f"Created VideoFile with UUID: {video_file_obj.uuid}"))
|
|
258
|
-
|
|
259
|
-
# Initialize video specs and frames
|
|
260
|
-
video_file_obj.initialize_video_specs()
|
|
261
|
-
video_file_obj.initialize_frames()
|
|
262
|
-
|
|
263
|
-
# Run Pipe 1 for OCR and AI processing
|
|
264
|
-
self.stdout.write(self.style.SUCCESS("Starting Pipe 1 processing (OCR + AI)..."))
|
|
265
|
-
success = video_file_obj.pipe_1(
|
|
266
|
-
model_name=model_name,
|
|
267
|
-
delete_frames_after=True,
|
|
268
|
-
ocr_frame_fraction=0.01,
|
|
269
|
-
ocr_cap=5
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
if not success:
|
|
273
|
-
self.stdout.write(self.style.ERROR("Pipe 1 processing failed"))
|
|
274
|
-
return
|
|
275
|
-
|
|
276
|
-
self.stdout.write(self.style.SUCCESS("Pipe 1 processing completed"))
|
|
277
|
-
|
|
278
|
-
# Ensure minimum patient data is available
|
|
279
|
-
self.stdout.write(self.style.SUCCESS("Ensuring minimum patient data..."))
|
|
280
|
-
self._ensure_default_patient_data(video_file_obj)
|
|
281
|
-
|
|
282
|
-
# Frame-level anonymization integration
|
|
283
|
-
if FRAME_CLEANING_AVAILABLE and video_file_obj.raw_file:
|
|
284
|
-
try:
|
|
285
|
-
self.stdout.write(self.style.SUCCESS("Starting frame-level anonymization..."))
|
|
286
|
-
# Properly instantiate FrameCleaner and ReportReader with correct arguments
|
|
287
|
-
frame_cleaner = FrameCleaner()
|
|
288
|
-
report_reader = ReportReader(
|
|
289
|
-
report_root_path=str(video_file_obj.raw_file.path),
|
|
290
|
-
locale="de_DE", # Default German locale for medical data
|
|
291
|
-
text_date_format="%d.%m.%Y" # Common German date format
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
# Updated to handle new return signature (path, metadata)
|
|
295
|
-
cleaned_video_path, extracted_metadata = frame_cleaner.clean_video(
|
|
296
|
-
video_path=Path(video_file_obj.raw_file.path),
|
|
297
|
-
endoscope_image_roi=video_file_obj.processor.get_roi_endoscope_image() if video_file_obj.processor else None,
|
|
298
|
-
endoscope_data_roi_nested=video_file_obj.processor.get_rois() if video_file_obj.processor else None,
|
|
299
|
-
output_path=video_file_obj.get_processed_file_path(),
|
|
300
|
-
technique="mask_overlay" # Use mask overlay technique as default, if not set this will be inferred.
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
# Save the cleaned video using Django's FileField
|
|
304
|
-
with open(cleaned_video_path, 'rb') as f:
|
|
305
|
-
video_file_obj.raw_file.save(cleaned_video_path.name, ContentFile(f.read()))
|
|
306
|
-
video_file_obj.save()
|
|
307
|
-
|
|
308
|
-
self.stdout.write(self.style.SUCCESS(f"Frame cleaning completed: {cleaned_video_path.name}"))
|
|
309
|
-
self.stdout.write(self.style.SUCCESS(f"Extracted metadata: {extracted_metadata}"))
|
|
310
|
-
|
|
311
|
-
except Exception as e:
|
|
312
|
-
self.stdout.write(self.style.WARNING(f"Frame cleaning failed, continuing with original video: {e}"))
|
|
313
|
-
elif not FRAME_CLEANING_AVAILABLE:
|
|
314
|
-
self.stdout.write(self.style.WARNING("Frame cleaning not available (lx_anonymizer not found)"))
|
|
315
|
-
|
|
316
|
-
# Now call pipe_1 on the VideoFile instance
|
|
317
|
-
if segmentation:
|
|
318
|
-
success = video_file_obj.pipe_1(model_name=model_name, model_meta_version = None)
|
|
319
|
-
|
|
320
|
-
if success:
|
|
321
|
-
self.stdout.write(self.style.SUCCESS("Pipeline 1 completed successfully"))
|
|
322
|
-
else:
|
|
323
|
-
self.stdout.write(self.style.ERROR("Pipeline 1 failed"))
|
|
324
|
-
|
|
325
|
-
def _ensure_default_patient_data(self, video_file):
|
|
326
|
-
"""
|
|
327
|
-
Ensure video has minimum required patient data in SensitiveMeta.
|
|
328
|
-
Creates default values if data is missing after OCR processing.
|
|
329
|
-
"""
|
|
330
|
-
from endoreg_db.models import SensitiveMeta
|
|
331
|
-
from datetime import date
|
|
332
|
-
|
|
333
|
-
if not video_file.sensitive_meta:
|
|
334
|
-
self.stdout.write(self.style.WARNING(f"No SensitiveMeta found for video {video_file.uuid}, creating default"))
|
|
335
|
-
|
|
336
|
-
# Create default SensitiveMeta with placeholder data
|
|
337
|
-
default_data = {
|
|
338
|
-
"patient_first_name": None,
|
|
339
|
-
"patient_last_name": None,
|
|
340
|
-
"patient_dob": None,
|
|
341
|
-
"examination_date": None,
|
|
342
|
-
"center_name": video_file.center.name if video_file.center else "unknown",
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
try:
|
|
346
|
-
sensitive_meta = SensitiveMeta.create_from_dict(default_data)
|
|
347
|
-
video_file.sensitive_meta = sensitive_meta
|
|
348
|
-
video_file.save(update_fields=['sensitive_meta'])
|
|
349
|
-
self.stdout.write(self.style.SUCCESS(f"Created default SensitiveMeta for video {video_file.uuid}"))
|
|
350
|
-
except Exception as e:
|
|
351
|
-
self.stdout.write(self.style.ERROR(f"Failed to create default SensitiveMeta for video {video_file.uuid}: {e}"))
|
|
352
|
-
|
|
353
|
-
else:
|
|
354
|
-
# Update existing SensitiveMeta with missing fields
|
|
355
|
-
update_needed = False
|
|
356
|
-
update_data = {}
|
|
357
|
-
|
|
358
|
-
if not video_file.sensitive_meta.patient_first_name:
|
|
359
|
-
update_data["patient_first_name"] = "Patient"
|
|
360
|
-
update_needed = True
|
|
361
|
-
|
|
362
|
-
if not video_file.sensitive_meta.patient_last_name:
|
|
363
|
-
update_data["patient_last_name"] = "Unknown"
|
|
364
|
-
update_needed = True
|
|
365
|
-
|
|
366
|
-
if not video_file.sensitive_meta.patient_dob:
|
|
367
|
-
update_data["patient_dob"] = date(1990, 1, 1)
|
|
368
|
-
update_needed = True
|
|
369
|
-
|
|
370
|
-
if not video_file.sensitive_meta.examination_date:
|
|
371
|
-
update_data["examination_date"] = date.today()
|
|
372
|
-
update_needed = True
|
|
373
|
-
|
|
374
|
-
if update_needed:
|
|
375
|
-
try:
|
|
376
|
-
video_file.sensitive_meta.update_from_dict(update_data)
|
|
377
|
-
self.stdout.write(self.style.SUCCESS(f"Updated missing SensitiveMeta fields for video {video_file.uuid}: {list(update_data.keys())}"))
|
|
378
|
-
except Exception as e:
|
|
379
|
-
self.stdout.write(self.style.ERROR(f"Failed to update SensitiveMeta for video {video_file.uuid}: {e}"))
|
|
380
|
-
else:
|
|
381
|
-
self.stdout.write(self.style.SUCCESS(f"SensitiveMeta for video {video_file.uuid} already has all required fields"))
|
|
382
|
-
|
|
383
|
-
def _choose_processor_interactively(
|
|
384
|
-
self, processors_qs
|
|
385
|
-
) -> EndoscopyProcessor:
|
|
386
|
-
"""
|
|
387
|
-
Interactively prompts the user to select an endoscopy processor from a list.
|
|
388
|
-
|
|
389
|
-
Displays all available processors and requests user input until a valid selection is made. Aborts the process if the user interrupts input.
|
|
390
|
-
|
|
391
|
-
Args:
|
|
392
|
-
processors_qs: Queryset of EndoscopyProcessor objects to present for selection.
|
|
393
|
-
|
|
394
|
-
Returns:
|
|
395
|
-
The EndoscopyProcessor object chosen by the user.
|
|
396
|
-
"""
|
|
397
|
-
# turn the QS into a concrete list so we can index it later
|
|
398
|
-
processors = list(processors_qs) # -> [EndoscopyProcessor, …]
|
|
399
|
-
|
|
400
|
-
self.stdout.write(self.style.ERROR(
|
|
401
|
-
f"\nThe centre has {len(processors)} endoscopy processors.\n"
|
|
402
|
-
"Choose one for this import:\n"
|
|
403
|
-
))
|
|
404
|
-
for idx, proc in enumerate(processors, 1):
|
|
405
|
-
self.stdout.write(f" [{idx}] {proc.name}")
|
|
406
|
-
|
|
407
|
-
while True: # keep prompting until valid
|
|
408
|
-
try:
|
|
409
|
-
choice = input("Processor number › ").strip()
|
|
410
|
-
except (EOFError, KeyboardInterrupt):
|
|
411
|
-
self.stderr.write("\nAborted.")
|
|
412
|
-
raise SystemExit(1)
|
|
413
|
-
|
|
414
|
-
try:
|
|
415
|
-
index = int(choice) - 1
|
|
416
|
-
if not 0 <= index < len(processors):
|
|
417
|
-
raise ValueError
|
|
418
|
-
except ValueError:
|
|
419
|
-
self.stderr.write("❌ Please enter a number in the list above.\n")
|
|
420
|
-
continue
|
|
421
|
-
|
|
422
|
-
return processors[index] # ← the chosen object
|