endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of endoreg-db might be problematic. Click here for more details.

Files changed (450) hide show
  1. endoreg_db/admin.py +10 -5
  2. endoreg_db/apps.py +4 -7
  3. endoreg_db/authz/auth.py +1 -0
  4. endoreg_db/authz/backends.py +1 -1
  5. endoreg_db/authz/management/commands/list_routes.py +2 -0
  6. endoreg_db/authz/middleware.py +8 -7
  7. endoreg_db/authz/permissions.py +21 -10
  8. endoreg_db/authz/policy.py +14 -19
  9. endoreg_db/authz/views_auth.py +14 -10
  10. endoreg_db/codemods/rename_datetime_fields.py +8 -1
  11. endoreg_db/exceptions.py +5 -2
  12. endoreg_db/forms/__init__.py +0 -1
  13. endoreg_db/forms/examination_form.py +4 -3
  14. endoreg_db/forms/patient_finding_intervention_form.py +30 -8
  15. endoreg_db/forms/patient_form.py +9 -13
  16. endoreg_db/forms/questionnaires/__init__.py +1 -1
  17. endoreg_db/forms/settings/__init__.py +4 -1
  18. endoreg_db/forms/unit.py +2 -1
  19. endoreg_db/helpers/count_db.py +17 -14
  20. endoreg_db/helpers/default_objects.py +2 -1
  21. endoreg_db/helpers/download_segmentation_model.py +4 -3
  22. endoreg_db/helpers/interact.py +0 -5
  23. endoreg_db/helpers/test_video_helper.py +33 -25
  24. endoreg_db/import_files/__init__.py +1 -1
  25. endoreg_db/import_files/context/__init__.py +1 -1
  26. endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
  27. endoreg_db/import_files/context/ensure_center.py +4 -4
  28. endoreg_db/import_files/context/file_lock.py +3 -3
  29. endoreg_db/import_files/context/import_context.py +11 -12
  30. endoreg_db/import_files/context/validate_directories.py +1 -0
  31. endoreg_db/import_files/file_storage/create_report_file.py +57 -34
  32. endoreg_db/import_files/file_storage/create_video_file.py +64 -35
  33. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
  34. endoreg_db/import_files/file_storage/state_management.py +89 -122
  35. endoreg_db/import_files/file_storage/storage.py +5 -1
  36. endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
  37. endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
  38. endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
  39. endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
  40. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
  41. endoreg_db/import_files/report_import_service.py +36 -30
  42. endoreg_db/import_files/video_import_service.py +27 -23
  43. endoreg_db/logger_conf.py +56 -40
  44. endoreg_db/management/__init__.py +1 -1
  45. endoreg_db/management/commands/__init__.py +1 -1
  46. endoreg_db/management/commands/check_auth.py +45 -38
  47. endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
  48. endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
  49. endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
  50. endoreg_db/management/commands/fix_video_paths.py +75 -54
  51. endoreg_db/management/commands/import_report.py +1 -3
  52. endoreg_db/management/commands/list_routes.py +2 -0
  53. endoreg_db/management/commands/load_ai_model_data.py +8 -2
  54. endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
  55. endoreg_db/management/commands/load_center_data.py +3 -3
  56. endoreg_db/management/commands/load_distribution_data.py +35 -38
  57. endoreg_db/management/commands/load_endoscope_data.py +0 -3
  58. endoreg_db/management/commands/load_examination_data.py +20 -4
  59. endoreg_db/management/commands/load_finding_data.py +18 -3
  60. endoreg_db/management/commands/load_gender_data.py +17 -24
  61. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
  62. endoreg_db/management/commands/load_information_source.py +0 -3
  63. endoreg_db/management/commands/load_lab_value_data.py +14 -3
  64. endoreg_db/management/commands/load_legacy_data.py +303 -0
  65. endoreg_db/management/commands/load_name_data.py +1 -2
  66. endoreg_db/management/commands/load_pdf_type_data.py +4 -8
  67. endoreg_db/management/commands/load_profession_data.py +0 -1
  68. endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
  69. endoreg_db/management/commands/load_requirement_data.py +6 -2
  70. endoreg_db/management/commands/load_unit_data.py +0 -4
  71. endoreg_db/management/commands/load_user_groups.py +5 -7
  72. endoreg_db/management/commands/model_input.py +169 -0
  73. endoreg_db/management/commands/register_ai_model.py +22 -16
  74. endoreg_db/management/commands/setup_endoreg_db.py +110 -32
  75. endoreg_db/management/commands/storage_management.py +14 -8
  76. endoreg_db/management/commands/summarize_db_content.py +154 -63
  77. endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
  78. endoreg_db/management/commands/validate_video_files.py +82 -50
  79. endoreg_db/management/commands/video_validation.py +4 -6
  80. endoreg_db/migrations/0001_initial.py +112 -63
  81. endoreg_db/models/__init__.py +8 -0
  82. endoreg_db/models/administration/ai/active_model.py +5 -5
  83. endoreg_db/models/administration/ai/ai_model.py +41 -18
  84. endoreg_db/models/administration/ai/model_type.py +1 -0
  85. endoreg_db/models/administration/case/case.py +22 -22
  86. endoreg_db/models/administration/center/__init__.py +5 -5
  87. endoreg_db/models/administration/center/center.py +6 -2
  88. endoreg_db/models/administration/center/center_resource.py +18 -4
  89. endoreg_db/models/administration/center/center_shift.py +3 -1
  90. endoreg_db/models/administration/center/center_waste.py +6 -2
  91. endoreg_db/models/administration/person/__init__.py +1 -1
  92. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  94. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  95. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  96. endoreg_db/models/administration/person/names/first_name.py +6 -4
  97. endoreg_db/models/administration/person/names/last_name.py +4 -3
  98. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  99. endoreg_db/models/administration/person/patient/patient.py +0 -1
  100. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  101. endoreg_db/models/administration/person/person.py +1 -1
  102. endoreg_db/models/administration/product/__init__.py +7 -6
  103. endoreg_db/models/administration/product/product.py +6 -2
  104. endoreg_db/models/administration/product/product_group.py +9 -7
  105. endoreg_db/models/administration/product/product_material.py +9 -2
  106. endoreg_db/models/administration/product/reference_product.py +64 -15
  107. endoreg_db/models/administration/qualification/qualification.py +3 -1
  108. endoreg_db/models/administration/shift/shift.py +3 -1
  109. endoreg_db/models/administration/shift/shift_type.py +12 -4
  110. endoreg_db/models/aidataset/__init__.py +5 -0
  111. endoreg_db/models/aidataset/aidataset.py +193 -0
  112. endoreg_db/models/label/__init__.py +1 -1
  113. endoreg_db/models/label/label.py +10 -2
  114. endoreg_db/models/label/label_set.py +3 -1
  115. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  116. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  117. endoreg_db/models/media/__init__.py +12 -5
  118. endoreg_db/models/media/frame/__init__.py +1 -1
  119. endoreg_db/models/media/frame/frame.py +34 -8
  120. endoreg_db/models/media/pdf/__init__.py +2 -1
  121. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  122. endoreg_db/models/media/pdf/report_file.py +6 -2
  123. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  124. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  125. endoreg_db/models/media/video/create_from_file.py +20 -41
  126. endoreg_db/models/media/video/pipe_1.py +75 -30
  127. endoreg_db/models/media/video/pipe_2.py +37 -12
  128. endoreg_db/models/media/video/video_file.py +36 -24
  129. endoreg_db/models/media/video/video_file_ai.py +235 -70
  130. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  131. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  132. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  133. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  134. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  135. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  136. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  140. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  141. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  142. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  143. endoreg_db/models/media/video/video_file_io.py +85 -33
  144. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  145. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  146. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  147. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  148. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  149. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  150. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  151. endoreg_db/models/media/video/video_file_segments.py +118 -27
  152. endoreg_db/models/media/video/video_metadata.py +25 -6
  153. endoreg_db/models/media/video/video_processing.py +54 -15
  154. endoreg_db/models/medical/__init__.py +3 -13
  155. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  156. endoreg_db/models/medical/disease.py +18 -6
  157. endoreg_db/models/medical/event.py +6 -2
  158. endoreg_db/models/medical/examination/__init__.py +5 -1
  159. endoreg_db/models/medical/examination/examination.py +22 -6
  160. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  161. endoreg_db/models/medical/examination/examination_time.py +6 -2
  162. endoreg_db/models/medical/finding/__init__.py +3 -1
  163. endoreg_db/models/medical/finding/finding.py +37 -12
  164. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  165. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  166. endoreg_db/models/medical/finding/finding_type.py +3 -1
  167. endoreg_db/models/medical/hardware/__init__.py +1 -1
  168. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  169. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  170. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  171. endoreg_db/models/medical/medication/__init__.py +7 -3
  172. endoreg_db/models/medical/medication/medication.py +3 -1
  173. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  175. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  176. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  177. endoreg_db/models/medical/patient/__init__.py +2 -10
  178. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  179. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  180. endoreg_db/models/medical/patient/patient_event.py +12 -4
  181. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  182. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  183. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  184. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  185. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  186. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  187. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  188. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  189. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  190. endoreg_db/models/metadata/model_meta.py +40 -12
  191. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  192. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  193. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  194. endoreg_db/models/metadata/video_meta.py +146 -39
  195. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  196. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  197. endoreg_db/models/operation_log.py +63 -0
  198. endoreg_db/models/other/__init__.py +10 -10
  199. endoreg_db/models/other/distribution/__init__.py +9 -7
  200. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  201. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  202. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  203. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  204. endoreg_db/models/other/emission/__init__.py +1 -1
  205. endoreg_db/models/other/emission/emission_factor.py +9 -3
  206. endoreg_db/models/other/information_source.py +15 -5
  207. endoreg_db/models/other/material.py +3 -1
  208. endoreg_db/models/other/transport_route.py +3 -1
  209. endoreg_db/models/other/unit.py +6 -2
  210. endoreg_db/models/report/report.py +0 -1
  211. endoreg_db/models/requirement/requirement.py +84 -27
  212. endoreg_db/models/requirement/requirement_error.py +5 -6
  213. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  214. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  215. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  216. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  217. endoreg_db/models/requirement/requirement_operator.py +28 -8
  218. endoreg_db/models/requirement/requirement_set.py +34 -11
  219. endoreg_db/models/state/__init__.py +1 -0
  220. endoreg_db/models/state/audit_ledger.py +9 -2
  221. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  222. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  223. endoreg_db/models/state/raw_pdf.py +0 -1
  224. endoreg_db/models/state/video.py +2 -4
  225. endoreg_db/models/utils.py +4 -2
  226. endoreg_db/queries/__init__.py +2 -6
  227. endoreg_db/queries/annotations/__init__.py +1 -3
  228. endoreg_db/queries/annotations/legacy.py +37 -26
  229. endoreg_db/root_urls.py +3 -4
  230. endoreg_db/schemas/examination_evaluation.py +3 -0
  231. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  232. endoreg_db/serializers/__init__.py +2 -8
  233. endoreg_db/serializers/administration/__init__.py +1 -2
  234. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  235. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  236. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  237. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  238. endoreg_db/serializers/administration/center.py +7 -2
  239. endoreg_db/serializers/administration/gender.py +4 -2
  240. endoreg_db/serializers/anonymization.py +13 -13
  241. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  242. endoreg_db/serializers/examination/__init__.py +1 -1
  243. endoreg_db/serializers/examination/base.py +12 -13
  244. endoreg_db/serializers/examination/dropdown.py +6 -7
  245. endoreg_db/serializers/examination_serializer.py +3 -6
  246. endoreg_db/serializers/finding/__init__.py +1 -1
  247. endoreg_db/serializers/finding/finding.py +14 -7
  248. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  249. endoreg_db/serializers/finding_classification/choice.py +3 -3
  250. endoreg_db/serializers/finding_classification/classification.py +2 -4
  251. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  252. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  253. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  254. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  255. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  256. endoreg_db/serializers/meta/__init__.py +1 -2
  257. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  258. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  259. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  260. endoreg_db/serializers/misc/__init__.py +2 -2
  261. endoreg_db/serializers/misc/file_overview.py +11 -7
  262. endoreg_db/serializers/misc/stats.py +10 -8
  263. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  264. endoreg_db/serializers/misc/upload_job.py +32 -29
  265. endoreg_db/serializers/patient/__init__.py +2 -1
  266. endoreg_db/serializers/patient/patient.py +32 -15
  267. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  268. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  269. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  270. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  271. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  272. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  273. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  274. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  275. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  276. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  277. endoreg_db/serializers/pdf/__init__.py +1 -3
  278. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  279. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  280. endoreg_db/serializers/video/__init__.py +2 -2
  281. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  282. endoreg_db/serializers/video/video_file_brief.py +6 -2
  283. endoreg_db/serializers/video/video_file_detail.py +36 -23
  284. endoreg_db/serializers/video/video_file_list.py +4 -2
  285. endoreg_db/serializers/video/video_processing_history.py +54 -50
  286. endoreg_db/services/__init__.py +1 -1
  287. endoreg_db/services/anonymization.py +2 -2
  288. endoreg_db/services/examination_evaluation.py +40 -17
  289. endoreg_db/services/model_meta_from_hf.py +76 -0
  290. endoreg_db/services/polling_coordinator.py +101 -70
  291. endoreg_db/services/pseudonym_service.py +27 -22
  292. endoreg_db/services/report_import.py +6 -3
  293. endoreg_db/services/segment_sync.py +75 -59
  294. endoreg_db/services/video_import.py +6 -7
  295. endoreg_db/urls/__init__.py +2 -2
  296. endoreg_db/urls/ai.py +7 -25
  297. endoreg_db/urls/anonymization.py +61 -15
  298. endoreg_db/urls/auth.py +4 -4
  299. endoreg_db/urls/classification.py +4 -9
  300. endoreg_db/urls/examination.py +27 -18
  301. endoreg_db/urls/media.py +27 -34
  302. endoreg_db/urls/patient.py +11 -7
  303. endoreg_db/urls/requirements.py +3 -1
  304. endoreg_db/urls/root_urls.py +2 -3
  305. endoreg_db/urls/stats.py +24 -16
  306. endoreg_db/urls/upload.py +3 -11
  307. endoreg_db/utils/__init__.py +14 -15
  308. endoreg_db/utils/ai/__init__.py +1 -1
  309. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  310. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  311. endoreg_db/utils/ai/get.py +2 -1
  312. endoreg_db/utils/ai/inference_dataset.py +14 -15
  313. endoreg_db/utils/ai/model_training/config.py +117 -0
  314. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  315. endoreg_db/utils/ai/model_training/losses.py +68 -0
  316. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  317. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  318. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  319. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  320. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  321. endoreg_db/utils/ai/predict.py +4 -4
  322. endoreg_db/utils/ai/preprocess.py +19 -11
  323. endoreg_db/utils/calc_duration_seconds.py +4 -4
  324. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  325. endoreg_db/utils/check_video_files.py +74 -47
  326. endoreg_db/utils/cropping.py +10 -9
  327. endoreg_db/utils/dataloader.py +11 -3
  328. endoreg_db/utils/dates.py +3 -4
  329. endoreg_db/utils/defaults/set_default_center.py +7 -6
  330. endoreg_db/utils/env.py +6 -2
  331. endoreg_db/utils/extract_specific_frames.py +24 -9
  332. endoreg_db/utils/file_operations.py +30 -18
  333. endoreg_db/utils/fix_video_path_direct.py +57 -41
  334. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  335. endoreg_db/utils/hashs.py +3 -18
  336. endoreg_db/utils/links/requirement_link.py +96 -52
  337. endoreg_db/utils/ocr.py +30 -25
  338. endoreg_db/utils/operation_log.py +61 -0
  339. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  340. endoreg_db/utils/paths.py +6 -6
  341. endoreg_db/utils/permissions.py +40 -24
  342. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  343. endoreg_db/utils/product/sum_emissions.py +5 -3
  344. endoreg_db/utils/product/sum_weights.py +4 -2
  345. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  346. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  347. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  348. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  349. endoreg_db/utils/setup_config.py +21 -5
  350. endoreg_db/utils/storage.py +3 -1
  351. endoreg_db/utils/translation.py +19 -15
  352. endoreg_db/utils/uuid.py +1 -0
  353. endoreg_db/utils/validate_endo_roi.py +12 -4
  354. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  355. endoreg_db/utils/validate_video_detailed.py +207 -149
  356. endoreg_db/utils/video/__init__.py +7 -3
  357. endoreg_db/utils/video/extract_frames.py +30 -18
  358. endoreg_db/utils/video/names.py +11 -6
  359. endoreg_db/utils/video/streaming_processor.py +175 -101
  360. endoreg_db/utils/video/video_splitter.py +30 -19
  361. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  362. endoreg_db/views/__init__.py +0 -20
  363. endoreg_db/views/anonymization/__init__.py +6 -2
  364. endoreg_db/views/anonymization/media_management.py +2 -6
  365. endoreg_db/views/anonymization/overview.py +34 -1
  366. endoreg_db/views/anonymization/validate.py +79 -18
  367. endoreg_db/views/auth/__init__.py +1 -1
  368. endoreg_db/views/auth/keycloak.py +16 -14
  369. endoreg_db/views/examination/__init__.py +12 -15
  370. endoreg_db/views/examination/examination.py +5 -5
  371. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  372. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  373. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  374. endoreg_db/views/examination/get_findings.py +8 -10
  375. endoreg_db/views/examination/get_instruments.py +3 -2
  376. endoreg_db/views/examination/get_interventions.py +1 -1
  377. endoreg_db/views/finding/__init__.py +2 -2
  378. endoreg_db/views/finding/finding.py +58 -54
  379. endoreg_db/views/finding/get_classifications.py +1 -1
  380. endoreg_db/views/finding/get_interventions.py +1 -1
  381. endoreg_db/views/finding_classification/__init__.py +5 -5
  382. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  383. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  384. endoreg_db/views/media/__init__.py +13 -13
  385. endoreg_db/views/media/pdf_media.py +9 -9
  386. endoreg_db/views/media/sensitive_metadata.py +10 -7
  387. endoreg_db/views/media/video_media.py +4 -4
  388. endoreg_db/views/meta/__init__.py +1 -1
  389. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  390. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  391. endoreg_db/views/misc/__init__.py +6 -34
  392. endoreg_db/views/misc/center.py +2 -1
  393. endoreg_db/views/misc/csrf.py +2 -1
  394. endoreg_db/views/misc/gender.py +2 -1
  395. endoreg_db/views/misc/stats.py +141 -106
  396. endoreg_db/views/patient/__init__.py +1 -3
  397. endoreg_db/views/patient/patient.py +141 -99
  398. endoreg_db/views/patient_examination/__init__.py +5 -5
  399. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  400. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  401. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  402. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  403. endoreg_db/views/patient_examination/video.py +114 -80
  404. endoreg_db/views/patient_finding/__init__.py +1 -1
  405. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  406. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  407. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  408. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  409. endoreg_db/views/report/reimport.py +1 -1
  410. endoreg_db/views/report/report_stream.py +5 -8
  411. endoreg_db/views/requirement/__init__.py +2 -1
  412. endoreg_db/views/requirement/evaluate.py +7 -9
  413. endoreg_db/views/requirement/lookup.py +2 -3
  414. endoreg_db/views/requirement/lookup_store.py +0 -1
  415. endoreg_db/views/requirement/requirement_utils.py +2 -4
  416. endoreg_db/views/stats/__init__.py +4 -4
  417. endoreg_db/views/stats/stats_views.py +152 -115
  418. endoreg_db/views/video/__init__.py +18 -27
  419. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  420. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  421. endoreg_db/views/video/correction.py +5 -6
  422. endoreg_db/views/video/reimport.py +134 -99
  423. endoreg_db/views/video/segments_crud.py +134 -44
  424. endoreg_db/views/video/video_apply_mask.py +13 -12
  425. endoreg_db/views/video/video_correction.py +2 -1
  426. endoreg_db/views/video/video_download_processed.py +15 -15
  427. endoreg_db/views/video/video_meta_stats.py +7 -6
  428. endoreg_db/views/video/video_processing_history.py +3 -2
  429. endoreg_db/views/video/video_remove_frames.py +13 -12
  430. endoreg_db/views/video/video_stream.py +110 -82
  431. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  432. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
  433. endoreg_db/management/commands/import_fallback_video.py +0 -203
  434. endoreg_db/management/commands/import_video.py +0 -422
  435. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  436. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  437. endoreg_db/serializers/label/__init__.py +0 -7
  438. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  439. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  440. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  441. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  442. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  443. endoreg_db/services/__old/pdf_import.py +0 -1487
  444. endoreg_db/services/__old/video_import.py +0 -1306
  445. endoreg_db/tasks/upload_tasks.py +0 -216
  446. endoreg_db/tasks/video_ingest.py +0 -161
  447. endoreg_db/tasks/video_processing_tasks.py +0 -327
  448. endoreg_db/views/misc/translation.py +0 -182
  449. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  450. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,9 @@ import logging
2
2
  from typing import TYPE_CHECKING
3
3
 
4
4
  from endoreg_db.models.media.video.video_file_io import _get_frame_dir_path
5
- from endoreg_db.utils.video.ffmpeg_wrapper import extract_frames as ffmpeg_extract_frames
5
+ from endoreg_db.utils.video.ffmpeg_wrapper import (
6
+ extract_frames as ffmpeg_extract_frames,
7
+ )
6
8
 
7
9
  if TYPE_CHECKING:
8
10
  from endoreg_db.models import VideoFile
@@ -48,19 +50,27 @@ def _extract_frames(
48
50
  if from_processed:
49
51
  raw_file_path = video.get_processed_file_path()
50
52
  if not raw_file_path or not raw_file_path.exists():
51
- raise FileNotFoundError(f"Processed video file not found at {raw_file_path} for video {video.uuid}. Cannot extract frames.")
53
+ raise FileNotFoundError(
54
+ f"Processed video file not found at {raw_file_path} for video {video.video_hash}. Cannot extract frames."
55
+ )
52
56
  else:
53
57
  # Pre-validation checks (outside any transaction)
54
58
  if not video.has_raw:
55
- raise FileNotFoundError(f"Raw video file not available for {video.uuid}. Cannot extract frames.")
59
+ raise FileNotFoundError(
60
+ f"Raw video file not available for {video.video_hash}. Cannot extract frames."
61
+ )
56
62
 
57
63
  raw_file_path = video.get_raw_file_path()
58
64
  if not raw_file_path or not raw_file_path.exists():
59
- raise FileNotFoundError(f"Raw video file not found at {raw_file_path} for video {video.uuid}. Cannot extract frames.")
65
+ raise FileNotFoundError(
66
+ f"Raw video file not found at {raw_file_path} for video {video.video_hash}. Cannot extract frames."
67
+ )
60
68
 
61
69
  frame_dir = _get_frame_dir_path(video)
62
70
  if not frame_dir:
63
- raise ValueError(f"Cannot determine frame directory path for video {video.uuid}.")
71
+ raise ValueError(
72
+ f"Cannot determine frame directory path for video {video.video_hash}."
73
+ )
64
74
 
65
75
  state = video.get_or_create_state()
66
76
  frames_exist_in_db = Frame.objects.filter(video=video).exists()
@@ -70,59 +80,83 @@ def _extract_frames(
70
80
  if (state.frames_extracted or files_exist_on_disk) and not overwrite:
71
81
  logger.info(
72
82
  "Frames already extracted or files exist for video %s, and overwrite=False. Skipping extraction.",
73
- video.uuid,
83
+ video.video_hash,
74
84
  )
75
85
  with transaction.atomic():
76
86
  state.refresh_from_db()
77
87
  if frames_exist_in_db:
78
- updated_count = Frame.objects.filter(video=video, is_extracted=False).update(is_extracted=True)
88
+ updated_count = Frame.objects.filter(
89
+ video=video, is_extracted=False
90
+ ).update(is_extracted=True)
79
91
  if updated_count > 0:
80
92
  logger.info(
81
93
  "Marked %d existing Frame objects as extracted for video %s based on current records.",
82
94
  updated_count,
83
- video.uuid,
95
+ video.video_hash,
84
96
  )
85
97
  if files_exist_on_disk and not state.frames_extracted:
86
98
  logger.warning(
87
99
  "Files exist on disk for video %s but state.frames_extracted is False. Persisting corrected state.",
88
- video.uuid,
100
+ video.video_hash,
89
101
  )
90
102
  state.mark_frames_extracted(save=True)
91
103
  return True
92
104
 
93
105
  # Overwrite: delete existing frames/files before re-extraction.
94
106
  if overwrite:
95
- logger.info("Overwrite=True. Preparing to delete existing frames/files for video %s before extraction.", video.uuid)
107
+ logger.info(
108
+ "Overwrite=True. Preparing to delete existing frames/files for video %s before extraction.",
109
+ video.video_hash,
110
+ )
96
111
  try:
97
112
  _delete_frames(video)
98
113
  with transaction.atomic():
99
- updated_count = Frame.objects.filter(video=video, is_extracted=True).update(is_extracted=False)
114
+ updated_count = Frame.objects.filter(
115
+ video=video, is_extracted=True
116
+ ).update(is_extracted=False)
100
117
  if updated_count > 0:
101
118
  logger.info(
102
119
  "Reset %d Frame objects to is_extracted=False for video %s due to overwrite.",
103
120
  updated_count,
104
- video.uuid,
121
+ video.video_hash,
105
122
  )
106
123
  state.refresh_from_db()
107
124
  except Exception as del_e:
108
- logger.error("Failed to delete existing frames for video %s during overwrite: %s", video.uuid, del_e, exc_info=True)
109
- raise RuntimeError(f"Failed to delete existing frames for video {video.uuid} during overwrite.") from del_e
125
+ logger.error(
126
+ "Failed to delete existing frames for video %s during overwrite: %s",
127
+ video.video_hash,
128
+ del_e,
129
+ exc_info=True,
130
+ )
131
+ raise RuntimeError(
132
+ f"Failed to delete existing frames for video {video.video_hash} during overwrite."
133
+ ) from del_e
110
134
 
111
135
  frame_dir.mkdir(parents=True, exist_ok=True)
112
136
 
113
137
  try:
114
- logger.info("Starting frame extraction for video %s to %s", video.uuid, frame_dir)
138
+ logger.info(
139
+ "Starting frame extraction for video %s to %s", video.video_hash, frame_dir
140
+ )
115
141
  # Step 1: Perform the long-running frame extraction outside any transaction.
116
- extracted_paths = ffmpeg_extract_frames(raw_file_path, frame_dir, quality=quality, ext=ext)
142
+ extracted_paths = ffmpeg_extract_frames(
143
+ raw_file_path, frame_dir, quality=quality, ext=ext
144
+ )
117
145
  if not extracted_paths:
118
146
  logger.warning(
119
147
  "ffmpeg_extract_frames returned no paths for video %s. Check video duration and ffmpeg logs.",
120
- video.uuid,
148
+ video.video_hash,
121
149
  )
122
150
  if video.frame_count is not None and video.frame_count > 0:
123
- raise RuntimeError(f"ffmpeg_extract_frames returned no paths for video {video.uuid}, but {video.frame_count} frames were expected.")
151
+ raise RuntimeError(
152
+ f"ffmpeg_extract_frames returned no paths for video {video.video_hash}, but {video.frame_count} frames were expected."
153
+ )
124
154
 
125
- logger.info("Successfully extracted %d frames using ffmpeg for video %s.", len(extracted_paths), video.uuid)
155
+ logger.info(
156
+ "Successfully extracted %d frames using ffmpeg for video %s.",
157
+ len(extracted_paths),
158
+ video.video_hash,
159
+ )
126
160
 
127
161
  extracted_frame_numbers = []
128
162
  for frame_path in extracted_paths:
@@ -130,38 +164,70 @@ def _extract_frames(
130
164
  frame_number = int(frame_path.stem.split("_")[-1])
131
165
  extracted_frame_numbers.append(frame_number)
132
166
  except (ValueError, IndexError) as e:
133
- logger.warning("Could not parse frame number from extracted file %s: %s", frame_path.name, e)
167
+ logger.warning(
168
+ "Could not parse frame number from extracted file %s: %s",
169
+ frame_path.name,
170
+ e,
171
+ )
134
172
 
135
173
  # Step 2: Perform all the quick DB updates inside a minimal atomic transaction.
136
174
  with transaction.atomic():
137
175
  if extracted_frame_numbers:
138
176
  try:
139
- update_count = Frame.objects.filter(video=video, frame_number__in=extracted_frame_numbers).update(is_extracted=True)
140
- logger.info("Marked %d Frame objects as is_extracted=True for video %s.", update_count, video.uuid)
177
+ update_count = Frame.objects.filter(
178
+ video=video, frame_number__in=extracted_frame_numbers
179
+ ).update(is_extracted=True)
180
+ logger.info(
181
+ "Marked %d Frame objects as is_extracted=True for video %s.",
182
+ update_count,
183
+ video.video_hash,
184
+ )
141
185
  if update_count != len(extracted_frame_numbers):
142
186
  logger.warning(
143
187
  "Number of updated frames (%d) does not match number of parsed extracted files (%d) for video %s.",
144
188
  update_count,
145
189
  len(extracted_frame_numbers),
146
- video.uuid,
190
+ video.video_hash,
147
191
  )
148
192
  except Exception as update_e:
149
- logger.error("Failed to update is_extracted flag for frames of video %s: %s", video.uuid, update_e, exc_info=True)
193
+ logger.error(
194
+ "Failed to update is_extracted flag for frames of video %s: %s",
195
+ video.video_hash,
196
+ update_e,
197
+ exc_info=True,
198
+ )
150
199
  state.refresh_from_db()
151
200
  state.mark_frames_extracted()
152
201
  return True
153
202
 
154
203
  except Exception as e:
155
- logger.error("Frame extraction or update failed for video %s: %s", video.uuid, e, exc_info=True)
156
- logger.warning("Cleaning up frame directory %s for video %s due to extraction error.", frame_dir, video.uuid)
204
+ logger.error(
205
+ "Frame extraction or update failed for video %s: %s",
206
+ video.video_hash,
207
+ e,
208
+ exc_info=True,
209
+ )
210
+ logger.warning(
211
+ "Cleaning up frame directory %s for video %s due to extraction error.",
212
+ frame_dir,
213
+ video.video_hash,
214
+ )
157
215
  shutil.rmtree(frame_dir, ignore_errors=True)
158
216
  try:
159
217
  with transaction.atomic():
160
- Frame.objects.filter(video=video, is_extracted=True).update(is_extracted=False)
218
+ Frame.objects.filter(video=video, is_extracted=True).update(
219
+ is_extracted=False
220
+ )
161
221
  state.refresh_from_db()
162
222
  if state.frames_extracted:
163
223
  state.frames_extracted = False
164
224
  state.save(update_fields=["frames_extracted"])
165
225
  except Exception as db_err:
166
- logger.error("Failed to reset flags/state in DB during error handling for video %s: %s", video.uuid, db_err)
167
- raise RuntimeError(f"Frame extraction or update failed for video {video.uuid}.") from e
226
+ logger.error(
227
+ "Failed to reset flags/state in DB during error handling for video %s: %s",
228
+ video.video_hash,
229
+ db_err,
230
+ )
231
+ raise RuntimeError(
232
+ f"Frame extraction or update failed for video {video.video_hash}."
233
+ ) from e
@@ -15,12 +15,22 @@ def _get_frame(video: "VideoFile", frame_number: int) -> "Frame":
15
15
  # Access related manager directly
16
16
  return video.frames.get(frame_number=frame_number)
17
17
  except AttributeError:
18
- logger.error("Could not access frame %d for video %s via related manager.", frame_number, video.uuid)
18
+ logger.error(
19
+ "Could not access frame %d for video %s via related manager.",
20
+ frame_number,
21
+ video.video_hash,
22
+ )
19
23
  # Fallback query
20
24
  return Frame.objects.get(video_file=video, frame_number=frame_number)
21
25
  except Frame.DoesNotExist:
22
- logger.error("Frame %d not found for video %s.", frame_number, video.uuid)
26
+ logger.error("Frame %d not found for video %s.", frame_number, video.video_hash)
23
27
  raise # Re-raise DoesNotExist
24
28
  except Exception as e:
25
- logger.error("Error getting frame %d for video %s: %s", frame_number, video.uuid, e, exc_info=True)
29
+ logger.error(
30
+ "Error getting frame %d for video %s: %s",
31
+ frame_number,
32
+ video.video_hash,
33
+ e,
34
+ exc_info=True,
35
+ )
26
36
  raise # Re-raise other exceptions
@@ -13,7 +13,10 @@ def _get_frame_path(video: "VideoFile", frame_number: int) -> Optional[Path]:
13
13
  """Constructs the expected path for a given frame number."""
14
14
  target_dir = video.get_frame_dir_path() # Use IO helper
15
15
  if not target_dir:
16
- logger.warning("Cannot get frame path for video %s: Frame directory not set.", video.uuid)
16
+ logger.warning(
17
+ "Cannot get frame path for video %s: Frame directory not set.",
18
+ video.video_hash,
19
+ )
17
20
  return None
18
21
 
19
22
  frame_filename = f"frame_{frame_number:07d}.jpg"
@@ -14,7 +14,11 @@ def _get_frame_paths(video: "VideoFile") -> List[Path]:
14
14
  """Returns a sorted list of Path objects for extracted frame image files."""
15
15
  frame_dir = _get_frame_dir_path(video)
16
16
  if not frame_dir or not frame_dir.exists():
17
- logger.warning("Frame directory %s does not exist for video %s.", frame_dir, video.uuid)
17
+ logger.warning(
18
+ "Frame directory %s does not exist for video %s.",
19
+ frame_dir,
20
+ video.video_hash,
21
+ )
18
22
  return []
19
23
 
20
24
  frame_paths = list(frame_dir.glob("frame_*.jpg"))
@@ -22,7 +26,15 @@ def _get_frame_paths(video: "VideoFile") -> List[Path]:
22
26
  try:
23
27
  frame_paths.sort(key=lambda p: int(p.stem.split("_")[-1]))
24
28
  except (ValueError, IndexError) as e:
25
- logger.error("Error sorting frame paths in %s: %s. Found paths: %s", frame_dir, e, [p.name for p in frame_paths], exc_info=True)
26
- logger.warning("Falling back to unsorted frame paths to preserve available data.")
29
+ logger.error(
30
+ "Error sorting frame paths in %s: %s. Found paths: %s",
31
+ frame_dir,
32
+ e,
33
+ [p.name for p in frame_paths],
34
+ exc_info=True,
35
+ )
36
+ logger.warning(
37
+ "Falling back to unsorted frame paths to preserve available data."
38
+ )
27
39
  return frame_paths
28
40
  return frame_paths
@@ -9,7 +9,9 @@ if TYPE_CHECKING:
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
11
 
12
- def _get_frame_range(video: "VideoFile", start_frame_number: int, end_frame_number: int) -> "QuerySet[Frame]":
12
+ def _get_frame_range(
13
+ video: "VideoFile", start_frame_number: int, end_frame_number: int
14
+ ) -> "QuerySet[Frame]":
13
15
  """Gets a QuerySet of Frame objects within a specific range, ordered by frame number."""
14
16
  from endoreg_db.models import Frame
15
17
 
@@ -20,7 +22,10 @@ def _get_frame_range(video: "VideoFile", start_frame_number: int, end_frame_numb
20
22
  frame_number__lte=end_frame_number,
21
23
  ).order_by("frame_number")
22
24
  except AttributeError:
23
- logger.error("Could not access frame range for video %s via related manager.", video.uuid)
25
+ logger.error(
26
+ "Could not access frame range for video %s via related manager.",
27
+ video.video_hash,
28
+ )
24
29
  # Fallback query
25
30
  return Frame.objects.filter(
26
31
  video_file=video,
@@ -28,5 +33,12 @@ def _get_frame_range(video: "VideoFile", start_frame_number: int, end_frame_numb
28
33
  frame_number__lte=end_frame_number,
29
34
  ).order_by("frame_number")
30
35
  except Exception as e:
31
- logger.error("Error getting frame range (%d-%d) for video %s: %s", start_frame_number, end_frame_number, video.uuid, e, exc_info=True)
36
+ logger.error(
37
+ "Error getting frame range (%d-%d) for video %s: %s",
38
+ start_frame_number,
39
+ end_frame_number,
40
+ video.video_hash,
41
+ e,
42
+ exc_info=True,
43
+ )
32
44
  return Frame.objects.none() # Return empty queryset on error
@@ -17,9 +17,14 @@ def _get_frames(video: "VideoFile") -> "QuerySet[Frame]":
17
17
  # Access related manager directly
18
18
  return video.frames.order_by("frame_number")
19
19
  except AttributeError:
20
- logger.error("Could not access frames for video %s. 'frames' related manager not found.", video.uuid)
20
+ logger.error(
21
+ "Could not access frames for video %s. 'frames' related manager not found.",
22
+ video.video_hash,
23
+ )
21
24
  # Fallback query
22
25
  return Frame.objects.filter(video_file=video).order_by("frame_number")
23
26
  except Exception as e:
24
- logger.error("Error getting frames for video %s: %s", video.uuid, e, exc_info=True)
27
+ logger.error(
28
+ "Error getting frames for video %s: %s", video.video_hash, e, exc_info=True
29
+ )
25
30
  return Frame.objects.none() # Return empty queryset on error
@@ -32,29 +32,54 @@ def _initialize_frames(video: "VideoFile", frame_paths: Optional[List[Path]] = N
32
32
  - On Failure: Does not change state (error is raised).
33
33
  """
34
34
  from endoreg_db.models import Frame
35
- from endoreg_db.models.media.video.video_file_frames._bulk_create_frames import _bulk_create_frames
36
- from endoreg_db.models.media.video.video_file_frames._create_frame_object import _create_frame_object
35
+ from endoreg_db.models.media.video.video_file_frames._bulk_create_frames import (
36
+ _bulk_create_frames,
37
+ )
38
+ from endoreg_db.models.media.video.video_file_frames._create_frame_object import (
39
+ _create_frame_object,
40
+ )
37
41
 
38
42
  frames_to_create = []
39
43
  num_expected_or_provided = 0
40
44
  mark_as_extracted = False
41
45
 
42
46
  if frame_paths:
43
- logger.info("Initializing Frame objects based on %d provided paths for video %s.", len(frame_paths), video.uuid)
47
+ logger.info(
48
+ "Initializing Frame objects based on %d provided paths for video %s.",
49
+ len(frame_paths),
50
+ video.video_hash,
51
+ )
44
52
  mark_as_extracted = True
45
53
  num_expected_or_provided = len(frame_paths)
46
- for frame_path in tqdm(frame_paths, desc=f"Initializing Frames from Paths {video.uuid}", unit="frame"):
54
+ for frame_path in tqdm(
55
+ frame_paths,
56
+ desc=f"Initializing Frames from Paths {video.video_hash}",
57
+ unit="frame",
58
+ ):
47
59
  try:
48
60
  frame_number = int(frame_path.stem.split("_")[-1])
49
61
  relative_path_str = frame_path.name
50
- frames_to_create.append(_create_frame_object(video, frame_number, relative_path_str, extracted=mark_as_extracted))
62
+ frames_to_create.append(
63
+ _create_frame_object(
64
+ video,
65
+ frame_number,
66
+ relative_path_str,
67
+ extracted=mark_as_extracted,
68
+ )
69
+ )
51
70
  except (ValueError, IndexError) as e:
52
- logger.warning("Could not parse frame number from %s: %s", frame_path.name, e)
71
+ logger.warning(
72
+ "Could not parse frame number from %s: %s", frame_path.name, e
73
+ )
53
74
  continue
54
75
  else:
55
76
  expected_frame_count = video.frame_count
56
77
  if expected_frame_count is None or expected_frame_count <= 0:
57
- logger.warning("Cannot initialize frames for video %s: Frame count is %s.", video.uuid, expected_frame_count)
78
+ logger.warning(
79
+ "Cannot initialize frames for video %s: Frame count is %s.",
80
+ video.video_hash,
81
+ expected_frame_count,
82
+ )
58
83
  try:
59
84
  state = video.get_or_create_state()
60
85
  if state.frames_initialized or state.frame_count is not None:
@@ -62,53 +87,109 @@ def _initialize_frames(video: "VideoFile", frame_paths: Optional[List[Path]] = N
62
87
  state.frame_count = None
63
88
  state.save(update_fields=["frames_initialized", "frame_count"])
64
89
  except Exception as state_e:
65
- logger.error("Failed to reset state during empty initialization for video %s: %s", video.uuid, state_e, exc_info=True)
90
+ logger.error(
91
+ "Failed to reset state during empty initialization for video %s: %s",
92
+ video.video_hash,
93
+ state_e,
94
+ exc_info=True,
95
+ )
66
96
  return
67
97
 
68
- logger.info("Initializing %d expected Frame objects for video %s (is_extracted=False).", expected_frame_count, video.uuid)
98
+ logger.info(
99
+ "Initializing %d expected Frame objects for video %s (is_extracted=False).",
100
+ expected_frame_count,
101
+ video.video_hash,
102
+ )
69
103
  mark_as_extracted = False
70
104
  num_expected_or_provided = expected_frame_count
71
- for frame_number in tqdm(range(expected_frame_count), desc=f"Initializing Expected Frames {video.uuid}", unit="frame"):
105
+ for frame_number in tqdm(
106
+ range(expected_frame_count),
107
+ desc=f"Initializing Expected Frames {video.video_hash}",
108
+ unit="frame",
109
+ ):
72
110
  relative_path_str = f"frame_{frame_number:07d}.jpg"
73
- frames_to_create.append(_create_frame_object(video, frame_number, relative_path_str, extracted=mark_as_extracted))
111
+ frames_to_create.append(
112
+ _create_frame_object(
113
+ video, frame_number, relative_path_str, extracted=mark_as_extracted
114
+ )
115
+ )
74
116
 
75
117
  if frames_to_create:
76
118
  for attempt in range(5):
77
119
  try:
78
120
  _bulk_create_frames(video, frames_to_create)
79
121
  num_created_or_ignored = len(frames_to_create)
80
- logger.info("Bulk create attempted for %d Frame objects for video %s (ignore_conflicts=True).", num_created_or_ignored, video.uuid)
122
+ logger.info(
123
+ "Bulk create attempted for %d Frame objects for video %s (ignore_conflicts=True).",
124
+ num_created_or_ignored,
125
+ video.video_hash,
126
+ )
81
127
 
82
128
  if mark_as_extracted:
83
129
  frame_numbers_to_update = [f.frame_number for f in frames_to_create]
84
130
  if frame_numbers_to_update:
85
- update_count = Frame.objects.filter(video=video, frame_number__in=frame_numbers_to_update, is_extracted=False).update(is_extracted=True)
131
+ update_count = Frame.objects.filter(
132
+ video=video,
133
+ frame_number__in=frame_numbers_to_update,
134
+ is_extracted=False,
135
+ ).update(is_extracted=True)
86
136
  if update_count > 0:
87
- logger.info("Marked %d existing Frame objects as is_extracted=True for video %s.", update_count, video.uuid)
137
+ logger.info(
138
+ "Marked %d existing Frame objects as is_extracted=True for video %s.",
139
+ update_count,
140
+ video.video_hash,
141
+ )
88
142
 
89
143
  try:
90
144
  state = video.get_or_create_state()
91
145
  state.frames_initialized = True
92
146
  state.frame_count = num_expected_or_provided
93
147
  state.save(update_fields=["frames_initialized", "frame_count"])
94
- logger.info("Set frames_initialized=True and frame_count=%d for video %s.", num_expected_or_provided, video.uuid)
148
+ logger.info(
149
+ "Set frames_initialized=True and frame_count=%d for video %s.",
150
+ num_expected_or_provided,
151
+ video.video_hash,
152
+ )
95
153
  except Exception as state_e:
96
- logger.error("Failed to update state after frame initialization for video %s: %s", video.uuid, state_e, exc_info=True)
97
- raise RuntimeError(f"Failed to update state after frame initialization for video {video.uuid}") from state_e
154
+ logger.error(
155
+ "Failed to update state after frame initialization for video %s: %s",
156
+ video.video_hash,
157
+ state_e,
158
+ exc_info=True,
159
+ )
160
+ raise RuntimeError(
161
+ f"Failed to update state after frame initialization for video {video.video_hash}"
162
+ ) from state_e
98
163
 
99
164
  except OperationalError as e:
100
165
  if "database is locked" in str(e):
101
- logger.warning("Database is locked, retrying frame initialization for video %s (attempt %d/5).", video.uuid, attempt + 1)
166
+ logger.warning(
167
+ "Database is locked, retrying frame initialization for video %s (attempt %d/5).",
168
+ video.video_hash,
169
+ attempt + 1,
170
+ )
102
171
  time.sleep(2**attempt)
103
172
  if attempt < 4:
104
173
  continue
105
174
  else:
106
- raise RuntimeError(f"Failed to initialize frames for video {video.uuid}.") from e
107
- logger.error("Error initializing frames for video %s: %s", video.uuid, e, exc_info=True)
108
- raise RuntimeError(f"Failed to initialize frames for video {video.uuid}.") from e
175
+ raise RuntimeError(
176
+ f"Failed to initialize frames for video {video.video_hash}."
177
+ ) from e
178
+ logger.error(
179
+ "Error initializing frames for video %s: %s",
180
+ video.video_hash,
181
+ e,
182
+ exc_info=True,
183
+ )
184
+ raise RuntimeError(
185
+ f"Failed to initialize frames for video {video.video_hash}."
186
+ ) from e
109
187
 
110
188
  else:
111
- logger.warning("No valid frames found/generated to initialize for video %s.", video.uuid)
189
+ logger.warning(
190
+ "No valid frames found/generated to initialize for video %s.",
191
+ video.video_hash,
192
+ )
112
193
  try:
113
194
  state = video.get_or_create_state()
114
195
  if state.frames_initialized or state.frame_count is not None:
@@ -116,4 +197,9 @@ def _initialize_frames(video: "VideoFile", frame_paths: Optional[List[Path]] = N
116
197
  state.frame_count = None
117
198
  state.save(update_fields=["frames_initialized", "frame_count"])
118
199
  except Exception as state_e:
119
- logger.error("Failed to reset state during empty initialization for video %s: %s", video.uuid, state_e, exc_info=True)
200
+ logger.error(
201
+ "Failed to reset state during empty initialization for video %s: %s",
202
+ video.video_hash,
203
+ state_e,
204
+ exc_info=True,
205
+ )