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,327 +0,0 @@
1
- """
2
- Video processing tasks for Celery-based asynchronous video processing.
3
-
4
- This module provides Celery tasks for:
5
- - Video masking with streaming FFmpeg processing
6
- - Frame removal with streaming optimization
7
- - Video reprocessing workflows
8
- - Progress tracking and status updates
9
- """
10
-
11
- from pathlib import Path
12
- from typing import Dict, Any, List, Optional
13
- from celery import shared_task
14
- from celery.utils.log import get_task_logger
15
- from django.shortcuts import get_object_or_404
16
-
17
- logger = get_task_logger(__name__)
18
-
19
- @shared_task(bind=True)
20
- def apply_video_mask_task(self, video_id: int, mask_type: str = 'device_default',
21
- device_name: str = 'olympus_cv_1500', use_streaming: bool = True,
22
- custom_mask: Optional[Dict[str, Any]] = None):
23
- """
24
- Apply mask to video using streaming processing.
25
-
26
- Args:
27
- video_id: ID of the VideoFile to process
28
- mask_type: Type of mask to apply ('device_default', 'roi_based', 'custom')
29
- device_name: Device name for default mask
30
- use_streaming: Whether to use streaming processing (recommended)
31
- custom_mask: Custom mask configuration (if mask_type='custom')
32
- """
33
- try:
34
- # Update task progress
35
- self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Initializing mask application...'})
36
-
37
- # Import models here to avoid circular imports
38
- from endoreg_db.models import VideoFile
39
- from lx_anonymizer.frame_cleaner import FrameCleaner
40
-
41
- # Get video file
42
- video = get_object_or_404(VideoFile, pk=video_id)
43
- video_path = Path(video.file.path)
44
-
45
- if not video_path.exists():
46
- raise FileNotFoundError(f"Video file not found: {video_path}")
47
-
48
- # Create output path
49
- output_dir = video_path.parent / "processed"
50
- output_dir.mkdir(exist_ok=True)
51
- output_path = output_dir / f"{video_path.stem}_masked{video_path.suffix}"
52
-
53
- self.update_state(state='PROGRESS', meta={'progress': 10, 'message': 'Setting up FrameCleaner...'})
54
-
55
- # Initialize FrameCleaner
56
- cleaner = FrameCleaner()
57
-
58
- # Determine mask configuration
59
- if mask_type == 'custom' and custom_mask:
60
- mask_config = custom_mask
61
- elif mask_type == 'roi_based':
62
- # Would need ROI data from video metadata
63
- mask_config = cleaner._load_mask(device_name) # Fallback for now
64
- else: # device_default
65
- mask_config = cleaner._load_mask(device_name)
66
-
67
- self.update_state(state='PROGRESS', meta={'progress': 20, 'message': f'Applying {mask_type} mask...'})
68
-
69
- # Apply mask using streaming
70
- if use_streaming:
71
- success = cleaner._mask_video_streaming(
72
- video_path, mask_config, output_path, use_named_pipe=True
73
- )
74
- else:
75
- success = cleaner._mask_video(video_path, mask_config, output_path)
76
-
77
- if not success:
78
- raise RuntimeError("Video masking failed")
79
-
80
- self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
81
-
82
- # Verify output
83
- if not output_path.exists() or output_path.stat().st_size == 0:
84
- raise RuntimeError("Output video is empty or missing")
85
-
86
- result = {
87
- 'status': 'completed',
88
- 'output_path': str(output_path),
89
- 'mask_type': mask_type,
90
- 'device_name': device_name,
91
- 'use_streaming': use_streaming,
92
- 'output_size': output_path.stat().st_size,
93
- 'message': 'Video masking completed successfully'
94
- }
95
-
96
- logger.info(f"Video masking completed for video {video_id}: {output_path}")
97
- return result
98
-
99
- except Exception as e:
100
- logger.error(f"Video masking failed for video {video_id}: {e}")
101
- self.update_state(
102
- state='FAILURE',
103
- meta={'error': str(e), 'message': f'Video masking failed: {e}'}
104
- )
105
- raise
106
-
107
-
108
- def _setup_frame_removal(video_id: int, detection_engine: str):
109
- from endoreg_db.models import VideoFile
110
- from lx_anonymizer.frame_cleaner import FrameCleaner
111
- from django.shortcuts import get_object_or_404
112
- video = get_object_or_404(VideoFile, pk=video_id)
113
- video_path = Path(video.raw_file.path)
114
- if not video_path.exists():
115
- raise FileNotFoundError(f"Video file not found: {video_path}")
116
- output_dir = video_path.parent / "processed"
117
- output_dir.mkdir(exist_ok=True)
118
- output_path = output_dir / f"{video_path.stem}_cleaned{video_path.suffix}"
119
- use_minicpm = detection_engine == 'minicpm'
120
- cleaner = FrameCleaner()
121
- return video, video_path, output_path, cleaner
122
-
123
- def _detect_sensitive_frames(self, cleaner, video_path, selection_method, manual_frames, total_frames):
124
- frames_to_remove = []
125
- if selection_method == 'manual' and manual_frames:
126
- frames_to_remove = manual_frames
127
- self.update_state(state='PROGRESS', meta={'progress': 50, 'message': f'Using manual frame selection: {len(frames_to_remove)} frames'})
128
- elif selection_method == 'automatic':
129
- self.update_state(state='PROGRESS', meta={'progress': 20, 'message': 'Detecting sensitive frames...'})
130
- if total_frames > 10000:
131
- self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Using statistical sampling for large video...'})
132
- sensitive_frames, estimated_ratio, early_stopped = cleaner._sample_frames_coroutine(
133
- video_path, total_frames, max_samples=500
134
- )
135
- frames_to_remove = sensitive_frames
136
- else:
137
- self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Analyzing all frames...'})
138
- for abs_i, gray_frame, skip in cleaner._iter_video(video_path, total_frames):
139
- progress = 30 + (abs_i / total_frames) * 40 # 30-70% for detection
140
- if abs_i % 100 == 0:
141
- self.update_state(state='PROGRESS', meta={
142
- 'progress': int(progress),
143
- 'message': f'Analyzing frame {abs_i}/{total_frames}...'
144
- })
145
- ocr_text, avg_conf, _ = cleaner.frame_ocr.extract_text_from_frame(
146
- gray_frame, roi=None, high_quality=True
147
- )
148
- if ocr_text:
149
- frame_metadata = cleaner.extract_metadata_deepseek(ocr_text)
150
- if not frame_metadata:
151
- frame_metadata = cleaner.frame_metadata_extractor.extract_metadata_from_frame_text(ocr_text)
152
- has_sensitive = cleaner.frame_metadata_extractor.is_sensitive_content(frame_metadata)
153
- if has_sensitive:
154
- frames_to_remove.append(abs_i)
155
- return frames_to_remove
156
-
157
- def _remove_frames_from_video(cleaner, video_path, frames_to_remove, output_path, use_streaming):
158
- if use_streaming:
159
- return cleaner.remove_frames_from_video_streaming(
160
- video_path, frames_to_remove, output_path, use_named_pipe=True
161
- )
162
- else:
163
- return cleaner.remove_frames_from_video(
164
- video_path, frames_to_remove, output_path
165
- )
166
-
167
- def _verify_frame_removal_output(output_path):
168
- if not output_path.exists() or output_path.stat().st_size == 0:
169
- raise RuntimeError("Output video is empty or missing")
170
-
171
- @shared_task(bind=True)
172
- def remove_video_frames_task(self, video_id: int, selection_method: str = 'automatic',
173
- detection_engine: str = 'minicpm', use_streaming: bool = True,
174
- manual_frames: Optional[List[int]] = None):
175
- """
176
- Remove frames from video using streaming processing.
177
-
178
- Args:
179
- video_id: ID of the VideoFile to process
180
- selection_method: 'automatic' or 'manual'
181
- detection_engine: 'minicpm' or 'traditional'
182
- use_streaming: Whether to use streaming processing
183
- manual_frames: List of frame indices to remove (for manual selection)
184
- """
185
- try:
186
- # Update task progress
187
- self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Initializing frame removal...'})
188
-
189
- video, video_path, output_path, cleaner = _setup_frame_removal(video_id, detection_engine)
190
-
191
- self.update_state(state='PROGRESS', meta={'progress': 10, 'message': 'Setting up FrameCleaner...'})
192
-
193
- # Get total frame count
194
- total_frames = cleaner._get_total_frames()
195
-
196
- frames_to_remove = _detect_sensitive_frames(
197
- self, cleaner, video_path, selection_method, manual_frames, total_frames
198
- )
199
-
200
- self.update_state(state='PROGRESS', meta={'progress': 70, 'message': f'Removing {len(frames_to_remove)} frames...'})
201
-
202
- # Remove frames using streaming
203
- success = _remove_frames_from_video(cleaner, video_path, frames_to_remove, output_path, use_streaming)
204
-
205
- if not success:
206
- raise RuntimeError("Frame removal failed")
207
-
208
- self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
209
-
210
- _verify_frame_removal_output(output_path)
211
-
212
- result = {
213
- 'status': 'completed',
214
- 'output_path': str(output_path),
215
- 'frames_removed': len(frames_to_remove),
216
- 'selection_method': selection_method,
217
- 'detection_engine': detection_engine,
218
- 'use_streaming': use_streaming,
219
- 'output_size': output_path.stat().st_size,
220
- 'message': f'Successfully removed {len(frames_to_remove)} frames'
221
- }
222
-
223
- logger.info(f"Frame removal completed for video {video_id}: {len(frames_to_remove)} frames removed")
224
- return result
225
-
226
- except Exception as e:
227
- logger.error(f"Frame removal failed for video {video_id}: {e}")
228
- self.update_state(
229
- state='FAILURE',
230
- meta={'error': str(e), 'message': f'Frame removal failed: {e}'}
231
- )
232
- raise
233
-
234
-
235
- @shared_task(bind=True)
236
- def reprocess_video_task(self, video_id: int):
237
- """
238
- Reprocess video with updated settings.
239
-
240
- Args:
241
- video_id: ID of the VideoFile to reprocess
242
- """
243
- try:
244
- self.update_state(state='PROGRESS', meta={'progress': 0, 'message': 'Starting video reprocessing...'})
245
-
246
- # Import models here to avoid circular imports
247
- from endoreg_db.models import VideoFile
248
- from lx_anonymizer.frame_cleaner import FrameCleaner
249
-
250
- # Get video file
251
- video = get_object_or_404(VideoFile, pk=video_id)
252
- video_path = Path(video.file.path)
253
-
254
- if not video_path.exists():
255
- raise FileNotFoundError(f"Video file not found: {video_path}")
256
-
257
- self.update_state(state='PROGRESS', meta={'progress': 20, 'message': 'Initializing FrameCleaner...'})
258
-
259
- # Initialize FrameCleaner with optimal settings
260
- cleaner = FrameCleaner()
261
-
262
- # Create output path
263
- output_dir = video_path.parent / "processed"
264
- output_dir.mkdir(exist_ok=True)
265
- output_path = output_dir / f"{video_path.stem}_reprocessed{video_path.suffix}"
266
-
267
- self.update_state(state='PROGRESS', meta={'progress': 30, 'message': 'Analyzing video...'})
268
-
269
- # Perform full analysis
270
- analysis_result = cleaner.analyze_video_sensitivity()
271
-
272
- self.update_state(state='PROGRESS', meta={'progress': 60, 'message': f'Processing with {analysis_result["recommended_method"]}...'})
273
-
274
- # Process based on analysis recommendation
275
- if analysis_result["recommended_method"] == "masking":
276
- # Apply device-specific masking
277
- mask_config = cleaner._load_mask("olympus_cv_1500") # Default device
278
- success = cleaner._mask_video_streaming(
279
- video_path, mask_config, output_path, use_named_pipe=True
280
- )
281
- else:
282
- # Remove sensitive frames
283
- sensitive_frames = analysis_result.get("sensitive_frame_list", [])
284
- # Filter out string elements like "...truncated"
285
- sensitive_frames = [f for f in sensitive_frames if isinstance(f, int)]
286
-
287
- success = cleaner.remove_frames_from_video_streaming(
288
- video_path, sensitive_frames, output_path, use_named_pipe=True
289
- )
290
-
291
- if not success:
292
- raise RuntimeError("Video reprocessing failed")
293
-
294
- self.update_state(state='PROGRESS', meta={'progress': 90, 'message': 'Finalizing...'})
295
-
296
- # Update video metadata with analysis results
297
- if hasattr(video, 'sensitive_frame_count'):
298
- video.sensitive_frame_count = analysis_result.get('sensitive_frames', 0)
299
- if hasattr(video, 'total_frames'):
300
- video.total_frames = analysis_result.get('total_frames', 0)
301
- if hasattr(video, 'sensitive_ratio'):
302
- video.sensitive_ratio = analysis_result.get('sensitivity_ratio', 0.0)
303
-
304
- try:
305
- video.save()
306
- except Exception as e:
307
- logger.warning(f"Could not save video metadata: {e}")
308
-
309
- result = {
310
- 'status': 'completed',
311
- 'output_path': str(output_path),
312
- 'analysis_result': analysis_result,
313
- 'processing_method': analysis_result["recommended_method"],
314
- 'output_size': output_path.stat().st_size if output_path.exists() else 0,
315
- 'message': 'Video reprocessing completed successfully'
316
- }
317
-
318
- logger.info(f"Video reprocessing completed for video {video_id}")
319
- return result
320
-
321
- except Exception as e:
322
- logger.error(f"Video reprocessing failed for video {video_id}: {e}")
323
- self.update_state(
324
- state='FAILURE',
325
- meta={'error': str(e), 'message': f'Video reprocessing failed: {e}'}
326
- )
327
- raise
@@ -1,182 +0,0 @@
1
- """
2
- Automatisierte Internationalisierung für medizinische Terminologie
3
- Ersetzt manuelle name_de/name_en Felder durch django-modeltranslation
4
- """
5
- from modeltranslation.translator import TranslationOptions, translator
6
- # Source: https://github.com/deschler/django-modeltranslation
7
- #https://django-modeltranslation.readthedocs.io/en/latest/installation.html#advanced-settings
8
-
9
- from endoreg_db.models import (
10
- Examination,
11
- Finding,
12
- FindingClassification,
13
- FindingClassificationChoice,
14
- FindingIntervention
15
- )
16
-
17
- class ExaminationTranslationOptions(TranslationOptions):
18
- fields = ('name', 'description')
19
- required_languages = ('de', 'en')
20
- fallback_languages = {'default': ('en', 'de')}
21
-
22
- translator.register(Examination, ExaminationTranslationOptions)
23
-
24
-
25
- class FindingTranslationOptions(TranslationOptions):
26
- fields = ('name', 'description')
27
- required_languages = ('de', 'en')
28
- fallback_languages = {'default': ('en', 'de')}
29
-
30
- translator.register(Finding, FindingTranslationOptions)
31
-
32
-
33
- class FindingClassificationTranslationOptions(TranslationOptions):
34
- fields = ('name', 'description')
35
- required_languages = ('de', 'en')
36
- fallback_languages = {'default': ('en', 'de')}
37
-
38
- translator.register(FindingClassification, FindingClassificationTranslationOptions)
39
-
40
-
41
- class FindingClassificationChoiceTranslationOptions(TranslationOptions):
42
- fields = ('name', 'description')
43
- required_languages = ('de', 'en')
44
- fallback_languages = {'default': ('en', 'de')}
45
-
46
- translator.register(FindingClassificationChoice, FindingClassificationChoiceTranslationOptions)
47
-
48
-
49
- class InterventionTranslationOptions(TranslationOptions):
50
- fields = ('name', 'description')
51
- required_languages = ('de', 'en')
52
- fallback_languages = {'default': ('en', 'de')}
53
-
54
- translator.register(FindingIntervention, InterventionTranslationOptions)
55
-
56
-
57
- # Mixin für automatische Sprachauswahl in Serializers
58
- class TranslatedFieldMixin:
59
- """
60
- Mixin für Serializer um automatisch die richtige Sprache zu wählen
61
- Ersetzt manuelle get_name_display() Methoden
62
- """
63
-
64
- def get_translated_field(self, obj, field_name):
65
- """
66
- Automatische Sprachauswahl basierend auf Accept-Language Header
67
- """
68
- request = self.context.get('request')
69
- if request:
70
- # Django's get_language() berücksichtigt Accept-Language Header
71
- from django.utils.translation import get_language
72
- current_language = get_language()
73
-
74
- # Versuche sprachspezifisches Feld
75
- translated_field = f"{field_name}_{current_language}"
76
- translated_value = getattr(obj, translated_field, None)
77
-
78
- if translated_value:
79
- return translated_value
80
-
81
- # Fallback auf Hauptfeld
82
- return getattr(obj, field_name, '')
83
-
84
- def to_representation(self, instance):
85
- """
86
- Automatisches Ersetzen von name/description mit übersetzten Versionen
87
- """
88
- data = super().to_representation(instance)
89
-
90
- # Ersetze name mit übersetzter Version
91
- if 'name' in data:
92
- data['name'] = self.get_translated_field(instance, 'name')
93
-
94
- # Ersetze description mit übersetzter Version
95
- if 'description' in data:
96
- data['description'] = self.get_translated_field(instance, 'description')
97
-
98
- return data
99
-
100
-
101
- # Command für Migration bestehender Daten
102
- class TranslationMigrationHelper:
103
- """
104
- Helper für Migration von name_de/name_en zu modeltranslation
105
- """
106
-
107
- @staticmethod
108
- def migrate_examination_data():
109
- """Migriere bestehende Examination Daten"""
110
- from endoreg_db.models import Examination
111
-
112
- for examination in Examination.objects.all():
113
- # Migriere name_de/name_en zu name_de/name_en (modeltranslation)
114
- if hasattr(examination, 'name_de') and examination.name_de:
115
- examination.name_de = examination.name_de
116
- if hasattr(examination, 'name_en') and examination.name_en:
117
- examination.name_en = examination.name_en
118
-
119
- # Fallback auf 'name' wenn Übersetzungen fehlen
120
- if not examination.name_de and examination.name:
121
- examination.name_de = examination.name
122
- if not examination.name_en and examination.name:
123
- examination.name_en = examination.name
124
-
125
- examination.save()
126
-
127
- @staticmethod
128
- def migrate_all_models():
129
- """Migriere alle Modelle mit Übersetzungen"""
130
- models_to_migrate = [
131
- 'Examination', 'Finding', 'FindingClassification',
132
- 'FindingClassificationChoice', 'Intervention'
133
- ]
134
-
135
- for model_name in models_to_migrate:
136
- print(f"Migriere {model_name}...")
137
- # Implementierung für jedes Modell analog zu migrate_examination_data()
138
-
139
-
140
- # Erweiterte YAML Fixtures für Übersetzungen
141
- class TranslatedFixtureLoader:
142
- """
143
- Loader für YAML Fixtures mit Übersetzungsunterstützung
144
- Automatische Erkennung und Laden von name_de/name_en Feldern
145
- """
146
-
147
- @staticmethod
148
- def load_translated_fixture(model_class, fixture_data):
149
- """
150
- Lade Fixture mit automatischer Übersetzungszuordnung
151
- """
152
- for item in fixture_data:
153
- fields = item.get('fields', {})
154
-
155
- # Erstelle oder aktualisiere Objekt
156
- obj, created = model_class.objects.update_or_create(
157
- name=fields.get('name'),
158
- defaults=fields
159
- )
160
-
161
- # Setze Übersetzungen falls vorhanden
162
- if 'name_de' in fields:
163
- obj.name_de = fields['name_de']
164
- if 'name_en' in fields:
165
- obj.name_en = fields['name_en']
166
-
167
- obj.save()
168
-
169
- action = "erstellt" if created else "aktualisiert"
170
- print(f"{model_class.__name__} '{obj.name}' {action}")
171
-
172
-
173
- # Settings für django-modeltranslation
174
- MODELTRANSLATION_SETTINGS = {
175
- 'AVAILABLE_LANGUAGES': ('de', 'en'),
176
- 'DEFAULT_LANGUAGE': 'en',
177
- 'FALLBACK_LANGUAGES': {
178
- 'default': ('en', 'de'),
179
- },
180
- 'AUTO_POPULATE': True, # Automatisches Füllen fehlender Übersetzungen
181
- 'ENABLE_REGISTRATIONS': True,
182
- }