endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__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.

Files changed (503) hide show
  1. endoreg_db/authz/auth.py +74 -0
  2. endoreg_db/authz/backends.py +168 -0
  3. endoreg_db/authz/management/commands/list_routes.py +18 -0
  4. endoreg_db/authz/middleware.py +83 -0
  5. endoreg_db/authz/permissions.py +127 -0
  6. endoreg_db/authz/policy.py +218 -0
  7. endoreg_db/authz/views_auth.py +66 -0
  8. endoreg_db/config/env.py +13 -8
  9. endoreg_db/data/__init__.py +2 -11
  10. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
  11. endoreg_db/data/event_classification/data.yaml +4 -0
  12. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  13. endoreg_db/data/examination/examinations/data.yaml +114 -14
  14. endoreg_db/data/examination/time-type/data.yaml +0 -3
  15. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  16. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  17. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  18. endoreg_db/data/finding/00_generic.yaml +35 -0
  19. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  20. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  21. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  22. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  23. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  24. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  25. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  26. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  27. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  28. endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
  29. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  30. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  31. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  32. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  33. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  34. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  35. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  36. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  37. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  38. endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
  39. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  40. endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
  41. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  42. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  43. endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
  44. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  45. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  46. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  47. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  48. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  49. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  50. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  51. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  52. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  53. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  54. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  55. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  56. endoreg_db/data/finding_type/data.yaml +8 -12
  57. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  58. endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
  59. endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
  60. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  61. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
  62. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  63. endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
  64. endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
  65. endoreg_db/data/requirement_set/_old_ +109 -0
  66. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  67. endoreg_db/data/setup_config.yaml +4 -4
  68. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  69. endoreg_db/exceptions.py +4 -2
  70. endoreg_db/forms/examination_form.py +1 -1
  71. endoreg_db/helpers/data_loader.py +125 -53
  72. endoreg_db/helpers/default_objects.py +116 -81
  73. endoreg_db/import_files/__init__.py +27 -0
  74. endoreg_db/import_files/context/__init__.py +7 -0
  75. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  76. endoreg_db/import_files/context/ensure_center.py +17 -0
  77. endoreg_db/import_files/context/file_lock.py +66 -0
  78. endoreg_db/import_files/context/import_context.py +43 -0
  79. endoreg_db/import_files/context/validate_directories.py +56 -0
  80. endoreg_db/import_files/file_storage/__init__.py +15 -0
  81. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  82. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  83. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  84. endoreg_db/import_files/file_storage/state_management.py +400 -0
  85. endoreg_db/import_files/file_storage/storage.py +36 -0
  86. endoreg_db/import_files/import_service.md +26 -0
  87. endoreg_db/import_files/processing/__init__.py +11 -0
  88. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  89. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  90. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  91. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
  92. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  93. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  94. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  95. endoreg_db/import_files/report_import_service.py +141 -0
  96. endoreg_db/import_files/video_import_service.py +150 -0
  97. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  98. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  99. endoreg_db/management/commands/import_report.py +130 -65
  100. endoreg_db/management/commands/import_video.py +9 -10
  101. endoreg_db/management/commands/import_video_with_classification.py +2 -2
  102. endoreg_db/management/commands/list_routes.py +18 -0
  103. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  104. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  105. endoreg_db/management/commands/load_base_db_data.py +5 -134
  106. endoreg_db/management/commands/load_center_data.py +12 -12
  107. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  108. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  109. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  110. endoreg_db/management/commands/load_disease_data.py +25 -28
  111. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  112. endoreg_db/management/commands/load_event_data.py +14 -16
  113. endoreg_db/management/commands/load_examination_data.py +31 -44
  114. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  115. endoreg_db/management/commands/load_finding_data.py +52 -80
  116. endoreg_db/management/commands/load_information_source.py +21 -23
  117. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  118. endoreg_db/management/commands/load_medication_data.py +13 -12
  119. endoreg_db/management/commands/load_organ_data.py +15 -19
  120. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  121. endoreg_db/management/commands/load_profession_data.py +14 -17
  122. endoreg_db/management/commands/load_qualification_data.py +20 -23
  123. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  124. endoreg_db/management/commands/load_requirement_data.py +62 -39
  125. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  126. endoreg_db/management/commands/load_risk_data.py +7 -6
  127. endoreg_db/management/commands/load_shift_data.py +20 -23
  128. endoreg_db/management/commands/load_tag_data.py +8 -11
  129. endoreg_db/management/commands/load_unit_data.py +17 -19
  130. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  131. endoreg_db/management/commands/start_filewatcher.py +46 -37
  132. endoreg_db/management/commands/storage_management.py +271 -203
  133. endoreg_db/management/commands/validate_video_files.py +1 -5
  134. endoreg_db/migrations/0001_initial.py +297 -250
  135. endoreg_db/models/__init__.py +78 -123
  136. endoreg_db/models/administration/__init__.py +21 -42
  137. endoreg_db/models/administration/ai/active_model.py +2 -2
  138. endoreg_db/models/administration/ai/ai_model.py +7 -6
  139. endoreg_db/models/administration/case/__init__.py +1 -15
  140. endoreg_db/models/administration/case/case.py +3 -3
  141. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  142. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  143. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  144. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  145. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  146. endoreg_db/models/administration/center/center.py +33 -19
  147. endoreg_db/models/administration/center/center_product.py +12 -9
  148. endoreg_db/models/administration/center/center_resource.py +25 -19
  149. endoreg_db/models/administration/center/center_shift.py +21 -17
  150. endoreg_db/models/administration/center/center_waste.py +16 -8
  151. endoreg_db/models/administration/person/__init__.py +2 -0
  152. endoreg_db/models/administration/person/employee/employee.py +10 -5
  153. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  154. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  155. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  156. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  157. endoreg_db/models/administration/person/patient/patient.py +129 -100
  158. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  159. endoreg_db/models/administration/person/person.py +4 -0
  160. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  161. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  162. endoreg_db/models/administration/product/product.py +20 -15
  163. endoreg_db/models/administration/product/product_material.py +17 -18
  164. endoreg_db/models/administration/product/product_weight.py +12 -8
  165. endoreg_db/models/administration/product/reference_product.py +23 -55
  166. endoreg_db/models/administration/qualification/qualification.py +7 -3
  167. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  168. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  169. endoreg_db/models/administration/shift/shift.py +16 -12
  170. endoreg_db/models/administration/shift/shift_type.py +23 -31
  171. endoreg_db/models/label/__init__.py +8 -9
  172. endoreg_db/models/label/annotation/image_classification.py +10 -9
  173. endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
  174. endoreg_db/models/label/label.py +15 -15
  175. endoreg_db/models/label/label_set.py +19 -6
  176. endoreg_db/models/label/label_type.py +1 -1
  177. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  178. endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
  179. endoreg_db/models/label/video_segmentation_label.py +4 -0
  180. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  181. endoreg_db/models/media/frame/frame.py +22 -22
  182. endoreg_db/models/media/pdf/raw_pdf.py +194 -194
  183. endoreg_db/models/media/pdf/report_file.py +25 -29
  184. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
  185. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  186. endoreg_db/models/media/processing_history/__init__.py +5 -0
  187. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  188. endoreg_db/models/media/video/__init__.py +1 -0
  189. endoreg_db/models/media/video/create_from_file.py +139 -77
  190. endoreg_db/models/media/video/pipe_2.py +8 -9
  191. endoreg_db/models/media/video/video_file.py +174 -112
  192. endoreg_db/models/media/video/video_file_ai.py +288 -74
  193. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  194. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  195. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  197. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  198. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  199. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  201. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  202. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  203. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  204. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  205. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  206. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  207. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  208. endoreg_db/models/media/video/video_file_io.py +113 -61
  209. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  210. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  211. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  212. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  213. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  214. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  215. endoreg_db/models/media/video/video_file_segments.py +24 -17
  216. endoreg_db/models/media/video/video_metadata.py +19 -35
  217. endoreg_db/models/media/video/video_processing.py +96 -95
  218. endoreg_db/models/medical/contraindication/README.md +1 -0
  219. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  220. endoreg_db/models/medical/disease.py +22 -16
  221. endoreg_db/models/medical/event.py +31 -18
  222. endoreg_db/models/medical/examination/__init__.py +13 -6
  223. endoreg_db/models/medical/examination/examination.py +39 -20
  224. endoreg_db/models/medical/examination/examination_indication.py +30 -95
  225. endoreg_db/models/medical/examination/examination_time.py +23 -8
  226. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  227. endoreg_db/models/medical/examination/examination_type.py +3 -4
  228. endoreg_db/models/medical/finding/finding.py +32 -40
  229. endoreg_db/models/medical/finding/finding_classification.py +42 -72
  230. endoreg_db/models/medical/finding/finding_intervention.py +25 -22
  231. endoreg_db/models/medical/finding/finding_type.py +13 -12
  232. endoreg_db/models/medical/hardware/endoscope.py +26 -26
  233. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  234. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  235. endoreg_db/models/medical/medication/medication.py +22 -10
  236. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  237. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  238. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  239. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  240. endoreg_db/models/medical/organ/__init__.py +15 -12
  241. endoreg_db/models/medical/patient/medication_examples.py +6 -6
  242. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  243. endoreg_db/models/medical/patient/patient_event.py +19 -22
  244. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  245. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  246. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  247. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  248. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  249. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  250. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  251. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  252. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  253. endoreg_db/models/medical/risk/risk.py +7 -6
  254. endoreg_db/models/medical/risk/risk_type.py +8 -5
  255. endoreg_db/models/metadata/model_meta.py +60 -29
  256. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  257. endoreg_db/models/metadata/pdf_meta.py +31 -24
  258. endoreg_db/models/metadata/sensitive_meta.py +105 -85
  259. endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
  260. endoreg_db/models/metadata/video_meta.py +51 -31
  261. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  262. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  263. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  264. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  265. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  266. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  267. endoreg_db/models/other/emission/emission_factor.py +18 -8
  268. endoreg_db/models/other/gender.py +10 -5
  269. endoreg_db/models/other/information_source.py +50 -29
  270. endoreg_db/models/other/material.py +9 -5
  271. endoreg_db/models/other/resource.py +6 -4
  272. endoreg_db/models/other/tag.py +10 -5
  273. endoreg_db/models/other/transport_route.py +13 -8
  274. endoreg_db/models/other/unit.py +10 -6
  275. endoreg_db/models/other/waste.py +6 -5
  276. endoreg_db/models/report/report.py +6 -0
  277. endoreg_db/models/requirement/requirement.py +329 -361
  278. endoreg_db/models/requirement/requirement_error.py +85 -0
  279. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  280. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  281. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  282. endoreg_db/models/requirement/requirement_operator.py +103 -112
  283. endoreg_db/models/requirement/requirement_set.py +74 -57
  284. endoreg_db/models/state/__init__.py +4 -4
  285. endoreg_db/models/state/abstract.py +2 -2
  286. endoreg_db/models/state/anonymization.py +12 -0
  287. endoreg_db/models/state/audit_ledger.py +49 -51
  288. endoreg_db/models/state/label_video_segment.py +9 -0
  289. endoreg_db/models/state/raw_pdf.py +101 -68
  290. endoreg_db/models/state/sensitive_meta.py +6 -2
  291. endoreg_db/models/state/video.py +110 -90
  292. endoreg_db/models/upload_job.py +35 -34
  293. endoreg_db/models/utils.py +28 -25
  294. endoreg_db/queries/__init__.py +3 -1
  295. endoreg_db/root_urls.py +21 -2
  296. endoreg_db/schemas/examination_evaluation.py +1 -1
  297. endoreg_db/serializers/__init__.py +2 -10
  298. endoreg_db/serializers/anonymization.py +18 -10
  299. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  300. endoreg_db/serializers/meta/__init__.py +1 -6
  301. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  302. endoreg_db/serializers/misc/file_overview.py +11 -99
  303. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  304. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  305. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  306. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  307. endoreg_db/serializers/video/segmentation.py +2 -1
  308. endoreg_db/serializers/video/video_file_list.py +65 -34
  309. endoreg_db/serializers/video/video_processing_history.py +20 -5
  310. endoreg_db/services/__old/pdf_import.py +1487 -0
  311. endoreg_db/services/__old/video_import.py +1306 -0
  312. endoreg_db/services/anonymization.py +128 -89
  313. endoreg_db/services/lookup_service.py +65 -52
  314. endoreg_db/services/lookup_store.py +2 -2
  315. endoreg_db/services/pdf_import.py +0 -1382
  316. endoreg_db/services/report_import.py +10 -0
  317. endoreg_db/services/video_import.py +6 -1255
  318. endoreg_db/tasks/upload_tasks.py +79 -70
  319. endoreg_db/tasks/video_ingest.py +8 -4
  320. endoreg_db/urls/__init__.py +5 -32
  321. endoreg_db/urls/ai.py +32 -0
  322. endoreg_db/urls/media.py +121 -83
  323. endoreg_db/urls/root_urls.py +29 -0
  324. endoreg_db/utils/__init__.py +15 -5
  325. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  326. endoreg_db/utils/case_generator/__init__.py +3 -0
  327. endoreg_db/utils/dataloader.py +142 -40
  328. endoreg_db/utils/defaults/set_default_center.py +32 -0
  329. endoreg_db/utils/names.py +22 -16
  330. endoreg_db/utils/paths.py +110 -46
  331. endoreg_db/utils/permissions.py +2 -1
  332. endoreg_db/utils/pipelines/Readme.md +1 -1
  333. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  334. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
  335. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  336. endoreg_db/utils/setup_config.py +8 -5
  337. endoreg_db/utils/storage.py +115 -0
  338. endoreg_db/utils/validate_endo_roi.py +8 -2
  339. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  340. endoreg_db/views/__init__.py +85 -183
  341. endoreg_db/views/ai/__init__.py +8 -0
  342. endoreg_db/views/ai/label.py +155 -0
  343. endoreg_db/views/anonymization/media_management.py +202 -166
  344. endoreg_db/views/anonymization/overview.py +99 -67
  345. endoreg_db/views/anonymization/validate.py +182 -44
  346. endoreg_db/views/media/__init__.py +7 -20
  347. endoreg_db/views/media/pdf_media.py +197 -174
  348. endoreg_db/views/media/sensitive_metadata.py +193 -138
  349. endoreg_db/views/media/video_media.py +89 -82
  350. endoreg_db/views/meta/__init__.py +0 -8
  351. endoreg_db/views/misc/__init__.py +1 -7
  352. endoreg_db/views/misc/upload_views.py +94 -93
  353. endoreg_db/views/patient/patient.py +5 -4
  354. endoreg_db/views/report/__init__.py +5 -7
  355. endoreg_db/views/{pdf → report}/reimport.py +22 -22
  356. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
  357. endoreg_db/views/requirement/evaluate.py +188 -187
  358. endoreg_db/views/requirement/lookup.py +17 -3
  359. endoreg_db/views/requirement/lookup_store.py +22 -90
  360. endoreg_db/views/requirement/requirement_utils.py +89 -0
  361. endoreg_db/views/video/__init__.py +23 -24
  362. endoreg_db/views/video/correction.py +201 -172
  363. endoreg_db/views/video/reimport.py +1 -1
  364. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
  365. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  366. endoreg_db/views/video/video_stream.py +7 -8
  367. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
  368. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
  369. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  370. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  371. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  372. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  373. endoreg_db/data/finding/complication.yaml +0 -16
  374. endoreg_db/data/finding/data.yaml +0 -105
  375. endoreg_db/data/finding/examination_setting.yaml +0 -16
  376. endoreg_db/data/finding/medication_related.yaml +0 -18
  377. endoreg_db/data/finding/outcome.yaml +0 -12
  378. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
  379. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  380. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  381. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  382. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  383. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  384. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  385. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
  386. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  387. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  388. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  389. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  390. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  391. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  392. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  393. endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
  394. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  395. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  396. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  397. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  398. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  399. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  400. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  401. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  402. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  403. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  404. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  405. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  406. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  407. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  408. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  409. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  410. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  411. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  412. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  413. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  414. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  415. endoreg_db/data/requirement/age.yaml +0 -26
  416. endoreg_db/data/requirement/gender.yaml +0 -25
  417. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  418. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  419. endoreg_db/management/commands/validate_video.py +0 -204
  420. endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
  421. endoreg_db/migrations/0003_add_center_display_name.py +0 -30
  422. endoreg_db/models/administration/permissions/__init__.py +0 -44
  423. endoreg_db/models/rule/__init__.py +0 -13
  424. endoreg_db/models/rule/rule.py +0 -27
  425. endoreg_db/models/rule/rule_applicator.py +0 -224
  426. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  427. endoreg_db/models/rule/rule_type.py +0 -20
  428. endoreg_db/models/rule/ruleset.py +0 -17
  429. endoreg_db/renames.yml +0 -8
  430. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  431. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  432. endoreg_db/serializers/_old/video.py +0 -71
  433. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  434. endoreg_db/serializers/meta/report_meta.py +0 -53
  435. endoreg_db/serializers/report/__init__.py +0 -9
  436. endoreg_db/serializers/report/mixins.py +0 -45
  437. endoreg_db/serializers/report/report.py +0 -105
  438. endoreg_db/serializers/report/report_list.py +0 -22
  439. endoreg_db/serializers/report/secure_file_url.py +0 -26
  440. endoreg_db/serializers/video/video_metadata.py +0 -105
  441. endoreg_db/services/requirements_object.py +0 -147
  442. endoreg_db/services/storage_aware_video_processor.py +0 -344
  443. endoreg_db/urls/files.py +0 -6
  444. endoreg_db/urls/label_video_segment_validate.py +0 -33
  445. endoreg_db/urls/label_video_segments.py +0 -46
  446. endoreg_db/urls/report.py +0 -48
  447. endoreg_db/urls/video.py +0 -61
  448. endoreg_db/utils/case_generator/case_generator.py +0 -159
  449. endoreg_db/utils/case_generator/utils.py +0 -30
  450. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
  451. endoreg_db/views/label/__init__.py +0 -5
  452. endoreg_db/views/label/label.py +0 -15
  453. endoreg_db/views/label_video_segment/__init__.py +0 -16
  454. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  455. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  456. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  457. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  458. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  459. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  460. endoreg_db/views/label_video_segment/validate.py +0 -226
  461. endoreg_db/views/media/segments.py +0 -71
  462. endoreg_db/views/meta/available_files_list.py +0 -146
  463. endoreg_db/views/meta/report_meta.py +0 -53
  464. endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
  465. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  466. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  467. endoreg_db/views/misc/secure_url_validate.py +0 -79
  468. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  469. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  470. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  471. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  472. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  473. endoreg_db/views/pdf/__init__.py +0 -8
  474. endoreg_db/views/report/report_list.py +0 -112
  475. endoreg_db/views/report/report_with_secure_url.py +0 -28
  476. endoreg_db/views/report/start_examination.py +0 -7
  477. endoreg_db/views/video/segmentation.py +0 -274
  478. endoreg_db/views/video/task_status.py +0 -49
  479. endoreg_db/views/video/timeline.py +0 -46
  480. endoreg_db/views/video/video_analyze.py +0 -52
  481. endoreg_db/views.py +0 -0
  482. /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
  483. /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
  484. /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
  485. /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
  486. /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
  487. /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
  488. /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
  489. /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
  490. /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
  491. /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
  492. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  493. /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
  494. /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
  495. /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
  496. /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
  497. /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
  498. /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
  499. /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
  500. /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
  501. /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
  502. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  503. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  import uuid
6
6
  from pathlib import Path
7
- from typing import TYPE_CHECKING, Optional, Union, cast
7
+ from typing import TYPE_CHECKING, Optional, Self, Union, cast
8
8
 
9
9
  from django.core.files import File
10
10
  from django.core.validators import FileExtensionValidator
@@ -13,10 +13,11 @@ from django.db.models import F
13
13
  from django.db.models.fields.files import FieldFile
14
14
 
15
15
  from endoreg_db.utils.calc_duration_seconds import _calc_duration_vf
16
+ from endoreg_db.utils.video.ffmpeg_wrapper import assemble_video_from_frames
16
17
 
17
18
  from ...label import Label, LabelVideoSegment
18
19
  from ...state import VideoState
19
- from ...utils import ANONYM_VIDEO_DIR, VIDEO_DIR
20
+ from endoreg_db.utils.paths import ANONYM_VIDEO_DIR, SENSITIVE_VIDEO_DIR
20
21
 
21
22
  # --- Import model-specific function modules ---
22
23
  from .create_from_file import _create_from_file
@@ -25,6 +26,7 @@ from .pipe_2 import _pipe_2
25
26
  from .video_file_ai import _extract_text_from_video_frames, _predict_video_pipeline
26
27
  from .video_file_anonymize import (
27
28
  _anonymize,
29
+ _censor_outside_frames,
28
30
  _cleanup_raw_assets,
29
31
  _create_anonymized_frame_files,
30
32
  )
@@ -72,6 +74,8 @@ from .video_file_meta import (
72
74
  logger = logging.getLogger(__name__) # Changed from "video_file"
73
75
 
74
76
  if TYPE_CHECKING:
77
+ from django.db.models.fields.files import FieldFile
78
+
75
79
  from endoreg_db.models import (
76
80
  Center,
77
81
  EndoscopyProcessor,
@@ -113,7 +117,7 @@ class VideoFile(models.Model):
113
117
  objects = VideoQuerySet.as_manager()
114
118
 
115
119
  raw_file = models.FileField(
116
- upload_to=VIDEO_DIR.name, # Use .name for relative path
120
+ upload_to=SENSITIVE_VIDEO_DIR.name, # Use .name for relative path
117
121
  validators=[FileExtensionValidator(allowed_extensions=["mp4"])],
118
122
  null=True,
119
123
  blank=True,
@@ -142,45 +146,45 @@ class VideoFile(models.Model):
142
146
  null=True,
143
147
  blank=True,
144
148
  related_name="video_file",
145
- ) # type: ignore
146
- center = models.ForeignKey("Center", on_delete=models.PROTECT) # type: ignore
149
+ )
150
+ center = models.ForeignKey("Center", on_delete=models.PROTECT)
147
151
  processor = models.ForeignKey(
148
152
  "EndoscopyProcessor", on_delete=models.PROTECT, blank=True, null=True
149
- ) # type: ignore
153
+ )
150
154
  video_meta = models.OneToOneField(
151
155
  "VideoMeta",
152
156
  on_delete=models.SET_NULL,
153
157
  null=True,
154
158
  blank=True,
155
159
  related_name="video_file",
156
- ) # type: ignore
160
+ )
157
161
  examination = models.ForeignKey(
158
162
  "PatientExamination",
159
163
  on_delete=models.SET_NULL,
160
164
  blank=True,
161
165
  null=True,
162
166
  related_name="video_files",
163
- ) # type: ignore
167
+ )
164
168
  patient = models.ForeignKey(
165
169
  "Patient",
166
170
  on_delete=models.SET_NULL,
167
171
  blank=True,
168
172
  null=True,
169
173
  related_name="video_files",
170
- ) # type: ignore
174
+ )
171
175
  ai_model_meta = models.ForeignKey(
172
176
  "ModelMeta", on_delete=models.SET_NULL, blank=True, null=True
173
- ) # type: ignore
177
+ )
174
178
  state = models.OneToOneField(
175
179
  "VideoState",
176
180
  on_delete=models.SET_NULL,
177
181
  null=True,
178
182
  blank=True,
179
183
  related_name="video_file",
180
- ) # type: ignore
184
+ )
181
185
  import_meta = models.OneToOneField(
182
186
  "VideoImportMeta", on_delete=models.CASCADE, blank=True, null=True
183
- ) # type: ignore
187
+ )
184
188
 
185
189
  original_file_name = models.CharField(max_length=255, blank=True, null=True)
186
190
  uploaded_at = models.DateTimeField(auto_now_add=True)
@@ -206,17 +210,25 @@ class VideoFile(models.Model):
206
210
  date_modified = models.DateTimeField(auto_now=True)
207
211
 
208
212
  if TYPE_CHECKING:
209
- label_video_segments: "models.QuerySet[LabelVideoSegment]"
210
- frames: "models.QuerySet[Frame]"
211
- center: "Center"
212
- processor: "EndoscopyProcessor"
213
- video_meta: "VideoMeta"
214
- examination: "PatientExamination"
215
- patient: "Patient"
216
- sensitive_meta: "SensitiveMeta"
217
- state: "VideoState"
218
- ai_model_meta: "ModelMeta"
219
- import_meta: "VideoImportMeta"
213
+ from django.db.models.manager import RelatedManager
214
+
215
+ @property
216
+ def label_video_segments(self) -> RelatedManager[LabelVideoSegment]: ...
217
+
218
+ @property
219
+ def frames(self) -> RelatedManager[Frame]: ...
220
+
221
+ center: models.ForeignKey["Center"]
222
+ processor: models.ForeignKey["EndoscopyProcessor | None"]
223
+ video_meta: models.OneToOneField["VideoMeta | None"]
224
+ examination: models.ForeignKey["PatientExamination | None"]
225
+ patient: models.ForeignKey["Patient | None"]
226
+ sensitive_meta: models.OneToOneField["SensitiveMeta | None"]
227
+ state: models.OneToOneField["VideoState | None"]
228
+ ai_model_meta: models.ForeignKey["ModelMeta | None"]
229
+ import_meta: models.OneToOneField["VideoImportMeta | None"]
230
+ raw_file = cast(FieldFile, raw_file)
231
+ processed_file = cast(FieldFile, processed_file)
220
232
 
221
233
  @property
222
234
  def ffmpeg_meta(self) -> "FFMpegMeta":
@@ -257,7 +269,10 @@ class VideoFile(models.Model):
257
269
  assert _file is not None, self.NO_ACTIVE_FILE
258
270
  if not _file or not _file.name:
259
271
  raise ValueError(self.NO_FILE_ASSOCIATED)
260
- return _file.url
272
+ url = getattr(_file, "url", None)
273
+ if not url:
274
+ raise ValueError("Active raw file URL could not be resolved.")
275
+ return str(url)
261
276
 
262
277
  # Pipeline Functions
263
278
  pipe_1 = _pipe_1
@@ -416,9 +431,34 @@ class VideoFile(models.Model):
416
431
  )
417
432
 
418
433
  if path is None:
419
- raise ValueError("Active file path could not be resolved.")
434
+ raise ValueError(
435
+ "Active file path could not be resolved. VideoFile raw file is missing."
436
+ )
420
437
  return path
421
438
 
439
+ @property
440
+ def active_file_url(self) -> str:
441
+ """Return the URL of the active video file, if available."""
442
+ file_obj = self.active_file
443
+ if not isinstance(file_obj, FieldFile):
444
+ raise ValueError("Active file is not a valid Django FieldFile instance.")
445
+ try:
446
+ url = getattr(file_obj, "url", None)
447
+ except Exception as exc: # storage backends may raise when missing
448
+ logger.warning(
449
+ "Active file URL unavailable for video %s: %s",
450
+ self.uuid,
451
+ exc,
452
+ )
453
+ raise ValueError(
454
+ "Active file URL could not be resolved for this VideoFile."
455
+ ) from exc
456
+
457
+ if not url:
458
+ raise ValueError("Active file URL is empty for this VideoFile.")
459
+
460
+ return str(url)
461
+
422
462
  @classmethod
423
463
  def create_from_file(
424
464
  cls, file_path: Union[str, Path], center_name: str, **kwargs
@@ -478,11 +518,16 @@ class VideoFile(models.Model):
478
518
  _delete_frames(self)
479
519
 
480
520
  # Call the original delete method to remove the instance from the database
481
- active_path = self.active_file_path
482
- logger.info(f"Deleting VideoFile: {self.uuid} - {active_path}")
521
+ try:
522
+ active_path = self.active_file_path
523
+ logger.info(f"Deleting VideoFile: {self.uuid} - {active_path}")
524
+
525
+ except ValueError:
526
+ logger.info(f"Deleting VideoFile: {self.uuid} - No active file path found.")
527
+ active_path = None
483
528
 
484
529
  # Delete associated files if they exist
485
- if active_path.exists():
530
+ if active_path and active_path.exists():
486
531
  active_path.unlink(missing_ok=True)
487
532
 
488
533
  # Delete file storage
@@ -531,32 +576,19 @@ class VideoFile(models.Model):
531
576
  **IMPORTANT:** Only the raw video is deleted. The processed (anonymized)
532
577
  video is preserved as the final validated output.
533
578
  """
534
- from datetime import date as dt_date
535
-
536
- from endoreg_db.models import SensitiveMeta
537
-
538
- if not self.sensitive_meta:
539
- # CRITICAL FIX: Use create_from_dict with default patient data
540
- default_data = {
541
- "patient_first_name": "Patient",
542
- "patient_last_name": "Unknown",
543
- "patient_dob": dt_date(1990, 1, 1),
544
- "examination_date": dt_date.today(),
545
- "center": self.center,
546
- }
547
- self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
548
579
 
549
580
  # CRITICAL FIX: Delete RAW video file, not the processed (anonymized) one
550
581
  # CRITICAL: Update metadata BEFORE deleting raw video
551
- # Metadata update may trigger frame extraction, which needs raw video
552
- sensitive_meta = _update_text_metadata(
553
- self, extracted_data_dict, overwrite=True
554
- )
582
+ if extracted_data_dict and self.sensitive_meta:
583
+ self.sensitive_meta.update_from_dict(extracted_data_dict)
584
+ else:
585
+ return False
555
586
 
556
587
  # After validation and metadata update, only the anonymized video should remain
557
588
  from .video_file_io import _get_raw_file_path
558
589
 
559
590
  raw_path = _get_raw_file_path(self)
591
+
560
592
  if raw_path and raw_path.exists():
561
593
  logger.info(f"Deleting raw video file after validation: {raw_path}")
562
594
  raw_path.unlink(missing_ok=True)
@@ -567,11 +599,14 @@ class VideoFile(models.Model):
567
599
  f"Raw video deleted for {self.uuid}. Anonymized video preserved."
568
600
  )
569
601
  else:
570
- logger.warning(f"Raw video file not found for deletion: {self.uuid}")
602
+ logger.warning(
603
+ "Raw video file not found for deletion during validation %s.",
604
+ self.uuid,
605
+ )
571
606
 
572
- if sensitive_meta:
607
+ if self.sensitive_meta:
573
608
  # Mark as processed after validation
574
- self.get_or_create_state().mark_sensitive_meta_processed(save=True)
609
+ self.get_or_create_state().mark_anonymization_validated(save=True)
575
610
  # Save the VideoFile instance to persist changes
576
611
  self.save()
577
612
  logger.info(
@@ -602,7 +637,6 @@ class VideoFile(models.Model):
602
637
  # Create a new state if it doesn't exist
603
638
  self.state = self.get_or_create_state()
604
639
 
605
- self.sensitive_meta = self.get_or_create_sensitive_meta()
606
640
  self.save()
607
641
  # Initialize frames based on the video specs
608
642
  self.initialize_frames()
@@ -626,6 +660,11 @@ class VideoFile(models.Model):
626
660
  Mark this video's processing state as having its sensitive meta fully processed.
627
661
  This proxies to the related VideoState and persists by default.
628
662
  """
663
+ sm = self.sensitive_meta
664
+ from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
665
+
666
+ if not isinstance(sm, SensitiveMeta):
667
+ raise AttributeError()
629
668
  state = self.get_or_create_state()
630
669
  state.mark_sensitive_meta_processed(save=save)
631
670
  return self
@@ -635,8 +674,13 @@ class VideoFile(models.Model):
635
674
  Mark the associated SensitiveMeta as verified by setting both DOB and names as verified.
636
675
  Ensures the SensitiveMeta and its state exist.
637
676
  """
638
- sm = self.get_or_create_sensitive_meta()
677
+ sm = self.sensitive_meta
639
678
  # Use SensitiveMeta methods to update underlying SensitiveMetaState
679
+ from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
680
+
681
+ if not isinstance(sm, SensitiveMeta):
682
+ raise AttributeError()
683
+
640
684
  sm.mark_dob_verified()
641
685
  sm.mark_names_verified()
642
686
  return self
@@ -675,65 +719,6 @@ class VideoFile(models.Model):
675
719
 
676
720
  return state
677
721
 
678
- def get_or_create_sensitive_meta(self) -> "SensitiveMeta":
679
- """
680
- Retrieve the associated SensitiveMeta instance for this video, creating and assigning one if it does not exist.
681
-
682
- **Two-Phase Patient Data Pattern:**
683
- This method implements a two-phase approach to handle incomplete patient data:
684
-
685
- **Phase 1: Initial Creation (with defaults)**
686
- - Creates SensitiveMeta with default patient data to prevent hash calculation errors
687
- - Default values: patient_first_name="Patient", patient_last_name="Unknown", patient_dob=1990-01-01
688
- - Allows video import to proceed even without extracted patient data
689
- - Temporary hash and pseudo-entities are created
690
-
691
- **Phase 2: Update (with extracted data)**
692
- - Real patient data is extracted later (e.g., from video OCR via lx_anonymizer)
693
- - update_from_dict() is called with actual patient information
694
- - Hash is recalculated automatically using real data
695
- - Correct pseudo-entities are created/linked based on new hash
696
-
697
- **Example workflow:**
698
- ```python
699
- # Phase 1: Video creation
700
- video = VideoFile.create_from_file_initialized(...)
701
- video.initialize() # Calls this method
702
- # → SensitiveMeta created with defaults
703
- # → Hash: sha256("Patient Unknown 1990-01-01...")
704
-
705
- # Phase 2: Frame cleaning extracts real data
706
- extracted = {"patient_first_name": "Max", "patient_last_name": "Mustermann", ...}
707
- video.sensitive_meta.update_from_dict(extracted)
708
- # → Hash: sha256("Max Mustermann 1985-03-15...") (RECALCULATED)
709
- ```
710
-
711
- Returns:
712
- SensitiveMeta: The related SensitiveMeta instance.
713
-
714
- See Also:
715
- - sensitive_meta_logic.perform_save_logic() for hash calculation details
716
- - sensitive_meta_logic.update_sensitive_meta_from_dict() for update mechanism
717
- """
718
- from datetime import date as dt_date
719
-
720
- from endoreg_db.models import SensitiveMeta
721
-
722
- if self.sensitive_meta is None:
723
- # Use create_from_dict with default patient data
724
- # to prevent "First name is required to calculate patient hash" error
725
- default_data = {
726
- "patient_first_name": "Patient",
727
- "patient_last_name": "Unknown",
728
- "patient_dob": dt_date(1990, 1, 1),
729
- "examination_date": dt_date.today(),
730
- "center": self.center,
731
- }
732
- self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
733
- self.save(update_fields=["sensitive_meta"])
734
- # Do not mark state as processed here; it will be set after extraction/validation steps
735
- return self.sensitive_meta
736
-
737
722
  def get_outside_segments(
738
723
  self, only_validated: bool = False
739
724
  ) -> models.QuerySet["LabelVideoSegment"]:
@@ -767,6 +752,82 @@ class VideoFile(models.Model):
767
752
  )
768
753
  return self.label_video_segments.none()
769
754
 
755
+ @classmethod
756
+ def create_video_without_outside_frames(
757
+ cls, instance: "VideoFile", only_validated: bool = False
758
+ ) -> bool:
759
+ """
760
+ Creates a new video by excluding frames that belong to 'outside' segments.
761
+
762
+ Parameters:
763
+ only_validated (bool): If True, only validated segments are considered for frame exclusion.
764
+
765
+ Returns:
766
+ VideoFile: A new VideoFile instance with the frames excluding those labeled as 'outside'.
767
+ """
768
+ video = instance
769
+
770
+ if not video:
771
+ logger.warning(
772
+ "No processed video file available for VideoFile %s.", cls.uuid
773
+ )
774
+ return False
775
+ try:
776
+ extracted = video.extract_frames(
777
+ quality=2,
778
+ overwrite=False,
779
+ ext="jpg",
780
+ verbose=False,
781
+ from_processed=True,
782
+ )
783
+ assert extracted is True
784
+ except AssertionError:
785
+ extracted = video.extract_frames(
786
+ quality=2,
787
+ overwrite=False,
788
+ ext="jpg",
789
+ verbose=False,
790
+ from_processed=True,
791
+ )
792
+ assert extracted is True
793
+ try:
794
+ # Step 1: Get the "outside" labeled frames
795
+ censored = _censor_outside_frames(video)
796
+ frames = [instance.get_frame_dir_path()]
797
+ assert len(frames) != 0
798
+ fps = (
799
+ video.fps if video.fps else 120.0
800
+ ) # Default to 30 FPS if fps is not set
801
+ assert censored is True
802
+ assert fps is not None
803
+ assert video.width is not None
804
+ assert video.height is not None
805
+ # assert isinstance(frames, list[Path]) #TODO improve TypeCheck
806
+
807
+ # Step 2: Reassemble the video with frames excluding the 'outside' labeled frames
808
+ output_video_path = Path(f"/path/to/output/{cls.uuid}_filtered.mp4")
809
+ fps = cls.fps if cls.fps else 30.0 # Default to 30 FPS if fps is not set
810
+ new_video_file = assemble_video_from_frames(
811
+ frames, output_video_path, fps, width=video.width, height=video.height
812
+ )
813
+ video.processed_file = new_video_file
814
+ return True
815
+ except AssertionError as ae:
816
+ logger.error(
817
+ f"Assertion error while creating video without 'outside' frames for VideoFile {cls.uuid}: {ae}",
818
+ exc_info=True,
819
+ )
820
+ return False
821
+ except Label.DoesNotExist:
822
+ logger.warning("Outside label not found in the database.")
823
+ return False
824
+ except Exception as e:
825
+ logger.error(
826
+ f"Error creating video without 'outside' frames for VideoFile {cls.uuid}: {e}",
827
+ exc_info=True,
828
+ )
829
+ return False
830
+
770
831
  @classmethod
771
832
  def get_all_videos(cls) -> models.QuerySet["VideoFile"]:
772
833
  """
@@ -809,7 +870,8 @@ class VideoFile(models.Model):
809
870
  raise ValueError("FPS must be set and greater than zero.")
810
871
  return frame_number / fps
811
872
 
812
- def get_video_by_id(self, video_id: int) -> "VideoFile":
873
+ @staticmethod
874
+ def get_video_by_pk(pk: int) -> "VideoFile":
813
875
  """
814
876
  Retrieve a VideoFile instance by its primary key (ID).
815
877
 
@@ -822,4 +884,4 @@ class VideoFile(models.Model):
822
884
  Raises:
823
885
  VideoFile.DoesNotExist: If no VideoFile with the given ID exists.
824
886
  """
825
- return self.objects.get(pk=video_id)
887
+ return VideoFile.objects.get(pk=video_id)