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
@@ -1,17 +1,23 @@
1
1
  from pathlib import Path
2
+
2
3
  from rest_framework import serializers
3
- from ...models import VideoFile
4
+
5
+ from ...models import VideoFile
6
+
4
7
  try:
5
8
  import cv2
6
9
  except ImportError:
7
10
  cv2 = None
8
- from django.conf import settings
9
11
  # from django.conf import settings
10
12
  from typing import TYPE_CHECKING
13
+
14
+ from django.conf import settings
11
15
  from rest_framework.exceptions import ValidationError
16
+
12
17
  if TYPE_CHECKING:
13
18
  from endoreg_db.models import VideoFile
14
-
19
+
20
+
15
21
  class VideoFileSerializer(serializers.ModelSerializer):
16
22
  """
17
23
  Serializer that dynamically handles video retrieval and streaming.
@@ -55,24 +61,24 @@ class VideoFileSerializer(serializers.ModelSerializer):
55
61
 
56
62
  # @staticmethod #using @staticmethod makes it reusable without needing to create a serializer instance.
57
63
  # Without @staticmethod, you would need to instantiate the serializer before calling the method, which is unnecessary her
58
- def get_video_selection_field(self, obj:"Video"):
64
+ def get_video_selection_field(self, obj: "VideoFile"):
59
65
  """
60
66
  Return the UUID of the video for use as a selection value in frontend dropdowns.
61
-
67
+
62
68
  Parameters:
63
69
  obj (Video): The video instance being serialized.
64
-
70
+
65
71
  Returns:
66
72
  str: The UUID of the video.
67
73
  """
68
- return obj.uuid
74
+ return obj.video_hash
69
75
 
70
76
  def get_video_url(
71
77
  self, obj
72
78
  ): # when we serialize a RawVideoFile object (video metadata), the get_video_url method is automatically invoked by DRF
73
79
  """
74
80
  Return the absolute API URL for accessing the video file.
75
-
81
+
76
82
  If the video ID is invalid or the request context is missing, returns a dictionary with an error message.
77
83
  """
78
84
  if not obj.id:
@@ -82,14 +88,16 @@ class VideoFileSerializer(serializers.ModelSerializer):
82
88
  "request"
83
89
  ) # Gets the request object (provided by DRF).
84
90
  if request:
85
- return request.build_absolute_uri(f"/api/video/{obj.id}/") # Added api/ prefix
91
+ return request.build_absolute_uri(
92
+ f"/api/video/{obj.id}/"
93
+ ) # Added api/ prefix
86
94
 
87
95
  return {"error": "Video URL not available"}
88
96
 
89
- def get_duration(self, obj:"Video"):
97
+ def get_duration(self, obj: "VideoFile"):
90
98
  """
91
99
  Return the duration of the video in seconds, using the stored value if available or extracting it dynamically with OpenCV.
92
-
100
+
93
101
  If the duration is not present in the database, the method opens the video file, retrieves its frame count and frames per second (FPS), and calculates the duration. Returns `None` if the video cannot be opened or FPS is zero.
94
102
  """
95
103
  if hasattr(obj, "duration") and obj.duration:
@@ -99,7 +107,7 @@ class VideoFileSerializer(serializers.ModelSerializer):
99
107
 
100
108
  # Dynamically extract duration if not stored
101
109
  video_path = obj.active_file.path
102
-
110
+
103
111
  cap = cv2.VideoCapture(video_path)
104
112
  try:
105
113
  if not cap.isOpened():
@@ -114,13 +122,13 @@ class VideoFileSerializer(serializers.ModelSerializer):
114
122
  finally:
115
123
  cap.release()
116
124
 
117
- def get_file(self, obj:"Video"):
125
+ def get_file(self, obj: "VideoFile"):
118
126
  """
119
127
  Returns the relative file path of the active video file, or an error message if the file is missing or invalid.
120
-
128
+
121
129
  Parameters:
122
130
  obj (Video): The video instance whose file path is to be retrieved.
123
-
131
+
124
132
  Returns:
125
133
  str or dict: The relative file path as a string, or a dictionary with an error message if the file is missing or invalid.
126
134
  """
@@ -134,10 +142,10 @@ class VideoFileSerializer(serializers.ModelSerializer):
134
142
  obj.active_file.name
135
143
  ).strip() # Only return the file path, no URL,#obj.active_file returning a FieldFile object instead of a string
136
144
 
137
- def get_full_video_path(self, obj:"Video"):
145
+ def get_full_video_path(self, obj: "VideoFile"):
138
146
  """
139
147
  Return the absolute filesystem path to the video's active file.
140
-
148
+
141
149
  If the file does not exist or an error occurs during path construction, returns a dictionary with an error message.
142
150
  """
143
151
  if not obj.active_file:
@@ -145,26 +153,34 @@ class VideoFileSerializer(serializers.ModelSerializer):
145
153
 
146
154
  try:
147
155
  # Use the active_file_path property which handles both processed and raw files
148
- if hasattr(obj, 'active_file_path') and obj.active_file_path:
156
+ if hasattr(obj, "active_file_path") and obj.active_file_path:
149
157
  full_path = obj.active_file_path
150
- return str(full_path) if full_path.exists() else {"error": f"file not found at: {full_path}"}
158
+ return (
159
+ str(full_path)
160
+ if full_path.exists()
161
+ else {"error": f"file not found at: {full_path}"}
162
+ )
151
163
  else:
152
164
  # Fallback: construct path manually
153
165
  video_relative_path = str(obj.active_file.name).strip()
154
166
  if not video_relative_path:
155
167
  return {"error": "Video file path is empty or invalid"}
156
-
168
+
157
169
  # Construct the path using the file's actual path
158
170
  full_path = obj.active_file.path
159
- return str(full_path) if Path(full_path).exists() else {"error": f"file not found at: {full_path}"}
160
-
171
+ return (
172
+ str(full_path)
173
+ if Path(full_path).exists()
174
+ else {"error": f"file not found at: {full_path}"}
175
+ )
176
+
161
177
  except Exception as e:
162
178
  return {"error": f"Error constructing file path: {str(e)}"}
163
179
 
164
- def get_sequences(self, obj:"Video"):
180
+ def get_sequences(self, obj: "VideoFile"):
165
181
  """
166
182
  Retrieve frame sequences for each label from the video object.
167
-
183
+
168
184
  Returns:
169
185
  dict: A mapping of label names to lists of frame ranges, or an error message if no sequences are found.
170
186
  """
@@ -172,25 +188,25 @@ class VideoFileSerializer(serializers.ModelSerializer):
172
188
  "error": "no sequence found, check database first"
173
189
  } # Get from sequences, return {} if missing
174
190
 
175
- def get_label_names(self, obj:"Video"):
191
+ def get_label_names(self, obj: "VideoFile"):
176
192
  """
177
193
  Return a list of label names present in the video's frame sequences.
178
-
194
+
179
195
  Parameters:
180
196
  obj (Video): The video instance to extract label names from.
181
-
197
+
182
198
  Returns:
183
199
  list[str]: List of label names, or an empty list if no sequences are found.
184
200
  """
185
201
  sequences = self.get_sequences(obj)
186
202
  return list(sequences.keys()) if sequences else []
187
203
 
188
- def get_label_time_segments(self, obj:"Video"):
204
+ def get_label_time_segments(self, obj: "VideoFile"):
189
205
  """
190
206
  Convert frame sequences for each label into time segments with frame-level metadata.
191
-
207
+
192
208
  For each label in the video, this method generates a list of time segments based on frame index ranges, converting them to seconds using the video's FPS. Each segment includes the raw frame indices, start and end times in seconds, and detailed information for each frame in the segment, such as filename, full file path, and a placeholder for predictions.
193
-
209
+
194
210
  Returns:
195
211
  dict: A dictionary mapping each label to its list of time segments and associated frame metadata.
196
212
  """
@@ -201,13 +217,18 @@ class VideoFileSerializer(serializers.ModelSerializer):
201
217
 
202
218
  if not fps or fps <= 0:
203
219
  # Strict by default — only use fallback if explicitly enabled and > 0
204
- if getattr(settings, "VIDEO_ALLOW_FPS_FALLBACK", False) and getattr(settings, "VIDEO_DEFAULT_FPS", 0) > 0:
220
+ if (
221
+ getattr(settings, "VIDEO_ALLOW_FPS_FALLBACK", False)
222
+ and getattr(settings, "VIDEO_DEFAULT_FPS", 0) > 0
223
+ ):
205
224
  fps = settings.VIDEO_DEFAULT_FPS
206
225
  else:
207
- raise ValidationError({
208
- "label_time_segments": "FPS unavailable — cannot calculate time segments",
209
- "video_id": getattr(obj, "id", None),
210
- })
226
+ raise ValidationError(
227
+ {
228
+ "label_time_segments": "FPS unavailable — cannot calculate time segments",
229
+ "video_id": getattr(obj, "id", None),
230
+ }
231
+ )
211
232
 
212
233
  sequences = self.get_sequences(obj) # Fetch sequence data
213
234
  frame_dir = Path(obj.frame_dir) # Get the correct directory from the model
@@ -229,17 +250,16 @@ class VideoFileSerializer(serializers.ModelSerializer):
229
250
 
230
251
  # Fetch predictions for frames within this range
231
252
  for frame_num in range(start_frame, end_frame + 1):
232
-
233
- frame_filename = f"frame_{str(frame_num).zfill(7)}.jpg" # Frame filename format
234
- frame_path = (
235
- frame_dir / frame_filename
236
- ) # Full path to the frame
237
-
238
- frame_data[frame_num] = {
239
- "frame_filename": frame_filename,
240
- "frame_file_path": str(frame_path),
241
- "predictions": None,
242
- }
253
+ frame_filename = (
254
+ f"frame_{str(frame_num).zfill(7)}.jpg" # Frame filename format
255
+ )
256
+ frame_path = frame_dir / frame_filename # Full path to the frame
257
+
258
+ frame_data[frame_num] = {
259
+ "frame_filename": frame_filename,
260
+ "frame_file_path": str(frame_path),
261
+ "predictions": None,
262
+ }
243
263
 
244
264
  # Append the converted time segment
245
265
  label_times.append(
@@ -261,4 +281,3 @@ class VideoFileSerializer(serializers.ModelSerializer):
261
281
  }
262
282
 
263
283
  return time_segments
264
-
@@ -6,5 +6,9 @@ from rest_framework import serializers
6
6
 
7
7
  class VideoBriefSerializer(serializers.ModelSerializer):
8
8
  class Meta:
9
- model = VideoFile
10
- fields = ["id", "original_file_name", "sensitive_meta_id"] # for tables/overview
9
+ model = VideoFile
10
+ fields = [
11
+ "id",
12
+ "original_file_name",
13
+ "sensitive_meta_id",
14
+ ] # for tables/overview
@@ -6,23 +6,32 @@ from endoreg_db.models.media.video.video_file import VideoFile
6
6
  from endoreg_db.serializers.video.video_file_brief import VideoBriefSerializer
7
7
  from ...utils.calc_duration_seconds import _calc_duration_vf
8
8
 
9
+
9
10
  class VideoDetailSerializer(VideoBriefSerializer):
10
11
  # pull selected fields from SensitiveMeta (READ-ONLY) - using SerializerMethodField to handle datetime->date conversion
11
- patient_first_name = serializers.CharField(source="sensitive_meta.patient_first_name", read_only=True)
12
- patient_last_name = serializers.CharField(source="sensitive_meta.patient_last_name", read_only=True)
13
- patient_dob = serializers.SerializerMethodField()
14
- examination_date = serializers.SerializerMethodField()
12
+ patient_first_name = serializers.CharField(
13
+ source="sensitive_meta.patient_first_name", read_only=True
14
+ )
15
+ patient_last_name = serializers.CharField(
16
+ source="sensitive_meta.patient_last_name", read_only=True
17
+ )
18
+ patient_dob = serializers.SerializerMethodField()
19
+ examination_date = serializers.SerializerMethodField()
15
20
 
16
- file = serializers.SerializerMethodField()
17
- full_path = serializers.SerializerMethodField()
18
- duration = serializers.SerializerMethodField()
19
- video_url = serializers.SerializerMethodField()
21
+ file = serializers.SerializerMethodField()
22
+ full_path = serializers.SerializerMethodField()
23
+ duration = serializers.SerializerMethodField()
24
+ video_url = serializers.SerializerMethodField()
20
25
 
21
26
  class Meta(VideoBriefSerializer.Meta):
22
27
  fields = VideoBriefSerializer.Meta.fields + [
23
- "file", "full_path", "video_url",
24
- "patient_first_name", "patient_last_name",
25
- "patient_dob", "examination_date",
28
+ "file",
29
+ "full_path",
30
+ "video_url",
31
+ "patient_first_name",
32
+ "patient_last_name",
33
+ "patient_dob",
34
+ "examination_date",
26
35
  "duration",
27
36
  ]
28
37
 
@@ -38,46 +47,50 @@ class VideoDetailSerializer(VideoBriefSerializer):
38
47
  def get_video_url(self, obj):
39
48
  """
40
49
  Return the absolute URL for accessing the video streaming resource.
41
-
50
+
42
51
  Returns:
43
52
  str or None: The absolute URL to the video streaming endpoint if a request context is available; otherwise, None.
44
53
  """
45
54
  request = self.context.get("request")
46
55
  # Use video streaming endpoint (VideoStreamView)
47
- return request.build_absolute_uri(f"/api/media/videos/{obj.pk}/") if request else None
48
-
49
- def get_duration(self, obj:VideoFile):
56
+ return (
57
+ request.build_absolute_uri(f"/api/media/videos/{obj.pk}/")
58
+ if request
59
+ else None
60
+ )
61
+
62
+ def get_duration(self, obj: VideoFile):
50
63
  """
51
64
  Return the duration of the video, using the stored value if available or calculating it if not.
52
-
65
+
53
66
  Parameters:
54
67
  obj (VideoFile): The video file instance.
55
-
68
+
56
69
  Returns:
57
70
  float or None: Duration of the video in seconds, or None if unavailable.
58
71
  """
59
72
  return obj.duration or _calc_duration_vf(obj)
60
-
73
+
61
74
  def get_patient_dob(self, obj):
62
75
  """
63
76
  Returns the patient's date of birth as a date object if available, or None if not present.
64
-
77
+
65
78
  Extracts the date part from the patient's date of birth field in the sensitive metadata, handling both datetime and date types.
66
79
  """
67
80
  if obj.sensitive_meta and obj.sensitive_meta.patient_dob:
68
81
  # If it's a datetime, extract the date part
69
82
  dob = obj.sensitive_meta.patient_dob
70
- return dob.date() if hasattr(dob, 'date') else dob
83
+ return dob.date() if hasattr(dob, "date") else dob
71
84
  return None
72
-
85
+
73
86
  def get_examination_date(self, obj):
74
87
  """
75
88
  Returns the examination date as a date object from the sensitive metadata, or None if unavailable.
76
-
89
+
77
90
  If the examination date is a datetime, only the date part is returned.
78
91
  """
79
92
  if obj.sensitive_meta and obj.sensitive_meta.examination_date:
80
93
  # If it's a datetime, extract the date part
81
94
  exam_date = obj.sensitive_meta.examination_date
82
- return exam_date.date() if hasattr(exam_date, 'date') else exam_date
95
+ return exam_date.date() if hasattr(exam_date, "date") else exam_date
83
96
  return None
@@ -1,5 +1,5 @@
1
1
  # endoreg_db/serializers/video/video_file_list.py
2
- from typing import Literal, Optional
2
+ from typing import Literal
3
3
  import logging
4
4
 
5
5
  from rest_framework import serializers
@@ -38,7 +38,9 @@ class VideoFileListSerializer(serializers.ModelSerializer):
38
38
  """
39
39
  try:
40
40
  return getattr(obj, "state", None)
41
- except Exception as exc: # pragma: no cover - type of error is DB/backend-specific
41
+ except (
42
+ Exception
43
+ ) as exc: # pragma: no cover - type of error is DB/backend-specific
42
44
  logger.warning(
43
45
  "VideoFileListSerializer: unable to access state for VideoFile(id=%s): %s",
44
46
  getattr(obj, "id", "unknown"),
@@ -4,6 +4,7 @@ Video Processing History Serializer
4
4
  Serializes VideoProcessingHistory model for API responses.
5
5
  Created as part of Phase 1.1: Video Correction API Endpoints.
6
6
  """
7
+
7
8
  from collections.abc import Mapping
8
9
 
9
10
  from rest_framework import serializers
@@ -14,60 +15,61 @@ from endoreg_db.models import VideoProcessingHistory
14
15
  class VideoProcessingHistorySerializer(serializers.ModelSerializer):
15
16
  """
16
17
  Serializer for VideoProcessingHistory model.
17
-
18
+
18
19
  Provides operation audit trail (masking, frame removal, analysis)
19
20
  with download URLs for processed files.
20
21
  """
22
+
21
23
  download_url = serializers.SerializerMethodField()
22
24
  operation_display = serializers.SerializerMethodField()
23
25
  status_display = serializers.SerializerMethodField()
24
26
  duration = serializers.ReadOnlyField()
25
27
  is_complete = serializers.ReadOnlyField()
26
-
28
+
27
29
  class Meta:
28
30
  model = VideoProcessingHistory
29
31
  fields = [
30
- 'id',
31
- 'video',
32
- 'operation',
33
- 'operation_display',
34
- 'status',
35
- 'status_display',
36
- 'config',
37
- 'output_file',
38
- 'download_url',
39
- 'details',
40
- 'task_id',
41
- 'created_at',
42
- 'completed_at',
43
- 'duration',
44
- 'is_complete',
32
+ "id",
33
+ "video",
34
+ "operation",
35
+ "operation_display",
36
+ "status",
37
+ "status_display",
38
+ "config",
39
+ "output_file",
40
+ "download_url",
41
+ "details",
42
+ "task_id",
43
+ "created_at",
44
+ "completed_at",
45
+ "duration",
46
+ "is_complete",
45
47
  ]
46
- read_only_fields = ['id', 'created_at', 'completed_at']
47
-
48
+ read_only_fields = ["id", "created_at", "completed_at"]
49
+
48
50
  def get_download_url(self, obj) -> str | None:
49
51
  """
50
52
  Generate download URL for processed video file.
51
-
53
+
52
54
  Args:
53
55
  obj: VideoProcessingHistory instance
54
-
56
+
55
57
  Returns:
56
58
  str: URL to download processed file, or None if not available
57
59
  """
58
60
  if not obj.output_file or obj.status != VideoProcessingHistory.STATUS_SUCCESS:
59
61
  return None
60
-
62
+
61
63
  # Build URL to download endpoint (to be implemented)
62
64
  # Format: /api/media/processed-videos/{video_id}/{history_id}/
63
65
  context = self.context if isinstance(self.context, Mapping) else None
64
- request = context.get('request') if context else None
66
+ request = context.get("request") if context else None
65
67
  if request:
66
68
  return request.build_absolute_uri(
67
- f'/api/media/processed-videos/{obj.video.id}/{obj.id}/'
69
+ f"/api/media/processed-videos/{obj.video.id}/{obj.id}/"
68
70
  )
69
-
70
- return f'/api/media/processed-videos/{obj.video.id}/{obj.id}/'
71
+
72
+ return f"/api/media/processed-videos/{obj.video.id}/{obj.id}/"
71
73
 
72
74
  def get_operation_display(self, obj) -> str:
73
75
  display = getattr(obj, "get_operation_display", None)
@@ -78,37 +80,39 @@ class VideoProcessingHistorySerializer(serializers.ModelSerializer):
78
80
  display = getattr(obj, "get_status_display", None)
79
81
  result = display() if callable(display) else obj.status
80
82
  return str(result)
81
-
83
+
82
84
  def validate_operation(self, value):
83
85
  """
84
86
  Validate operation is one of the defined choices.
85
-
87
+
86
88
  Args:
87
89
  value: Operation type
88
-
90
+
89
91
  Returns:
90
92
  str: Validated operation
91
-
93
+
92
94
  Raises:
93
95
  ValidationError: If operation is invalid
94
96
  """
95
- valid_operations = [choice[0] for choice in VideoProcessingHistory.OPERATION_CHOICES]
97
+ valid_operations = [
98
+ choice[0] for choice in VideoProcessingHistory.OPERATION_CHOICES
99
+ ]
96
100
  if value not in valid_operations:
97
101
  raise serializers.ValidationError(
98
102
  f"Invalid operation. Must be one of: {', '.join(valid_operations)}"
99
103
  )
100
104
  return value
101
-
105
+
102
106
  def validate_status(self, value):
103
107
  """
104
108
  Validate status is one of the defined choices.
105
-
109
+
106
110
  Args:
107
111
  value: Status type
108
-
112
+
109
113
  Returns:
110
114
  str: Validated status
111
-
115
+
112
116
  Raises:
113
117
  ValidationError: If status is invalid
114
118
  """
@@ -118,17 +122,17 @@ class VideoProcessingHistorySerializer(serializers.ModelSerializer):
118
122
  f"Invalid status. Must be one of: {', '.join(valid_statuses)}"
119
123
  )
120
124
  return value
121
-
125
+
122
126
  def validate_config(self, value):
123
127
  """
124
128
  Validate config based on operation type.
125
-
129
+
126
130
  Args:
127
131
  value: Config dictionary
128
-
132
+
129
133
  Returns:
130
134
  dict: Validated config
131
-
135
+
132
136
  Raises:
133
137
  ValidationError: If config is invalid for operation
134
138
  """
@@ -136,33 +140,33 @@ class VideoProcessingHistorySerializer(serializers.ModelSerializer):
136
140
  raise serializers.ValidationError("config must be a dictionary")
137
141
 
138
142
  initial = self.initial_data if isinstance(self.initial_data, Mapping) else {}
139
- operation = initial.get('operation')
140
-
143
+ operation = initial.get("operation")
144
+
141
145
  # Validate masking config
142
146
  if operation == VideoProcessingHistory.OPERATION_MASKING:
143
- required_fields = ['mask_type']
144
- if 'mask_type' not in value:
147
+ required_fields = ["mask_type"]
148
+ if "mask_type" not in value:
145
149
  raise serializers.ValidationError(
146
150
  f"Masking config must include: {', '.join(required_fields)}"
147
151
  )
148
-
152
+
149
153
  # If device mask, require device_name
150
- if value['mask_type'] == 'device' and 'device_name' not in value:
154
+ if value["mask_type"] == "device" and "device_name" not in value:
151
155
  raise serializers.ValidationError(
152
156
  "Device mask requires 'device_name' in config"
153
157
  )
154
-
158
+
155
159
  # If custom ROI, require roi coordinates
156
- if value['mask_type'] == 'custom' and 'roi' not in value:
160
+ if value["mask_type"] == "custom" and "roi" not in value:
157
161
  raise serializers.ValidationError(
158
162
  "Custom mask requires 'roi' coordinates in config"
159
163
  )
160
-
164
+
161
165
  # Validate frame removal config
162
166
  elif operation == VideoProcessingHistory.OPERATION_FRAME_REMOVAL:
163
- if 'frame_list' not in value and 'detection_method' not in value:
167
+ if "frame_list" not in value and "detection_method" not in value:
164
168
  raise serializers.ValidationError(
165
169
  "Frame removal config must include 'frame_list' (manual) or 'detection_method' (automatic)"
166
170
  )
167
-
171
+
168
172
  return value
@@ -2,4 +2,4 @@
2
2
  Services package for endoreg_db.
3
3
 
4
4
  Contains business logic services that can be reused across different parts of the application.
5
- """
5
+ """
@@ -6,7 +6,7 @@ from typing import Optional
6
6
  from django.db import transaction
7
7
 
8
8
  from endoreg_db.models import RawPdfFile, VideoFile
9
- from endoreg_db.services.__old.video_import import VideoImportService
9
+ from endoreg_db.services.video_import import VideoImportService
10
10
  from endoreg_db.services.report_import import ReportImportService
11
11
  from endoreg_db.utils.paths import STORAGE_DIR
12
12
  from endoreg_db.utils.storage import ensure_local_file, file_exists
@@ -52,7 +52,7 @@ class AnonymizationService:
52
52
  if vf.state
53
53
  else "not_started",
54
54
  "fileExists": file_exists(vf.raw_file),
55
- "uuid": str(vf.uuid) if vf.uuid else None,
55
+ "uuid": str(vf.video_hash) if vf.video_hash else None,
56
56
  }
57
57
 
58
58
  pdf = (