endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +8 -31
- endoreg_db/data/_examples/disease.yaml +55 -0
- endoreg_db/data/_examples/disease_classification.yaml +13 -0
- endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
- endoreg_db/data/_examples/event.yaml +64 -0
- endoreg_db/data/_examples/examination.yaml +72 -0
- endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/_examples/finding/complication.yaml +16 -0
- endoreg_db/data/_examples/finding/data.yaml +105 -0
- endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
- endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
- endoreg_db/data/_examples/finding/outcome.yaml +12 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/_examples/finding_type/data.yaml +43 -0
- endoreg_db/data/_examples/requirement/age.yaml +26 -0
- endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/_examples/requirement/gender.yaml +25 -0
- endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
- endoreg_db/data/_examples/requirement/medication.yaml +93 -0
- endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
- endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
- endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
- endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
- endoreg_db/data/requirement_set/90_coloreg.yaml +178 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +5 -2
- endoreg_db/helpers/data_loader.py +1 -1
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +1 -1
- endoreg_db/management/commands/init_default_ai_model.py +1 -1
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +2 -1
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_requirement_data.py +60 -31
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/setup_endoreg_db.py +14 -10
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/migrations/0001_initial.py +1799 -1300
- endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
- endoreg_db/migrations/_old/0001_initial.py +1857 -0
- endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
- endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
- endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
- endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
- endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
- endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
- endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +103 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +7 -8
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +249 -177
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +48 -56
- endoreg_db/models/media/video/pipe_1.py +30 -33
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +359 -204
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +109 -62
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +17 -18
- endoreg_db/models/medical/examination/examination_indication.py +26 -25
- endoreg_db/models/medical/examination/examination_time.py +16 -6
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +38 -39
- endoreg_db/models/medical/finding/finding_classification.py +37 -48
- endoreg_db/models/medical/finding/finding_intervention.py +27 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +20 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +1 -5
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +139 -18
- endoreg_db/models/metadata/pdf_meta.py +19 -24
- endoreg_db/models/metadata/sensitive_meta.py +102 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +383 -43
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +25 -25
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/requirement/requirement.py +580 -272
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +36 -33
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +46 -47
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +40 -46
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +58 -53
- endoreg_db/models/upload_job.py +32 -55
- endoreg_db/models/utils.py +1 -2
- endoreg_db/root_urls.py +21 -2
- endoreg_db/serializers/__init__.py +26 -57
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/meta/report_meta.py +1 -1
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/__init__.py +1 -1
- endoreg_db/serializers/misc/file_overview.py +33 -91
- endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/anonymization.py +75 -73
- endoreg_db/services/lookup_service.py +256 -73
- endoreg_db/services/lookup_store.py +174 -30
- endoreg_db/services/pdf_import.py +711 -310
- endoreg_db/services/storage_aware_video_processor.py +140 -114
- endoreg_db/services/video_import.py +266 -117
- endoreg_db/urls/__init__.py +27 -27
- endoreg_db/urls/label_video_segments.py +2 -0
- endoreg_db/urls/media.py +108 -66
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +88 -16
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +5 -12
- endoreg_db/views/anonymization/media_management.py +198 -163
- endoreg_db/views/anonymization/overview.py +4 -1
- endoreg_db/views/anonymization/validate.py +174 -40
- endoreg_db/views/media/__init__.py +2 -0
- endoreg_db/views/media/pdf_media.py +131 -150
- endoreg_db/views/media/sensitive_metadata.py +46 -6
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/media/video_segments.py +187 -260
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/pdf/__init__.py +5 -8
- endoreg_db/views/pdf/pdf_stream.py +186 -0
- endoreg_db/views/pdf/pdf_stream_views.py +0 -127
- endoreg_db/views/pdf/reimport.py +86 -91
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +186 -288
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +0 -4
- endoreg_db/views/video/correction.py +2 -2
- endoreg_db/views/video/video_examination_viewset.py +202 -289
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +350 -255
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/views/pdf/pdf_media.py +0 -239
- endoreg_db/views/report/__init__.py +0 -9
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/video_media.py +0 -158
- endoreg_db/views.py +0 -0
- /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
- /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
- /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
from django.db import transaction
|
|
2
|
-
from pathlib import Path
|
|
3
1
|
import logging
|
|
4
2
|
import shutil
|
|
5
3
|
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
6
5
|
from typing import Optional
|
|
7
6
|
|
|
8
|
-
from
|
|
7
|
+
from django.db import transaction
|
|
8
|
+
|
|
9
9
|
from endoreg_db.exceptions import InsufficientStorageError
|
|
10
|
+
from endoreg_db.models import AnonymizationTask, VideoFile
|
|
11
|
+
|
|
10
12
|
# from endoreg_db.models.media.video.create_from_file import check_storage_capacity
|
|
11
13
|
|
|
12
14
|
logger = logging.getLogger(__name__)
|
|
@@ -16,209 +18,230 @@ class StorageAwareVideoProcessor:
|
|
|
16
18
|
"""
|
|
17
19
|
Enhanced video processor with built-in storage management and automatic cleanup.
|
|
18
20
|
"""
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
def __init__(self, auto_cleanup: bool = True, min_free_space_gb: float = 10.0):
|
|
21
23
|
self.auto_cleanup = auto_cleanup
|
|
22
24
|
self.min_free_space_gb = min_free_space_gb
|
|
23
|
-
|
|
25
|
+
|
|
24
26
|
def check_and_ensure_storage(self, required_space_estimate: int = None) -> bool:
|
|
25
27
|
"""
|
|
26
28
|
Check storage capacity and perform cleanup if needed.
|
|
27
|
-
|
|
29
|
+
|
|
28
30
|
Args:
|
|
29
31
|
required_space_estimate: Estimated space needed in bytes
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
Returns:
|
|
32
34
|
True if enough space is available, False otherwise
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
Raises:
|
|
35
37
|
InsufficientStorageError: If space cannot be freed
|
|
36
38
|
"""
|
|
37
39
|
try:
|
|
38
40
|
# Get current storage stats
|
|
39
|
-
total, used, free = shutil.disk_usage(
|
|
41
|
+
total, used, free = shutil.disk_usage("/")
|
|
40
42
|
free_gb = free / (1024**3)
|
|
41
43
|
usage_percent = (used / total) * 100
|
|
42
|
-
|
|
43
|
-
logger.info(
|
|
44
|
-
|
|
44
|
+
|
|
45
|
+
logger.info(
|
|
46
|
+
f"Storage check: {free_gb:.1f}GB free ({usage_percent:.1f}% used)"
|
|
47
|
+
)
|
|
48
|
+
|
|
45
49
|
# Check if we need emergency cleanup
|
|
46
50
|
needs_cleanup = (
|
|
47
|
-
usage_percent >= 95.0
|
|
48
|
-
free_gb < self.min_free_space_gb
|
|
49
|
-
(required_space_estimate and free < required_space_estimate * 1.2)
|
|
51
|
+
usage_percent >= 95.0
|
|
52
|
+
or free_gb < self.min_free_space_gb
|
|
53
|
+
or (required_space_estimate and free < required_space_estimate * 1.2)
|
|
50
54
|
)
|
|
51
|
-
|
|
55
|
+
|
|
52
56
|
if needs_cleanup and self.auto_cleanup:
|
|
53
|
-
logger.warning(
|
|
57
|
+
logger.warning(
|
|
58
|
+
f"Storage critically low ({usage_percent:.1f}%), performing automatic cleanup"
|
|
59
|
+
)
|
|
54
60
|
self._perform_emergency_cleanup()
|
|
55
|
-
|
|
61
|
+
|
|
56
62
|
# Re-check after cleanup
|
|
57
|
-
total, used, free = shutil.disk_usage(
|
|
63
|
+
total, used, free = shutil.disk_usage("/")
|
|
58
64
|
free_gb = free / (1024**3)
|
|
59
65
|
usage_percent = (used / total) * 100
|
|
60
|
-
|
|
66
|
+
|
|
61
67
|
if usage_percent >= 98.0:
|
|
62
68
|
raise InsufficientStorageError(
|
|
63
69
|
f"Storage critically low even after cleanup: {usage_percent:.1f}% used, "
|
|
64
70
|
f"only {free_gb:.1f}GB free",
|
|
65
|
-
required_space=required_space_estimate
|
|
66
|
-
|
|
71
|
+
required_space=required_space_estimate
|
|
72
|
+
or int(self.min_free_space_gb * 1024**3),
|
|
73
|
+
available_space=free,
|
|
67
74
|
)
|
|
68
|
-
|
|
75
|
+
|
|
69
76
|
return True
|
|
70
|
-
|
|
77
|
+
|
|
71
78
|
except Exception as e:
|
|
72
79
|
logger.error(f"Storage check failed: {e}")
|
|
73
80
|
raise
|
|
74
|
-
|
|
81
|
+
|
|
75
82
|
def _perform_emergency_cleanup(self) -> int:
|
|
76
83
|
"""
|
|
77
84
|
Perform emergency storage cleanup.
|
|
78
|
-
|
|
85
|
+
|
|
79
86
|
Returns:
|
|
80
87
|
Bytes freed
|
|
81
88
|
"""
|
|
82
89
|
total_freed = 0
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
try:
|
|
85
92
|
# 1. Clean up extracted frames for completed videos
|
|
86
93
|
frames_freed = self._cleanup_completed_video_frames()
|
|
87
94
|
total_freed += frames_freed
|
|
88
|
-
|
|
95
|
+
|
|
89
96
|
# 2. Clean up upload cache older than 1 day
|
|
90
97
|
uploads_freed = self._cleanup_old_uploads(max_age_hours=24)
|
|
91
98
|
total_freed += uploads_freed
|
|
92
|
-
|
|
99
|
+
|
|
93
100
|
# 3. Clean up large log files
|
|
94
101
|
logs_freed = self._cleanup_large_logs()
|
|
95
102
|
total_freed += logs_freed
|
|
96
|
-
|
|
103
|
+
|
|
97
104
|
# 4. Clean up temporary files
|
|
98
105
|
temp_freed = self._cleanup_temp_files()
|
|
99
106
|
total_freed += temp_freed
|
|
100
|
-
|
|
101
|
-
logger.info(
|
|
102
|
-
|
|
107
|
+
|
|
108
|
+
logger.info(
|
|
109
|
+
f"Emergency cleanup completed: {total_freed / (1024**3):.2f}GB freed"
|
|
110
|
+
)
|
|
111
|
+
|
|
103
112
|
except Exception as e:
|
|
104
113
|
logger.error(f"Emergency cleanup failed: {e}")
|
|
105
|
-
|
|
114
|
+
|
|
106
115
|
return total_freed
|
|
107
|
-
|
|
116
|
+
|
|
108
117
|
def _cleanup_completed_video_frames(self) -> int:
|
|
109
118
|
"""Clean up frames for videos that have completed processing."""
|
|
110
119
|
total_freed = 0
|
|
111
|
-
|
|
120
|
+
|
|
112
121
|
try:
|
|
113
122
|
from django.conf import settings
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
|
|
124
|
+
frames_dir = Path(settings.BASE_DIR).parent / "storage" / "frames"
|
|
125
|
+
|
|
116
126
|
if not frames_dir.exists():
|
|
117
127
|
return 0
|
|
118
|
-
|
|
128
|
+
|
|
119
129
|
# Find videos with completed anonymization
|
|
120
130
|
completed_videos = VideoFile.objects.filter(
|
|
121
|
-
anonymization_tasks__status=
|
|
131
|
+
anonymization_tasks__status="done_processing_anonymization"
|
|
122
132
|
).distinct()
|
|
123
|
-
|
|
133
|
+
|
|
124
134
|
for video in completed_videos:
|
|
125
135
|
# Find frame directories for this video
|
|
126
136
|
video_frame_dirs = list(frames_dir.glob(f"*{video.uuid}*"))
|
|
127
|
-
|
|
137
|
+
|
|
128
138
|
for frame_dir in video_frame_dirs:
|
|
129
139
|
if frame_dir.is_dir():
|
|
130
140
|
try:
|
|
131
141
|
# Calculate directory size
|
|
132
142
|
dir_size = sum(
|
|
133
|
-
f.stat().st_size
|
|
143
|
+
f.stat().st_size
|
|
144
|
+
for f in frame_dir.rglob("*")
|
|
145
|
+
if f.is_file()
|
|
134
146
|
)
|
|
135
|
-
|
|
147
|
+
|
|
136
148
|
# Remove the directory
|
|
137
149
|
shutil.rmtree(frame_dir, ignore_errors=True)
|
|
138
150
|
total_freed += dir_size
|
|
139
|
-
|
|
140
|
-
logger.info(
|
|
141
|
-
|
|
151
|
+
|
|
152
|
+
logger.info(
|
|
153
|
+
f"Cleaned frames for {video.uuid}: {dir_size / (1024**2):.1f}MB"
|
|
154
|
+
)
|
|
155
|
+
|
|
142
156
|
except Exception as e:
|
|
143
|
-
logger.warning(
|
|
144
|
-
|
|
157
|
+
logger.warning(
|
|
158
|
+
f"Failed to clean frames for {video.uuid}: {e}"
|
|
159
|
+
)
|
|
160
|
+
|
|
145
161
|
except Exception as e:
|
|
146
162
|
logger.error(f"Frame cleanup failed: {e}")
|
|
147
|
-
|
|
163
|
+
|
|
148
164
|
return total_freed
|
|
149
|
-
|
|
165
|
+
|
|
150
166
|
def _cleanup_old_uploads(self, max_age_hours: int = 24) -> int:
|
|
151
167
|
"""Clean up old upload cache files."""
|
|
152
168
|
total_freed = 0
|
|
153
|
-
|
|
169
|
+
|
|
154
170
|
try:
|
|
155
171
|
from django.conf import settings
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
|
|
173
|
+
uploads_dir = Path(settings.BASE_DIR).parent / "storage" / "uploads"
|
|
174
|
+
|
|
158
175
|
if not uploads_dir.exists():
|
|
159
176
|
return 0
|
|
160
|
-
|
|
177
|
+
|
|
161
178
|
cutoff_time = datetime.now().timestamp() - (max_age_hours * 3600)
|
|
162
|
-
|
|
163
|
-
for file_path in uploads_dir.rglob(
|
|
179
|
+
|
|
180
|
+
for file_path in uploads_dir.rglob("*"):
|
|
164
181
|
if file_path.is_file():
|
|
165
182
|
try:
|
|
166
183
|
if file_path.stat().st_mtime < cutoff_time:
|
|
167
184
|
file_size = file_path.stat().st_size
|
|
168
185
|
file_path.unlink()
|
|
169
186
|
total_freed += file_size
|
|
170
|
-
|
|
187
|
+
|
|
171
188
|
except Exception as e:
|
|
172
189
|
logger.warning(f"Failed to clean upload file {file_path}: {e}")
|
|
173
|
-
|
|
190
|
+
|
|
174
191
|
except Exception as e:
|
|
175
192
|
logger.error(f"Upload cleanup failed: {e}")
|
|
176
|
-
|
|
193
|
+
|
|
177
194
|
return total_freed
|
|
178
|
-
|
|
195
|
+
|
|
179
196
|
def _cleanup_large_logs(self, max_size_mb: int = 50) -> int:
|
|
180
197
|
"""Clean up large log files by truncating them."""
|
|
181
198
|
total_freed = 0
|
|
182
|
-
|
|
199
|
+
|
|
183
200
|
try:
|
|
184
201
|
from django.conf import settings
|
|
202
|
+
|
|
185
203
|
project_root = Path(settings.BASE_DIR).parent
|
|
186
204
|
max_size_bytes = max_size_mb * 1024 * 1024
|
|
187
|
-
|
|
188
|
-
for log_file in project_root.rglob(
|
|
205
|
+
|
|
206
|
+
for log_file in project_root.rglob("*.log"):
|
|
189
207
|
try:
|
|
190
208
|
if log_file.stat().st_size > max_size_bytes:
|
|
191
209
|
original_size = log_file.stat().st_size
|
|
192
|
-
|
|
210
|
+
|
|
193
211
|
# Truncate the log file
|
|
194
|
-
with open(log_file,
|
|
195
|
-
f.write(
|
|
196
|
-
|
|
212
|
+
with open(log_file, "w") as f:
|
|
213
|
+
f.write(
|
|
214
|
+
f"# Log truncated at {datetime.now()} due to size limit\n"
|
|
215
|
+
)
|
|
216
|
+
|
|
197
217
|
total_freed += original_size
|
|
198
|
-
logger.info(
|
|
199
|
-
|
|
218
|
+
logger.info(
|
|
219
|
+
f"Truncated log {log_file}: {original_size / (1024**2):.1f}MB"
|
|
220
|
+
)
|
|
221
|
+
|
|
200
222
|
except Exception as e:
|
|
201
223
|
logger.warning(f"Failed to truncate log {log_file}: {e}")
|
|
202
|
-
|
|
224
|
+
|
|
203
225
|
except Exception as e:
|
|
204
226
|
logger.error(f"Log cleanup failed: {e}")
|
|
205
|
-
|
|
227
|
+
|
|
206
228
|
return total_freed
|
|
207
|
-
|
|
229
|
+
|
|
208
230
|
def _cleanup_temp_files(self) -> int:
|
|
209
231
|
"""Clean up temporary files."""
|
|
210
232
|
total_freed = 0
|
|
211
|
-
|
|
233
|
+
|
|
212
234
|
try:
|
|
213
235
|
temp_patterns = [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
236
|
+
"/tmp/tmp*",
|
|
237
|
+
"/tmp/temp*",
|
|
238
|
+
"/tmp/django*",
|
|
239
|
+
"/tmp/ffmpeg*",
|
|
218
240
|
]
|
|
219
|
-
|
|
241
|
+
|
|
220
242
|
for pattern in temp_patterns:
|
|
221
243
|
import glob
|
|
244
|
+
|
|
222
245
|
for temp_file in glob.glob(pattern):
|
|
223
246
|
try:
|
|
224
247
|
temp_path = Path(temp_file)
|
|
@@ -226,119 +249,122 @@ class StorageAwareVideoProcessor:
|
|
|
226
249
|
file_size = temp_path.stat().st_size
|
|
227
250
|
temp_path.unlink()
|
|
228
251
|
total_freed += file_size
|
|
229
|
-
|
|
252
|
+
|
|
230
253
|
except Exception as e:
|
|
231
254
|
logger.warning(f"Failed to clean temp file {temp_file}: {e}")
|
|
232
|
-
|
|
255
|
+
|
|
233
256
|
except Exception as e:
|
|
234
257
|
logger.error(f"Temp file cleanup failed: {e}")
|
|
235
|
-
|
|
258
|
+
|
|
236
259
|
return total_freed
|
|
237
|
-
|
|
260
|
+
|
|
238
261
|
def process_video_with_storage_management(
|
|
239
|
-
self,
|
|
240
|
-
video_file: VideoFile,
|
|
262
|
+
self,
|
|
263
|
+
video_file: VideoFile,
|
|
241
264
|
cleanup_frames_after: bool = True,
|
|
242
|
-
progress_callback: Optional[callable] = None
|
|
265
|
+
progress_callback: Optional[callable] = None,
|
|
243
266
|
) -> bool:
|
|
244
267
|
"""
|
|
245
268
|
Process a video with automatic storage management.
|
|
246
|
-
|
|
269
|
+
|
|
247
270
|
Args:
|
|
248
271
|
video_file: VideoFile instance to process
|
|
249
272
|
cleanup_frames_after: Whether to clean up frames after processing
|
|
250
273
|
progress_callback: Optional progress callback function
|
|
251
|
-
|
|
274
|
+
|
|
252
275
|
Returns:
|
|
253
276
|
True if processing succeeded, False otherwise
|
|
254
277
|
"""
|
|
255
278
|
try:
|
|
256
279
|
# Estimate required space (rough calculation)
|
|
257
280
|
video_size = 0
|
|
258
|
-
if video_file.raw_file and hasattr(video_file.raw_file,
|
|
281
|
+
if video_file.raw_file and hasattr(video_file.raw_file, "size"):
|
|
259
282
|
video_size = video_file.raw_file.size
|
|
260
|
-
|
|
283
|
+
|
|
261
284
|
# Estimate: frames ~= 3x video size, processing ~= 2x video size
|
|
262
285
|
estimated_space_needed = video_size * 5
|
|
263
|
-
|
|
286
|
+
|
|
264
287
|
# Check storage before starting
|
|
265
288
|
self.check_and_ensure_storage(estimated_space_needed)
|
|
266
|
-
|
|
289
|
+
|
|
267
290
|
# Update task status
|
|
268
291
|
task = self._get_or_create_task(video_file)
|
|
269
292
|
task.start_processing()
|
|
270
|
-
|
|
293
|
+
|
|
271
294
|
if progress_callback:
|
|
272
295
|
progress_callback(10, "Starting video processing...")
|
|
273
|
-
|
|
296
|
+
|
|
274
297
|
# Run the actual video processing pipeline
|
|
275
298
|
success = video_file.pipe_1(
|
|
276
299
|
model_name="image_multilabel_classification_colonoscopy_default",
|
|
277
|
-
delete_frames_after=cleanup_frames_after
|
|
300
|
+
delete_frames_after=cleanup_frames_after,
|
|
278
301
|
)
|
|
279
|
-
|
|
302
|
+
|
|
280
303
|
if success:
|
|
281
304
|
if progress_callback:
|
|
282
305
|
progress_callback(90, "Processing completed, cleaning up...")
|
|
283
|
-
|
|
306
|
+
|
|
284
307
|
# Mark as completed
|
|
285
308
|
task.mark_completed("Video processing completed successfully")
|
|
286
|
-
|
|
309
|
+
|
|
287
310
|
# Additional cleanup if requested
|
|
288
311
|
if cleanup_frames_after:
|
|
289
312
|
self._cleanup_video_frames(video_file)
|
|
290
|
-
|
|
313
|
+
|
|
291
314
|
if progress_callback:
|
|
292
315
|
progress_callback(100, "Processing completed successfully")
|
|
293
|
-
|
|
294
|
-
logger.info(
|
|
316
|
+
|
|
317
|
+
logger.info(
|
|
318
|
+
f"Video processing completed successfully: {video_file.uuid}"
|
|
319
|
+
)
|
|
295
320
|
return True
|
|
296
321
|
|
|
297
322
|
task.mark_failed("Video processing pipeline failed")
|
|
298
323
|
logger.error(f"Video processing failed: {video_file.uuid}")
|
|
299
324
|
return False
|
|
300
|
-
|
|
325
|
+
|
|
301
326
|
except InsufficientStorageError as e:
|
|
302
327
|
logger.error(f"Storage error during video processing: {e}")
|
|
303
328
|
task = self._get_or_create_task(video_file)
|
|
304
329
|
task.mark_failed(f"Insufficient storage: {e}")
|
|
305
330
|
return False
|
|
306
|
-
|
|
331
|
+
|
|
307
332
|
except Exception as e:
|
|
308
333
|
logger.error(f"Video processing failed: {e}")
|
|
309
334
|
task = self._get_or_create_task(video_file)
|
|
310
335
|
task.mark_failed(f"Processing error: {e}")
|
|
311
336
|
return False
|
|
312
|
-
|
|
337
|
+
|
|
313
338
|
def _get_or_create_task(self, video_file: VideoFile) -> AnonymizationTask:
|
|
314
339
|
"""Get or create an anonymization task for the video."""
|
|
315
340
|
task, created = AnonymizationTask.objects.get_or_create(
|
|
316
341
|
video_file=video_file,
|
|
317
342
|
defaults={
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
343
|
+
"status": "not_started",
|
|
344
|
+
"progress": 0,
|
|
345
|
+
"message": "Initializing...",
|
|
346
|
+
},
|
|
322
347
|
)
|
|
323
348
|
return task
|
|
324
|
-
|
|
349
|
+
|
|
325
350
|
def _cleanup_video_frames(self, video_file: VideoFile):
|
|
326
351
|
"""Clean up frames for a specific video."""
|
|
327
352
|
try:
|
|
328
353
|
from django.conf import settings
|
|
329
|
-
|
|
330
|
-
|
|
354
|
+
|
|
355
|
+
frames_dir = Path(settings.BASE_DIR).parent / "storage" / "frames"
|
|
356
|
+
|
|
331
357
|
# Find frame directories for this video
|
|
332
358
|
video_frame_dirs = list(frames_dir.glob(f"*{video_file.uuid}*"))
|
|
333
|
-
|
|
359
|
+
|
|
334
360
|
for frame_dir in video_frame_dirs:
|
|
335
361
|
if frame_dir.is_dir():
|
|
336
362
|
shutil.rmtree(frame_dir, ignore_errors=True)
|
|
337
363
|
logger.info(f"Cleaned up frames for video {video_file.uuid}")
|
|
338
|
-
|
|
364
|
+
|
|
339
365
|
except Exception as e:
|
|
340
366
|
logger.warning(f"Failed to clean up frames for {video_file.uuid}: {e}")
|
|
341
367
|
|
|
342
368
|
|
|
343
369
|
# Global instance for easy access
|
|
344
|
-
storage_aware_processor = StorageAwareVideoProcessor()
|
|
370
|
+
storage_aware_processor = StorageAwareVideoProcessor()
|