endoreg-db 0.8.8.9__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 +146 -83
- 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/migrations/__init__.py +0 -0
- 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 -3
- 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/ffmpeg_wrapper.py +217 -52
- 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.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +436 -433
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +0 -119
- 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.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
from endoreg_db.models import
|
|
2
|
-
|
|
1
|
+
from endoreg_db.models import (
|
|
2
|
+
Examination,
|
|
3
|
+
Finding,
|
|
4
|
+
FindingClassification,
|
|
5
|
+
PatientFinding,
|
|
6
|
+
)
|
|
7
|
+
from endoreg_db.serializers.patient_finding import (
|
|
8
|
+
PatientFindingClassificationSerializer,
|
|
9
|
+
PatientFindingDetailSerializer,
|
|
10
|
+
PatientFindingListSerializer,
|
|
11
|
+
PatientFindingWriteSerializer,
|
|
12
|
+
)
|
|
3
13
|
|
|
4
14
|
|
|
5
15
|
from django.db import transaction
|
|
@@ -20,30 +30,39 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
|
20
30
|
Hochoptimiertes ViewSet für PatientFinding mit Query-Optimierung,
|
|
21
31
|
Bulk-Endpoints und intelligenter Serializer-Auswahl
|
|
22
32
|
"""
|
|
33
|
+
|
|
23
34
|
permission_classes = [IsAuthenticated]
|
|
24
35
|
filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter]
|
|
25
|
-
filterset_fields = [
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
filterset_fields = [
|
|
37
|
+
"patient_examination__patient",
|
|
38
|
+
"finding",
|
|
39
|
+
"patient_examination__examination",
|
|
40
|
+
]
|
|
41
|
+
ordering_fields = ["id", "patient_examination__date_start"]
|
|
42
|
+
search_fields = [
|
|
43
|
+
"finding__name",
|
|
44
|
+
"patient_examination__patient__first_name",
|
|
45
|
+
"patient_examination__patient__last_name",
|
|
46
|
+
]
|
|
28
47
|
|
|
29
48
|
def get_queryset(self):
|
|
30
49
|
"""Optimierte QuerySet mit Prefetching basierend auf Action"""
|
|
31
50
|
base_queryset = PatientFinding.objects.select_related(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
"patient_examination__patient",
|
|
52
|
+
"patient_examination__examination",
|
|
53
|
+
"finding",
|
|
35
54
|
)
|
|
36
55
|
|
|
37
56
|
# Detail-Views: fetch nested relations
|
|
38
|
-
if self.action in [
|
|
57
|
+
if self.action in ["retrieve", "update", "partial_update"]:
|
|
39
58
|
return base_queryset.prefetch_related(
|
|
40
59
|
"classifications__classification",
|
|
41
60
|
"classifications__choice",
|
|
42
61
|
# 'locations__location_classification',
|
|
43
62
|
# 'locations__location_choice',
|
|
44
|
-
# 'morphologies__morphology_classification',
|
|
63
|
+
# 'morphologies__morphology_classification',
|
|
45
64
|
# 'morphologies__morphology_choice',
|
|
46
|
-
|
|
65
|
+
"interventions__intervention",
|
|
47
66
|
)
|
|
48
67
|
|
|
49
68
|
# For List-Views: fetch only necessary relations
|
|
@@ -51,90 +70,90 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
|
51
70
|
|
|
52
71
|
def get_serializer_class(self):
|
|
53
72
|
"""Intelligente Serializer-Auswahl basierend auf Action"""
|
|
54
|
-
if self.action ==
|
|
73
|
+
if self.action == "list":
|
|
55
74
|
return PatientFindingListSerializer
|
|
56
|
-
elif self.action in [
|
|
75
|
+
elif self.action in ["create", "update", "partial_update"]:
|
|
57
76
|
return PatientFindingWriteSerializer
|
|
58
77
|
else:
|
|
59
78
|
return PatientFindingDetailSerializer
|
|
60
79
|
|
|
61
80
|
@method_decorator(cache_page(60 * 15)) # 15 Minuten Cache
|
|
62
|
-
@method_decorator(vary_on_headers(
|
|
63
|
-
@action(detail=False, methods=[
|
|
81
|
+
@method_decorator(vary_on_headers("Accept-Language"))
|
|
82
|
+
@action(detail=False, methods=["get"])
|
|
64
83
|
def examination_manifest(self, request):
|
|
65
84
|
"""
|
|
66
85
|
Bulk-Endpoint: Liefert alle Setup-Daten für eine Examination in einem Call
|
|
67
86
|
"""
|
|
68
|
-
examination_id = request.query_params.get(
|
|
87
|
+
examination_id = request.query_params.get("examination_id")
|
|
69
88
|
if not examination_id:
|
|
70
89
|
return Response(
|
|
71
|
-
{
|
|
72
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
90
|
+
{"error": "examination_id parameter erforderlich"},
|
|
91
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
73
92
|
)
|
|
74
93
|
|
|
75
94
|
try:
|
|
76
95
|
examination = Examination.objects.get(id=examination_id)
|
|
77
96
|
except Examination.DoesNotExist:
|
|
78
97
|
return Response(
|
|
79
|
-
{
|
|
80
|
-
status=status.HTTP_404_NOT_FOUND
|
|
98
|
+
{"error": "Examination nicht gefunden"},
|
|
99
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
81
100
|
)
|
|
82
101
|
|
|
83
102
|
# Alle Daten in optimierten Queries laden
|
|
84
103
|
findings = examination.get_available_findings().prefetch_related(
|
|
85
|
-
|
|
86
|
-
'morphology_classifications__choices'
|
|
104
|
+
"location_classifications__choices", "morphology_classifications__choices"
|
|
87
105
|
)
|
|
88
106
|
|
|
89
107
|
manifest_data = {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
"examination": {
|
|
109
|
+
"id": examination.id,
|
|
110
|
+
"name": examination.name,
|
|
93
111
|
# 'name_de': examination.name_de,
|
|
94
112
|
# 'name_en': examination.name_en,
|
|
95
113
|
},
|
|
96
|
-
|
|
114
|
+
"findings": [],
|
|
97
115
|
}
|
|
98
116
|
|
|
99
117
|
for finding in findings:
|
|
100
118
|
assert isinstance(finding, Finding), "Expected Finding instance"
|
|
101
119
|
finding_data = {
|
|
102
|
-
|
|
103
|
-
|
|
120
|
+
"id": finding.id,
|
|
121
|
+
"name": finding.name,
|
|
104
122
|
# 'name_de': finding.name_de,
|
|
105
123
|
# 'name_en': finding.name_en,
|
|
106
124
|
"classifications": [],
|
|
107
|
-
|
|
108
|
-
|
|
125
|
+
"location_classifications": [],
|
|
126
|
+
"morphology_classifications": [],
|
|
109
127
|
}
|
|
110
128
|
|
|
111
129
|
for classification_obj in finding.get_classifications():
|
|
112
|
-
assert isinstance(classification_obj, FindingClassification),
|
|
130
|
+
assert isinstance(classification_obj, FindingClassification), (
|
|
131
|
+
"Expected FindingClassification instance"
|
|
132
|
+
)
|
|
113
133
|
classification_data = {
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
"id": classification_obj.id,
|
|
135
|
+
"name": classification_obj.name,
|
|
116
136
|
"choices": [
|
|
117
137
|
{
|
|
118
|
-
|
|
119
|
-
|
|
138
|
+
"id": choice.id,
|
|
139
|
+
"name": choice.name,
|
|
120
140
|
}
|
|
121
141
|
for choice in classification_obj.choices.all()
|
|
122
|
-
]
|
|
142
|
+
],
|
|
123
143
|
}
|
|
124
144
|
|
|
125
|
-
finding_data[
|
|
145
|
+
finding_data["classifications"].append(classification_data)
|
|
126
146
|
|
|
127
|
-
@action(detail=False, methods=[
|
|
147
|
+
@action(detail=False, methods=["post"])
|
|
128
148
|
def bulk_create(self, request):
|
|
129
149
|
"""
|
|
130
150
|
Bulk-Endpoint für gleichzeitige Erstellung mehrerer PatientFindings
|
|
131
151
|
Optimiert für Mobile Apps mit schlechter Verbindung
|
|
132
152
|
"""
|
|
133
|
-
findings_data = request.data.get(
|
|
153
|
+
findings_data = request.data.get("findings", [])
|
|
134
154
|
if not findings_data:
|
|
135
155
|
return Response(
|
|
136
|
-
{
|
|
137
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
156
|
+
{"error": "findings array required"}, status=status.HTTP_400_BAD_REQUEST
|
|
138
157
|
)
|
|
139
158
|
|
|
140
159
|
created_findings = []
|
|
@@ -146,33 +165,34 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
|
146
165
|
if serializer.is_valid():
|
|
147
166
|
try:
|
|
148
167
|
finding = serializer.save()
|
|
149
|
-
created_findings.append(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
'status': 'created'
|
|
153
|
-
})
|
|
168
|
+
created_findings.append(
|
|
169
|
+
{"index": i, "id": finding.id, "status": "created"}
|
|
170
|
+
)
|
|
154
171
|
except Exception as e:
|
|
155
|
-
errors.append({
|
|
156
|
-
'index': i,
|
|
157
|
-
'error': str(e),
|
|
158
|
-
'status': 'error'
|
|
159
|
-
})
|
|
172
|
+
errors.append({"index": i, "error": str(e), "status": "error"})
|
|
160
173
|
else:
|
|
161
|
-
errors.append(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
errors.append(
|
|
175
|
+
{
|
|
176
|
+
"index": i,
|
|
177
|
+
"errors": serializer.errors,
|
|
178
|
+
"status": "validation_error",
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return Response(
|
|
183
|
+
{
|
|
184
|
+
"created": created_findings,
|
|
185
|
+
"errors": errors,
|
|
186
|
+
"total_processed": len(findings_data),
|
|
187
|
+
"success_count": len(created_findings),
|
|
188
|
+
"error_count": len(errors),
|
|
189
|
+
},
|
|
190
|
+
status=status.HTTP_201_CREATED
|
|
191
|
+
if created_findings
|
|
192
|
+
else status.HTTP_400_BAD_REQUEST,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
@action(detail=True, methods=["post"])
|
|
176
196
|
def add_classification(self, request, pk=None):
|
|
177
197
|
"""
|
|
178
198
|
Create and link a PatientFindingClassification to the PatientFinding
|
|
@@ -185,32 +205,38 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
|
185
205
|
|
|
186
206
|
"""
|
|
187
207
|
patient_finding = self.get_object()
|
|
188
|
-
assert isinstance(patient_finding, PatientFinding),
|
|
208
|
+
assert isinstance(patient_finding, PatientFinding), (
|
|
209
|
+
"Expected PatientFinding instance"
|
|
210
|
+
)
|
|
189
211
|
classification_data = request.data
|
|
190
212
|
|
|
191
213
|
# Validierung
|
|
192
|
-
classification_id = classification_data.get(
|
|
193
|
-
choice_id = classification_data.get(
|
|
214
|
+
classification_id = classification_data.get("classification_id")
|
|
215
|
+
choice_id = classification_data.get("choice_id")
|
|
194
216
|
|
|
195
217
|
if not classification_id or not choice_id:
|
|
196
218
|
return Response(
|
|
197
|
-
{
|
|
198
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
219
|
+
{"error": "classification und choice erforderlich"},
|
|
220
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
199
221
|
)
|
|
200
222
|
|
|
201
223
|
patient_finding.add_classification(classification_id, choice_id)
|
|
202
224
|
try:
|
|
203
|
-
patient_finding_classification = patient_finding.add_classification(
|
|
204
|
-
|
|
225
|
+
patient_finding_classification = patient_finding.add_classification(
|
|
226
|
+
classification_id, choice_id
|
|
227
|
+
)
|
|
228
|
+
serializer = PatientFindingClassificationSerializer(
|
|
229
|
+
patient_finding_classification
|
|
230
|
+
)
|
|
205
231
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
206
232
|
|
|
207
233
|
except FindingClassification.DoesNotExist:
|
|
208
234
|
return Response(
|
|
209
|
-
{
|
|
210
|
-
status=status.HTTP_404_NOT_FOUND
|
|
235
|
+
{"error": "location_classification nicht gefunden"},
|
|
236
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
211
237
|
)
|
|
212
238
|
|
|
213
|
-
@action(detail=False, methods=[
|
|
239
|
+
@action(detail=False, methods=["get"])
|
|
214
240
|
def export_for_analysis(self, request):
|
|
215
241
|
"""
|
|
216
242
|
Export-Endpoint für Datenanalyse mit flacher Struktur
|
|
@@ -219,41 +245,47 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
|
219
245
|
queryset = self.filter_queryset(self.get_queryset())
|
|
220
246
|
|
|
221
247
|
# Format-Parameter
|
|
222
|
-
export_format = request.query_params.get(
|
|
248
|
+
export_format = request.query_params.get("format", "json")
|
|
223
249
|
|
|
224
250
|
# Flache Datenstruktur für Analyse
|
|
225
251
|
export_data = []
|
|
226
252
|
for finding in queryset:
|
|
227
|
-
assert isinstance(finding, PatientFinding),
|
|
253
|
+
assert isinstance(finding, PatientFinding), (
|
|
254
|
+
"Expected PatientFinding instance"
|
|
255
|
+
)
|
|
228
256
|
base_data = {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
257
|
+
"finding_id": finding.id,
|
|
258
|
+
"patient_id": finding.patient_examination.patient.id,
|
|
259
|
+
"patient_name": finding.patient_examination.patient.get_full_name(),
|
|
260
|
+
"examination_type": finding.patient_examination.examination.name,
|
|
261
|
+
"examination_date": finding.patient_examination.date_start,
|
|
262
|
+
"finding_name": finding.finding.name,
|
|
235
263
|
}
|
|
236
264
|
|
|
237
265
|
# Locations denormalisieren
|
|
238
266
|
for classification in finding.classifications.all():
|
|
239
267
|
classification_data = base_data.copy()
|
|
240
|
-
classification_data.update(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
268
|
+
classification_data.update(
|
|
269
|
+
{
|
|
270
|
+
"location_classification": classification.location_classification.name,
|
|
271
|
+
"location_choice": classification.location_choice.name,
|
|
272
|
+
"location_subcategories": classification.subcategories,
|
|
273
|
+
}
|
|
274
|
+
)
|
|
245
275
|
export_data.append(classification_data)
|
|
246
276
|
|
|
247
277
|
# Wenn keine Locations, trotzdem Base-Data hinzufügen
|
|
248
278
|
if not finding.locations.exists():
|
|
249
279
|
export_data.append(base_data)
|
|
250
280
|
|
|
251
|
-
if export_format ==
|
|
281
|
+
if export_format == "csv":
|
|
252
282
|
# CSV-Export implementierung würde hier hin
|
|
253
283
|
pass
|
|
254
284
|
|
|
255
|
-
return Response(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
285
|
+
return Response(
|
|
286
|
+
{
|
|
287
|
+
"data": export_data,
|
|
288
|
+
"count": len(export_data),
|
|
289
|
+
"exported_at": timezone.now(),
|
|
290
|
+
}
|
|
291
|
+
)
|
|
@@ -4,10 +4,11 @@ from rest_framework import status
|
|
|
4
4
|
from endoreg_db.models import (
|
|
5
5
|
PatientFinding,
|
|
6
6
|
FindingClassificationChoice,
|
|
7
|
-
FindingClassification
|
|
7
|
+
FindingClassification,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
@api_view(["POST"])
|
|
11
12
|
def create_patient_finding_classification(request):
|
|
12
13
|
"""
|
|
13
14
|
Create a patient finding classification relationship.
|
|
@@ -18,50 +19,57 @@ def create_patient_finding_classification(request):
|
|
|
18
19
|
}
|
|
19
20
|
"""
|
|
20
21
|
try:
|
|
21
|
-
patient_finding_id = request.data.get(
|
|
22
|
-
choice_id = request.data.get(
|
|
23
|
-
classification_id = request.data.get(
|
|
24
|
-
|
|
22
|
+
patient_finding_id = request.data.get("patient_finding_id")
|
|
23
|
+
choice_id = request.data.get("classification_choice_id")
|
|
24
|
+
classification_id = request.data.get("classification_id")
|
|
25
|
+
|
|
25
26
|
if not patient_finding_id or not choice_id:
|
|
26
27
|
return Response(
|
|
27
|
-
{
|
|
28
|
-
|
|
28
|
+
{
|
|
29
|
+
"detail": "patient_finding_id and classification_choice_id are required"
|
|
30
|
+
},
|
|
31
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
29
32
|
)
|
|
30
|
-
|
|
33
|
+
|
|
31
34
|
# Get the objects
|
|
32
35
|
try:
|
|
33
36
|
patient_finding = PatientFinding.objects.get(id=patient_finding_id)
|
|
34
37
|
except PatientFinding.DoesNotExist:
|
|
35
38
|
return Response(
|
|
36
|
-
{
|
|
37
|
-
status=status.HTTP_404_NOT_FOUND
|
|
39
|
+
{"detail": f"PatientFinding with id {patient_finding_id} not found"},
|
|
40
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
38
41
|
)
|
|
39
|
-
|
|
42
|
+
|
|
40
43
|
try:
|
|
41
44
|
choice = FindingClassificationChoice.objects.get(id=choice_id)
|
|
42
45
|
except FindingClassificationChoice.DoesNotExist:
|
|
43
46
|
return Response(
|
|
44
|
-
{
|
|
45
|
-
status=status.HTTP_404_NOT_FOUND
|
|
47
|
+
{"detail": f"ClassificationChoice with id {choice_id} not found"},
|
|
48
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
46
49
|
)
|
|
47
50
|
|
|
48
51
|
try:
|
|
49
52
|
FindingClassification.objects.get(id=classification_id)
|
|
50
53
|
except FindingClassification.DoesNotExist:
|
|
51
54
|
return Response(
|
|
52
|
-
{
|
|
53
|
-
status=status.HTTP_404_NOT_FOUND
|
|
55
|
+
{"detail": f"Classification with id {classification_id} not found"},
|
|
56
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
54
57
|
)
|
|
55
|
-
patient_finding_classification = patient_finding.add_classification(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
patient_finding_classification = patient_finding.add_classification(
|
|
59
|
+
classification_id=classification_id, choice_id=choice_id
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return Response(
|
|
63
|
+
{
|
|
64
|
+
"id": patient_finding_classification.id,
|
|
65
|
+
"patient_finding_id": patient_finding.id,
|
|
66
|
+
"classification_choice_id": choice.id,
|
|
67
|
+
},
|
|
68
|
+
status=status.HTTP_201_CREATED,
|
|
69
|
+
)
|
|
70
|
+
|
|
63
71
|
except Exception as e:
|
|
64
72
|
return Response(
|
|
65
|
-
{
|
|
66
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
67
|
-
)
|
|
73
|
+
{"detail": f"Error creating patient finding classification: {str(e)}"},
|
|
74
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
75
|
+
)
|
|
@@ -11,7 +11,7 @@ from endoreg_db.services.report_import import ReportImportService
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class ReportReimportView(APIView):
|
|
15
15
|
"""
|
|
16
16
|
API endpoint to re-import a pdf file and regenerate metadata.
|
|
17
17
|
This is useful when OCR failed or metadata is incomplete.
|
|
@@ -5,7 +5,6 @@ import re
|
|
|
5
5
|
from django.http import FileResponse, Http404, StreamingHttpResponse
|
|
6
6
|
from django.views.decorators.clickjacking import (
|
|
7
7
|
xframe_options_exempt,
|
|
8
|
-
xframe_options_sameorigin,
|
|
9
8
|
)
|
|
10
9
|
from rest_framework.views import APIView
|
|
11
10
|
|
|
@@ -172,13 +171,11 @@ class ReportStreamView(APIView):
|
|
|
172
171
|
logger.debug(f"Serving full {file_type} report {pk} ({file_size} bytes)")
|
|
173
172
|
|
|
174
173
|
try:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
f'inline; filename="{safe_filename}"'
|
|
181
|
-
)
|
|
174
|
+
file_handle = open(file_path, "rb")
|
|
175
|
+
response = FileResponse(file_handle, content_type="application/pdf")
|
|
176
|
+
response["Content-Length"] = str(file_size)
|
|
177
|
+
response["Accept-Ranges"] = "bytes"
|
|
178
|
+
response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
182
179
|
|
|
183
180
|
# FileResponse will take ownership of file_handle and close it after response
|
|
184
181
|
return response
|
|
@@ -2,8 +2,7 @@ from endoreg_db.models.requirement.requirement import Requirement
|
|
|
2
2
|
from endoreg_db.views.requirement.requirement_utils import safe_evaluate_requirement
|
|
3
3
|
from endoreg_db.models.requirement.requirement_set import RequirementSet
|
|
4
4
|
from endoreg_db.models.requirement.requirement_evaluation.evaluate_with_dependencies import (
|
|
5
|
-
evaluate_requirement_sets_with_dependencies,
|
|
6
|
-
RequirementStatus, # if you export it there, otherwise re-declare in view
|
|
5
|
+
evaluate_requirement_sets_with_dependencies, # if you export it there, otherwise re-declare in view
|
|
7
6
|
)
|
|
8
7
|
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
9
8
|
from rest_framework import status
|
|
@@ -51,10 +50,7 @@ def evaluate_requirements(request):
|
|
|
51
50
|
|
|
52
51
|
# ---- fetch PatientExamination
|
|
53
52
|
try:
|
|
54
|
-
pe = (
|
|
55
|
-
PatientExamination.objects.select_related("patient")
|
|
56
|
-
.get(id=pe_id)
|
|
57
|
-
)
|
|
53
|
+
pe = PatientExamination.objects.select_related("patient").get(id=pe_id)
|
|
58
54
|
except PatientExamination.DoesNotExist:
|
|
59
55
|
msg = f"PatientExamination with id {pe_id} does not exist"
|
|
60
56
|
errors.append(msg)
|
|
@@ -153,9 +149,11 @@ def evaluate_requirements(request):
|
|
|
153
149
|
|
|
154
150
|
for set_id, req_dict in set_results.items():
|
|
155
151
|
req_set = sets_by_id.get(set_id)
|
|
156
|
-
set_name =
|
|
157
|
-
req_set, "name", str(set_id)
|
|
158
|
-
|
|
152
|
+
set_name = (
|
|
153
|
+
getattr(req_set, "name", str(set_id))
|
|
154
|
+
if req_set is not None
|
|
155
|
+
else str(set_id)
|
|
156
|
+
)
|
|
159
157
|
|
|
160
158
|
for req_id, (status_value, details) in req_dict.items():
|
|
161
159
|
try:
|
|
@@ -54,7 +54,7 @@ class LookupViewSet(viewsets.ViewSet):
|
|
|
54
54
|
"selectedRequirementSetIds",
|
|
55
55
|
"selectedChoices",
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
user_tags = Tag
|
|
59
59
|
|
|
60
60
|
@action(detail=False, methods=["post"])
|
|
@@ -134,7 +134,7 @@ class LookupViewSet(viewsets.ViewSet):
|
|
|
134
134
|
|
|
135
135
|
except Exception:
|
|
136
136
|
pass
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
user_tags = request.data.get("user_tags", None)
|
|
139
139
|
if user_tags and not isinstance(user_tags, list):
|
|
140
140
|
user_tags = [user_tags]
|
|
@@ -269,7 +269,6 @@ class LookupViewSet(viewsets.ViewSet):
|
|
|
269
269
|
cache.set(f"{ORIGIN_MAP_PREFIX}{pk}", pe_id, DEFAULT_TTL_SECONDS)
|
|
270
270
|
return Response(store.get_all(), status=status.HTTP_200_OK)
|
|
271
271
|
|
|
272
|
-
|
|
273
272
|
except Exception:
|
|
274
273
|
pass
|
|
275
274
|
|
|
@@ -8,7 +8,6 @@ from typing import Any, Dict, Iterable, Optional
|
|
|
8
8
|
from django.conf import settings
|
|
9
9
|
from django.core.cache import cache
|
|
10
10
|
|
|
11
|
-
from endoreg_db.models.medical import PatientExamination
|
|
12
11
|
|
|
13
12
|
# Align TTL with Django cache TIMEOUT for consistency in tests and runtime
|
|
14
13
|
|
|
@@ -31,7 +31,7 @@ def safe_evaluate_requirement(
|
|
|
31
31
|
if hasattr(requirement, "evaluate_with_details"):
|
|
32
32
|
met, details = requirement.evaluate_with_details(*args, mode=mode, **kwargs)
|
|
33
33
|
else:
|
|
34
|
-
met = requirement.evaluate(*args,
|
|
34
|
+
met = requirement.evaluate(*args, **kwargs)
|
|
35
35
|
details = "Voraussetzung erfüllt" if met else "Voraussetzung nicht erfüllt"
|
|
36
36
|
error = None
|
|
37
37
|
|
|
@@ -70,9 +70,7 @@ def safe_evaluate_requirement(
|
|
|
70
70
|
display_name = getattr(requirement, "description", None) or getattr(
|
|
71
71
|
requirement, "name", "unbekannte Voraussetzung"
|
|
72
72
|
)
|
|
73
|
-
details =
|
|
74
|
-
f"Bei der Auswertung der Voraussetzung „{display_name}“ ist ein interner Fehler aufgetreten."
|
|
75
|
-
)
|
|
73
|
+
details = f"Bei der Auswertung der Voraussetzung „{display_name}“ ist ein interner Fehler aufgetreten."
|
|
76
74
|
error = f"{e.__class__.__name__}: {e}"
|
|
77
75
|
logger.exception(
|
|
78
76
|
"Requirement '%s' unexpected error",
|
|
@@ -6,8 +6,8 @@ from .stats_views import (
|
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
"ExaminationStatsView",
|
|
10
|
+
"VideoSegmentStatsView",
|
|
11
|
+
"SensitiveMetaStatsView",
|
|
12
|
+
"GeneralStatsView",
|
|
13
13
|
]
|