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
@@ -0,0 +1,128 @@
1
+ from typing import Optional, Tuple
2
+
3
+ from datetime import date as Date
4
+ import datetime
5
+
6
+ from .k_anonymity import _build_sensitive_meta_qi_queryset
7
+ from .fake import fake_name_with_similar_dob_and_gender
8
+
9
+ from endoreg_db.models import SensitiveMeta
10
+
11
+ def k_pseudonymize(
12
+ instance: SensitiveMeta,
13
+ *,
14
+ k_threshold: int = 3,
15
+ dob_year_tolerance: int = 3,
16
+ qi_subset: Optional[Tuple[str, ...]] = None,
17
+ locale: str = "de_DE",
18
+ seed: Optional[int] = None,
19
+ save: bool = True,
20
+ ) -> Tuple[SensitiveMeta, int, bool]:
21
+ """
22
+ Ensure a SensitiveMeta instance reaches at least `k_threshold` anonymity
23
+ for the given quasi-identifier subset by pseudonymizing patient
24
+ first_name, last_name and DOB if necessary.
25
+
26
+ Args:
27
+ instance:
28
+ The SensitiveMeta instance to process.
29
+ k_threshold:
30
+ Minimal k for the chosen QI subset.
31
+ dob_year_tolerance:
32
+ Used both for k-anonymity DOB band and for Faker's DOB perturbation.
33
+ qi_subset:
34
+ Which QIs to use for k-anonymity check.
35
+ Elements from: {"first_name", "last_name", "center", "gender", "dob_band"}.
36
+ Default = all of them.
37
+ locale:
38
+ Faker locale for a realistic name.
39
+ seed:
40
+ Optional seed for reproducibility.
41
+ save:
42
+ If True, save the instance after pseudonymization.
43
+
44
+ Returns:
45
+ (instance, k_value_after, is_k_anonymous_after)
46
+ """
47
+ if qi_subset is None:
48
+ qi_subset = tuple(QI_FLAGS)
49
+
50
+ # --- 1) Compute k for the requested subset BEFORE pseudonymization ---
51
+ use_first_name = "first_name" in qi_subset
52
+ use_last_name = "last_name" in qi_subset
53
+ use_center = "center" in qi_subset
54
+ use_gender = "gender" in qi_subset
55
+ use_dob_band = "dob_band" in qi_subset
56
+
57
+ qs_before = _build_sensitive_meta_qi_queryset(
58
+ instance,
59
+ dob_year_tolerance=dob_year_tolerance,
60
+ include_self=True,
61
+ use_first_name=use_first_name,
62
+ use_last_name=use_last_name,
63
+ use_center=use_center,
64
+ use_gender=use_gender,
65
+ use_dob_band=use_dob_band,
66
+ )
67
+ k_before = qs_before.count()
68
+
69
+ if k_before >= k_threshold:
70
+ # Already sufficiently anonymous, nothing to do
71
+ return instance, k_before, True
72
+
73
+ # --- 2) Pseudonymize name + DOB using Faker ---
74
+ # Gender string for Faker
75
+ if instance.patient_gender and getattr(instance.patient_gender, "name", None):
76
+ gender_name = instance.patient_gender.name
77
+ else:
78
+ # Fallback if gender missing -> bias to 'male' but you can change that
79
+ gender_name = "male"
80
+
81
+ # Original DOB as date (fallback to today's date if missing)
82
+ if instance.patient_dob is not None:
83
+ orig_dob: Date = instance.patient_dob.date()
84
+ else:
85
+ orig_dob = Date.today()
86
+
87
+ first_name, last_name, fake_dob = fake_name_with_similar_dob_and_gender(
88
+ gender=gender_name,
89
+ dob=orig_dob,
90
+ year_tolerance=dob_year_tolerance,
91
+ locale=locale,
92
+ seed=seed,
93
+ )
94
+
95
+ # Assign to instance (SensitiveMeta.patient_dob is a DateTimeField)
96
+ instance.patient_first_name = first_name
97
+ instance.patient_last_name = last_name
98
+ instance.patient_dob = datetime(
99
+ fake_dob.year, fake_dob.month, fake_dob.day
100
+ ) # naive is usually fine for DOB
101
+
102
+ if save:
103
+ instance.save(update_fields=["patient_first_name", "patient_last_name", "patient_dob"])
104
+
105
+ # --- 3) Recompute k AFTER pseudonymization ---
106
+ qs_after = _build_sensitive_meta_qi_queryset(
107
+ instance,
108
+ dob_year_tolerance=dob_year_tolerance,
109
+ include_self=True,
110
+ use_first_name=use_first_name,
111
+ use_last_name=use_last_name,
112
+ use_center=use_center,
113
+ use_gender=use_gender,
114
+ use_dob_band=use_dob_band,
115
+ )
116
+ k_after = qs_after.count()
117
+ is_k_anon_after = k_after >= k_threshold
118
+
119
+ logger.info(
120
+ "k_pseudonymize: SensitiveMeta pk=%s, subset=%s, k_before=%s, k_after=%s, threshold=%s",
121
+ instance.pk,
122
+ qi_subset,
123
+ k_before,
124
+ k_after,
125
+ k_threshold,
126
+ )
127
+
128
+ return instance, k_after, is_k_anon_after
@@ -0,0 +1,141 @@
1
+ # endoreg_db/services/report_import_service.py
2
+ from __future__ import annotations
3
+
4
+ import logging
5
+ from pathlib import Path
6
+ from typing import Optional, Union
7
+
8
+ from endoreg_db.import_files.context.file_lock import file_lock
9
+ from endoreg_db.import_files.context.import_context import ImportContext
10
+ from endoreg_db.import_files.processing.report_processing.report_anonymization import (
11
+ ReportAnonymizer,
12
+ )
13
+
14
+ from endoreg_db.import_files.file_storage.create_report_file import (
15
+ create_or_retrieve_report_file,
16
+ )
17
+ from endoreg_db.import_files.file_storage.state_management import (
18
+ finalize_report_success,
19
+ finalize_failure,
20
+ mark_instance_processing_started,
21
+ )
22
+ from endoreg_db.import_files.context.validate_directories import validate_directories
23
+
24
+ from endoreg_db.import_files.file_storage.storage import create_sensitive_copy
25
+ from endoreg_db.models.media import RawPdfFile
26
+ from endoreg_db.utils.paths import (
27
+ SENSITIVE_REPORT_DIR,
28
+ )
29
+
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class ReportImportService:
35
+ """
36
+ Service for importing and anonymizing report (PDF) files.
37
+
38
+ Responsibilities:
39
+ - Acquire file lock
40
+ - Create sensitive copy
41
+ - Create/reuse RawPdfFile (dedupe by hash) + history
42
+ - Run anonymization pipeline (primary + fallback)
43
+ - Finalize state and move anonymized file
44
+ - Cleanup on error
45
+ """
46
+
47
+ def __init__(self) -> None:
48
+ self.logger = logger
49
+ self.anonymizer = ReportAnonymizer()
50
+ self.processing_context: Optional[ImportContext] = None
51
+ self.current_report: Optional[RawPdfFile] = None
52
+
53
+ validate_directories()
54
+
55
+
56
+ def import_and_anonymize(
57
+ self,
58
+ file_path: Union[Path, str],
59
+ center_name: str,
60
+ retry: bool = False,
61
+ delete_source: bool = True,
62
+ ) -> "RawPdfFile | None":
63
+ """
64
+ Public entrypoint: wrap import_and_anonymize logic.
65
+ """
66
+ # First, initialize import context. this will be updated during import and keep track of current paths, file type and center and processor.
67
+ ctx = ImportContext(
68
+ file_path=Path(file_path),
69
+ center_name=center_name,
70
+ delete_source=delete_source,
71
+ file_type="report"
72
+ )
73
+ self.logger.info("validating and preparing file")
74
+ if not ctx.file_path.exists():
75
+ raise FileNotFoundError(f"Video file not found: {file_path}")
76
+
77
+ ctx.sensitive_path = create_sensitive_copy(
78
+ ctx.file_path,
79
+ SENSITIVE_REPORT_DIR
80
+ )
81
+
82
+ with file_lock(ctx.file_path):
83
+ logger.info("Acquired file lock for %s", ctx.file_path)
84
+
85
+ # create or retrieve RawPdfFile + update history
86
+ ctx.current_report, needs_processing = create_or_retrieve_report_file(ctx)
87
+ ctx.current_report.get_or_create_state()
88
+ assert(ctx.current_report.state is not None)
89
+ ctx.current_report = ctx.current_report
90
+
91
+ ctx.retry = retry
92
+ # Retry is a forced overwrite of needs processing - therefore the retry will cause full deletion of processed files using finalize failure.
93
+ if retry and needs_processing and not ctx.current_report.state.anonymization_validated:
94
+ # ensure clean slate for forced reprocessing
95
+ finalize_failure(ctx)
96
+ ctx.current_report, needs_processing = create_or_retrieve_report_file(ctx)
97
+ assert(needs_processing is True)
98
+ elif not needs_processing and not retry:
99
+ return ctx.current_report
100
+
101
+ mark_instance_processing_started(ctx.current_report, ctx)
102
+ try:
103
+ # --- Anonymization with fallback ---
104
+ try:
105
+ ctx = self.anonymizer.anonymize_report(ctx)
106
+ logger.info(
107
+ "Primary report anonymization succeeded for %s",
108
+ ctx.file_path,
109
+ )
110
+ except Exception as primary_exc:
111
+ logger.exception(
112
+ "Primary report anonymization failed for %s: %s "
113
+ "- trying basic anonymization",
114
+ ctx.file_path,
115
+ primary_exc,
116
+ )
117
+ try:
118
+ ctx = self.anonymizer.anonymize_report(ctx)
119
+ except Exception as e:
120
+ logger.error(f"PDF Extraction failed for the second time. {e}")
121
+ raise
122
+
123
+ logger.info(
124
+ "Basic report anonymization succeeded for %s",
125
+ ctx.file_path,
126
+ )
127
+
128
+ # --- Finalize success: history + move anonymized file ---
129
+ finalize_report_success(ctx)
130
+
131
+ return ctx.current_report
132
+
133
+ except Exception as exc:
134
+ logger.exception(
135
+ "Report import/anonymization failed for %s: %s", ctx.file_path, exc
136
+ )
137
+ # mark failure in history
138
+ finalize_failure(ctx)
139
+ raise
140
+
141
+
@@ -0,0 +1,150 @@
1
+ # endoreg_db/services/video_import.py
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import Optional, Union
5
+
6
+
7
+ from endoreg_db.import_files.context import (
8
+ ImportContext,
9
+ file_lock,
10
+ )
11
+ from endoreg_db.import_files.file_storage.state_management import (
12
+ finalize_failure,
13
+ finalize_video_success
14
+ )
15
+ from endoreg_db.import_files.file_storage.storage import create_sensitive_copy
16
+ from endoreg_db.import_files.file_storage.create_video_file import (
17
+ create_or_retrieve_video_file,
18
+ )
19
+ from endoreg_db.import_files.context.validate_directories import validate_directories
20
+ from endoreg_db.import_files.file_storage.state_management import (
21
+ mark_instance_processing_started,
22
+ )
23
+ from endoreg_db.models import VideoFile
24
+ from endoreg_db.import_files.processing.video_processing.video_anonymization import VideoAnonymizer
25
+ from endoreg_db.utils.paths import (
26
+ SENSITIVE_VIDEO_DIR,
27
+ )
28
+
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class VideoImportService:
34
+ """
35
+ Service for importing and anonymizing video files.
36
+ Uses a central video instance pattern for cleaner state management.
37
+ Responsibility:
38
+ Validate path
39
+ Move/copy raw file into stable storage
40
+ Create/attach VideoFile, VideoState, default SensitiveMeta
41
+ Mark a single clear state like state.import_completed = True or state.ready_for_anonymization = True
42
+
43
+ It does not:
44
+ Run frame cleaning
45
+ Run ML
46
+ Create processed_file
47
+ Decide fallback anonymization
48
+
49
+ These actions are delegated to the modules inside file_import
50
+
51
+ """
52
+
53
+ def __init__(self):
54
+ self.logger = logger
55
+ self.anonymizer = VideoAnonymizer()
56
+ self.processing_context: Optional[ImportContext] = None
57
+ self.current_video: Optional[VideoFile] = None
58
+
59
+ validate_directories()
60
+
61
+
62
+ def import_and_anonymize(
63
+ self,
64
+ file_path: Union[Path, str],
65
+ center_name: str,
66
+ processor_name: str,
67
+ retry:bool = False,
68
+ delete_source: bool = True,
69
+ ) -> "VideoFile | None":
70
+ """
71
+ Public entrypoint: wrap import_and_anonymize logic.
72
+ """
73
+ # First, initialize import context. this will be updated during import and keep track of current paths, file type and center and processor.
74
+ ctx = ImportContext(
75
+ file_path=Path(file_path),
76
+ center_name=center_name,
77
+ processor_name=processor_name,
78
+ delete_source=delete_source,
79
+ file_type="video"
80
+ )
81
+ self.logger.info("validating and preparing file")
82
+ if not ctx.file_path.exists():
83
+ raise FileNotFoundError(f"Video file not found: {file_path}")
84
+
85
+ ctx.sensitive_path = create_sensitive_copy(
86
+ ctx.file_path,
87
+ SENSITIVE_VIDEO_DIR
88
+ )
89
+
90
+ with file_lock(ctx.file_path):
91
+ logger.info("Acquired file lock for %s", ctx.file_path)
92
+
93
+
94
+ # create or retrieve VideoFile + update history
95
+ ctx.current_video, needs_processing = (
96
+ create_or_retrieve_video_file(ctx)
97
+ )
98
+ ctx.current_video.get_or_create_state()
99
+ assert(ctx.current_video.state is not None)
100
+ ctx.current_video = ctx.current_video
101
+
102
+ ctx.retry = retry
103
+ # Retry is a forced overwrite of needs processing - therefore the retry will cause full deletion of processed files using finalize failure.
104
+
105
+ if retry and needs_processing and not ctx.current_video.state.anonymization_validated:
106
+ finalize_failure(ctx)
107
+ ctx.current_video, needs_processing = create_or_retrieve_video_file(ctx)
108
+ assert(needs_processing is True)
109
+ elif not needs_processing and not retry:
110
+ return ctx.current_video
111
+
112
+ mark_instance_processing_started(ctx.current_video, ctx)
113
+ try:
114
+ # --- Anonymization with fallback ---
115
+ try:
116
+ ctx = self.anonymizer.anonymize_video(ctx)
117
+ logger.info(
118
+ "Primary video anonymization succeeded for %s",
119
+ ctx.file_path,
120
+ )
121
+ except Exception as primary_exc:
122
+ logger.exception(
123
+ "Primary video anonymization failed for %s: %s "
124
+ "- trying basic anonymization",
125
+ ctx.file_path,
126
+ primary_exc,
127
+ )
128
+ try:
129
+ ctx = self.anonymizer.anonymize_video(ctx)
130
+ except Exception as e:
131
+ logger.error(f"Video Extraction failed for the second time. {e}")
132
+ raise
133
+ logger.info(
134
+ "Secondary video anonymization succeeded for %s",
135
+ ctx.file_path,
136
+ )
137
+ logger.info(f"Anonymized Video is located at: {ctx.anonymized_path}")
138
+
139
+ # --- Finalize success: history + move anonymized file ---
140
+ finalize_video_success(ctx)
141
+
142
+ return ctx.current_video
143
+
144
+
145
+ except Exception as exc:
146
+ logger.exception(
147
+ "Video import/anonymization failed for %s: %s", ctx.file_path, exc
148
+ )
149
+ finalize_failure(ctx)
150
+ raise
@@ -5,7 +5,7 @@ Django management command to create ModelMeta from Hugging Face model.
5
5
  from pathlib import Path
6
6
 
7
7
  from django.core.files.base import ContentFile
8
- from django.core.management.base import BaseCommand
8
+ from django.core.management.base import BaseCommand, CommandError
9
9
  from huggingface_hub import hf_hub_download
10
10
 
11
11
  from endoreg_db.models import AiModel, LabelSet, ModelMeta
@@ -39,12 +39,19 @@ class Command(BaseCommand):
39
39
  default="1",
40
40
  help="Version for the model meta",
41
41
  )
42
+ parser.add_argument(
43
+ "--labelset_version",
44
+ type=int,
45
+ default=None,
46
+ help="LabelSet version; if omitted, the latest by name is used",
47
+ )
42
48
 
43
49
  def handle(self, *args, **options):
44
50
  model_id = options["model_id"]
45
51
  model_name = options["model_name"]
46
52
  labelset_name = options["labelset_name"]
47
53
  version = options["meta_version"]
54
+ labelset_version = options.get("labelset_version")
48
55
 
49
56
  self.stdout.write(f"Downloading model {model_id} from Hugging Face...")
50
57
 
@@ -52,7 +59,7 @@ class Command(BaseCommand):
52
59
  # Download the model weights
53
60
  weights_path = hf_hub_download(
54
61
  repo_id=model_id,
55
- filename="colo_segmentation_RegNetX800MF_base.ckpt",
62
+ filename="colo_segmentation_RegNetX800MF_base.safetensors",
56
63
  local_dir="/tmp",
57
64
  )
58
65
  self.stdout.write(f"Downloaded weights to: {weights_path}")
@@ -64,14 +71,17 @@ class Command(BaseCommand):
64
71
  if created:
65
72
  self.stdout.write(f"Created AI model: {ai_model.name}")
66
73
 
67
- # Get labelset
68
- try:
69
- labelset = LabelSet.objects.get(name=labelset_name)
70
- except LabelSet.DoesNotExist:
71
- self.stdout.write(
72
- self.style.ERROR(f"LabelSet '{labelset_name}' not found")
74
+ # Get labelset (optionally by version); fail with non-zero exit
75
+ labelset_qs = LabelSet.objects.filter(name=labelset_name)
76
+ if labelset_version is not None:
77
+ labelset_qs = labelset_qs.filter(version=labelset_version)
78
+ labelset = labelset_qs.order_by("-version").first()
79
+ if labelset is None:
80
+ raise CommandError(
81
+ f"LabelSet '{labelset_name}'"
82
+ + (f" v{labelset_version}" if labelset_version is not None else "")
83
+ + " not found"
73
84
  )
74
- return
75
85
 
76
86
  # Create ModelMeta
77
87
  model_meta, created = ModelMeta.objects.get_or_create(
@@ -95,7 +105,7 @@ class Command(BaseCommand):
95
105
  # Save the weights file to the model
96
106
  with open(weights_path, "rb") as f:
97
107
  model_meta.weights.save(
98
- f"{model_name}_v{version}_pytorch_model.bin", ContentFile(f.read())
108
+ f"{model_name}_v{version}.safetensors", ContentFile(f.read())
99
109
  )
100
110
 
101
111
  # Set as active meta
@@ -113,3 +123,4 @@ class Command(BaseCommand):
113
123
  import traceback
114
124
 
115
125
  traceback.print_exc()
126
+ raise CommandError("ModelMeta creation failed") from e