endoreg-db 0.3.6__py3-none-any.whl → 0.8.6.1__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 +92 -3
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +18 -6
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +92 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +144 -65
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/{label → ai_model_label}/label/data.yaml +88 -62
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/{label → ai_model_label}/label-type/data.yaml +6 -6
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/{model_type → ai_model_type}/data.yaml +6 -6
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -167
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +7 -7
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +8 -8
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +22 -22
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +18 -18
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +18 -18
- endoreg_db/data/case_template/rule/19_create_patient.yaml +16 -16
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -35
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +58 -58
- endoreg_db/data/case_template/template/base.yaml +7 -7
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +2 -2
- endoreg_db/data/case_template/tmp/_rule_value +13 -13
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -21
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +9 -9
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +6 -6
- endoreg_db/data/center/data.yaml +90 -59
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -144
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -48
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -37
- endoreg_db/data/disease/hepatology.yaml +4 -4
- endoreg_db/data/disease/misc.yaml +5 -6
- endoreg_db/data/disease/renal.yaml +4 -4
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -6
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +5 -5
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -41
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +19 -19
- endoreg_db/data/distribution/date/patient.yaml +6 -6
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +6 -6
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -132
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +10 -10
- endoreg_db/data/endoscopy_processor/data.yaml +50 -45
- endoreg_db/data/event/cardiology.yaml +15 -28
- endoreg_db/data/event/neurology.yaml +13 -13
- endoreg_db/data/event/surgery.yaml +12 -12
- endoreg_db/data/event/thrombembolism.yaml +19 -19
- endoreg_db/data/examination/examinations/data.yaml +72 -66
- endoreg_db/data/examination/time/data.yaml +47 -47
- endoreg_db/data/examination/time-type/data.yaml +7 -7
- endoreg_db/data/examination/type/data.yaml +17 -5
- endoreg_db/data/examination_indication/endoscopy.yaml +424 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +160 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- endoreg_db/data/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/finding/complication.yaml +16 -0
- endoreg_db/data/finding/data.yaml +105 -0
- endoreg_db/data/finding/examination_setting.yaml +16 -0
- endoreg_db/data/finding/medication_related.yaml +18 -0
- endoreg_db/data/finding/outcome.yaml +12 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +43 -0
- endoreg_db/data/gender/data.yaml +42 -18
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -30
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +5 -5
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +37 -31
- endoreg_db/data/lab_value/coagulation.yaml +54 -49
- endoreg_db/data/lab_value/electrolytes.yaml +228 -190
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -121
- endoreg_db/data/lab_value/hematology.yaml +184 -169
- endoreg_db/data/lab_value/hormones.yaml +59 -53
- endoreg_db/data/lab_value/lipids.yaml +53 -44
- endoreg_db/data/lab_value/misc.yaml +76 -30
- endoreg_db/data/lab_value/renal_function.yaml +12 -11
- endoreg_db/data/log_type/data.yaml +57 -0
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/medication/anticoagulation.yaml +64 -64
- endoreg_db/data/medication/tah.yaml +69 -69
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -120
- endoreg_db/data/medication_indication_type/data.yaml +10 -10
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +40 -40
- endoreg_db/data/medication_intake_time/base.yaml +30 -30
- endoreg_db/data/medication_schedule/apixaban.yaml +94 -94
- endoreg_db/data/medication_schedule/ass.yaml +12 -12
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -26
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +59 -0
- endoreg_db/data/network_device_type/data.yaml +12 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/patient_lab_sample_type/generic.yaml +5 -5
- endoreg_db/data/pdf_type/data.yaml +46 -28
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -66
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -33
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -308
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -88
- endoreg_db/data/profession/data.yaml +70 -70
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -55
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -26
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -19
- endoreg_db/data/requirement/age.yaml +26 -0
- endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/gender.yaml +25 -0
- endoreg_db/data/requirement/lab_value.yaml +441 -0
- endoreg_db/data/requirement/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/age.yaml +13 -0
- endoreg_db/data/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +52 -0
- endoreg_db/data/requirement_set_type/data.yaml +20 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -15
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift/m2.yaml +0 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -12
- endoreg_db/data/unit/concentration.yaml +115 -92
- endoreg_db/data/unit/data.yaml +17 -17
- endoreg_db/data/unit/length.yaml +30 -30
- endoreg_db/data/unit/misc.yaml +19 -19
- endoreg_db/data/unit/rate.yaml +5 -5
- endoreg_db/data/unit/time.yaml +48 -13
- endoreg_db/data/unit/volume.yaml +35 -35
- endoreg_db/data/unit/weight.yaml +37 -37
- endoreg_db/data/waste/data.yaml +11 -11
- endoreg_db/exceptions.py +19 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +5 -3
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +18 -0
- endoreg_db/forms/patient_form.py +27 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -23
- endoreg_db/forms/settings/__init__.py +8 -8
- endoreg_db/forms/unit.py +5 -5
- endoreg_db/helpers/__init__.py +0 -0
- endoreg_db/helpers/count_db.py +45 -0
- endoreg_db/helpers/data_loader.py +208 -0
- endoreg_db/helpers/default_objects.py +378 -0
- endoreg_db/helpers/download_segmentation_model.py +31 -0
- endoreg_db/helpers/interact.py +6 -0
- endoreg_db/helpers/test_video_helper.py +119 -0
- endoreg_db/logger_conf.py +140 -0
- endoreg_db/management/__init__.py +1 -0
- endoreg_db/management/commands/__init__.py +1 -0
- endoreg_db/management/commands/anonymize_video.py +0 -0
- endoreg_db/management/commands/check_auth.py +125 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +115 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
- endoreg_db/management/commands/fix_video_paths.py +165 -0
- endoreg_db/management/commands/import_fallback_video.py +203 -0
- endoreg_db/management/commands/import_report.py +298 -0
- endoreg_db/management/commands/import_video.py +423 -0
- endoreg_db/management/commands/import_video_with_classification.py +367 -0
- endoreg_db/management/commands/init_default_ai_model.py +112 -0
- endoreg_db/management/commands/load_ai_model_data.py +77 -45
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +192 -128
- endoreg_db/management/commands/load_center_data.py +68 -43
- endoreg_db/management/commands/{load_medication_intake_time_data.py → load_contraindication_data.py} +40 -40
- endoreg_db/management/commands/load_disease_classification_choices_data.py +40 -40
- endoreg_db/management/commands/load_disease_classification_data.py +40 -40
- endoreg_db/management/commands/load_disease_data.py +61 -39
- endoreg_db/management/commands/load_distribution_data.py +65 -65
- endoreg_db/management/commands/{load_endoscope_type_data.py → load_endoscope_data.py} +67 -44
- endoreg_db/management/commands/load_event_data.py +40 -40
- endoreg_db/management/commands/load_examination_data.py +74 -74
- endoreg_db/management/commands/load_examination_indication_data.py +86 -0
- endoreg_db/management/commands/load_finding_data.py +128 -0
- endoreg_db/management/commands/load_gender_data.py +43 -43
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +131 -132
- endoreg_db/management/commands/load_information_source.py +50 -44
- endoreg_db/management/commands/load_lab_value_data.py +49 -49
- endoreg_db/management/commands/load_medication_data.py +103 -41
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/{load_medication_indication_type_data.py → load_organ_data.py} +42 -40
- endoreg_db/management/commands/load_pdf_type_data.py +60 -60
- endoreg_db/management/commands/load_profession_data.py +43 -43
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +45 -45
- endoreg_db/management/commands/load_requirement_data.py +180 -0
- endoreg_db/management/commands/load_risk_data.py +56 -0
- endoreg_db/management/commands/load_shift_data.py +60 -0
- endoreg_db/management/commands/load_tag_data.py +57 -0
- endoreg_db/management/commands/load_unit_data.py +45 -45
- endoreg_db/management/commands/load_user_groups.py +28 -28
- endoreg_db/management/commands/register_ai_model.py +64 -65
- endoreg_db/management/commands/reset_celery_schedule.py +9 -9
- endoreg_db/management/commands/setup_endoreg_db.py +381 -0
- endoreg_db/management/commands/start_filewatcher.py +106 -0
- endoreg_db/management/commands/storage_management.py +548 -0
- endoreg_db/management/commands/summarize_db_content.py +189 -0
- endoreg_db/management/commands/validate_video.py +204 -0
- endoreg_db/management/commands/validate_video_files.py +161 -0
- endoreg_db/management/commands/video_validation.py +22 -0
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/migrations/0001_initial.py +1857 -582
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/models/__init__.py +359 -74
- endoreg_db/models/administration/__init__.py +116 -0
- endoreg_db/models/administration/ai/__init__.py +9 -0
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +156 -0
- endoreg_db/models/{ai_model → administration/ai}/model_type.py +41 -26
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +15 -6
- endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +125 -81
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +269 -276
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +86 -73
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +26 -28
- endoreg_db/models/{center → administration/center}/__init__.py +13 -4
- endoreg_db/models/administration/center/center.py +67 -0
- endoreg_db/models/administration/center/center_product.py +64 -0
- endoreg_db/models/administration/center/center_resource.py +49 -0
- endoreg_db/models/administration/center/center_shift.py +88 -0
- endoreg_db/models/administration/center/center_waste.py +30 -0
- endoreg_db/models/administration/permissions/__init__.py +44 -0
- endoreg_db/models/administration/person/__init__.py +24 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +35 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
- endoreg_db/models/administration/person/employee/employee_type.py +42 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +54 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/{persons → administration/person/names}/first_name.py +18 -18
- endoreg_db/models/{persons → administration/person/names}/last_name.py +18 -19
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/{persons → administration/person}/person.py +31 -31
- endoreg_db/models/administration/person/profession/__init__.py +24 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
- endoreg_db/models/administration/product/__init__.py +14 -0
- endoreg_db/models/administration/product/product.py +97 -0
- endoreg_db/models/administration/product/product_group.py +39 -0
- endoreg_db/models/administration/product/product_material.py +54 -0
- endoreg_db/models/{product → administration/product}/product_weight.py +47 -26
- endoreg_db/models/{product → administration/product}/reference_product.py +130 -99
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +37 -0
- endoreg_db/models/administration/qualification/qualification_type.py +35 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +69 -0
- endoreg_db/models/administration/shift/shift.py +51 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/label/__init__.py +24 -1
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +84 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
- endoreg_db/models/label/label.py +83 -84
- endoreg_db/models/label/label_set.py +53 -0
- endoreg_db/models/label/label_type.py +29 -0
- endoreg_db/models/label/label_video_segment/__init__.py +3 -0
- endoreg_db/models/label/label_video_segment/_create_from_video.py +41 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
- endoreg_db/models/label/video_segmentation_label.py +31 -0
- endoreg_db/models/label/video_segmentation_labelset.py +27 -0
- endoreg_db/models/media/__init__.py +16 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +111 -0
- endoreg_db/models/media/pdf/__init__.py +11 -0
- endoreg_db/models/media/pdf/raw_pdf.py +757 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
- endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +19 -19
- endoreg_db/models/media/video/__init__.py +8 -0
- endoreg_db/models/media/video/create_from_file.py +358 -0
- endoreg_db/models/media/video/pipe_1.py +213 -0
- endoreg_db/models/media/video/pipe_2.py +105 -0
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file.py +825 -0
- endoreg_db/models/media/video/video_file_ai.py +443 -0
- endoreg_db/models/media/video/video_file_anonymize.py +349 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -0
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +104 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +141 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/media/video/video_file_io.py +168 -0
- endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +45 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
- endoreg_db/models/media/video/video_file_segments.py +209 -0
- endoreg_db/models/media/video/video_metadata.py +65 -0
- endoreg_db/models/media/video/video_processing.py +152 -0
- endoreg_db/models/medical/__init__.py +146 -0
- endoreg_db/models/medical/contraindication/__init__.py +17 -0
- endoreg_db/models/medical/disease.py +156 -0
- endoreg_db/models/medical/event.py +137 -0
- endoreg_db/models/medical/examination/__init__.py +9 -0
- endoreg_db/models/medical/examination/examination.py +148 -0
- endoreg_db/models/medical/examination/examination_indication.py +278 -0
- endoreg_db/models/medical/examination/examination_time.py +49 -0
- endoreg_db/models/medical/examination/examination_time_type.py +41 -0
- endoreg_db/models/medical/examination/examination_type.py +48 -0
- endoreg_db/models/medical/finding/__init__.py +18 -0
- endoreg_db/models/medical/finding/finding.py +96 -0
- endoreg_db/models/medical/finding/finding_classification.py +142 -0
- endoreg_db/models/medical/finding/finding_intervention.py +52 -0
- endoreg_db/models/medical/finding/finding_type.py +35 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +65 -0
- endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +182 -143
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +419 -0
- endoreg_db/models/medical/medication/__init__.py +19 -0
- endoreg_db/models/medical/medication/medication.py +31 -0
- endoreg_db/models/medical/medication/medication_indication.py +50 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +39 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +44 -0
- endoreg_db/models/medical/medication/medication_schedule.py +45 -0
- endoreg_db/models/medical/organ/__init__.py +35 -0
- endoreg_db/models/medical/patient/__init__.py +56 -0
- endoreg_db/models/medical/patient/medication_examples.py +38 -0
- endoreg_db/models/medical/patient/patient_disease.py +63 -0
- endoreg_db/models/medical/patient/patient_event.py +75 -0
- endoreg_db/models/medical/patient/patient_examination.py +249 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +44 -0
- endoreg_db/models/medical/patient/patient_finding.py +357 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +40 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
- endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +222 -176
- endoreg_db/models/medical/patient/patient_medication.py +104 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +72 -0
- endoreg_db/models/medical/risk/risk_type.py +51 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/metadata/model_meta.py +206 -0
- endoreg_db/models/metadata/model_meta_logic.py +343 -0
- endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +89 -70
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1048 -0
- endoreg_db/models/metadata/video_meta.py +332 -0
- endoreg_db/models/metadata/video_prediction_logic.py +190 -0
- endoreg_db/models/metadata/video_prediction_meta.py +270 -0
- endoreg_db/models/other/__init__.py +40 -5
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +125 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +94 -0
- endoreg_db/models/{persons → other}/gender.py +27 -22
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +28 -16
- endoreg_db/models/other/resource.py +21 -17
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +33 -21
- endoreg_db/models/{unit.py → other/unit.py} +32 -22
- endoreg_db/models/other/waste.py +27 -20
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +767 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +95 -0
- endoreg_db/models/requirement/requirement_operator.py +176 -0
- endoreg_db/models/requirement/requirement_set.py +287 -0
- endoreg_db/models/rule/__init__.py +13 -0
- endoreg_db/models/{rules → rule}/rule.py +27 -24
- endoreg_db/models/{rules → rule}/rule_applicator.py +224 -224
- endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +16 -18
- endoreg_db/models/{rules → rule}/rule_type.py +19 -21
- endoreg_db/models/{rules → rule}/ruleset.py +17 -19
- endoreg_db/models/state/__init__.py +12 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/audit_ledger.py +150 -0
- endoreg_db/models/state/label_video_segment.py +22 -0
- endoreg_db/models/state/raw_pdf.py +187 -0
- endoreg_db/models/state/sensitive_meta.py +46 -0
- endoreg_db/models/state/video.py +232 -0
- endoreg_db/models/upload_job.py +99 -0
- endoreg_db/models/utils.py +135 -0
- endoreg_db/queries/__init__.py +4 -4
- endoreg_db/queries/annotations/__init__.py +2 -2
- endoreg_db/queries/annotations/legacy.py +158 -159
- endoreg_db/renames.yml +8 -0
- endoreg_db/root_urls.py +9 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +27 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
- endoreg_db/serializers/__init__.py +118 -10
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +223 -0
- endoreg_db/serializers/_old/raw_video_meta_validation.py +179 -0
- endoreg_db/serializers/_old/video.py +71 -0
- endoreg_db/serializers/administration/__init__.py +14 -0
- endoreg_db/serializers/administration/ai/__init__.py +10 -0
- endoreg_db/serializers/administration/ai/active_model.py +10 -0
- endoreg_db/serializers/administration/ai/ai_model.py +18 -0
- endoreg_db/serializers/administration/ai/model_type.py +10 -0
- endoreg_db/serializers/administration/center.py +9 -0
- endoreg_db/serializers/administration/gender.py +9 -0
- endoreg_db/serializers/anonymization.py +69 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +46 -0
- endoreg_db/serializers/examination/dropdown.py +21 -0
- endoreg_db/serializers/examination_serializer.py +12 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +54 -0
- endoreg_db/serializers/finding_classification/__init__.py +7 -0
- endoreg_db/serializers/finding_classification/choice.py +19 -0
- endoreg_db/serializers/finding_classification/classification.py +13 -0
- endoreg_db/serializers/label/__init__.py +7 -0
- endoreg_db/serializers/label/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/__init__.py +7 -0
- endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
- endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
- endoreg_db/serializers/meta/__init__.py +19 -0
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
- endoreg_db/serializers/meta/report_meta.py +53 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -0
- endoreg_db/serializers/meta/video_meta.py +39 -0
- endoreg_db/serializers/misc/__init__.py +14 -0
- endoreg_db/serializers/misc/file_overview.py +182 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +120 -0
- endoreg_db/serializers/misc/stats.py +33 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +71 -0
- endoreg_db/serializers/patient/__init__.py +11 -0
- endoreg_db/serializers/patient/patient.py +86 -0
- endoreg_db/serializers/patient/patient_dropdown.py +27 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
- endoreg_db/serializers/pdf/__init__.py +5 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
- endoreg_db/serializers/report/__init__.py +9 -0
- endoreg_db/serializers/report/mixins.py +45 -0
- endoreg_db/serializers/report/report.py +105 -0
- endoreg_db/serializers/report/report_list.py +22 -0
- endoreg_db/serializers/report/secure_file_url.py +26 -0
- endoreg_db/serializers/requirements/requirement_schema.py +25 -0
- endoreg_db/serializers/requirements/requirement_sets.py +29 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/segmentation.py +263 -0
- endoreg_db/serializers/video/video_file_brief.py +10 -0
- endoreg_db/serializers/video/video_file_detail.py +83 -0
- endoreg_db/serializers/video/video_file_list.py +67 -0
- endoreg_db/serializers/video/video_metadata.py +105 -0
- endoreg_db/serializers/video/video_processing_history.py +153 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +223 -0
- endoreg_db/services/examination_evaluation.py +149 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +411 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/pdf_import.py +1382 -0
- endoreg_db/services/polling_coordinator.py +288 -0
- endoreg_db/services/pseudonym_service.py +89 -0
- endoreg_db/services/requirements_object.py +147 -0
- endoreg_db/services/segment_sync.py +155 -0
- endoreg_db/services/storage_aware_video_processor.py +344 -0
- endoreg_db/services/video_import.py +1259 -0
- endoreg_db/tasks/upload_tasks.py +207 -0
- endoreg_db/tasks/video_ingest.py +157 -0
- endoreg_db/tasks/video_processing_tasks.py +327 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls/__init__.py +83 -0
- endoreg_db/urls/anonymization.py +32 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +39 -0
- endoreg_db/urls/examination.py +54 -0
- endoreg_db/urls/files.py +6 -0
- endoreg_db/urls/label_video_segment_validate.py +33 -0
- endoreg_db/urls/label_video_segments.py +46 -0
- endoreg_db/urls/media.py +227 -0
- endoreg_db/urls/patient.py +19 -0
- endoreg_db/urls/report.py +48 -0
- endoreg_db/urls/requirements.py +13 -0
- endoreg_db/urls/sensitive_meta.py +0 -0
- endoreg_db/urls/stats.py +46 -0
- endoreg_db/urls/upload.py +20 -0
- endoreg_db/urls/video.py +61 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +88 -1
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +5 -8
- endoreg_db/utils/ai/inference_dataset.py +52 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +159 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +291 -0
- endoreg_db/utils/ai/preprocess.py +68 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +0 -0
- endoreg_db/utils/case_generator/case_generator.py +159 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/utils/case_generator/utils.py +30 -0
- endoreg_db/utils/check_video_files.py +148 -0
- endoreg_db/utils/cropping.py +28 -28
- endoreg_db/utils/dataloader.py +175 -92
- endoreg_db/utils/dates.py +60 -0
- endoreg_db/utils/env.py +33 -0
- endoreg_db/utils/extract_specific_frames.py +72 -0
- endoreg_db/utils/file_operations.py +58 -30
- endoreg_db/utils/fix_video_path_direct.py +141 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +153 -34
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +193 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +76 -0
- endoreg_db/utils/ocr.py +190 -197
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/paths.py +95 -0
- endoreg_db/utils/permissions.py +143 -0
- endoreg_db/utils/pipelines/Readme.md +235 -0
- endoreg_db/utils/pipelines/__init__.py +0 -0
- endoreg_db/utils/pipelines/process_video_dir.py +120 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +20 -0
- endoreg_db/utils/product/sum_weights.py +18 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/requirement_helpers.py +0 -0
- endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
- endoreg_db/utils/requirement_operator_logic/lab_value_operators.py +578 -0
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
- endoreg_db/utils/setup_config.py +177 -0
- endoreg_db/utils/translation.py +27 -0
- endoreg_db/utils/uuid.py +4 -4
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/validate_video_detailed.py +357 -0
- endoreg_db/utils/video/__init__.py +26 -0
- endoreg_db/utils/video/extract_frames.py +88 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +835 -0
- endoreg_db/utils/video/names.py +42 -0
- endoreg_db/utils/video/streaming_processor.py +312 -0
- endoreg_db/utils/video/video_splitter.py +94 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
- endoreg_db/views/__init__.py +275 -0
- endoreg_db/views/anonymization/__init__.py +27 -0
- endoreg_db/views/anonymization/media_management.py +454 -0
- endoreg_db/views/anonymization/overview.py +216 -0
- endoreg_db/views/anonymization/validate.py +107 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +113 -0
- endoreg_db/views/examination/__init__.py +33 -0
- endoreg_db/views/examination/examination.py +37 -0
- endoreg_db/views/examination/examination_manifest_cache.py +26 -0
- endoreg_db/views/examination/get_finding_classification_choices.py +59 -0
- endoreg_db/views/examination/get_finding_classifications.py +36 -0
- endoreg_db/views/examination/get_findings.py +41 -0
- endoreg_db/views/examination/get_instruments.py +18 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +112 -0
- endoreg_db/views/finding/get_classifications.py +14 -0
- endoreg_db/views/finding/get_interventions.py +17 -0
- endoreg_db/views/finding_classification/__init__.py +13 -0
- endoreg_db/views/finding_classification/base.py +0 -0
- endoreg_db/views/finding_classification/finding_classification.py +42 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
- endoreg_db/views/label/__init__.py +5 -0
- endoreg_db/views/label/label.py +15 -0
- endoreg_db/views/label_video_segment/__init__.py +16 -0
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
- endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
- endoreg_db/views/label_video_segment/validate.py +226 -0
- endoreg_db/views/media/__init__.py +45 -0
- endoreg_db/views/media/pdf_media.py +388 -0
- endoreg_db/views/media/segments.py +71 -0
- endoreg_db/views/media/sensitive_metadata.py +314 -0
- endoreg_db/views/media/video_media.py +272 -0
- endoreg_db/views/media/video_segments.py +524 -0
- endoreg_db/views/meta/__init__.py +15 -0
- endoreg_db/views/meta/available_files_list.py +146 -0
- endoreg_db/views/meta/report_meta.py +53 -0
- endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
- endoreg_db/views/meta/sensitive_meta_list.py +104 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
- endoreg_db/views/misc/__init__.py +63 -0
- endoreg_db/views/misc/center.py +13 -0
- endoreg_db/views/misc/csrf.py +7 -0
- endoreg_db/views/misc/gender.py +14 -0
- endoreg_db/views/misc/secure_file_serving_view.py +80 -0
- endoreg_db/views/misc/secure_file_url_view.py +84 -0
- endoreg_db/views/misc/secure_url_validate.py +79 -0
- endoreg_db/views/misc/stats.py +220 -0
- endoreg_db/views/misc/translation.py +182 -0
- endoreg_db/views/misc/upload_views.py +240 -0
- endoreg_db/views/patient/__init__.py +5 -0
- endoreg_db/views/patient/patient.py +210 -0
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +140 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
- endoreg_db/views/patient_examination/video.py +194 -0
- endoreg_db/views/patient_finding/__init__.py +7 -0
- endoreg_db/views/patient_finding/base.py +0 -0
- endoreg_db/views/patient_finding/patient_finding.py +64 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
- endoreg_db/views/patient_finding_location/__init__.py +5 -0
- endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
- endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
- endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
- endoreg_db/views/pdf/__init__.py +8 -0
- endoreg_db/views/pdf/pdf_stream.py +187 -0
- endoreg_db/views/pdf/reimport.py +177 -0
- endoreg_db/views/report/__init__.py +9 -0
- endoreg_db/views/report/report_list.py +112 -0
- endoreg_db/views/report/report_with_secure_url.py +28 -0
- endoreg_db/views/report/start_examination.py +7 -0
- endoreg_db/views/requirement/__init__.py +10 -0
- endoreg_db/views/requirement/evaluate.py +279 -0
- endoreg_db/views/requirement/lookup.py +367 -0
- endoreg_db/views/requirement/lookup_store.py +252 -0
- endoreg_db/views/requirement_lookup/lookup.py +0 -0
- endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
- endoreg_db/views/stats/__init__.py +13 -0
- endoreg_db/views/stats/stats_views.py +229 -0
- endoreg_db/views/video/__init__.py +59 -0
- endoreg_db/views/video/correction.py +530 -0
- endoreg_db/views/video/reimport.py +195 -0
- endoreg_db/views/video/segmentation.py +274 -0
- endoreg_db/views/video/task_status.py +49 -0
- endoreg_db/views/video/timeline.py +46 -0
- endoreg_db/views/video/video_analyze.py +52 -0
- endoreg_db/views/video/video_apply_mask.py +48 -0
- endoreg_db/views/video/video_correction.py +21 -0
- endoreg_db/views/video/video_download_processed.py +58 -0
- endoreg_db/views/video/video_examination_viewset.py +242 -0
- endoreg_db/views/video/video_meta.py +29 -0
- endoreg_db/views/video/video_processing_history.py +24 -0
- endoreg_db/views/video/video_remove_frames.py +48 -0
- endoreg_db/views/video/video_stream.py +306 -0
- endoreg_db/views.py +0 -3
- endoreg_db-0.8.6.1.dist-info/METADATA +383 -0
- endoreg_db-0.8.6.1.dist-info/RECORD +793 -0
- {endoreg_db-0.3.6.dist-info → endoreg_db-0.8.6.1.dist-info}/WHEEL +1 -1
- {endoreg_db-0.3.6.dist-info → endoreg_db-0.8.6.1.dist-info/licenses}/LICENSE +674 -674
- endoreg_db/data/active_model/data.yaml +0 -3
- endoreg_db/data/label/label-set/data.yaml +0 -18
- endoreg_db/management/commands/_load_model_template.py +0 -41
- endoreg_db/management/commands/delete_all.py +0 -18
- endoreg_db/management/commands/delete_legacy_images.py +0 -19
- endoreg_db/management/commands/delete_legacy_videos.py +0 -17
- endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
- endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
- endoreg_db/management/commands/fix_auth_permission.py +0 -20
- endoreg_db/management/commands/import_legacy_images.py +0 -94
- endoreg_db/management/commands/import_legacy_videos.py +0 -76
- endoreg_db/management/commands/load_active_model_data.py +0 -45
- endoreg_db/management/commands/load_endoscopy_processor_data.py +0 -45
- endoreg_db/management/commands/load_g_play_data.py +0 -113
- endoreg_db/management/commands/load_label_data.py +0 -67
- endoreg_db/management/commands/load_medication_indication_data.py +0 -63
- endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
- endoreg_db/migrations/0002_rawvideofile.py +0 -26
- endoreg_db/migrations/0003_rawvideofile_frames_required.py +0 -18
- endoreg_db/migrations/0004_rename_hash_rawvideofile_video_hash.py +0 -18
- endoreg_db/migrations/0005_ffmpegmeta_remove_videoimportmeta_center_and_more.py +0 -56
- endoreg_db/migrations/0006_rawvideofile_center_alter_videometa_processor.py +0 -25
- endoreg_db/migrations/0007_rawvideofile_processor.py +0 -19
- endoreg_db/migrations/0008_rename_frames_required_rawvideofile_state_frames_required.py +0 -18
- endoreg_db/migrations/0009_sensitivemeta_rawvideofile_sensitive_meta.py +0 -31
- endoreg_db/migrations/0010_rename_endoscope_serial_number_sensitivemeta_endoscope_sn.py +0 -18
- endoreg_db/migrations/0011_rawvideofile_state_sensitive_data_retrieved.py +0 -18
- endoreg_db/migrations/0012_rawvideofile_prediction_dir_and_more.py +0 -109
- endoreg_db/migrations/0013_rawpdffile.py +0 -31
- endoreg_db/migrations/0014_pdftype_alter_rawpdffile_file_pdfmeta.py +0 -38
- endoreg_db/migrations/0015_rename_report_processed_rawpdffile_state_report_processed_and_more.py +0 -31
- endoreg_db/migrations/0016_rawpdffile_state_report_processing_required.py +0 -18
- endoreg_db/migrations/0017_firstname_lastname_center_first_names_and_more.py +0 -37
- endoreg_db/migrations/0018_reportreaderflag_reportreaderconfig.py +0 -37
- endoreg_db/migrations/0019_pdftype_cut_off_above_lines_and_more.py +0 -42
- endoreg_db/migrations/0020_rename_endoscopy_info_line_pdftype_endoscope_info_line.py +0 -18
- endoreg_db/migrations/0021_alter_pdftype_endoscope_info_line.py +0 -19
- endoreg_db/migrations/0022_alter_pdftype_endoscope_info_line.py +0 -19
- endoreg_db/migrations/0023_ttoquestionnaire_alter_pdftype_endoscope_info_line.py +0 -59
- endoreg_db/migrations/0024_remove_ttoquestionnaire_infections_and_more.py +0 -27
- endoreg_db/migrations/0025_event_alter_rawpdffile_file_patientevent.py +0 -42
- endoreg_db/migrations/0026_disease_diseaseclassification_and_more.py +0 -166
- endoreg_db/migrations/0027_labvalue_abbreviation_labvalue_default_normal_range_and_more.py +0 -38
- endoreg_db/migrations/0028_alter_unit_abbreviation.py +0 -18
- endoreg_db/migrations/0029_medicationintaketime_and_more.py +0 -75
- endoreg_db/migrations/0030_medicationindicationtype_and_more.py +0 -101
- endoreg_db/migrations/0031_rename_adapt_to_liver_function_medication_adapt_to_age_and_more.py +0 -38
- endoreg_db/migrations/0032_alter_medicationschedule_therapy_duration_d.py +0 -18
- endoreg_db/migrations/0033_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0034_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0035_alter_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0036_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0037_alter_medicationindication_sources.py +0 -18
- endoreg_db/migrations/0038_emissionfactor_material_product_productgroup_and_more.py +0 -164
- endoreg_db/migrations/0039_referenceproduct_name.py +0 -19
- endoreg_db/migrations/0040_quizanswertype_quizquestiontype_quizquestion_and_more.py +0 -50
- endoreg_db/migrations/0041_gender_patientmedication_medication_indication_and_more.py +0 -40
- endoreg_db/migrations/0042_casetemplateruletype_casetemplaterulevalue_and_more.py +0 -74
- endoreg_db/migrations/0043_casetemplatetype_name_de_casetemplatetype_name_en.py +0 -23
- endoreg_db/migrations/0044_casetemplateruletype_name_de_and_more.py +0 -23
- endoreg_db/migrations/0045_casetemplaterulevalue_value_type.py +0 -19
- endoreg_db/migrations/0046_casetemplaterulevalue_target_field.py +0 -18
- endoreg_db/migrations/0047_casetemplaterule_target_model.py +0 -18
- endoreg_db/migrations/0048_remove_casetemplaterule_chained_rules_and_more.py +0 -22
- endoreg_db/migrations/0049_remove_casetemplaterule_rule_values.py +0 -17
- endoreg_db/migrations/0050_casetemplaterule_rule_values.py +0 -18
- endoreg_db/migrations/0051_remove_casetemplaterule_calling_rules_and_more.py +0 -27
- endoreg_db/migrations/0052_rename_case_template_type_casetemplate_template_type.py +0 -18
- endoreg_db/migrations/0053_patientlabsampletype_patientlabsample_and_more.py +0 -38
- endoreg_db/migrations/0054_multiplecategoricalvaluedistribution_and_more.py +0 -69
- endoreg_db/migrations/0055_remove_casetemplaterule_rule_values_and_more.py +0 -59
- endoreg_db/migrations/0056_datevaluedistribution_and_more.py +0 -32
- endoreg_db/migrations/0057_remove_datevaluedistribution_max_date_and_more.py +0 -72
- endoreg_db/migrations/0058_datevaluedistribution_description_and_more.py +0 -28
- endoreg_db/migrations/0059_casetemplaterule_rule_values.py +0 -18
- endoreg_db/migrations/0060_labvalue__default_date_value_distribution_and_more.py +0 -44
- endoreg_db/migrations/0061_remove_patientlabvalue_date_patientlabvalue_datetime.py +0 -24
- endoreg_db/migrations/0062_labvalue_numeric_precision.py +0 -18
- endoreg_db/migrations/0063_alter_labvalue_numeric_precision.py +0 -18
- endoreg_db/migrations/0064_casetemplaterule_extra_parameters_and_more.py +0 -23
- endoreg_db/migrations/0065_rename__date_value_distribution_casetemplaterule_date_value_distribution_and_more.py +0 -58
- endoreg_db/migrations/0066_alter_patientlabvalue_patient_and_more.py +0 -29
- endoreg_db/migrations/0067_alter_medicationindication_indication_type.py +0 -19
- endoreg_db/models/ai_model/__init__.py +0 -3
- endoreg_db/models/ai_model/active_model.py +0 -9
- endoreg_db/models/ai_model/model_meta.py +0 -24
- endoreg_db/models/annotation/__init__.py +0 -2
- endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -80
- endoreg_db/models/annotation/image_classification.py +0 -27
- endoreg_db/models/center/center.py +0 -25
- endoreg_db/models/center/center_product.py +0 -34
- endoreg_db/models/center/center_resource.py +0 -19
- endoreg_db/models/center/center_waste.py +0 -11
- endoreg_db/models/data_file/__init__.py +0 -6
- endoreg_db/models/data_file/base_classes/__init__.py +0 -2
- endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -51
- endoreg_db/models/data_file/base_classes/abstract_video.py +0 -201
- endoreg_db/models/data_file/frame.py +0 -45
- endoreg_db/models/data_file/import_classes/__init__.py +0 -32
- endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
- endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
- endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
- endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -188
- endoreg_db/models/data_file/import_classes/raw_video.py +0 -343
- endoreg_db/models/data_file/metadata/__init__.py +0 -3
- endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -31
- endoreg_db/models/data_file/metadata/video_meta.py +0 -133
- endoreg_db/models/data_file/report_file.py +0 -89
- endoreg_db/models/data_file/video/__init__.py +0 -7
- endoreg_db/models/data_file/video/import_meta.py +0 -25
- endoreg_db/models/data_file/video/video.py +0 -25
- endoreg_db/models/data_file/video_segment.py +0 -107
- endoreg_db/models/disease.py +0 -56
- endoreg_db/models/emission/__init__.py +0 -1
- endoreg_db/models/emission/emission_factor.py +0 -20
- endoreg_db/models/event.py +0 -22
- endoreg_db/models/examination/__init__.py +0 -4
- endoreg_db/models/examination/examination.py +0 -26
- endoreg_db/models/examination/examination_time.py +0 -27
- endoreg_db/models/examination/examination_time_type.py +0 -24
- endoreg_db/models/examination/examination_type.py +0 -18
- endoreg_db/models/hardware/__init__.py +0 -2
- endoreg_db/models/hardware/endoscope.py +0 -44
- endoreg_db/models/information_source.py +0 -29
- endoreg_db/models/laboratory/__init__.py +0 -1
- endoreg_db/models/laboratory/lab_value.py +0 -102
- endoreg_db/models/legacy_data/__init__.py +0 -3
- endoreg_db/models/legacy_data/image.py +0 -34
- endoreg_db/models/medication/__init__.py +0 -1
- endoreg_db/models/medication/medication.py +0 -148
- endoreg_db/models/other/distribution.py +0 -215
- endoreg_db/models/patient_examination/__init__.py +0 -35
- endoreg_db/models/permissions/__init__.py +0 -44
- endoreg_db/models/persons/__init__.py +0 -7
- endoreg_db/models/persons/examiner/__init__.py +0 -2
- endoreg_db/models/persons/examiner/examiner.py +0 -16
- endoreg_db/models/persons/examiner/examiner_type.py +0 -2
- endoreg_db/models/persons/patient/__init__.py +0 -8
- endoreg_db/models/persons/patient/case/case.py +0 -30
- endoreg_db/models/persons/patient/patient.py +0 -216
- endoreg_db/models/persons/patient/patient_disease.py +0 -16
- endoreg_db/models/persons/patient/patient_event.py +0 -22
- endoreg_db/models/persons/patient/patient_lab_sample.py +0 -106
- endoreg_db/models/persons/patient/patient_medication.py +0 -44
- endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -28
- endoreg_db/models/persons/portal_user_information.py +0 -27
- endoreg_db/models/prediction/__init__.py +0 -2
- endoreg_db/models/prediction/image_classification.py +0 -37
- endoreg_db/models/prediction/video_prediction_meta.py +0 -244
- endoreg_db/models/product/__init__.py +0 -5
- endoreg_db/models/product/product.py +0 -97
- endoreg_db/models/product/product_group.py +0 -19
- endoreg_db/models/product/product_material.py +0 -24
- endoreg_db/models/questionnaires/__init__.py +0 -114
- endoreg_db/models/quiz/__init__.py +0 -2
- endoreg_db/models/quiz/quiz_answer.py +0 -41
- endoreg_db/models/quiz/quiz_question.py +0 -54
- endoreg_db/models/report_reader/__init__.py +0 -2
- endoreg_db/models/report_reader/report_reader_config.py +0 -53
- endoreg_db/models/rules/__init__.py +0 -5
- endoreg_db/queries/get/__init__.py +0 -6
- endoreg_db/queries/get/center.py +0 -42
- endoreg_db/queries/get/model.py +0 -13
- endoreg_db/queries/get/patient.py +0 -14
- endoreg_db/queries/get/patient_examination.py +0 -20
- endoreg_db/queries/get/report_file.py +0 -33
- endoreg_db/queries/get/video.py +0 -31
- endoreg_db/serializers/ai_model.py +0 -19
- endoreg_db/serializers/annotation.py +0 -17
- endoreg_db/serializers/center.py +0 -11
- endoreg_db/serializers/examination.py +0 -33
- endoreg_db/serializers/frame.py +0 -13
- endoreg_db/serializers/hardware.py +0 -21
- endoreg_db/serializers/label.py +0 -22
- endoreg_db/serializers/patient.py +0 -10
- endoreg_db/serializers/prediction.py +0 -15
- endoreg_db/serializers/report_file.py +0 -7
- endoreg_db/serializers/video.py +0 -27
- endoreg_db/tests.py +0 -3
- endoreg_db/utils/legacy_ocr.py +0 -201
- endoreg_db/utils/video_metadata.py +0 -87
- endoreg_db-0.3.6.dist-info/METADATA +0 -33
- endoreg_db-0.3.6.dist-info/RECORD +0 -357
- /endoreg_db/{models/persons/patient/case/__init__.py → api/serializers/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/annotation.py → api/views/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/prediction.py → config/__init__.py} +0 -0
- /endoreg_db/{queries/get/video_import_meta.py → data/case_template/rule_value/.init} +0 -0
- /endoreg_db/{queries/get/video_prediction_meta.py → data/distribution/multiple_categorical/.init} +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from endoreg_db.models.media.video.video_file_io import _get_frame_dir_path
|
|
3
|
+
from endoreg_db.utils.video.ffmpeg_wrapper import extract_frames as ffmpeg_extract_frames
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from endoreg_db.models import VideoFile
|
|
8
|
+
|
|
9
|
+
from django.db import transaction
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import shutil
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
def _extract_frames(
|
|
16
|
+
video: "VideoFile",
|
|
17
|
+
quality: int = 2,
|
|
18
|
+
overwrite: bool = False,
|
|
19
|
+
ext="jpg",
|
|
20
|
+
verbose=False,
|
|
21
|
+
) -> bool:
|
|
22
|
+
"""
|
|
23
|
+
Extract frames from a raw video file, update frame extraction status in the database, and manage related file system operations.
|
|
24
|
+
|
|
25
|
+
This function checks for existing extracted frames and skips extraction if appropriate, unless overwriting is requested. It handles deletion of existing frames when overwriting, invokes ffmpeg to extract frames, parses extracted frame numbers, updates corresponding database records, and manages video extraction state. Robust error handling ensures cleanup and state rollback on failure.
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
video (VideoFile): The video object from which frames are to be extracted.
|
|
29
|
+
quality (int, optional): Quality parameter for ffmpeg extraction. Defaults to 2.
|
|
30
|
+
overwrite (bool, optional): Whether to overwrite existing extracted frames. Defaults to False.
|
|
31
|
+
ext (str, optional): File extension for extracted frames. Defaults to "jpg".
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
bool: True if extraction and updates succeed.
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
FileNotFoundError: If the raw video file is missing.
|
|
38
|
+
RuntimeError: If extraction or database update fails.
|
|
39
|
+
ValueError: If the frame directory path cannot be determined.
|
|
40
|
+
"""
|
|
41
|
+
from ._delete_frames import _delete_frames
|
|
42
|
+
from endoreg_db.models.media.frame import Frame
|
|
43
|
+
|
|
44
|
+
# Pre-validation checks (outside any transaction)
|
|
45
|
+
if not video.has_raw:
|
|
46
|
+
raise FileNotFoundError(f"Raw video file not available for {video.uuid}. Cannot extract frames.")
|
|
47
|
+
|
|
48
|
+
raw_file_path = video.get_raw_file_path()
|
|
49
|
+
if not raw_file_path or not raw_file_path.exists():
|
|
50
|
+
raise FileNotFoundError(f"Raw video file not found at {raw_file_path} for video {video.uuid}. Cannot extract frames.")
|
|
51
|
+
|
|
52
|
+
frame_dir = _get_frame_dir_path(video)
|
|
53
|
+
if not frame_dir:
|
|
54
|
+
raise ValueError(f"Cannot determine frame directory path for video {video.uuid}.")
|
|
55
|
+
|
|
56
|
+
state = video.get_or_create_state()
|
|
57
|
+
frames_exist_in_db = Frame.objects.filter(video=video).exists()
|
|
58
|
+
files_exist_on_disk = frame_dir.exists() and any(frame_dir.iterdir())
|
|
59
|
+
|
|
60
|
+
# Fast-path: if frames exist and we are not overwriting, update state and return.
|
|
61
|
+
if (state.frames_extracted or files_exist_on_disk) and not overwrite:
|
|
62
|
+
logger.info(
|
|
63
|
+
"Frames already extracted or files exist for video %s, and overwrite=False. Skipping extraction.",
|
|
64
|
+
video.uuid,
|
|
65
|
+
)
|
|
66
|
+
if state.frames_extracted and frames_exist_in_db:
|
|
67
|
+
with transaction.atomic():
|
|
68
|
+
updated_count = Frame.objects.filter(video=video, is_extracted=False).update(is_extracted=True)
|
|
69
|
+
if updated_count > 0:
|
|
70
|
+
logger.info(
|
|
71
|
+
"Marked %d existing Frame objects as extracted for video %s based on state.",
|
|
72
|
+
updated_count,
|
|
73
|
+
video.uuid,
|
|
74
|
+
)
|
|
75
|
+
elif not state.frames_extracted and files_exist_on_disk:
|
|
76
|
+
logger.warning(
|
|
77
|
+
"Files exist on disk for video %s but state.frames_extracted is False. Correcting state to match disk.",
|
|
78
|
+
video.uuid,
|
|
79
|
+
)
|
|
80
|
+
# Fix inconsistent state: files exist but state.frames_extracted is False
|
|
81
|
+
state.frames_extracted = True
|
|
82
|
+
state.save(update_fields=['frames_extracted'])
|
|
83
|
+
|
|
84
|
+
# Also update Frame objects to be consistent
|
|
85
|
+
with transaction.atomic():
|
|
86
|
+
updated_count = Frame.objects.filter(video=video, is_extracted=False).update(is_extracted=True)
|
|
87
|
+
if updated_count > 0:
|
|
88
|
+
logger.info(
|
|
89
|
+
"Marked %d existing Frame objects as extracted for video %s after state correction.",
|
|
90
|
+
updated_count,
|
|
91
|
+
video.uuid,
|
|
92
|
+
)
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
# Overwrite: delete existing frames/files before re-extraction.
|
|
96
|
+
if overwrite:
|
|
97
|
+
logger.info("Overwrite=True. Preparing to delete existing frames/files for video %s before extraction.", video.uuid)
|
|
98
|
+
try:
|
|
99
|
+
_delete_frames(video)
|
|
100
|
+
with transaction.atomic():
|
|
101
|
+
updated_count = Frame.objects.filter(video=video, is_extracted=True).update(is_extracted=False)
|
|
102
|
+
if updated_count > 0:
|
|
103
|
+
logger.info(
|
|
104
|
+
"Reset %d Frame objects to is_extracted=False for video %s due to overwrite.",
|
|
105
|
+
updated_count,
|
|
106
|
+
video.uuid,
|
|
107
|
+
)
|
|
108
|
+
state.refresh_from_db()
|
|
109
|
+
except Exception as del_e:
|
|
110
|
+
logger.error("Failed to delete existing frames for video %s during overwrite: %s", video.uuid, del_e, exc_info=True)
|
|
111
|
+
raise RuntimeError(f"Failed to delete existing frames for video {video.uuid} during overwrite.") from del_e
|
|
112
|
+
|
|
113
|
+
frame_dir.mkdir(parents=True, exist_ok=True)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
logger.info("Starting frame extraction for video %s to %s", video.uuid, frame_dir)
|
|
117
|
+
# Step 1: Perform the long-running frame extraction outside any transaction.
|
|
118
|
+
extracted_paths = ffmpeg_extract_frames(raw_file_path, frame_dir, quality=quality, ext=ext)
|
|
119
|
+
if not extracted_paths:
|
|
120
|
+
logger.warning(
|
|
121
|
+
"ffmpeg_extract_frames returned no paths for video %s. Check video duration and ffmpeg logs.",
|
|
122
|
+
video.uuid,
|
|
123
|
+
)
|
|
124
|
+
if video.frame_count is not None and video.frame_count > 0:
|
|
125
|
+
raise RuntimeError(
|
|
126
|
+
f"ffmpeg_extract_frames returned no paths for video {video.uuid}, but {video.frame_count} frames were expected."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
logger.info("Successfully extracted %d frames using ffmpeg for video %s.", len(extracted_paths), video.uuid)
|
|
130
|
+
|
|
131
|
+
extracted_frame_numbers = []
|
|
132
|
+
for frame_path in extracted_paths:
|
|
133
|
+
try:
|
|
134
|
+
frame_number = int(frame_path.stem.split('_')[-1])
|
|
135
|
+
extracted_frame_numbers.append(frame_number)
|
|
136
|
+
except (ValueError, IndexError) as e:
|
|
137
|
+
logger.warning("Could not parse frame number from extracted file %s: %s", frame_path.name, e)
|
|
138
|
+
|
|
139
|
+
# Step 2: Perform all the quick DB updates inside a minimal atomic transaction.
|
|
140
|
+
with transaction.atomic():
|
|
141
|
+
if extracted_frame_numbers:
|
|
142
|
+
try:
|
|
143
|
+
update_count = Frame.objects.filter(
|
|
144
|
+
video=video, frame_number__in=extracted_frame_numbers
|
|
145
|
+
).update(is_extracted=True)
|
|
146
|
+
logger.info("Marked %d Frame objects as is_extracted=True for video %s.", update_count, video.uuid)
|
|
147
|
+
if update_count != len(extracted_frame_numbers):
|
|
148
|
+
logger.warning(
|
|
149
|
+
"Number of updated frames (%d) does not match number of parsed extracted files (%d) for video %s.",
|
|
150
|
+
update_count,
|
|
151
|
+
len(extracted_frame_numbers),
|
|
152
|
+
video.uuid,
|
|
153
|
+
)
|
|
154
|
+
except Exception as update_e:
|
|
155
|
+
logger.error("Failed to update is_extracted flag for frames of video %s: %s", video.uuid, update_e, exc_info=True)
|
|
156
|
+
if extracted_paths:
|
|
157
|
+
state.refresh_from_db()
|
|
158
|
+
state.mark_frames_extracted()
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.error("Frame extraction or update failed for video %s: %s", video.uuid, e, exc_info=True)
|
|
163
|
+
logger.warning("Cleaning up frame directory %s for video %s due to extraction error.", frame_dir, video.uuid)
|
|
164
|
+
shutil.rmtree(frame_dir, ignore_errors=True)
|
|
165
|
+
try:
|
|
166
|
+
with transaction.atomic():
|
|
167
|
+
Frame.objects.filter(video=video, is_extracted=True).update(is_extracted=False)
|
|
168
|
+
state.refresh_from_db()
|
|
169
|
+
if state.frames_extracted:
|
|
170
|
+
state.frames_extracted = False
|
|
171
|
+
state.save(update_fields=["frames_extracted"])
|
|
172
|
+
except Exception as db_err:
|
|
173
|
+
logger.error("Failed to reset flags/state in DB during error handling for video %s: %s", video.uuid, db_err)
|
|
174
|
+
raise RuntimeError(f"Frame extraction or update failed for video {video.uuid}.") from e
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from endoreg_db.models import VideoFile, Frame
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_frame(video: "VideoFile", frame_number: int) -> "Frame":
|
|
14
|
+
"""Gets a specific Frame object by its frame number."""
|
|
15
|
+
from endoreg_db.models import Frame
|
|
16
|
+
try:
|
|
17
|
+
# Access related manager directly
|
|
18
|
+
return video.frames.get(frame_number=frame_number)
|
|
19
|
+
except AttributeError:
|
|
20
|
+
logger.error("Could not access frame %d for video %s via related manager.", frame_number, video.uuid)
|
|
21
|
+
# Fallback query
|
|
22
|
+
return Frame.objects.get(video_file=video, frame_number=frame_number)
|
|
23
|
+
except Frame.DoesNotExist:
|
|
24
|
+
logger.error("Frame %d not found for video %s.", frame_number, video.uuid)
|
|
25
|
+
raise # Re-raise DoesNotExist
|
|
26
|
+
except Exception as e:
|
|
27
|
+
logger.error("Error getting frame %d for video %s: %s", frame_number, video.uuid, e, exc_info=True)
|
|
28
|
+
raise # Re-raise other exceptions
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from endoreg_db.models import VideoFile
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_frame_number(video: "VideoFile") -> int:
|
|
15
|
+
"""Counts the number of associated Frame objects in the database."""
|
|
16
|
+
try:
|
|
17
|
+
# Access related manager directly
|
|
18
|
+
return video.frames.count()
|
|
19
|
+
except AttributeError:
|
|
20
|
+
logger.error("Could not access frame count for video %s. 'frames' related manager not found.", str(video))
|
|
21
|
+
# Fallback query (less efficient)
|
|
22
|
+
frame_model = video.get_frame_model()
|
|
23
|
+
return frame_model.objects.filter(video_file=video).count()
|
|
24
|
+
except Exception as e:
|
|
25
|
+
logger.error("Error counting frames for video %s: %s", video.uuid, e, exc_info=True)
|
|
26
|
+
return 0
|
|
27
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# --- Frame Creation/Deletion ---
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from endoreg_db.models import VideoFile
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
def _get_frame_path(video: "VideoFile", frame_number: int) -> Optional[Path]:
|
|
12
|
+
"""Constructs the expected path for a given frame number."""
|
|
13
|
+
target_dir = video.get_frame_dir_path() # Use IO helper
|
|
14
|
+
if not target_dir:
|
|
15
|
+
logger.warning("Cannot get frame path for video %s: Frame directory not set.", video.uuid)
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
frame_filename = f"frame_{frame_number:07d}.jpg"
|
|
19
|
+
path = target_dir / frame_filename
|
|
20
|
+
return path
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from endoreg_db.models.media.video.video_file_io import _get_frame_dir_path
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from typing import TYPE_CHECKING, List
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from endoreg_db.models import VideoFile
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
def _get_frame_paths(video: "VideoFile") -> List[Path]:
|
|
13
|
+
"""Returns a sorted list of Path objects for extracted frame image files."""
|
|
14
|
+
frame_dir = _get_frame_dir_path(video)
|
|
15
|
+
if not frame_dir or not frame_dir.exists():
|
|
16
|
+
logger.warning("Frame directory %s does not exist for video %s.", frame_dir, video.uuid)
|
|
17
|
+
return []
|
|
18
|
+
|
|
19
|
+
frame_paths = list(frame_dir.glob('frame_*.jpg'))
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
frame_paths.sort(key=lambda p: int(p.stem.split('_')[-1]))
|
|
23
|
+
except (ValueError, IndexError) as e:
|
|
24
|
+
logger.error("Error sorting frame paths in %s: %s. Found paths: %s", frame_dir, e, [p.name for p in frame_paths], exc_info=True)
|
|
25
|
+
logger.warning("Falling back to unsorted frame paths to preserve available data.")
|
|
26
|
+
return frame_paths
|
|
27
|
+
return frame_paths
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
from django.db.models import QuerySet
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from endoreg_db.models import VideoFile, Frame
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_frame_range(video: "VideoFile", start_frame_number: int, end_frame_number: int) -> "QuerySet[Frame]":
|
|
16
|
+
"""Gets a QuerySet of Frame objects within a specific range, ordered by frame number."""
|
|
17
|
+
from endoreg_db.models import Frame
|
|
18
|
+
try:
|
|
19
|
+
# Access related manager directly
|
|
20
|
+
return video.frames.filter(
|
|
21
|
+
frame_number__gte=start_frame_number,
|
|
22
|
+
frame_number__lte=end_frame_number,
|
|
23
|
+
).order_by("frame_number")
|
|
24
|
+
except AttributeError:
|
|
25
|
+
logger.error("Could not access frame range for video %s via related manager.", video.uuid)
|
|
26
|
+
# Fallback query
|
|
27
|
+
return Frame.objects.filter(
|
|
28
|
+
video_file=video,
|
|
29
|
+
frame_number__gte=start_frame_number,
|
|
30
|
+
frame_number__lte=end_frame_number,
|
|
31
|
+
).order_by("frame_number")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
logger.error("Error getting frame range (%d-%d) for video %s: %s", start_frame_number, end_frame_number, video.uuid, e, exc_info=True)
|
|
34
|
+
return Frame.objects.none() # Return empty queryset on error
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from django.db.models import QuerySet
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from endoreg_db.models import VideoFile, Frame
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_frames(video: "VideoFile") -> "QuerySet[Frame]":
|
|
16
|
+
"""Gets a QuerySet of all associated Frame objects, ordered by frame number."""
|
|
17
|
+
from endoreg_db.models import Frame
|
|
18
|
+
try:
|
|
19
|
+
# Access related manager directly
|
|
20
|
+
return video.frames.order_by("frame_number")
|
|
21
|
+
except AttributeError:
|
|
22
|
+
logger.error("Could not access frames for video %s. 'frames' related manager not found.", video.uuid)
|
|
23
|
+
# Fallback query
|
|
24
|
+
return Frame.objects.filter(video_file=video).order_by("frame_number")
|
|
25
|
+
except Exception as e:
|
|
26
|
+
logger.error("Error getting frames for video %s: %s", video.uuid, e, exc_info=True)
|
|
27
|
+
return Frame.objects.none() # Return empty queryset on error
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from tqdm import tqdm
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
5
|
+
import logging
|
|
6
|
+
from django.db import OperationalError
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from endoreg_db.models import VideoFile
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _initialize_frames(video: "VideoFile", frame_paths: Optional[List[Path]] = None):
|
|
16
|
+
"""
|
|
17
|
+
Initializes Frame objects in the database based on either provided existing
|
|
18
|
+
frame paths or the expected frame count from the video metadata.
|
|
19
|
+
|
|
20
|
+
If `frame_paths` is provided, Frame objects are created/updated and marked
|
|
21
|
+
as `is_extracted=True`.
|
|
22
|
+
If `frame_paths` is None, Frame objects are created based on `video.frame_count`
|
|
23
|
+
and marked as `is_extracted=False`.
|
|
24
|
+
|
|
25
|
+
Updates state.frames_initialized and state.frame_count.
|
|
26
|
+
Uses bulk_create with ignore_conflicts=True, so it won't fail if frames already exist.
|
|
27
|
+
|
|
28
|
+
Raises RuntimeError on failure to create/update frames or update state.
|
|
29
|
+
|
|
30
|
+
State Transitions:
|
|
31
|
+
- On Success: Sets state.frames_initialized=True, state.frame_count=N.
|
|
32
|
+
- On Failure: Does not change state (error is raised).
|
|
33
|
+
"""
|
|
34
|
+
from endoreg_db.models import Frame
|
|
35
|
+
from endoreg_db.models.media.video.video_file_frames._bulk_create_frames import _bulk_create_frames
|
|
36
|
+
from endoreg_db.models.media.video.video_file_frames._create_frame_object import _create_frame_object
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
frames_to_create = []
|
|
40
|
+
num_expected_or_provided = 0
|
|
41
|
+
mark_as_extracted = False
|
|
42
|
+
|
|
43
|
+
if frame_paths:
|
|
44
|
+
logger.info("Initializing Frame objects based on %d provided paths for video %s.", len(frame_paths), video.uuid)
|
|
45
|
+
mark_as_extracted = True
|
|
46
|
+
num_expected_or_provided = len(frame_paths)
|
|
47
|
+
for frame_path in tqdm(frame_paths, desc=f"Initializing Frames from Paths {video.uuid}", unit="frame"):
|
|
48
|
+
try:
|
|
49
|
+
frame_number = int(frame_path.stem.split('_')[-1])
|
|
50
|
+
relative_path_str = frame_path.name
|
|
51
|
+
frames_to_create.append(
|
|
52
|
+
_create_frame_object(video, frame_number, relative_path_str, extracted=mark_as_extracted)
|
|
53
|
+
)
|
|
54
|
+
except (ValueError, IndexError) as e:
|
|
55
|
+
logger.warning("Could not parse frame number from %s: %s", frame_path.name, e)
|
|
56
|
+
continue
|
|
57
|
+
else:
|
|
58
|
+
expected_frame_count = video.frame_count
|
|
59
|
+
if expected_frame_count is None or expected_frame_count <= 0:
|
|
60
|
+
logger.warning("Cannot initialize frames for video %s: Frame count is %s.", video.uuid, expected_frame_count)
|
|
61
|
+
try:
|
|
62
|
+
state = video.get_or_create_state()
|
|
63
|
+
if state.frames_initialized or state.frame_count is not None:
|
|
64
|
+
state.frames_initialized = False
|
|
65
|
+
state.frame_count = None
|
|
66
|
+
state.save(update_fields=['frames_initialized', 'frame_count'])
|
|
67
|
+
except Exception as state_e:
|
|
68
|
+
logger.error("Failed to reset state during empty initialization for video %s: %s", video.uuid, state_e, exc_info=True)
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
logger.info("Initializing %d expected Frame objects for video %s (is_extracted=False).", expected_frame_count, video.uuid)
|
|
72
|
+
mark_as_extracted = False
|
|
73
|
+
num_expected_or_provided = expected_frame_count
|
|
74
|
+
for frame_number in tqdm(range(expected_frame_count), desc=f"Initializing Expected Frames {video.uuid}", unit="frame"):
|
|
75
|
+
relative_path_str = f"frame_{frame_number:07d}.jpg"
|
|
76
|
+
frames_to_create.append(
|
|
77
|
+
_create_frame_object(video, frame_number, relative_path_str, extracted=mark_as_extracted)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if frames_to_create:
|
|
81
|
+
for attempt in range(5):
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
_bulk_create_frames(video, frames_to_create)
|
|
85
|
+
num_created_or_ignored = len(frames_to_create)
|
|
86
|
+
logger.info("Bulk create attempted for %d Frame objects for video %s (ignore_conflicts=True).", num_created_or_ignored, video.uuid)
|
|
87
|
+
|
|
88
|
+
if mark_as_extracted:
|
|
89
|
+
frame_numbers_to_update = [f.frame_number for f in frames_to_create]
|
|
90
|
+
if frame_numbers_to_update:
|
|
91
|
+
update_count = Frame.objects.filter(
|
|
92
|
+
video=video,
|
|
93
|
+
frame_number__in=frame_numbers_to_update,
|
|
94
|
+
is_extracted=False
|
|
95
|
+
).update(is_extracted=True)
|
|
96
|
+
if update_count > 0:
|
|
97
|
+
logger.info("Marked %d existing Frame objects as is_extracted=True for video %s.", update_count, video.uuid)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
state = video.get_or_create_state()
|
|
101
|
+
state.frames_initialized = True
|
|
102
|
+
state.frame_count = num_expected_or_provided
|
|
103
|
+
state.save(update_fields=['frames_initialized', 'frame_count'])
|
|
104
|
+
logger.info("Set frames_initialized=True and frame_count=%d for video %s.", num_expected_or_provided, video.uuid)
|
|
105
|
+
except Exception as state_e:
|
|
106
|
+
logger.error("Failed to update state after frame initialization for video %s: %s", video.uuid, state_e, exc_info=True)
|
|
107
|
+
raise RuntimeError(f"Failed to update state after frame initialization for video {video.uuid}") from state_e
|
|
108
|
+
|
|
109
|
+
except OperationalError as e:
|
|
110
|
+
if "database is locked" in str(e):
|
|
111
|
+
logger.warning("Database is locked, retrying frame initialization for video %s (attempt %d/5).", video.uuid, attempt + 1)
|
|
112
|
+
time.sleep(2 ** attempt)
|
|
113
|
+
if attempt < 4:
|
|
114
|
+
continue
|
|
115
|
+
else:
|
|
116
|
+
raise RuntimeError(f"Failed to initialize frames for video {video.uuid}.") from e
|
|
117
|
+
logger.error("Error initializing frames for video %s: %s", video.uuid, e, exc_info=True)
|
|
118
|
+
raise RuntimeError(f"Failed to initialize frames for video {video.uuid}.") from e
|
|
119
|
+
|
|
120
|
+
else:
|
|
121
|
+
logger.warning("No valid frames found/generated to initialize for video %s.", video.uuid)
|
|
122
|
+
try:
|
|
123
|
+
state = video.get_or_create_state()
|
|
124
|
+
if state.frames_initialized or state.frame_count is not None:
|
|
125
|
+
state.frames_initialized = False
|
|
126
|
+
state.frame_count = None
|
|
127
|
+
state.save(update_fields=['frames_initialized', 'frame_count'])
|
|
128
|
+
except Exception as state_e:
|
|
129
|
+
logger.error("Failed to reset state during empty initialization for video %s: %s", video.uuid, state_e, exc_info=True)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from django.db import transaction
|
|
5
|
+
|
|
6
|
+
# Assuming ffmpeg_wrapper has or will have this function
|
|
7
|
+
from endoreg_db.utils.video.ffmpeg_wrapper import extract_frame_range as ffmpeg_extract_frame_range
|
|
8
|
+
|
|
9
|
+
from endoreg_db.models.media.video.video_file_io import _get_frame_dir_path
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from endoreg_db.models import VideoFile
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
def _delete_frame_range(video: "VideoFile", start_frame: int, end_frame: int):
|
|
17
|
+
"""
|
|
18
|
+
Deletes frame image files within the specified range [start_frame, end_frame)
|
|
19
|
+
and updates their is_extracted status to False. Runs within the caller's transaction.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
logger.info("Deleting frame files for video %s in range [%d, %d)", video.uuid, start_frame, end_frame)
|
|
23
|
+
frames_to_delete = video.frames.filter(
|
|
24
|
+
frame_number__gte=start_frame,
|
|
25
|
+
frame_number__lt=end_frame,
|
|
26
|
+
is_extracted=True
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
deleted_count = 0
|
|
30
|
+
paths_to_delete = [frame.file_path for frame in frames_to_delete] # Get paths before potential DB changes
|
|
31
|
+
|
|
32
|
+
# Update DB first
|
|
33
|
+
update_count = frames_to_delete.update(is_extracted=False)
|
|
34
|
+
logger.info("Marked %d Frame objects as is_extracted=False for video %s range [%d, %d).",
|
|
35
|
+
update_count, video.uuid, start_frame, end_frame)
|
|
36
|
+
|
|
37
|
+
# Then delete files
|
|
38
|
+
for frame_path in paths_to_delete:
|
|
39
|
+
try:
|
|
40
|
+
if frame_path.exists():
|
|
41
|
+
os.remove(frame_path)
|
|
42
|
+
deleted_count += 1
|
|
43
|
+
except Exception as e:
|
|
44
|
+
# Log warning but continue; DB state is already updated.
|
|
45
|
+
logger.warning("Could not delete frame file %s for video %s: %s", frame_path, video.uuid, e)
|
|
46
|
+
|
|
47
|
+
logger.info("Attempted deletion of %d files for video %s range [%d, %d). Actual deleted: %d.",
|
|
48
|
+
len(paths_to_delete), video.uuid, start_frame, end_frame, deleted_count)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@transaction.atomic
|
|
54
|
+
def _extract_frame_range(
|
|
55
|
+
video: "VideoFile",
|
|
56
|
+
start_frame: int,
|
|
57
|
+
end_frame: int,
|
|
58
|
+
quality: int = 2,
|
|
59
|
+
overwrite: bool = False,
|
|
60
|
+
ext="jpg",
|
|
61
|
+
verbose=False,
|
|
62
|
+
) -> bool:
|
|
63
|
+
"""
|
|
64
|
+
Extracts frames within the range [start_frame, end_frame) using ffmpeg.
|
|
65
|
+
Updates corresponding Frame objects' is_extracted flag.
|
|
66
|
+
Runs within the caller's transaction.
|
|
67
|
+
Does NOT update VideoState.frames_extracted.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
if not video.has_raw:
|
|
71
|
+
raise FileNotFoundError(f"Raw video file not available for {video.uuid}. Cannot extract frame range.")
|
|
72
|
+
|
|
73
|
+
raw_file_path = video.get_raw_file_path()
|
|
74
|
+
if not raw_file_path or not raw_file_path.exists():
|
|
75
|
+
raise FileNotFoundError(f"Raw video file not found at {raw_file_path} for video {video.uuid}. Cannot extract frame range.")
|
|
76
|
+
|
|
77
|
+
frame_dir = _get_frame_dir_path(video)
|
|
78
|
+
if not frame_dir:
|
|
79
|
+
raise ValueError(f"Cannot determine frame directory path for video {video.uuid}.")
|
|
80
|
+
|
|
81
|
+
# Check frames within the range that might already exist
|
|
82
|
+
frames_in_range = video.frames.filter(
|
|
83
|
+
frame_number__gte=start_frame,
|
|
84
|
+
frame_number__lt=end_frame
|
|
85
|
+
)
|
|
86
|
+
existing_extracted_in_range = frames_in_range.filter(is_extracted=True)
|
|
87
|
+
|
|
88
|
+
if existing_extracted_in_range.exists():
|
|
89
|
+
if overwrite:
|
|
90
|
+
logger.info("Overwrite=True, deleting existing frame files in range [%d, %d) for video %s before extraction.", start_frame, end_frame, video.uuid)
|
|
91
|
+
_delete_frame_range(video, start_frame, end_frame)
|
|
92
|
+
else:
|
|
93
|
+
logger.info("Frames already exist in range [%d, %d) for video %s and overwrite=False. Skipping extraction for this range.", start_frame, end_frame, video.uuid)
|
|
94
|
+
updated_count = frames_in_range.filter(is_extracted=False).update(is_extracted=True)
|
|
95
|
+
if updated_count > 0:
|
|
96
|
+
logger.info("Marked %d existing Frame objects in range [%d, %d) as extracted for video %s.", updated_count, start_frame, end_frame, video.uuid)
|
|
97
|
+
return True # Indicate success as frames are considered present
|
|
98
|
+
|
|
99
|
+
frame_dir.mkdir(parents=True, exist_ok=True)
|
|
100
|
+
extracted_paths = []
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
logger.info("Starting frame range extraction [%d, %d) for video %s to %s", start_frame, end_frame, video.uuid, frame_dir)
|
|
104
|
+
extracted_paths = ffmpeg_extract_frame_range(
|
|
105
|
+
raw_file_path, frame_dir, start_frame, end_frame, quality=quality, ext=ext
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
logger.info("ffmpeg extraction process completed for video %s range [%d, %d). Found %d files.", video.uuid, start_frame, end_frame, len(extracted_paths))
|
|
109
|
+
|
|
110
|
+
update_count = frames_in_range.update(is_extracted=True)
|
|
111
|
+
logger.info("Marked %d Frame objects in range [%d, %d) as is_extracted=True for video %s.", update_count, start_frame, end_frame, video.uuid)
|
|
112
|
+
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
except FileNotFoundError as err:
|
|
116
|
+
logger.error(
|
|
117
|
+
"Frame range extraction [%d, %d) failed for video %s: %s",
|
|
118
|
+
start_frame,
|
|
119
|
+
end_frame,
|
|
120
|
+
video.uuid,
|
|
121
|
+
err,
|
|
122
|
+
exc_info=True,
|
|
123
|
+
)
|
|
124
|
+
raise
|
|
125
|
+
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.error("Frame range extraction [%d, %d) or DB update failed for video %s: %s", start_frame, end_frame, video.uuid, e, exc_info=True)
|
|
128
|
+
|
|
129
|
+
logger.warning("Attempting file cleanup in range [%d, %d) for video %s due to extraction error.", start_frame, end_frame, video.uuid)
|
|
130
|
+
files_to_check = extracted_paths if 'extracted_paths' in locals() and extracted_paths else []
|
|
131
|
+
if not files_to_check:
|
|
132
|
+
files_to_check = [frame_dir / f"frame_{i:07d}.{ext}" for i in range(start_frame, end_frame)]
|
|
133
|
+
|
|
134
|
+
for potential_file in files_to_check:
|
|
135
|
+
if potential_file.exists():
|
|
136
|
+
try:
|
|
137
|
+
os.remove(potential_file)
|
|
138
|
+
except OSError as unlink_err:
|
|
139
|
+
logger.error("Failed to delete potential frame %s during cleanup: %s", potential_file, unlink_err)
|
|
140
|
+
|
|
141
|
+
raise RuntimeError(f"Frame range extraction or update failed for video {video.uuid} range [{start_frame}, {end_frame}).") from e
|