endoreg-db 0.8.6.4__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/__init__.py +0 -0
- endoreg_db/admin.py +92 -0
- endoreg_db/api/serializers/finding_descriptions.py +0 -0
- endoreg_db/api/views/finding_descriptions.py +0 -0
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +18 -0
- 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/__init__.py +0 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +144 -0
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/ai_model_label/label/data.yaml +88 -0
- 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/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_type/data.yaml +7 -0
- 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 -0
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
- endoreg_db/data/case_template/rule_value/.init +0 -0
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
- endoreg_db/data/case_template/template/base.yaml +8 -0
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
- endoreg_db/data/case_template/tmp/_rule_value +13 -0
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
- endoreg_db/data/center/data.yaml +91 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- 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 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +5 -0
- endoreg_db/data/disease/renal.yaml +5 -0
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
- endoreg_db/data/distribution/date/patient.yaml +7 -0
- endoreg_db/data/distribution/multiple_categorical/.init +0 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +11 -0
- endoreg_db/data/endoscopy_processor/data.yaml +50 -0
- endoreg_db/data/event/cardiology.yaml +15 -0
- endoreg_db/data/event/neurology.yaml +14 -0
- endoreg_db/data/event/surgery.yaml +13 -0
- endoreg_db/data/event/thrombembolism.yaml +20 -0
- endoreg_db/data/examination/examinations/data.yaml +72 -0
- endoreg_db/data/examination/time/data.yaml +48 -0
- endoreg_db/data/examination/time-type/data.yaml +8 -0
- endoreg_db/data/examination/type/data.yaml +17 -0
- 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 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +6 -0
- 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 -0
- endoreg_db/data/lab_value/coagulation.yaml +54 -0
- endoreg_db/data/lab_value/electrolytes.yaml +228 -0
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -0
- endoreg_db/data/lab_value/hematology.yaml +184 -0
- endoreg_db/data/lab_value/hormones.yaml +59 -0
- endoreg_db/data/lab_value/lipids.yaml +53 -0
- endoreg_db/data/lab_value/misc.yaml +76 -0
- endoreg_db/data/lab_value/renal_function.yaml +12 -0
- 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/material/material.yaml +91 -0
- endoreg_db/data/medication/anticoagulation.yaml +65 -0
- endoreg_db/data/medication/tah.yaml +70 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -0
- endoreg_db/data/medication_indication_type/data.yaml +11 -0
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
- endoreg_db/data/medication_intake_time/base.yaml +31 -0
- endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
- endoreg_db/data/medication_schedule/ass.yaml +12 -0
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
- 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 +6 -0
- endoreg_db/data/pdf_type/data.yaml +46 -0
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
- endoreg_db/data/profession/data.yaml +70 -0
- 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 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -0
- 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 -0
- 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/tmp/chronic_kidney_disease.yaml +0 -0
- endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
- endoreg_db/data/unit/concentration.yaml +115 -0
- endoreg_db/data/unit/data.yaml +17 -0
- endoreg_db/data/unit/length.yaml +31 -0
- endoreg_db/data/unit/misc.yaml +20 -0
- endoreg_db/data/unit/rate.yaml +6 -0
- endoreg_db/data/unit/time.yaml +48 -0
- endoreg_db/data/unit/volume.yaml +35 -0
- endoreg_db/data/unit/weight.yaml +38 -0
- endoreg_db/data/waste/data.yaml +12 -0
- endoreg_db/exceptions.py +19 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +5 -0
- 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 -0
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -0
- endoreg_db/forms/settings/__init__.py +8 -0
- endoreg_db/forms/unit.py +6 -0
- 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 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +192 -0
- endoreg_db/management/commands/load_center_data.py +68 -0
- endoreg_db/management/commands/load_contraindication_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_choices_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_data.py +41 -0
- endoreg_db/management/commands/load_disease_data.py +62 -0
- endoreg_db/management/commands/load_distribution_data.py +66 -0
- endoreg_db/management/commands/load_endoscope_data.py +68 -0
- endoreg_db/management/commands/load_event_data.py +41 -0
- endoreg_db/management/commands/load_examination_data.py +75 -0
- 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 +44 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +132 -0
- endoreg_db/management/commands/load_information_source.py +51 -0
- endoreg_db/management/commands/load_lab_value_data.py +50 -0
- endoreg_db/management/commands/load_medication_data.py +103 -0
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/load_organ_data.py +43 -0
- endoreg_db/management/commands/load_pdf_type_data.py +61 -0
- endoreg_db/management/commands/load_profession_data.py +44 -0
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/load_report_reader_flag_data.py +46 -0
- 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 +46 -0
- endoreg_db/management/commands/load_user_groups.py +28 -0
- endoreg_db/management/commands/register_ai_model.py +64 -0
- endoreg_db/management/commands/reset_celery_schedule.py +9 -0
- 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 -0
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +359 -0
- 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/administration/ai/model_type.py +41 -0
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/administration/case/case_template/__init__.py +15 -0
- endoreg_db/models/administration/case/case_template/case_template.py +125 -0
- endoreg_db/models/administration/case/case_template/case_template_rule.py +269 -0
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +86 -0
- endoreg_db/models/administration/case/case_template/case_template_type.py +26 -0
- endoreg_db/models/administration/center/__init__.py +13 -0
- 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/administration/person/names/first_name.py +18 -0
- endoreg_db/models/administration/person/names/last_name.py +19 -0
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/administration/person/person.py +31 -0
- 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/administration/product/product_weight.py +47 -0
- endoreg_db/models/administration/product/reference_product.py +130 -0
- 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 -0
- 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 -0
- 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/media/pdf/report_reader/report_reader_flag.py +20 -0
- 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/medical/hardware/endoscopy_processor.py +182 -0
- 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/medical/patient/patient_lab_value.py +222 -0
- 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/metadata/pdf_meta.py +89 -0
- 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 -0
- 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/other/gender.py +27 -0
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +28 -0
- endoreg_db/models/other/resource.py +22 -0
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +33 -0
- endoreg_db/models/other/unit.py +32 -0
- endoreg_db/models/other/waste.py +27 -0
- 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/rule/rule.py +27 -0
- endoreg_db/models/rule/rule_applicator.py +224 -0
- endoreg_db/models/rule/rule_attribute_dtype.py +17 -0
- endoreg_db/models/rule/rule_type.py +20 -0
- endoreg_db/models/rule/ruleset.py +17 -0
- 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 +5 -0
- endoreg_db/queries/annotations/__init__.py +3 -0
- endoreg_db/queries/annotations/legacy.py +158 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- 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 -0
- 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 -0
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/utils/ai/get.py +5 -0
- 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 +29 -0
- endoreg_db/utils/dataloader.py +175 -0
- 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 -0
- 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 -0
- 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 -0
- 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 -0
- 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 +274 -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 +186 -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 -0
- endoreg_db-0.8.6.4.dist-info/METADATA +383 -0
- endoreg_db-0.8.6.4.dist-info/RECORD +793 -0
- endoreg_db-0.8.6.4.dist-info/WHEEL +4 -0
- endoreg_db-0.8.6.4.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
"""Concrete model for video files, handling both raw and processed states."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import uuid
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Optional, Union, cast
|
|
8
|
+
|
|
9
|
+
from django.core.files import File
|
|
10
|
+
from django.core.validators import FileExtensionValidator
|
|
11
|
+
from django.db import models
|
|
12
|
+
from django.db.models import F
|
|
13
|
+
from django.db.models.fields.files import FieldFile
|
|
14
|
+
|
|
15
|
+
from endoreg_db.utils.calc_duration_seconds import _calc_duration_vf
|
|
16
|
+
|
|
17
|
+
from ...label import Label, LabelVideoSegment
|
|
18
|
+
from ...state import VideoState
|
|
19
|
+
from ...utils import ANONYM_VIDEO_DIR, VIDEO_DIR
|
|
20
|
+
|
|
21
|
+
# --- Import model-specific function modules ---
|
|
22
|
+
from .create_from_file import _create_from_file
|
|
23
|
+
from .pipe_1 import _pipe_1, _test_after_pipe_1
|
|
24
|
+
from .pipe_2 import _pipe_2
|
|
25
|
+
from .video_file_ai import _extract_text_from_video_frames, _predict_video_pipeline
|
|
26
|
+
from .video_file_anonymize import (
|
|
27
|
+
_anonymize,
|
|
28
|
+
_cleanup_raw_assets,
|
|
29
|
+
_create_anonymized_frame_files,
|
|
30
|
+
)
|
|
31
|
+
from .video_file_frames import (
|
|
32
|
+
_bulk_create_frames,
|
|
33
|
+
_create_frame_object,
|
|
34
|
+
_delete_frames,
|
|
35
|
+
_extract_frames,
|
|
36
|
+
_get_frame,
|
|
37
|
+
_get_frame_number,
|
|
38
|
+
_get_frame_path,
|
|
39
|
+
_get_frame_paths,
|
|
40
|
+
_get_frame_range,
|
|
41
|
+
_get_frames,
|
|
42
|
+
_initialize_frames,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Update import aliases for clarity and to use as helpers
|
|
46
|
+
from .video_file_frames._manage_frame_range import (
|
|
47
|
+
_delete_frame_range as _delete_frame_range_helper,
|
|
48
|
+
)
|
|
49
|
+
from .video_file_frames._manage_frame_range import (
|
|
50
|
+
_extract_frame_range as _extract_frame_range_helper,
|
|
51
|
+
)
|
|
52
|
+
from .video_file_io import (
|
|
53
|
+
_delete_with_file,
|
|
54
|
+
_get_base_frame_dir,
|
|
55
|
+
_get_frame_dir_path,
|
|
56
|
+
_get_processed_file_path,
|
|
57
|
+
_get_raw_file_path,
|
|
58
|
+
_get_target_anonymized_video_path,
|
|
59
|
+
_get_temp_anonymized_frame_dir,
|
|
60
|
+
_set_frame_dir,
|
|
61
|
+
)
|
|
62
|
+
from .video_file_meta import (
|
|
63
|
+
_get_crop_template,
|
|
64
|
+
_get_endo_roi,
|
|
65
|
+
_get_fps,
|
|
66
|
+
_initialize_video_specs,
|
|
67
|
+
_update_text_metadata,
|
|
68
|
+
_update_video_meta,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Configure logging
|
|
72
|
+
logger = logging.getLogger(__name__) # Changed from "video_file"
|
|
73
|
+
|
|
74
|
+
if TYPE_CHECKING:
|
|
75
|
+
from endoreg_db.models import (
|
|
76
|
+
Center,
|
|
77
|
+
EndoscopyProcessor,
|
|
78
|
+
FFMpegMeta,
|
|
79
|
+
Frame,
|
|
80
|
+
ModelMeta,
|
|
81
|
+
Patient,
|
|
82
|
+
PatientExamination,
|
|
83
|
+
SensitiveMeta,
|
|
84
|
+
VideoImportMeta,
|
|
85
|
+
VideoMeta,
|
|
86
|
+
VideoState,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class VideoQuerySet(models.QuerySet):
|
|
91
|
+
def next_after(self, last_id=None):
|
|
92
|
+
"""
|
|
93
|
+
Return the next VideoFile instance with a primary key greater than the given last_id.
|
|
94
|
+
|
|
95
|
+
Parameters:
|
|
96
|
+
last_id (int or None): The primary key to start after. If None or invalid, returns the first instance.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
VideoFile or None: The next VideoFile instance, or None if not found.
|
|
100
|
+
"""
|
|
101
|
+
if last_id is not None:
|
|
102
|
+
try:
|
|
103
|
+
last_id = int(last_id)
|
|
104
|
+
except (ValueError, TypeError):
|
|
105
|
+
return None
|
|
106
|
+
q = self if last_id is None else self.filter(pk__gt=last_id)
|
|
107
|
+
return q.order_by("pk").first()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class VideoFile(models.Model):
|
|
111
|
+
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
|
112
|
+
|
|
113
|
+
objects = VideoQuerySet.as_manager()
|
|
114
|
+
|
|
115
|
+
raw_file = models.FileField(
|
|
116
|
+
upload_to=VIDEO_DIR.name, # Use .name for relative path
|
|
117
|
+
validators=[FileExtensionValidator(allowed_extensions=["mp4"])],
|
|
118
|
+
null=True,
|
|
119
|
+
blank=True,
|
|
120
|
+
)
|
|
121
|
+
processed_file = models.FileField(
|
|
122
|
+
upload_to=ANONYM_VIDEO_DIR.name, # Use .name for relative path
|
|
123
|
+
validators=[FileExtensionValidator(allowed_extensions=["mp4"])],
|
|
124
|
+
null=True,
|
|
125
|
+
blank=True,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
video_hash = models.CharField(
|
|
129
|
+
max_length=255, unique=True, help_text="Hash of the raw video file."
|
|
130
|
+
)
|
|
131
|
+
processed_video_hash = models.CharField(
|
|
132
|
+
max_length=255,
|
|
133
|
+
unique=True,
|
|
134
|
+
null=True,
|
|
135
|
+
blank=True,
|
|
136
|
+
help_text="Hash of the processed video file, unique if not null.",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
sensitive_meta = models.OneToOneField(
|
|
140
|
+
"SensitiveMeta",
|
|
141
|
+
on_delete=models.SET_NULL,
|
|
142
|
+
null=True,
|
|
143
|
+
blank=True,
|
|
144
|
+
related_name="video_file",
|
|
145
|
+
) # type: ignore
|
|
146
|
+
center = models.ForeignKey("Center", on_delete=models.PROTECT) # type: ignore
|
|
147
|
+
processor = models.ForeignKey(
|
|
148
|
+
"EndoscopyProcessor", on_delete=models.PROTECT, blank=True, null=True
|
|
149
|
+
) # type: ignore
|
|
150
|
+
video_meta = models.OneToOneField(
|
|
151
|
+
"VideoMeta",
|
|
152
|
+
on_delete=models.SET_NULL,
|
|
153
|
+
null=True,
|
|
154
|
+
blank=True,
|
|
155
|
+
related_name="video_file",
|
|
156
|
+
) # type: ignore
|
|
157
|
+
examination = models.ForeignKey(
|
|
158
|
+
"PatientExamination",
|
|
159
|
+
on_delete=models.SET_NULL,
|
|
160
|
+
blank=True,
|
|
161
|
+
null=True,
|
|
162
|
+
related_name="video_files",
|
|
163
|
+
) # type: ignore
|
|
164
|
+
patient = models.ForeignKey(
|
|
165
|
+
"Patient",
|
|
166
|
+
on_delete=models.SET_NULL,
|
|
167
|
+
blank=True,
|
|
168
|
+
null=True,
|
|
169
|
+
related_name="video_files",
|
|
170
|
+
) # type: ignore
|
|
171
|
+
ai_model_meta = models.ForeignKey(
|
|
172
|
+
"ModelMeta", on_delete=models.SET_NULL, blank=True, null=True
|
|
173
|
+
) # type: ignore
|
|
174
|
+
state = models.OneToOneField(
|
|
175
|
+
"VideoState",
|
|
176
|
+
on_delete=models.SET_NULL,
|
|
177
|
+
null=True,
|
|
178
|
+
blank=True,
|
|
179
|
+
related_name="video_file",
|
|
180
|
+
) # type: ignore
|
|
181
|
+
import_meta = models.OneToOneField(
|
|
182
|
+
"VideoImportMeta", on_delete=models.CASCADE, blank=True, null=True
|
|
183
|
+
) # type: ignore
|
|
184
|
+
|
|
185
|
+
original_file_name = models.CharField(max_length=255, blank=True, null=True)
|
|
186
|
+
uploaded_at = models.DateTimeField(auto_now_add=True)
|
|
187
|
+
frame_dir = models.CharField(
|
|
188
|
+
max_length=512,
|
|
189
|
+
blank=True,
|
|
190
|
+
help_text="Path to frames extracted from the raw video.",
|
|
191
|
+
)
|
|
192
|
+
fps = models.FloatField(blank=True, null=True)
|
|
193
|
+
duration = models.FloatField(blank=True, null=True)
|
|
194
|
+
frame_count = models.IntegerField(blank=True, null=True)
|
|
195
|
+
width = models.IntegerField(blank=True, null=True)
|
|
196
|
+
height = models.IntegerField(blank=True, null=True)
|
|
197
|
+
suffix = models.CharField(max_length=10, blank=True, null=True)
|
|
198
|
+
sequences = models.JSONField(
|
|
199
|
+
default=dict,
|
|
200
|
+
blank=True,
|
|
201
|
+
help_text="AI prediction sequences based on raw frames.",
|
|
202
|
+
)
|
|
203
|
+
date = models.DateField(blank=True, null=True)
|
|
204
|
+
meta = models.JSONField(blank=True, null=True)
|
|
205
|
+
date_created = models.DateTimeField(auto_now_add=True)
|
|
206
|
+
date_modified = models.DateTimeField(auto_now=True)
|
|
207
|
+
|
|
208
|
+
if TYPE_CHECKING:
|
|
209
|
+
label_video_segments: "models.QuerySet[LabelVideoSegment]"
|
|
210
|
+
frames: "models.QuerySet[Frame]"
|
|
211
|
+
center: "Center"
|
|
212
|
+
processor: "EndoscopyProcessor"
|
|
213
|
+
video_meta: "VideoMeta"
|
|
214
|
+
examination: "PatientExamination"
|
|
215
|
+
patient: "Patient"
|
|
216
|
+
sensitive_meta: "SensitiveMeta"
|
|
217
|
+
state: "VideoState"
|
|
218
|
+
ai_model_meta: "ModelMeta"
|
|
219
|
+
import_meta: "VideoImportMeta"
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def ffmpeg_meta(self) -> "FFMpegMeta":
|
|
223
|
+
"""
|
|
224
|
+
Return the associated FFMpegMeta instance for this video, initializing video specs if necessary.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
FFMpegMeta: The FFMpegMeta object containing metadata for this video.
|
|
228
|
+
"""
|
|
229
|
+
from endoreg_db.models import FFMpegMeta
|
|
230
|
+
|
|
231
|
+
if self.video_meta is not None:
|
|
232
|
+
if self.video_meta.ffmpeg_meta is not None:
|
|
233
|
+
return self.video_meta.ffmpeg_meta
|
|
234
|
+
raise AssertionError("Expected FFMpegMeta instance.")
|
|
235
|
+
else:
|
|
236
|
+
self.initialize_video_specs()
|
|
237
|
+
ffmpeg_meta = self.video_meta.ffmpeg_meta if self.video_meta else None
|
|
238
|
+
assert isinstance(ffmpeg_meta, FFMpegMeta), "Expected FFMpegMeta instance."
|
|
239
|
+
return ffmpeg_meta
|
|
240
|
+
|
|
241
|
+
# Exception message constants
|
|
242
|
+
|
|
243
|
+
NO_ACTIVE_FILE = "Has no raw file"
|
|
244
|
+
NO_FILE_ASSOCIATED = "Active file has no associated file."
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def active_raw_file(self) -> File:
|
|
248
|
+
"""Return the raw file if available, otherwise raise ValueError."""
|
|
249
|
+
if self.has_raw:
|
|
250
|
+
return self.raw_file
|
|
251
|
+
raise ValueError(self.NO_ACTIVE_FILE)
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def active_raw_file_url(self) -> str:
|
|
255
|
+
"""Return the URL of the active raw file, or raise ValueError if unavailable."""
|
|
256
|
+
_file = self.active_raw_file
|
|
257
|
+
assert _file is not None, self.NO_ACTIVE_FILE
|
|
258
|
+
if not _file or not _file.name:
|
|
259
|
+
raise ValueError(self.NO_FILE_ASSOCIATED)
|
|
260
|
+
return _file.url
|
|
261
|
+
|
|
262
|
+
# Pipeline Functions
|
|
263
|
+
pipe_1 = _pipe_1
|
|
264
|
+
test_after_pipe_1 = _test_after_pipe_1
|
|
265
|
+
pipe_2 = _pipe_2
|
|
266
|
+
|
|
267
|
+
# Metadata Funtions
|
|
268
|
+
update_video_meta = _update_video_meta
|
|
269
|
+
initialize_video_specs = _initialize_video_specs
|
|
270
|
+
get_fps = _get_fps
|
|
271
|
+
get_endo_roi = _get_endo_roi
|
|
272
|
+
get_crop_template = _get_crop_template
|
|
273
|
+
update_text_metadata = _update_text_metadata
|
|
274
|
+
|
|
275
|
+
extract_frames = _extract_frames
|
|
276
|
+
initialize_frames = _initialize_frames
|
|
277
|
+
delete_frames = _delete_frames
|
|
278
|
+
get_frame_path = _get_frame_path
|
|
279
|
+
get_frame_paths = _get_frame_paths
|
|
280
|
+
get_frame_number = _get_frame_number
|
|
281
|
+
get_frames = _get_frames
|
|
282
|
+
get_frame = _get_frame
|
|
283
|
+
get_frame_range = _get_frame_range
|
|
284
|
+
get_duration = _calc_duration_vf
|
|
285
|
+
create_frame_object = _create_frame_object
|
|
286
|
+
bulk_create_frames = _bulk_create_frames
|
|
287
|
+
|
|
288
|
+
# Define new methods that call the helper functions
|
|
289
|
+
def extract_specific_frame_range(
|
|
290
|
+
self, start_frame: int, end_frame: int, overwrite: bool = False, **kwargs
|
|
291
|
+
) -> bool:
|
|
292
|
+
"""
|
|
293
|
+
Extract frames from the video within the specified frame range.
|
|
294
|
+
|
|
295
|
+
Parameters:
|
|
296
|
+
start_frame (int): The starting frame number (inclusive).
|
|
297
|
+
end_frame (int): The ending frame number (exclusive).
|
|
298
|
+
overwrite (bool): Whether to overwrite existing frames in the range.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
bool: True if frame extraction was successful, False otherwise.
|
|
302
|
+
|
|
303
|
+
Additional keyword arguments:
|
|
304
|
+
quality (int, optional): Quality setting for extracted frames.
|
|
305
|
+
ext (str, optional): File extension for extracted frames.
|
|
306
|
+
verbose (bool, optional): Whether to enable verbose output.
|
|
307
|
+
"""
|
|
308
|
+
quality = kwargs.get("quality", 2)
|
|
309
|
+
ext = kwargs.get("ext", "jpg")
|
|
310
|
+
verbose = kwargs.get("verbose", False)
|
|
311
|
+
|
|
312
|
+
# Log if unexpected kwargs are passed, beyond those used by the helper
|
|
313
|
+
expected_helper_kwargs = {"quality", "ext", "verbose"}
|
|
314
|
+
unexpected_kwargs = {
|
|
315
|
+
k: v for k, v in kwargs.items() if k not in expected_helper_kwargs
|
|
316
|
+
}
|
|
317
|
+
if unexpected_kwargs:
|
|
318
|
+
logger.warning(
|
|
319
|
+
f"Unexpected keyword arguments for extract_specific_frame_range, will be ignored by helper: {unexpected_kwargs}"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
return _extract_frame_range_helper(
|
|
323
|
+
video=self,
|
|
324
|
+
start_frame=start_frame,
|
|
325
|
+
end_frame=end_frame,
|
|
326
|
+
quality=quality,
|
|
327
|
+
overwrite=overwrite,
|
|
328
|
+
ext=ext,
|
|
329
|
+
verbose=verbose,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
def delete_specific_frame_range(self, start_frame: int, end_frame: int) -> None:
|
|
333
|
+
"""
|
|
334
|
+
Deletes frame files for a specific range [start_frame, end_frame).
|
|
335
|
+
"""
|
|
336
|
+
_delete_frame_range_helper(
|
|
337
|
+
video=self, start_frame=start_frame, end_frame=end_frame
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
delete_with_file = _delete_with_file
|
|
341
|
+
get_base_frame_dir = _get_base_frame_dir
|
|
342
|
+
set_frame_dir = _set_frame_dir
|
|
343
|
+
get_frame_dir_path = _get_frame_dir_path
|
|
344
|
+
get_temp_anonymized_frame_dir = _get_temp_anonymized_frame_dir
|
|
345
|
+
get_target_anonymized_video_path = _get_target_anonymized_video_path
|
|
346
|
+
get_raw_file_path = _get_raw_file_path
|
|
347
|
+
get_processed_file_path = _get_processed_file_path
|
|
348
|
+
|
|
349
|
+
anonymize = _anonymize
|
|
350
|
+
_create_anonymized_frame_files = _create_anonymized_frame_files
|
|
351
|
+
_cleanup_raw_assets = _cleanup_raw_assets
|
|
352
|
+
|
|
353
|
+
predict_video = _predict_video_pipeline
|
|
354
|
+
extract_text_from_frames = _extract_text_from_video_frames
|
|
355
|
+
|
|
356
|
+
@classmethod
|
|
357
|
+
def check_hash_exists(cls, video_hash: str) -> bool:
|
|
358
|
+
"""
|
|
359
|
+
Checks if a VideoFile with the given raw video hash already exists.
|
|
360
|
+
"""
|
|
361
|
+
return cls.objects.filter(video_hash=video_hash).exists()
|
|
362
|
+
|
|
363
|
+
@property
|
|
364
|
+
def is_processed(self) -> bool:
|
|
365
|
+
return bool(self.processed_file and self.processed_file.name)
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def has_raw(self) -> bool:
|
|
369
|
+
"""
|
|
370
|
+
Return True if a raw video file is associated with this instance.
|
|
371
|
+
"""
|
|
372
|
+
return bool(self.raw_file and self.raw_file.name)
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def active_file(self) -> FieldFile:
|
|
376
|
+
"""
|
|
377
|
+
Return the active video file, preferring the processed file if available.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
File: The processed file if present; otherwise, the raw file.
|
|
381
|
+
|
|
382
|
+
Raises:
|
|
383
|
+
ValueError: If neither a processed nor a raw file is available.
|
|
384
|
+
"""
|
|
385
|
+
processed = self.processed_file
|
|
386
|
+
if isinstance(processed, FieldFile) and processed.name:
|
|
387
|
+
return processed
|
|
388
|
+
|
|
389
|
+
raw = self.raw_file
|
|
390
|
+
if isinstance(raw, FieldFile) and raw.name:
|
|
391
|
+
return raw
|
|
392
|
+
|
|
393
|
+
raise ValueError(
|
|
394
|
+
"No active file available. VideoFile has neither raw nor processed file."
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
def active_file_path(self) -> Path:
|
|
399
|
+
"""
|
|
400
|
+
Return the filesystem path of the active video file.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
Path: The path to the processed file if available, otherwise the raw file.
|
|
404
|
+
|
|
405
|
+
Raises:
|
|
406
|
+
ValueError: If neither a processed nor raw file is present.
|
|
407
|
+
"""
|
|
408
|
+
active = self.active_file
|
|
409
|
+
if active is self.processed_file:
|
|
410
|
+
path = _get_processed_file_path(self)
|
|
411
|
+
elif active is self.raw_file:
|
|
412
|
+
path = _get_raw_file_path(self)
|
|
413
|
+
else:
|
|
414
|
+
raise ValueError(
|
|
415
|
+
"No active file path available. VideoFile has neither raw nor processed file."
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
if path is None:
|
|
419
|
+
raise ValueError("Active file path could not be resolved.")
|
|
420
|
+
return path
|
|
421
|
+
|
|
422
|
+
@classmethod
|
|
423
|
+
def create_from_file(
|
|
424
|
+
cls, file_path: Union[str, Path], center_name: str, **kwargs
|
|
425
|
+
) -> Optional["VideoFile"]:
|
|
426
|
+
# Ensure file_path is a Path object
|
|
427
|
+
if isinstance(file_path, str):
|
|
428
|
+
file_path = Path(file_path)
|
|
429
|
+
# Pass center_name and other kwargs to the helper function
|
|
430
|
+
if not center_name:
|
|
431
|
+
try:
|
|
432
|
+
center_name = os.environ["CENTER_NAME"]
|
|
433
|
+
except KeyError:
|
|
434
|
+
logger.error(
|
|
435
|
+
"Center name must be provided to create VideoFile from file. You can set CENTER_NAME in environment variables."
|
|
436
|
+
)
|
|
437
|
+
return None
|
|
438
|
+
return _create_from_file(cls, file_path, center_name=center_name, **kwargs)
|
|
439
|
+
|
|
440
|
+
@classmethod
|
|
441
|
+
def create_from_file_initialized(
|
|
442
|
+
cls,
|
|
443
|
+
file_path: Union[str, Path],
|
|
444
|
+
center_name: str,
|
|
445
|
+
processor_name: Optional[str] = None,
|
|
446
|
+
delete_source: bool = False,
|
|
447
|
+
save_video_file: bool = True, # Add this line
|
|
448
|
+
):
|
|
449
|
+
"""
|
|
450
|
+
Creates a VideoFile instance from a given video file path.
|
|
451
|
+
Handles transcoding (if necessary), hashing, file storage, and database record creation.
|
|
452
|
+
Raises exceptions on failure.
|
|
453
|
+
"""
|
|
454
|
+
# Ensure file_path is a Path object
|
|
455
|
+
if isinstance(file_path, str):
|
|
456
|
+
file_path = Path(file_path)
|
|
457
|
+
|
|
458
|
+
# Call the helper function to create the VideoFile instance
|
|
459
|
+
video_file = _create_from_file(
|
|
460
|
+
cls_model=VideoFile,
|
|
461
|
+
file_path=file_path,
|
|
462
|
+
center_name=center_name,
|
|
463
|
+
processor_name=processor_name,
|
|
464
|
+
delete_source=delete_source,
|
|
465
|
+
save=save_video_file, # Add this line
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
video_file = video_file.initialize()
|
|
469
|
+
return video_file
|
|
470
|
+
|
|
471
|
+
def delete(self, using=None, keep_parents=False) -> tuple[int, dict[str, int]]:
|
|
472
|
+
"""
|
|
473
|
+
Delete the VideoFile instance, including associated files and frames.
|
|
474
|
+
|
|
475
|
+
Overrides the default delete method to ensure proper cleanup of related resources.
|
|
476
|
+
"""
|
|
477
|
+
# Ensure frames are deleted before the main instance
|
|
478
|
+
_delete_frames(self)
|
|
479
|
+
|
|
480
|
+
# Call the original delete method to remove the instance from the database
|
|
481
|
+
active_path = self.active_file_path
|
|
482
|
+
logger.info(f"Deleting VideoFile: {self.uuid} - {active_path}")
|
|
483
|
+
|
|
484
|
+
# Delete associated files if they exist
|
|
485
|
+
if active_path.exists():
|
|
486
|
+
active_path.unlink(missing_ok=True)
|
|
487
|
+
|
|
488
|
+
# Delete file storage
|
|
489
|
+
if self.raw_file and self.raw_file.storage.exists(self.raw_file.name):
|
|
490
|
+
self.raw_file.storage.delete(self.raw_file.name)
|
|
491
|
+
if self.processed_file and self.processed_file.storage.exists(
|
|
492
|
+
self.processed_file.name
|
|
493
|
+
):
|
|
494
|
+
self.processed_file.storage.delete(self.processed_file.name)
|
|
495
|
+
|
|
496
|
+
# Use proper database connection
|
|
497
|
+
if using is None:
|
|
498
|
+
using = "default"
|
|
499
|
+
|
|
500
|
+
raw_file_path = self.get_raw_file_path()
|
|
501
|
+
if raw_file_path:
|
|
502
|
+
raw_file_path = Path(raw_file_path)
|
|
503
|
+
lock_path = raw_file_path.with_suffix(raw_file_path.suffix + ".lock")
|
|
504
|
+
if lock_path.exists():
|
|
505
|
+
try:
|
|
506
|
+
lock_path.unlink()
|
|
507
|
+
logger.info(f"Removed processing lock: {lock_path}")
|
|
508
|
+
except Exception as e:
|
|
509
|
+
logger.warning(f"Could not remove processing lock {lock_path}: {e}")
|
|
510
|
+
|
|
511
|
+
try:
|
|
512
|
+
# Call parent delete with proper parameters
|
|
513
|
+
result = super().delete(using=using, keep_parents=keep_parents)
|
|
514
|
+
logger.info(f"VideoFile {self.uuid} deleted successfully.")
|
|
515
|
+
return result
|
|
516
|
+
except Exception as e:
|
|
517
|
+
logger.error(f"Error deleting VideoFile {self.uuid}: {e}")
|
|
518
|
+
raise
|
|
519
|
+
|
|
520
|
+
def validate_metadata_annotation(
|
|
521
|
+
self, extracted_data_dict: Optional[dict] = None
|
|
522
|
+
) -> bool:
|
|
523
|
+
"""
|
|
524
|
+
Validate the metadata of the VideoFile instance.
|
|
525
|
+
|
|
526
|
+
Called after annotation in the frontend, this method:
|
|
527
|
+
1. Updates sensitive metadata with user-annotated data
|
|
528
|
+
2. Deletes the RAW video file (keeping only the anonymized version)
|
|
529
|
+
3. Marks the video as validated
|
|
530
|
+
|
|
531
|
+
**IMPORTANT:** Only the raw video is deleted. The processed (anonymized)
|
|
532
|
+
video is preserved as the final validated output.
|
|
533
|
+
"""
|
|
534
|
+
from datetime import date as dt_date
|
|
535
|
+
|
|
536
|
+
from endoreg_db.models import SensitiveMeta
|
|
537
|
+
|
|
538
|
+
if not self.sensitive_meta:
|
|
539
|
+
# CRITICAL FIX: Use create_from_dict with default patient data
|
|
540
|
+
default_data = {
|
|
541
|
+
"patient_first_name": "Patient",
|
|
542
|
+
"patient_last_name": "Unknown",
|
|
543
|
+
"patient_dob": dt_date(1990, 1, 1),
|
|
544
|
+
"examination_date": dt_date.today(),
|
|
545
|
+
"center": self.center,
|
|
546
|
+
}
|
|
547
|
+
self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
|
|
548
|
+
|
|
549
|
+
# CRITICAL FIX: Delete RAW video file, not the processed (anonymized) one
|
|
550
|
+
# CRITICAL: Update metadata BEFORE deleting raw video
|
|
551
|
+
# Metadata update may trigger frame extraction, which needs raw video
|
|
552
|
+
sensitive_meta = _update_text_metadata(
|
|
553
|
+
self, extracted_data_dict, overwrite=True
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
# After validation and metadata update, only the anonymized video should remain
|
|
557
|
+
from .video_file_io import _get_raw_file_path
|
|
558
|
+
|
|
559
|
+
raw_path = _get_raw_file_path(self)
|
|
560
|
+
if raw_path and raw_path.exists():
|
|
561
|
+
logger.info(f"Deleting raw video file after validation: {raw_path}")
|
|
562
|
+
raw_path.unlink(missing_ok=True)
|
|
563
|
+
# Clear the raw_file field in database (use delete() to avoid save issues)
|
|
564
|
+
if self.raw_file:
|
|
565
|
+
self.raw_file.delete(save=False)
|
|
566
|
+
logger.info(
|
|
567
|
+
f"Raw video deleted for {self.uuid}. Anonymized video preserved."
|
|
568
|
+
)
|
|
569
|
+
else:
|
|
570
|
+
logger.warning(f"Raw video file not found for deletion: {self.uuid}")
|
|
571
|
+
|
|
572
|
+
if sensitive_meta:
|
|
573
|
+
# Mark as processed after validation
|
|
574
|
+
self.get_or_create_state().mark_sensitive_meta_processed(save=True)
|
|
575
|
+
# Save the VideoFile instance to persist changes
|
|
576
|
+
self.save()
|
|
577
|
+
logger.info(
|
|
578
|
+
f"Metadata annotation validated and saved for video {self.uuid}."
|
|
579
|
+
)
|
|
580
|
+
return True
|
|
581
|
+
else:
|
|
582
|
+
logger.error(
|
|
583
|
+
f"Failed to validate metadata annotation for video {self.uuid}."
|
|
584
|
+
)
|
|
585
|
+
return False
|
|
586
|
+
|
|
587
|
+
def initialize(self):
|
|
588
|
+
"""
|
|
589
|
+
Initialize the VideoFile instance by updating metadata, setting up video specs, assigning frame directory, ensuring related state and sensitive metadata exist, saving the instance, and initializing frames.
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
VideoFile: The initialized VideoFile instance.
|
|
593
|
+
"""
|
|
594
|
+
|
|
595
|
+
self.update_video_meta()
|
|
596
|
+
# Initialize video specs
|
|
597
|
+
self.initialize_video_specs(use_raw=True)
|
|
598
|
+
|
|
599
|
+
# Set the frame directory
|
|
600
|
+
self.set_frame_dir()
|
|
601
|
+
|
|
602
|
+
# Create a new state if it doesn't exist
|
|
603
|
+
self.state = self.get_or_create_state()
|
|
604
|
+
|
|
605
|
+
self.sensitive_meta = self.get_or_create_sensitive_meta()
|
|
606
|
+
self.save()
|
|
607
|
+
# Initialize frames based on the video specs
|
|
608
|
+
self.initialize_frames()
|
|
609
|
+
|
|
610
|
+
return self
|
|
611
|
+
|
|
612
|
+
def __str__(self):
|
|
613
|
+
"""
|
|
614
|
+
Return a human-readable string summarizing the video's state, active file name, and UUID.
|
|
615
|
+
"""
|
|
616
|
+
active_path = self.active_file_path
|
|
617
|
+
file_name = active_path.name if active_path else "No file"
|
|
618
|
+
state = (
|
|
619
|
+
"Processed" if self.is_processed else ("Raw" if self.has_raw else "No File")
|
|
620
|
+
)
|
|
621
|
+
return f"VideoFile ({state}): {file_name} (UUID: {self.uuid})"
|
|
622
|
+
|
|
623
|
+
# --- Convenience state/meta helpers used in tests and admin workflows ---
|
|
624
|
+
def mark_sensitive_meta_processed(self, *, save: bool = True) -> "VideoFile":
|
|
625
|
+
"""
|
|
626
|
+
Mark this video's processing state as having its sensitive meta fully processed.
|
|
627
|
+
This proxies to the related VideoState and persists by default.
|
|
628
|
+
"""
|
|
629
|
+
state = self.get_or_create_state()
|
|
630
|
+
state.mark_sensitive_meta_processed(save=save)
|
|
631
|
+
return self
|
|
632
|
+
|
|
633
|
+
def mark_sensitive_meta_verified(self) -> "VideoFile":
|
|
634
|
+
"""
|
|
635
|
+
Mark the associated SensitiveMeta as verified by setting both DOB and names as verified.
|
|
636
|
+
Ensures the SensitiveMeta and its state exist.
|
|
637
|
+
"""
|
|
638
|
+
sm = self.get_or_create_sensitive_meta()
|
|
639
|
+
# Use SensitiveMeta methods to update underlying SensitiveMetaState
|
|
640
|
+
sm.mark_dob_verified()
|
|
641
|
+
sm.mark_names_verified()
|
|
642
|
+
return self
|
|
643
|
+
|
|
644
|
+
def save(self, *args, **kwargs):
|
|
645
|
+
# Ensure state exists or is created before the main save operation
|
|
646
|
+
# Now call the original save method
|
|
647
|
+
"""
|
|
648
|
+
Saves the VideoFile instance to the database.
|
|
649
|
+
|
|
650
|
+
Overrides the default save method to persist changes to the VideoFile model.
|
|
651
|
+
"""
|
|
652
|
+
super().save(*args, **kwargs)
|
|
653
|
+
|
|
654
|
+
def get_or_create_state(self) -> "VideoState":
|
|
655
|
+
"""Ensure this video has a persisted ``VideoState`` and return it."""
|
|
656
|
+
|
|
657
|
+
state = self.state
|
|
658
|
+
|
|
659
|
+
# When tests reuse cached instances across database flushes, ``state`` may reference
|
|
660
|
+
# a row that no longer exists. Guard against that by validating persistence.
|
|
661
|
+
state_pk = getattr(state, "pk", None)
|
|
662
|
+
if state is not None and state_pk is not None:
|
|
663
|
+
if not VideoState.objects.filter(pk=state_pk).exists():
|
|
664
|
+
state = None
|
|
665
|
+
|
|
666
|
+
if state is None:
|
|
667
|
+
# Create a fresh state to avoid refresh_from_db() failures on unsaved instances.
|
|
668
|
+
state = VideoState.objects.create()
|
|
669
|
+
self.state = state
|
|
670
|
+
|
|
671
|
+
# Persist the relation immediately if the VideoFile already exists in the DB so
|
|
672
|
+
# later refreshes see the association without requiring additional saves.
|
|
673
|
+
if self.pk:
|
|
674
|
+
self.save(update_fields=["state"])
|
|
675
|
+
|
|
676
|
+
return state
|
|
677
|
+
|
|
678
|
+
def get_or_create_sensitive_meta(self) -> "SensitiveMeta":
|
|
679
|
+
"""
|
|
680
|
+
Retrieve the associated SensitiveMeta instance for this video, creating and assigning one if it does not exist.
|
|
681
|
+
|
|
682
|
+
**Two-Phase Patient Data Pattern:**
|
|
683
|
+
This method implements a two-phase approach to handle incomplete patient data:
|
|
684
|
+
|
|
685
|
+
**Phase 1: Initial Creation (with defaults)**
|
|
686
|
+
- Creates SensitiveMeta with default patient data to prevent hash calculation errors
|
|
687
|
+
- Default values: patient_first_name="Patient", patient_last_name="Unknown", patient_dob=1990-01-01
|
|
688
|
+
- Allows video import to proceed even without extracted patient data
|
|
689
|
+
- Temporary hash and pseudo-entities are created
|
|
690
|
+
|
|
691
|
+
**Phase 2: Update (with extracted data)**
|
|
692
|
+
- Real patient data is extracted later (e.g., from video OCR via lx_anonymizer)
|
|
693
|
+
- update_from_dict() is called with actual patient information
|
|
694
|
+
- Hash is recalculated automatically using real data
|
|
695
|
+
- Correct pseudo-entities are created/linked based on new hash
|
|
696
|
+
|
|
697
|
+
**Example workflow:**
|
|
698
|
+
```python
|
|
699
|
+
# Phase 1: Video creation
|
|
700
|
+
video = VideoFile.create_from_file_initialized(...)
|
|
701
|
+
video.initialize() # Calls this method
|
|
702
|
+
# → SensitiveMeta created with defaults
|
|
703
|
+
# → Hash: sha256("Patient Unknown 1990-01-01...")
|
|
704
|
+
|
|
705
|
+
# Phase 2: Frame cleaning extracts real data
|
|
706
|
+
extracted = {"patient_first_name": "Max", "patient_last_name": "Mustermann", ...}
|
|
707
|
+
video.sensitive_meta.update_from_dict(extracted)
|
|
708
|
+
# → Hash: sha256("Max Mustermann 1985-03-15...") (RECALCULATED)
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
Returns:
|
|
712
|
+
SensitiveMeta: The related SensitiveMeta instance.
|
|
713
|
+
|
|
714
|
+
See Also:
|
|
715
|
+
- sensitive_meta_logic.perform_save_logic() for hash calculation details
|
|
716
|
+
- sensitive_meta_logic.update_sensitive_meta_from_dict() for update mechanism
|
|
717
|
+
"""
|
|
718
|
+
from datetime import date as dt_date
|
|
719
|
+
|
|
720
|
+
from endoreg_db.models import SensitiveMeta
|
|
721
|
+
|
|
722
|
+
if self.sensitive_meta is None:
|
|
723
|
+
# Use create_from_dict with default patient data
|
|
724
|
+
# to prevent "First name is required to calculate patient hash" error
|
|
725
|
+
default_data = {
|
|
726
|
+
"patient_first_name": "Patient",
|
|
727
|
+
"patient_last_name": "Unknown",
|
|
728
|
+
"patient_dob": dt_date(1990, 1, 1),
|
|
729
|
+
"examination_date": dt_date.today(),
|
|
730
|
+
"center": self.center,
|
|
731
|
+
}
|
|
732
|
+
self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
|
|
733
|
+
self.save(update_fields=["sensitive_meta"])
|
|
734
|
+
# Do not mark state as processed here; it will be set after extraction/validation steps
|
|
735
|
+
return self.sensitive_meta
|
|
736
|
+
|
|
737
|
+
def get_outside_segments(
|
|
738
|
+
self, only_validated: bool = False
|
|
739
|
+
) -> models.QuerySet["LabelVideoSegment"]:
|
|
740
|
+
"""
|
|
741
|
+
Return all video segments labeled as "outside" for this video.
|
|
742
|
+
|
|
743
|
+
Parameters:
|
|
744
|
+
only_validated (bool): If True, only segments with a validated state are included.
|
|
745
|
+
|
|
746
|
+
Returns:
|
|
747
|
+
QuerySet: A queryset of LabelVideoSegment instances labeled as "outside". Returns an empty queryset if the label does not exist or an error occurs.
|
|
748
|
+
"""
|
|
749
|
+
try:
|
|
750
|
+
outside_label = Label.objects.get(name__iexact="outside")
|
|
751
|
+
segments = self.label_video_segments.filter(label=outside_label)
|
|
752
|
+
|
|
753
|
+
if only_validated:
|
|
754
|
+
# Filter based on the is_validated field in the related state object
|
|
755
|
+
segments = segments.filter(state__is_validated=True)
|
|
756
|
+
|
|
757
|
+
return segments
|
|
758
|
+
except Label.DoesNotExist:
|
|
759
|
+
logger.warning("Outside label not found in the database.")
|
|
760
|
+
return self.label_video_segments.none()
|
|
761
|
+
except Exception as e:
|
|
762
|
+
logger.error(
|
|
763
|
+
"Error getting outside segments for video %s: %s",
|
|
764
|
+
self.uuid,
|
|
765
|
+
e,
|
|
766
|
+
exc_info=True,
|
|
767
|
+
)
|
|
768
|
+
return self.label_video_segments.none()
|
|
769
|
+
|
|
770
|
+
@classmethod
|
|
771
|
+
def get_all_videos(cls) -> models.QuerySet["VideoFile"]:
|
|
772
|
+
"""
|
|
773
|
+
Returns a queryset containing all VideoFile records.
|
|
774
|
+
|
|
775
|
+
This class method retrieves every VideoFile instance in the database without filtering.
|
|
776
|
+
"""
|
|
777
|
+
return cast(models.QuerySet["VideoFile"], cls.objects.all())
|
|
778
|
+
|
|
779
|
+
def count_unmodified_others(self) -> int:
|
|
780
|
+
"""
|
|
781
|
+
Count the number of other VideoFile instances that have not been modified since creation.
|
|
782
|
+
|
|
783
|
+
Returns:
|
|
784
|
+
int: The count of VideoFile records, excluding this instance, where the modification timestamp matches the creation timestamp.
|
|
785
|
+
"""
|
|
786
|
+
return (
|
|
787
|
+
VideoFile.objects.filter(
|
|
788
|
+
date_modified=F("date_created")
|
|
789
|
+
) # compare the two fields in SQL
|
|
790
|
+
.exclude(pk=self.pk) # exclude this instance
|
|
791
|
+
.count() # run a fast COUNT(*) on the filtered set
|
|
792
|
+
)
|
|
793
|
+
|
|
794
|
+
def frame_number_to_s(self, frame_number: int) -> float:
|
|
795
|
+
"""
|
|
796
|
+
Convert a frame number to its corresponding time in seconds based on the video's frames per second (FPS).
|
|
797
|
+
|
|
798
|
+
Parameters:
|
|
799
|
+
frame_number (int): The frame number to convert.
|
|
800
|
+
|
|
801
|
+
Returns:
|
|
802
|
+
float: The time in seconds corresponding to the given frame number.
|
|
803
|
+
|
|
804
|
+
Raises:
|
|
805
|
+
ValueError: If the video's FPS is not set or is less than or equal to zero.
|
|
806
|
+
"""
|
|
807
|
+
fps = self.get_fps()
|
|
808
|
+
if fps is None or fps <= 0:
|
|
809
|
+
raise ValueError("FPS must be set and greater than zero.")
|
|
810
|
+
return frame_number / fps
|
|
811
|
+
|
|
812
|
+
def get_video_by_id(self, video_id: int) -> "VideoFile":
|
|
813
|
+
"""
|
|
814
|
+
Retrieve a VideoFile instance by its primary key (ID).
|
|
815
|
+
|
|
816
|
+
Parameters:
|
|
817
|
+
video_id (int): The primary key of the VideoFile to retrieve.
|
|
818
|
+
|
|
819
|
+
Returns:
|
|
820
|
+
VideoFile: The VideoFile instance with the specified ID.
|
|
821
|
+
|
|
822
|
+
Raises:
|
|
823
|
+
VideoFile.DoesNotExist: If no VideoFile with the given ID exists.
|
|
824
|
+
"""
|
|
825
|
+
return self.objects.get(pk=video_id)
|