endoreg-db 0.4.5__py3-none-any.whl → 0.8.6.3__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.
- endoreg_db/admin.py +90 -1
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +12 -0
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +92 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +76 -4
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/{label → ai_model_label}/label/data.yaml +27 -1
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/center/data.yaml +40 -9
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/misc.yaml +1 -2
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +2 -2
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +6 -6
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscopy_processor/data.yaml +3 -0
- endoreg_db/data/event/cardiology.yaml +0 -13
- endoreg_db/data/examination/examinations/data.yaml +34 -28
- endoreg_db/data/examination/type/data.yaml +12 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +424 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +160 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- endoreg_db/data/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/finding/complication.yaml +16 -0
- endoreg_db/data/finding/data.yaml +105 -0
- endoreg_db/data/finding/examination_setting.yaml +16 -0
- endoreg_db/data/finding/medication_related.yaml +18 -0
- endoreg_db/data/finding/outcome.yaml +12 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +43 -0
- endoreg_db/data/gender/data.yaml +24 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +7 -1
- endoreg_db/data/lab_value/coagulation.yaml +6 -1
- endoreg_db/data/lab_value/electrolytes.yaml +39 -1
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +12 -0
- endoreg_db/data/lab_value/hematology.yaml +17 -2
- endoreg_db/data/lab_value/hormones.yaml +6 -0
- endoreg_db/data/lab_value/lipids.yaml +12 -3
- endoreg_db/data/lab_value/misc.yaml +48 -2
- endoreg_db/data/lab_value/renal_function.yaml +2 -1
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/medication/anticoagulation.yaml +5 -5
- endoreg_db/data/medication/tah.yaml +5 -5
- endoreg_db/data/medication_indication/anticoagulation.yaml +48 -53
- endoreg_db/data/medication_intake_time/base.yaml +4 -4
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +30 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/pdf_type/data.yaml +27 -9
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +4 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +5 -0
- endoreg_db/data/requirement/age.yaml +26 -0
- endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/gender.yaml +25 -0
- endoreg_db/data/requirement/lab_value.yaml +441 -0
- endoreg_db/data/requirement/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/age.yaml +13 -0
- endoreg_db/data/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +52 -0
- endoreg_db/data/requirement_set_type/data.yaml +20 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
- endoreg_db/data/unit/concentration.yaml +23 -0
- endoreg_db/data/unit/time.yaml +36 -1
- endoreg_db/exceptions.py +19 -0
- endoreg_db/forms/__init__.py +3 -1
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +18 -0
- endoreg_db/forms/patient_form.py +27 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/questionnaires/tto_questionnaire.py +19 -19
- endoreg_db/helpers/count_db.py +45 -0
- endoreg_db/helpers/data_loader.py +208 -0
- endoreg_db/helpers/default_objects.py +378 -0
- endoreg_db/helpers/download_segmentation_model.py +31 -0
- endoreg_db/helpers/interact.py +6 -0
- endoreg_db/helpers/test_video_helper.py +119 -0
- endoreg_db/logger_conf.py +140 -0
- endoreg_db/management/__init__.py +1 -0
- endoreg_db/management/commands/__init__.py +1 -0
- endoreg_db/management/commands/anonymize_video.py +0 -0
- endoreg_db/management/commands/check_auth.py +125 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +115 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
- endoreg_db/management/commands/fix_video_paths.py +165 -0
- endoreg_db/management/commands/import_fallback_video.py +203 -0
- endoreg_db/management/commands/import_report.py +298 -0
- endoreg_db/management/commands/import_video.py +423 -0
- endoreg_db/management/commands/import_video_with_classification.py +367 -0
- endoreg_db/management/commands/init_default_ai_model.py +112 -0
- endoreg_db/management/commands/load_ai_model_data.py +58 -26
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +174 -118
- endoreg_db/management/commands/load_center_data.py +46 -21
- endoreg_db/management/commands/{load_logging_data.py → load_contraindication_data.py} +4 -2
- endoreg_db/management/commands/load_disease_data.py +29 -7
- endoreg_db/management/commands/{load_endoscope_type_data.py → load_endoscope_data.py} +30 -7
- endoreg_db/management/commands/load_examination_indication_data.py +86 -0
- endoreg_db/management/commands/load_finding_data.py +128 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +0 -1
- endoreg_db/management/commands/load_information_source.py +13 -7
- endoreg_db/management/commands/load_lab_value_data.py +3 -3
- endoreg_db/management/commands/load_medication_data.py +83 -21
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/{load_medication_intake_time_data.py → load_organ_data.py} +7 -5
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/load_requirement_data.py +180 -0
- endoreg_db/management/commands/load_risk_data.py +56 -0
- endoreg_db/management/commands/load_shift_data.py +60 -0
- endoreg_db/management/commands/load_tag_data.py +57 -0
- endoreg_db/management/commands/register_ai_model.py +1 -1
- endoreg_db/management/commands/setup_endoreg_db.py +381 -0
- endoreg_db/management/commands/start_filewatcher.py +106 -0
- endoreg_db/management/commands/storage_management.py +548 -0
- endoreg_db/management/commands/summarize_db_content.py +189 -0
- endoreg_db/management/commands/validate_video.py +204 -0
- endoreg_db/management/commands/validate_video_files.py +161 -0
- endoreg_db/management/commands/video_validation.py +22 -0
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/migrations/0001_initial.py +1234 -944
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/models/__init__.py +339 -53
- endoreg_db/models/administration/__init__.py +116 -0
- endoreg_db/models/administration/ai/__init__.py +9 -0
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +156 -0
- endoreg_db/models/{ai_model → administration/ai}/model_type.py +19 -4
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +10 -1
- endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +60 -16
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +6 -13
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +21 -8
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +1 -3
- endoreg_db/models/{center → administration/center}/__init__.py +9 -0
- endoreg_db/models/administration/center/center.py +67 -0
- endoreg_db/models/administration/center/center_product.py +64 -0
- endoreg_db/models/administration/center/center_resource.py +49 -0
- endoreg_db/models/administration/center/center_shift.py +88 -0
- endoreg_db/models/administration/center/center_waste.py +30 -0
- endoreg_db/models/administration/permissions/__init__.py +44 -0
- endoreg_db/models/administration/person/__init__.py +24 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +35 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
- endoreg_db/models/administration/person/employee/employee_type.py +42 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +54 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/{persons → administration/person/names}/first_name.py +1 -1
- endoreg_db/models/{persons → administration/person/names}/last_name.py +2 -3
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/administration/person/profession/__init__.py +24 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
- endoreg_db/models/administration/product/__init__.py +14 -0
- endoreg_db/models/administration/product/product.py +97 -0
- endoreg_db/models/administration/product/product_group.py +39 -0
- endoreg_db/models/administration/product/product_material.py +54 -0
- endoreg_db/models/{product → administration/product}/product_weight.py +21 -0
- endoreg_db/models/{product → administration/product}/reference_product.py +44 -13
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +37 -0
- endoreg_db/models/administration/qualification/qualification_type.py +35 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +69 -0
- endoreg_db/models/administration/shift/shift.py +51 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/label/__init__.py +24 -1
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +84 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
- endoreg_db/models/label/label.py +53 -54
- endoreg_db/models/label/label_set.py +53 -0
- endoreg_db/models/label/label_type.py +29 -0
- endoreg_db/models/label/label_video_segment/__init__.py +3 -0
- endoreg_db/models/label/label_video_segment/_create_from_video.py +41 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
- endoreg_db/models/label/video_segmentation_label.py +31 -0
- endoreg_db/models/label/video_segmentation_labelset.py +27 -0
- endoreg_db/models/media/__init__.py +16 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +111 -0
- endoreg_db/models/media/pdf/__init__.py +11 -0
- endoreg_db/models/media/pdf/raw_pdf.py +757 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
- endoreg_db/models/media/video/__init__.py +8 -0
- endoreg_db/models/media/video/create_from_file.py +358 -0
- endoreg_db/models/media/video/pipe_1.py +213 -0
- endoreg_db/models/media/video/pipe_2.py +105 -0
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file.py +825 -0
- endoreg_db/models/media/video/video_file_ai.py +443 -0
- endoreg_db/models/media/video/video_file_anonymize.py +349 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -0
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +104 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +141 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/media/video/video_file_io.py +168 -0
- endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +45 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
- endoreg_db/models/media/video/video_file_segments.py +209 -0
- endoreg_db/models/media/video/video_metadata.py +65 -0
- endoreg_db/models/media/video/video_processing.py +152 -0
- endoreg_db/models/medical/__init__.py +146 -0
- endoreg_db/models/medical/contraindication/__init__.py +17 -0
- endoreg_db/models/medical/disease.py +156 -0
- endoreg_db/models/medical/event.py +137 -0
- endoreg_db/models/medical/examination/__init__.py +9 -0
- endoreg_db/models/medical/examination/examination.py +148 -0
- endoreg_db/models/medical/examination/examination_indication.py +278 -0
- endoreg_db/models/medical/examination/examination_time.py +49 -0
- endoreg_db/models/medical/examination/examination_time_type.py +41 -0
- endoreg_db/models/medical/examination/examination_type.py +48 -0
- endoreg_db/models/medical/finding/__init__.py +18 -0
- endoreg_db/models/medical/finding/finding.py +96 -0
- endoreg_db/models/medical/finding/finding_classification.py +142 -0
- endoreg_db/models/medical/finding/finding_intervention.py +52 -0
- endoreg_db/models/medical/finding/finding_type.py +35 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +65 -0
- endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +68 -29
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +419 -0
- endoreg_db/models/medical/medication/__init__.py +19 -0
- endoreg_db/models/medical/medication/medication.py +31 -0
- endoreg_db/models/medical/medication/medication_indication.py +50 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +39 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +44 -0
- endoreg_db/models/medical/medication/medication_schedule.py +45 -0
- endoreg_db/models/medical/organ/__init__.py +35 -0
- endoreg_db/models/medical/patient/__init__.py +56 -0
- endoreg_db/models/medical/patient/medication_examples.py +38 -0
- endoreg_db/models/medical/patient/patient_disease.py +63 -0
- endoreg_db/models/medical/patient/patient_event.py +75 -0
- endoreg_db/models/medical/patient/patient_examination.py +249 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +44 -0
- endoreg_db/models/medical/patient/patient_finding.py +357 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +40 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
- endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +68 -22
- endoreg_db/models/medical/patient/patient_medication.py +104 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +72 -0
- endoreg_db/models/medical/risk/risk_type.py +51 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/metadata/model_meta.py +206 -0
- endoreg_db/models/metadata/model_meta_logic.py +343 -0
- endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +32 -13
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1048 -0
- endoreg_db/models/metadata/video_meta.py +332 -0
- endoreg_db/models/metadata/video_prediction_logic.py +190 -0
- endoreg_db/models/metadata/video_prediction_meta.py +270 -0
- endoreg_db/models/other/__init__.py +36 -1
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +125 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +94 -0
- endoreg_db/models/{persons → other}/gender.py +8 -3
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +14 -2
- endoreg_db/models/other/resource.py +6 -2
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +15 -3
- endoreg_db/models/{unit.py → other/unit.py} +16 -6
- endoreg_db/models/other/waste.py +10 -3
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +767 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +95 -0
- endoreg_db/models/requirement/requirement_operator.py +176 -0
- endoreg_db/models/requirement/requirement_set.py +287 -0
- endoreg_db/models/rule/__init__.py +13 -0
- endoreg_db/models/{rules → rule}/rule.py +6 -3
- endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +0 -2
- endoreg_db/models/{rules → rule}/rule_type.py +0 -2
- endoreg_db/models/{rules → rule}/ruleset.py +0 -2
- endoreg_db/models/state/__init__.py +12 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/audit_ledger.py +150 -0
- endoreg_db/models/state/label_video_segment.py +22 -0
- endoreg_db/models/state/raw_pdf.py +187 -0
- endoreg_db/models/state/sensitive_meta.py +46 -0
- endoreg_db/models/state/video.py +232 -0
- endoreg_db/models/upload_job.py +99 -0
- endoreg_db/models/utils.py +135 -0
- endoreg_db/renames.yml +8 -0
- endoreg_db/root_urls.py +9 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +27 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
- endoreg_db/serializers/__init__.py +118 -10
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +223 -0
- endoreg_db/serializers/_old/raw_video_meta_validation.py +179 -0
- endoreg_db/serializers/_old/video.py +71 -0
- endoreg_db/serializers/administration/__init__.py +14 -0
- endoreg_db/serializers/administration/ai/__init__.py +10 -0
- endoreg_db/serializers/administration/ai/active_model.py +10 -0
- endoreg_db/serializers/administration/ai/ai_model.py +18 -0
- endoreg_db/serializers/administration/ai/model_type.py +10 -0
- endoreg_db/serializers/administration/center.py +9 -0
- endoreg_db/serializers/administration/gender.py +9 -0
- endoreg_db/serializers/anonymization.py +69 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +46 -0
- endoreg_db/serializers/examination/dropdown.py +21 -0
- endoreg_db/serializers/examination_serializer.py +12 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +54 -0
- endoreg_db/serializers/finding_classification/__init__.py +7 -0
- endoreg_db/serializers/finding_classification/choice.py +19 -0
- endoreg_db/serializers/finding_classification/classification.py +13 -0
- endoreg_db/serializers/label/__init__.py +7 -0
- endoreg_db/serializers/label/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/__init__.py +7 -0
- endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
- endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
- endoreg_db/serializers/meta/__init__.py +19 -0
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
- endoreg_db/serializers/meta/report_meta.py +53 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -0
- endoreg_db/serializers/meta/video_meta.py +39 -0
- endoreg_db/serializers/misc/__init__.py +14 -0
- endoreg_db/serializers/misc/file_overview.py +182 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +120 -0
- endoreg_db/serializers/misc/stats.py +33 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +71 -0
- endoreg_db/serializers/patient/__init__.py +11 -0
- endoreg_db/serializers/patient/patient.py +86 -0
- endoreg_db/serializers/patient/patient_dropdown.py +27 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
- endoreg_db/serializers/pdf/__init__.py +5 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
- endoreg_db/serializers/report/__init__.py +9 -0
- endoreg_db/serializers/report/mixins.py +45 -0
- endoreg_db/serializers/report/report.py +105 -0
- endoreg_db/serializers/report/report_list.py +22 -0
- endoreg_db/serializers/report/secure_file_url.py +26 -0
- endoreg_db/serializers/requirements/requirement_schema.py +25 -0
- endoreg_db/serializers/requirements/requirement_sets.py +29 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/segmentation.py +263 -0
- endoreg_db/serializers/video/video_file_brief.py +10 -0
- endoreg_db/serializers/video/video_file_detail.py +83 -0
- endoreg_db/serializers/video/video_file_list.py +67 -0
- endoreg_db/serializers/video/video_metadata.py +105 -0
- endoreg_db/serializers/video/video_processing_history.py +153 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +223 -0
- endoreg_db/services/examination_evaluation.py +149 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +411 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/pdf_import.py +1382 -0
- endoreg_db/services/polling_coordinator.py +288 -0
- endoreg_db/services/pseudonym_service.py +89 -0
- endoreg_db/services/requirements_object.py +147 -0
- endoreg_db/services/segment_sync.py +155 -0
- endoreg_db/services/storage_aware_video_processor.py +344 -0
- endoreg_db/services/video_import.py +1259 -0
- endoreg_db/tasks/upload_tasks.py +207 -0
- endoreg_db/tasks/video_ingest.py +157 -0
- endoreg_db/tasks/video_processing_tasks.py +327 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls/__init__.py +83 -0
- endoreg_db/urls/anonymization.py +32 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +39 -0
- endoreg_db/urls/examination.py +54 -0
- endoreg_db/urls/files.py +6 -0
- endoreg_db/urls/label_video_segment_validate.py +33 -0
- endoreg_db/urls/label_video_segments.py +46 -0
- endoreg_db/urls/media.py +227 -0
- endoreg_db/urls/patient.py +19 -0
- endoreg_db/urls/report.py +48 -0
- endoreg_db/urls/requirements.py +13 -0
- endoreg_db/urls/sensitive_meta.py +0 -0
- endoreg_db/urls/stats.py +46 -0
- endoreg_db/urls/upload.py +20 -0
- endoreg_db/urls/video.py +61 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +88 -1
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +1 -4
- endoreg_db/utils/ai/inference_dataset.py +52 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +159 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +291 -0
- endoreg_db/utils/ai/preprocess.py +68 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +0 -0
- endoreg_db/utils/case_generator/case_generator.py +159 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/utils/case_generator/utils.py +30 -0
- endoreg_db/utils/check_video_files.py +148 -0
- endoreg_db/utils/dataloader.py +118 -35
- endoreg_db/utils/dates.py +60 -0
- endoreg_db/utils/env.py +33 -0
- endoreg_db/utils/extract_specific_frames.py +72 -0
- endoreg_db/utils/file_operations.py +29 -1
- endoreg_db/utils/fix_video_path_direct.py +141 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +123 -4
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +193 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +76 -0
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/paths.py +95 -0
- endoreg_db/utils/permissions.py +143 -0
- endoreg_db/utils/pipelines/Readme.md +235 -0
- endoreg_db/utils/pipelines/__init__.py +0 -0
- endoreg_db/utils/pipelines/process_video_dir.py +120 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +20 -0
- endoreg_db/utils/product/sum_weights.py +18 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/requirement_helpers.py +0 -0
- endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
- endoreg_db/utils/requirement_operator_logic/lab_value_operators.py +578 -0
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
- endoreg_db/utils/setup_config.py +177 -0
- endoreg_db/utils/translation.py +27 -0
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/validate_video_detailed.py +357 -0
- endoreg_db/utils/video/__init__.py +26 -0
- endoreg_db/utils/video/extract_frames.py +88 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +835 -0
- endoreg_db/utils/video/names.py +42 -0
- endoreg_db/utils/video/streaming_processor.py +312 -0
- endoreg_db/utils/video/video_splitter.py +94 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
- endoreg_db/views/__init__.py +274 -0
- endoreg_db/views/anonymization/__init__.py +27 -0
- endoreg_db/views/anonymization/media_management.py +454 -0
- endoreg_db/views/anonymization/overview.py +216 -0
- endoreg_db/views/anonymization/validate.py +107 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +113 -0
- endoreg_db/views/examination/__init__.py +33 -0
- endoreg_db/views/examination/examination.py +37 -0
- endoreg_db/views/examination/examination_manifest_cache.py +26 -0
- endoreg_db/views/examination/get_finding_classification_choices.py +59 -0
- endoreg_db/views/examination/get_finding_classifications.py +36 -0
- endoreg_db/views/examination/get_findings.py +41 -0
- endoreg_db/views/examination/get_instruments.py +18 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +112 -0
- endoreg_db/views/finding/get_classifications.py +14 -0
- endoreg_db/views/finding/get_interventions.py +17 -0
- endoreg_db/views/finding_classification/__init__.py +13 -0
- endoreg_db/views/finding_classification/base.py +0 -0
- endoreg_db/views/finding_classification/finding_classification.py +42 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
- endoreg_db/views/label/__init__.py +5 -0
- endoreg_db/views/label/label.py +15 -0
- endoreg_db/views/label_video_segment/__init__.py +16 -0
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
- endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
- endoreg_db/views/label_video_segment/validate.py +226 -0
- endoreg_db/views/media/__init__.py +45 -0
- endoreg_db/views/media/pdf_media.py +388 -0
- endoreg_db/views/media/segments.py +71 -0
- endoreg_db/views/media/sensitive_metadata.py +314 -0
- endoreg_db/views/media/video_media.py +272 -0
- endoreg_db/views/media/video_segments.py +524 -0
- endoreg_db/views/meta/__init__.py +15 -0
- endoreg_db/views/meta/available_files_list.py +146 -0
- endoreg_db/views/meta/report_meta.py +53 -0
- endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
- endoreg_db/views/meta/sensitive_meta_list.py +104 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
- endoreg_db/views/misc/__init__.py +63 -0
- endoreg_db/views/misc/center.py +13 -0
- endoreg_db/views/misc/csrf.py +7 -0
- endoreg_db/views/misc/gender.py +14 -0
- endoreg_db/views/misc/secure_file_serving_view.py +80 -0
- endoreg_db/views/misc/secure_file_url_view.py +84 -0
- endoreg_db/views/misc/secure_url_validate.py +79 -0
- endoreg_db/views/misc/stats.py +220 -0
- endoreg_db/views/misc/translation.py +182 -0
- endoreg_db/views/misc/upload_views.py +240 -0
- endoreg_db/views/patient/__init__.py +5 -0
- endoreg_db/views/patient/patient.py +210 -0
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +140 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
- endoreg_db/views/patient_examination/video.py +194 -0
- endoreg_db/views/patient_finding/__init__.py +7 -0
- endoreg_db/views/patient_finding/base.py +0 -0
- endoreg_db/views/patient_finding/patient_finding.py +64 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
- endoreg_db/views/patient_finding_location/__init__.py +5 -0
- endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
- endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
- endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
- endoreg_db/views/pdf/__init__.py +8 -0
- endoreg_db/views/pdf/pdf_stream.py +187 -0
- endoreg_db/views/pdf/reimport.py +177 -0
- endoreg_db/views/report/__init__.py +9 -0
- endoreg_db/views/report/report_list.py +112 -0
- endoreg_db/views/report/report_with_secure_url.py +28 -0
- endoreg_db/views/report/start_examination.py +7 -0
- endoreg_db/views/requirement/__init__.py +10 -0
- endoreg_db/views/requirement/evaluate.py +279 -0
- endoreg_db/views/requirement/lookup.py +367 -0
- endoreg_db/views/requirement/lookup_store.py +252 -0
- endoreg_db/views/requirement_lookup/lookup.py +0 -0
- endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
- endoreg_db/views/stats/__init__.py +13 -0
- endoreg_db/views/stats/stats_views.py +229 -0
- endoreg_db/views/video/__init__.py +59 -0
- endoreg_db/views/video/correction.py +530 -0
- endoreg_db/views/video/reimport.py +195 -0
- endoreg_db/views/video/segmentation.py +274 -0
- endoreg_db/views/video/task_status.py +49 -0
- endoreg_db/views/video/timeline.py +46 -0
- endoreg_db/views/video/video_analyze.py +52 -0
- endoreg_db/views/video/video_apply_mask.py +48 -0
- endoreg_db/views/video/video_correction.py +21 -0
- endoreg_db/views/video/video_download_processed.py +58 -0
- endoreg_db/views/video/video_examination_viewset.py +242 -0
- endoreg_db/views/video/video_meta.py +29 -0
- endoreg_db/views/video/video_processing_history.py +24 -0
- endoreg_db/views/video/video_remove_frames.py +48 -0
- endoreg_db/views/video/video_stream.py +306 -0
- endoreg_db/views.py +0 -3
- endoreg_db-0.8.6.3.dist-info/METADATA +383 -0
- endoreg_db-0.8.6.3.dist-info/RECORD +793 -0
- {endoreg_db-0.4.5.dist-info → endoreg_db-0.8.6.3.dist-info}/WHEEL +1 -1
- endoreg_db/data/active_model/data.yaml +0 -3
- endoreg_db/data/agl_service/data.yaml +0 -19
- endoreg_db/data/label/label-set/data.yaml +0 -18
- endoreg_db/management/commands/_load_model_template.py +0 -41
- endoreg_db/management/commands/delete_all.py +0 -18
- endoreg_db/management/commands/delete_legacy_images.py +0 -19
- endoreg_db/management/commands/delete_legacy_videos.py +0 -17
- endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
- endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
- endoreg_db/management/commands/fix_auth_permission.py +0 -20
- endoreg_db/management/commands/import_legacy_images.py +0 -94
- endoreg_db/management/commands/import_legacy_videos.py +0 -76
- endoreg_db/management/commands/load_active_model_data.py +0 -45
- endoreg_db/management/commands/load_endoscopy_processor_data.py +0 -45
- endoreg_db/management/commands/load_g_play_data.py +0 -113
- endoreg_db/management/commands/load_label_data.py +0 -67
- endoreg_db/management/commands/load_medication_indication_data.py +0 -63
- endoreg_db/management/commands/load_medication_indication_type_data.py +0 -41
- endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
- endoreg_db/management/commands/load_network_data.py +0 -57
- endoreg_db/migrations/0002_anonymizedimagelabel_anonymousimageannotation_and_more.py +0 -55
- endoreg_db/migrations/0003_anonymousimageannotation_original_image_url_and_more.py +0 -39
- endoreg_db/migrations/0004_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0005_uploadedfile_alter_rawpdffile_file_anonymizedfile.py +0 -40
- endoreg_db/migrations/0006_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0007_networkdevicelogentry_datetime_and_more.py +0 -43
- endoreg_db/models/ai_model/__init__.py +0 -3
- endoreg_db/models/ai_model/active_model.py +0 -9
- endoreg_db/models/ai_model/model_meta.py +0 -24
- endoreg_db/models/annotation/__init__.py +0 -3
- endoreg_db/models/annotation/anonymized_image_annotation.py +0 -60
- endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -80
- endoreg_db/models/annotation/image_classification.py +0 -27
- endoreg_db/models/center/center.py +0 -25
- endoreg_db/models/center/center_product.py +0 -34
- endoreg_db/models/center/center_resource.py +0 -19
- endoreg_db/models/center/center_waste.py +0 -11
- endoreg_db/models/data_file/__init__.py +0 -6
- endoreg_db/models/data_file/base_classes/__init__.py +0 -2
- endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -51
- endoreg_db/models/data_file/base_classes/abstract_video.py +0 -201
- endoreg_db/models/data_file/frame.py +0 -45
- endoreg_db/models/data_file/import_classes/__init__.py +0 -32
- endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
- endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
- endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
- endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -188
- endoreg_db/models/data_file/import_classes/raw_video.py +0 -343
- endoreg_db/models/data_file/metadata/__init__.py +0 -3
- endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -31
- endoreg_db/models/data_file/metadata/video_meta.py +0 -133
- endoreg_db/models/data_file/report_file.py +0 -89
- endoreg_db/models/data_file/video/__init__.py +0 -7
- endoreg_db/models/data_file/video/import_meta.py +0 -25
- endoreg_db/models/data_file/video/video.py +0 -25
- endoreg_db/models/data_file/video_segment.py +0 -107
- endoreg_db/models/disease.py +0 -56
- endoreg_db/models/emission/__init__.py +0 -1
- endoreg_db/models/emission/emission_factor.py +0 -20
- endoreg_db/models/event.py +0 -22
- endoreg_db/models/examination/__init__.py +0 -4
- endoreg_db/models/examination/examination.py +0 -26
- endoreg_db/models/examination/examination_time.py +0 -27
- endoreg_db/models/examination/examination_time_type.py +0 -24
- endoreg_db/models/examination/examination_type.py +0 -18
- endoreg_db/models/hardware/__init__.py +0 -2
- endoreg_db/models/hardware/endoscope.py +0 -44
- endoreg_db/models/information_source.py +0 -29
- endoreg_db/models/laboratory/__init__.py +0 -1
- endoreg_db/models/laboratory/lab_value.py +0 -102
- endoreg_db/models/legacy_data/__init__.py +0 -3
- endoreg_db/models/legacy_data/image.py +0 -34
- endoreg_db/models/logging/__init__.py +0 -4
- endoreg_db/models/logging/agl_service.py +0 -19
- endoreg_db/models/logging/base.py +0 -22
- endoreg_db/models/logging/log_type.py +0 -23
- endoreg_db/models/logging/network_device.py +0 -24
- endoreg_db/models/medication/__init__.py +0 -1
- endoreg_db/models/medication/medication.py +0 -148
- endoreg_db/models/network/__init__.py +0 -3
- endoreg_db/models/network/agl_service.py +0 -38
- endoreg_db/models/network/network_device.py +0 -53
- endoreg_db/models/network/network_device_type.py +0 -23
- endoreg_db/models/other/distribution.py +0 -215
- endoreg_db/models/patient_examination/__init__.py +0 -35
- endoreg_db/models/permissions/__init__.py +0 -44
- endoreg_db/models/persons/__init__.py +0 -7
- endoreg_db/models/persons/examiner/__init__.py +0 -2
- endoreg_db/models/persons/examiner/examiner.py +0 -16
- endoreg_db/models/persons/examiner/examiner_type.py +0 -2
- endoreg_db/models/persons/patient/__init__.py +0 -8
- endoreg_db/models/persons/patient/case/case.py +0 -30
- endoreg_db/models/persons/patient/patient.py +0 -216
- endoreg_db/models/persons/patient/patient_disease.py +0 -16
- endoreg_db/models/persons/patient/patient_event.py +0 -22
- endoreg_db/models/persons/patient/patient_lab_sample.py +0 -106
- endoreg_db/models/persons/patient/patient_medication.py +0 -44
- endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -28
- endoreg_db/models/persons/portal_user_information.py +0 -27
- endoreg_db/models/prediction/__init__.py +0 -2
- endoreg_db/models/prediction/image_classification.py +0 -37
- endoreg_db/models/prediction/video_prediction_meta.py +0 -244
- endoreg_db/models/product/__init__.py +0 -5
- endoreg_db/models/product/product.py +0 -97
- endoreg_db/models/product/product_group.py +0 -19
- endoreg_db/models/product/product_material.py +0 -24
- endoreg_db/models/questionnaires/__init__.py +0 -114
- endoreg_db/models/quiz/__init__.py +0 -2
- endoreg_db/models/quiz/quiz_answer.py +0 -41
- endoreg_db/models/quiz/quiz_question.py +0 -54
- endoreg_db/models/report_reader/__init__.py +0 -2
- endoreg_db/models/report_reader/report_reader_config.py +0 -53
- endoreg_db/models/rules/__init__.py +0 -5
- endoreg_db/queries/get/__init__.py +0 -6
- endoreg_db/queries/get/center.py +0 -42
- endoreg_db/queries/get/model.py +0 -13
- endoreg_db/queries/get/patient.py +0 -14
- endoreg_db/queries/get/patient_examination.py +0 -20
- endoreg_db/queries/get/report_file.py +0 -33
- endoreg_db/queries/get/video.py +0 -31
- endoreg_db/serializers/ai_model.py +0 -19
- endoreg_db/serializers/annotation.py +0 -17
- endoreg_db/serializers/center.py +0 -11
- endoreg_db/serializers/examination.py +0 -33
- endoreg_db/serializers/frame.py +0 -13
- endoreg_db/serializers/hardware.py +0 -21
- endoreg_db/serializers/label.py +0 -22
- endoreg_db/serializers/patient.py +0 -10
- endoreg_db/serializers/prediction.py +0 -15
- endoreg_db/serializers/report_file.py +0 -7
- endoreg_db/serializers/video.py +0 -27
- endoreg_db/tests.py +0 -3
- endoreg_db/utils/legacy_ocr.py +0 -201
- endoreg_db/utils/video_metadata.py +0 -87
- endoreg_db-0.4.5.dist-info/METADATA +0 -34
- endoreg_db-0.4.5.dist-info/RECORD +0 -316
- /endoreg_db/{data/distribution/numeric/.init → api/serializers/finding_descriptions.py} +0 -0
- /endoreg_db/{models/persons/patient/case/__init__.py → api/views/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/annotation.py → config/__init__.py} +0 -0
- /endoreg_db/data/{label → ai_model_label}/label-type/data.yaml +0 -0
- /endoreg_db/data/{model_type → ai_model_type}/data.yaml +0 -0
- /endoreg_db/{queries/get/prediction.py → data/shift/m2.yaml} +0 -0
- /endoreg_db/{queries/get/video_import_meta.py → factories/__init__.py} +0 -0
- /endoreg_db/{queries/get/video_prediction_meta.py → helpers/__init__.py} +0 -0
- /endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +0 -0
- /endoreg_db/models/{persons → administration/person}/person.py +0 -0
- /endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +0 -0
- /endoreg_db/models/{rules → rule}/rule_applicator.py +0 -0
- {endoreg_db-0.4.5.dist-info → endoreg_db-0.8.6.3.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from endoreg_db.models import Examination, Finding, FindingClassification, PatientFinding
|
|
2
|
+
from endoreg_db.serializers.patient_finding import PatientFindingClassificationSerializer, PatientFindingDetailSerializer, PatientFindingListSerializer, PatientFindingWriteSerializer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from django.db import transaction
|
|
6
|
+
from django.utils import timezone
|
|
7
|
+
from django.utils.decorators import method_decorator
|
|
8
|
+
from django.views.decorators.cache import cache_page
|
|
9
|
+
from django.views.decorators.vary import vary_on_headers
|
|
10
|
+
from django_filters.rest_framework import DjangoFilterBackend
|
|
11
|
+
from rest_framework import status, viewsets
|
|
12
|
+
from rest_framework.decorators import action
|
|
13
|
+
from rest_framework.filters import OrderingFilter, SearchFilter
|
|
14
|
+
from rest_framework.permissions import IsAuthenticated
|
|
15
|
+
from rest_framework.response import Response
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
|
|
19
|
+
"""
|
|
20
|
+
Hochoptimiertes ViewSet für PatientFinding mit Query-Optimierung,
|
|
21
|
+
Bulk-Endpoints und intelligenter Serializer-Auswahl
|
|
22
|
+
"""
|
|
23
|
+
permission_classes = [IsAuthenticated]
|
|
24
|
+
filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter]
|
|
25
|
+
filterset_fields = ['patient_examination__patient', 'finding', 'patient_examination__examination']
|
|
26
|
+
ordering_fields = ['id', 'patient_examination__date_start']
|
|
27
|
+
search_fields = ['finding__name', 'patient_examination__patient__first_name', 'patient_examination__patient__last_name']
|
|
28
|
+
|
|
29
|
+
def get_queryset(self):
|
|
30
|
+
"""Optimierte QuerySet mit Prefetching basierend auf Action"""
|
|
31
|
+
base_queryset = PatientFinding.objects.select_related(
|
|
32
|
+
'patient_examination__patient',
|
|
33
|
+
'patient_examination__examination',
|
|
34
|
+
'finding'
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Detail-Views: fetch nested relations
|
|
38
|
+
if self.action in ['retrieve', 'update', 'partial_update']:
|
|
39
|
+
return base_queryset.prefetch_related(
|
|
40
|
+
"classifications__classification",
|
|
41
|
+
"classifications__choice",
|
|
42
|
+
# 'locations__location_classification',
|
|
43
|
+
# 'locations__location_choice',
|
|
44
|
+
# 'morphologies__morphology_classification',
|
|
45
|
+
# 'morphologies__morphology_choice',
|
|
46
|
+
'interventions__intervention'
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# For List-Views: fetch only necessary relations
|
|
50
|
+
return base_queryset
|
|
51
|
+
|
|
52
|
+
def get_serializer_class(self):
|
|
53
|
+
"""Intelligente Serializer-Auswahl basierend auf Action"""
|
|
54
|
+
if self.action == 'list':
|
|
55
|
+
return PatientFindingListSerializer
|
|
56
|
+
elif self.action in ['create', 'update', 'partial_update']:
|
|
57
|
+
return PatientFindingWriteSerializer
|
|
58
|
+
else:
|
|
59
|
+
return PatientFindingDetailSerializer
|
|
60
|
+
|
|
61
|
+
@method_decorator(cache_page(60 * 15)) # 15 Minuten Cache
|
|
62
|
+
@method_decorator(vary_on_headers('Accept-Language'))
|
|
63
|
+
@action(detail=False, methods=['get'])
|
|
64
|
+
def examination_manifest(self, request):
|
|
65
|
+
"""
|
|
66
|
+
Bulk-Endpoint: Liefert alle Setup-Daten für eine Examination in einem Call
|
|
67
|
+
"""
|
|
68
|
+
examination_id = request.query_params.get('examination_id')
|
|
69
|
+
if not examination_id:
|
|
70
|
+
return Response(
|
|
71
|
+
{'error': 'examination_id parameter erforderlich'},
|
|
72
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
examination = Examination.objects.get(id=examination_id)
|
|
77
|
+
except Examination.DoesNotExist:
|
|
78
|
+
return Response(
|
|
79
|
+
{'error': 'Examination nicht gefunden'},
|
|
80
|
+
status=status.HTTP_404_NOT_FOUND
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Alle Daten in optimierten Queries laden
|
|
84
|
+
findings = examination.get_available_findings().prefetch_related(
|
|
85
|
+
'location_classifications__choices',
|
|
86
|
+
'morphology_classifications__choices'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
manifest_data = {
|
|
90
|
+
'examination': {
|
|
91
|
+
'id': examination.id,
|
|
92
|
+
'name': examination.name,
|
|
93
|
+
# 'name_de': examination.name_de,
|
|
94
|
+
# 'name_en': examination.name_en,
|
|
95
|
+
},
|
|
96
|
+
'findings': []
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for finding in findings:
|
|
100
|
+
assert isinstance(finding, Finding), "Expected Finding instance"
|
|
101
|
+
finding_data = {
|
|
102
|
+
'id': finding.id,
|
|
103
|
+
'name': finding.name,
|
|
104
|
+
# 'name_de': finding.name_de,
|
|
105
|
+
# 'name_en': finding.name_en,
|
|
106
|
+
"classifications": [],
|
|
107
|
+
'location_classifications': [],
|
|
108
|
+
'morphology_classifications': []
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for classification_obj in finding.get_classifications():
|
|
112
|
+
assert isinstance(classification_obj, FindingClassification), "Expected FindingClassification instance"
|
|
113
|
+
classification_data = {
|
|
114
|
+
'id': classification_obj.id,
|
|
115
|
+
'name': classification_obj.name,
|
|
116
|
+
"choices": [
|
|
117
|
+
{
|
|
118
|
+
'id': choice.id,
|
|
119
|
+
'name': choice.name,
|
|
120
|
+
}
|
|
121
|
+
for choice in classification_obj.choices.all()
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
finding_data['classifications'].append(classification_data)
|
|
126
|
+
|
|
127
|
+
@action(detail=False, methods=['post'])
|
|
128
|
+
def bulk_create(self, request):
|
|
129
|
+
"""
|
|
130
|
+
Bulk-Endpoint für gleichzeitige Erstellung mehrerer PatientFindings
|
|
131
|
+
Optimiert für Mobile Apps mit schlechter Verbindung
|
|
132
|
+
"""
|
|
133
|
+
findings_data = request.data.get('findings', [])
|
|
134
|
+
if not findings_data:
|
|
135
|
+
return Response(
|
|
136
|
+
{'error': 'findings array required'},
|
|
137
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
created_findings = []
|
|
141
|
+
errors = []
|
|
142
|
+
|
|
143
|
+
with transaction.atomic():
|
|
144
|
+
for i, finding_data in enumerate(findings_data):
|
|
145
|
+
serializer = self.get_serializer(data=finding_data)
|
|
146
|
+
if serializer.is_valid():
|
|
147
|
+
try:
|
|
148
|
+
finding = serializer.save()
|
|
149
|
+
created_findings.append({
|
|
150
|
+
'index': i,
|
|
151
|
+
'id': finding.id,
|
|
152
|
+
'status': 'created'
|
|
153
|
+
})
|
|
154
|
+
except Exception as e:
|
|
155
|
+
errors.append({
|
|
156
|
+
'index': i,
|
|
157
|
+
'error': str(e),
|
|
158
|
+
'status': 'error'
|
|
159
|
+
})
|
|
160
|
+
else:
|
|
161
|
+
errors.append({
|
|
162
|
+
'index': i,
|
|
163
|
+
'errors': serializer.errors,
|
|
164
|
+
'status': 'validation_error'
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
return Response({
|
|
168
|
+
'created': created_findings,
|
|
169
|
+
'errors': errors,
|
|
170
|
+
'total_processed': len(findings_data),
|
|
171
|
+
'success_count': len(created_findings),
|
|
172
|
+
'error_count': len(errors)
|
|
173
|
+
}, status=status.HTTP_201_CREATED if created_findings else status.HTTP_400_BAD_REQUEST)
|
|
174
|
+
|
|
175
|
+
@action(detail=True, methods=['post'])
|
|
176
|
+
def add_classification(self, request, pk=None):
|
|
177
|
+
"""
|
|
178
|
+
Create and link a PatientFindingClassification to the PatientFinding
|
|
179
|
+
|
|
180
|
+
Called by: POST /api/patient-findings/{id}/add-classification/ #TODO CHECK
|
|
181
|
+
|
|
182
|
+
Expected payload: {
|
|
183
|
+
"classification_id": 1,
|
|
184
|
+
"choice_id": 2
|
|
185
|
+
|
|
186
|
+
"""
|
|
187
|
+
patient_finding = self.get_object()
|
|
188
|
+
assert isinstance(patient_finding, PatientFinding), "Expected PatientFinding instance"
|
|
189
|
+
classification_data = request.data
|
|
190
|
+
|
|
191
|
+
# Validierung
|
|
192
|
+
classification_id = classification_data.get('classification_id')
|
|
193
|
+
choice_id = classification_data.get('choice_id')
|
|
194
|
+
|
|
195
|
+
if not classification_id or not choice_id:
|
|
196
|
+
return Response(
|
|
197
|
+
{'error': 'classification und choice erforderlich'},
|
|
198
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
patient_finding.add_classification(classification_id, choice_id)
|
|
202
|
+
try:
|
|
203
|
+
patient_finding_classification = patient_finding.add_classification(classification_id, choice_id)
|
|
204
|
+
serializer = PatientFindingClassificationSerializer(patient_finding_classification)
|
|
205
|
+
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
206
|
+
|
|
207
|
+
except FindingClassification.DoesNotExist:
|
|
208
|
+
return Response(
|
|
209
|
+
{'error': 'location_classification nicht gefunden'},
|
|
210
|
+
status=status.HTTP_404_NOT_FOUND
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@action(detail=False, methods=['get'])
|
|
214
|
+
def export_for_analysis(self, request):
|
|
215
|
+
"""
|
|
216
|
+
Export-Endpoint für Datenanalyse mit flacher Struktur
|
|
217
|
+
Unterstützt CSV/JSON Export mit denormalisierten Daten
|
|
218
|
+
"""
|
|
219
|
+
queryset = self.filter_queryset(self.get_queryset())
|
|
220
|
+
|
|
221
|
+
# Format-Parameter
|
|
222
|
+
export_format = request.query_params.get('format', 'json')
|
|
223
|
+
|
|
224
|
+
# Flache Datenstruktur für Analyse
|
|
225
|
+
export_data = []
|
|
226
|
+
for finding in queryset:
|
|
227
|
+
assert isinstance(finding, PatientFinding), "Expected PatientFinding instance"
|
|
228
|
+
base_data = {
|
|
229
|
+
'finding_id': finding.id,
|
|
230
|
+
'patient_id': finding.patient_examination.patient.id,
|
|
231
|
+
'patient_name': finding.patient_examination.patient.get_full_name(),
|
|
232
|
+
'examination_type': finding.patient_examination.examination.name,
|
|
233
|
+
'examination_date': finding.patient_examination.date_start,
|
|
234
|
+
'finding_name': finding.finding.name,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# Locations denormalisieren
|
|
238
|
+
for classification in finding.classifications.all():
|
|
239
|
+
classification_data = base_data.copy()
|
|
240
|
+
classification_data.update({
|
|
241
|
+
'location_classification': classification.location_classification.name,
|
|
242
|
+
'location_choice': classification.location_choice.name,
|
|
243
|
+
'location_subcategories': classification.subcategories,
|
|
244
|
+
})
|
|
245
|
+
export_data.append(classification_data)
|
|
246
|
+
|
|
247
|
+
# Wenn keine Locations, trotzdem Base-Data hinzufügen
|
|
248
|
+
if not finding.locations.exists():
|
|
249
|
+
export_data.append(base_data)
|
|
250
|
+
|
|
251
|
+
if export_format == 'csv':
|
|
252
|
+
# CSV-Export implementierung würde hier hin
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
return Response({
|
|
256
|
+
'data': export_data,
|
|
257
|
+
'count': len(export_data),
|
|
258
|
+
'exported_at': timezone.now()
|
|
259
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from rest_framework.decorators import api_view
|
|
2
|
+
from rest_framework.response import Response
|
|
3
|
+
from rest_framework import status
|
|
4
|
+
from endoreg_db.models import (
|
|
5
|
+
PatientFinding,
|
|
6
|
+
FindingClassificationChoice,
|
|
7
|
+
FindingClassification
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
@api_view(['POST'])
|
|
11
|
+
def create_patient_finding_classification(request):
|
|
12
|
+
"""
|
|
13
|
+
Create a patient finding classification relationship.
|
|
14
|
+
Expected payload: {
|
|
15
|
+
"patient_finding_id": 1,
|
|
16
|
+
"classification_id": 2,
|
|
17
|
+
"classification_choice_id": 2
|
|
18
|
+
}
|
|
19
|
+
"""
|
|
20
|
+
try:
|
|
21
|
+
patient_finding_id = request.data.get('patient_finding_id')
|
|
22
|
+
choice_id = request.data.get('classification_choice_id')
|
|
23
|
+
classification_id = request.data.get('classification_id')
|
|
24
|
+
|
|
25
|
+
if not patient_finding_id or not choice_id:
|
|
26
|
+
return Response(
|
|
27
|
+
{'detail': 'patient_finding_id and classification_choice_id are required'},
|
|
28
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Get the objects
|
|
32
|
+
try:
|
|
33
|
+
patient_finding = PatientFinding.objects.get(id=patient_finding_id)
|
|
34
|
+
except PatientFinding.DoesNotExist:
|
|
35
|
+
return Response(
|
|
36
|
+
{'detail': f'PatientFinding with id {patient_finding_id} not found'},
|
|
37
|
+
status=status.HTTP_404_NOT_FOUND
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
choice = FindingClassificationChoice.objects.get(id=choice_id)
|
|
42
|
+
except FindingClassificationChoice.DoesNotExist:
|
|
43
|
+
return Response(
|
|
44
|
+
{'detail': f'ClassificationChoice with id {choice_id} not found'},
|
|
45
|
+
status=status.HTTP_404_NOT_FOUND
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
FindingClassification.objects.get(id=classification_id)
|
|
50
|
+
except FindingClassification.DoesNotExist:
|
|
51
|
+
return Response(
|
|
52
|
+
{'detail': f'Classification with id {classification_id} not found'},
|
|
53
|
+
status=status.HTTP_404_NOT_FOUND
|
|
54
|
+
)
|
|
55
|
+
patient_finding_classification = patient_finding.add_classification(classification_id = classification_id, choice_id = choice_id)
|
|
56
|
+
|
|
57
|
+
return Response({
|
|
58
|
+
'id': patient_finding_classification.id,
|
|
59
|
+
'patient_finding_id': patient_finding.id,
|
|
60
|
+
'classification_choice_id': choice.id
|
|
61
|
+
}, status=status.HTTP_201_CREATED)
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
return Response(
|
|
65
|
+
{'detail': f'Error creating patient finding classification: {str(e)}'},
|
|
66
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
67
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from endoreg_db.serializers.patient_finding.patient_finding import PatientFindingSerializer
|
|
2
|
+
from rest_framework.viewsets import ModelViewSet
|
|
3
|
+
from rest_framework.decorators import api_view, permission_classes
|
|
4
|
+
from rest_framework.response import Response
|
|
5
|
+
from rest_framework import status
|
|
6
|
+
from endoreg_db.models.medical.patient.patient_finding import PatientFinding
|
|
7
|
+
from endoreg_db.models.medical.patient.patient_finding_location import PatientFindingLocation
|
|
8
|
+
from endoreg_db.models.medical.patient.patient_finding_morphology import PatientFindingMorphology
|
|
9
|
+
from endoreg_db.models import ( FindingLocationClassificationChoice, FindingMorphologyClassificationChoice )
|
|
10
|
+
from rest_framework import serializers
|
|
11
|
+
from utils.permissions import EnvironmentAwarePermission
|
|
12
|
+
|
|
13
|
+
class PatientFindingViewSet(ModelViewSet):
|
|
14
|
+
queryset = PatientFinding.objects.all()
|
|
15
|
+
serializer_class = PatientFindingSerializer
|
|
16
|
+
|
|
17
|
+
@api_view(['POST'])
|
|
18
|
+
@permission_classes([EnvironmentAwarePermission])
|
|
19
|
+
def create_patient_finding_location(request):
|
|
20
|
+
"""
|
|
21
|
+
Create a patient finding location relationship.
|
|
22
|
+
Expected payload: {
|
|
23
|
+
"patient_finding_id": 1,
|
|
24
|
+
"location_classification_choice_id": 2
|
|
25
|
+
}
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
patient_finding_id = request.data.get('patient_finding_id')
|
|
29
|
+
choice_id = request.data.get('location_classification_choice_id')
|
|
30
|
+
|
|
31
|
+
if not patient_finding_id or not choice_id:
|
|
32
|
+
return Response(
|
|
33
|
+
{'detail': 'patient_finding_id and location_classification_choice_id are required'},
|
|
34
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Get the objects
|
|
38
|
+
try:
|
|
39
|
+
patient_finding = PatientFinding.objects.get(id=patient_finding_id)
|
|
40
|
+
except PatientFinding.DoesNotExist:
|
|
41
|
+
return Response(
|
|
42
|
+
{'detail': f'PatientFinding with id {patient_finding_id} not found'},
|
|
43
|
+
status=status.HTTP_404_NOT_FOUND
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
choice = FindingLocationClassificationChoice.objects.get(id=choice_id)
|
|
48
|
+
except FindingLocationClassificationChoice.DoesNotExist:
|
|
49
|
+
return Response(
|
|
50
|
+
{'detail': f'LocationClassificationChoice with id {choice_id} not found'},
|
|
51
|
+
status=status.HTTP_404_NOT_FOUND
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Create the relationship
|
|
55
|
+
patient_finding_location = PatientFindingLocation.objects.create(
|
|
56
|
+
patient_finding=patient_finding,
|
|
57
|
+
location_classification_choice=choice
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return Response({
|
|
61
|
+
'id': patient_finding_location.id,
|
|
62
|
+
'patient_finding_id': patient_finding.id,
|
|
63
|
+
'location_classification_choice_id': choice.id
|
|
64
|
+
}, status=status.HTTP_201_CREATED)
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return Response(
|
|
68
|
+
{'detail': f'Error creating patient finding location: {str(e)}'},
|
|
69
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
70
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from endoreg_db.serializers.patient_finding.patient_finding import PatientFindingSerializer
|
|
2
|
+
from rest_framework.viewsets import ModelViewSet
|
|
3
|
+
from rest_framework.decorators import api_view, permission_classes
|
|
4
|
+
from rest_framework.response import Response
|
|
5
|
+
from rest_framework import status
|
|
6
|
+
from endoreg_db.models.medical.patient.patient_finding import PatientFinding
|
|
7
|
+
from endoreg_db.models.medical.patient.patient_finding_location import PatientFindingLocation
|
|
8
|
+
from endoreg_db.models.medical.patient.patient_finding_morphology import PatientFindingMorphology
|
|
9
|
+
from endoreg_db.models import ( FindingLocationClassificationChoice, FindingMorphologyClassificationChoice)
|
|
10
|
+
from rest_framework import serializers
|
|
11
|
+
from utils.permissions import EnvironmentAwarePermission
|
|
12
|
+
|
|
13
|
+
class PatientFindingViewSet(ModelViewSet):
|
|
14
|
+
queryset = PatientFinding.objects.all()
|
|
15
|
+
serializer_class = PatientFindingSerializer
|
|
16
|
+
|
|
17
|
+
@api_view(['POST'])
|
|
18
|
+
@permission_classes([EnvironmentAwarePermission])
|
|
19
|
+
def create_patient_finding_morphology(request):
|
|
20
|
+
"""
|
|
21
|
+
Create a patient finding morphology relationship.
|
|
22
|
+
Expected payload: {
|
|
23
|
+
"patient_finding_id": 1,
|
|
24
|
+
"morphology_classification_choice_id": 2
|
|
25
|
+
}
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
patient_finding_id = request.data.get('patient_finding_id')
|
|
29
|
+
choice_id = request.data.get('morphology_classification_choice_id')
|
|
30
|
+
|
|
31
|
+
if not patient_finding_id or not choice_id:
|
|
32
|
+
return Response(
|
|
33
|
+
{'detail': 'patient_finding_id and morphology_classification_choice_id are required'},
|
|
34
|
+
status=status.HTTP_400_BAD_REQUEST
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Get the objects
|
|
38
|
+
try:
|
|
39
|
+
patient_finding = PatientFinding.objects.get(id=patient_finding_id)
|
|
40
|
+
except PatientFinding.DoesNotExist:
|
|
41
|
+
return Response(
|
|
42
|
+
{'detail': f'PatientFinding with id {patient_finding_id} not found'},
|
|
43
|
+
status=status.HTTP_404_NOT_FOUND
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
choice = FindingMorphologyClassificationChoice.objects.get(id=choice_id)
|
|
48
|
+
except FindingMorphologyClassificationChoice.DoesNotExist:
|
|
49
|
+
return Response(
|
|
50
|
+
{'detail': f'MorphologyClassificationChoice with id {choice_id} not found'},
|
|
51
|
+
status=status.HTTP_404_NOT_FOUND
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Create the relationship
|
|
55
|
+
patient_finding_morphology = PatientFindingMorphology.objects.create(
|
|
56
|
+
patient_finding=patient_finding,
|
|
57
|
+
morphology_classification_choice=choice
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return Response({
|
|
61
|
+
'id': patient_finding_morphology.id,
|
|
62
|
+
'patient_finding_id': patient_finding.id,
|
|
63
|
+
'morphology_classification_choice_id': choice.id
|
|
64
|
+
}, status=status.HTTP_201_CREATED)
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return Response(
|
|
68
|
+
{'detail': f'Error creating patient finding morphology: {str(e)}'},
|
|
69
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
70
|
+
)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from django.http import FileResponse, Http404, StreamingHttpResponse
|
|
6
|
+
from django.views.decorators.clickjacking import xframe_options_exempt, xframe_options_sameorigin
|
|
7
|
+
from rest_framework.views import APIView
|
|
8
|
+
|
|
9
|
+
from endoreg_db.models import RawPdfFile
|
|
10
|
+
|
|
11
|
+
from ...utils.permissions import EnvironmentAwarePermission
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
_RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ClosingFileWrapper:
|
|
18
|
+
"""Custom file wrapper that ensures file is closed after streaming"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, file_handle, blksize=8192):
|
|
21
|
+
self.file_handle = file_handle
|
|
22
|
+
self.blksize = blksize
|
|
23
|
+
|
|
24
|
+
def __iter__(self):
|
|
25
|
+
return self
|
|
26
|
+
|
|
27
|
+
def __next__(self):
|
|
28
|
+
data = self.file_handle.read(self.blksize)
|
|
29
|
+
if not data:
|
|
30
|
+
self.file_handle.close()
|
|
31
|
+
raise StopIteration
|
|
32
|
+
return data
|
|
33
|
+
|
|
34
|
+
def close(self):
|
|
35
|
+
if hasattr(self.file_handle, "close"):
|
|
36
|
+
self.file_handle.close()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class PdfStreamView(APIView):
|
|
40
|
+
"""
|
|
41
|
+
Streams a PDF file with correct HTTP range support and proper file handle management.
|
|
42
|
+
|
|
43
|
+
Supports streaming both raw (original) and anonymized PDF files.
|
|
44
|
+
|
|
45
|
+
Query Parameters:
|
|
46
|
+
type: 'raw' (default) or 'anonymized' - Selects which PDF file to stream
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
GET /api/media/pdf/1/?type=raw - Stream original raw PDF
|
|
50
|
+
GET /api/media/pdf/1/?type=anonymized - Stream anonymized PDF
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
permission_classes = [EnvironmentAwarePermission]
|
|
54
|
+
|
|
55
|
+
@xframe_options_exempt
|
|
56
|
+
def get(self, request, pdf_id: int, *args, **kwargs):
|
|
57
|
+
file_type = "raw" # Initialize for error logging
|
|
58
|
+
try:
|
|
59
|
+
pdf_obj = RawPdfFile.objects.filter(pk=pdf_id).first()
|
|
60
|
+
if not pdf_obj:
|
|
61
|
+
logger.warning(f"PDF not found: ID {pdf_id}")
|
|
62
|
+
raise Http404("PDF not found")
|
|
63
|
+
|
|
64
|
+
# Parse query parameters to determine which file to stream
|
|
65
|
+
file_type = request.query_params.get("type", "raw").lower()
|
|
66
|
+
if file_type not in ["raw", "anonymized"]:
|
|
67
|
+
logger.warning(f"Invalid file_type '{file_type}', defaulting to 'raw'")
|
|
68
|
+
file_type = "raw"
|
|
69
|
+
|
|
70
|
+
# Determine which file field to use
|
|
71
|
+
if file_type == "raw":
|
|
72
|
+
file_field = pdf_obj.file
|
|
73
|
+
if not file_field:
|
|
74
|
+
logger.warning(f"No raw PDF file available for PDF ID {pdf_id}")
|
|
75
|
+
raise Http404("Raw PDF file not available")
|
|
76
|
+
else: # anonymized
|
|
77
|
+
file_field = pdf_obj.anonymized_file
|
|
78
|
+
if not file_field:
|
|
79
|
+
logger.warning(
|
|
80
|
+
f"No anonymized PDF file available for PDF ID {pdf_id}"
|
|
81
|
+
)
|
|
82
|
+
raise Http404("Anonymized PDF file not available")
|
|
83
|
+
|
|
84
|
+
# Check if file exists on filesystem
|
|
85
|
+
try:
|
|
86
|
+
file_path = file_field.path
|
|
87
|
+
if not os.path.exists(file_path):
|
|
88
|
+
logger.error(f"PDF file does not exist on filesystem: {file_path}")
|
|
89
|
+
raise Http404(
|
|
90
|
+
f"{file_type.capitalize()} PDF file not found on filesystem"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
file_size = os.path.getsize(file_path)
|
|
94
|
+
except (OSError, IOError, AttributeError) as e:
|
|
95
|
+
logger.error(f"Error accessing {file_type} PDF file {pdf_id}: {e}")
|
|
96
|
+
raise Http404(f"{file_type.capitalize()} PDF file not accessible")
|
|
97
|
+
|
|
98
|
+
# Generate safe filename
|
|
99
|
+
base_filename = (
|
|
100
|
+
os.path.basename(file_field.name)
|
|
101
|
+
if file_field.name
|
|
102
|
+
else f"document_{pdf_id}.pdf"
|
|
103
|
+
)
|
|
104
|
+
if not base_filename.endswith(".pdf"):
|
|
105
|
+
base_filename += ".pdf"
|
|
106
|
+
|
|
107
|
+
# Add type indicator to filename for clarity
|
|
108
|
+
if file_type == "anonymized":
|
|
109
|
+
name_parts = base_filename.rsplit(".", 1)
|
|
110
|
+
safe_filename = f"{name_parts[0]}_anonymized.{name_parts[1]}"
|
|
111
|
+
else:
|
|
112
|
+
safe_filename = base_filename
|
|
113
|
+
|
|
114
|
+
# Handle Range requests
|
|
115
|
+
range_header = request.headers.get("Range")
|
|
116
|
+
if range_header:
|
|
117
|
+
logger.debug(
|
|
118
|
+
f"Range request for {file_type} PDF {pdf_id}: {range_header}"
|
|
119
|
+
)
|
|
120
|
+
match = _RANGE_RE.match(range_header)
|
|
121
|
+
if match:
|
|
122
|
+
start = int(match.group(1))
|
|
123
|
+
end = int(match.group(2) or file_size - 1)
|
|
124
|
+
|
|
125
|
+
# Validate range
|
|
126
|
+
if start >= file_size or start < 0:
|
|
127
|
+
logger.warning(
|
|
128
|
+
f"Invalid range start {start} for file size {file_size}"
|
|
129
|
+
)
|
|
130
|
+
raise Http404("Invalid range")
|
|
131
|
+
|
|
132
|
+
if end >= file_size:
|
|
133
|
+
end = file_size - 1
|
|
134
|
+
|
|
135
|
+
chunk_size = end - start + 1
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
file_handle = open(file_path, "rb")
|
|
139
|
+
file_handle.seek(start)
|
|
140
|
+
|
|
141
|
+
logger.debug(
|
|
142
|
+
f"Serving {file_type} PDF {pdf_id} range {start}-{end}/{file_size}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
response = StreamingHttpResponse(
|
|
146
|
+
ClosingFileWrapper(file_handle, blksize=8192),
|
|
147
|
+
status=206,
|
|
148
|
+
content_type="application/pdf",
|
|
149
|
+
)
|
|
150
|
+
response["Content-Length"] = str(chunk_size)
|
|
151
|
+
response["Content-Range"] = f"bytes {start}-{end}/{file_size}"
|
|
152
|
+
response["Accept-Ranges"] = "bytes"
|
|
153
|
+
response["Content-Disposition"] = (
|
|
154
|
+
f'inline; filename="{safe_filename}"'
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return response
|
|
158
|
+
except (OSError, IOError) as e:
|
|
159
|
+
logger.error(
|
|
160
|
+
f"Error opening {file_type} PDF file for range request: {e}"
|
|
161
|
+
)
|
|
162
|
+
raise Http404(f"Error accessing {file_type} PDF file")
|
|
163
|
+
else:
|
|
164
|
+
logger.warning(f"Invalid Range header format: {range_header}")
|
|
165
|
+
|
|
166
|
+
# Serve entire file using FileResponse (automatically handles file closing)
|
|
167
|
+
logger.debug(f"Serving full {file_type} PDF {pdf_id} ({file_size} bytes)")
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
file_handle = open(file_path, "rb")
|
|
171
|
+
response = FileResponse(file_handle, content_type="application/pdf")
|
|
172
|
+
response["Content-Length"] = str(file_size)
|
|
173
|
+
response["Accept-Ranges"] = "bytes"
|
|
174
|
+
response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
175
|
+
|
|
176
|
+
# FileResponse will take ownership of file_handle and close it after response
|
|
177
|
+
return response
|
|
178
|
+
except (OSError, IOError) as e:
|
|
179
|
+
logger.error(f"Error opening {file_type} PDF file: {e}")
|
|
180
|
+
raise Http404(f"Error accessing {file_type} PDF file")
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.error(
|
|
184
|
+
f"Unexpected error streaming {file_type if 'file_type' in locals() else 'PDF'} {pdf_id}: {e}",
|
|
185
|
+
exc_info=True,
|
|
186
|
+
)
|
|
187
|
+
raise Http404("Error streaming PDF")
|