endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/admin.py +10 -5
- endoreg_db/apps.py +4 -7
- endoreg_db/authz/auth.py +1 -0
- endoreg_db/authz/backends.py +1 -1
- endoreg_db/authz/management/commands/list_routes.py +2 -0
- endoreg_db/authz/middleware.py +8 -7
- endoreg_db/authz/permissions.py +21 -10
- endoreg_db/authz/policy.py +14 -19
- endoreg_db/authz/views_auth.py +14 -10
- endoreg_db/codemods/rename_datetime_fields.py +8 -1
- endoreg_db/exceptions.py +5 -2
- endoreg_db/forms/__init__.py +0 -1
- endoreg_db/forms/examination_form.py +4 -3
- endoreg_db/forms/patient_finding_intervention_form.py +30 -8
- endoreg_db/forms/patient_form.py +9 -13
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/settings/__init__.py +4 -1
- endoreg_db/forms/unit.py +2 -1
- endoreg_db/helpers/count_db.py +17 -14
- endoreg_db/helpers/default_objects.py +2 -1
- endoreg_db/helpers/download_segmentation_model.py +4 -3
- endoreg_db/helpers/interact.py +0 -5
- endoreg_db/helpers/test_video_helper.py +33 -25
- endoreg_db/import_files/__init__.py +1 -1
- endoreg_db/import_files/context/__init__.py +1 -1
- endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
- endoreg_db/import_files/context/ensure_center.py +4 -4
- endoreg_db/import_files/context/file_lock.py +3 -3
- endoreg_db/import_files/context/import_context.py +11 -12
- endoreg_db/import_files/context/validate_directories.py +1 -0
- endoreg_db/import_files/file_storage/create_report_file.py +57 -34
- endoreg_db/import_files/file_storage/create_video_file.py +64 -35
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
- endoreg_db/import_files/file_storage/state_management.py +89 -122
- endoreg_db/import_files/file_storage/storage.py +5 -1
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
- endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
- endoreg_db/import_files/report_import_service.py +36 -30
- endoreg_db/import_files/video_import_service.py +27 -23
- endoreg_db/logger_conf.py +56 -40
- endoreg_db/management/__init__.py +1 -1
- endoreg_db/management/commands/__init__.py +1 -1
- endoreg_db/management/commands/check_auth.py +45 -38
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
- endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
- endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
- endoreg_db/management/commands/fix_video_paths.py +75 -54
- endoreg_db/management/commands/import_report.py +1 -3
- endoreg_db/management/commands/list_routes.py +2 -0
- endoreg_db/management/commands/load_ai_model_data.py +8 -2
- endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
- endoreg_db/management/commands/load_center_data.py +3 -3
- endoreg_db/management/commands/load_distribution_data.py +35 -38
- endoreg_db/management/commands/load_endoscope_data.py +0 -3
- endoreg_db/management/commands/load_examination_data.py +20 -4
- endoreg_db/management/commands/load_finding_data.py +18 -3
- endoreg_db/management/commands/load_gender_data.py +17 -24
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
- endoreg_db/management/commands/load_information_source.py +0 -3
- endoreg_db/management/commands/load_lab_value_data.py +14 -3
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_name_data.py +1 -2
- endoreg_db/management/commands/load_pdf_type_data.py +4 -8
- endoreg_db/management/commands/load_profession_data.py +0 -1
- endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
- endoreg_db/management/commands/load_requirement_data.py +6 -2
- endoreg_db/management/commands/load_unit_data.py +0 -4
- endoreg_db/management/commands/load_user_groups.py +5 -7
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +22 -16
- endoreg_db/management/commands/setup_endoreg_db.py +110 -32
- endoreg_db/management/commands/storage_management.py +14 -8
- endoreg_db/management/commands/summarize_db_content.py +154 -63
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +82 -50
- endoreg_db/management/commands/video_validation.py +4 -6
- endoreg_db/migrations/0001_initial.py +112 -63
- endoreg_db/models/__init__.py +8 -0
- endoreg_db/models/administration/ai/active_model.py +5 -5
- endoreg_db/models/administration/ai/ai_model.py +41 -18
- endoreg_db/models/administration/ai/model_type.py +1 -0
- endoreg_db/models/administration/case/case.py +22 -22
- endoreg_db/models/administration/center/__init__.py +5 -5
- endoreg_db/models/administration/center/center.py +6 -2
- endoreg_db/models/administration/center/center_resource.py +18 -4
- endoreg_db/models/administration/center/center_shift.py +3 -1
- endoreg_db/models/administration/center/center_waste.py +6 -2
- endoreg_db/models/administration/person/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/employee_type.py +3 -1
- endoreg_db/models/administration/person/examiner/__init__.py +1 -1
- endoreg_db/models/administration/person/examiner/examiner.py +10 -2
- endoreg_db/models/administration/person/names/first_name.py +6 -4
- endoreg_db/models/administration/person/names/last_name.py +4 -3
- endoreg_db/models/administration/person/patient/__init__.py +1 -1
- endoreg_db/models/administration/person/patient/patient.py +0 -1
- endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
- endoreg_db/models/administration/person/person.py +1 -1
- endoreg_db/models/administration/product/__init__.py +7 -6
- endoreg_db/models/administration/product/product.py +6 -2
- endoreg_db/models/administration/product/product_group.py +9 -7
- endoreg_db/models/administration/product/product_material.py +9 -2
- endoreg_db/models/administration/product/reference_product.py +64 -15
- endoreg_db/models/administration/qualification/qualification.py +3 -1
- endoreg_db/models/administration/shift/shift.py +3 -1
- endoreg_db/models/administration/shift/shift_type.py +12 -4
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +1 -1
- endoreg_db/models/label/label.py +10 -2
- endoreg_db/models/label/label_set.py +3 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
- endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
- endoreg_db/models/media/__init__.py +12 -5
- endoreg_db/models/media/frame/__init__.py +1 -1
- endoreg_db/models/media/frame/frame.py +34 -8
- endoreg_db/models/media/pdf/__init__.py +2 -1
- endoreg_db/models/media/pdf/raw_pdf.py +11 -4
- endoreg_db/models/media/pdf/report_file.py +6 -2
- endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
- endoreg_db/models/media/video/create_from_file.py +20 -41
- endoreg_db/models/media/video/pipe_1.py +75 -30
- endoreg_db/models/media/video/pipe_2.py +37 -12
- endoreg_db/models/media/video/video_file.py +36 -24
- endoreg_db/models/media/video/video_file_ai.py +235 -70
- endoreg_db/models/media/video/video_file_anonymize.py +240 -65
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
- endoreg_db/models/media/video/video_file_io.py +85 -33
- endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
- endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
- endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
- endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
- endoreg_db/models/media/video/video_file_segments.py +118 -27
- endoreg_db/models/media/video/video_metadata.py +25 -6
- endoreg_db/models/media/video/video_processing.py +54 -15
- endoreg_db/models/medical/__init__.py +3 -13
- endoreg_db/models/medical/contraindication/__init__.py +3 -1
- endoreg_db/models/medical/disease.py +18 -6
- endoreg_db/models/medical/event.py +6 -2
- endoreg_db/models/medical/examination/__init__.py +5 -1
- endoreg_db/models/medical/examination/examination.py +22 -6
- endoreg_db/models/medical/examination/examination_indication.py +23 -7
- endoreg_db/models/medical/examination/examination_time.py +6 -2
- endoreg_db/models/medical/finding/__init__.py +3 -1
- endoreg_db/models/medical/finding/finding.py +37 -12
- endoreg_db/models/medical/finding/finding_classification.py +27 -8
- endoreg_db/models/medical/finding/finding_intervention.py +19 -6
- endoreg_db/models/medical/finding/finding_type.py +3 -1
- endoreg_db/models/medical/hardware/__init__.py +1 -1
- endoreg_db/models/medical/hardware/endoscope.py +14 -2
- endoreg_db/models/medical/laboratory/__init__.py +1 -1
- endoreg_db/models/medical/laboratory/lab_value.py +139 -39
- endoreg_db/models/medical/medication/__init__.py +7 -3
- endoreg_db/models/medical/medication/medication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
- endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
- endoreg_db/models/medical/medication/medication_schedule.py +3 -1
- endoreg_db/models/medical/patient/__init__.py +2 -10
- endoreg_db/models/medical/patient/medication_examples.py +3 -14
- endoreg_db/models/medical/patient/patient_disease.py +17 -5
- endoreg_db/models/medical/patient/patient_event.py +12 -4
- endoreg_db/models/medical/patient/patient_examination.py +52 -15
- endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
- endoreg_db/models/medical/patient/patient_finding.py +105 -29
- endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
- endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
- endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
- endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
- endoreg_db/models/medical/patient/patient_medication.py +25 -7
- endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
- endoreg_db/models/metadata/model_meta.py +40 -12
- endoreg_db/models/metadata/model_meta_logic.py +51 -16
- endoreg_db/models/metadata/sensitive_meta.py +65 -28
- endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
- endoreg_db/models/metadata/video_meta.py +146 -39
- endoreg_db/models/metadata/video_prediction_logic.py +70 -21
- endoreg_db/models/metadata/video_prediction_meta.py +80 -27
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +10 -10
- endoreg_db/models/other/distribution/__init__.py +9 -7
- endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
- endoreg_db/models/other/emission/__init__.py +1 -1
- endoreg_db/models/other/emission/emission_factor.py +9 -3
- endoreg_db/models/other/information_source.py +15 -5
- endoreg_db/models/other/material.py +3 -1
- endoreg_db/models/other/transport_route.py +3 -1
- endoreg_db/models/other/unit.py +6 -2
- endoreg_db/models/report/report.py +0 -1
- endoreg_db/models/requirement/requirement.py +84 -27
- endoreg_db/models/requirement/requirement_error.py +5 -6
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
- endoreg_db/models/requirement/requirement_operator.py +28 -8
- endoreg_db/models/requirement/requirement_set.py +34 -11
- endoreg_db/models/state/__init__.py +1 -0
- endoreg_db/models/state/audit_ledger.py +9 -2
- endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +0 -1
- endoreg_db/models/state/video.py +2 -4
- endoreg_db/models/utils.py +4 -2
- endoreg_db/queries/__init__.py +2 -6
- endoreg_db/queries/annotations/__init__.py +1 -3
- endoreg_db/queries/annotations/legacy.py +37 -26
- endoreg_db/root_urls.py +3 -4
- endoreg_db/schemas/examination_evaluation.py +3 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
- endoreg_db/serializers/__init__.py +2 -8
- endoreg_db/serializers/administration/__init__.py +1 -2
- endoreg_db/serializers/administration/ai/__init__.py +0 -1
- endoreg_db/serializers/administration/ai/active_model.py +3 -1
- endoreg_db/serializers/administration/ai/ai_model.py +5 -3
- endoreg_db/serializers/administration/ai/model_type.py +3 -1
- endoreg_db/serializers/administration/center.py +7 -2
- endoreg_db/serializers/administration/gender.py +4 -2
- endoreg_db/serializers/anonymization.py +13 -13
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
- endoreg_db/serializers/examination/__init__.py +1 -1
- endoreg_db/serializers/examination/base.py +12 -13
- endoreg_db/serializers/examination/dropdown.py +6 -7
- endoreg_db/serializers/examination_serializer.py +3 -6
- endoreg_db/serializers/finding/__init__.py +1 -1
- endoreg_db/serializers/finding/finding.py +14 -7
- endoreg_db/serializers/finding_classification/__init__.py +3 -3
- endoreg_db/serializers/finding_classification/choice.py +3 -3
- endoreg_db/serializers/finding_classification/classification.py +2 -4
- endoreg_db/serializers/label_video_segment/__init__.py +5 -3
- endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
- endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
- endoreg_db/serializers/meta/__init__.py +1 -2
- endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
- endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
- endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
- endoreg_db/serializers/misc/__init__.py +2 -2
- endoreg_db/serializers/misc/file_overview.py +11 -7
- endoreg_db/serializers/misc/stats.py +10 -8
- endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
- endoreg_db/serializers/misc/upload_job.py +32 -29
- endoreg_db/serializers/patient/__init__.py +2 -1
- endoreg_db/serializers/patient/patient.py +32 -15
- endoreg_db/serializers/patient/patient_dropdown.py +11 -3
- endoreg_db/serializers/patient_examination/__init__.py +1 -1
- endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
- endoreg_db/serializers/patient_finding/__init__.py +1 -1
- endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
- endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
- endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
- endoreg_db/serializers/pdf/__init__.py +1 -3
- endoreg_db/serializers/requirements/requirement_schema.py +1 -6
- endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
- endoreg_db/serializers/video/__init__.py +2 -2
- endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
- endoreg_db/serializers/video/video_file_brief.py +6 -2
- endoreg_db/serializers/video/video_file_detail.py +36 -23
- endoreg_db/serializers/video/video_file_list.py +4 -2
- endoreg_db/serializers/video/video_processing_history.py +54 -50
- endoreg_db/services/__init__.py +1 -1
- endoreg_db/services/anonymization.py +2 -2
- endoreg_db/services/examination_evaluation.py +40 -17
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/polling_coordinator.py +101 -70
- endoreg_db/services/pseudonym_service.py +27 -22
- endoreg_db/services/report_import.py +6 -3
- endoreg_db/services/segment_sync.py +75 -59
- endoreg_db/services/video_import.py +6 -7
- endoreg_db/urls/__init__.py +2 -2
- endoreg_db/urls/ai.py +7 -25
- endoreg_db/urls/anonymization.py +61 -15
- endoreg_db/urls/auth.py +4 -4
- endoreg_db/urls/classification.py +4 -9
- endoreg_db/urls/examination.py +27 -18
- endoreg_db/urls/media.py +27 -34
- endoreg_db/urls/patient.py +11 -7
- endoreg_db/urls/requirements.py +3 -1
- endoreg_db/urls/root_urls.py +2 -3
- endoreg_db/urls/stats.py +24 -16
- endoreg_db/urls/upload.py +3 -11
- endoreg_db/utils/__init__.py +14 -15
- endoreg_db/utils/ai/__init__.py +1 -1
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +2 -1
- endoreg_db/utils/ai/inference_dataset.py +14 -15
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
- endoreg_db/utils/ai/predict.py +4 -4
- endoreg_db/utils/ai/preprocess.py +19 -11
- endoreg_db/utils/calc_duration_seconds.py +4 -4
- endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
- endoreg_db/utils/check_video_files.py +74 -47
- endoreg_db/utils/cropping.py +10 -9
- endoreg_db/utils/dataloader.py +11 -3
- endoreg_db/utils/dates.py +3 -4
- endoreg_db/utils/defaults/set_default_center.py +7 -6
- endoreg_db/utils/env.py +6 -2
- endoreg_db/utils/extract_specific_frames.py +24 -9
- endoreg_db/utils/file_operations.py +30 -18
- endoreg_db/utils/fix_video_path_direct.py +57 -41
- endoreg_db/utils/frame_anonymization_utils.py +157 -157
- endoreg_db/utils/hashs.py +3 -18
- endoreg_db/utils/links/requirement_link.py +96 -52
- endoreg_db/utils/ocr.py +30 -25
- endoreg_db/utils/operation_log.py +61 -0
- endoreg_db/utils/parse_and_generate_yaml.py +12 -13
- endoreg_db/utils/paths.py +6 -6
- endoreg_db/utils/permissions.py +40 -24
- endoreg_db/utils/pipelines/process_video_dir.py +50 -26
- endoreg_db/utils/product/sum_emissions.py +5 -3
- endoreg_db/utils/product/sum_weights.py +4 -2
- endoreg_db/utils/pydantic_models/__init__.py +3 -4
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
- endoreg_db/utils/setup_config.py +21 -5
- endoreg_db/utils/storage.py +3 -1
- endoreg_db/utils/translation.py +19 -15
- endoreg_db/utils/uuid.py +1 -0
- endoreg_db/utils/validate_endo_roi.py +12 -4
- endoreg_db/utils/validate_subcategory_dict.py +26 -24
- endoreg_db/utils/validate_video_detailed.py +207 -149
- endoreg_db/utils/video/__init__.py +7 -3
- endoreg_db/utils/video/extract_frames.py +30 -18
- endoreg_db/utils/video/names.py +11 -6
- endoreg_db/utils/video/streaming_processor.py +175 -101
- endoreg_db/utils/video/video_splitter.py +30 -19
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
- endoreg_db/views/__init__.py +0 -20
- endoreg_db/views/anonymization/__init__.py +6 -2
- endoreg_db/views/anonymization/media_management.py +2 -6
- endoreg_db/views/anonymization/overview.py +34 -1
- endoreg_db/views/anonymization/validate.py +79 -18
- endoreg_db/views/auth/__init__.py +1 -1
- endoreg_db/views/auth/keycloak.py +16 -14
- endoreg_db/views/examination/__init__.py +12 -15
- endoreg_db/views/examination/examination.py +5 -5
- endoreg_db/views/examination/examination_manifest_cache.py +5 -5
- endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
- endoreg_db/views/examination/get_finding_classifications.py +9 -7
- endoreg_db/views/examination/get_findings.py +8 -10
- endoreg_db/views/examination/get_instruments.py +3 -2
- endoreg_db/views/examination/get_interventions.py +1 -1
- endoreg_db/views/finding/__init__.py +2 -2
- endoreg_db/views/finding/finding.py +58 -54
- endoreg_db/views/finding/get_classifications.py +1 -1
- endoreg_db/views/finding/get_interventions.py +1 -1
- endoreg_db/views/finding_classification/__init__.py +5 -5
- endoreg_db/views/finding_classification/finding_classification.py +5 -6
- endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
- endoreg_db/views/media/__init__.py +13 -13
- endoreg_db/views/media/pdf_media.py +9 -9
- endoreg_db/views/media/sensitive_metadata.py +10 -7
- endoreg_db/views/media/video_media.py +4 -4
- endoreg_db/views/meta/__init__.py +1 -1
- endoreg_db/views/meta/sensitive_meta_list.py +20 -22
- endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
- endoreg_db/views/misc/__init__.py +6 -34
- endoreg_db/views/misc/center.py +2 -1
- endoreg_db/views/misc/csrf.py +2 -1
- endoreg_db/views/misc/gender.py +2 -1
- endoreg_db/views/misc/stats.py +141 -106
- endoreg_db/views/patient/__init__.py +1 -3
- endoreg_db/views/patient/patient.py +141 -99
- endoreg_db/views/patient_examination/__init__.py +5 -5
- endoreg_db/views/patient_examination/patient_examination.py +43 -42
- endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
- endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
- endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
- endoreg_db/views/patient_examination/video.py +114 -80
- endoreg_db/views/patient_finding/__init__.py +1 -1
- endoreg_db/views/patient_finding/patient_finding.py +17 -10
- endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
- endoreg_db/views/patient_finding_classification/__init__.py +1 -1
- endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
- endoreg_db/views/report/reimport.py +1 -1
- endoreg_db/views/report/report_stream.py +5 -8
- endoreg_db/views/requirement/__init__.py +2 -1
- endoreg_db/views/requirement/evaluate.py +7 -9
- endoreg_db/views/requirement/lookup.py +2 -3
- endoreg_db/views/requirement/lookup_store.py +0 -1
- endoreg_db/views/requirement/requirement_utils.py +2 -4
- endoreg_db/views/stats/__init__.py +4 -4
- endoreg_db/views/stats/stats_views.py +152 -115
- endoreg_db/views/video/__init__.py +18 -27
- endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
- endoreg_db/views/{ai → video/ai}/label.py +20 -16
- endoreg_db/views/video/correction.py +5 -6
- endoreg_db/views/video/reimport.py +134 -99
- endoreg_db/views/video/segments_crud.py +134 -44
- endoreg_db/views/video/video_apply_mask.py +13 -12
- endoreg_db/views/video/video_correction.py +2 -1
- endoreg_db/views/video/video_download_processed.py +15 -15
- endoreg_db/views/video/video_meta_stats.py +7 -6
- endoreg_db/views/video/video_processing_history.py +3 -2
- endoreg_db/views/video/video_remove_frames.py +13 -12
- endoreg_db/views/video/video_stream.py +110 -82
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
- endoreg_db/management/commands/import_fallback_video.py +0 -203
- endoreg_db/management/commands/import_video.py +0 -422
- endoreg_db/management/commands/import_video_with_classification.py +0 -367
- endoreg_db/models/media/processing_history/processing_history.py +0 -96
- endoreg_db/serializers/label/__init__.py +0 -7
- endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
- endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
- endoreg_db/services/__old/pdf_import.py +0 -1487
- endoreg_db/services/__old/video_import.py +0 -1306
- endoreg_db/tasks/upload_tasks.py +0 -216
- endoreg_db/tasks/video_ingest.py +0 -161
- endoreg_db/tasks/video_processing_tasks.py +0 -327
- endoreg_db/views/misc/translation.py +0 -182
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,7 +18,9 @@ from rest_framework.decorators import api_view, permission_classes
|
|
|
18
18
|
from rest_framework.response import Response
|
|
19
19
|
|
|
20
20
|
from endoreg_db.models import Label, LabelVideoSegment, VideoFile
|
|
21
|
-
from endoreg_db.serializers.label_video_segment.label_video_segment import
|
|
21
|
+
from endoreg_db.serializers.label_video_segment.label_video_segment import (
|
|
22
|
+
LabelVideoSegmentSerializer,
|
|
23
|
+
)
|
|
22
24
|
from endoreg_db.utils.permissions import EnvironmentAwarePermission
|
|
23
25
|
|
|
24
26
|
logger = logging.getLogger(__name__)
|
|
@@ -49,14 +51,21 @@ def video_segments_stats(request):
|
|
|
49
51
|
stats = {
|
|
50
52
|
"total_segments": total_segments,
|
|
51
53
|
"videos_with_segments": videos_with_segments,
|
|
52
|
-
"by_label": {
|
|
54
|
+
"by_label": {
|
|
55
|
+
item["label__name"]: item["count"]
|
|
56
|
+
for item in label_counts
|
|
57
|
+
if item["label__name"]
|
|
58
|
+
},
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
return Response(stats, status=status.HTTP_200_OK)
|
|
56
62
|
|
|
57
63
|
except Exception as e:
|
|
58
64
|
logger.error(f"Error fetching video segment stats: {e}")
|
|
59
|
-
return Response(
|
|
65
|
+
return Response(
|
|
66
|
+
{"error": "Failed to fetch segment statistics"},
|
|
67
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
68
|
+
)
|
|
60
69
|
|
|
61
70
|
|
|
62
71
|
@api_view(["GET", "POST"])
|
|
@@ -84,13 +93,24 @@ def video_segments_collection(request):
|
|
|
84
93
|
try:
|
|
85
94
|
segment = serializer.save()
|
|
86
95
|
logger.info(f"Successfully created video segment {segment.pk}")
|
|
87
|
-
return Response(
|
|
96
|
+
return Response(
|
|
97
|
+
LabelVideoSegmentSerializer(segment).data,
|
|
98
|
+
status=status.HTTP_201_CREATED,
|
|
99
|
+
)
|
|
88
100
|
except Exception as e:
|
|
89
101
|
logger.error(f"Error creating video segment: {str(e)}")
|
|
90
|
-
return Response(
|
|
102
|
+
return Response(
|
|
103
|
+
{"error": f"Failed to create segment: {str(e)}"},
|
|
104
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
105
|
+
)
|
|
91
106
|
else:
|
|
92
|
-
logger.warning(
|
|
93
|
-
|
|
107
|
+
logger.warning(
|
|
108
|
+
f"Invalid data for video segment creation: {serializer.errors}"
|
|
109
|
+
)
|
|
110
|
+
return Response(
|
|
111
|
+
{"error": "Invalid data", "details": serializer.errors},
|
|
112
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
113
|
+
)
|
|
94
114
|
|
|
95
115
|
elif request.method == "GET":
|
|
96
116
|
# Optional filtering by video_id
|
|
@@ -104,14 +124,20 @@ def video_segments_collection(request):
|
|
|
104
124
|
video = VideoFile.objects.get(id=video_id)
|
|
105
125
|
queryset = queryset.filter(video_file=video)
|
|
106
126
|
except VideoFile.DoesNotExist:
|
|
107
|
-
return Response(
|
|
127
|
+
return Response(
|
|
128
|
+
{"error": f"Video with id {video_id} not found"},
|
|
129
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
130
|
+
)
|
|
108
131
|
|
|
109
132
|
if label_id:
|
|
110
133
|
try:
|
|
111
134
|
label = Label.objects.get(id=label_id)
|
|
112
135
|
queryset = queryset.filter(label=label)
|
|
113
136
|
except Label.DoesNotExist:
|
|
114
|
-
return Response(
|
|
137
|
+
return Response(
|
|
138
|
+
{"error": f"Label with id {label_id} not found"},
|
|
139
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
140
|
+
)
|
|
115
141
|
|
|
116
142
|
# Order by video and start time for consistent results
|
|
117
143
|
segments = queryset.order_by("video_file__id", "start_frame_number")
|
|
@@ -152,7 +178,10 @@ def video_segments_by_video(request, pk):
|
|
|
152
178
|
label = Label.objects.get(name=label_name)
|
|
153
179
|
queryset = queryset.filter(label=label)
|
|
154
180
|
except Label.DoesNotExist:
|
|
155
|
-
return Response(
|
|
181
|
+
return Response(
|
|
182
|
+
{"error": f'Label "{label_name}" not found'},
|
|
183
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
184
|
+
)
|
|
156
185
|
|
|
157
186
|
segments = queryset.order_by("start_frame_number")
|
|
158
187
|
serializer = LabelVideoSegmentSerializer(segments, many=True)
|
|
@@ -170,14 +199,27 @@ def video_segments_by_video(request, pk):
|
|
|
170
199
|
if serializer.is_valid():
|
|
171
200
|
try:
|
|
172
201
|
segment = serializer.save()
|
|
173
|
-
logger.info(
|
|
174
|
-
|
|
202
|
+
logger.info(
|
|
203
|
+
f"Successfully created segment {segment.pk} for video {pk}"
|
|
204
|
+
)
|
|
205
|
+
return Response(
|
|
206
|
+
LabelVideoSegmentSerializer(segment).data,
|
|
207
|
+
status=status.HTTP_201_CREATED,
|
|
208
|
+
)
|
|
175
209
|
except Exception as e:
|
|
176
210
|
logger.error(f"Error creating segment for video {pk}: {str(e)}")
|
|
177
|
-
return Response(
|
|
211
|
+
return Response(
|
|
212
|
+
{"error": f"Failed to create segment: {str(e)}"},
|
|
213
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
214
|
+
)
|
|
178
215
|
else:
|
|
179
|
-
logger.warning(
|
|
180
|
-
|
|
216
|
+
logger.warning(
|
|
217
|
+
f"Invalid data for segment creation: {serializer.errors}"
|
|
218
|
+
)
|
|
219
|
+
return Response(
|
|
220
|
+
{"error": "Invalid data", "details": serializer.errors},
|
|
221
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
222
|
+
)
|
|
181
223
|
|
|
182
224
|
|
|
183
225
|
@api_view(["GET", "PATCH", "DELETE"])
|
|
@@ -208,10 +250,14 @@ def video_segment_detail(request, pk, segment_id):
|
|
|
208
250
|
return Response(serializer.data)
|
|
209
251
|
|
|
210
252
|
elif request.method == "PATCH":
|
|
211
|
-
logger.info(
|
|
253
|
+
logger.info(
|
|
254
|
+
f"Updating segment {segment_id} for video {pk} with data: {request.data}"
|
|
255
|
+
)
|
|
212
256
|
|
|
213
257
|
with transaction.atomic():
|
|
214
|
-
serializer = LabelVideoSegmentSerializer(
|
|
258
|
+
serializer = LabelVideoSegmentSerializer(
|
|
259
|
+
segment, data=request.data, partial=True
|
|
260
|
+
)
|
|
215
261
|
if serializer.is_valid():
|
|
216
262
|
try:
|
|
217
263
|
segment = serializer.save()
|
|
@@ -219,10 +265,16 @@ def video_segment_detail(request, pk, segment_id):
|
|
|
219
265
|
return Response(LabelVideoSegmentSerializer(segment).data)
|
|
220
266
|
except Exception as e:
|
|
221
267
|
logger.error(f"Error updating segment {segment_id}: {str(e)}")
|
|
222
|
-
return Response(
|
|
268
|
+
return Response(
|
|
269
|
+
{"error": f"Failed to update segment: {str(e)}"},
|
|
270
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
271
|
+
)
|
|
223
272
|
else:
|
|
224
273
|
logger.warning(f"Invalid data for segment update: {serializer.errors}")
|
|
225
|
-
return Response(
|
|
274
|
+
return Response(
|
|
275
|
+
{"error": "Invalid data", "details": serializer.errors},
|
|
276
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
277
|
+
)
|
|
226
278
|
|
|
227
279
|
elif request.method == "DELETE":
|
|
228
280
|
logger.info(f"Deleting segment {segment_id} from video {pk}")
|
|
@@ -230,10 +282,16 @@ def video_segment_detail(request, pk, segment_id):
|
|
|
230
282
|
with transaction.atomic():
|
|
231
283
|
segment.delete()
|
|
232
284
|
logger.info(f"Successfully deleted segment {segment_id}")
|
|
233
|
-
return Response(
|
|
285
|
+
return Response(
|
|
286
|
+
{"message": f"Segment {segment_id} deleted successfully"},
|
|
287
|
+
status=status.HTTP_204_NO_CONTENT,
|
|
288
|
+
)
|
|
234
289
|
except Exception as e:
|
|
235
290
|
logger.error(f"Error deleting segment {segment_id}: {str(e)}")
|
|
236
|
-
return Response(
|
|
291
|
+
return Response(
|
|
292
|
+
{"error": f"Failed to delete segment: {str(e)}"},
|
|
293
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
294
|
+
)
|
|
237
295
|
|
|
238
296
|
|
|
239
297
|
# ============================================================================
|
|
@@ -282,7 +340,9 @@ def video_segment_validate(request, pk: int, segment_id: int):
|
|
|
282
340
|
try:
|
|
283
341
|
is_validated = request.data.get("is_validated", True)
|
|
284
342
|
notes = request.data.get("notes", "")
|
|
285
|
-
information_source_name = request.data.get(
|
|
343
|
+
information_source_name = request.data.get(
|
|
344
|
+
"information_source_name", "manual_annotation"
|
|
345
|
+
)
|
|
286
346
|
|
|
287
347
|
# Optional: update times (seconds) before validation
|
|
288
348
|
start_time = request.data.get("start_time")
|
|
@@ -299,7 +359,9 @@ def video_segment_validate(request, pk: int, segment_id: int):
|
|
|
299
359
|
)
|
|
300
360
|
segment.start_frame_number = new_start
|
|
301
361
|
segment.end_frame_number = new_end
|
|
302
|
-
segment.save(
|
|
362
|
+
segment.save(
|
|
363
|
+
update_fields=["start_frame_number", "end_frame_number"]
|
|
364
|
+
)
|
|
303
365
|
|
|
304
366
|
segment.mark_validated(
|
|
305
367
|
is_validated=is_validated,
|
|
@@ -323,9 +385,13 @@ def video_segment_validate(request, pk: int, segment_id: int):
|
|
|
323
385
|
|
|
324
386
|
except Exception as e:
|
|
325
387
|
logger.error(f"Error validating segment {segment_id} in video {pk}: {e}")
|
|
326
|
-
return Response(
|
|
388
|
+
return Response(
|
|
389
|
+
{"error": f"Validation failed: {str(e)}"},
|
|
390
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
391
|
+
)
|
|
392
|
+
|
|
327
393
|
|
|
328
|
-
#TODO Pass user based information source to backend. This is the endpoint currently used by the VideoExamination endpoint
|
|
394
|
+
# TODO Pass user based information source to backend. This is the endpoint currently used by the VideoExamination endpoint
|
|
329
395
|
@api_view(["POST"])
|
|
330
396
|
@permission_classes([EnvironmentAwarePermission])
|
|
331
397
|
def video_segments_validate_bulk(request, pk: int):
|
|
@@ -351,22 +417,24 @@ def video_segments_validate_bulk(request, pk: int):
|
|
|
351
417
|
segment_ids = request.data.get("segment_ids", [])
|
|
352
418
|
is_validated = request.data.get("is_validated", True)
|
|
353
419
|
notes = request.data.get("notes", "")
|
|
354
|
-
information_source_name = request.data.get(
|
|
420
|
+
information_source_name = request.data.get(
|
|
421
|
+
"information_source_name", "manual_annotation"
|
|
422
|
+
)
|
|
355
423
|
if notes:
|
|
356
424
|
logger.info(f"Segment Validiert ${notes}")
|
|
357
425
|
if not segment_ids:
|
|
358
|
-
return Response(
|
|
426
|
+
return Response(
|
|
427
|
+
{"error": "segment_ids is required"}, status=status.HTTP_400_BAD_REQUEST
|
|
428
|
+
)
|
|
359
429
|
|
|
360
430
|
# optional per-segment timing info (seconds)
|
|
361
431
|
segments_data_list = request.data.get("segments", []) or []
|
|
362
432
|
segments_data = {int(s["id"]): s for s in segments_data_list if "id" in s}
|
|
363
433
|
|
|
364
434
|
try:
|
|
365
|
-
segments = (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
.select_related("state", "video_file")
|
|
369
|
-
)
|
|
435
|
+
segments = LabelVideoSegment.objects.filter(
|
|
436
|
+
pk__in=segment_ids, video_file=video
|
|
437
|
+
).select_related("state", "video_file")
|
|
370
438
|
|
|
371
439
|
if not segments.exists():
|
|
372
440
|
return Response(
|
|
@@ -396,13 +464,18 @@ def video_segments_validate_bulk(request, pk: int):
|
|
|
396
464
|
segment.start_frame_number = new_start
|
|
397
465
|
segment.end_frame_number = new_end
|
|
398
466
|
segment.save(
|
|
399
|
-
update_fields=[
|
|
467
|
+
update_fields=[
|
|
468
|
+
"start_frame_number",
|
|
469
|
+
"end_frame_number",
|
|
470
|
+
]
|
|
400
471
|
)
|
|
401
472
|
|
|
402
473
|
# 2) mark as validated + update information source + notes
|
|
403
474
|
segment.mark_validated(
|
|
404
475
|
is_validated=is_validated,
|
|
405
|
-
information_source_name=str(information_source_name)
|
|
476
|
+
information_source_name=str(information_source_name)
|
|
477
|
+
if is_validated
|
|
478
|
+
else str(None),
|
|
406
479
|
)
|
|
407
480
|
updated_count += 1
|
|
408
481
|
|
|
@@ -422,13 +495,18 @@ def video_segments_validate_bulk(request, pk: int):
|
|
|
422
495
|
|
|
423
496
|
if failed_ids:
|
|
424
497
|
response_data["failed_ids"] = failed_ids
|
|
425
|
-
response_data["warning"] =
|
|
498
|
+
response_data["warning"] = (
|
|
499
|
+
f"{len(failed_ids)} segments could not be validated"
|
|
500
|
+
)
|
|
426
501
|
|
|
427
502
|
return Response(response_data, status=status.HTTP_200_OK)
|
|
428
503
|
|
|
429
504
|
except Exception as e:
|
|
430
505
|
logger.error(f"Error in bulk validation for video {pk}: {e}")
|
|
431
|
-
return Response(
|
|
506
|
+
return Response(
|
|
507
|
+
{"error": f"Bulk validation failed: {str(e)}"},
|
|
508
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
509
|
+
)
|
|
432
510
|
|
|
433
511
|
|
|
434
512
|
@api_view(["GET", "POST"])
|
|
@@ -478,7 +556,9 @@ def video_segments_validation_status(request, pk: int):
|
|
|
478
556
|
# Get validation status
|
|
479
557
|
label_name = request.query_params.get("label_name")
|
|
480
558
|
|
|
481
|
-
segments_query = LabelVideoSegment.objects.filter(
|
|
559
|
+
segments_query = LabelVideoSegment.objects.filter(
|
|
560
|
+
video_file=video
|
|
561
|
+
).select_related("state", "label")
|
|
482
562
|
|
|
483
563
|
if label_name:
|
|
484
564
|
segments_query = segments_query.filter(label__name=label_name)
|
|
@@ -505,7 +585,8 @@ def video_segments_validation_status(request, pk: int):
|
|
|
505
585
|
"total_segments": total_count,
|
|
506
586
|
"validated_count": validated_count,
|
|
507
587
|
"unvalidated_count": total_count - validated_count,
|
|
508
|
-
"validation_complete": validated_count == total_count
|
|
588
|
+
"validation_complete": validated_count == total_count
|
|
589
|
+
and total_count > 0,
|
|
509
590
|
"by_label": by_label,
|
|
510
591
|
"label_filter": label_name,
|
|
511
592
|
},
|
|
@@ -517,7 +598,9 @@ def video_segments_validation_status(request, pk: int):
|
|
|
517
598
|
label_name = request.data.get("label_name")
|
|
518
599
|
notes = request.data.get("notes", "")
|
|
519
600
|
|
|
520
|
-
segments_query = LabelVideoSegment.objects.filter(
|
|
601
|
+
segments_query = LabelVideoSegment.objects.filter(
|
|
602
|
+
video_file=video
|
|
603
|
+
).select_related("state", "label")
|
|
521
604
|
|
|
522
605
|
if label_name:
|
|
523
606
|
segments_query = segments_query.filter(label__name=label_name)
|
|
@@ -525,7 +608,14 @@ def video_segments_validation_status(request, pk: int):
|
|
|
525
608
|
segments = segments_query.all()
|
|
526
609
|
|
|
527
610
|
if not segments.exists():
|
|
528
|
-
return Response(
|
|
611
|
+
return Response(
|
|
612
|
+
{
|
|
613
|
+
"message": "No segments found to validate",
|
|
614
|
+
"video_id": pk,
|
|
615
|
+
"updated_count": 0,
|
|
616
|
+
},
|
|
617
|
+
status=status.HTTP_200_OK,
|
|
618
|
+
)
|
|
529
619
|
|
|
530
620
|
updated_count = 0
|
|
531
621
|
failed_count = 0
|
|
@@ -535,8 +625,6 @@ def video_segments_validation_status(request, pk: int):
|
|
|
535
625
|
try:
|
|
536
626
|
if segment.state:
|
|
537
627
|
segment.state.is_validated = True
|
|
538
|
-
if notes and hasattr(segment.state, "validation_notes"):
|
|
539
|
-
segment.state.validation_notes = notes
|
|
540
628
|
segment.state.save()
|
|
541
629
|
updated_count += 1
|
|
542
630
|
else:
|
|
@@ -546,8 +634,10 @@ def video_segments_validation_status(request, pk: int):
|
|
|
546
634
|
failed_count += 1
|
|
547
635
|
|
|
548
636
|
logger.info(f"Completed validation for {updated_count} segments in video {pk}")
|
|
549
|
-
logger.info(
|
|
550
|
-
|
|
637
|
+
logger.info("Removing Outside Segments")
|
|
638
|
+
video.label_video_segments.filter(
|
|
639
|
+
video_file=video, label__name="outside", state__is_validated=False
|
|
640
|
+
).delete()
|
|
551
641
|
return Response(
|
|
552
642
|
{
|
|
553
643
|
"message": f"Video segment validation completed for video {pk}",
|
|
@@ -12,37 +12,38 @@ class VideoApplyMaskView(APIView):
|
|
|
12
12
|
"""
|
|
13
13
|
POST /api/video-apply-mask/{id}/ - Apply mask to video using streaming processing
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
permission_classes = [EnvironmentAwarePermission]
|
|
16
17
|
|
|
17
18
|
def post(self, request, pk):
|
|
18
19
|
video = get_object_or_404(VideoFile, pk=pk)
|
|
19
20
|
|
|
20
|
-
mask_type = request.data.get(
|
|
21
|
-
device_name = request.data.get(
|
|
22
|
-
use_streaming = request.data.get(
|
|
23
|
-
custom_mask = request.data.get(
|
|
21
|
+
mask_type = request.data.get("mask_type", "device_default")
|
|
22
|
+
device_name = request.data.get("device_name", "olympus_cv_1500")
|
|
23
|
+
use_streaming = request.data.get("use_streaming", True)
|
|
24
|
+
custom_mask = request.data.get("custom_mask")
|
|
24
25
|
|
|
25
26
|
try:
|
|
26
27
|
# Start async task for video masking
|
|
27
28
|
from endoreg_db.tasks.video_processing_tasks import apply_video_mask_task
|
|
28
29
|
|
|
29
30
|
task_data = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
"video_id": pk,
|
|
32
|
+
"mask_type": mask_type,
|
|
33
|
+
"device_name": device_name,
|
|
34
|
+
"use_streaming": use_streaming,
|
|
35
|
+
"custom_mask": custom_mask,
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
task = apply_video_mask_task.delay(**task_data)
|
|
38
39
|
|
|
39
40
|
return Response(
|
|
40
41
|
{"task_id": task.id, "status": "started"},
|
|
41
|
-
status=status.HTTP_202_ACCEPTED
|
|
42
|
+
status=status.HTTP_202_ACCEPTED,
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
except Exception as e:
|
|
45
46
|
return Response(
|
|
46
47
|
{"error": f"Failed to start masking task: {str(e)}"},
|
|
47
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
48
|
-
)
|
|
48
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
49
|
+
)
|
|
@@ -13,9 +13,10 @@ class VideoCorrectionView(APIView):
|
|
|
13
13
|
"""
|
|
14
14
|
GET /api/video/media/video-correction/{id}/ - Get video details for correction
|
|
15
15
|
"""
|
|
16
|
+
|
|
16
17
|
permission_classes = [EnvironmentAwarePermission]
|
|
17
18
|
|
|
18
19
|
def get(self, request, pk):
|
|
19
20
|
video = get_object_or_404(VideoFile, pk=pk)
|
|
20
21
|
ser = VideoDetailSerializer(video, context={"request": request})
|
|
21
|
-
return Response(ser.data, status=status.HTTP_200_OK)
|
|
22
|
+
return Response(ser.data, status=status.HTTP_200_OK)
|
|
@@ -13,46 +13,46 @@ class VideoDownloadProcessedView(APIView):
|
|
|
13
13
|
"""
|
|
14
14
|
GET /api/video-download-processed/{id}/ - Download processed video result
|
|
15
15
|
"""
|
|
16
|
+
|
|
16
17
|
permission_classes = [EnvironmentAwarePermission]
|
|
17
18
|
|
|
18
19
|
def get(self, request, pk):
|
|
19
20
|
# Remove unused 'video' variable
|
|
20
|
-
output_path = request.query_params.get(
|
|
21
|
+
output_path = request.query_params.get("path")
|
|
21
22
|
|
|
22
23
|
# Define the allowed base directory for processed videos
|
|
23
|
-
processed_base_dir = os.path.abspath(
|
|
24
|
+
processed_base_dir = os.path.abspath(
|
|
25
|
+
os.getenv("PROCESSED_VIDEO_DIR", "/srv/processed_videos")
|
|
26
|
+
)
|
|
24
27
|
if not output_path:
|
|
25
28
|
return Response(
|
|
26
|
-
{"error": "Processed file not found"},
|
|
27
|
-
status=status.HTTP_404_NOT_FOUND
|
|
29
|
+
{"error": "Processed file not found"}, status=status.HTTP_404_NOT_FOUND
|
|
28
30
|
)
|
|
29
31
|
|
|
30
32
|
# Resolve the absolute path and check if it's within the allowed directory
|
|
31
33
|
abs_output_path = os.path.abspath(output_path)
|
|
32
34
|
if not abs_output_path.startswith(processed_base_dir + os.sep):
|
|
33
35
|
return Response(
|
|
34
|
-
{"error": "Invalid file path"},
|
|
35
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
36
|
+
{"error": "Invalid file path"}, status=status.HTTP_400_BAD_REQUEST
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
if not os.path.exists(abs_output_path):
|
|
39
40
|
return Response(
|
|
40
|
-
{"error": "Processed file not found"},
|
|
41
|
-
status=status.HTTP_404_NOT_FOUND
|
|
41
|
+
{"error": "Processed file not found"}, status=status.HTTP_404_NOT_FOUND
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
try:
|
|
45
45
|
from django.http import FileResponse
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
|
|
47
|
+
with open(abs_output_path, "rb") as f:
|
|
48
|
+
response = FileResponse(f, content_type="video/mp4")
|
|
49
|
+
response["Content-Disposition"] = (
|
|
50
|
+
f'attachment; filename="{os.path.basename(abs_output_path)}"'
|
|
50
51
|
)
|
|
51
|
-
response['Content-Disposition'] = f'attachment; filename="{os.path.basename(abs_output_path)}"'
|
|
52
52
|
return response
|
|
53
53
|
|
|
54
54
|
except Exception as e:
|
|
55
55
|
return Response(
|
|
56
56
|
{"error": f"Failed to serve file: {str(e)}"},
|
|
57
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
58
|
-
)
|
|
57
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
58
|
+
)
|
|
@@ -12,6 +12,7 @@ class VideoMetadataStatsView(APIView):
|
|
|
12
12
|
"""
|
|
13
13
|
GET media/videos/{pk}/metadata/ - Get video metadata including sensitivity analysis
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
permission_classes = [EnvironmentAwarePermission]
|
|
16
17
|
|
|
17
18
|
def get(self, request, pk):
|
|
@@ -19,11 +20,11 @@ class VideoMetadataStatsView(APIView):
|
|
|
19
20
|
|
|
20
21
|
# Get or calculate metadata
|
|
21
22
|
metadata = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
"sensitiveFrameCount": getattr(video, "sensitive_frame_count", None),
|
|
24
|
+
"totalFrames": getattr(video, "total_frames", None),
|
|
25
|
+
"sensitiveRatio": getattr(video, "sensitive_ratio", None),
|
|
26
|
+
"duration": getattr(video, "duration", None),
|
|
27
|
+
"resolution": getattr(video, "resolution", None),
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
return Response(metadata, status=status.HTTP_200_OK)
|
|
30
|
+
return Response(metadata, status=status.HTTP_200_OK)
|
|
@@ -12,13 +12,14 @@ class VideoProcessingHistoryView(APIView):
|
|
|
12
12
|
"""
|
|
13
13
|
GET /api/video-processing-history/{id}/ - Get processing history for a video
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
permission_classes = [EnvironmentAwarePermission]
|
|
16
17
|
|
|
17
18
|
def get(self, request, pk):
|
|
18
19
|
_video = get_object_or_404(VideoFile, pk=pk)
|
|
19
20
|
|
|
20
21
|
# For now, return empty history - can be extended with actual history tracking
|
|
21
|
-
#TODO plan when to implement this
|
|
22
|
+
# TODO plan when to implement this
|
|
22
23
|
history = []
|
|
23
24
|
|
|
24
|
-
return Response(history, status=status.HTTP_200_OK)
|
|
25
|
+
return Response(history, status=status.HTTP_200_OK)
|
|
@@ -12,37 +12,38 @@ class VideoRemoveFramesView(APIView):
|
|
|
12
12
|
"""
|
|
13
13
|
POST /api/video-remove-frames/{id}/ - Remove frames from video using streaming processing
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
permission_classes = [EnvironmentAwarePermission]
|
|
16
17
|
|
|
17
18
|
def post(self, request, pk):
|
|
18
19
|
video = get_object_or_404(VideoFile, pk=pk)
|
|
19
20
|
|
|
20
|
-
selection_method = request.data.get(
|
|
21
|
-
detection_engine = request.data.get(
|
|
22
|
-
use_streaming = request.data.get(
|
|
23
|
-
manual_frames = request.data.get(
|
|
21
|
+
selection_method = request.data.get("selection_method", "automatic")
|
|
22
|
+
detection_engine = request.data.get("detection_engine", "minicpm")
|
|
23
|
+
use_streaming = request.data.get("use_streaming", True)
|
|
24
|
+
manual_frames = request.data.get("manual_frames")
|
|
24
25
|
|
|
25
26
|
try:
|
|
26
27
|
# Start async task for frame removal
|
|
27
28
|
from endoreg_db.tasks.video_processing_tasks import remove_video_frames_task
|
|
28
29
|
|
|
29
30
|
task_data = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
"video_id": pk,
|
|
32
|
+
"selection_method": selection_method,
|
|
33
|
+
"detection_engine": detection_engine,
|
|
34
|
+
"use_streaming": use_streaming,
|
|
35
|
+
"manual_frames": manual_frames,
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
task = remove_video_frames_task.delay(**task_data)
|
|
38
39
|
|
|
39
40
|
return Response(
|
|
40
41
|
{"task_id": task.id, "status": "started"},
|
|
41
|
-
status=status.HTTP_202_ACCEPTED
|
|
42
|
+
status=status.HTTP_202_ACCEPTED,
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
except Exception as e:
|
|
45
46
|
return Response(
|
|
46
47
|
{"error": f"Failed to start frame removal task: {str(e)}"},
|
|
47
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
48
|
-
)
|
|
48
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
49
|
+
)
|