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
|
@@ -91,7 +91,9 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
91
91
|
if track_hparams:
|
|
92
92
|
self.save_hyperparameters()
|
|
93
93
|
if labels is None:
|
|
94
|
-
raise ValueError(
|
|
94
|
+
raise ValueError(
|
|
95
|
+
"labels must be provided to initialize MultiLabelClassificationNet"
|
|
96
|
+
)
|
|
95
97
|
|
|
96
98
|
self.model_type = model_type
|
|
97
99
|
self.labels = list(labels)
|
|
@@ -135,13 +137,23 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
135
137
|
strict = kwargs.pop("strict", True)
|
|
136
138
|
labels = kwargs.pop("labels", None)
|
|
137
139
|
if not labels:
|
|
138
|
-
raise ValueError(
|
|
140
|
+
raise ValueError(
|
|
141
|
+
"labels must be provided when loading .safetensors checkpoints"
|
|
142
|
+
)
|
|
139
143
|
model_type = kwargs.pop("model_type", None) or "EfficientNetB4"
|
|
140
144
|
load_imagenet = kwargs.pop("load_imagenet_weights", False)
|
|
141
145
|
|
|
142
|
-
device =
|
|
146
|
+
device = (
|
|
147
|
+
torch.device(map_location)
|
|
148
|
+
if map_location is not None
|
|
149
|
+
else torch.device("cpu")
|
|
150
|
+
)
|
|
143
151
|
if isinstance(device, torch.device):
|
|
144
|
-
device_hint =
|
|
152
|
+
device_hint = (
|
|
153
|
+
f"{device.type}:{device.index}"
|
|
154
|
+
if device.index is not None
|
|
155
|
+
else device.type
|
|
156
|
+
)
|
|
145
157
|
else:
|
|
146
158
|
device_hint = device
|
|
147
159
|
|
|
@@ -160,7 +172,9 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
160
172
|
if missing:
|
|
161
173
|
logger.warning("Missing parameters when loading %s: %s", path, missing)
|
|
162
174
|
if unexpected:
|
|
163
|
-
logger.warning(
|
|
175
|
+
logger.warning(
|
|
176
|
+
"Unexpected parameters when loading %s: %s", path, unexpected
|
|
177
|
+
)
|
|
164
178
|
|
|
165
179
|
instance.to(device)
|
|
166
180
|
return instance
|
|
@@ -245,7 +259,8 @@ class MultiLabelClassificationNet(LightningModule):
|
|
|
245
259
|
self.parameters(), self.lr, momentum=0.5, weight_decay=self.weight_decay
|
|
246
260
|
)
|
|
247
261
|
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(
|
|
248
|
-
optimizer,
|
|
262
|
+
optimizer,
|
|
263
|
+
T_0=20,
|
|
249
264
|
)
|
|
250
265
|
|
|
251
266
|
return {
|
endoreg_db/utils/ai/predict.py
CHANGED
|
@@ -85,11 +85,11 @@ class Classifier:
|
|
|
85
85
|
with torch.inference_mode():
|
|
86
86
|
if self.verbose:
|
|
87
87
|
ic("Starting inference")
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
# Ensure model exists
|
|
90
90
|
if self.model is None:
|
|
91
91
|
raise ValueError("Model is not loaded")
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
# Use the device the model is currently on, with fallback to CPU
|
|
94
94
|
try:
|
|
95
95
|
# Check what device the model parameters are on
|
|
@@ -107,10 +107,10 @@ class Classifier:
|
|
|
107
107
|
device = torch.device("cpu")
|
|
108
108
|
if verbose:
|
|
109
109
|
print(f"Device detection failed, using CPU: {e}")
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
# Ensure model is in eval mode
|
|
112
112
|
self.model.eval()
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
for batch in tqdm(dl):
|
|
115
115
|
batch = batch.to(device, non_blocking=True)
|
|
116
116
|
prediction = self.model(batch)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from PIL import Image, ImageOps # Import the required modules from Pillow
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
def crop_img(img, crop):
|
|
5
6
|
"""
|
|
6
7
|
Crops the image based on the specified dimensions and adds padding to maintain aspect ratio.
|
|
@@ -15,21 +16,26 @@ def crop_img(img, crop):
|
|
|
15
16
|
# Convert crop dimensions to Pillow format: left, upper, right, lower
|
|
16
17
|
ymin, ymax, xmin, xmax = crop
|
|
17
18
|
img_cropped = img.crop((xmin, ymin, xmax, ymax))
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
# Calculate the new size and the required padding
|
|
20
21
|
width, height = img_cropped.size
|
|
21
22
|
delta = width - height
|
|
22
|
-
|
|
23
|
+
|
|
23
24
|
if delta > 0:
|
|
24
|
-
padding = (
|
|
25
|
+
padding = (
|
|
26
|
+
0,
|
|
27
|
+
abs(delta) // 2,
|
|
28
|
+
0,
|
|
29
|
+
abs(delta) - abs(delta) // 2,
|
|
30
|
+
) # (left, top, right, bottom)
|
|
25
31
|
elif delta < 0:
|
|
26
32
|
padding = (abs(delta) // 2, 0, abs(delta) - abs(delta) // 2, 0)
|
|
27
33
|
else:
|
|
28
34
|
padding = (0, 0, 0, 0)
|
|
29
|
-
|
|
35
|
+
|
|
30
36
|
# Pad the image to make it square
|
|
31
37
|
img_padded = ImageOps.expand(img_cropped, padding)
|
|
32
|
-
|
|
38
|
+
|
|
33
39
|
return img_padded
|
|
34
40
|
|
|
35
41
|
|
|
@@ -37,7 +43,9 @@ class Cropper:
|
|
|
37
43
|
def __init__(self):
|
|
38
44
|
pass
|
|
39
45
|
|
|
40
|
-
def __call__(
|
|
46
|
+
def __call__(
|
|
47
|
+
self, img, crop=None, scale=None, scale_method=Image.Resampling.LANCZOS
|
|
48
|
+
):
|
|
41
49
|
"""
|
|
42
50
|
Applies cropping and scaling transformations to the input image.
|
|
43
51
|
|
|
@@ -52,17 +60,17 @@ class Cropper:
|
|
|
52
60
|
"""
|
|
53
61
|
# Convert numpy array to PIL Image if necessary
|
|
54
62
|
if isinstance(img, np.ndarray):
|
|
55
|
-
img = Image.fromarray(img.astype(
|
|
56
|
-
|
|
63
|
+
img = Image.fromarray(img.astype("uint8"), "RGB")
|
|
64
|
+
|
|
57
65
|
if crop is not None:
|
|
58
66
|
img = crop_img(img, crop)
|
|
59
67
|
else:
|
|
60
68
|
raise Exception("Automatic crop detection not implemented yet")
|
|
61
|
-
|
|
69
|
+
|
|
62
70
|
if scale is not None:
|
|
63
71
|
img = img.resize(scale, resample=scale_method)
|
|
64
|
-
|
|
72
|
+
|
|
65
73
|
# Convert PIL Image back to numpy array
|
|
66
74
|
img = np.array(img)
|
|
67
|
-
|
|
75
|
+
|
|
68
76
|
return img
|
|
@@ -4,7 +4,7 @@ if TYPE_CHECKING:
|
|
|
4
4
|
from endoreg_db.models import VideoFile
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def _calc_duration_vf(obj:"VideoFile") -> float:
|
|
7
|
+
def _calc_duration_vf(obj: "VideoFile") -> float:
|
|
8
8
|
"""
|
|
9
9
|
Calculate duration of a VideoFile.
|
|
10
10
|
"""
|
|
@@ -12,13 +12,13 @@ def _calc_duration_vf(obj:"VideoFile") -> float:
|
|
|
12
12
|
raise ValueError("ffmpeg_meta is missing, cannot calculate duration.")
|
|
13
13
|
|
|
14
14
|
fps = obj.get_fps()
|
|
15
|
-
frame_count = obj.frame_count
|
|
15
|
+
frame_count = obj.frame_count # TODO similar implementation as in get_fps
|
|
16
16
|
|
|
17
17
|
duration = frame_count / fps if fps > 0 else -1
|
|
18
18
|
if duration > 0:
|
|
19
19
|
return duration
|
|
20
20
|
else:
|
|
21
21
|
raise ValueError(
|
|
22
|
-
f"Invalid duration calculated for video {obj.
|
|
22
|
+
f"Invalid duration calculated for video {obj.video_hash}: {duration}. "
|
|
23
23
|
"Ensure the video file is valid and accessible."
|
|
24
|
-
)
|
|
24
|
+
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from datetime import datetime, timezone
|
|
2
2
|
from endoreg_db.models import Patient, PatientLabSample, PatientLabSampleType
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class LabSampleFactory:
|
|
5
6
|
"""
|
|
6
7
|
Provides methods to generate lab samples.
|
|
@@ -25,9 +26,7 @@ class LabSampleFactory:
|
|
|
25
26
|
sample_type = PatientLabSampleType.objects.get(name="generic")
|
|
26
27
|
|
|
27
28
|
lab_sample = PatientLabSample.objects.create(
|
|
28
|
-
patient=patient,
|
|
29
|
-
sample_type=sample_type,
|
|
30
|
-
date=datetime.now(tz=timezone.utc)
|
|
29
|
+
patient=patient, sample_type=sample_type, date=datetime.now(tz=timezone.utc)
|
|
31
30
|
)
|
|
32
31
|
|
|
33
|
-
return lab_sample
|
|
32
|
+
return lab_sample
|
|
@@ -3,146 +3,173 @@
|
|
|
3
3
|
Simple video file existence checker and path corrector for VideoFile records.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import argparse
|
|
6
7
|
import os
|
|
7
8
|
import sys
|
|
8
9
|
from pathlib import Path
|
|
9
|
-
import argparse
|
|
10
10
|
|
|
11
11
|
# Parse command-line arguments and environment variables for configuration
|
|
12
|
-
parser = argparse.ArgumentParser(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
parser.add_argument(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
parser = argparse.ArgumentParser(
|
|
13
|
+
description="Simple video file existence checker and path corrector for VideoFile records."
|
|
14
|
+
)
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"--django-base",
|
|
17
|
+
type=str,
|
|
18
|
+
default=os.environ.get(
|
|
19
|
+
"ENDOREG_DJANGO_PROJECT_PATH",
|
|
20
|
+
str(Path(__file__).resolve().parent.parent.parent),
|
|
21
|
+
),
|
|
22
|
+
help="Path to the Django project base (default: env ENDOREG_DJANGO_PROJECT_PATH or project root)",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--django-settings",
|
|
26
|
+
type=str,
|
|
27
|
+
default=os.environ.get("DJANGO_SETTINGS_MODULE", "dev.dev_settings"),
|
|
28
|
+
help="Django settings module (default: env DJANGO_SETTINGS_MODULE or dev.dev_settings)",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--storage-dir",
|
|
32
|
+
type=str,
|
|
33
|
+
default=os.environ.get("ENDOREG_STORAGE_DIR", "./storage"),
|
|
34
|
+
help="Path to the storage directory (default: ./storage or $ENDOREG_STORAGE_DIR)",
|
|
35
|
+
)
|
|
19
36
|
args, unknown = parser.parse_known_args()
|
|
20
37
|
|
|
21
38
|
sys.path.insert(0, args.django_base)
|
|
22
|
-
os.environ.setdefault(
|
|
39
|
+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", args.django_settings)
|
|
23
40
|
|
|
24
41
|
try:
|
|
25
42
|
import django
|
|
43
|
+
|
|
26
44
|
django.setup()
|
|
27
45
|
from endoreg_db.models import VideoFile
|
|
46
|
+
|
|
28
47
|
DJANGO_AVAILABLE = True
|
|
29
48
|
except Exception as e:
|
|
30
49
|
print(f"Django not available: {e}")
|
|
31
50
|
DJANGO_AVAILABLE = False
|
|
32
51
|
|
|
52
|
+
|
|
33
53
|
def find_video_files():
|
|
34
54
|
"""Find all video files in storage directory."""
|
|
35
55
|
storage_dir = Path(args.storage_dir)
|
|
36
56
|
video_files = []
|
|
37
|
-
|
|
38
|
-
for pattern in [
|
|
57
|
+
|
|
58
|
+
for pattern in ["**/*.mp4", "**/*.avi", "**/*.mov", "**/*.mkv"]:
|
|
39
59
|
video_files.extend(storage_dir.glob(pattern))
|
|
40
|
-
|
|
60
|
+
|
|
41
61
|
return video_files
|
|
42
62
|
|
|
63
|
+
|
|
43
64
|
def check_video_file_accessibility(file_path):
|
|
44
65
|
"""Check if a video file is accessible and valid."""
|
|
45
66
|
try:
|
|
46
67
|
if not file_path.exists():
|
|
47
68
|
return False, "File does not exist"
|
|
48
|
-
|
|
69
|
+
|
|
49
70
|
if file_path.stat().st_size == 0:
|
|
50
71
|
return False, "File is empty (0 bytes)"
|
|
51
|
-
|
|
72
|
+
|
|
52
73
|
if not os.access(file_path, os.R_OK):
|
|
53
74
|
return False, "File is not readable"
|
|
54
|
-
|
|
75
|
+
|
|
55
76
|
# Try to read first few bytes to check if it's actually a file
|
|
56
|
-
with open(file_path,
|
|
77
|
+
with open(file_path, "rb") as f:
|
|
57
78
|
header = f.read(8)
|
|
58
79
|
if len(header) < 8:
|
|
59
80
|
return False, "File too small or corrupted"
|
|
60
|
-
|
|
61
|
-
return True, f"OK - {file_path.stat().st_size / (1024*1024):.1f} MB"
|
|
62
|
-
|
|
81
|
+
|
|
82
|
+
return True, f"OK - {file_path.stat().st_size / (1024 * 1024):.1f} MB"
|
|
83
|
+
|
|
63
84
|
except Exception as e:
|
|
64
85
|
return False, f"Error checking file: {e}"
|
|
65
86
|
|
|
87
|
+
|
|
66
88
|
def main():
|
|
67
89
|
print("🔍 VIDEO FILE EXISTENCE CHECKER")
|
|
68
90
|
print("=" * 40)
|
|
69
|
-
|
|
91
|
+
|
|
70
92
|
# Find all video files
|
|
71
93
|
print("1. Scanning for video files...")
|
|
72
94
|
video_files = find_video_files()
|
|
73
95
|
print(f"Found {len(video_files)} video files in storage directory")
|
|
74
|
-
|
|
96
|
+
|
|
75
97
|
if not video_files:
|
|
76
98
|
print("❌ No video files found in storage directory!")
|
|
77
99
|
return
|
|
78
|
-
|
|
100
|
+
|
|
79
101
|
# Check each file
|
|
80
102
|
print("\n2. Checking file accessibility...")
|
|
81
103
|
accessible_files = []
|
|
82
|
-
|
|
104
|
+
|
|
83
105
|
for video_file in video_files[:10]: # Check first 10
|
|
84
106
|
accessible, message = check_video_file_accessibility(video_file)
|
|
85
107
|
status = "✅" if accessible else "❌"
|
|
86
108
|
print(f"{status} {video_file.name}: {message}")
|
|
87
|
-
|
|
109
|
+
|
|
88
110
|
if accessible:
|
|
89
111
|
accessible_files.append(video_file)
|
|
90
|
-
|
|
112
|
+
|
|
91
113
|
if not accessible_files:
|
|
92
114
|
print("\n❌ No accessible video files found!")
|
|
93
115
|
return
|
|
94
|
-
|
|
116
|
+
|
|
95
117
|
print(f"\n✅ Found {len(accessible_files)} accessible video files")
|
|
96
|
-
|
|
118
|
+
|
|
97
119
|
# If Django is available, check database records
|
|
98
120
|
if DJANGO_AVAILABLE:
|
|
99
121
|
print("\n3. Checking database records...")
|
|
100
122
|
try:
|
|
101
123
|
video_5 = VideoFile.objects.get(pk=5)
|
|
102
|
-
print(
|
|
103
|
-
print(f" UUID: {video_5.
|
|
104
|
-
|
|
124
|
+
print("📋 Video ID 5 found in database:")
|
|
125
|
+
print(f" UUID: {video_5.video_hash}")
|
|
126
|
+
|
|
105
127
|
# Check different file path attributes
|
|
106
|
-
for attr in [
|
|
128
|
+
for attr in ["raw_file", "processed_file"]:
|
|
107
129
|
if hasattr(video_5, attr):
|
|
108
130
|
file_field = getattr(video_5, attr)
|
|
109
131
|
if file_field:
|
|
110
132
|
try:
|
|
111
133
|
file_path = Path(file_field.path)
|
|
112
|
-
accessible, message = check_video_file_accessibility(
|
|
134
|
+
accessible, message = check_video_file_accessibility(
|
|
135
|
+
file_path
|
|
136
|
+
)
|
|
113
137
|
status = "✅" if accessible else "❌"
|
|
114
138
|
print(f" {attr}: {status} {file_path} ({message})")
|
|
115
139
|
except Exception as e:
|
|
116
140
|
print(f" {attr}: ❌ Error accessing path: {e}")
|
|
117
141
|
else:
|
|
118
142
|
print(f" {attr}: ❌ No file set")
|
|
119
|
-
|
|
143
|
+
|
|
120
144
|
# Check if UUID matches any found files
|
|
121
|
-
uuid_str = str(video_5.
|
|
145
|
+
uuid_str = str(video_5.video_hash)
|
|
122
146
|
matching_files = [f for f in accessible_files if uuid_str in str(f)]
|
|
123
|
-
|
|
147
|
+
|
|
124
148
|
if matching_files:
|
|
125
149
|
print(f"\n💡 Found matching files for UUID {uuid_str}:")
|
|
126
150
|
for match in matching_files:
|
|
127
151
|
accessible, message = check_video_file_accessibility(match)
|
|
128
152
|
print(f" ✅ {match} ({message})")
|
|
129
|
-
|
|
130
|
-
print(
|
|
153
|
+
|
|
154
|
+
print("\n🔧 SOLUTION: Update VideoFile record to use:")
|
|
131
155
|
print(f" {matching_files[0]}")
|
|
132
|
-
print(
|
|
133
|
-
print(
|
|
134
|
-
print(
|
|
135
|
-
|
|
156
|
+
print("\n🐍 Django command to fix:")
|
|
157
|
+
print(" video = VideoFile.objects.get(pk=5)")
|
|
158
|
+
print(
|
|
159
|
+
f" video.raw_file.name = '{matching_files[0].relative_to(Path(args.storage_dir))}'"
|
|
160
|
+
)
|
|
161
|
+
print(" video.save()")
|
|
136
162
|
else:
|
|
137
163
|
print(f"\n❌ No files found matching UUID {uuid_str}")
|
|
138
|
-
|
|
164
|
+
|
|
139
165
|
except Exception as e:
|
|
140
166
|
print(f"❌ Error checking database: {e}")
|
|
141
|
-
|
|
142
|
-
print(
|
|
143
|
-
print(
|
|
167
|
+
|
|
168
|
+
print("\n4. 🎯 QUICK TEST RECOMMENDATION:")
|
|
169
|
+
print(" Use this accessible file for testing:")
|
|
144
170
|
print(f" {accessible_files[0]}")
|
|
145
|
-
print(f" Size: {accessible_files[0].stat().st_size / (1024*1024):.1f} MB")
|
|
171
|
+
print(f" Size: {accessible_files[0].stat().st_size / (1024 * 1024):.1f} MB")
|
|
172
|
+
|
|
146
173
|
|
|
147
174
|
if __name__ == "__main__":
|
|
148
|
-
main()
|
|
175
|
+
main()
|
endoreg_db/utils/cropping.py
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
from PIL import Image
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
def crop_and_insert(image: Image, x, y, h, w, bg_color=(255, 255, 255)):
|
|
4
5
|
"""
|
|
5
6
|
Crops a region from an inverted grayscale image and inserts it into a white image of the same size as the original.
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
Parameters:
|
|
8
9
|
- fp: File path or a file object of the original image.
|
|
9
10
|
- x, y: The top-left coordinates of the rectangle to be cropped.
|
|
10
11
|
- h, w: The height and width of the rectangle to be cropped.
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
Returns:
|
|
13
14
|
A PIL Image object containing the original image with the specified region replaced.
|
|
14
15
|
"""
|
|
15
16
|
# Load the original image
|
|
16
17
|
original_image = image
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
# Crop the specified region from the inverted image
|
|
19
20
|
crop_rectangle = (x, y, x + w, y + h)
|
|
20
21
|
cropped_content = original_image.crop(crop_rectangle)
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
# Create a new white image of the same size as the original image
|
|
23
|
-
white_background = Image.new(
|
|
24
|
-
|
|
24
|
+
white_background = Image.new("RGB", original_image.size, bg_color)
|
|
25
|
+
|
|
25
26
|
# Paste the cropped content onto the white image at the specified location
|
|
26
27
|
white_background.paste(cropped_content, (x, y))
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
# The final image can be displayed or saved as needed
|
|
29
|
-
return white_background
|
|
30
|
+
return white_background
|
endoreg_db/utils/dataloader.py
CHANGED
|
@@ -122,7 +122,9 @@ def load_data_with_foreign_keys(
|
|
|
122
122
|
requirement_types = fields.get("requirement_types", [])
|
|
123
123
|
|
|
124
124
|
if not requirement_types:
|
|
125
|
-
raise ValueError(
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"Requirement '{name}' must define at least one requirement_types entry."
|
|
127
|
+
)
|
|
126
128
|
|
|
127
129
|
####################
|
|
128
130
|
# TODO REMOVE AFTER TRANSLATION SUPPORT IS ADDED
|
|
@@ -265,7 +267,9 @@ def load_data_with_foreign_keys(
|
|
|
265
267
|
obj, created = _save_instance()
|
|
266
268
|
|
|
267
269
|
if created and verbose:
|
|
268
|
-
command.stdout.write(
|
|
270
|
+
command.stdout.write(
|
|
271
|
+
command.style.SUCCESS(f"Created {model.__name__} {name}")
|
|
272
|
+
)
|
|
269
273
|
elif verbose:
|
|
270
274
|
pass
|
|
271
275
|
|
|
@@ -274,4 +278,8 @@ def load_data_with_foreign_keys(
|
|
|
274
278
|
if related_objs: # Only set if there are objects to set
|
|
275
279
|
getattr(obj, field_name).set(related_objs)
|
|
276
280
|
if verbose:
|
|
277
|
-
command.stdout.write(
|
|
281
|
+
command.stdout.write(
|
|
282
|
+
command.style.SUCCESS(
|
|
283
|
+
f"Set {len(related_objs)} {field_name} for {model.__name__} {name}"
|
|
284
|
+
)
|
|
285
|
+
)
|
endoreg_db/utils/dates.py
CHANGED
|
@@ -2,7 +2,6 @@ from datetime import datetime, date, timedelta
|
|
|
2
2
|
from random import randint
|
|
3
3
|
from calendar import monthrange
|
|
4
4
|
from django.utils import timezone
|
|
5
|
-
import datetime
|
|
6
5
|
|
|
7
6
|
# TODO replace used random_day_by_year function implementation when
|
|
8
7
|
# creating pseudo patients with new function "random date by age_at_date and examination_date"
|
|
@@ -45,16 +44,16 @@ def ensure_aware_datetime(dt):
|
|
|
45
44
|
"""
|
|
46
45
|
Ensures a datetime object is timezone-aware.
|
|
47
46
|
If the datetime is naive (has no timezone info), the current timezone is applied.
|
|
48
|
-
|
|
47
|
+
|
|
49
48
|
Args:
|
|
50
49
|
dt: A datetime object that may be naive
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
Returns:
|
|
53
52
|
A timezone-aware datetime object
|
|
54
53
|
"""
|
|
55
54
|
if dt is None:
|
|
56
55
|
return None
|
|
57
|
-
|
|
56
|
+
|
|
58
57
|
if isinstance(dt, datetime.datetime) and timezone.is_naive(dt):
|
|
59
58
|
return timezone.make_aware(dt)
|
|
60
59
|
return dt
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import subprocess
|
|
2
|
-
from endoreg_db.models.administration.center import center
|
|
3
2
|
|
|
4
3
|
# Start process with interactive pipes
|
|
5
4
|
proc = subprocess.Popen(
|
|
@@ -8,7 +7,7 @@ proc = subprocess.Popen(
|
|
|
8
7
|
stdout=subprocess.PIPE,
|
|
9
8
|
stderr=subprocess.STDOUT,
|
|
10
9
|
text=True,
|
|
11
|
-
bufsize=1
|
|
10
|
+
bufsize=1,
|
|
12
11
|
)
|
|
13
12
|
|
|
14
13
|
proc.stdin.write("print('Trying to extract...')\n")
|
|
@@ -17,11 +16,13 @@ proc.stdin.flush()
|
|
|
17
16
|
try:
|
|
18
17
|
subprocess.run(["python", "manage.py", "load_center_data"], check=True)
|
|
19
18
|
proc.stdout.write("print('found center')")
|
|
20
|
-
except subprocess.CalledProcessError
|
|
21
|
-
proc.stdout.write(
|
|
19
|
+
except subprocess.CalledProcessError:
|
|
20
|
+
proc.stdout.write(
|
|
21
|
+
"print('Didn't find center. Please add it to endoreg_db luxnix or via export DEFAULT_CENTER"
|
|
22
|
+
)
|
|
22
23
|
# """
|
|
23
24
|
# Future Implementation using dialogue
|
|
24
|
-
#"""
|
|
25
|
+
# """
|
|
25
26
|
# # Send commands as if from terminal
|
|
26
27
|
# proc.stdin.write("print('You dont have a default center set up yet. Please enter one here.')\n\nprint('Rule: use_this_format_and_connect_words_with_underscore')")
|
|
27
28
|
# proc.stdin.flush()
|
|
@@ -29,4 +30,4 @@ except subprocess.CalledProcessError as e:
|
|
|
29
30
|
# # Read responses
|
|
30
31
|
# for _ in range(3):
|
|
31
32
|
# line = proc.stdout.readline()
|
|
32
|
-
# print("Selected >>", line.strip())
|
|
33
|
+
# print("Selected >>", line.strip())
|
endoreg_db/utils/env.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
|
|
3
3
|
DEBUG = os.getenv("DEBUG", "false").lower() == "true"
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
def get_env_var(var_name: str, default: str = None) -> str | None:
|
|
6
7
|
"""
|
|
7
8
|
Get the value of an environment variable, with an optional default value.
|
|
@@ -13,12 +14,13 @@ def get_env_var(var_name: str, default: str = None) -> str | None:
|
|
|
13
14
|
"""
|
|
14
15
|
value = os.environ.get(var_name)
|
|
15
16
|
if value:
|
|
16
|
-
value = value.strip(
|
|
17
|
+
value = value.strip("\"'") # Strip both single and double quotes
|
|
17
18
|
if DEBUG:
|
|
18
19
|
print(f"Environment variable {var_name}: {value}")
|
|
19
20
|
return value
|
|
20
21
|
return default
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
def set_env_var(var_name: str, value: str) -> None:
|
|
23
25
|
"""
|
|
24
26
|
Set the value of an environment variable.
|
|
@@ -29,5 +31,7 @@ def set_env_var(var_name: str, value: str) -> None:
|
|
|
29
31
|
if DEBUG:
|
|
30
32
|
print(f"Set environment variable {var_name}: {value}")
|
|
31
33
|
|
|
32
|
-
DJANGO_SETTINGS_MODULE = get_env_var("DJANGO_SETTINGS_MODULE") or "endoreg_db.settings_dev"
|
|
33
34
|
|
|
35
|
+
DJANGO_SETTINGS_MODULE = (
|
|
36
|
+
get_env_var("DJANGO_SETTINGS_MODULE") or "endoreg_db.settings_dev"
|
|
37
|
+
)
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
import shutil
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
def extract_selected_frames(
|
|
5
6
|
video_path: Path,
|
|
6
7
|
frame_numbers: list,
|
|
7
8
|
output_dir: Path,
|
|
8
9
|
fps: int = 50,
|
|
9
10
|
quality: int = 2,
|
|
10
|
-
ext: str = "png"
|
|
11
|
+
ext: str = "png",
|
|
11
12
|
):
|
|
12
13
|
"""
|
|
13
14
|
Extract specific frames from a video using the same quality logic as the original extractor.
|
|
@@ -43,12 +44,21 @@ def extract_selected_frames(
|
|
|
43
44
|
timestamp=timestamp_sec,
|
|
44
45
|
output_path=str(output_file),
|
|
45
46
|
quality=quality,
|
|
46
|
-
ext=ext
|
|
47
|
+
ext=ext,
|
|
47
48
|
)
|
|
49
|
+
|
|
50
|
+
|
|
48
51
|
import subprocess
|
|
49
52
|
from pathlib import Path
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
|
|
55
|
+
def extract_single_frame(
|
|
56
|
+
input_path: str,
|
|
57
|
+
timestamp: float,
|
|
58
|
+
output_path: str,
|
|
59
|
+
quality: int = 2,
|
|
60
|
+
ext: str = "png",
|
|
61
|
+
):
|
|
52
62
|
"""
|
|
53
63
|
Extract a single frame from a video using ffmpeg.
|
|
54
64
|
|
|
@@ -61,12 +71,17 @@ def extract_single_frame(input_path: str, timestamp: float, output_path: str, qu
|
|
|
61
71
|
"""
|
|
62
72
|
cmd = [
|
|
63
73
|
"ffmpeg",
|
|
64
|
-
"-loglevel",
|
|
65
|
-
"
|
|
66
|
-
"-
|
|
67
|
-
"
|
|
68
|
-
"-
|
|
69
|
-
str(
|
|
74
|
+
"-loglevel",
|
|
75
|
+
"error",
|
|
76
|
+
"-ss",
|
|
77
|
+
f"{timestamp:.3f}",
|
|
78
|
+
"-i",
|
|
79
|
+
str(input_path),
|
|
80
|
+
"-frames:v",
|
|
81
|
+
"1",
|
|
82
|
+
"-q:v",
|
|
83
|
+
str(quality),
|
|
84
|
+
str(output_path),
|
|
70
85
|
]
|
|
71
86
|
|
|
72
87
|
subprocess.run(cmd, check=True)
|