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
@@ -4,6 +4,7 @@ from ...models import SensitiveMeta
4
4
 
5
5
  logger = logging.getLogger(__name__)
6
6
 
7
+
7
8
  class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
8
9
  """
9
10
  Serializer for displaying SensitiveMeta details with verification state.
@@ -17,7 +18,9 @@ class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
17
18
 
18
19
  # Related fields
19
20
  center_name = serializers.CharField(source="center.name", read_only=True)
20
- patient_gender_name = serializers.CharField(source="patient_gender.name", read_only=True)
21
+ patient_gender_name = serializers.CharField(
22
+ source="patient_gender.name", read_only=True
23
+ )
21
24
  examiners_display = serializers.SerializerMethodField()
22
25
 
23
26
  # Formatted display fields
@@ -57,7 +60,7 @@ class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
57
60
  "text",
58
61
  "anonymized_text",
59
62
  "external_id",
60
- "external_id_origin"
63
+ "external_id_origin",
61
64
  ]
62
65
  read_only_fields = [
63
66
  "id",
@@ -66,14 +69,23 @@ class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
66
69
  ]
67
70
 
68
71
  # --- Verification getters ---
69
- def get_is_verified(self, obj): return getattr(obj, "is_verified", False)
70
- def get_dob_verified(self, obj): return getattr(getattr(obj, "state", None), "dob_verified", False)
71
- def get_names_verified(self, obj): return getattr(getattr(obj, "state", None), "names_verified", False)
72
+ def get_is_verified(self, obj):
73
+ return getattr(obj, "is_verified", False)
74
+
75
+ def get_dob_verified(self, obj):
76
+ return getattr(getattr(obj, "state", None), "dob_verified", False)
77
+
78
+ def get_names_verified(self, obj):
79
+ return getattr(getattr(obj, "state", None), "names_verified", False)
72
80
 
73
81
  # --- Examiner display ---
74
82
  def get_examiners_display(self, obj):
75
83
  try:
76
- return [f"{e.first_name} {e.last_name}" for e in obj.examiners.all()] if obj.pk else []
84
+ return (
85
+ [f"{e.first_name} {e.last_name}" for e in obj.examiners.all()]
86
+ if obj.pk
87
+ else []
88
+ )
77
89
  except Exception as e:
78
90
  logger.warning(f"Error fetching examiners for SensitiveMeta {obj.pk}: {e}")
79
91
  return []
@@ -83,7 +95,9 @@ class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
83
95
  return obj.patient_dob.strftime("%Y-%m-%d") if obj.patient_dob else None
84
96
 
85
97
  def get_examination_date_display(self, obj):
86
- return obj.examination_date.strftime("%Y-%m-%d") if obj.examination_date else None
98
+ return (
99
+ obj.examination_date.strftime("%Y-%m-%d") if obj.examination_date else None
100
+ )
87
101
 
88
102
  # --- Hash short forms ---
89
103
  def get_patient_hash_display(self, obj):
@@ -98,10 +112,11 @@ class SensitiveMetaDetailSerializer(serializers.ModelSerializer):
98
112
 
99
113
  def get_anonymized_text(self, obj):
100
114
  return obj.anonymized_text if isinstance(obj.anonymized_text, str) else None
101
-
102
- def get_external_id(self, obj) -> str | None:
103
- return obj.external_id if isinstance(obj.external_id, str) else None
104
-
105
- def get_external_id_origin(self, obj) -> str | None:
106
- return obj.external_id_origin if isinstance(obj.external_id_origin, str) else None
107
115
 
116
+ def get_external_id(self, obj) -> str | None:
117
+ return obj.external_id if isinstance(obj.external_id, str) else None
118
+
119
+ def get_external_id_origin(self, obj) -> str | None:
120
+ return (
121
+ obj.external_id_origin if isinstance(obj.external_id_origin, str) else None
122
+ )
@@ -7,44 +7,43 @@ from ...models import SensitiveMeta, Center, Gender
7
7
  logger = logging.getLogger(__name__)
8
8
 
9
9
 
10
-
11
10
  class SensitiveMetaUpdateSerializer(serializers.ModelSerializer):
12
11
  """
13
12
  Serializer for updating SensitiveMeta fields including verification state.
14
13
  Handles partial updates and state management.
15
14
  """
16
-
15
+
17
16
  # Verification state fields
18
17
  dob_verified = serializers.BooleanField(required=False)
19
18
  names_verified = serializers.BooleanField(required=False)
20
-
19
+
21
20
  # Center can be updated by name
22
21
  center_name = serializers.CharField(write_only=True, required=False)
23
-
22
+
24
23
  # Gender can be updated by name
25
24
  patient_gender_name = serializers.CharField(write_only=True, required=False)
26
25
 
27
26
  class Meta:
28
27
  model = SensitiveMeta
29
28
  fields = [
30
- 'patient_first_name',
31
- 'patient_last_name',
32
- 'patient_dob',
33
- 'examination_date',
34
- 'center_name',
35
- 'patient_gender_name',
36
- 'endoscope_type',
37
- 'endoscope_sn',
38
- 'examiner_first_name',
39
- 'examiner_last_name',
40
- 'dob_verified',
41
- 'names_verified',
29
+ "patient_first_name",
30
+ "patient_last_name",
31
+ "patient_dob",
32
+ "examination_date",
33
+ "center_name",
34
+ "patient_gender_name",
35
+ "endoscope_type",
36
+ "endoscope_sn",
37
+ "examiner_first_name",
38
+ "examiner_last_name",
39
+ "dob_verified",
40
+ "names_verified",
42
41
  ]
43
42
 
44
43
  def validate_center_name(self, value):
45
44
  """
46
45
  Validates that a center with the given natural key exists.
47
-
46
+
48
47
  Raises a validation error if the specified center does not exist.
49
48
  """
50
49
  if value:
@@ -58,7 +57,7 @@ class SensitiveMetaUpdateSerializer(serializers.ModelSerializer):
58
57
  def validate_patient_gender_name(self, value):
59
58
  """
60
59
  Validates that a gender with the given name exists.
61
-
60
+
62
61
  Raises a validation error if no matching Gender is found.
63
62
  """
64
63
  if value:
@@ -72,21 +71,21 @@ class SensitiveMetaUpdateSerializer(serializers.ModelSerializer):
72
71
  def validate(self, data):
73
72
  """
74
73
  Validate that patient first and last names, if provided, are not empty strings.
75
-
74
+
76
75
  Raises a validation error if either `patient_first_name` or `patient_last_name` is present but empty.
77
76
  """
78
77
  # Ensure names are not empty if provided
79
- first_name = data.get('patient_first_name')
78
+ first_name = data.get("patient_first_name")
80
79
  if first_name is not None and not first_name.strip():
81
- raise serializers.ValidationError({
82
- 'patient_first_name': 'First name cannot be empty.'
83
- })
84
-
85
- last_name = data.get('patient_last_name')
80
+ raise serializers.ValidationError(
81
+ {"patient_first_name": "First name cannot be empty."}
82
+ )
83
+
84
+ last_name = data.get("patient_last_name")
86
85
  if last_name is not None and not last_name.strip():
87
- raise serializers.ValidationError({
88
- 'patient_last_name': 'Last name cannot be empty.'
89
- })
86
+ raise serializers.ValidationError(
87
+ {"patient_last_name": "Last name cannot be empty."}
88
+ )
90
89
 
91
90
  return data
92
91
 
@@ -94,55 +93,61 @@ class SensitiveMetaUpdateSerializer(serializers.ModelSerializer):
94
93
  def update(self, instance, validated_data):
95
94
  """
96
95
  Updates a SensitiveMeta instance with provided data, including related center, gender, and verification state fields.
97
-
96
+
98
97
  Handles assignment of related Center and Gender objects by name, updates model fields, and manages verification state flags (`dob_verified`, `names_verified`) in the associated state object if provided.
99
-
98
+
100
99
  Returns:
101
100
  SensitiveMeta: The updated SensitiveMeta instance.
102
101
  """
103
102
  # Extract verification state data
104
- dob_verified = validated_data.pop('dob_verified', None)
105
- names_verified = validated_data.pop('names_verified', None)
106
-
103
+ dob_verified = validated_data.pop("dob_verified", None)
104
+ names_verified = validated_data.pop("names_verified", None)
105
+
107
106
  # Extract and handle center update
108
- center_name = validated_data.pop('center_name', None)
107
+ center_name = validated_data.pop("center_name", None)
109
108
  if center_name:
110
109
  try:
111
110
  center = Center.objects.get_by_natural_key(center_name)
112
111
  instance.center = center
113
112
  except Center.DoesNotExist:
114
113
  logger.error(f"Center '{center_name}' not found during update")
115
- raise serializers.ValidationError(f"Center '{center_name}' does not exist.")
116
-
114
+ raise serializers.ValidationError(
115
+ f"Center '{center_name}' does not exist."
116
+ )
117
+
117
118
  # Extract and handle gender update
118
- patient_gender_name = validated_data.pop('patient_gender_name', None)
119
+ patient_gender_name = validated_data.pop("patient_gender_name", None)
119
120
  if patient_gender_name:
120
121
  try:
121
122
  gender = Gender.objects.get(name=patient_gender_name)
122
123
  instance.patient_gender = gender
123
124
  except Gender.DoesNotExist:
124
125
  logger.error(f"Gender '{patient_gender_name}' not found during update")
125
- raise serializers.ValidationError(f"Gender '{patient_gender_name}' does not exist.")
126
+ raise serializers.ValidationError(
127
+ f"Gender '{patient_gender_name}' does not exist."
128
+ )
126
129
 
127
130
  # Update regular fields using the model's update_from_dict method
128
131
  if validated_data:
129
132
  instance.update_from_dict(validated_data)
130
-
133
+
131
134
  # Update verification state if provided
132
135
  if dob_verified is not None or names_verified is not None:
133
136
  # Ensure state exists
134
137
  state = instance.get_or_create_state()
135
-
138
+
136
139
  if dob_verified is not None:
137
140
  state.dob_verified = dob_verified
138
- logger.info(f"Updated DOB verification for SensitiveMeta {instance.pk}: {dob_verified}")
139
-
141
+ logger.info(
142
+ f"Updated DOB verification for SensitiveMeta {instance.pk}: {dob_verified}"
143
+ )
144
+
140
145
  if names_verified is not None:
141
146
  state.names_verified = names_verified
142
- logger.info(f"Updated names verification for SensitiveMeta {instance.pk}: {names_verified}")
143
-
147
+ logger.info(
148
+ f"Updated names verification for SensitiveMeta {instance.pk}: {names_verified}"
149
+ )
150
+
144
151
  state.save()
145
152
 
146
153
  return instance
147
-
148
-
@@ -5,20 +5,21 @@ from ...models import SensitiveMeta
5
5
 
6
6
  logger = logging.getLogger(__name__)
7
7
 
8
+
8
9
  class SensitiveMetaVerificationSerializer(serializers.Serializer):
9
10
  """
10
11
  Simple serializer for bulk verification state updates.
11
12
  Used when only updating verification flags.
12
13
  """
13
-
14
+
14
15
  sensitive_meta_id = serializers.IntegerField()
15
16
  dob_verified = serializers.BooleanField(required=False)
16
17
  names_verified = serializers.BooleanField(required=False)
17
-
18
+
18
19
  def validate_sensitive_meta_id(self, value):
19
20
  """
20
21
  Validates that a SensitiveMeta object with the given ID exists and caches it.
21
-
22
+
22
23
  Raises:
23
24
  ValidationError: If no SensitiveMeta object is found with the specified ID.
24
25
  """
@@ -27,33 +28,35 @@ class SensitiveMetaVerificationSerializer(serializers.Serializer):
27
28
  self._cached_sensitive_meta = SensitiveMeta.objects.get(id=value)
28
29
  return value
29
30
  except SensitiveMeta.DoesNotExist:
30
- raise serializers.ValidationError(f"SensitiveMeta with ID {value} does not exist.")
31
+ raise serializers.ValidationError(
32
+ f"SensitiveMeta with ID {value} does not exist."
33
+ )
31
34
 
32
35
  def save(self):
33
36
  """
34
37
  Updates the verification state for a specified SensitiveMeta instance.
35
-
36
- Uses the cached SensitiveMeta object from validation, obtains or creates its verification state,
38
+
39
+ Uses the cached SensitiveMeta object from validation, obtains or creates its verification state,
37
40
  updates the `dob_verified` and `names_verified` fields if provided, and saves the changes.
38
-
41
+
39
42
  Returns:
40
43
  The updated verification state object.
41
44
  """
42
- sensitive_meta_id = self.validated_data['sensitive_meta_id']
43
- dob_verified = self.validated_data.get('dob_verified')
44
- names_verified = self.validated_data.get('names_verified')
45
-
45
+ sensitive_meta_id = self.validated_data["sensitive_meta_id"]
46
+ dob_verified = self.validated_data.get("dob_verified")
47
+ names_verified = self.validated_data.get("names_verified")
48
+
46
49
  # Use the cached instance from the validation step, avoiding a redundant query.
47
50
  sensitive_meta = self._cached_sensitive_meta
48
51
  state = sensitive_meta.get_or_create_state()
49
-
52
+
50
53
  if dob_verified is not None:
51
54
  state.dob_verified = dob_verified
52
-
55
+
53
56
  if names_verified is not None:
54
57
  state.names_verified = names_verified
55
-
58
+
56
59
  state.save()
57
-
60
+
58
61
  logger.info(f"Updated verification state for SensitiveMeta {sensitive_meta_id}")
59
- return state
62
+ return state
@@ -10,5 +10,5 @@ __all__ = [
10
10
  "StatsSerializer",
11
11
  "UploadJobStatusSerializer",
12
12
  "UploadCreateResponseSerializer",
13
- "TranslatableFieldMixin"
14
- ]
13
+ "TranslatableFieldMixin",
14
+ ]
@@ -3,8 +3,12 @@ from typing import TYPE_CHECKING
3
3
  from rest_framework import serializers
4
4
 
5
5
  from endoreg_db.models.media import RawPdfFile, VideoFile
6
- from endoreg_db.models.state.anonymization import AnonymizationState as PdfAnonymizationState
7
- from endoreg_db.models.state.anonymization import AnonymizationState as VideoAnonymizationState
6
+ from endoreg_db.models.state.anonymization import (
7
+ AnonymizationState as PdfAnonymizationState,
8
+ )
9
+ from endoreg_db.models.state.anonymization import (
10
+ AnonymizationState as VideoAnonymizationState,
11
+ )
8
12
 
9
13
  if TYPE_CHECKING:
10
14
  pass
@@ -41,8 +45,6 @@ class FileOverviewSerializer(serializers.Serializer):
41
45
  Raises:
42
46
  TypeError: If the instance is not a VideoFile or RawPdfFile.
43
47
  """
44
- text = ""
45
- anonym_text = ""
46
48
 
47
49
  if isinstance(instance, VideoFile):
48
50
  media_type = "video"
@@ -76,10 +78,12 @@ class FileOverviewSerializer(serializers.Serializer):
76
78
  rps.anonymization_status if rps else PdfAnonymizationState.NOT_STARTED
77
79
  )
78
80
 
79
- # ------- annotation status (not applicable for PDFs)
81
+ # ------- annotation status (not applicable for reports)
80
82
  annot_status = (
81
- PdfAnonymizationState.VALIDATED if rps.anonymization_validated else PdfAnonymizationState.NOT_STARTED
82
- )
83
+ PdfAnonymizationState.VALIDATED
84
+ if rps.anonymization_validated
85
+ else PdfAnonymizationState.NOT_STARTED
86
+ )
83
87
 
84
88
  else: # shouldn't happen
85
89
  raise TypeError(f"Unsupported instance for overview: {type(instance)}")
@@ -1,12 +1,14 @@
1
1
  from rest_framework import serializers
2
2
 
3
+
3
4
  class StatsSerializer(serializers.Serializer):
4
5
  """
5
6
  Serializer for statistics data from AuditLedger.
6
-
7
+
7
8
  This serializer defines the structure of statistics data and ensures
8
9
  consistent API responses.
9
10
  """
11
+
10
12
  totalCases = serializers.IntegerField()
11
13
  totalVideos = serializers.IntegerField()
12
14
  totalAnnotations = serializers.IntegerField()
@@ -14,20 +16,20 @@ class StatsSerializer(serializers.Serializer):
14
16
  totalImages = serializers.IntegerField()
15
17
  videosCompleted = serializers.IntegerField()
16
18
  videosAnonym = serializers.IntegerField()
17
-
19
+
18
20
  # You can add additional fields or methods here as needed
19
21
  # For example, to calculate derived statistics:
20
- #TODO
22
+ # TODO
21
23
  def get_completion_percentage(self, obj):
22
24
  """
23
25
  Calculates the percentage of completed videos out of the total videos.
24
-
26
+
25
27
  Args:
26
28
  obj: A dictionary containing 'videosCompleted' and 'totalVideos' keys.
27
-
29
+
28
30
  Returns:
29
31
  The completion percentage as a float rounded to two decimal places, or 0 if totalVideos is zero or less.
30
32
  """
31
- if obj['totalVideos'] > 0:
32
- return round((obj['videosCompleted'] / obj['totalVideos']) * 100, 2)
33
- return 0
33
+ if obj["totalVideos"] > 0:
34
+ return round((obj["videosCompleted"] / obj["totalVideos"]) * 100, 2)
35
+ return 0
@@ -4,20 +4,20 @@ from django.utils.translation import get_language
4
4
  class TranslatableFieldMixin:
5
5
  """Mixin für automatische Sprachauswahl basierend auf Accept-Language"""
6
6
 
7
- def get_localized_name(self, obj, field_base='name'):
7
+ def get_localized_name(self, obj, field_base="name"):
8
8
  """
9
9
  Retrieve a localized value for a specified field from an object, using language preference fallbacks.
10
-
10
+
11
11
  Attempts to return the value of the field with the current language code suffix (e.g., `name_en`). If unavailable or empty, falls back to the German (`_de`) version, then the English (`_en`) version, and finally the base field without a language suffix. Returns an empty string if no value is found.
12
-
12
+
13
13
  Parameters:
14
14
  obj: The object containing the translatable fields.
15
15
  field_base (str): The base name of the field to localize (default is 'name').
16
-
16
+
17
17
  Returns:
18
18
  str: The localized field value, or an empty string if none is available.
19
19
  """
20
- current_lang = get_language() or 'en'
20
+ current_lang = get_language() or "en"
21
21
 
22
22
  # Versuche sprachspezifisches Feld
23
23
  lang_field = f"{field_base}_{current_lang}"
@@ -41,4 +41,4 @@ class TranslatableFieldMixin:
41
41
  return value
42
42
 
43
43
  # Letzter Fallback auf Basis-Feld
44
- return getattr(obj, field_base, '')
44
+ return getattr(obj, field_base, "")
@@ -7,27 +7,29 @@ class UploadJobStatusSerializer(serializers.ModelSerializer):
7
7
  Read-only serializer for upload job status responses.
8
8
  Returns status information for polling endpoints.
9
9
  """
10
-
10
+
11
11
  sensitive_meta_id = serializers.IntegerField(
12
- source='sensitive_meta.id',
12
+ source="sensitive_meta.id",
13
13
  read_only=True,
14
14
  allow_null=True,
15
- help_text="ID of the created SensitiveMeta record (only when anonymized)"
15
+ help_text="ID of the created SensitiveMeta record (only when anonymized)",
16
16
  )
17
-
17
+
18
18
  # Optional helper fields for preview (can be populated by view if needed)
19
19
  text = serializers.CharField(read_only=True, required=False, allow_blank=True)
20
- anonymized_text = serializers.CharField(read_only=True, required=False, allow_blank=True)
20
+ anonymized_text = serializers.CharField(
21
+ read_only=True, required=False, allow_blank=True
22
+ )
21
23
 
22
24
  class Meta:
23
25
  model = UploadJob
24
26
  fields = [
25
- 'status',
26
- 'error_detail',
27
- 'sensitive_meta_id',
28
- 'id',
29
- 'text',
30
- 'anonymized_text'
27
+ "status",
28
+ "error_detail",
29
+ "sensitive_meta_id",
30
+ "id",
31
+ "text",
32
+ "anonymized_text",
31
33
  ]
32
34
  read_only_fields = fields
33
35
 
@@ -36,21 +38,24 @@ class UploadJobStatusSerializer(serializers.ModelSerializer):
36
38
  Customize the representation to only include relevant fields based on status.
37
39
  """
38
40
  data = super().to_representation(instance)
39
-
41
+
40
42
  # Only include error_detail if status is error
41
43
  if instance.status != UploadJob.Status.ERROR:
42
- data.pop('error_detail', None)
43
-
44
+ data.pop("error_detail", None)
45
+
44
46
  # Only include sensitive_meta_id if status is anonymized and we have a meta record
45
- if instance.status != UploadJob.Status.ANONYMIZED or not instance.sensitive_meta:
46
- data.pop('sensitive_meta_id', None)
47
-
47
+ if (
48
+ instance.status != UploadJob.Status.ANONYMIZED
49
+ or not instance.sensitive_meta
50
+ ):
51
+ data.pop("sensitive_meta_id", None)
52
+
48
53
  # Remove empty optional fields
49
- if not data.get('text'):
50
- data.pop('text', None)
51
- if not data.get('anonymized_text'):
52
- data.pop('anonymized_text', None)
53
-
54
+ if not data.get("text"):
55
+ data.pop("text", None)
56
+ if not data.get("anonymized_text"):
57
+ data.pop("anonymized_text", None)
58
+
54
59
  return data
55
60
 
56
61
 
@@ -59,13 +64,11 @@ class UploadCreateResponseSerializer(serializers.Serializer):
59
64
  Serializer for the initial upload response.
60
65
  Returns upload_id and status_url for polling.
61
66
  """
62
-
67
+
63
68
  upload_id = serializers.UUIDField(
64
- read_only=True,
65
- help_text="UUID of the created upload job"
69
+ read_only=True, help_text="UUID of the created upload job"
66
70
  )
67
-
71
+
68
72
  status_url = serializers.CharField(
69
- read_only=True,
70
- help_text="URL to poll for upload status updates"
71
- )
73
+ read_only=True, help_text="URL to poll for upload status updates"
74
+ )
@@ -5,7 +5,8 @@ from .patient import (
5
5
  from .patient_dropdown import (
6
6
  PatientDropdownSerializer,
7
7
  )
8
+
8
9
  __all__ = [
9
10
  "PatientSerializer",
10
11
  "PatientDropdownSerializer",
11
- ]
12
+ ]