endoreg-db 0.6.4__py3-none-any.whl → 0.8.1__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 (778) hide show
  1. endoreg_db/admin.py +26 -26
  2. endoreg_db/api_urls.py +4 -0
  3. endoreg_db/apps.py +12 -0
  4. endoreg_db/assets/dummy_model.ckpt +1 -0
  5. endoreg_db/codemods/readme.md +88 -0
  6. endoreg_db/codemods/rename_datetime_fields.py +92 -0
  7. endoreg_db/config/env.py +101 -0
  8. endoreg_db/data/__init__.py +12 -0
  9. endoreg_db/data/ai_model/data.yaml +1 -1
  10. endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
  11. endoreg_db/data/ai_model_label/label-set/data.yaml +20 -1
  12. endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
  13. endoreg_db/data/center/data.yaml +13 -12
  14. endoreg_db/data/center_shift/ukw.yaml +9 -0
  15. endoreg_db/data/db_summary.csv +58 -0
  16. endoreg_db/data/db_summary.xlsx +0 -0
  17. endoreg_db/data/disease/misc.yaml +1 -2
  18. endoreg_db/data/endoscopy_processor/data.yaml +3 -0
  19. endoreg_db/data/event/cardiology.yaml +0 -13
  20. endoreg_db/data/examination/examinations/data.yaml +14 -9
  21. endoreg_db/data/examination_indication/endoscopy.yaml +30 -30
  22. endoreg_db/data/examination_indication_classification/endoscopy.yaml +11 -11
  23. endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
  24. endoreg_db/data/finding/anatomy_colon.yaml +128 -0
  25. endoreg_db/data/finding/colonoscopy.yaml +40 -0
  26. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
  27. endoreg_db/data/finding/complication.yaml +16 -0
  28. endoreg_db/data/finding/data.yaml +3 -46
  29. endoreg_db/data/finding/examination_setting.yaml +16 -0
  30. endoreg_db/data/finding/medication_related.yaml +18 -0
  31. endoreg_db/data/finding/outcome.yaml +12 -0
  32. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
  33. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
  34. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
  35. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
  36. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
  37. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
  38. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
  39. endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
  40. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
  41. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
  42. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
  43. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
  44. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
  45. endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
  46. endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
  47. endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
  48. endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
  49. endoreg_db/data/finding_classification/medication_related.yaml +23 -0
  50. endoreg_db/data/finding_classification/visualized.yaml +33 -0
  51. endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
  52. endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_circularity_default.yaml +0 -2
  53. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
  54. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
  55. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
  56. endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_nice.yaml +4 -7
  57. endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_paris.yaml +0 -8
  58. endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_planarity_default.yaml +6 -13
  59. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
  60. endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_surface_intact_default.yaml +3 -6
  61. endoreg_db/data/{finding_location_classification_choice/colonoscopy.yaml → finding_classification_choice/colonoscopy_location.yaml} +11 -22
  62. endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
  63. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
  64. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
  65. endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
  66. endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
  67. endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
  68. endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
  69. endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
  70. endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
  71. endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
  72. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +8 -3
  73. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +6 -6
  74. endoreg_db/data/finding_type/data.yaml +23 -10
  75. endoreg_db/data/gender/data.yaml +8 -1
  76. endoreg_db/data/information_source/annotation.yaml +6 -0
  77. endoreg_db/data/information_source/prediction.yaml +7 -0
  78. endoreg_db/data/information_source_type/data.yaml +8 -0
  79. endoreg_db/data/lab_value/misc.yaml +43 -0
  80. endoreg_db/data/medication/anticoagulation.yaml +5 -5
  81. endoreg_db/data/medication/tah.yaml +5 -5
  82. endoreg_db/data/medication_intake_time/base.yaml +4 -4
  83. endoreg_db/data/names_first/first_names.yaml +3 -0
  84. endoreg_db/data/pdf_type/data.yaml +26 -2
  85. endoreg_db/data/qualification/endoscopy.yaml +36 -0
  86. endoreg_db/data/qualification/m2.yaml +39 -0
  87. endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
  88. endoreg_db/data/qualification/sonography.yaml +36 -0
  89. endoreg_db/data/qualification_type/base.yaml +29 -0
  90. endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
  91. endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +5 -0
  92. endoreg_db/data/requirement/age.yaml +26 -0
  93. endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
  94. endoreg_db/data/requirement/disease_cardiovascular.yaml +6 -6
  95. endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +9 -6
  96. endoreg_db/data/requirement/disease_hepatology.yaml +1 -1
  97. endoreg_db/data/requirement/disease_misc.yaml +3 -3
  98. endoreg_db/data/requirement/disease_renal.yaml +18 -2
  99. endoreg_db/data/requirement/{colonoscopy_indications.yaml → endoscopy_bleeding_risk.yaml} +6 -3
  100. endoreg_db/data/requirement/event_cardiology.yaml +17 -17
  101. endoreg_db/data/requirement/event_requirements.yaml +145 -0
  102. endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
  103. endoreg_db/data/requirement/gender.yaml +25 -0
  104. endoreg_db/data/requirement/lab_value.yaml +352 -31
  105. endoreg_db/data/requirement/medication.yaml +93 -0
  106. endoreg_db/data/requirement_operator/age.yaml +13 -0
  107. endoreg_db/data/requirement_operator/lab_operators.yaml +36 -35
  108. endoreg_db/data/requirement_operator/model_operators.yaml +13 -7
  109. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
  110. endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
  111. endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +42 -2
  112. endoreg_db/data/requirement_type/requirement_types.yaml +82 -0
  113. endoreg_db/data/shift/endoscopy.yaml +21 -0
  114. endoreg_db/data/shift_type/base.yaml +35 -0
  115. endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
  116. endoreg_db/data/unit/concentration.yaml +23 -0
  117. endoreg_db/exceptions.py +19 -0
  118. endoreg_db/forms/patient_finding_intervention_form.py +4 -5
  119. endoreg_db/forms/patient_form.py +7 -6
  120. endoreg_db/forms/questionnaires/__init__.py +1 -1
  121. endoreg_db/forms/questionnaires/tto_questionnaire.py +19 -19
  122. endoreg_db/helpers/count_db.py +45 -0
  123. endoreg_db/helpers/data_loader.py +208 -0
  124. endoreg_db/helpers/default_objects.py +359 -0
  125. endoreg_db/helpers/interact.py +6 -0
  126. endoreg_db/helpers/test_video_helper.py +119 -0
  127. endoreg_db/logger_conf.py +140 -0
  128. endoreg_db/management/__init__.py +1 -0
  129. endoreg_db/management/commands/__init__.py +1 -0
  130. endoreg_db/management/commands/anonymize_video.py +0 -0
  131. endoreg_db/management/commands/check_auth.py +125 -0
  132. endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
  133. endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
  134. endoreg_db/management/commands/fix_video_paths.py +165 -0
  135. endoreg_db/management/commands/import_fallback_video.py +203 -0
  136. endoreg_db/management/commands/import_report.py +298 -0
  137. endoreg_db/management/commands/import_video.py +422 -0
  138. endoreg_db/management/commands/import_video_with_classification.py +367 -0
  139. endoreg_db/management/commands/init_default_ai_model.py +112 -0
  140. endoreg_db/management/commands/load_ai_model_data.py +2 -7
  141. endoreg_db/management/commands/load_base_db_data.py +1 -0
  142. endoreg_db/management/commands/load_endoscope_data.py +2 -2
  143. endoreg_db/management/commands/load_examination_indication_data.py +2 -3
  144. endoreg_db/management/commands/load_finding_data.py +49 -92
  145. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +0 -1
  146. endoreg_db/management/commands/load_information_source.py +13 -7
  147. endoreg_db/management/commands/load_name_data.py +37 -0
  148. endoreg_db/management/commands/load_qualification_data.py +59 -0
  149. endoreg_db/management/commands/load_requirement_data.py +30 -6
  150. endoreg_db/management/commands/load_shift_data.py +60 -0
  151. endoreg_db/management/commands/load_tag_data.py +57 -0
  152. endoreg_db/management/commands/register_ai_model.py +1 -1
  153. endoreg_db/management/commands/start_filewatcher.py +106 -0
  154. endoreg_db/management/commands/storage_management.py +548 -0
  155. endoreg_db/management/commands/summarize_db_content.py +189 -0
  156. endoreg_db/management/commands/validate_video.py +204 -0
  157. endoreg_db/management/commands/validate_video_files.py +161 -0
  158. endoreg_db/management/commands/video_validation.py +22 -0
  159. endoreg_db/migrations/0001_initial.py +625 -813
  160. endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
  161. endoreg_db/models/__init__.py +270 -307
  162. endoreg_db/models/administration/__init__.py +116 -0
  163. endoreg_db/models/{ai_model → administration/ai}/__init__.py +6 -1
  164. endoreg_db/models/administration/ai/active_model.py +35 -0
  165. endoreg_db/models/administration/ai/ai_model.py +156 -0
  166. endoreg_db/models/{ai_model → administration/ai}/model_type.py +6 -1
  167. endoreg_db/models/administration/case/__init__.py +19 -0
  168. endoreg_db/models/administration/case/case.py +114 -0
  169. endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +3 -3
  170. endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +3 -10
  171. endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +2 -4
  172. endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +1 -3
  173. endoreg_db/models/{center → administration/center}/__init__.py +3 -1
  174. endoreg_db/models/administration/center/center.py +61 -0
  175. endoreg_db/models/administration/center/center_product.py +64 -0
  176. endoreg_db/models/{center → administration/center}/center_resource.py +19 -3
  177. endoreg_db/models/administration/center/center_shift.py +88 -0
  178. endoreg_db/models/administration/center/center_waste.py +30 -0
  179. endoreg_db/models/administration/permissions/__init__.py +44 -0
  180. endoreg_db/models/administration/person/__init__.py +24 -0
  181. endoreg_db/models/administration/person/employee/__init__.py +3 -0
  182. endoreg_db/models/administration/person/employee/employee.py +35 -0
  183. endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
  184. endoreg_db/models/administration/person/employee/employee_type.py +42 -0
  185. endoreg_db/models/administration/person/examiner/__init__.py +4 -0
  186. endoreg_db/models/administration/person/examiner/examiner.py +54 -0
  187. endoreg_db/models/administration/person/names/__init__.py +0 -0
  188. endoreg_db/models/{persons → administration/person/names}/first_name.py +1 -1
  189. endoreg_db/models/{persons → administration/person/names}/last_name.py +2 -3
  190. endoreg_db/models/administration/person/patient/__init__.py +5 -0
  191. endoreg_db/models/administration/person/patient/patient.py +460 -0
  192. endoreg_db/models/administration/person/profession/__init__.py +24 -0
  193. endoreg_db/models/administration/person/user/__init__.py +5 -0
  194. endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
  195. endoreg_db/models/administration/product/product.py +97 -0
  196. endoreg_db/models/administration/product/product_group.py +39 -0
  197. endoreg_db/models/administration/product/product_material.py +54 -0
  198. endoreg_db/models/{product → administration/product}/product_weight.py +9 -0
  199. endoreg_db/models/{product → administration/product}/reference_product.py +26 -11
  200. endoreg_db/models/administration/qualification/__init__.py +7 -0
  201. endoreg_db/models/administration/qualification/qualification.py +37 -0
  202. endoreg_db/models/administration/qualification/qualification_type.py +35 -0
  203. endoreg_db/models/administration/shift/__init__.py +9 -0
  204. endoreg_db/models/administration/shift/scheduled_days.py +69 -0
  205. endoreg_db/models/administration/shift/shift.py +51 -0
  206. endoreg_db/models/administration/shift/shift_type.py +108 -0
  207. endoreg_db/models/label/__init__.py +24 -1
  208. endoreg_db/models/label/annotation/__init__.py +12 -0
  209. endoreg_db/models/label/annotation/image_classification.py +84 -0
  210. endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
  211. endoreg_db/models/label/label.py +45 -74
  212. endoreg_db/models/label/label_set.py +53 -0
  213. endoreg_db/models/label/label_type.py +29 -0
  214. endoreg_db/models/label/label_video_segment/__init__.py +3 -0
  215. endoreg_db/models/label/label_video_segment/_create_from_video.py +41 -0
  216. endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
  217. endoreg_db/models/label/video_segmentation_label.py +31 -0
  218. endoreg_db/models/{annotation → label}/video_segmentation_labelset.py +7 -0
  219. endoreg_db/models/media/__init__.py +14 -0
  220. endoreg_db/models/media/frame/__init__.py +3 -0
  221. endoreg_db/models/media/frame/frame.py +111 -0
  222. endoreg_db/models/media/pdf/__init__.py +11 -0
  223. endoreg_db/models/media/pdf/raw_pdf.py +608 -0
  224. endoreg_db/models/media/pdf/report_file.py +162 -0
  225. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
  226. endoreg_db/models/media/video/__init__.py +4 -0
  227. endoreg_db/models/media/video/create_from_file.py +336 -0
  228. endoreg_db/models/media/video/pipe_1.py +195 -0
  229. endoreg_db/models/media/video/pipe_2.py +105 -0
  230. endoreg_db/models/media/video/refactor_plan.md +0 -0
  231. endoreg_db/models/media/video/video_file.py +680 -0
  232. endoreg_db/models/media/video/video_file_ai.py +443 -0
  233. endoreg_db/models/media/video/video_file_anonymize.py +348 -0
  234. endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
  235. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -0
  236. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
  237. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +104 -0
  238. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
  239. endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
  240. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
  241. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
  242. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
  243. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
  244. endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
  245. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
  246. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +129 -0
  247. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
  248. endoreg_db/models/media/video/video_file_frames.py +0 -0
  249. endoreg_db/models/media/video/video_file_io.py +166 -0
  250. endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
  251. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +45 -0
  252. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
  253. endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
  254. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
  255. endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
  256. endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
  257. endoreg_db/models/media/video/video_file_meta.py +11 -0
  258. endoreg_db/models/media/video/video_file_segments.py +209 -0
  259. endoreg_db/models/medical/__init__.py +146 -0
  260. endoreg_db/models/{contraindication → medical/contraindication}/__init__.py +1 -5
  261. endoreg_db/models/{disease.py → medical/disease.py} +60 -52
  262. endoreg_db/models/{event.py → medical/event.py} +31 -54
  263. endoreg_db/models/{examination → medical/examination}/__init__.py +1 -1
  264. endoreg_db/models/medical/examination/examination.py +148 -0
  265. endoreg_db/models/{examination → medical/examination}/examination_indication.py +64 -35
  266. endoreg_db/models/{examination → medical/examination}/examination_time.py +0 -4
  267. endoreg_db/models/{examination → medical/examination}/examination_time_type.py +1 -8
  268. endoreg_db/models/{examination → medical/examination}/examination_type.py +1 -7
  269. endoreg_db/models/medical/finding/__init__.py +18 -0
  270. endoreg_db/models/medical/finding/finding.py +96 -0
  271. endoreg_db/models/medical/finding/finding_classification.py +142 -0
  272. endoreg_db/models/{finding → medical/finding}/finding_intervention.py +2 -10
  273. endoreg_db/models/medical/finding/finding_type.py +35 -0
  274. endoreg_db/models/medical/hardware/__init__.py +8 -0
  275. endoreg_db/models/{hardware → medical/hardware}/endoscope.py +28 -23
  276. endoreg_db/models/medical/laboratory/__init__.py +5 -0
  277. endoreg_db/models/medical/laboratory/lab_value.py +419 -0
  278. endoreg_db/models/{medication → medical/medication}/medication.py +1 -3
  279. endoreg_db/models/{medication → medical/medication}/medication_indication_type.py +8 -3
  280. endoreg_db/models/{medication → medical/medication}/medication_intake_time.py +21 -3
  281. endoreg_db/models/{medication → medical/medication}/medication_schedule.py +13 -5
  282. endoreg_db/models/{organ → medical/organ}/__init__.py +3 -6
  283. endoreg_db/models/medical/patient/__init__.py +56 -0
  284. endoreg_db/models/medical/patient/medication_examples.py +38 -0
  285. endoreg_db/models/medical/patient/patient_disease.py +63 -0
  286. endoreg_db/models/medical/patient/patient_event.py +75 -0
  287. endoreg_db/models/medical/patient/patient_examination.py +249 -0
  288. endoreg_db/models/{persons → medical}/patient/patient_examination_indication.py +21 -9
  289. endoreg_db/models/medical/patient/patient_finding.py +357 -0
  290. endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
  291. endoreg_db/models/{patient → medical/patient}/patient_finding_intervention.py +15 -1
  292. endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
  293. endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +40 -15
  294. endoreg_db/models/medical/patient/patient_medication.py +104 -0
  295. endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
  296. endoreg_db/models/{risk → medical/risk}/risk_type.py +0 -4
  297. endoreg_db/models/{data_file/metadata → metadata}/__init__.py +6 -0
  298. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  299. endoreg_db/models/metadata/model_meta.py +193 -0
  300. endoreg_db/models/metadata/model_meta_logic.py +236 -0
  301. endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +28 -13
  302. endoreg_db/models/metadata/sensitive_meta.py +288 -0
  303. endoreg_db/models/metadata/sensitive_meta_logic.py +643 -0
  304. endoreg_db/models/metadata/video_meta.py +332 -0
  305. endoreg_db/models/metadata/video_prediction_logic.py +190 -0
  306. endoreg_db/models/metadata/video_prediction_meta.py +270 -0
  307. endoreg_db/models/other/__init__.py +17 -0
  308. endoreg_db/models/other/distribution/date_value_distribution.py +0 -2
  309. endoreg_db/models/other/distribution/numeric_value_distribution.py +30 -2
  310. endoreg_db/models/{emission → other/emission}/emission_factor.py +15 -6
  311. endoreg_db/models/{persons → other}/gender.py +8 -3
  312. endoreg_db/models/other/information_source.py +159 -0
  313. endoreg_db/models/other/material.py +10 -2
  314. endoreg_db/models/other/resource.py +6 -2
  315. endoreg_db/models/other/tag.py +27 -0
  316. endoreg_db/models/other/transport_route.py +13 -2
  317. endoreg_db/models/{unit.py → other/unit.py} +16 -6
  318. endoreg_db/models/other/waste.py +10 -3
  319. endoreg_db/models/requirement/requirement.py +556 -114
  320. endoreg_db/models/requirement/requirement_evaluation/__init__.py +4 -132
  321. endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
  322. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
  323. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +80 -87
  324. endoreg_db/models/requirement/requirement_operator.py +132 -14
  325. endoreg_db/models/requirement/requirement_set.py +181 -21
  326. endoreg_db/models/rule/__init__.py +13 -0
  327. endoreg_db/models/{rules → rule}/rule.py +6 -3
  328. endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +0 -2
  329. endoreg_db/models/{rules → rule}/rule_type.py +0 -2
  330. endoreg_db/models/{rules → rule}/ruleset.py +0 -2
  331. endoreg_db/models/state/__init__.py +12 -0
  332. endoreg_db/models/state/abstract.py +11 -0
  333. endoreg_db/models/state/audit_ledger.py +150 -0
  334. endoreg_db/models/state/label_video_segment.py +22 -0
  335. endoreg_db/models/state/raw_pdf.py +187 -0
  336. endoreg_db/models/state/sensitive_meta.py +46 -0
  337. endoreg_db/models/state/video.py +232 -0
  338. endoreg_db/models/upload_job.py +99 -0
  339. endoreg_db/models/utils.py +135 -0
  340. endoreg_db/models/video_metadata.py +66 -0
  341. endoreg_db/models/video_processing.py +153 -0
  342. endoreg_db/renames.yml +8 -0
  343. endoreg_db/root_urls.py +9 -0
  344. endoreg_db/schemas/__init__.py +0 -0
  345. endoreg_db/schemas/examination_evaluation.py +27 -0
  346. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
  347. endoreg_db/serializers/__init__.py +147 -10
  348. endoreg_db/serializers/{raw_pdf_meta_validation.py → _old/raw_pdf_meta_validation.py} +3 -3
  349. endoreg_db/serializers/{raw_video_meta_validation.py → _old/raw_video_meta_validation.py} +18 -14
  350. endoreg_db/serializers/_old/video.py +71 -0
  351. endoreg_db/serializers/administration/__init__.py +14 -0
  352. endoreg_db/serializers/administration/ai/__init__.py +10 -0
  353. endoreg_db/serializers/administration/ai/active_model.py +10 -0
  354. endoreg_db/serializers/administration/ai/ai_model.py +18 -0
  355. endoreg_db/serializers/administration/ai/model_type.py +10 -0
  356. endoreg_db/serializers/administration/center.py +9 -0
  357. endoreg_db/serializers/administration/gender.py +9 -0
  358. endoreg_db/serializers/anonymization.py +66 -0
  359. endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
  360. endoreg_db/serializers/examination/__init__.py +10 -0
  361. endoreg_db/serializers/examination/base.py +46 -0
  362. endoreg_db/serializers/examination/dropdown.py +21 -0
  363. endoreg_db/serializers/examination_serializer.py +12 -0
  364. endoreg_db/serializers/finding/__init__.py +5 -0
  365. endoreg_db/serializers/finding/finding.py +54 -0
  366. endoreg_db/serializers/finding_classification/__init__.py +7 -0
  367. endoreg_db/serializers/finding_classification/choice.py +19 -0
  368. endoreg_db/serializers/finding_classification/classification.py +13 -0
  369. endoreg_db/serializers/label/__init__.py +7 -0
  370. endoreg_db/serializers/label/image_classification_annotation.py +62 -0
  371. endoreg_db/serializers/label/label.py +15 -0
  372. endoreg_db/serializers/label_video_segment/__init__.py +7 -0
  373. endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
  374. endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
  375. endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
  376. endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
  377. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
  378. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
  379. endoreg_db/serializers/meta/__init__.py +19 -0
  380. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
  381. endoreg_db/serializers/meta/report_meta.py +53 -0
  382. endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
  383. endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
  384. endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -0
  385. endoreg_db/serializers/meta/video_meta.py +39 -0
  386. endoreg_db/serializers/misc/__init__.py +14 -0
  387. endoreg_db/serializers/misc/file_overview.py +152 -0
  388. endoreg_db/serializers/misc/stats.py +33 -0
  389. endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
  390. endoreg_db/serializers/misc/upload_job.py +71 -0
  391. endoreg_db/serializers/misc/vop_patient_data.py +120 -0
  392. endoreg_db/serializers/patient/__init__.py +11 -0
  393. endoreg_db/serializers/patient/patient.py +86 -0
  394. endoreg_db/serializers/patient/patient_dropdown.py +27 -0
  395. endoreg_db/serializers/patient_examination/__init__.py +7 -0
  396. endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
  397. endoreg_db/serializers/patient_finding/__init__.py +15 -0
  398. endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
  399. endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
  400. endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
  401. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
  402. endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
  403. endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
  404. endoreg_db/serializers/pdf/__init__.py +5 -0
  405. endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
  406. endoreg_db/serializers/report/__init__.py +9 -0
  407. endoreg_db/serializers/report/mixins.py +45 -0
  408. endoreg_db/serializers/report/report.py +105 -0
  409. endoreg_db/serializers/report/report_list.py +22 -0
  410. endoreg_db/serializers/report/secure_file_url.py +26 -0
  411. endoreg_db/serializers/requirements/requirement_schema.py +25 -0
  412. endoreg_db/serializers/requirements/requirement_sets.py +29 -0
  413. endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
  414. endoreg_db/serializers/video/__init__.py +7 -0
  415. endoreg_db/serializers/video/segmentation.py +263 -0
  416. endoreg_db/serializers/video/video_file_brief.py +10 -0
  417. endoreg_db/serializers/video/video_file_detail.py +83 -0
  418. endoreg_db/serializers/video/video_file_list.py +67 -0
  419. endoreg_db/serializers/video/video_metadata.py +105 -0
  420. endoreg_db/serializers/video/video_processing_history.py +153 -0
  421. endoreg_db/services/__init__.py +5 -0
  422. endoreg_db/services/anonymization.py +223 -0
  423. endoreg_db/services/examination_evaluation.py +149 -0
  424. endoreg_db/services/finding_description_service.py +0 -0
  425. endoreg_db/services/lookup_service.py +241 -0
  426. endoreg_db/services/lookup_store.py +122 -0
  427. endoreg_db/services/ollama_api_docs.py +1528 -0
  428. endoreg_db/services/pdf_import.py +993 -0
  429. endoreg_db/services/polling_coordinator.py +288 -0
  430. endoreg_db/services/pseudonym_service.py +89 -0
  431. endoreg_db/services/requirements_object.py +147 -0
  432. endoreg_db/services/segment_sync.py +155 -0
  433. endoreg_db/services/storage_aware_video_processor.py +344 -0
  434. endoreg_db/services/video_import.py +915 -0
  435. endoreg_db/tasks/upload_tasks.py +207 -0
  436. endoreg_db/tasks/video_ingest.py +157 -0
  437. endoreg_db/tasks/video_processing_tasks.py +327 -0
  438. endoreg_db/urls/__init__.py +72 -0
  439. endoreg_db/urls/anonymization.py +32 -0
  440. endoreg_db/urls/auth.py +16 -0
  441. endoreg_db/urls/classification.py +39 -0
  442. endoreg_db/urls/examination.py +54 -0
  443. endoreg_db/urls/files.py +6 -0
  444. endoreg_db/urls/label_video_segment_validate.py +33 -0
  445. endoreg_db/urls/label_video_segments.py +44 -0
  446. endoreg_db/urls/media.py +32 -0
  447. endoreg_db/urls/patient.py +19 -0
  448. endoreg_db/urls/pdf.py +0 -0
  449. endoreg_db/urls/report.py +78 -0
  450. endoreg_db/urls/requirements.py +13 -0
  451. endoreg_db/urls/sensitive_meta.py +36 -0
  452. endoreg_db/urls/stats.py +46 -0
  453. endoreg_db/urls/upload.py +20 -0
  454. endoreg_db/urls/video.py +119 -0
  455. endoreg_db/urls.py +6 -283
  456. endoreg_db/utils/__init__.py +66 -57
  457. endoreg_db/utils/ai/__init__.py +9 -0
  458. endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +1 -4
  459. endoreg_db/{models/ai_model/lightning → utils/ai}/inference_dataset.py +0 -1
  460. endoreg_db/{models/ai_model/lightning → utils/ai}/multilabel_classification_net.py +14 -10
  461. endoreg_db/{models/ai_model/lightning → utils/ai}/postprocess.py +15 -5
  462. endoreg_db/utils/ai/predict.py +291 -0
  463. endoreg_db/{models/ai_model/lightning → utils/ai}/preprocess.py +1 -1
  464. endoreg_db/utils/calc_duration_seconds.py +24 -0
  465. endoreg_db/utils/case_generator/__init__.py +0 -0
  466. endoreg_db/utils/check_video_files.py +148 -0
  467. endoreg_db/utils/dataloader.py +50 -12
  468. endoreg_db/utils/dates.py +21 -0
  469. endoreg_db/utils/env.py +33 -0
  470. endoreg_db/utils/extract_specific_frames.py +72 -0
  471. endoreg_db/utils/file_operations.py +29 -1
  472. endoreg_db/utils/fix_video_path_direct.py +141 -0
  473. endoreg_db/utils/frame_anonymization_utils.py +463 -0
  474. endoreg_db/utils/links/__init__.py +0 -0
  475. endoreg_db/utils/links/requirement_link.py +193 -0
  476. endoreg_db/utils/mime_types.py +0 -0
  477. endoreg_db/utils/names.py +2 -0
  478. endoreg_db/utils/paths.py +100 -82
  479. endoreg_db/utils/permissions.py +143 -0
  480. endoreg_db/utils/pipelines/Readme.md +235 -0
  481. endoreg_db/utils/pipelines/__init__.py +0 -0
  482. endoreg_db/utils/pipelines/process_video_dir.py +120 -0
  483. endoreg_db/utils/product/__init__.py +0 -0
  484. endoreg_db/utils/product/sum_emissions.py +20 -0
  485. endoreg_db/utils/product/sum_weights.py +18 -0
  486. endoreg_db/utils/pydantic_models/db_config.py +1 -1
  487. endoreg_db/utils/requirement_helpers.py +0 -0
  488. endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
  489. endoreg_db/utils/requirement_operator_logic/lab_value_operators.py +578 -0
  490. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
  491. endoreg_db/utils/translation.py +27 -0
  492. endoreg_db/utils/validate_video_detailed.py +357 -0
  493. endoreg_db/utils/video/__init__.py +19 -6
  494. endoreg_db/utils/video/extract_frames.py +37 -70
  495. endoreg_db/utils/video/ffmpeg_wrapper.py +772 -0
  496. endoreg_db/utils/video/names.py +42 -0
  497. endoreg_db/utils/video/streaming_processor.py +312 -0
  498. endoreg_db/utils/video/video_splitter.py +94 -0
  499. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
  500. endoreg_db/views/__init__.py +282 -2
  501. endoreg_db/views/anonymization/__init__.py +27 -0
  502. endoreg_db/views/anonymization/media_management.py +454 -0
  503. endoreg_db/views/anonymization/overview.py +216 -0
  504. endoreg_db/views/anonymization/validate.py +63 -0
  505. endoreg_db/views/auth/__init__.py +13 -0
  506. endoreg_db/views/{views.py → auth/keycloak.py} +19 -13
  507. endoreg_db/views/examination/__init__.py +33 -0
  508. endoreg_db/views/examination/examination.py +37 -0
  509. endoreg_db/views/examination/examination_manifest_cache.py +26 -0
  510. endoreg_db/views/examination/get_finding_classification_choices.py +59 -0
  511. endoreg_db/views/examination/get_finding_classifications.py +36 -0
  512. endoreg_db/views/examination/get_findings.py +41 -0
  513. endoreg_db/views/examination/get_instruments.py +18 -0
  514. endoreg_db/views/examination/get_interventions.py +14 -0
  515. endoreg_db/views/finding/__init__.py +9 -0
  516. endoreg_db/views/finding/finding.py +112 -0
  517. endoreg_db/views/finding/get_classifications.py +14 -0
  518. endoreg_db/views/finding/get_interventions.py +17 -0
  519. endoreg_db/views/finding_classification/__init__.py +13 -0
  520. endoreg_db/views/finding_classification/base.py +0 -0
  521. endoreg_db/views/finding_classification/finding_classification.py +42 -0
  522. endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
  523. endoreg_db/views/label/__init__.py +5 -0
  524. endoreg_db/views/label/label.py +15 -0
  525. endoreg_db/views/label_video_segment/__init__.py +16 -0
  526. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
  527. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
  528. endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
  529. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
  530. endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
  531. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
  532. endoreg_db/views/label_video_segment/validate.py +226 -0
  533. endoreg_db/views/media/__init__.py +9 -0
  534. endoreg_db/views/media/pdf_media.py +386 -0
  535. endoreg_db/views/media/video_media.py +272 -0
  536. endoreg_db/views/meta/__init__.py +15 -0
  537. endoreg_db/views/meta/available_files_list.py +146 -0
  538. endoreg_db/views/meta/report_meta.py +53 -0
  539. endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
  540. endoreg_db/views/meta/sensitive_meta_list.py +104 -0
  541. endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
  542. endoreg_db/views/misc/__init__.py +63 -0
  543. endoreg_db/views/misc/center.py +13 -0
  544. endoreg_db/views/misc/gender.py +14 -0
  545. endoreg_db/views/misc/secure_file_serving_view.py +80 -0
  546. endoreg_db/views/misc/secure_file_url_view.py +84 -0
  547. endoreg_db/views/misc/secure_url_validate.py +79 -0
  548. endoreg_db/views/misc/stats.py +220 -0
  549. endoreg_db/views/misc/translation.py +182 -0
  550. endoreg_db/views/misc/upload_views.py +240 -0
  551. endoreg_db/views/patient/__init__.py +5 -0
  552. endoreg_db/views/patient/patient.py +210 -0
  553. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
  554. endoreg_db/views/patient_examination/__init__.py +11 -0
  555. endoreg_db/views/patient_examination/patient_examination.py +140 -0
  556. endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
  557. endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
  558. endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
  559. endoreg_db/views/patient_examination/video.py +194 -0
  560. endoreg_db/views/patient_finding/__init__.py +7 -0
  561. endoreg_db/views/patient_finding/base.py +0 -0
  562. endoreg_db/views/patient_finding/patient_finding.py +64 -0
  563. endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
  564. endoreg_db/views/patient_finding_classification/__init__.py +5 -0
  565. endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
  566. endoreg_db/views/patient_finding_location/__init__.py +5 -0
  567. endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
  568. endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
  569. endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
  570. endoreg_db/views/pdf/__init__.py +11 -0
  571. endoreg_db/views/pdf/pdf_media.py +239 -0
  572. endoreg_db/views/pdf/pdf_stream_views.py +127 -0
  573. endoreg_db/views/pdf/reimport.py +151 -0
  574. endoreg_db/views/report/__init__.py +9 -0
  575. endoreg_db/views/report/report_list.py +112 -0
  576. endoreg_db/views/report/report_with_secure_url.py +28 -0
  577. endoreg_db/views/report/start_examination.py +7 -0
  578. endoreg_db/views/requirement/__init__.py +10 -0
  579. endoreg_db/views/requirement/evaluate.py +279 -0
  580. endoreg_db/views/requirement/lookup.py +483 -0
  581. endoreg_db/views/requirement/lookup_store.py +252 -0
  582. endoreg_db/views/requirement_lookup/lookup.py +0 -0
  583. endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
  584. endoreg_db/views/stats/__init__.py +13 -0
  585. endoreg_db/views/stats/stats_views.py +229 -0
  586. endoreg_db/views/video/__init__.py +72 -0
  587. endoreg_db/views/video/correction.py +672 -0
  588. endoreg_db/views/video/media/__init__.py +23 -0
  589. endoreg_db/views/video/media/task_status.py +49 -0
  590. endoreg_db/views/video/media/video_analyze.py +52 -0
  591. endoreg_db/views/video/media/video_apply_mask.py +48 -0
  592. endoreg_db/views/video/media/video_correction.py +21 -0
  593. endoreg_db/views/video/media/video_download_processed.py +58 -0
  594. endoreg_db/views/video/media/video_media.py +158 -0
  595. endoreg_db/views/video/media/video_meta.py +29 -0
  596. endoreg_db/views/video/media/video_processing_history.py +24 -0
  597. endoreg_db/views/video/media/video_remove_frames.py +48 -0
  598. endoreg_db/views/video/media/video_reprocess.py +40 -0
  599. endoreg_db/views/video/reimport.py +192 -0
  600. endoreg_db/views/video/segmentation.py +274 -0
  601. endoreg_db/views/{views_for_timeline.py → video/timeline.py} +3 -3
  602. endoreg_db/views/video/video_examination_viewset.py +329 -0
  603. endoreg_db/views/video/video_stream.py +188 -0
  604. endoreg_db-0.8.1.dist-info/METADATA +384 -0
  605. endoreg_db-0.8.1.dist-info/RECORD +789 -0
  606. endoreg_db/data/agl_service/data.yaml +0 -19
  607. endoreg_db/data/finding_location_classification/colonoscopy.yaml +0 -46
  608. endoreg_db/data/finding_morphology_classification/colonoscopy.yaml +0 -48
  609. endoreg_db/data/finding_morphology_classification_choice/colonoscopy_size.yaml +0 -57
  610. endoreg_db/management/commands/_load_model_template.py +0 -41
  611. endoreg_db/management/commands/delete_all.py +0 -18
  612. endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
  613. endoreg_db/management/commands/fix_auth_permission.py +0 -20
  614. endoreg_db/management/commands/load_active_model_data.py +0 -45
  615. endoreg_db/management/commands/load_g_play_data.py +0 -113
  616. endoreg_db/management/commands/load_logging_data.py +0 -39
  617. endoreg_db/management/commands/load_lx_data.py +0 -64
  618. endoreg_db/management/commands/load_medication_indication_data.py +0 -63
  619. endoreg_db/management/commands/load_medication_indication_type_data.py +0 -41
  620. endoreg_db/management/commands/load_medication_intake_time_data.py +0 -41
  621. endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
  622. endoreg_db/management/commands/load_network_data.py +0 -57
  623. endoreg_db/migrations/0002_alter_frame_image_alter_rawframe_image.py +0 -23
  624. endoreg_db/migrations/0003_alter_frame_image_alter_rawframe_image.py +0 -23
  625. endoreg_db/migrations/0004_alter_rawvideofile_file_alter_video_file.py +0 -25
  626. endoreg_db/migrations/0005_rawvideofile_frame_count_and_more.py +0 -33
  627. endoreg_db/migrations/0006_frame_extracted_rawframe_extracted.py +0 -23
  628. endoreg_db/migrations/0007_rename_pseudo_patient_video_patient_and_more.py +0 -24
  629. endoreg_db/migrations/0008_remove_reportfile_patient_examination_and_more.py +0 -48
  630. endoreg_db/migrations/0009_requirementoperator_requirementsettype_and_more.py +0 -154
  631. endoreg_db/models/ai_model/active_model.py +0 -9
  632. endoreg_db/models/ai_model/ai_model.py +0 -90
  633. endoreg_db/models/ai_model/lightning/__init__.py +0 -3
  634. endoreg_db/models/ai_model/lightning/predict.py +0 -172
  635. endoreg_db/models/ai_model/lightning/prediction_visualizer.py +0 -55
  636. endoreg_db/models/ai_model/lightning/run_visualizer.py +0 -21
  637. endoreg_db/models/ai_model/model_meta.py +0 -240
  638. endoreg_db/models/annotation/__init__.py +0 -32
  639. endoreg_db/models/annotation/anonymized_image_annotation.py +0 -115
  640. endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -117
  641. endoreg_db/models/annotation/image_classification.py +0 -86
  642. endoreg_db/models/annotation/video_segmentation_annotation.py +0 -52
  643. endoreg_db/models/case/__init__.py +0 -1
  644. endoreg_db/models/case/case.py +0 -34
  645. endoreg_db/models/center/center.py +0 -51
  646. endoreg_db/models/center/center_product.py +0 -33
  647. endoreg_db/models/center/center_waste.py +0 -16
  648. endoreg_db/models/data_file/__init__.py +0 -39
  649. endoreg_db/models/data_file/base_classes/__init__.py +0 -7
  650. endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -98
  651. endoreg_db/models/data_file/base_classes/abstract_pdf.py +0 -127
  652. endoreg_db/models/data_file/base_classes/abstract_video.py +0 -806
  653. endoreg_db/models/data_file/base_classes/frame_helpers.py +0 -17
  654. endoreg_db/models/data_file/base_classes/prepare_bulk_frames.py +0 -19
  655. endoreg_db/models/data_file/base_classes/utils.py +0 -58
  656. endoreg_db/models/data_file/frame.py +0 -29
  657. endoreg_db/models/data_file/import_classes/__init__.py +0 -18
  658. endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
  659. endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
  660. endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
  661. endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -254
  662. endoreg_db/models/data_file/import_classes/raw_video.py +0 -290
  663. endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -290
  664. endoreg_db/models/data_file/metadata/video_meta.py +0 -199
  665. endoreg_db/models/data_file/report_file.py +0 -56
  666. endoreg_db/models/data_file/video/__init__.py +0 -11
  667. endoreg_db/models/data_file/video/import_meta.py +0 -25
  668. endoreg_db/models/data_file/video/video.py +0 -196
  669. endoreg_db/models/data_file/video_segment.py +0 -214
  670. endoreg_db/models/examination/examination.py +0 -67
  671. endoreg_db/models/finding/__init__.py +0 -11
  672. endoreg_db/models/finding/finding.py +0 -75
  673. endoreg_db/models/finding/finding_location_classification.py +0 -94
  674. endoreg_db/models/finding/finding_morphology_classification.py +0 -89
  675. endoreg_db/models/finding/finding_type.py +0 -22
  676. endoreg_db/models/hardware/__init__.py +0 -2
  677. endoreg_db/models/information_source.py +0 -65
  678. endoreg_db/models/laboratory/__init__.py +0 -1
  679. endoreg_db/models/laboratory/lab_value.py +0 -162
  680. endoreg_db/models/logging/__init__.py +0 -11
  681. endoreg_db/models/logging/agl_service.py +0 -19
  682. endoreg_db/models/logging/base.py +0 -22
  683. endoreg_db/models/logging/log_type.py +0 -23
  684. endoreg_db/models/logging/network_device.py +0 -27
  685. endoreg_db/models/lx/__init__.py +0 -4
  686. endoreg_db/models/lx/client.py +0 -57
  687. endoreg_db/models/lx/identity.py +0 -34
  688. endoreg_db/models/lx/permission.py +0 -18
  689. endoreg_db/models/lx/user.py +0 -16
  690. endoreg_db/models/network/__init__.py +0 -9
  691. endoreg_db/models/network/agl_service.py +0 -38
  692. endoreg_db/models/network/network_device.py +0 -58
  693. endoreg_db/models/network/network_device_type.py +0 -23
  694. endoreg_db/models/other/distribution.py +0 -5
  695. endoreg_db/models/patient/__init__.py +0 -24
  696. endoreg_db/models/patient/patient_examination.py +0 -182
  697. endoreg_db/models/patient/patient_finding.py +0 -143
  698. endoreg_db/models/patient/patient_finding_location.py +0 -120
  699. endoreg_db/models/patient/patient_finding_morphology.py +0 -166
  700. endoreg_db/models/permissions/__init__.py +0 -44
  701. endoreg_db/models/persons/__init__.py +0 -34
  702. endoreg_db/models/persons/examiner/__init__.py +0 -2
  703. endoreg_db/models/persons/examiner/examiner.py +0 -60
  704. endoreg_db/models/persons/examiner/examiner_type.py +0 -2
  705. endoreg_db/models/persons/patient/__init__.py +0 -8
  706. endoreg_db/models/persons/patient/patient.py +0 -389
  707. endoreg_db/models/persons/patient/patient_disease.py +0 -22
  708. endoreg_db/models/persons/patient/patient_event.py +0 -52
  709. endoreg_db/models/persons/patient/patient_lab_sample.py +0 -108
  710. endoreg_db/models/persons/patient/patient_medication.py +0 -59
  711. endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -88
  712. endoreg_db/models/persons/portal_user_information.py +0 -27
  713. endoreg_db/models/prediction/__init__.py +0 -8
  714. endoreg_db/models/prediction/image_classification.py +0 -51
  715. endoreg_db/models/prediction/video_prediction_meta.py +0 -306
  716. endoreg_db/models/product/product.py +0 -110
  717. endoreg_db/models/product/product_group.py +0 -27
  718. endoreg_db/models/product/product_material.py +0 -28
  719. endoreg_db/models/questionnaires/__init__.py +0 -114
  720. endoreg_db/models/quiz/__init__.py +0 -9
  721. endoreg_db/models/quiz/quiz_answer.py +0 -41
  722. endoreg_db/models/quiz/quiz_question.py +0 -54
  723. endoreg_db/models/report_reader/report_reader_config.py +0 -53
  724. endoreg_db/models/rules/__init__.py +0 -5
  725. endoreg_db/queries/get/__init__.py +0 -6
  726. endoreg_db/queries/get/center.py +0 -42
  727. endoreg_db/queries/get/model.py +0 -13
  728. endoreg_db/queries/get/patient.py +0 -14
  729. endoreg_db/queries/get/patient_examination.py +0 -20
  730. endoreg_db/queries/get/report_file.py +0 -33
  731. endoreg_db/queries/get/video.py +0 -31
  732. endoreg_db/serializers/ai_model.py +0 -19
  733. endoreg_db/serializers/annotation.py +0 -14
  734. endoreg_db/serializers/center.py +0 -11
  735. endoreg_db/serializers/examination.py +0 -33
  736. endoreg_db/serializers/frame.py +0 -9
  737. endoreg_db/serializers/hardware.py +0 -21
  738. endoreg_db/serializers/label.py +0 -22
  739. endoreg_db/serializers/patient.py +0 -33
  740. endoreg_db/serializers/prediction.py +0 -10
  741. endoreg_db/serializers/raw_pdf_anony_text_validation.py +0 -137
  742. endoreg_db/serializers/report_file.py +0 -7
  743. endoreg_db/serializers/video.py +0 -20
  744. endoreg_db/serializers/video_segmentation.py +0 -574
  745. endoreg_db/tests.py +0 -3
  746. endoreg_db/utils/legacy_ocr.py +0 -201
  747. endoreg_db/utils/video/transcode_videofile.py +0 -111
  748. endoreg_db/views/patient_views.py +0 -90
  749. endoreg_db/views/raw_pdf_anony_text_validation_views.py +0 -95
  750. endoreg_db/views/raw_pdf_meta_validation_views.py +0 -111
  751. endoreg_db/views/raw_video_meta_validation_views.py +0 -148
  752. endoreg_db/views/report_views.py +0 -96
  753. endoreg_db/views/video_segmentation_views.py +0 -166
  754. endoreg_db-0.6.4.dist-info/METADATA +0 -161
  755. endoreg_db-0.6.4.dist-info/RECORD +0 -470
  756. /endoreg_db/{case_generator/__init__.py → api/serializers/finding_descriptions.py} +0 -0
  757. /endoreg_db/{queries/get/annotation.py → api/views/finding_descriptions.py} +0 -0
  758. /endoreg_db/{queries/get/prediction.py → data/shift/m2.yaml} +0 -0
  759. /endoreg_db/{queries/get/video_import_meta.py → factories/__init__.py} +0 -0
  760. /endoreg_db/{queries/get/video_prediction_meta.py → helpers/__init__.py} +0 -0
  761. /endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +0 -0
  762. /endoreg_db/models/{persons → administration/person}/person.py +0 -0
  763. /endoreg_db/models/{product → administration/product}/__init__.py +0 -0
  764. /endoreg_db/models/{report_reader → media/pdf/report_reader}/__init__.py +0 -0
  765. /endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +0 -0
  766. /endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +0 -0
  767. /endoreg_db/models/{medication → medical/medication}/__init__.py +0 -0
  768. /endoreg_db/models/{medication → medical/medication}/medication_indication.py +0 -0
  769. /endoreg_db/models/{risk → medical/risk}/__init__.py +0 -0
  770. /endoreg_db/models/{risk → medical/risk}/risk.py +0 -0
  771. /endoreg_db/models/{emission → other/emission}/__init__.py +0 -0
  772. /endoreg_db/models/{rules → rule}/rule_applicator.py +0 -0
  773. /endoreg_db/{case_generator → utils/case_generator}/case_generator.py +0 -0
  774. /endoreg_db/{case_generator → utils/case_generator}/lab_sample_factory.py +0 -0
  775. /endoreg_db/{case_generator → utils/case_generator}/utils.py +0 -0
  776. /endoreg_db/views/{csrf.py → misc/csrf.py} +0 -0
  777. {endoreg_db-0.6.4.dist-info → endoreg_db-0.8.1.dist-info}/WHEEL +0 -0
  778. {endoreg_db-0.6.4.dist-info → endoreg_db-0.8.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,70 @@
1
+ from endoreg_db.serializers.patient_finding.patient_finding import PatientFindingSerializer
2
+ from rest_framework.viewsets import ModelViewSet
3
+ from rest_framework.decorators import api_view, permission_classes
4
+ from rest_framework.response import Response
5
+ from rest_framework import status
6
+ from endoreg_db.models.medical.patient.patient_finding import PatientFinding
7
+ from endoreg_db.models.medical.patient.patient_finding_location import PatientFindingLocation
8
+ from endoreg_db.models.medical.patient.patient_finding_morphology import PatientFindingMorphology
9
+ from endoreg_db.models import ( FindingLocationClassificationChoice, FindingMorphologyClassificationChoice )
10
+ from rest_framework import serializers
11
+ from utils.permissions import EnvironmentAwarePermission
12
+
13
+ class PatientFindingViewSet(ModelViewSet):
14
+ queryset = PatientFinding.objects.all()
15
+ serializer_class = PatientFindingSerializer
16
+
17
+ @api_view(['POST'])
18
+ @permission_classes([EnvironmentAwarePermission])
19
+ def create_patient_finding_location(request):
20
+ """
21
+ Create a patient finding location relationship.
22
+ Expected payload: {
23
+ "patient_finding_id": 1,
24
+ "location_classification_choice_id": 2
25
+ }
26
+ """
27
+ try:
28
+ patient_finding_id = request.data.get('patient_finding_id')
29
+ choice_id = request.data.get('location_classification_choice_id')
30
+
31
+ if not patient_finding_id or not choice_id:
32
+ return Response(
33
+ {'detail': 'patient_finding_id and location_classification_choice_id are required'},
34
+ status=status.HTTP_400_BAD_REQUEST
35
+ )
36
+
37
+ # Get the objects
38
+ try:
39
+ patient_finding = PatientFinding.objects.get(id=patient_finding_id)
40
+ except PatientFinding.DoesNotExist:
41
+ return Response(
42
+ {'detail': f'PatientFinding with id {patient_finding_id} not found'},
43
+ status=status.HTTP_404_NOT_FOUND
44
+ )
45
+
46
+ try:
47
+ choice = FindingLocationClassificationChoice.objects.get(id=choice_id)
48
+ except FindingLocationClassificationChoice.DoesNotExist:
49
+ return Response(
50
+ {'detail': f'LocationClassificationChoice with id {choice_id} not found'},
51
+ status=status.HTTP_404_NOT_FOUND
52
+ )
53
+
54
+ # Create the relationship
55
+ patient_finding_location = PatientFindingLocation.objects.create(
56
+ patient_finding=patient_finding,
57
+ location_classification_choice=choice
58
+ )
59
+
60
+ return Response({
61
+ 'id': patient_finding_location.id,
62
+ 'patient_finding_id': patient_finding.id,
63
+ 'location_classification_choice_id': choice.id
64
+ }, status=status.HTTP_201_CREATED)
65
+
66
+ except Exception as e:
67
+ return Response(
68
+ {'detail': f'Error creating patient finding location: {str(e)}'},
69
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR
70
+ )
@@ -0,0 +1,5 @@
1
+ from .pfm_create import create_patient_finding_morphology
2
+
3
+ __all__ = [
4
+ "create_patient_finding_morphology",
5
+ ]
@@ -0,0 +1,70 @@
1
+ from endoreg_db.serializers.patient_finding.patient_finding import PatientFindingSerializer
2
+ from rest_framework.viewsets import ModelViewSet
3
+ from rest_framework.decorators import api_view, permission_classes
4
+ from rest_framework.response import Response
5
+ from rest_framework import status
6
+ from endoreg_db.models.medical.patient.patient_finding import PatientFinding
7
+ from endoreg_db.models.medical.patient.patient_finding_location import PatientFindingLocation
8
+ from endoreg_db.models.medical.patient.patient_finding_morphology import PatientFindingMorphology
9
+ from endoreg_db.models import ( FindingLocationClassificationChoice, FindingMorphologyClassificationChoice)
10
+ from rest_framework import serializers
11
+ from utils.permissions import EnvironmentAwarePermission
12
+
13
+ class PatientFindingViewSet(ModelViewSet):
14
+ queryset = PatientFinding.objects.all()
15
+ serializer_class = PatientFindingSerializer
16
+
17
+ @api_view(['POST'])
18
+ @permission_classes([EnvironmentAwarePermission])
19
+ def create_patient_finding_morphology(request):
20
+ """
21
+ Create a patient finding morphology relationship.
22
+ Expected payload: {
23
+ "patient_finding_id": 1,
24
+ "morphology_classification_choice_id": 2
25
+ }
26
+ """
27
+ try:
28
+ patient_finding_id = request.data.get('patient_finding_id')
29
+ choice_id = request.data.get('morphology_classification_choice_id')
30
+
31
+ if not patient_finding_id or not choice_id:
32
+ return Response(
33
+ {'detail': 'patient_finding_id and morphology_classification_choice_id are required'},
34
+ status=status.HTTP_400_BAD_REQUEST
35
+ )
36
+
37
+ # Get the objects
38
+ try:
39
+ patient_finding = PatientFinding.objects.get(id=patient_finding_id)
40
+ except PatientFinding.DoesNotExist:
41
+ return Response(
42
+ {'detail': f'PatientFinding with id {patient_finding_id} not found'},
43
+ status=status.HTTP_404_NOT_FOUND
44
+ )
45
+
46
+ try:
47
+ choice = FindingMorphologyClassificationChoice.objects.get(id=choice_id)
48
+ except FindingMorphologyClassificationChoice.DoesNotExist:
49
+ return Response(
50
+ {'detail': f'MorphologyClassificationChoice with id {choice_id} not found'},
51
+ status=status.HTTP_404_NOT_FOUND
52
+ )
53
+
54
+ # Create the relationship
55
+ patient_finding_morphology = PatientFindingMorphology.objects.create(
56
+ patient_finding=patient_finding,
57
+ morphology_classification_choice=choice
58
+ )
59
+
60
+ return Response({
61
+ 'id': patient_finding_morphology.id,
62
+ 'patient_finding_id': patient_finding.id,
63
+ 'morphology_classification_choice_id': choice.id
64
+ }, status=status.HTTP_201_CREATED)
65
+
66
+ except Exception as e:
67
+ return Response(
68
+ {'detail': f'Error creating patient finding morphology: {str(e)}'},
69
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR
70
+ )
@@ -0,0 +1,11 @@
1
+ from .pdf_media import (
2
+ PDFMediaView,
3
+ UpdateSensitiveMetaView,
4
+ ClosingFileWrapper
5
+ )
6
+
7
+ __all__ = [
8
+ "PDFMediaView",
9
+ "UpdateSensitiveMetaView",
10
+ "ClosingFileWrapper",
11
+ ]
@@ -0,0 +1,239 @@
1
+ from django.http import FileResponse, Http404, StreamingHttpResponse
2
+ import mimetypes
3
+ import os
4
+ import logging
5
+ import re
6
+ from ...models import RawPdfFile
7
+ from ...serializers._old.raw_pdf_meta_validation import PDFFileForMetaSerializer, SensitiveMetaUpdateSerializer
8
+ from rest_framework.views import APIView
9
+ from rest_framework.response import Response
10
+ from rest_framework import status
11
+ from ...models import SensitiveMeta
12
+ from django.views.decorators.clickjacking import xframe_options_sameorigin
13
+ from django.utils.decorators import method_decorator
14
+ from django.db import transaction
15
+ from django.urls import reverse
16
+ from django.utils.encoding import iri_to_uri
17
+ from endoreg_db.utils.paths import PDF_DIR, STORAGE_DIR
18
+ from .pdf_stream_views import ClosingFileWrapper
19
+
20
+ logger = logging.getLogger(__name__)
21
+ _RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
22
+
23
+ class PDFMediaView(APIView):
24
+ """
25
+ Unified API for PDFs to support frontend flows:
26
+ - Without `id`: returns next PDF metadata (including anonymized_text) and stream URLs
27
+ - With `id`: streams the PDF (original by default; `?variant=anonymized` for anonymized)
28
+ - Integrates with Media Management expectations (clean deletion after validation is handled elsewhere)
29
+ """
30
+
31
+ def get(self, request):
32
+ """
33
+ Handles both:
34
+ - Fetching PDF metadata (if `id` is NOT provided)
35
+ - Streaming the actual PDF file (if `id` is provided)
36
+ """
37
+ pdf_id = request.GET.get("id")
38
+ last_id = request.GET.get("last_id")
39
+
40
+ if pdf_id:
41
+ return self.serve_pdf_file(pdf_id)
42
+ else:
43
+ return self.fetch_pdf_metadata(last_id)
44
+
45
+ def fetch_pdf_metadata(self, last_id):
46
+ """
47
+ Fetches the first or next available PDF metadata and provides stream URLs.
48
+ """
49
+ pdf_entry = PDFFileForMetaSerializer.get_next_pdf(last_id)
50
+ if pdf_entry is None:
51
+ return Response({"error": "No more PDFs available."}, status=status.HTTP_404_NOT_FOUND)
52
+
53
+ serialized_pdf = PDFFileForMetaSerializer(pdf_entry, context={'request': self.request})
54
+
55
+ # Build stream URLs pointing to this unified endpoint
56
+ try:
57
+ media_url = reverse('pdf_media')
58
+ except Exception:
59
+ media_url = "/api/pdf/media/"
60
+ stream_url = f"{media_url}?id={pdf_entry.id}"
61
+ anon_stream_url = f"{media_url}?id={pdf_entry.id}&variant=anonymized"
62
+
63
+ data = dict(serialized_pdf.data)
64
+ data.update({
65
+ 'stream_url': iri_to_uri(self.request.build_absolute_uri(stream_url)),
66
+ 'anonymized_stream_url': iri_to_uri(self.request.build_absolute_uri(anon_stream_url)),
67
+ 'pdf_id': pdf_entry.id,
68
+ 'has_anonymized': bool(getattr(pdf_entry, 'anonymized_file', None) and getattr(pdf_entry.anonymized_file, 'name', None)),
69
+ })
70
+ return Response(data, status=status.HTTP_200_OK)
71
+
72
+ @method_decorator(xframe_options_sameorigin)
73
+ def serve_pdf_file(self, pdf_id):
74
+ """
75
+ Streams the actual PDF file (original or anonymized) with Range support.
76
+ Query param `variant=anonymized` selects anonymized file; default is original.
77
+ """
78
+ variant = (self.request.GET.get('variant') or 'original').lower()
79
+ range_header = self.request.headers.get("Range")
80
+
81
+ try:
82
+ pdf_entry = RawPdfFile.objects.get(id=pdf_id)
83
+ except RawPdfFile.DoesNotExist:
84
+ return Response({"error": "Invalid PDF ID."}, status=status.HTTP_400_BAD_REQUEST)
85
+
86
+ # Choose file according to variant
87
+ file_field = None
88
+ if variant == 'anonymized' and getattr(pdf_entry, 'anonymized_file', None):
89
+ file_field = pdf_entry.anonymized_file
90
+ else:
91
+ file_field = pdf_entry.file
92
+
93
+ if not file_field:
94
+ return Response({"error": "PDF file not found."}, status=status.HTTP_404_NOT_FOUND)
95
+
96
+ # Resolve path and attempt self-heal for originals
97
+ try:
98
+ file_path = file_field.path
99
+ except Exception:
100
+ file_path = None
101
+
102
+ if not file_path or not os.path.exists(file_path):
103
+ if variant != 'anonymized':
104
+ # Try to self-heal original reference to sensitive storage
105
+ sensitive_path = os.path.join(str(PDF_DIR), "sensitive", f"{pdf_entry.pdf_hash}.pdf")
106
+ if os.path.exists(sensitive_path):
107
+ try:
108
+ relative_name = os.path.relpath(sensitive_path, str(STORAGE_DIR))
109
+ if getattr(pdf_entry.file, 'name', None) != relative_name:
110
+ pdf_entry.file.name = relative_name
111
+ pdf_entry.save(update_fields=['file'])
112
+ logger.info("Self-healed PDF file reference for ID %s -> %s", pdf_entry.id, pdf_entry.file.path)
113
+ file_path = sensitive_path
114
+ except Exception as e:
115
+ logger.error("Failed to self-heal file path for PDF %s: %s", pdf_entry.id, e)
116
+ file_path = sensitive_path
117
+ # If still missing (or anonymized missing), fail
118
+ if not file_path or not os.path.exists(file_path):
119
+ raise Http404("PDF file not found on server.")
120
+
121
+ # Prepare headers
122
+ safe_filename = os.path.basename(getattr(file_field, 'name', None) or f"document_{pdf_id}.pdf")
123
+ if not safe_filename.endswith('.pdf'):
124
+ safe_filename += '.pdf'
125
+
126
+ file_size = os.path.getsize(file_path)
127
+
128
+ # Range support
129
+ if range_header:
130
+ match = _RANGE_RE.match(range_header)
131
+ if match:
132
+ start = int(match.group(1))
133
+ end = int(match.group(2) or file_size - 1)
134
+
135
+ if start < 0 or start >= file_size:
136
+ raise Http404("Invalid range")
137
+ if end >= file_size:
138
+ end = file_size - 1
139
+
140
+ chunk_size = end - start + 1
141
+ try:
142
+ fh = open(file_path, 'rb')
143
+ fh.seek(start)
144
+ resp = StreamingHttpResponse(
145
+ ClosingFileWrapper(fh, blksize=8192),
146
+ status=206,
147
+ content_type="application/pdf",
148
+ )
149
+ resp["Content-Length"] = str(chunk_size)
150
+ resp["Content-Range"] = f"bytes {start}-{end}/{file_size}"
151
+ resp["Accept-Ranges"] = "bytes"
152
+ resp["Content-Disposition"] = f'inline; filename="{safe_filename}"'
153
+ return resp
154
+ except (OSError, IOError) as e:
155
+ logger.error(f"Error opening PDF file for range request: {e}")
156
+ raise Http404("Error accessing PDF file")
157
+
158
+ # Fallback: serve full file
159
+ mime_type, _ = mimetypes.guess_type(file_path)
160
+ try:
161
+ fh = open(file_path, 'rb')
162
+ response = FileResponse(fh, content_type=mime_type or "application/pdf")
163
+ response["Content-Length"] = str(file_size)
164
+ response["Accept-Ranges"] = "bytes"
165
+ response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
166
+ return response
167
+ except (OSError, IOError) as e:
168
+ logger.error(f"Error opening PDF file: {e}")
169
+ raise Http404("Error accessing PDF file")
170
+
171
+ class UpdateSensitiveMetaView(APIView):
172
+ """
173
+ API endpoint to update patient details in the SensitiveMeta table.
174
+ Handles partial updates (only edited fields) and raw file deletion after validation acceptance.
175
+ """
176
+
177
+ @transaction.atomic
178
+ def patch(self, request, *args, **kwargs):
179
+ """
180
+ Updates the provided fields for a specific patient record.
181
+ Only updates fields that are sent in the request.
182
+ Automatically deletes raw PDF files when validation is accepted.
183
+ """
184
+ sensitive_meta_id = request.data.get("sensitive_meta_id")
185
+
186
+ if not sensitive_meta_id:
187
+ return Response({"error": "sensitive_meta_id is required."}, status=status.HTTP_400_BAD_REQUEST)
188
+
189
+ try:
190
+ sensitive_meta = SensitiveMeta.objects.get(id=sensitive_meta_id)
191
+ except SensitiveMeta.DoesNotExist:
192
+ return Response({"error": "Patient record not found."}, status=status.HTTP_404_NOT_FOUND)
193
+
194
+ is_accepting_validation = request.data.get("is_verified", False)
195
+ delete_raw_files = request.data.get("delete_raw_files", False)
196
+ if is_accepting_validation:
197
+ delete_raw_files = True
198
+ logger.info(f"Validation accepted for PDF SensitiveMeta {sensitive_meta_id}, marking raw files for deletion")
199
+
200
+ serializer = SensitiveMetaUpdateSerializer(sensitive_meta, data=request.data, partial=True)
201
+
202
+ if serializer.is_valid():
203
+ updated_sm = serializer.save()
204
+ if delete_raw_files and updated_sm.is_verified:
205
+ try:
206
+ pdf_file = RawPdfFile.objects.filter(sensitive_meta=updated_sm).first()
207
+ if pdf_file:
208
+ self._schedule_raw_file_deletion(pdf_file)
209
+ logger.info(f"Scheduled raw file deletion for PDF {pdf_file.id}")
210
+ else:
211
+ logger.warning(f"No PDF file found for SensitiveMeta {sensitive_meta_id}")
212
+ except Exception as e:
213
+ logger.error(f"Error scheduling raw file deletion for PDF SensitiveMeta {sensitive_meta_id}: {e}")
214
+ return Response({"message": "Patient information updated successfully.", "updated_data": serializer.data}, status=status.HTTP_200_OK)
215
+
216
+ return Response({"error": "Invalid data.", "details": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
217
+
218
+ def _schedule_raw_file_deletion(self, pdf_file):
219
+ """
220
+ Schedule deletion of raw PDF file after validation acceptance.
221
+ Deletes the original (sensitive) file but keeps anonymized_file for frontend.
222
+ """
223
+ try:
224
+ def cleanup_raw_files():
225
+ try:
226
+ if pdf_file.file and getattr(pdf_file.file, 'path', None) and os.path.exists(pdf_file.file.path):
227
+ logger.info(f"Deleting original (sensitive) PDF file: {pdf_file.file.path}")
228
+ os.remove(pdf_file.file.path)
229
+ pdf_file.file = None
230
+ pdf_file.save(update_fields=['file'])
231
+ logger.info(f"Successfully deleted original file for PDF {pdf_file.id}")
232
+ else:
233
+ logger.info(f"Original file already deleted or not found for PDF {pdf_file.id}")
234
+ except Exception as e:
235
+ logger.error(f"Error during raw file cleanup for PDF {pdf_file.id}: {e}")
236
+ transaction.on_commit(cleanup_raw_files)
237
+ except Exception as e:
238
+ logger.error(f"Error scheduling raw file deletion for PDF {pdf_file.id}: {e}")
239
+ raise
@@ -0,0 +1,127 @@
1
+ import re
2
+ import logging
3
+ from django.http import FileResponse, StreamingHttpResponse, Http404
4
+ from rest_framework.views import APIView
5
+ from ...utils.permissions import EnvironmentAwarePermission
6
+ from endoreg_db.models import RawPdfFile
7
+ import os
8
+ from django.views.decorators.clickjacking import xframe_options_sameorigin
9
+
10
+ logger = logging.getLogger(__name__)
11
+ _RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
12
+
13
+ class ClosingFileWrapper:
14
+ """Custom file wrapper that ensures file is closed after streaming"""
15
+ def __init__(self, file_handle, blksize=8192):
16
+ self.file_handle = file_handle
17
+ self.blksize = blksize
18
+
19
+ def __iter__(self):
20
+ return self
21
+
22
+ def __next__(self):
23
+ data = self.file_handle.read(self.blksize)
24
+ if not data:
25
+ self.file_handle.close()
26
+ raise StopIteration
27
+ return data
28
+
29
+ def close(self):
30
+ if hasattr(self.file_handle, 'close'):
31
+ self.file_handle.close()
32
+
33
+ class PDFStreamView(APIView):
34
+ """
35
+ Streams a PDF file with correct HTTP range support and proper file handle management.
36
+ """
37
+ permission_classes = [EnvironmentAwarePermission]
38
+
39
+ @xframe_options_sameorigin
40
+ def get(self, request, pdf_id: int, *args, **kwargs):
41
+ try:
42
+ pdf_obj = RawPdfFile.objects.filter(pk=pdf_id).first()
43
+ if not pdf_obj or not pdf_obj.file:
44
+ logger.warning(f"PDF not found: ID {pdf_id}")
45
+ raise Http404("PDF not found")
46
+
47
+ # Check if file exists on filesystem
48
+ try:
49
+ file_path = pdf_obj.file.path
50
+ if not os.path.exists(file_path):
51
+ logger.error(f"PDF file does not exist on filesystem: {file_path}")
52
+ raise Http404("PDF file not found on filesystem")
53
+
54
+ file_size = os.path.getsize(file_path)
55
+ except (OSError, IOError, AttributeError) as e:
56
+ logger.error(f"Error accessing PDF file {pdf_id}: {e}")
57
+ raise Http404("PDF file not accessible")
58
+
59
+ # Generate safe filename
60
+ safe_filename = os.path.basename(pdf_obj.file.name) if pdf_obj.file.name else f"document_{pdf_id}.pdf"
61
+ if not safe_filename.endswith('.pdf'):
62
+ safe_filename += '.pdf'
63
+
64
+ # Handle Range requests
65
+ range_header = request.headers.get("Range")
66
+ if range_header:
67
+ logger.debug(f"Range request for PDF {pdf_id}: {range_header}")
68
+ match = _RANGE_RE.match(range_header)
69
+ if match:
70
+ start = int(match.group(1))
71
+ end = int(match.group(2) or file_size - 1)
72
+
73
+ # Validate range
74
+ if start >= file_size or start < 0:
75
+ logger.warning(f"Invalid range start {start} for file size {file_size}")
76
+ raise Http404("Invalid range")
77
+
78
+ if end >= file_size:
79
+ end = file_size - 1
80
+
81
+ chunk_size = end - start + 1
82
+
83
+ try:
84
+ file_handle = open(file_path, "rb")
85
+ file_handle.seek(start)
86
+
87
+ logger.debug(f"Serving PDF {pdf_id} range {start}-{end}/{file_size}")
88
+
89
+ response = StreamingHttpResponse(
90
+ ClosingFileWrapper(file_handle, blksize=8192),
91
+ status=206,
92
+ content_type="application/pdf",
93
+ )
94
+ response["Content-Length"] = str(chunk_size)
95
+ response["Content-Range"] = f"bytes {start}-{end}/{file_size}"
96
+ response["Accept-Ranges"] = "bytes"
97
+ response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
98
+
99
+ return response
100
+ except (OSError, IOError) as e:
101
+ logger.error(f"Error opening PDF file for range request: {e}")
102
+ raise Http404("Error accessing PDF file")
103
+ else:
104
+ logger.warning(f"Invalid Range header format: {range_header}")
105
+
106
+ # Serve entire file using FileResponse (automatically handles file closing)
107
+ logger.debug(f"Serving full PDF {pdf_id} ({file_size} bytes)")
108
+
109
+ try:
110
+ file_handle = open(file_path, "rb")
111
+ response = FileResponse(
112
+ file_handle,
113
+ content_type="application/pdf"
114
+ )
115
+ response["Content-Length"] = str(file_size)
116
+ response["Accept-Ranges"] = "bytes"
117
+ response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
118
+
119
+ # FileResponse will take ownership of file_handle and close it after response
120
+ return response
121
+ except (OSError, IOError) as e:
122
+ logger.error(f"Error opening PDF file: {e}")
123
+ raise Http404("Error accessing PDF file")
124
+
125
+ except Exception as e:
126
+ logger.error(f"Unexpected error streaming PDF {pdf_id}: {e}", exc_info=True)
127
+ raise Http404("Error streaming PDF")
@@ -0,0 +1,151 @@
1
+ from rest_framework.views import APIView
2
+ from rest_framework.response import Response
3
+ from rest_framework import status
4
+ import logging
5
+ from pathlib import Path
6
+ from django.db import transaction
7
+ from ...models import RawPdfFile, SensitiveMeta
8
+ from ...services.pdf_import import PdfImportService
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class PdfReimportView(APIView):
12
+ """
13
+ API endpoint to re-import a pdf file and regenerate metadata.
14
+ This is useful when OCR failed or metadata is incomplete.
15
+ """
16
+
17
+ def __init__(self, **kwargs):
18
+ super().__init__(**kwargs)
19
+ self.pdf_service = PdfImportService()
20
+
21
+ def post(self, request, pdf_id):
22
+ """
23
+ Re-import a pdf file to regenerate SensitiveMeta and other metadata.
24
+ Instead of creating a new pdf, this updates the existing one.
25
+ """
26
+ # Validate pdf_id parameter
27
+ if not pdf_id or not isinstance(pdf_id, int):
28
+ return Response(
29
+ {"error": "Invalid pdf ID provided."},
30
+ status=status.HTTP_400_BAD_REQUEST
31
+ )
32
+
33
+ try:
34
+ pdf = RawPdfFile.objects.get(id=pdf_id)
35
+ logger.info(f"Found PDF {pdf.uuid} (ID: {pdf_id}) for re-import")
36
+ except RawPdfFile.DoesNotExist:
37
+ logger.warning(f"PDF with ID {pdf_id} not found")
38
+ return Response(
39
+ {"error": f"PDF with ID {pdf_id} not found."},
40
+ status=status.HTTP_404_NOT_FOUND
41
+ )
42
+
43
+
44
+
45
+ # Check if the raw file actually exists on disk
46
+ raw_file_path = Path(pdf.file.path)
47
+ if not raw_file_path.exists():
48
+ logger.error(f"Raw file not found on disk: {raw_file_path}")
49
+ return Response(
50
+ {"error": f"PDF file not found on server: {raw_file_path.name}"},
51
+ status=status.HTTP_400_BAD_REQUEST
52
+ )
53
+
54
+ # Check if PDF has required relationships
55
+ if not pdf.center:
56
+ logger.warning(f"PDF {pdf.uuid} has no associated center")
57
+ return Response(
58
+ {"error": "Video has no associated center."},
59
+ status=status.HTTP_400_BAD_REQUEST
60
+ )
61
+
62
+ try:
63
+ logger.info(f"Starting in-place re-import for pdf {pdf.uuid} (ID: {pdf_id})")
64
+
65
+ with transaction.atomic():
66
+ # Clear existing metadata to force regeneration
67
+ old_meta_id = None
68
+ if pdf.sensitive_meta:
69
+ old_meta_id = pdf.sensitive_meta.id
70
+ logger.info(f"Clearing existing SensitiveMeta {old_meta_id} for pdf {pdf.uuid}")
71
+ pdf.sensitive_meta = None
72
+ pdf.save(update_fields=['sensitive_meta'])
73
+
74
+ # Delete the old SensitiveMeta record
75
+ try:
76
+ SensitiveMeta.objects.filter(id=old_meta_id).delete()
77
+ logger.info(f"Deleted old SensitiveMeta {old_meta_id}")
78
+ except Exception as e:
79
+ logger.warning(f"Could not delete old SensitiveMeta {old_meta_id}: {e}")
80
+
81
+
82
+
83
+
84
+
85
+ # Ensure minimum patient data is available
86
+ logger.info(f"Ensuring minimum patient data for {pdf.uuid}")
87
+ self.pdf_service._ensure_default_patient_data(pdf)
88
+
89
+ # Refresh from database to get updated data
90
+ pdf.refresh_from_db()
91
+
92
+ # Use VideoImportService for anonymization
93
+ try:
94
+
95
+ logger.info(f"Starting anonymization using VideoImportService for {pdf.uuid}")
96
+ self.pdf_service.import_and_anonymize(
97
+ pdf_file_obj=pdf,
98
+ )
99
+
100
+ logger.info(f"VideoImportService anonymization completed for {pdf.uuid}")
101
+
102
+
103
+ return Response({
104
+ "message": "Video re-import with VideoImportService completed successfully.",
105
+ "pdf_id": pdf_id,
106
+ "uuid": str(pdf.uuid),
107
+ "frame_cleaning_applied": True,
108
+ "sensitive_meta_created": pdf.sensitive_meta is not None,
109
+ "sensitive_meta_id": pdf.sensitive_meta.id if pdf.sensitive_meta else None,
110
+ "updated_in_place": True,
111
+ "status": "done"
112
+ }, status=status.HTTP_200_OK)
113
+
114
+ except Exception as e:
115
+ logger.exception(f"VideoImportService anonymization failed for pdf {pdf.uuid}: {e}")
116
+ logger.warning("Continuing without anonymization due to error")
117
+
118
+ # Set anonymization status to "done" even without frame cleaning
119
+ pdf
120
+
121
+ return Response({
122
+ "message": "Video re-import completed successfully.",
123
+ "pdf_id": pdf_id,
124
+ "uuid": str(pdf.uuid),
125
+ "sensitive_meta_created": pdf.sensitive_meta is not None,
126
+ "sensitive_meta_id": .sensitive_meta.id if pdf.sensitive_meta else None,
127
+ "updated_in_place": True,
128
+ "status": "done" # ⭐ Add explicit done status
129
+ }, status=status.HTTP_200_OK)
130
+
131
+ except Exception as e:
132
+ logger.error(f"Failed to re-import pdf {pdf.uuid}: {str(e)}", exc_info=True)
133
+
134
+ # Handle specific error types
135
+ error_msg = str(e)
136
+ if any(phrase in error_msg.lower() for phrase in ["insufficient storage", "no space left", "disk full"]):
137
+ # Storage error - return specific error message
138
+ return Response({
139
+ "error": f"Storage error during re-import: {error_msg}",
140
+ "error_type": "storage_error",
141
+ "pdf_id": pdf_id,
142
+ "uuid": str(pdf.uuid)
143
+ }, status=status.HTTP_507_INSUFFICIENT_STORAGE)
144
+ else:
145
+ # Other errors
146
+ return Response({
147
+ "error": f"Re-import failed: {error_msg}",
148
+ "error_type": "processing_error",
149
+ "pdf_id": pdf_id,
150
+ "uuid": str(pdf.uuid)
151
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)