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
@@ -1,105 +0,0 @@
1
- """
2
- Video Metadata Serializer
3
-
4
- Serializes VideoMetadata model for API responses.
5
- Created as part of Phase 1.1: Video Correction API Endpoints.
6
- """
7
- from rest_framework import serializers
8
- from endoreg_db.models.media.video import VideoMetadata
9
- import json
10
-
11
-
12
- class VideoMetadataSerializer(serializers.ModelSerializer):
13
- """
14
- Serializer for VideoMetadata model.
15
-
16
- Provides analysis results (sensitive frame count, ratio, frame IDs)
17
- for the correction UI.
18
- """
19
- sensitive_frame_ids_list = serializers.SerializerMethodField()
20
- sensitive_percentage = serializers.ReadOnlyField()
21
- has_analysis = serializers.ReadOnlyField()
22
-
23
- class Meta:
24
- model = VideoMetadata
25
- fields = [
26
- 'id',
27
- 'video',
28
- 'sensitive_frame_count',
29
- 'sensitive_ratio',
30
- 'sensitive_frame_ids',
31
- 'sensitive_frame_ids_list',
32
- 'sensitive_percentage',
33
- 'has_analysis',
34
- 'analyzed_at',
35
- ]
36
- read_only_fields = ['id', 'analyzed_at']
37
-
38
- def get_sensitive_frame_ids_list(self, obj) -> list:
39
- """
40
- Parse sensitive_frame_ids from JSON string to Python list.
41
-
42
- Returns:
43
- list: Frame indices (0-based), or empty list if no analysis
44
- """
45
- if not obj.sensitive_frame_ids:
46
- return []
47
-
48
- try:
49
- return json.loads(obj.sensitive_frame_ids)
50
- except (json.JSONDecodeError, TypeError):
51
- return []
52
-
53
- def validate_sensitive_frame_ids(self, value):
54
- """
55
- Validate that sensitive_frame_ids is a valid JSON array.
56
-
57
- Args:
58
- value: JSON string representing frame IDs
59
-
60
- Returns:
61
- str: Validated JSON string
62
-
63
- Raises:
64
- ValidationError: If value is not valid JSON or not an array
65
- """
66
- if not value:
67
- return value
68
-
69
- try:
70
- parsed = json.loads(value)
71
- if not isinstance(parsed, list):
72
- raise serializers.ValidationError(
73
- "sensitive_frame_ids must be a JSON array"
74
- )
75
-
76
- # Validate all elements are integers
77
- if not all(isinstance(x, int) for x in parsed):
78
- raise serializers.ValidationError(
79
- "All frame IDs must be integers"
80
- )
81
-
82
- return value
83
- except json.JSONDecodeError:
84
- raise serializers.ValidationError(
85
- "sensitive_frame_ids must be valid JSON"
86
- )
87
-
88
- def validate_sensitive_ratio(self, value):
89
- """
90
- Validate that sensitive_ratio is between 0.0 and 1.0.
91
-
92
- Args:
93
- value: Ratio value
94
-
95
- Returns:
96
- float: Validated ratio
97
-
98
- Raises:
99
- ValidationError: If value is outside valid range
100
- """
101
- if value is not None and (value < 0.0 or value > 1.0):
102
- raise serializers.ValidationError(
103
- "sensitive_ratio must be between 0.0 and 1.0"
104
- )
105
- return value
@@ -1,147 +0,0 @@
1
- from ast import List
2
- import pickle
3
- from endoreg_db.models import Requirement, Examination, PatientExamination
4
- from endoreg_db.serializers import PatientExaminationSerializer, ExaminationSerializer, FindingClassificationSerializer, RequirementSerializer
5
-
6
-
7
- class LookupService:
8
- def __init__(self, db_session):
9
- self.db_session = db_session
10
- self.hexdict = int()
11
-
12
- def hash_lookup(self, key, value):
13
- """
14
- Store a key-value pair in the lookup dictionary.
15
- """
16
- lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
17
- lookup_dict[key] = value
18
- self.hexdict = pickle.dumps(dict).hex()
19
- return True
20
- def hash_retrieve(self, key):
21
- """
22
- Retrieve a value by key from the lookup dictionary.
23
- """
24
- lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
25
- return lookup_dict.get(key, None)
26
-
27
- def hash_add_key_value(self, key, value):
28
- """
29
- Add a key-value pair to the lookup dictionary.
30
- """
31
- lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
32
- lookup_dict[key] = value
33
- self.hexdict = pickle.dumps(lookup_dict).hex()
34
- return True
35
-
36
- def hash_dehash(self):
37
- """
38
- Retrieve the entire lookup dictionary.
39
- """
40
- lookup_dict = pickle.loads(bytes.fromhex(self.hexdict))
41
- return lookup_dict
42
-
43
- def fetch_examination_dict(self, patient_id, tags: List[str] = None):
44
- """
45
- Fetch examinations for a given patient ID, optionally filtered by tags.
46
- """
47
- query = self.db_session.query(Examination).filter(Examination.patient_id == patient_id)
48
- if tags:
49
- query = query.filter(Examination.tags.any(Examination.tags.in_(tags)))
50
- examinations = query.all()
51
- return [ExaminationSerializer(exam).data for exam in examinations]
52
-
53
- def fetch_patient_examination_by_id(self, patient_id, examination_id):
54
- """
55
- Fetch a patient examination object from the database by its ID.
56
- """
57
- return self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
58
-
59
- def fetch_patient_examinations(self, patient_id):
60
- """
61
- Fetch all patient examinations for a given patient ID.
62
- """
63
- examinations = self.db_session.query(PatientExamination).filter(PatientExamination.patient_id == patient_id).all()
64
- return [PatientExaminationSerializer(exam).data for exam in examinations]
65
-
66
- def fetch_findings_by_patient_examination(self, patient_examination_id):
67
- """
68
- Fetch findings associated with a given patient examination ID.
69
- """
70
- patient_examination = self.db_session.query(PatientExamination).filter(PatientExamination.id == patient_examination_id).first()
71
- if not patient_examination:
72
- return []
73
- return [finding.serialize() for finding in patient_examination.findings]
74
-
75
- def fetch_classifications_by_finding(self, finding_id):
76
- """
77
- Fetch classifications associated with a given finding ID.
78
- """
79
- finding = self.db_session.query(Finding).filter(Finding.id == finding_id).first()
80
- if not finding:
81
- return []
82
- return [classification.serialize() for classification in finding.classifications]
83
-
84
- def fetch_default_finding_classification(self):
85
- """
86
- Fetch the default finding classification from the database.
87
- """
88
- return self.db_session.query(FindingClassification).filter(FindingClassification.is_default == True).first()
89
-
90
- def fetch_finding_classification_choice_by_requirement(self, requirement_id):
91
- """
92
- Retrieve finding classification choices based on the provided requirement ID.
93
- """
94
- requirement = self.get_requirement_by_id(requirement_id)
95
- if not requirement:
96
- return []
97
- return [choice.serialize() for choice in requirement.finding_classification_choices]
98
-
99
- def fetch_requirement_choices_by_requirement(self, requirement_id):
100
- """
101
- Retrieve requirement choices based on the provided requirement ID.
102
- """
103
- requirement = self.get_requirement_by_id(requirement_id)
104
- if not requirement:
105
- return []
106
- return [choice.serialize() for choice in requirement.requirement_choices]
107
-
108
- def available_finding_classification_choices_by_finding_classification(self, finding_classification):
109
- """
110
- Retrieve available finding classification choices based on the provided finding classification.
111
- """
112
- return self.db_session.query(FindingClassificationChoice).filter(
113
- FindingClassificationChoice.finding_classification_id == finding_classification.id
114
- ).all()
115
-
116
- def get_requirement_by_id(self, requirement_id):
117
- """
118
- Fetch a requirement object from the database by its ID.
119
- """
120
- return self.db_session.query(Requirement).filter(Requirement.id == requirement_id).first()
121
-
122
- def get_all_requirements_for_requirement_sets(self, requirement_set_ids: List[int]):
123
- """
124
- Fetch all requirements associated with the given requirement set IDs.
125
- """
126
- return self.db_session.query(Requirement).filter(Requirement.requirement_set_id.in_(requirement_set_ids)).all()
127
-
128
- def get_all_requirement_sets_for_examination(self, examination_id):
129
- """
130
- Fetch all requirement sets associated with the given examination ID.
131
- """
132
- examination = self.db_session.query(Examination).filter(Examination.id == examination_id).first()
133
- if not examination:
134
- return []
135
- return [req_set.serialize() for req_set in examination.requirement_sets]
136
-
137
- def serialize_requirement(self, requirement):
138
- """
139
- Serialize a requirement object to a byte stream.
140
- """
141
- return pickle.dumps(requirement)
142
-
143
- def deserialize_requirement(self, serialized_requirement):
144
- """
145
- Deserialize a byte stream back to a requirement object.
146
- """
147
- return pickle.loads(serialized_requirement)
@@ -1,344 +0,0 @@
1
- from django.db import transaction
2
- from pathlib import Path
3
- import logging
4
- import shutil
5
- from datetime import datetime
6
- from typing import Optional
7
-
8
- from endoreg_db.models import VideoFile, AnonymizationTask
9
- from endoreg_db.exceptions import InsufficientStorageError
10
- # from endoreg_db.models.media.video.create_from_file import check_storage_capacity
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- class StorageAwareVideoProcessor:
16
- """
17
- Enhanced video processor with built-in storage management and automatic cleanup.
18
- """
19
-
20
- def __init__(self, auto_cleanup: bool = True, min_free_space_gb: float = 10.0):
21
- self.auto_cleanup = auto_cleanup
22
- self.min_free_space_gb = min_free_space_gb
23
-
24
- def check_and_ensure_storage(self, required_space_estimate: int = None) -> bool:
25
- """
26
- Check storage capacity and perform cleanup if needed.
27
-
28
- Args:
29
- required_space_estimate: Estimated space needed in bytes
30
-
31
- Returns:
32
- True if enough space is available, False otherwise
33
-
34
- Raises:
35
- InsufficientStorageError: If space cannot be freed
36
- """
37
- try:
38
- # Get current storage stats
39
- total, used, free = shutil.disk_usage('/')
40
- free_gb = free / (1024**3)
41
- usage_percent = (used / total) * 100
42
-
43
- logger.info(f"Storage check: {free_gb:.1f}GB free ({usage_percent:.1f}% used)")
44
-
45
- # Check if we need emergency cleanup
46
- needs_cleanup = (
47
- usage_percent >= 95.0 or
48
- free_gb < self.min_free_space_gb or
49
- (required_space_estimate and free < required_space_estimate * 1.2)
50
- )
51
-
52
- if needs_cleanup and self.auto_cleanup:
53
- logger.warning(f"Storage critically low ({usage_percent:.1f}%), performing automatic cleanup")
54
- self._perform_emergency_cleanup()
55
-
56
- # Re-check after cleanup
57
- total, used, free = shutil.disk_usage('/')
58
- free_gb = free / (1024**3)
59
- usage_percent = (used / total) * 100
60
-
61
- if usage_percent >= 98.0:
62
- raise InsufficientStorageError(
63
- f"Storage critically low even after cleanup: {usage_percent:.1f}% used, "
64
- f"only {free_gb:.1f}GB free",
65
- required_space=required_space_estimate or int(self.min_free_space_gb * 1024**3),
66
- available_space=free
67
- )
68
-
69
- return True
70
-
71
- except Exception as e:
72
- logger.error(f"Storage check failed: {e}")
73
- raise
74
-
75
- def _perform_emergency_cleanup(self) -> int:
76
- """
77
- Perform emergency storage cleanup.
78
-
79
- Returns:
80
- Bytes freed
81
- """
82
- total_freed = 0
83
-
84
- try:
85
- # 1. Clean up extracted frames for completed videos
86
- frames_freed = self._cleanup_completed_video_frames()
87
- total_freed += frames_freed
88
-
89
- # 2. Clean up upload cache older than 1 day
90
- uploads_freed = self._cleanup_old_uploads(max_age_hours=24)
91
- total_freed += uploads_freed
92
-
93
- # 3. Clean up large log files
94
- logs_freed = self._cleanup_large_logs()
95
- total_freed += logs_freed
96
-
97
- # 4. Clean up temporary files
98
- temp_freed = self._cleanup_temp_files()
99
- total_freed += temp_freed
100
-
101
- logger.info(f"Emergency cleanup completed: {total_freed / (1024**3):.2f}GB freed")
102
-
103
- except Exception as e:
104
- logger.error(f"Emergency cleanup failed: {e}")
105
-
106
- return total_freed
107
-
108
- def _cleanup_completed_video_frames(self) -> int:
109
- """Clean up frames for videos that have completed processing."""
110
- total_freed = 0
111
-
112
- try:
113
- from django.conf import settings
114
- frames_dir = Path(settings.BASE_DIR).parent / 'storage' / 'frames'
115
-
116
- if not frames_dir.exists():
117
- return 0
118
-
119
- # Find videos with completed anonymization
120
- completed_videos = VideoFile.objects.filter(
121
- anonymization_tasks__status='done'
122
- ).distinct()
123
-
124
- for video in completed_videos:
125
- # Find frame directories for this video
126
- video_frame_dirs = list(frames_dir.glob(f"*{video.uuid}*"))
127
-
128
- for frame_dir in video_frame_dirs:
129
- if frame_dir.is_dir():
130
- try:
131
- # Calculate directory size
132
- dir_size = sum(
133
- f.stat().st_size for f in frame_dir.rglob('*') if f.is_file()
134
- )
135
-
136
- # Remove the directory
137
- shutil.rmtree(frame_dir, ignore_errors=True)
138
- total_freed += dir_size
139
-
140
- logger.info(f"Cleaned frames for {video.uuid}: {dir_size / (1024**2):.1f}MB")
141
-
142
- except Exception as e:
143
- logger.warning(f"Failed to clean frames for {video.uuid}: {e}")
144
-
145
- except Exception as e:
146
- logger.error(f"Frame cleanup failed: {e}")
147
-
148
- return total_freed
149
-
150
- def _cleanup_old_uploads(self, max_age_hours: int = 24) -> int:
151
- """Clean up old upload cache files."""
152
- total_freed = 0
153
-
154
- try:
155
- from django.conf import settings
156
- uploads_dir = Path(settings.BASE_DIR).parent / 'storage' / 'uploads'
157
-
158
- if not uploads_dir.exists():
159
- return 0
160
-
161
- cutoff_time = datetime.now().timestamp() - (max_age_hours * 3600)
162
-
163
- for file_path in uploads_dir.rglob('*'):
164
- if file_path.is_file():
165
- try:
166
- if file_path.stat().st_mtime < cutoff_time:
167
- file_size = file_path.stat().st_size
168
- file_path.unlink()
169
- total_freed += file_size
170
-
171
- except Exception as e:
172
- logger.warning(f"Failed to clean upload file {file_path}: {e}")
173
-
174
- except Exception as e:
175
- logger.error(f"Upload cleanup failed: {e}")
176
-
177
- return total_freed
178
-
179
- def _cleanup_large_logs(self, max_size_mb: int = 50) -> int:
180
- """Clean up large log files by truncating them."""
181
- total_freed = 0
182
-
183
- try:
184
- from django.conf import settings
185
- project_root = Path(settings.BASE_DIR).parent
186
- max_size_bytes = max_size_mb * 1024 * 1024
187
-
188
- for log_file in project_root.rglob('*.log'):
189
- try:
190
- if log_file.stat().st_size > max_size_bytes:
191
- original_size = log_file.stat().st_size
192
-
193
- # Truncate the log file
194
- with open(log_file, 'w') as f:
195
- f.write(f"# Log truncated at {datetime.now()} due to size limit\n")
196
-
197
- total_freed += original_size
198
- logger.info(f"Truncated log {log_file}: {original_size / (1024**2):.1f}MB")
199
-
200
- except Exception as e:
201
- logger.warning(f"Failed to truncate log {log_file}: {e}")
202
-
203
- except Exception as e:
204
- logger.error(f"Log cleanup failed: {e}")
205
-
206
- return total_freed
207
-
208
- def _cleanup_temp_files(self) -> int:
209
- """Clean up temporary files."""
210
- total_freed = 0
211
-
212
- try:
213
- temp_patterns = [
214
- '/tmp/tmp*',
215
- '/tmp/temp*',
216
- '/tmp/django*',
217
- '/tmp/ffmpeg*',
218
- ]
219
-
220
- for pattern in temp_patterns:
221
- import glob
222
- for temp_file in glob.glob(pattern):
223
- try:
224
- temp_path = Path(temp_file)
225
- if temp_path.is_file():
226
- file_size = temp_path.stat().st_size
227
- temp_path.unlink()
228
- total_freed += file_size
229
-
230
- except Exception as e:
231
- logger.warning(f"Failed to clean temp file {temp_file}: {e}")
232
-
233
- except Exception as e:
234
- logger.error(f"Temp file cleanup failed: {e}")
235
-
236
- return total_freed
237
-
238
- def process_video_with_storage_management(
239
- self,
240
- video_file: VideoFile,
241
- cleanup_frames_after: bool = True,
242
- progress_callback: Optional[callable] = None
243
- ) -> bool:
244
- """
245
- Process a video with automatic storage management.
246
-
247
- Args:
248
- video_file: VideoFile instance to process
249
- cleanup_frames_after: Whether to clean up frames after processing
250
- progress_callback: Optional progress callback function
251
-
252
- Returns:
253
- True if processing succeeded, False otherwise
254
- """
255
- try:
256
- # Estimate required space (rough calculation)
257
- video_size = 0
258
- if video_file.raw_file and hasattr(video_file.raw_file, 'size'):
259
- video_size = video_file.raw_file.size
260
-
261
- # Estimate: frames ~= 3x video size, processing ~= 2x video size
262
- estimated_space_needed = video_size * 5
263
-
264
- # Check storage before starting
265
- self.check_and_ensure_storage(estimated_space_needed)
266
-
267
- # Update task status
268
- task = self._get_or_create_task(video_file)
269
- task.start_processing()
270
-
271
- if progress_callback:
272
- progress_callback(10, "Starting video processing...")
273
-
274
- # Run the actual video processing pipeline
275
- success = video_file.pipe_1(
276
- model_name="image_multilabel_classification_colonoscopy_default",
277
- delete_frames_after=cleanup_frames_after
278
- )
279
-
280
- if success:
281
- if progress_callback:
282
- progress_callback(90, "Processing completed, cleaning up...")
283
-
284
- # Mark as completed
285
- task.mark_completed("Video processing completed successfully")
286
-
287
- # Additional cleanup if requested
288
- if cleanup_frames_after:
289
- self._cleanup_video_frames(video_file)
290
-
291
- if progress_callback:
292
- progress_callback(100, "Processing completed successfully")
293
-
294
- logger.info(f"Video processing completed successfully: {video_file.uuid}")
295
- return True
296
-
297
- task.mark_failed("Video processing pipeline failed")
298
- logger.error(f"Video processing failed: {video_file.uuid}")
299
- return False
300
-
301
- except InsufficientStorageError as e:
302
- logger.error(f"Storage error during video processing: {e}")
303
- task = self._get_or_create_task(video_file)
304
- task.mark_failed(f"Insufficient storage: {e}")
305
- return False
306
-
307
- except Exception as e:
308
- logger.error(f"Video processing failed: {e}")
309
- task = self._get_or_create_task(video_file)
310
- task.mark_failed(f"Processing error: {e}")
311
- return False
312
-
313
- def _get_or_create_task(self, video_file: VideoFile) -> AnonymizationTask:
314
- """Get or create an anonymization task for the video."""
315
- task, created = AnonymizationTask.objects.get_or_create(
316
- video_file=video_file,
317
- defaults={
318
- 'status': 'not_started',
319
- 'progress': 0,
320
- 'message': 'Initializing...'
321
- }
322
- )
323
- return task
324
-
325
- def _cleanup_video_frames(self, video_file: VideoFile):
326
- """Clean up frames for a specific video."""
327
- try:
328
- from django.conf import settings
329
- frames_dir = Path(settings.BASE_DIR).parent / 'storage' / 'frames'
330
-
331
- # Find frame directories for this video
332
- video_frame_dirs = list(frames_dir.glob(f"*{video_file.uuid}*"))
333
-
334
- for frame_dir in video_frame_dirs:
335
- if frame_dir.is_dir():
336
- shutil.rmtree(frame_dir, ignore_errors=True)
337
- logger.info(f"Cleaned up frames for video {video_file.uuid}")
338
-
339
- except Exception as e:
340
- logger.warning(f"Failed to clean up frames for {video_file.uuid}: {e}")
341
-
342
-
343
- # Global instance for easy access
344
- storage_aware_processor = StorageAwareVideoProcessor()
endoreg_db/urls/files.py DELETED
@@ -1,6 +0,0 @@
1
- from django.urls import path
2
- from endoreg_db.views import AvailableFilesListView
3
-
4
- urlpatterns = [
5
- path('available-files/', AvailableFilesListView.as_view(), name='available_files_list'),
6
- ]
@@ -1,33 +0,0 @@
1
- from django.urls import path
2
-
3
- from endoreg_db.views.label_video_segment.validate import (
4
- LabelVideoSegmentValidateView,
5
- BulkSegmentValidateView,
6
- VideoSegmentValidationCompleteView
7
- )
8
-
9
- url_patterns = [
10
- # Einzelne Segment-Validierung
11
- # POST /api/label-video-segment/<int:segment_id>/validate/
12
- path(
13
- 'label-video-segment/<int:segment_id>/validate/',
14
- LabelVideoSegmentValidateView.as_view(),
15
- name='label_video_segment_validate'
16
- ),
17
-
18
- # Bulk-Validierung mehrerer Segmente
19
- # POST /api/label-video-segments/validate-bulk/
20
- path(
21
- 'label-video-segments/validate-bulk/',
22
- BulkSegmentValidateView.as_view(),
23
- name='label_video_segments_validate_bulk'
24
- ),
25
-
26
- # Alle Segmente eines Videos als validiert markieren
27
- # POST /api/videos/<int:video_id>/segments/validate-complete/
28
- path(
29
- 'videos/<int:video_id>/segments/validate-complete/',
30
- VideoSegmentValidationCompleteView.as_view(),
31
- name='video_segments_validate_complete'
32
- ),
33
- ]
@@ -1,46 +0,0 @@
1
- from django.urls import path
2
- from endoreg_db.views import (
3
- create_video_segment_annotation,
4
- update_label_video_segment,
5
- SensitiveMetaDetailView,
6
- video_segments_view,
7
- video_segment_detail_view,
8
- get_lvs_by_name_and_video_id
9
- )
10
-
11
-
12
-
13
- url_patterns = [
14
- path(
15
- "lvs/by-label-name/<str:label_name>/by-video-id/<int:video_id>/",
16
- get_lvs_by_name_and_video_id,
17
- name='get_lvs_by_name_and_video_id'
18
- ),
19
- path(
20
- 'annotations/',
21
- create_video_segment_annotation,
22
- name='create_annotation'
23
- ),
24
- path(
25
- 'annotations/<int:annotation_id>/',
26
- update_label_video_segment,
27
- name='update_annotation'
28
- ),
29
- path(
30
- 'save-anonymization-annotation-video/<int:annotation_id>/',
31
- SensitiveMetaDetailView.as_view(),
32
- name='save_anonymization_annotation_video'
33
- ),
34
- # Label Video Segment API endpoints
35
- path(
36
- 'video-segments/',
37
- video_segments_view,
38
- name='video_segments'
39
- ),
40
- path(
41
- 'video-segments/<int:segment_id>/',
42
- video_segment_detail_view,
43
- name='video_segment_detail'
44
- ),
45
-
46
- ]