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,288 @@
|
|
|
1
|
+
# endoreg_db/services/polling_coordinator.py
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import threading
|
|
5
|
+
from typing import Dict, Optional
|
|
6
|
+
from django.core.cache import cache
|
|
7
|
+
from django.utils import timezone
|
|
8
|
+
from datetime import timedelta
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class PollingCoordinator:
|
|
13
|
+
"""
|
|
14
|
+
Service to prevent duplicate polling operations on the same media items.
|
|
15
|
+
Uses Django cache and thread-safe operations to coordinate polling requests.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# Class-level lock for thread safety
|
|
19
|
+
_lock = threading.Lock()
|
|
20
|
+
|
|
21
|
+
# Cache key prefixes
|
|
22
|
+
PROCESSING_PREFIX = "polling_processing:"
|
|
23
|
+
LAST_CHECK_PREFIX = "polling_last_check:"
|
|
24
|
+
|
|
25
|
+
# Default timeouts
|
|
26
|
+
PROCESSING_TIMEOUT = 300 # 5 minutes
|
|
27
|
+
CHECK_COOLDOWN = 10 # 10 seconds minimum between checks
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def acquire_processing_lock(cls, file_id: int, file_type: str = "video", timeout: Optional[int] = None) -> bool:
|
|
31
|
+
"""
|
|
32
|
+
Acquire a processing lock for a media file to prevent duplicate processing.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
file_id: ID of the media file
|
|
36
|
+
file_type: Type of media (video, pdf)
|
|
37
|
+
timeout: Lock timeout in seconds (default: 5 minutes)
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
True if lock acquired, False if already locked
|
|
41
|
+
"""
|
|
42
|
+
if timeout is None:
|
|
43
|
+
timeout = cls.PROCESSING_TIMEOUT
|
|
44
|
+
|
|
45
|
+
cache_key = f"{cls.PROCESSING_PREFIX}{file_type}:{file_id}"
|
|
46
|
+
|
|
47
|
+
with cls._lock:
|
|
48
|
+
# Try to acquire lock atomically
|
|
49
|
+
lock_acquired = cache.add(cache_key, {
|
|
50
|
+
"locked_at": timezone.now().isoformat(),
|
|
51
|
+
"file_id": file_id,
|
|
52
|
+
"file_type": file_type,
|
|
53
|
+
"thread_id": threading.get_ident()
|
|
54
|
+
}, timeout)
|
|
55
|
+
|
|
56
|
+
if lock_acquired:
|
|
57
|
+
logger.info(f"Processing lock acquired for {file_type}:{file_id}")
|
|
58
|
+
return True
|
|
59
|
+
else:
|
|
60
|
+
# Check if existing lock is stale
|
|
61
|
+
existing_lock = cache.get(cache_key)
|
|
62
|
+
if existing_lock:
|
|
63
|
+
logger.warning(f"Processing lock already exists for {file_type}:{file_id}: {existing_lock}")
|
|
64
|
+
else:
|
|
65
|
+
logger.warning(f"Failed to acquire processing lock for {file_type}:{file_id}")
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def release_processing_lock(cls, file_id: int, file_type: str = "video") -> bool:
|
|
70
|
+
"""
|
|
71
|
+
Release a processing lock for a media file.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
file_id: ID of the media file
|
|
75
|
+
file_type: Type of media (video, pdf)
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
True if lock released, False if lock didn't exist
|
|
79
|
+
"""
|
|
80
|
+
cache_key = f"{cls.PROCESSING_PREFIX}{file_type}:{file_id}"
|
|
81
|
+
|
|
82
|
+
with cls._lock:
|
|
83
|
+
if cache.delete(cache_key):
|
|
84
|
+
logger.info(f"Processing lock released for {file_type}:{file_id}")
|
|
85
|
+
return True
|
|
86
|
+
else:
|
|
87
|
+
logger.warning(f"No processing lock found to release for {file_type}:{file_id}")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def is_processing_locked(cls, file_id: int, file_type: str = "video") -> bool:
|
|
92
|
+
"""
|
|
93
|
+
Check if a media file is currently processing locked.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
file_id: ID of the media file
|
|
97
|
+
file_type: Type of media (video, pdf)
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
True if locked, False otherwise
|
|
101
|
+
"""
|
|
102
|
+
cache_key = f"{cls.PROCESSING_PREFIX}{file_type}:{file_id}"
|
|
103
|
+
return cache.get(cache_key) is not None
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def can_check_status(cls, file_id: int, file_type: str = "video") -> bool:
|
|
107
|
+
"""
|
|
108
|
+
Check if enough time has passed since last status check to prevent spam.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
file_id: ID of the media file
|
|
112
|
+
file_type: Type of media (video, pdf)
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
True if status check is allowed, False if still in cooldown
|
|
116
|
+
"""
|
|
117
|
+
cache_key = f"{cls.LAST_CHECK_PREFIX}{file_type}:{file_id}"
|
|
118
|
+
last_check = cache.get(cache_key)
|
|
119
|
+
|
|
120
|
+
if last_check is None:
|
|
121
|
+
# First check or cooldown expired - allowed
|
|
122
|
+
cls._record_status_check(file_id, file_type)
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
# Check if cooldown period has passed
|
|
126
|
+
last_check_time = timezone.datetime.fromisoformat(last_check.replace('Z', '+00:00'))
|
|
127
|
+
cooldown_end = last_check_time + timedelta(seconds=cls.CHECK_COOLDOWN)
|
|
128
|
+
|
|
129
|
+
if timezone.now() > cooldown_end:
|
|
130
|
+
cls._record_status_check(file_id, file_type)
|
|
131
|
+
return True
|
|
132
|
+
else:
|
|
133
|
+
remaining_cooldown = (cooldown_end - timezone.now()).total_seconds()
|
|
134
|
+
logger.debug(f"Status check cooldown active for {file_type}:{file_id}, {remaining_cooldown:.1f}s remaining")
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def get_remaining_cooldown_seconds(cls, file_id: int, file_type: str = "video") -> int:
|
|
139
|
+
"""
|
|
140
|
+
Get the remaining cooldown seconds for a status check.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
file_id: ID of the media file
|
|
144
|
+
file_type: Type of media (video, pdf)
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Remaining cooldown in seconds (0 if no cooldown active)
|
|
148
|
+
"""
|
|
149
|
+
cache_key = f"{cls.LAST_CHECK_PREFIX}{file_type}:{file_id}"
|
|
150
|
+
last_check = cache.get(cache_key)
|
|
151
|
+
|
|
152
|
+
if last_check is None:
|
|
153
|
+
return 0
|
|
154
|
+
|
|
155
|
+
# Check if cooldown period has passed
|
|
156
|
+
last_check_time = timezone.datetime.fromisoformat(last_check.replace('Z', '+00:00'))
|
|
157
|
+
cooldown_end = last_check_time + timedelta(seconds=cls.CHECK_COOLDOWN)
|
|
158
|
+
|
|
159
|
+
if timezone.now() > cooldown_end:
|
|
160
|
+
return 0
|
|
161
|
+
else:
|
|
162
|
+
remaining_cooldown = (cooldown_end - timezone.now()).total_seconds()
|
|
163
|
+
# Round up to at least 1 second
|
|
164
|
+
return max(1, int(remaining_cooldown) + 1)
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def _record_status_check(cls, file_id: int, file_type: str = "video") -> None:
|
|
168
|
+
"""Record the time of a status check"""
|
|
169
|
+
cache_key = f"{cls.LAST_CHECK_PREFIX}{file_type}:{file_id}"
|
|
170
|
+
cache.set(cache_key, timezone.now().isoformat(), cls.CHECK_COOLDOWN + 5)
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def get_processing_locks_info(cls) -> Dict[str, any]:
|
|
174
|
+
"""
|
|
175
|
+
Get information about all currently active processing locks.
|
|
176
|
+
Useful for debugging and monitoring.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Dictionary with lock information
|
|
180
|
+
"""
|
|
181
|
+
# Note: This is a simplified version since Django cache doesn't support pattern scanning
|
|
182
|
+
# In production, consider using Redis with SCAN command for better performance
|
|
183
|
+
|
|
184
|
+
info = {
|
|
185
|
+
"coordinator_status": "active",
|
|
186
|
+
"config": {
|
|
187
|
+
"processing_timeout": cls.PROCESSING_TIMEOUT,
|
|
188
|
+
"check_cooldown": cls.CHECK_COOLDOWN
|
|
189
|
+
},
|
|
190
|
+
"note": "Active locks info requires Redis backend for pattern scanning"
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return info
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def clear_all_locks(cls, file_type: Optional[str] = None) -> int:
|
|
197
|
+
"""
|
|
198
|
+
Emergency function to clear all processing locks.
|
|
199
|
+
Use with caution - only for debugging/recovery scenarios.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
file_type: Optionally clear locks only for specific file type
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
Number of locks cleared (approximation)
|
|
206
|
+
"""
|
|
207
|
+
logger.warning("clear_all_locks called - this should only be used for debugging/recovery")
|
|
208
|
+
|
|
209
|
+
# This is a simplified implementation
|
|
210
|
+
# In production with Redis, you'd use SCAN to find and delete matching keys
|
|
211
|
+
if hasattr(cache, 'clear'):
|
|
212
|
+
cache.clear()
|
|
213
|
+
return -1 # Unknown count
|
|
214
|
+
else:
|
|
215
|
+
logger.warning("Cache backend doesn't support pattern deletion")
|
|
216
|
+
return 0
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# Decorator for views that need processing coordination
|
|
220
|
+
def processing_coordination(file_id_param: str = "file_id", file_type: str = "video"):
|
|
221
|
+
"""
|
|
222
|
+
Decorator to add automatic processing coordination to views.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
file_id_param: Name of the parameter containing file ID
|
|
226
|
+
file_type: Type of media file
|
|
227
|
+
"""
|
|
228
|
+
def decorator(view_func):
|
|
229
|
+
def wrapper(request, *args, **kwargs):
|
|
230
|
+
# Extract file_id from kwargs or request
|
|
231
|
+
file_id = kwargs.get(file_id_param) or request.data.get(file_id_param)
|
|
232
|
+
|
|
233
|
+
if file_id is None:
|
|
234
|
+
logger.error(f"No {file_id_param} found in request for processing coordination")
|
|
235
|
+
from rest_framework.response import Response
|
|
236
|
+
from rest_framework import status
|
|
237
|
+
return Response(
|
|
238
|
+
{"error": f"Missing {file_id_param} parameter"},
|
|
239
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Check if processing is already locked
|
|
243
|
+
if PollingCoordinator.is_processing_locked(file_id, file_type):
|
|
244
|
+
from rest_framework.response import Response
|
|
245
|
+
from rest_framework import status
|
|
246
|
+
return Response(
|
|
247
|
+
{"detail": "File is currently being processed by another request"},
|
|
248
|
+
status=status.HTTP_409_CONFLICT
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Proceed with the view
|
|
252
|
+
return view_func(request, *args, **kwargs)
|
|
253
|
+
|
|
254
|
+
return wrapper
|
|
255
|
+
return decorator
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# Context manager for automatic lock management
|
|
259
|
+
class ProcessingLockContext:
|
|
260
|
+
"""
|
|
261
|
+
Context manager for automatic processing lock acquisition and release.
|
|
262
|
+
|
|
263
|
+
Usage:
|
|
264
|
+
with ProcessingLockContext(file_id, "video") as lock:
|
|
265
|
+
if lock.acquired:
|
|
266
|
+
# Perform processing
|
|
267
|
+
pass
|
|
268
|
+
else:
|
|
269
|
+
# Handle lock acquisition failure
|
|
270
|
+
pass
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
def __init__(self, file_id: int, file_type: str = "video", timeout: Optional[int] = None):
|
|
274
|
+
self.file_id = file_id
|
|
275
|
+
self.file_type = file_type
|
|
276
|
+
self.timeout = timeout
|
|
277
|
+
self.acquired = False
|
|
278
|
+
|
|
279
|
+
def __enter__(self):
|
|
280
|
+
self.acquired = PollingCoordinator.acquire_processing_lock(
|
|
281
|
+
self.file_id, self.file_type, self.timeout
|
|
282
|
+
)
|
|
283
|
+
return self
|
|
284
|
+
|
|
285
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
286
|
+
if self.acquired:
|
|
287
|
+
PollingCoordinator.release_processing_lock(self.file_id, self.file_type)
|
|
288
|
+
return False # Don't suppress exceptions
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service for generating patient pseudonyms using SensitiveMeta logic.
|
|
3
|
+
"""
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Tuple, List
|
|
6
|
+
from django.db import transaction
|
|
7
|
+
|
|
8
|
+
from endoreg_db.models.administration.person.patient.patient import Patient
|
|
9
|
+
from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
|
|
10
|
+
from endoreg_db.models.metadata import sensitive_meta_logic as logic
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def generate_patient_pseudonym(patient: Patient) -> Tuple[str, bool]:
|
|
16
|
+
"""
|
|
17
|
+
Generate a pseudonym hash for an existing Patient using SensitiveMeta logic.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
patient: The Patient instance to generate a pseudonym for
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple of (patient_hash, persisted_flag)
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: If required fields are missing for hash calculation
|
|
27
|
+
"""
|
|
28
|
+
# Validate required fields for hash calculation
|
|
29
|
+
if not patient.dob:
|
|
30
|
+
raise ValueError("Patient date of birth (dob) is required for pseudonym generation")
|
|
31
|
+
|
|
32
|
+
if not patient.center:
|
|
33
|
+
raise ValueError("Patient center is required for pseudonym generation")
|
|
34
|
+
|
|
35
|
+
# Use existing patient_hash if it exists and is valid
|
|
36
|
+
if patient.patient_hash and len(patient.patient_hash.strip()) > 0:
|
|
37
|
+
logger.info(f"Patient {patient.id} already has a hash: {patient.patient_hash}")
|
|
38
|
+
return patient.patient_hash, True
|
|
39
|
+
|
|
40
|
+
# Create a transient SensitiveMeta instance to calculate the hash
|
|
41
|
+
# We don't save this instance, just use it for hash calculation
|
|
42
|
+
sensitive_meta = SensitiveMeta(
|
|
43
|
+
patient_first_name=patient.first_name or "",
|
|
44
|
+
patient_last_name=patient.last_name or "",
|
|
45
|
+
patient_dob=patient.dob,
|
|
46
|
+
center=patient.center,
|
|
47
|
+
patient_gender=patient.gender # Optional, but include if available
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# Calculate the hash using the existing logic
|
|
52
|
+
patient_hash = logic.calculate_patient_hash(sensitive_meta, salt=logic.SECRET_SALT)
|
|
53
|
+
|
|
54
|
+
# Persist the hash to the Patient model
|
|
55
|
+
with transaction.atomic():
|
|
56
|
+
patient.patient_hash = patient_hash
|
|
57
|
+
patient.save(update_fields=['patient_hash'])
|
|
58
|
+
|
|
59
|
+
logger.info(f"Generated and persisted pseudonym for patient {patient.id}")
|
|
60
|
+
|
|
61
|
+
return patient_hash, True
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"Error generating pseudonym for patient {patient.id}: {str(e)}")
|
|
65
|
+
raise ValueError(f"Failed to generate pseudonym: {str(e)}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def validate_patient_for_pseudonym(patient: Patient) -> list[str]:
|
|
69
|
+
"""
|
|
70
|
+
Validate that a patient has all required fields for pseudonym generation.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
patient: The Patient instance to validate
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
List of missing required fields (empty if all fields present)
|
|
77
|
+
"""
|
|
78
|
+
missing_fields = []
|
|
79
|
+
|
|
80
|
+
if not patient.dob:
|
|
81
|
+
missing_fields.append("dob")
|
|
82
|
+
|
|
83
|
+
if not patient.center:
|
|
84
|
+
missing_fields.append("center")
|
|
85
|
+
|
|
86
|
+
# Note: first_name and last_name can be empty strings according to the logic,
|
|
87
|
+
# so we don't require them to be non-empty
|
|
88
|
+
|
|
89
|
+
return missing_fields
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from ast import List
|
|
2
|
+
import pickle
|
|
3
|
+
from endoreg_db.models import Requirement, Examination, PatientExamination
|
|
4
|
+
from endoreg_db.serializers import PatientExaminationSerializer, ExaminationSerializer, FindingClassificationSerializer, RequirementSerializer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LookupService:
|
|
8
|
+
def __init__(self, db_session):
|
|
9
|
+
self.db_session = db_session
|
|
10
|
+
self.hexdict = int()
|
|
11
|
+
|
|
12
|
+
def hash_lookup(self, key, value):
|
|
13
|
+
"""
|
|
14
|
+
Store a key-value pair in the lookup dictionary.
|
|
15
|
+
"""
|
|
16
|
+
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
17
|
+
lookup_dict[key] = value
|
|
18
|
+
self.hexdict = pickle.dumps(dict).hex()
|
|
19
|
+
return True
|
|
20
|
+
def hash_retrieve(self, key):
|
|
21
|
+
"""
|
|
22
|
+
Retrieve a value by key from the lookup dictionary.
|
|
23
|
+
"""
|
|
24
|
+
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
25
|
+
return lookup_dict.get(key, None)
|
|
26
|
+
|
|
27
|
+
def hash_add_key_value(self, key, value):
|
|
28
|
+
"""
|
|
29
|
+
Add a key-value pair to the lookup dictionary.
|
|
30
|
+
"""
|
|
31
|
+
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
32
|
+
lookup_dict[key] = value
|
|
33
|
+
self.hexdict = pickle.dumps(lookup_dict).hex()
|
|
34
|
+
return True
|
|
35
|
+
|
|
36
|
+
def hash_dehash(self):
|
|
37
|
+
"""
|
|
38
|
+
Retrieve the entire lookup dictionary.
|
|
39
|
+
"""
|
|
40
|
+
lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
|
|
41
|
+
return lookup_dict
|
|
42
|
+
|
|
43
|
+
def fetch_examination_dict(self, patient_id, tags: List[str] = None):
|
|
44
|
+
"""
|
|
45
|
+
Fetch examinations for a given patient ID, optionally filtered by tags.
|
|
46
|
+
"""
|
|
47
|
+
query = self.db_session.query(Examination).filter(Examination.patient_id == patient_id)
|
|
48
|
+
if tags:
|
|
49
|
+
query = query.filter(Examination.tags.any(Examination.tags.in_(tags)))
|
|
50
|
+
examinations = query.all()
|
|
51
|
+
return [ExaminationSerializer(exam).data for exam in examinations]
|
|
52
|
+
|
|
53
|
+
def fetch_patient_examination_by_id(self, patient_id, examination_id):
|
|
54
|
+
"""
|
|
55
|
+
Fetch a patient examination object from the database by its ID.
|
|
56
|
+
"""
|
|
57
|
+
return self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
|
|
58
|
+
|
|
59
|
+
def fetch_patient_examinations(self, patient_id):
|
|
60
|
+
"""
|
|
61
|
+
Fetch all patient examinations for a given patient ID.
|
|
62
|
+
"""
|
|
63
|
+
examinations = self.db_session.query(PatientExamination).filter(PatientExamination.patient_id == patient_id).all()
|
|
64
|
+
return [PatientExaminationSerializer(exam).data for exam in examinations]
|
|
65
|
+
|
|
66
|
+
def fetch_findings_by_patient_examination(self, patient_examination_id):
|
|
67
|
+
"""
|
|
68
|
+
Fetch findings associated with a given patient examination ID.
|
|
69
|
+
"""
|
|
70
|
+
patient_examination = self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
|
|
71
|
+
if not patient_examination:
|
|
72
|
+
return []
|
|
73
|
+
return [finding.serialize() for finding in patient_examination.findings]
|
|
74
|
+
|
|
75
|
+
def fetch_classifications_by_finding(self, finding_id):
|
|
76
|
+
"""
|
|
77
|
+
Fetch classifications associated with a given finding ID.
|
|
78
|
+
"""
|
|
79
|
+
finding = self.db_session.query(Finding).filter(Finding.id == finding_id).first()
|
|
80
|
+
if not finding:
|
|
81
|
+
return []
|
|
82
|
+
return [classification.serialize() for classification in finding.classifications]
|
|
83
|
+
|
|
84
|
+
def fetch_default_finding_classification(self):
|
|
85
|
+
"""
|
|
86
|
+
Fetch the default finding classification from the database.
|
|
87
|
+
"""
|
|
88
|
+
return self.db_session.query(FindingClassification).filter(FindingClassification.is_default == True).first()
|
|
89
|
+
|
|
90
|
+
def fetch_finding_classification_choice_by_requirement(self, requirement_id):
|
|
91
|
+
"""
|
|
92
|
+
Retrieve finding classification choices based on the provided requirement ID.
|
|
93
|
+
"""
|
|
94
|
+
requirement = self.get_requirement_by_id(requirement_id)
|
|
95
|
+
if not requirement:
|
|
96
|
+
return []
|
|
97
|
+
return [choice.serialize() for choice in requirement.finding_classification_choices]
|
|
98
|
+
|
|
99
|
+
def fetch_requirement_choices_by_requirement(self, requirement_id):
|
|
100
|
+
"""
|
|
101
|
+
Retrieve requirement choices based on the provided requirement ID.
|
|
102
|
+
"""
|
|
103
|
+
requirement = self.get_requirement_by_id(requirement_id)
|
|
104
|
+
if not requirement:
|
|
105
|
+
return []
|
|
106
|
+
return [choice.serialize() for choice in requirement.requirement_choices]
|
|
107
|
+
|
|
108
|
+
def available_finding_classification_choices_by_finding_classification(self, finding_classification):
|
|
109
|
+
"""
|
|
110
|
+
Retrieve available finding classification choices based on the provided finding classification.
|
|
111
|
+
"""
|
|
112
|
+
return self.db_session.query(FindingClassificationChoice).filter(
|
|
113
|
+
FindingClassificationChoice.finding_classification_id == finding_classification.id
|
|
114
|
+
).all()
|
|
115
|
+
|
|
116
|
+
def get_requirement_by_id(self, requirement_id):
|
|
117
|
+
"""
|
|
118
|
+
Fetch a requirement object from the database by its ID.
|
|
119
|
+
"""
|
|
120
|
+
return self.db_session.query(Requirement).filter(Requirement.id == requirement_id).first()
|
|
121
|
+
|
|
122
|
+
def get_all_requirements_for_requirement_sets(self, requirement_set_ids: List[int]):
|
|
123
|
+
"""
|
|
124
|
+
Fetch all requirements associated with the given requirement set IDs.
|
|
125
|
+
"""
|
|
126
|
+
return self.db_session.query(Requirement).filter(Requirement.requirement_set_id.in_(requirement_set_ids)).all()
|
|
127
|
+
|
|
128
|
+
def get_all_requirement_sets_for_examination(self, examination_id):
|
|
129
|
+
"""
|
|
130
|
+
Fetch all requirement sets associated with the given examination ID.
|
|
131
|
+
"""
|
|
132
|
+
examination = self.db_session.query(Examination).filter(Examination.id == examination_id).first()
|
|
133
|
+
if not examination:
|
|
134
|
+
return []
|
|
135
|
+
return [req_set.serialize() for req_set in examination.requirement_sets]
|
|
136
|
+
|
|
137
|
+
def serialize_requirement(self, requirement):
|
|
138
|
+
"""
|
|
139
|
+
Serialize a requirement object to a byte stream.
|
|
140
|
+
"""
|
|
141
|
+
return pickle.dumps(requirement)
|
|
142
|
+
|
|
143
|
+
def deserialize_requirement(self, serialized_requirement):
|
|
144
|
+
"""
|
|
145
|
+
Deserialize a byte stream back to a requirement object.
|
|
146
|
+
"""
|
|
147
|
+
return pickle.loads(serialized_requirement)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service for synchronizing annotation updates with LabelVideoSegment creation.
|
|
3
|
+
|
|
4
|
+
This module provides functionality to create user-source LabelVideoSegments
|
|
5
|
+
when segment annotations are created or updated.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Optional, Dict, Any
|
|
10
|
+
from django.contrib.auth.models import User
|
|
11
|
+
from django.db import transaction
|
|
12
|
+
|
|
13
|
+
from ..models import VideoFile, Label, LabelVideoSegment, InformationSource
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_user_segment_from_annotation(annotation: Dict[str, Any], request_user: User) -> Optional[LabelVideoSegment]:
|
|
19
|
+
"""
|
|
20
|
+
Create a user-source LabelVideoSegment from a segment annotation.
|
|
21
|
+
|
|
22
|
+
This function:
|
|
23
|
+
1. Locates the original LabelVideoSegment (if segmentId is present)
|
|
24
|
+
2. Clones all its DB fields
|
|
25
|
+
3. Overwrites with new data from annotation
|
|
26
|
+
4. Sets information_source = user
|
|
27
|
+
5. Saves via model manager
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
annotation: Annotation data containing segment information
|
|
31
|
+
request_user: The authenticated user making the request
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
New LabelVideoSegment instance or None if creation failed/skipped
|
|
35
|
+
"""
|
|
36
|
+
# Validate this is a segment annotation
|
|
37
|
+
if annotation.get('type') != 'segment':
|
|
38
|
+
logger.debug("Annotation is not a segment type, skipping user segment creation")
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
# Get required data from annotation
|
|
42
|
+
video_id = annotation.get('videoId')
|
|
43
|
+
start_time = annotation.get('startTime')
|
|
44
|
+
end_time = annotation.get('endTime')
|
|
45
|
+
label_text = annotation.get('text', '').strip()
|
|
46
|
+
metadata = annotation.get('metadata', {})
|
|
47
|
+
original_segment_id = metadata.get('segmentId')
|
|
48
|
+
|
|
49
|
+
if not all([video_id, start_time is not None, end_time is not None]):
|
|
50
|
+
logger.warning("Missing required segment data in annotation, skipping user segment creation")
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# Get the video file
|
|
55
|
+
video_file = VideoFile.objects.get(id=video_id)
|
|
56
|
+
|
|
57
|
+
# Get video FPS for frame calculation
|
|
58
|
+
fps = video_file.get_fps()
|
|
59
|
+
if not fps or fps <= 0:
|
|
60
|
+
logger.warning(f"Invalid FPS ({fps}) for video {video_id}, using default 25")
|
|
61
|
+
fps = 25.0
|
|
62
|
+
|
|
63
|
+
# Calculate frame numbers
|
|
64
|
+
start_frame_number = int(start_time * fps)
|
|
65
|
+
end_frame_number = int(end_time * fps)
|
|
66
|
+
|
|
67
|
+
# Get or create user information source
|
|
68
|
+
user_source, _ = InformationSource.objects.get_or_create(
|
|
69
|
+
name="user",
|
|
70
|
+
defaults={'description': 'User-generated annotations'}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Try to find label by name from annotation text
|
|
74
|
+
label = None
|
|
75
|
+
if label_text:
|
|
76
|
+
try:
|
|
77
|
+
label = Label.objects.filter(name__iexact=label_text).first()
|
|
78
|
+
if not label:
|
|
79
|
+
# Try to extract label from tags
|
|
80
|
+
tags = annotation.get('tags', [])
|
|
81
|
+
for tag in tags:
|
|
82
|
+
label = Label.objects.filter(name__iexact=tag).first()
|
|
83
|
+
if label:
|
|
84
|
+
break
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.warning(f"Error finding label '{label_text}': {e}")
|
|
87
|
+
|
|
88
|
+
# Start with default segment data
|
|
89
|
+
segment_data = {
|
|
90
|
+
'video_file': video_file,
|
|
91
|
+
'start_frame_number': start_frame_number,
|
|
92
|
+
'end_frame_number': end_frame_number,
|
|
93
|
+
'source': user_source,
|
|
94
|
+
'label': label,
|
|
95
|
+
'prediction_meta': None, # User segments don't have prediction meta
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# If original segment ID is provided, try to clone from original
|
|
99
|
+
if original_segment_id:
|
|
100
|
+
try:
|
|
101
|
+
original_segment = LabelVideoSegment.objects.get(id=original_segment_id)
|
|
102
|
+
|
|
103
|
+
# Check if timing or label actually changed
|
|
104
|
+
original_start_time = original_segment.start_frame_number / fps
|
|
105
|
+
original_end_time = original_segment.end_frame_number / fps
|
|
106
|
+
|
|
107
|
+
timing_changed = (
|
|
108
|
+
abs(original_start_time - start_time) > 0.1 or # Allow small floating point differences
|
|
109
|
+
abs(original_end_time - end_time) > 0.1
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
label_changed = (
|
|
113
|
+
(label and original_segment.label != label) or
|
|
114
|
+
(not label and original_segment.label is not None)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Only create new segment if something actually changed
|
|
118
|
+
if not timing_changed and not label_changed:
|
|
119
|
+
logger.debug(f"No changes detected in segment {original_segment_id}, skipping user segment creation")
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
# Clone relevant fields from original segment
|
|
123
|
+
segment_data.update({
|
|
124
|
+
'prediction_meta': original_segment.prediction_meta,
|
|
125
|
+
'label': label or original_segment.label, # Use new label if provided, otherwise keep original
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
logger.info(f"Cloning segment {original_segment_id} with user modifications")
|
|
129
|
+
|
|
130
|
+
except LabelVideoSegment.DoesNotExist:
|
|
131
|
+
logger.warning(f"Original segment {original_segment_id} not found, creating new user segment")
|
|
132
|
+
|
|
133
|
+
# Create the new user segment using the manager
|
|
134
|
+
with transaction.atomic():
|
|
135
|
+
new_segment = LabelVideoSegment.create_from_video(
|
|
136
|
+
source=video_file,
|
|
137
|
+
prediction_meta=segment_data.get('prediction_meta'),
|
|
138
|
+
label=segment_data['label'],
|
|
139
|
+
start_frame_number=start_frame_number,
|
|
140
|
+
end_frame_number=end_frame_number,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Set the user information source
|
|
144
|
+
new_segment.source = user_source
|
|
145
|
+
new_segment.save()
|
|
146
|
+
|
|
147
|
+
logger.info(f"Created user segment {new_segment.id} for video {video_id} by user {request_user.username}")
|
|
148
|
+
return new_segment
|
|
149
|
+
|
|
150
|
+
except VideoFile.DoesNotExist:
|
|
151
|
+
logger.error(f"Video {video_id} not found, cannot create user segment")
|
|
152
|
+
return None
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(f"Error creating user segment from annotation: {e}")
|
|
155
|
+
return None
|