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
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Video processing tasks for Celery-based asynchronous video processing.
|
|
3
|
-
|
|
4
|
-
This module provides Celery tasks for:
|
|
5
|
-
- Video masking with streaming FFmpeg processing
|
|
6
|
-
- Frame removal with streaming optimization
|
|
7
|
-
- Video reprocessing workflows
|
|
8
|
-
- Progress tracking and status updates
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Dict, Any, List, Optional
|
|
13
|
-
from celery import shared_task
|
|
14
|
-
from celery.utils.log import get_task_logger
|
|
15
|
-
from django.shortcuts import get_object_or_404
|
|
16
|
-
|
|
17
|
-
logger = get_task_logger(__name__)
|
|
18
|
-
|
|
19
|
-
@shared_task(bind=True)
|
|
20
|
-
def apply_video_mask_task(self, video_id: int, mask_type: str = 'device_default',
|
|
21
|
-
device_name: str = 'olympus_cv_1500', use_streaming: bool = True,
|
|
22
|
-
custom_mask: Optional[Dict[str, Any]] = None):
|
|
23
|
-
"""
|
|
24
|
-
Apply mask to video using streaming processing.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
video_id: ID of the VideoFile to process
|
|
28
|
-
mask_type: Type of mask to apply ('device_default', 'roi_based', 'custom')
|
|
29
|
-
device_name: Device name for default mask
|
|
30
|
-
use_streaming: Whether to use streaming processing (recommended)
|
|
31
|
-
custom_mask: Custom mask configuration (if mask_type='custom')
|
|
32
|
-
"""
|
|
33
|
-
try:
|
|
34
|
-
# Update task progress
|
|
35
|
-
self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Initializing mask application...'})
|
|
36
|
-
|
|
37
|
-
# Import models here to avoid circular imports
|
|
38
|
-
from endoreg_db.models import VideoFile
|
|
39
|
-
from lx_anonymizer.frame_cleaner import FrameCleaner
|
|
40
|
-
|
|
41
|
-
# Get video file
|
|
42
|
-
video = get_object_or_404(VideoFile, pk=video_id)
|
|
43
|
-
video_path = Path(video.file.path)
|
|
44
|
-
|
|
45
|
-
if not video_path.exists():
|
|
46
|
-
raise FileNotFoundError(f"Video file not found: {video_path}")
|
|
47
|
-
|
|
48
|
-
# Create output path
|
|
49
|
-
output_dir = video_path.parent / "processed"
|
|
50
|
-
output_dir.mkdir(exist_ok=True)
|
|
51
|
-
output_path = output_dir / f"{video_path.stem}_masked{video_path.suffix}"
|
|
52
|
-
|
|
53
|
-
self.update_state(state='PROGRESS', meta={'progress': 10, 'message': 'Setting up FrameCleaner...'})
|
|
54
|
-
|
|
55
|
-
# Initialize FrameCleaner
|
|
56
|
-
cleaner = FrameCleaner()
|
|
57
|
-
|
|
58
|
-
# Determine mask configuration
|
|
59
|
-
if mask_type == 'custom' and custom_mask:
|
|
60
|
-
mask_config = custom_mask
|
|
61
|
-
elif mask_type == 'roi_based':
|
|
62
|
-
# Would need ROI data from video metadata
|
|
63
|
-
mask_config = cleaner._load_mask(device_name) # Fallback for now
|
|
64
|
-
else: # device_default
|
|
65
|
-
mask_config = cleaner._load_mask(device_name)
|
|
66
|
-
|
|
67
|
-
self.update_state(state='PROGRESS', meta={'progress': 20, 'message': f'Applying {mask_type} mask...'})
|
|
68
|
-
|
|
69
|
-
# Apply mask using streaming
|
|
70
|
-
if use_streaming:
|
|
71
|
-
success = cleaner._mask_video_streaming(
|
|
72
|
-
video_path, mask_config, output_path, use_named_pipe=True
|
|
73
|
-
)
|
|
74
|
-
else:
|
|
75
|
-
success = cleaner._mask_video(video_path, mask_config, output_path)
|
|
76
|
-
|
|
77
|
-
if not success:
|
|
78
|
-
raise RuntimeError("Video masking failed")
|
|
79
|
-
|
|
80
|
-
self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
|
|
81
|
-
|
|
82
|
-
# Verify output
|
|
83
|
-
if not output_path.exists() or output_path.stat().st_size == 0:
|
|
84
|
-
raise RuntimeError("Output video is empty or missing")
|
|
85
|
-
|
|
86
|
-
result = {
|
|
87
|
-
'status': 'completed',
|
|
88
|
-
'output_path': str(output_path),
|
|
89
|
-
'mask_type': mask_type,
|
|
90
|
-
'device_name': device_name,
|
|
91
|
-
'use_streaming': use_streaming,
|
|
92
|
-
'output_size': output_path.stat().st_size,
|
|
93
|
-
'message': 'Video masking completed successfully'
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
logger.info(f"Video masking completed for video {video_id}: {output_path}")
|
|
97
|
-
return result
|
|
98
|
-
|
|
99
|
-
except Exception as e:
|
|
100
|
-
logger.error(f"Video masking failed for video {video_id}: {e}")
|
|
101
|
-
self.update_state(
|
|
102
|
-
state='FAILURE',
|
|
103
|
-
meta={'error': str(e), 'message': f'Video masking failed: {e}'}
|
|
104
|
-
)
|
|
105
|
-
raise
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def _setup_frame_removal(video_id: int, detection_engine: str):
|
|
109
|
-
from endoreg_db.models import VideoFile
|
|
110
|
-
from lx_anonymizer.frame_cleaner import FrameCleaner
|
|
111
|
-
from django.shortcuts import get_object_or_404
|
|
112
|
-
video = get_object_or_404(VideoFile, pk=video_id)
|
|
113
|
-
video_path = Path(video.raw_file.path)
|
|
114
|
-
if not video_path.exists():
|
|
115
|
-
raise FileNotFoundError(f"Video file not found: {video_path}")
|
|
116
|
-
output_dir = video_path.parent / "processed"
|
|
117
|
-
output_dir.mkdir(exist_ok=True)
|
|
118
|
-
output_path = output_dir / f"{video_path.stem}_cleaned{video_path.suffix}"
|
|
119
|
-
use_minicpm = detection_engine == 'minicpm'
|
|
120
|
-
cleaner = FrameCleaner()
|
|
121
|
-
return video, video_path, output_path, cleaner
|
|
122
|
-
|
|
123
|
-
def _detect_sensitive_frames(self, cleaner, video_path, selection_method, manual_frames, total_frames):
|
|
124
|
-
frames_to_remove = []
|
|
125
|
-
if selection_method == 'manual' and manual_frames:
|
|
126
|
-
frames_to_remove = manual_frames
|
|
127
|
-
self.update_state(state='PROGRESS', meta={'progress': 50, 'message': f'Using manual frame selection: {len(frames_to_remove)} frames'})
|
|
128
|
-
elif selection_method == 'automatic':
|
|
129
|
-
self.update_state(state='PROGRESS', meta={'progress': 20, 'message': 'Detecting sensitive frames...'})
|
|
130
|
-
if total_frames > 10000:
|
|
131
|
-
self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Using statistical sampling for large video...'})
|
|
132
|
-
sensitive_frames, estimated_ratio, early_stopped = cleaner._sample_frames_coroutine(
|
|
133
|
-
video_path, total_frames, max_samples=500
|
|
134
|
-
)
|
|
135
|
-
frames_to_remove = sensitive_frames
|
|
136
|
-
else:
|
|
137
|
-
self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Analyzing all frames...'})
|
|
138
|
-
for abs_i, gray_frame, skip in cleaner._iter_video(video_path, total_frames):
|
|
139
|
-
progress = 30 + (abs_i / total_frames) * 40 # 30-70% for detection
|
|
140
|
-
if abs_i % 100 == 0:
|
|
141
|
-
self.update_state(state='PROGRESS', meta={
|
|
142
|
-
'progress': int(progress),
|
|
143
|
-
'message': f'Analyzing frame {abs_i}/{total_frames}...'
|
|
144
|
-
})
|
|
145
|
-
ocr_text, avg_conf, _ = cleaner.frame_ocr.extract_text_from_frame(
|
|
146
|
-
gray_frame, roi=None, high_quality=True
|
|
147
|
-
)
|
|
148
|
-
if ocr_text:
|
|
149
|
-
frame_metadata = cleaner.extract_metadata_deepseek(ocr_text)
|
|
150
|
-
if not frame_metadata:
|
|
151
|
-
frame_metadata = cleaner.frame_metadata_extractor.extract_metadata_from_frame_text(ocr_text)
|
|
152
|
-
has_sensitive = cleaner.frame_metadata_extractor.is_sensitive_content(frame_metadata)
|
|
153
|
-
if has_sensitive:
|
|
154
|
-
frames_to_remove.append(abs_i)
|
|
155
|
-
return frames_to_remove
|
|
156
|
-
|
|
157
|
-
def _remove_frames_from_video(cleaner, video_path, frames_to_remove, output_path, use_streaming):
|
|
158
|
-
if use_streaming:
|
|
159
|
-
return cleaner.remove_frames_from_video_streaming(
|
|
160
|
-
video_path, frames_to_remove, output_path, use_named_pipe=True
|
|
161
|
-
)
|
|
162
|
-
else:
|
|
163
|
-
return cleaner.remove_frames_from_video(
|
|
164
|
-
video_path, frames_to_remove, output_path
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
def _verify_frame_removal_output(output_path):
|
|
168
|
-
if not output_path.exists() or output_path.stat().st_size == 0:
|
|
169
|
-
raise RuntimeError("Output video is empty or missing")
|
|
170
|
-
|
|
171
|
-
@shared_task(bind=True)
|
|
172
|
-
def remove_video_frames_task(self, video_id: int, selection_method: str = 'automatic',
|
|
173
|
-
detection_engine: str = 'minicpm', use_streaming: bool = True,
|
|
174
|
-
manual_frames: Optional[List[int]] = None):
|
|
175
|
-
"""
|
|
176
|
-
Remove frames from video using streaming processing.
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
video_id: ID of the VideoFile to process
|
|
180
|
-
selection_method: 'automatic' or 'manual'
|
|
181
|
-
detection_engine: 'minicpm' or 'traditional'
|
|
182
|
-
use_streaming: Whether to use streaming processing
|
|
183
|
-
manual_frames: List of frame indices to remove (for manual selection)
|
|
184
|
-
"""
|
|
185
|
-
try:
|
|
186
|
-
# Update task progress
|
|
187
|
-
self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Initializing frame removal...'})
|
|
188
|
-
|
|
189
|
-
video, video_path, output_path, cleaner = _setup_frame_removal(video_id, detection_engine)
|
|
190
|
-
|
|
191
|
-
self.update_state(state='PROGRESS', meta={'progress': 10, 'message': 'Setting up FrameCleaner...'})
|
|
192
|
-
|
|
193
|
-
# Get total frame count
|
|
194
|
-
total_frames = cleaner._get_total_frames()
|
|
195
|
-
|
|
196
|
-
frames_to_remove = _detect_sensitive_frames(
|
|
197
|
-
self, cleaner, video_path, selection_method, manual_frames, total_frames
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
self.update_state(state='PROGRESS', meta={'progress': 70, 'message': f'Removing {len(frames_to_remove)} frames...'})
|
|
201
|
-
|
|
202
|
-
# Remove frames using streaming
|
|
203
|
-
success = _remove_frames_from_video(cleaner, video_path, frames_to_remove, output_path, use_streaming)
|
|
204
|
-
|
|
205
|
-
if not success:
|
|
206
|
-
raise RuntimeError("Frame removal failed")
|
|
207
|
-
|
|
208
|
-
self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
|
|
209
|
-
|
|
210
|
-
_verify_frame_removal_output(output_path)
|
|
211
|
-
|
|
212
|
-
result = {
|
|
213
|
-
'status': 'completed',
|
|
214
|
-
'output_path': str(output_path),
|
|
215
|
-
'frames_removed': len(frames_to_remove),
|
|
216
|
-
'selection_method': selection_method,
|
|
217
|
-
'detection_engine': detection_engine,
|
|
218
|
-
'use_streaming': use_streaming,
|
|
219
|
-
'output_size': output_path.stat().st_size,
|
|
220
|
-
'message': f'Successfully removed {len(frames_to_remove)} frames'
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
logger.info(f"Frame removal completed for video {video_id}: {len(frames_to_remove)} frames removed")
|
|
224
|
-
return result
|
|
225
|
-
|
|
226
|
-
except Exception as e:
|
|
227
|
-
logger.error(f"Frame removal failed for video {video_id}: {e}")
|
|
228
|
-
self.update_state(
|
|
229
|
-
state='FAILURE',
|
|
230
|
-
meta={'error': str(e), 'message': f'Frame removal failed: {e}'}
|
|
231
|
-
)
|
|
232
|
-
raise
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
@shared_task(bind=True)
|
|
236
|
-
def reprocess_video_task(self, video_id: int):
|
|
237
|
-
"""
|
|
238
|
-
Reprocess video with updated settings.
|
|
239
|
-
|
|
240
|
-
Args:
|
|
241
|
-
video_id: ID of the VideoFile to reprocess
|
|
242
|
-
"""
|
|
243
|
-
try:
|
|
244
|
-
self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Starting video reprocessing...'})
|
|
245
|
-
|
|
246
|
-
# Import models here to avoid circular imports
|
|
247
|
-
from endoreg_db.models import VideoFile
|
|
248
|
-
from lx_anonymizer.frame_cleaner import FrameCleaner
|
|
249
|
-
|
|
250
|
-
# Get video file
|
|
251
|
-
video = get_object_or_404(VideoFile, pk=video_id)
|
|
252
|
-
video_path = Path(video.file.path)
|
|
253
|
-
|
|
254
|
-
if not video_path.exists():
|
|
255
|
-
raise FileNotFoundError(f"Video file not found: {video_path}")
|
|
256
|
-
|
|
257
|
-
self.update_state(state='PROGRESS', meta={'progress': 20, 'message': 'Initializing FrameCleaner...'})
|
|
258
|
-
|
|
259
|
-
# Initialize FrameCleaner with optimal settings
|
|
260
|
-
cleaner = FrameCleaner()
|
|
261
|
-
|
|
262
|
-
# Create output path
|
|
263
|
-
output_dir = video_path.parent / "processed"
|
|
264
|
-
output_dir.mkdir(exist_ok=True)
|
|
265
|
-
output_path = output_dir / f"{video_path.stem}_reprocessed{video_path.suffix}"
|
|
266
|
-
|
|
267
|
-
self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Analyzing video...'})
|
|
268
|
-
|
|
269
|
-
# Perform full analysis
|
|
270
|
-
analysis_result = cleaner.analyze_video_sensitivity()
|
|
271
|
-
|
|
272
|
-
self.update_state(state='PROGRESS', meta={'progress': 60, 'message': f'Processing with {analysis_result["recommended_method"]}...'})
|
|
273
|
-
|
|
274
|
-
# Process based on analysis recommendation
|
|
275
|
-
if analysis_result["recommended_method"] == "masking":
|
|
276
|
-
# Apply device-specific masking
|
|
277
|
-
mask_config = cleaner._load_mask("olympus_cv_1500") # Default device
|
|
278
|
-
success = cleaner._mask_video_streaming(
|
|
279
|
-
video_path, mask_config, output_path, use_named_pipe=True
|
|
280
|
-
)
|
|
281
|
-
else:
|
|
282
|
-
# Remove sensitive frames
|
|
283
|
-
sensitive_frames = analysis_result.get("sensitive_frame_list", [])
|
|
284
|
-
# Filter out string elements like "...truncated"
|
|
285
|
-
sensitive_frames = [f for f in sensitive_frames if isinstance(f, int)]
|
|
286
|
-
|
|
287
|
-
success = cleaner.remove_frames_from_video_streaming(
|
|
288
|
-
video_path, sensitive_frames, output_path, use_named_pipe=True
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
if not success:
|
|
292
|
-
raise RuntimeError("Video reprocessing failed")
|
|
293
|
-
|
|
294
|
-
self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
|
|
295
|
-
|
|
296
|
-
# Update video metadata with analysis results
|
|
297
|
-
if hasattr(video, 'sensitive_frame_count'):
|
|
298
|
-
video.sensitive_frame_count = analysis_result.get('sensitive_frames', 0)
|
|
299
|
-
if hasattr(video, 'total_frames'):
|
|
300
|
-
video.total_frames = analysis_result.get('total_frames', 0)
|
|
301
|
-
if hasattr(video, 'sensitive_ratio'):
|
|
302
|
-
video.sensitive_ratio = analysis_result.get('sensitivity_ratio', 0.0)
|
|
303
|
-
|
|
304
|
-
try:
|
|
305
|
-
video.save()
|
|
306
|
-
except Exception as e:
|
|
307
|
-
logger.warning(f"Could not save video metadata: {e}")
|
|
308
|
-
|
|
309
|
-
result = {
|
|
310
|
-
'status': 'completed',
|
|
311
|
-
'output_path': str(output_path),
|
|
312
|
-
'analysis_result': analysis_result,
|
|
313
|
-
'processing_method': analysis_result["recommended_method"],
|
|
314
|
-
'output_size': output_path.stat().st_size if output_path.exists() else 0,
|
|
315
|
-
'message': 'Video reprocessing completed successfully'
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
logger.info(f"Video reprocessing completed for video {video_id}")
|
|
319
|
-
return result
|
|
320
|
-
|
|
321
|
-
except Exception as e:
|
|
322
|
-
logger.error(f"Video reprocessing failed for video {video_id}: {e}")
|
|
323
|
-
self.update_state(
|
|
324
|
-
state='FAILURE',
|
|
325
|
-
meta={'error': str(e), 'message': f'Video reprocessing failed: {e}'}
|
|
326
|
-
)
|
|
327
|
-
raise
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Automatisierte Internationalisierung für medizinische Terminologie
|
|
3
|
-
Ersetzt manuelle name_de/name_en Felder durch django-modeltranslation
|
|
4
|
-
"""
|
|
5
|
-
from modeltranslation.translator import TranslationOptions, translator
|
|
6
|
-
# Source: https://github.com/deschler/django-modeltranslation
|
|
7
|
-
#https://django-modeltranslation.readthedocs.io/en/latest/installation.html#advanced-settings
|
|
8
|
-
|
|
9
|
-
from endoreg_db.models import (
|
|
10
|
-
Examination,
|
|
11
|
-
Finding,
|
|
12
|
-
FindingClassification,
|
|
13
|
-
FindingClassificationChoice,
|
|
14
|
-
FindingIntervention
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
class ExaminationTranslationOptions(TranslationOptions):
|
|
18
|
-
fields = ('name', 'description')
|
|
19
|
-
required_languages = ('de', 'en')
|
|
20
|
-
fallback_languages = {'default': ('en', 'de')}
|
|
21
|
-
|
|
22
|
-
translator.register(Examination, ExaminationTranslationOptions)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class FindingTranslationOptions(TranslationOptions):
|
|
26
|
-
fields = ('name', 'description')
|
|
27
|
-
required_languages = ('de', 'en')
|
|
28
|
-
fallback_languages = {'default': ('en', 'de')}
|
|
29
|
-
|
|
30
|
-
translator.register(Finding, FindingTranslationOptions)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class FindingClassificationTranslationOptions(TranslationOptions):
|
|
34
|
-
fields = ('name', 'description')
|
|
35
|
-
required_languages = ('de', 'en')
|
|
36
|
-
fallback_languages = {'default': ('en', 'de')}
|
|
37
|
-
|
|
38
|
-
translator.register(FindingClassification, FindingClassificationTranslationOptions)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class FindingClassificationChoiceTranslationOptions(TranslationOptions):
|
|
42
|
-
fields = ('name', 'description')
|
|
43
|
-
required_languages = ('de', 'en')
|
|
44
|
-
fallback_languages = {'default': ('en', 'de')}
|
|
45
|
-
|
|
46
|
-
translator.register(FindingClassificationChoice, FindingClassificationChoiceTranslationOptions)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class InterventionTranslationOptions(TranslationOptions):
|
|
50
|
-
fields = ('name', 'description')
|
|
51
|
-
required_languages = ('de', 'en')
|
|
52
|
-
fallback_languages = {'default': ('en', 'de')}
|
|
53
|
-
|
|
54
|
-
translator.register(FindingIntervention, InterventionTranslationOptions)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# Mixin für automatische Sprachauswahl in Serializers
|
|
58
|
-
class TranslatedFieldMixin:
|
|
59
|
-
"""
|
|
60
|
-
Mixin für Serializer um automatisch die richtige Sprache zu wählen
|
|
61
|
-
Ersetzt manuelle get_name_display() Methoden
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
def get_translated_field(self, obj, field_name):
|
|
65
|
-
"""
|
|
66
|
-
Automatische Sprachauswahl basierend auf Accept-Language Header
|
|
67
|
-
"""
|
|
68
|
-
request = self.context.get('request')
|
|
69
|
-
if request:
|
|
70
|
-
# Django's get_language() berücksichtigt Accept-Language Header
|
|
71
|
-
from django.utils.translation import get_language
|
|
72
|
-
current_language = get_language()
|
|
73
|
-
|
|
74
|
-
# Versuche sprachspezifisches Feld
|
|
75
|
-
translated_field = f"{field_name}_{current_language}"
|
|
76
|
-
translated_value = getattr(obj, translated_field, None)
|
|
77
|
-
|
|
78
|
-
if translated_value:
|
|
79
|
-
return translated_value
|
|
80
|
-
|
|
81
|
-
# Fallback auf Hauptfeld
|
|
82
|
-
return getattr(obj, field_name, '')
|
|
83
|
-
|
|
84
|
-
def to_representation(self, instance):
|
|
85
|
-
"""
|
|
86
|
-
Automatisches Ersetzen von name/description mit übersetzten Versionen
|
|
87
|
-
"""
|
|
88
|
-
data = super().to_representation(instance)
|
|
89
|
-
|
|
90
|
-
# Ersetze name mit übersetzter Version
|
|
91
|
-
if 'name' in data:
|
|
92
|
-
data['name'] = self.get_translated_field(instance, 'name')
|
|
93
|
-
|
|
94
|
-
# Ersetze description mit übersetzter Version
|
|
95
|
-
if 'description' in data:
|
|
96
|
-
data['description'] = self.get_translated_field(instance, 'description')
|
|
97
|
-
|
|
98
|
-
return data
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# Command für Migration bestehender Daten
|
|
102
|
-
class TranslationMigrationHelper:
|
|
103
|
-
"""
|
|
104
|
-
Helper für Migration von name_de/name_en zu modeltranslation
|
|
105
|
-
"""
|
|
106
|
-
|
|
107
|
-
@staticmethod
|
|
108
|
-
def migrate_examination_data():
|
|
109
|
-
"""Migriere bestehende Examination Daten"""
|
|
110
|
-
from endoreg_db.models import Examination
|
|
111
|
-
|
|
112
|
-
for examination in Examination.objects.all():
|
|
113
|
-
# Migriere name_de/name_en zu name_de/name_en (modeltranslation)
|
|
114
|
-
if hasattr(examination, 'name_de') and examination.name_de:
|
|
115
|
-
examination.name_de = examination.name_de
|
|
116
|
-
if hasattr(examination, 'name_en') and examination.name_en:
|
|
117
|
-
examination.name_en = examination.name_en
|
|
118
|
-
|
|
119
|
-
# Fallback auf 'name' wenn Übersetzungen fehlen
|
|
120
|
-
if not examination.name_de and examination.name:
|
|
121
|
-
examination.name_de = examination.name
|
|
122
|
-
if not examination.name_en and examination.name:
|
|
123
|
-
examination.name_en = examination.name
|
|
124
|
-
|
|
125
|
-
examination.save()
|
|
126
|
-
|
|
127
|
-
@staticmethod
|
|
128
|
-
def migrate_all_models():
|
|
129
|
-
"""Migriere alle Modelle mit Übersetzungen"""
|
|
130
|
-
models_to_migrate = [
|
|
131
|
-
'Examination', 'Finding', 'FindingClassification',
|
|
132
|
-
'FindingClassificationChoice', 'Intervention'
|
|
133
|
-
]
|
|
134
|
-
|
|
135
|
-
for model_name in models_to_migrate:
|
|
136
|
-
print(f"Migriere {model_name}...")
|
|
137
|
-
# Implementierung für jedes Modell analog zu migrate_examination_data()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
# Erweiterte YAML Fixtures für Übersetzungen
|
|
141
|
-
class TranslatedFixtureLoader:
|
|
142
|
-
"""
|
|
143
|
-
Loader für YAML Fixtures mit Übersetzungsunterstützung
|
|
144
|
-
Automatische Erkennung und Laden von name_de/name_en Feldern
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
@staticmethod
|
|
148
|
-
def load_translated_fixture(model_class, fixture_data):
|
|
149
|
-
"""
|
|
150
|
-
Lade Fixture mit automatischer Übersetzungszuordnung
|
|
151
|
-
"""
|
|
152
|
-
for item in fixture_data:
|
|
153
|
-
fields = item.get('fields', {})
|
|
154
|
-
|
|
155
|
-
# Erstelle oder aktualisiere Objekt
|
|
156
|
-
obj, created = model_class.objects.update_or_create(
|
|
157
|
-
name=fields.get('name'),
|
|
158
|
-
defaults=fields
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
# Setze Übersetzungen falls vorhanden
|
|
162
|
-
if 'name_de' in fields:
|
|
163
|
-
obj.name_de = fields['name_de']
|
|
164
|
-
if 'name_en' in fields:
|
|
165
|
-
obj.name_en = fields['name_en']
|
|
166
|
-
|
|
167
|
-
obj.save()
|
|
168
|
-
|
|
169
|
-
action = "erstellt" if created else "aktualisiert"
|
|
170
|
-
print(f"{model_class.__name__} '{obj.name}' {action}")
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# Settings für django-modeltranslation
|
|
174
|
-
MODELTRANSLATION_SETTINGS = {
|
|
175
|
-
'AVAILABLE_LANGUAGES': ('de', 'en'),
|
|
176
|
-
'DEFAULT_LANGUAGE': 'en',
|
|
177
|
-
'FALLBACK_LANGUAGES': {
|
|
178
|
-
'default': ('en', 'de'),
|
|
179
|
-
},
|
|
180
|
-
'AUTO_POPULATE': True, # Automatisches Füllen fehlender Übersetzungen
|
|
181
|
-
'ENABLE_REGISTRATIONS': True,
|
|
182
|
-
}
|
|
File without changes
|
|
File without changes
|