endoreg-db 0.8.9.2__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 +89 -122
- 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/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 -4
- 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/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.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
- 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.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,31 +1,39 @@
|
|
|
1
|
-
from typing import List, Optional, TYPE_CHECKING
|
|
1
|
+
from typing import List, Optional, TYPE_CHECKING # Modified import
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
|
|
5
5
|
from endoreg_db.models import (
|
|
6
|
-
PatientDisease,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
PatientDisease,
|
|
7
|
+
Disease,
|
|
8
|
+
DiseaseClassificationChoice,
|
|
9
|
+
Event,
|
|
10
|
+
PatientEvent,
|
|
11
|
+
Examination,
|
|
12
|
+
ExaminationIndication,
|
|
13
|
+
ExaminationIndicationClassificationChoice,
|
|
14
|
+
PatientExamination,
|
|
15
|
+
PatientExaminationIndication,
|
|
10
16
|
PatientFinding,
|
|
11
|
-
Finding,
|
|
12
|
-
FindingIntervention,
|
|
17
|
+
Finding,
|
|
18
|
+
FindingIntervention,
|
|
13
19
|
FindingClassification,
|
|
14
|
-
FindingClassificationChoice,
|
|
20
|
+
FindingClassificationChoice,
|
|
15
21
|
LabValue,
|
|
16
22
|
PatientLabValue,
|
|
17
23
|
PatientLabSample,
|
|
18
24
|
PatientLabSampleType,
|
|
19
|
-
PatientMedication,
|
|
20
|
-
PatientMedicationSchedule,
|
|
21
|
-
Medication,
|
|
22
|
-
MedicationIndication,
|
|
23
|
-
MedicationIntakeTime,
|
|
24
|
-
MedicationSchedule,
|
|
25
|
+
PatientMedication, # Added
|
|
26
|
+
PatientMedicationSchedule, # Added
|
|
27
|
+
Medication, # Added
|
|
28
|
+
MedicationIndication, # Added
|
|
29
|
+
MedicationIntakeTime, # Added
|
|
30
|
+
MedicationSchedule, # Added
|
|
25
31
|
)
|
|
26
|
-
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING: # Added for Patient import
|
|
27
34
|
from endoreg_db.models.administration.person.patient import Patient
|
|
28
35
|
|
|
36
|
+
|
|
29
37
|
class RequirementLinks(BaseModel):
|
|
30
38
|
"""
|
|
31
39
|
A class representing a dictionary of models related to a requirement.
|
|
@@ -45,34 +53,49 @@ class RequirementLinks(BaseModel):
|
|
|
45
53
|
finding_location_classification_choices (List[FindingLocationClassificationChoice]): A List of finding location classification choices.
|
|
46
54
|
finding_interventions (List[FindingIntervention]): A List of finding interventions.
|
|
47
55
|
"""
|
|
56
|
+
|
|
48
57
|
model_config = {"arbitrary_types_allowed": True}
|
|
49
|
-
#
|
|
58
|
+
#
|
|
50
59
|
# requirement_types: Optional[List["RequirementType"]] = None
|
|
51
60
|
# operators: Optional[List["RequirementOperator"]] = None
|
|
52
61
|
# The following model import causes circular import
|
|
53
|
-
#requirement_sets: Optional[List["RequirementSet"]] = None
|
|
62
|
+
# requirement_sets: Optional[List["RequirementSet"]] = None
|
|
54
63
|
examinations: List["Examination"] = Field(default_factory=list)
|
|
55
64
|
examination_indications: List["ExaminationIndication"] = Field(default_factory=list)
|
|
56
|
-
examination_indication_classification_choices: List[
|
|
65
|
+
examination_indication_classification_choices: List[
|
|
66
|
+
"ExaminationIndicationClassificationChoice"
|
|
67
|
+
] = Field(default_factory=list)
|
|
57
68
|
patient_examinations: List["PatientExamination"] = Field(default_factory=list)
|
|
58
|
-
|
|
59
|
-
patient_examination_indication: List["PatientExaminationIndication"] = Field(
|
|
69
|
+
|
|
70
|
+
patient_examination_indication: List["PatientExaminationIndication"] = Field(
|
|
71
|
+
default_factory=list
|
|
72
|
+
)
|
|
60
73
|
lab_values: List["LabValue"] = Field(default_factory=list)
|
|
61
74
|
patient_lab_values: List["PatientLabValue"] = Field(default_factory=list)
|
|
62
75
|
patient_lab_samples: List["PatientLabSample"] = Field(default_factory=list)
|
|
63
76
|
patient_diseases: List["PatientDisease"] = Field(default_factory=list)
|
|
64
77
|
diseases: List["Disease"] = Field(default_factory=list)
|
|
65
|
-
disease_classification_choices: List["DiseaseClassificationChoice"] = Field(
|
|
78
|
+
disease_classification_choices: List["DiseaseClassificationChoice"] = Field(
|
|
79
|
+
default_factory=list
|
|
80
|
+
)
|
|
66
81
|
events: List["Event"] = Field(default_factory=list)
|
|
67
82
|
patient_events: List["PatientEvent"] = Field(default_factory=list)
|
|
68
83
|
patient_findings: List["PatientFinding"] = Field(default_factory=list)
|
|
69
84
|
findings: List["Finding"] = Field(default_factory=list)
|
|
70
|
-
finding_classification_choices: List["FindingClassificationChoice"] = Field(
|
|
71
|
-
|
|
85
|
+
finding_classification_choices: List["FindingClassificationChoice"] = Field(
|
|
86
|
+
default_factory=list
|
|
87
|
+
)
|
|
88
|
+
finding_classifications: List["FindingClassification"] = Field(
|
|
89
|
+
default_factory=list
|
|
90
|
+
) # Added for direct classification checks if needed
|
|
72
91
|
finding_interventions: List["FindingIntervention"] = Field(default_factory=list)
|
|
73
92
|
patient_lab_sample_types: List["PatientLabSampleType"] = Field(default_factory=list)
|
|
74
|
-
patient_medications: List["PatientMedication"] = Field(
|
|
75
|
-
|
|
93
|
+
patient_medications: List["PatientMedication"] = Field(
|
|
94
|
+
default_factory=list
|
|
95
|
+
) # Added
|
|
96
|
+
patient_medication_schedules: List["PatientMedicationSchedule"] = Field(
|
|
97
|
+
default_factory=list
|
|
98
|
+
) # Added
|
|
76
99
|
# Added direct medication-related fields
|
|
77
100
|
medications: List["Medication"] = Field(default_factory=list)
|
|
78
101
|
medication_indications: List["MedicationIndication"] = Field(default_factory=list)
|
|
@@ -87,38 +110,42 @@ class RequirementLinks(BaseModel):
|
|
|
87
110
|
"""
|
|
88
111
|
if self.patient_lab_values:
|
|
89
112
|
for plv in self.patient_lab_values:
|
|
90
|
-
if
|
|
91
|
-
|
|
113
|
+
if (
|
|
114
|
+
hasattr(plv, "sample")
|
|
115
|
+
and plv.sample
|
|
116
|
+
and hasattr(plv.sample, "patient")
|
|
117
|
+
and plv.sample.patient
|
|
118
|
+
):
|
|
92
119
|
return plv.sample.patient
|
|
93
120
|
if self.patient_lab_samples:
|
|
94
121
|
for pls in self.patient_lab_samples:
|
|
95
|
-
if hasattr(pls,
|
|
122
|
+
if hasattr(pls, "patient") and pls.patient:
|
|
96
123
|
return pls.patient
|
|
97
124
|
if self.patient_examinations:
|
|
98
125
|
for pe in self.patient_examinations:
|
|
99
|
-
if hasattr(pe,
|
|
126
|
+
if hasattr(pe, "patient") and pe.patient:
|
|
100
127
|
return pe.patient
|
|
101
128
|
if self.patient_diseases:
|
|
102
129
|
for pd in self.patient_diseases:
|
|
103
|
-
if hasattr(pd,
|
|
130
|
+
if hasattr(pd, "patient") and pd.patient:
|
|
104
131
|
return pd.patient
|
|
105
132
|
if self.patient_events:
|
|
106
133
|
for pev in self.patient_events:
|
|
107
|
-
if hasattr(pev,
|
|
134
|
+
if hasattr(pev, "patient") and pev.patient:
|
|
108
135
|
return pev.patient
|
|
109
136
|
if self.patient_findings:
|
|
110
137
|
for pf in self.patient_findings:
|
|
111
|
-
if hasattr(pf,
|
|
138
|
+
if hasattr(pf, "patient") and pf.patient:
|
|
112
139
|
return pf.patient
|
|
113
140
|
# Check PatientMedication
|
|
114
141
|
if self.patient_medications:
|
|
115
142
|
for pm in self.patient_medications:
|
|
116
|
-
if hasattr(pm,
|
|
143
|
+
if hasattr(pm, "patient") and pm.patient:
|
|
117
144
|
return pm.patient
|
|
118
145
|
# Check PatientMedicationSchedule
|
|
119
146
|
if self.patient_medication_schedules:
|
|
120
147
|
for pms in self.patient_medication_schedules:
|
|
121
|
-
if hasattr(pms,
|
|
148
|
+
if hasattr(pms, "patient") and pms.patient:
|
|
122
149
|
return pms.patient
|
|
123
150
|
return None
|
|
124
151
|
|
|
@@ -126,32 +153,37 @@ class RequirementLinks(BaseModel):
|
|
|
126
153
|
def data_model_dict(self):
|
|
127
154
|
"""
|
|
128
155
|
Provides access to the data model dictionary used for requirement type parsing.
|
|
129
|
-
|
|
156
|
+
|
|
130
157
|
Returns:
|
|
131
158
|
The `data_model_dict` imported from the requirement type parser module.
|
|
132
159
|
"""
|
|
133
|
-
from endoreg_db.models.requirement.requirement_evaluation.requirement_type_parser import
|
|
160
|
+
from endoreg_db.models.requirement.requirement_evaluation.requirement_type_parser import (
|
|
161
|
+
data_model_dict,
|
|
162
|
+
)
|
|
163
|
+
|
|
134
164
|
return data_model_dict
|
|
135
165
|
|
|
136
166
|
@property
|
|
137
167
|
def data_model_dict_reverse(self):
|
|
138
168
|
"""
|
|
139
169
|
Provides a reverse mapping dictionary for data model types used in requirement evaluation.
|
|
140
|
-
|
|
170
|
+
|
|
141
171
|
Returns:
|
|
142
172
|
The `data_model_dict_reverse` dictionary imported from the requirement type parser module.
|
|
143
173
|
"""
|
|
144
|
-
from endoreg_db.models.requirement.requirement_evaluation.requirement_type_parser import
|
|
174
|
+
from endoreg_db.models.requirement.requirement_evaluation.requirement_type_parser import (
|
|
175
|
+
data_model_dict_reverse,
|
|
176
|
+
)
|
|
145
177
|
|
|
146
178
|
return data_model_dict_reverse
|
|
147
179
|
|
|
148
|
-
def match_any(self, other:"RequirementLinks") -> bool:
|
|
180
|
+
def match_any(self, other: "RequirementLinks") -> bool:
|
|
149
181
|
"""
|
|
150
182
|
Determines if any linked model in this instance is also present in another RequirementLinks instance.
|
|
151
|
-
|
|
183
|
+
|
|
152
184
|
Compares each list attribute of both instances and returns True if any element in any list overlaps.
|
|
153
185
|
"""
|
|
154
|
-
|
|
186
|
+
|
|
155
187
|
other_dict = other.model_dump()
|
|
156
188
|
self_dict = self.model_dump()
|
|
157
189
|
for key in self_dict:
|
|
@@ -159,12 +191,12 @@ class RequirementLinks(BaseModel):
|
|
|
159
191
|
if key in other_dict and self_dict[key] and other_dict[key]:
|
|
160
192
|
if any(item in other_dict[key] for item in self_dict[key]):
|
|
161
193
|
return True
|
|
162
|
-
return False
|
|
163
|
-
|
|
194
|
+
return False # Ensure False is returned if no match is found
|
|
195
|
+
|
|
164
196
|
def active(self) -> dict[str, list]:
|
|
165
197
|
"""
|
|
166
198
|
Returns a dictionary of all non-empty linked model lists.
|
|
167
|
-
|
|
199
|
+
|
|
168
200
|
Only attributes with non-empty lists are included in the returned dictionary.
|
|
169
201
|
"""
|
|
170
202
|
active_links_dict = {}
|
|
@@ -180,14 +212,26 @@ class RequirementLinks(BaseModel):
|
|
|
180
212
|
"""
|
|
181
213
|
data = self.model_dump()
|
|
182
214
|
fields = [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
215
|
+
"examinations",
|
|
216
|
+
"examination_indications",
|
|
217
|
+
"patient_examinations",
|
|
218
|
+
"lab_values",
|
|
219
|
+
"patient_lab_values",
|
|
220
|
+
"patient_diseases",
|
|
221
|
+
"diseases",
|
|
222
|
+
"disease_classification_choices",
|
|
223
|
+
"events",
|
|
224
|
+
"patient_events",
|
|
225
|
+
"findings",
|
|
226
|
+
"patient_findings",
|
|
227
|
+
"finding_classification_choices",
|
|
228
|
+
"finding_interventions",
|
|
229
|
+
"patient_medications",
|
|
230
|
+
"patient_medication_schedules",
|
|
231
|
+
"medications",
|
|
232
|
+
"medication_indications",
|
|
233
|
+
"medication_intake_times",
|
|
234
|
+
"medication_schedules",
|
|
189
235
|
]
|
|
190
236
|
parts = [f"{f}={len(data.get(f, []))}" for f in fields]
|
|
191
237
|
return f"RequirementLinks({', '.join(parts)})"
|
|
192
|
-
|
|
193
|
-
|
endoreg_db/utils/ocr.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import pytesseract
|
|
2
|
-
from PIL import Image, ImageOps
|
|
2
|
+
from PIL import Image, ImageOps
|
|
3
|
+
import cv2
|
|
3
4
|
import os
|
|
4
5
|
from collections import Counter
|
|
5
6
|
from tempfile import TemporaryDirectory
|
|
6
7
|
import re
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from typing import Dict, List
|
|
9
|
-
import numpy as np
|
|
10
10
|
from endoreg_db.utils.cropping import crop_and_insert
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
N_FRAMES_MEAN_OCR = 2
|
|
15
14
|
|
|
15
|
+
|
|
16
16
|
# Helper function to process date strings
|
|
17
17
|
def process_date_text(date_text):
|
|
18
18
|
"""
|
|
@@ -26,7 +26,7 @@ def process_date_text(date_text):
|
|
|
26
26
|
"""
|
|
27
27
|
try:
|
|
28
28
|
# Remove any non-digit characters
|
|
29
|
-
date_text_clean = re.sub(r
|
|
29
|
+
date_text_clean = re.sub(r"\D", "", date_text)
|
|
30
30
|
# Reformat to 'ddmmyyyy' if necessary
|
|
31
31
|
if len(date_text_clean) == 8:
|
|
32
32
|
return datetime.strptime(date_text_clean, "%d%m%Y").date()
|
|
@@ -37,14 +37,15 @@ def process_date_text(date_text):
|
|
|
37
37
|
# set date to 1/1/1900
|
|
38
38
|
return datetime.strptime("01011900", "%d%m%Y").date()
|
|
39
39
|
|
|
40
|
+
|
|
40
41
|
# Helper function to process patient names
|
|
41
42
|
def process_name_text(name_text):
|
|
42
43
|
"""
|
|
43
44
|
Remove all numbers, punctuation, and whitespace from a string of text and return the result.
|
|
44
45
|
"""
|
|
45
|
-
name = re.sub(r'[0-9!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~\s]+',
|
|
46
|
+
name = re.sub(r'[0-9!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~\s]+', "", name_text).strip()
|
|
46
47
|
# capitalize first letter of each word
|
|
47
|
-
name =
|
|
48
|
+
name = " ".join([word.capitalize() for word in name.split()])
|
|
48
49
|
return name
|
|
49
50
|
|
|
50
51
|
|
|
@@ -53,7 +54,8 @@ def process_general_text(endoscope_text):
|
|
|
53
54
|
"""
|
|
54
55
|
This function takes in a string of text from an endoscope and returns a cleaned version of the text.
|
|
55
56
|
"""
|
|
56
|
-
return
|
|
57
|
+
return " ".join(endoscope_text.split())
|
|
58
|
+
|
|
57
59
|
|
|
58
60
|
def roi_values_valid(roi):
|
|
59
61
|
"""
|
|
@@ -61,6 +63,7 @@ def roi_values_valid(roi):
|
|
|
61
63
|
"""
|
|
62
64
|
return all([value >= 0 for value in roi.values()])
|
|
63
65
|
|
|
66
|
+
|
|
64
67
|
# Function to extract text from ROIs
|
|
65
68
|
def extract_text_from_rois(image_path, processor):
|
|
66
69
|
"""
|
|
@@ -75,11 +78,11 @@ def extract_text_from_rois(image_path, processor):
|
|
|
75
78
|
"""
|
|
76
79
|
# Read the image using Pillow
|
|
77
80
|
image = Image.open(image_path)
|
|
78
|
-
image_dimensions = image.size
|
|
81
|
+
image_dimensions = image.size # (width, height)
|
|
79
82
|
|
|
80
83
|
####### Adjust Image #######
|
|
81
84
|
# Convert to grayscale
|
|
82
|
-
gray = image.convert(
|
|
85
|
+
gray = image.convert("L")
|
|
83
86
|
|
|
84
87
|
# Invert colors for white text on black background
|
|
85
88
|
inverted = ImageOps.invert(gray)
|
|
@@ -89,36 +92,36 @@ def extract_text_from_rois(image_path, processor):
|
|
|
89
92
|
|
|
90
93
|
# Define your ROIs and their corresponding post-processing functions in tuples
|
|
91
94
|
rois_with_postprocessing = [
|
|
92
|
-
(
|
|
95
|
+
("examination_date", processor.get_roi_examination_date, process_date_text),
|
|
93
96
|
("patient_first_name", processor.get_roi_patient_first_name, process_name_text),
|
|
94
|
-
(
|
|
95
|
-
(
|
|
96
|
-
(
|
|
97
|
-
(
|
|
97
|
+
("patient_last_name", processor.get_roi_patient_last_name, process_name_text),
|
|
98
|
+
("patient_dob", processor.get_roi_patient_dob, process_date_text),
|
|
99
|
+
("endoscope_type", processor.get_roi_endoscope_type, process_general_text),
|
|
100
|
+
("endoscope_sn", processor.get_roi_endoscopy_sn, process_general_text),
|
|
98
101
|
]
|
|
99
102
|
|
|
100
103
|
# Extract and post-process text for each ROI
|
|
101
104
|
for roi_name, roi_function, post_process in rois_with_postprocessing:
|
|
102
105
|
# Get the ROI dictionary
|
|
103
106
|
roi = roi_function()
|
|
104
|
-
|
|
107
|
+
|
|
105
108
|
# Check if the ROI has values
|
|
106
|
-
|
|
109
|
+
|
|
107
110
|
if roi_values_valid(roi):
|
|
108
|
-
x, y, w, h = roi[
|
|
109
|
-
|
|
111
|
+
x, y, w, h = roi["x"], roi["y"], roi["width"], roi["height"]
|
|
112
|
+
|
|
110
113
|
# Get white image with original shape and just the roi remaining
|
|
111
|
-
roi_image = crop_and_insert(inverted, x,y,h,w)
|
|
114
|
+
roi_image = crop_and_insert(inverted, x, y, h, w)
|
|
112
115
|
|
|
113
116
|
# OCR configuration: Recognize white text on black background without corrections
|
|
114
|
-
config =
|
|
117
|
+
config = "--psm 10 -c tessedit_char_whitelist=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-üöäÜÖÄß"
|
|
115
118
|
|
|
116
119
|
# Use pytesseract to do OCR on the preprocessed ROI
|
|
117
120
|
text = pytesseract.image_to_string(roi_image, config=config).strip()
|
|
118
121
|
|
|
119
122
|
# Post-process extracted text
|
|
120
123
|
processed_text = post_process(text)
|
|
121
|
-
|
|
124
|
+
|
|
122
125
|
extracted_texts[roi_name] = processed_text
|
|
123
126
|
|
|
124
127
|
else:
|
|
@@ -126,6 +129,7 @@ def extract_text_from_rois(image_path, processor):
|
|
|
126
129
|
|
|
127
130
|
return extracted_texts
|
|
128
131
|
|
|
132
|
+
|
|
129
133
|
def get_most_frequent_values(rois_texts: Dict[str, List[str]]) -> Dict[str, str]:
|
|
130
134
|
"""
|
|
131
135
|
Given a dictionary of ROIs and their corresponding texts, returns a dictionary of the most frequent text for each ROI.
|
|
@@ -142,6 +146,7 @@ def get_most_frequent_values(rois_texts: Dict[str, List[str]]) -> Dict[str, str]
|
|
|
142
146
|
most_frequent[key], _ = counter.most_common(1)[0] if counter else (None, None)
|
|
143
147
|
return most_frequent
|
|
144
148
|
|
|
149
|
+
|
|
145
150
|
def process_video(video_path, processor):
|
|
146
151
|
"""
|
|
147
152
|
Processes a video file by extracting text from regions of interest (ROIs) in each frame.
|
|
@@ -169,10 +174,10 @@ def process_video(video_path, processor):
|
|
|
169
174
|
frame_path = os.path.join(temp_dir, f"frame_{frame_number}.jpg")
|
|
170
175
|
cv2.imwrite(frame_path, frame) # Save the frame as a JPEG file
|
|
171
176
|
# cv2.imwrite(f"_tmp/frame_{frame_number}.jpg", frame)
|
|
172
|
-
|
|
177
|
+
|
|
173
178
|
# Extract text from ROIs
|
|
174
179
|
extracted_texts = extract_text_from_rois(frame_path, processor)
|
|
175
|
-
|
|
180
|
+
|
|
176
181
|
# Store the extracted text from each ROI
|
|
177
182
|
for key, text in extracted_texts.items():
|
|
178
183
|
rois_texts[key].append(text)
|
|
@@ -180,11 +185,11 @@ def process_video(video_path, processor):
|
|
|
180
185
|
|
|
181
186
|
frame_number += 1
|
|
182
187
|
|
|
183
|
-
if frames_for_mean_extraction >= N_FRAMES_MEAN_OCR:
|
|
188
|
+
if frames_for_mean_extraction >= N_FRAMES_MEAN_OCR:
|
|
189
|
+
break
|
|
184
190
|
|
|
185
191
|
# Release the video capture object
|
|
186
192
|
video.release()
|
|
187
193
|
|
|
188
194
|
# Get the most frequent values for each ROI
|
|
189
195
|
return get_most_frequent_values(rois_texts)
|
|
190
|
-
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from django.http import HttpRequest
|
|
7
|
+
|
|
8
|
+
from endoreg_db.models.operation_log import OperationLog
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def record_operation(
|
|
14
|
+
request: HttpRequest,
|
|
15
|
+
*,
|
|
16
|
+
action: str,
|
|
17
|
+
resource_type: str = "",
|
|
18
|
+
resource_id: Optional[int] = None,
|
|
19
|
+
status_before: Optional[str] = None,
|
|
20
|
+
status_after: Optional[str] = None,
|
|
21
|
+
meta: Optional[dict[str, Any]] = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Create an OperationLog entry from a view.
|
|
25
|
+
"""
|
|
26
|
+
user = getattr(request, "user", None)
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
log = OperationLog(
|
|
30
|
+
actor_user=user if getattr(user, "is_authenticated", False) else None,
|
|
31
|
+
actor_username=getattr(user, "username", "") if user else "",
|
|
32
|
+
actor_email=getattr(user, "email", "") if user else "",
|
|
33
|
+
actor_keycloak_id="", # fill later if you add it to your user model
|
|
34
|
+
action=action,
|
|
35
|
+
http_method=getattr(request, "method", ""),
|
|
36
|
+
path=getattr(request, "path", ""),
|
|
37
|
+
resource_type=resource_type,
|
|
38
|
+
resource_id=resource_id,
|
|
39
|
+
status_before=status_before or "",
|
|
40
|
+
status_after=status_after or "",
|
|
41
|
+
meta=meta or None,
|
|
42
|
+
)
|
|
43
|
+
log.save()
|
|
44
|
+
except Exception:
|
|
45
|
+
# Never kill the main request flow because of logging
|
|
46
|
+
logger.exception(
|
|
47
|
+
"Failed to record operation %s for %s(%s)",
|
|
48
|
+
action,
|
|
49
|
+
resource_type,
|
|
50
|
+
resource_id,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# TODO: will make the name more generic later base don the requirement,after merge
|
|
55
|
+
def get_resource_type_from_instance(obj):
|
|
56
|
+
name = obj.__class__.__name__
|
|
57
|
+
'''if name == "VideoFile":
|
|
58
|
+
return "video"
|
|
59
|
+
if name == "RawPdfFile":
|
|
60
|
+
return "pdf"'''
|
|
61
|
+
return name.lower()
|
|
@@ -7,25 +7,24 @@ module_root = file_path.parent.parent
|
|
|
7
7
|
data_dir = module_root / "data"
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def collect_center_names(
|
|
11
|
-
):
|
|
10
|
+
def collect_center_names():
|
|
12
11
|
input_file_path = data_dir / "center/data.yaml"
|
|
13
12
|
fist_name_dir = data_dir / "names_first"
|
|
14
13
|
last_name_dir = data_dir / "names_last"
|
|
15
14
|
# Load the input YAML file
|
|
16
|
-
with open(input_file_path,
|
|
15
|
+
with open(input_file_path, "r", encoding="utf-8") as file:
|
|
17
16
|
data = yaml.safe_load(file)
|
|
18
|
-
|
|
17
|
+
|
|
19
18
|
# Containers for first and last names
|
|
20
19
|
first_names_set = set()
|
|
21
20
|
last_names_set = set()
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
# Extract first and last names from the YAML data
|
|
24
23
|
for entry in data:
|
|
25
|
-
fields = entry.get(
|
|
26
|
-
first_names_set.update(fields.get(
|
|
27
|
-
last_names_set.update(fields.get(
|
|
28
|
-
|
|
24
|
+
fields = entry.get("fields", {})
|
|
25
|
+
first_names_set.update(fields.get("first_names", []))
|
|
26
|
+
last_names_set.update(fields.get("last_names", []))
|
|
27
|
+
|
|
29
28
|
# Create a list of dictionaries for first and last names
|
|
30
29
|
first_names_data = [
|
|
31
30
|
{"model": "endoreg_db.first_name", "fields": {"name": name}}
|
|
@@ -35,12 +34,12 @@ def collect_center_names(
|
|
|
35
34
|
{"model": "endoreg_db.last_name", "fields": {"name": name}}
|
|
36
35
|
for name in sorted(last_names_set)
|
|
37
36
|
]
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
# Write the data to separate YAML files
|
|
40
|
-
with open(fist_name_dir/"first_names.yaml", "w", encoding=
|
|
39
|
+
with open(fist_name_dir / "first_names.yaml", "w", encoding="utf-8") as first_file:
|
|
41
40
|
yaml.dump(first_names_data, first_file, allow_unicode=True, sort_keys=False)
|
|
42
|
-
|
|
43
|
-
with open(last_name_dir/"last_names.yaml", "w", encoding=
|
|
41
|
+
|
|
42
|
+
with open(last_name_dir / "last_names.yaml", "w", encoding="utf-8") as last_file:
|
|
44
43
|
yaml.dump(last_names_data, last_file, allow_unicode=True, sort_keys=False)
|
|
45
44
|
|
|
46
45
|
# print("Generated first_names.yaml and last_names.yaml successfully.")
|
endoreg_db/utils/paths.py
CHANGED
|
@@ -40,8 +40,8 @@ if not STORAGE_DIR.exists():
|
|
|
40
40
|
IMPORT_DIR_NAME = "import"
|
|
41
41
|
EXPORT_DIR_NAME = "export"
|
|
42
42
|
|
|
43
|
-
IMPORT_DIR = IO_DIR / IMPORT_DIR_NAME
|
|
44
|
-
EXPORT_DIR = IO_DIR / EXPORT_DIR_NAME
|
|
43
|
+
IMPORT_DIR = IO_DIR / IMPORT_DIR_NAME # data/import
|
|
44
|
+
EXPORT_DIR = IO_DIR / EXPORT_DIR_NAME # data/export
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
IMPORT_VIDEO_DIR_NAME = "video_import"
|
|
@@ -64,7 +64,7 @@ DOCUMENT_DIR = STORAGE_DIR / "documents"
|
|
|
64
64
|
|
|
65
65
|
# After initial import, files will remain here.
|
|
66
66
|
|
|
67
|
-
TRANSCODING_DIR = STORAGE_DIR /"temp"
|
|
67
|
+
TRANSCODING_DIR = STORAGE_DIR / "temp"
|
|
68
68
|
|
|
69
69
|
SENSITIVE_VIDEO_DIR_NAME = "sensitive_videos"
|
|
70
70
|
SENSITIVE_REPORT_DIR_NAME = "sensitive_reports"
|
|
@@ -116,7 +116,7 @@ data_paths: Dict[str, Path] = {
|
|
|
116
116
|
"weights_export": EXPORT_DIR / WEIGHTS_DIR_NAME,
|
|
117
117
|
"transcoding": TRANSCODING_DIR,
|
|
118
118
|
"frame": FRAME_DIR,
|
|
119
|
-
"documents": DOCUMENT_DIR
|
|
119
|
+
"documents": DOCUMENT_DIR,
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
logger.info(f"Storage directory: {STORAGE_DIR.resolve()}")
|
|
@@ -126,7 +126,7 @@ for key, path in data_paths.items():
|
|
|
126
126
|
path.mkdir(parents=True, exist_ok=True)
|
|
127
127
|
|
|
128
128
|
logger.info(f"{key.capitalize()} directory: {path.resolve()}")
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
|
|
131
131
|
def to_storage_relative(path: Union[str, Path]) -> str:
|
|
132
132
|
"""
|
|
@@ -156,4 +156,4 @@ def to_storage_relative(path: Union[str, Path]) -> str:
|
|
|
156
156
|
return str(path)
|
|
157
157
|
|
|
158
158
|
# Use POSIX-style separators for Django FileField
|
|
159
|
-
return rel.as_posix()
|
|
159
|
+
return rel.as_posix()
|