endoreg-db 0.3.4__py3-none-any.whl → 0.3.6__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.
Files changed (350) hide show
  1. endoreg_db/admin.py +3 -3
  2. endoreg_db/apps.py +6 -6
  3. endoreg_db/data/__init__.py +65 -16
  4. endoreg_db/data/active_model/data.yaml +2 -2
  5. endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
  6. endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
  7. endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
  8. endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
  9. endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
  10. endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
  11. endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
  12. endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
  13. endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
  14. endoreg_db/data/case_template/template/base.yaml +8 -0
  15. endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
  16. endoreg_db/data/case_template/tmp/_rule_value +13 -0
  17. endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
  18. endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
  19. endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
  20. endoreg_db/data/center/data.yaml +60 -52
  21. endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
  22. endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
  23. endoreg_db/data/disease/cardiovascular.yaml +37 -0
  24. endoreg_db/data/disease/hepatology.yaml +5 -0
  25. endoreg_db/data/disease/misc.yaml +6 -0
  26. endoreg_db/data/disease/renal.yaml +5 -0
  27. endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
  28. endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
  29. endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
  30. endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
  31. endoreg_db/data/distribution/date/patient.yaml +7 -0
  32. endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
  33. endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
  34. endoreg_db/data/endoscope_type/data.yaml +10 -10
  35. endoreg_db/data/endoscopy_processor/data.yaml +45 -45
  36. endoreg_db/data/event/cardiology.yaml +28 -0
  37. endoreg_db/data/event/neurology.yaml +14 -0
  38. endoreg_db/data/event/surgery.yaml +13 -0
  39. endoreg_db/data/event/thrombembolism.yaml +20 -0
  40. endoreg_db/data/examination/examinations/data.yaml +65 -16
  41. endoreg_db/data/examination/time/data.yaml +47 -47
  42. endoreg_db/data/examination/time-type/data.yaml +7 -7
  43. endoreg_db/data/examination/type/data.yaml +5 -5
  44. endoreg_db/data/gender/data.yaml +18 -0
  45. endoreg_db/data/information_source/data.yaml +30 -30
  46. endoreg_db/data/information_source/medication.yaml +6 -0
  47. endoreg_db/data/lab_value/cardiac_enzymes.yaml +31 -0
  48. endoreg_db/data/lab_value/coagulation.yaml +49 -0
  49. endoreg_db/data/lab_value/electrolytes.yaml +190 -0
  50. endoreg_db/data/lab_value/gastrointestinal_function.yaml +121 -0
  51. endoreg_db/data/lab_value/hematology.yaml +169 -0
  52. endoreg_db/data/lab_value/hormones.yaml +53 -0
  53. endoreg_db/data/lab_value/lipids.yaml +44 -0
  54. endoreg_db/data/lab_value/misc.yaml +30 -0
  55. endoreg_db/data/lab_value/renal_function.yaml +11 -0
  56. endoreg_db/data/label/label/data.yaml +62 -62
  57. endoreg_db/data/label/label-set/data.yaml +17 -17
  58. endoreg_db/data/label/label-type/data.yaml +6 -6
  59. endoreg_db/data/material/material.yaml +91 -0
  60. endoreg_db/data/medication/anticoagulation.yaml +65 -0
  61. endoreg_db/data/medication/tah.yaml +70 -0
  62. endoreg_db/data/medication_indication/anticoagulation.yaml +120 -0
  63. endoreg_db/data/medication_indication_type/data.yaml +11 -0
  64. endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
  65. endoreg_db/data/medication_intake_time/base.yaml +31 -0
  66. endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
  67. endoreg_db/data/medication_schedule/ass.yaml +12 -0
  68. endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
  69. endoreg_db/data/model_type/data.yaml +6 -6
  70. endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
  71. endoreg_db/data/pdf_type/data.yaml +28 -28
  72. endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
  73. endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
  74. endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
  75. endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
  76. endoreg_db/data/profession/data.yaml +70 -70
  77. endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
  78. endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +26 -26
  79. endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +19 -19
  80. endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -0
  81. endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
  82. endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
  83. endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
  84. endoreg_db/data/unit/concentration.yaml +92 -0
  85. endoreg_db/data/unit/data.yaml +17 -17
  86. endoreg_db/data/unit/length.yaml +30 -30
  87. endoreg_db/data/unit/misc.yaml +20 -0
  88. endoreg_db/data/unit/rate.yaml +6 -0
  89. endoreg_db/data/unit/time.yaml +13 -0
  90. endoreg_db/data/unit/volume.yaml +35 -26
  91. endoreg_db/data/unit/weight.yaml +37 -30
  92. endoreg_db/data/waste/data.yaml +12 -0
  93. endoreg_db/forms/__init__.py +2 -2
  94. endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -23
  95. endoreg_db/forms/settings/__init__.py +8 -8
  96. endoreg_db/forms/unit.py +5 -5
  97. endoreg_db/management/commands/_load_model_template.py +40 -40
  98. endoreg_db/management/commands/delete_all.py +18 -18
  99. endoreg_db/management/commands/delete_legacy_images.py +19 -19
  100. endoreg_db/management/commands/delete_legacy_videos.py +16 -16
  101. endoreg_db/management/commands/extract_legacy_video_frames.py +18 -18
  102. endoreg_db/management/commands/fetch_legacy_image_dataset.py +32 -32
  103. endoreg_db/management/commands/fix_auth_permission.py +20 -20
  104. endoreg_db/management/commands/import_legacy_images.py +94 -94
  105. endoreg_db/management/commands/import_legacy_videos.py +76 -76
  106. endoreg_db/management/commands/load_active_model_data.py +44 -44
  107. endoreg_db/management/commands/load_ai_model_data.py +44 -44
  108. endoreg_db/management/commands/load_base_db_data.py +128 -71
  109. endoreg_db/management/commands/load_center_data.py +42 -42
  110. endoreg_db/management/commands/load_disease_classification_choices_data.py +41 -0
  111. endoreg_db/management/commands/load_disease_classification_data.py +41 -0
  112. endoreg_db/management/commands/load_disease_data.py +40 -0
  113. endoreg_db/management/commands/load_distribution_data.py +66 -0
  114. endoreg_db/management/commands/load_endoscope_type_data.py +44 -44
  115. endoreg_db/management/commands/load_endoscopy_processor_data.py +44 -44
  116. endoreg_db/management/commands/load_event_data.py +41 -0
  117. endoreg_db/management/commands/load_examination_data.py +74 -74
  118. endoreg_db/management/commands/load_g_play_data.py +113 -0
  119. endoreg_db/management/commands/load_gender_data.py +44 -0
  120. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +133 -0
  121. endoreg_db/management/commands/load_information_source.py +44 -44
  122. endoreg_db/management/commands/load_lab_value_data.py +50 -0
  123. endoreg_db/management/commands/load_label_data.py +66 -66
  124. endoreg_db/management/commands/load_medication_data.py +41 -0
  125. endoreg_db/management/commands/load_medication_indication_data.py +63 -0
  126. endoreg_db/management/commands/load_medication_indication_type_data.py +41 -0
  127. endoreg_db/management/commands/load_medication_intake_time_data.py +41 -0
  128. endoreg_db/management/commands/load_medication_schedule_data.py +55 -0
  129. endoreg_db/management/commands/load_pdf_type_data.py +60 -60
  130. endoreg_db/management/commands/load_profession_data.py +43 -43
  131. endoreg_db/management/commands/load_report_reader_flag.py +45 -45
  132. endoreg_db/management/commands/load_unit_data.py +45 -45
  133. endoreg_db/management/commands/load_user_groups.py +28 -28
  134. endoreg_db/management/commands/register_ai_model.py +65 -65
  135. endoreg_db/management/commands/reset_celery_schedule.py +9 -9
  136. endoreg_db/migrations/0001_initial.py +582 -582
  137. endoreg_db/migrations/0002_rawvideofile.py +26 -26
  138. endoreg_db/migrations/0003_rawvideofile_frames_required.py +18 -18
  139. endoreg_db/migrations/0004_rename_hash_rawvideofile_video_hash.py +18 -18
  140. endoreg_db/migrations/0005_ffmpegmeta_remove_videoimportmeta_center_and_more.py +56 -56
  141. endoreg_db/migrations/0006_rawvideofile_center_alter_videometa_processor.py +25 -25
  142. endoreg_db/migrations/0007_rawvideofile_processor.py +19 -19
  143. endoreg_db/migrations/0008_rename_frames_required_rawvideofile_state_frames_required.py +18 -18
  144. endoreg_db/migrations/0009_sensitivemeta_rawvideofile_sensitive_meta.py +31 -31
  145. endoreg_db/migrations/0010_rename_endoscope_serial_number_sensitivemeta_endoscope_sn.py +18 -18
  146. endoreg_db/migrations/0011_rawvideofile_state_sensitive_data_retrieved.py +18 -18
  147. endoreg_db/migrations/0012_rawvideofile_prediction_dir_and_more.py +109 -109
  148. endoreg_db/migrations/0013_rawpdffile.py +31 -31
  149. endoreg_db/migrations/0014_pdftype_alter_rawpdffile_file_pdfmeta.py +38 -38
  150. endoreg_db/migrations/0015_rename_report_processed_rawpdffile_state_report_processed_and_more.py +31 -31
  151. endoreg_db/migrations/0016_rawpdffile_state_report_processing_required.py +18 -18
  152. endoreg_db/migrations/0017_firstname_lastname_center_first_names_and_more.py +37 -37
  153. endoreg_db/migrations/0018_reportreaderflag_reportreaderconfig.py +37 -37
  154. endoreg_db/migrations/0019_pdftype_cut_off_above_lines_and_more.py +42 -42
  155. endoreg_db/migrations/0020_rename_endoscopy_info_line_pdftype_endoscope_info_line.py +18 -18
  156. endoreg_db/migrations/0021_alter_pdftype_endoscope_info_line.py +19 -19
  157. endoreg_db/migrations/0022_alter_pdftype_endoscope_info_line.py +19 -19
  158. endoreg_db/migrations/0023_ttoquestionnaire_alter_pdftype_endoscope_info_line.py +59 -59
  159. endoreg_db/migrations/0024_remove_ttoquestionnaire_infections_and_more.py +27 -27
  160. endoreg_db/migrations/0025_event_alter_rawpdffile_file_patientevent.py +42 -0
  161. endoreg_db/migrations/0026_disease_diseaseclassification_and_more.py +166 -0
  162. endoreg_db/migrations/0027_labvalue_abbreviation_labvalue_default_normal_range_and_more.py +38 -0
  163. endoreg_db/migrations/0028_alter_unit_abbreviation.py +18 -0
  164. endoreg_db/migrations/0029_medicationintaketime_and_more.py +75 -0
  165. endoreg_db/migrations/0030_medicationindicationtype_and_more.py +101 -0
  166. endoreg_db/migrations/0031_rename_adapt_to_liver_function_medication_adapt_to_age_and_more.py +38 -0
  167. endoreg_db/migrations/0032_alter_medicationschedule_therapy_duration_d.py +18 -0
  168. endoreg_db/migrations/0033_medicationindication_sources.py +18 -0
  169. endoreg_db/migrations/0034_alter_rawpdffile_file.py +20 -0
  170. endoreg_db/migrations/0035_alter_medicationindication_sources.py +18 -0
  171. endoreg_db/migrations/0036_alter_rawpdffile_file.py +20 -0
  172. endoreg_db/migrations/0037_alter_medicationindication_sources.py +18 -0
  173. endoreg_db/migrations/0038_emissionfactor_material_product_productgroup_and_more.py +164 -0
  174. endoreg_db/migrations/0039_referenceproduct_name.py +19 -0
  175. endoreg_db/migrations/0040_quizanswertype_quizquestiontype_quizquestion_and_more.py +50 -0
  176. endoreg_db/migrations/0041_gender_patientmedication_medication_indication_and_more.py +40 -0
  177. endoreg_db/migrations/0042_casetemplateruletype_casetemplaterulevalue_and_more.py +74 -0
  178. endoreg_db/migrations/0043_casetemplatetype_name_de_casetemplatetype_name_en.py +23 -0
  179. endoreg_db/migrations/0044_casetemplateruletype_name_de_and_more.py +23 -0
  180. endoreg_db/migrations/0045_casetemplaterulevalue_value_type.py +19 -0
  181. endoreg_db/migrations/0046_casetemplaterulevalue_target_field.py +18 -0
  182. endoreg_db/migrations/0047_casetemplaterule_target_model.py +18 -0
  183. endoreg_db/migrations/0048_remove_casetemplaterule_chained_rules_and_more.py +22 -0
  184. endoreg_db/migrations/0049_remove_casetemplaterule_rule_values.py +17 -0
  185. endoreg_db/migrations/0050_casetemplaterule_rule_values.py +18 -0
  186. endoreg_db/migrations/0051_remove_casetemplaterule_calling_rules_and_more.py +27 -0
  187. endoreg_db/migrations/0052_rename_case_template_type_casetemplate_template_type.py +18 -0
  188. endoreg_db/migrations/0053_patientlabsampletype_patientlabsample_and_more.py +38 -0
  189. endoreg_db/migrations/0054_multiplecategoricalvaluedistribution_and_more.py +69 -0
  190. endoreg_db/migrations/0055_remove_casetemplaterule_rule_values_and_more.py +59 -0
  191. endoreg_db/migrations/0056_datevaluedistribution_and_more.py +32 -0
  192. endoreg_db/migrations/0057_remove_datevaluedistribution_max_date_and_more.py +72 -0
  193. endoreg_db/migrations/0058_datevaluedistribution_description_and_more.py +28 -0
  194. endoreg_db/migrations/0059_casetemplaterule_rule_values.py +18 -0
  195. endoreg_db/migrations/0060_labvalue__default_date_value_distribution_and_more.py +44 -0
  196. endoreg_db/migrations/0061_remove_patientlabvalue_date_patientlabvalue_datetime.py +24 -0
  197. endoreg_db/migrations/0062_labvalue_numeric_precision.py +18 -0
  198. endoreg_db/migrations/0063_alter_labvalue_numeric_precision.py +18 -0
  199. endoreg_db/migrations/0064_casetemplaterule_extra_parameters_and_more.py +23 -0
  200. endoreg_db/migrations/0065_rename__date_value_distribution_casetemplaterule_date_value_distribution_and_more.py +58 -0
  201. endoreg_db/migrations/0066_alter_patientlabvalue_patient_and_more.py +29 -0
  202. endoreg_db/migrations/0067_alter_medicationindication_indication_type.py +19 -0
  203. endoreg_db/models/__init__.py +74 -57
  204. endoreg_db/models/ai_model/__init__.py +3 -3
  205. endoreg_db/models/ai_model/active_model.py +9 -9
  206. endoreg_db/models/ai_model/model_meta.py +24 -24
  207. endoreg_db/models/ai_model/model_type.py +25 -25
  208. endoreg_db/models/ai_model/utils.py +8 -8
  209. endoreg_db/models/annotation/__init__.py +1 -1
  210. endoreg_db/models/annotation/binary_classification_annotation_task.py +80 -80
  211. endoreg_db/models/annotation/image_classification.py +26 -26
  212. endoreg_db/models/case_template/__init__.py +6 -0
  213. endoreg_db/models/case_template/case_template.py +81 -0
  214. endoreg_db/models/case_template/case_template_rule.py +276 -0
  215. endoreg_db/models/case_template/case_template_rule_value.py +73 -0
  216. endoreg_db/models/case_template/case_template_type.py +28 -0
  217. endoreg_db/models/center/__init__.py +4 -0
  218. endoreg_db/models/{center.py → center/center.py} +24 -24
  219. endoreg_db/models/center/center_product.py +34 -0
  220. endoreg_db/models/center/center_resource.py +19 -0
  221. endoreg_db/models/center/center_waste.py +11 -0
  222. endoreg_db/models/data_file/__init__.py +5 -5
  223. endoreg_db/models/data_file/base_classes/__init__.py +2 -2
  224. endoreg_db/models/data_file/base_classes/abstract_frame.py +50 -50
  225. endoreg_db/models/data_file/base_classes/abstract_video.py +200 -200
  226. endoreg_db/models/data_file/frame.py +45 -45
  227. endoreg_db/models/data_file/import_classes/__init__.py +31 -31
  228. endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +34 -34
  229. endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +28 -28
  230. endoreg_db/models/data_file/import_classes/processing_functions/video.py +260 -260
  231. endoreg_db/models/data_file/import_classes/raw_pdf.py +188 -185
  232. endoreg_db/models/data_file/import_classes/raw_video.py +343 -343
  233. endoreg_db/models/data_file/metadata/__init__.py +3 -3
  234. endoreg_db/models/data_file/metadata/pdf_meta.py +70 -70
  235. endoreg_db/models/data_file/metadata/sensitive_meta.py +31 -31
  236. endoreg_db/models/data_file/metadata/video_meta.py +132 -131
  237. endoreg_db/models/data_file/report_file.py +89 -89
  238. endoreg_db/models/data_file/video/__init__.py +6 -6
  239. endoreg_db/models/data_file/video/import_meta.py +25 -25
  240. endoreg_db/models/data_file/video/video.py +25 -25
  241. endoreg_db/models/data_file/video_segment.py +107 -107
  242. endoreg_db/models/disease.py +56 -0
  243. endoreg_db/models/emission/__init__.py +1 -0
  244. endoreg_db/models/emission/emission_factor.py +20 -0
  245. endoreg_db/models/event.py +22 -0
  246. endoreg_db/models/examination/__init__.py +3 -3
  247. endoreg_db/models/examination/examination.py +26 -26
  248. endoreg_db/models/examination/examination_time.py +27 -27
  249. endoreg_db/models/examination/examination_time_type.py +24 -24
  250. endoreg_db/models/examination/examination_type.py +18 -18
  251. endoreg_db/models/hardware/__init__.py +1 -1
  252. endoreg_db/models/hardware/endoscope.py +44 -44
  253. endoreg_db/models/hardware/endoscopy_processor.py +143 -143
  254. endoreg_db/models/information_source.py +29 -22
  255. endoreg_db/models/label/label.py +84 -84
  256. endoreg_db/models/laboratory/__init__.py +1 -0
  257. endoreg_db/models/laboratory/lab_value.py +102 -0
  258. endoreg_db/models/legacy_data/__init__.py +3 -3
  259. endoreg_db/models/legacy_data/image.py +34 -34
  260. endoreg_db/models/medication/__init__.py +1 -0
  261. endoreg_db/models/medication/medication.py +148 -0
  262. endoreg_db/models/other/__init__.py +5 -0
  263. endoreg_db/models/other/distribution.py +215 -0
  264. endoreg_db/models/other/material.py +16 -0
  265. endoreg_db/models/other/resource.py +18 -0
  266. endoreg_db/models/other/transport_route.py +21 -0
  267. endoreg_db/models/other/waste.py +20 -0
  268. endoreg_db/models/patient_examination/__init__.py +35 -35
  269. endoreg_db/models/permissions/__init__.py +44 -44
  270. endoreg_db/models/persons/__init__.py +7 -6
  271. endoreg_db/models/persons/examiner/__init__.py +1 -1
  272. endoreg_db/models/persons/examiner/examiner.py +15 -15
  273. endoreg_db/models/persons/examiner/examiner_type.py +1 -1
  274. endoreg_db/models/persons/first_name.py +17 -17
  275. endoreg_db/models/persons/gender.py +22 -0
  276. endoreg_db/models/persons/last_name.py +19 -19
  277. endoreg_db/models/persons/patient/__init__.py +8 -0
  278. endoreg_db/models/persons/patient/case/__init__.py +0 -0
  279. endoreg_db/models/persons/patient/case/case.py +30 -0
  280. endoreg_db/models/persons/patient/patient.py +216 -0
  281. endoreg_db/models/persons/patient/patient_disease.py +16 -0
  282. endoreg_db/models/persons/patient/patient_event.py +22 -0
  283. endoreg_db/models/persons/patient/patient_lab_sample.py +106 -0
  284. endoreg_db/models/persons/patient/patient_lab_value.py +176 -0
  285. endoreg_db/models/persons/patient/patient_medication.py +44 -0
  286. endoreg_db/models/persons/patient/patient_medication_schedule.py +28 -0
  287. endoreg_db/models/persons/person.py +31 -34
  288. endoreg_db/models/persons/portal_user_information.py +27 -29
  289. endoreg_db/models/prediction/__init__.py +1 -1
  290. endoreg_db/models/prediction/image_classification.py +37 -37
  291. endoreg_db/models/prediction/video_prediction_meta.py +244 -244
  292. endoreg_db/models/product/__init__.py +5 -0
  293. endoreg_db/models/product/product.py +97 -0
  294. endoreg_db/models/product/product_group.py +19 -0
  295. endoreg_db/models/product/product_material.py +24 -0
  296. endoreg_db/models/product/product_weight.py +26 -0
  297. endoreg_db/models/product/reference_product.py +99 -0
  298. endoreg_db/models/questionnaires/__init__.py +114 -114
  299. endoreg_db/models/quiz/__init__.py +2 -0
  300. endoreg_db/models/quiz/quiz_answer.py +41 -0
  301. endoreg_db/models/quiz/quiz_question.py +54 -0
  302. endoreg_db/models/report_reader/__init__.py +1 -1
  303. endoreg_db/models/report_reader/report_reader_config.py +53 -53
  304. endoreg_db/models/report_reader/report_reader_flag.py +19 -19
  305. endoreg_db/models/rules/__init__.py +5 -0
  306. endoreg_db/models/rules/rule.py +24 -0
  307. endoreg_db/models/rules/rule_applicator.py +224 -0
  308. endoreg_db/models/rules/rule_attribute_dtype.py +19 -0
  309. endoreg_db/models/rules/rule_type.py +22 -0
  310. endoreg_db/models/rules/ruleset.py +19 -0
  311. endoreg_db/models/unit.py +21 -19
  312. endoreg_db/queries/__init__.py +4 -4
  313. endoreg_db/queries/annotations/__init__.py +2 -2
  314. endoreg_db/queries/annotations/legacy.py +159 -159
  315. endoreg_db/queries/get/__init__.py +5 -5
  316. endoreg_db/queries/get/center.py +42 -42
  317. endoreg_db/queries/get/model.py +13 -13
  318. endoreg_db/queries/get/patient.py +14 -14
  319. endoreg_db/queries/get/patient_examination.py +20 -20
  320. endoreg_db/queries/get/report_file.py +33 -33
  321. endoreg_db/queries/get/video.py +31 -31
  322. endoreg_db/serializers/__init__.py +9 -9
  323. endoreg_db/serializers/ai_model.py +18 -18
  324. endoreg_db/serializers/annotation.py +17 -17
  325. endoreg_db/serializers/center.py +11 -11
  326. endoreg_db/serializers/examination.py +32 -32
  327. endoreg_db/serializers/frame.py +13 -13
  328. endoreg_db/serializers/hardware.py +20 -20
  329. endoreg_db/serializers/label.py +22 -22
  330. endoreg_db/serializers/patient.py +10 -10
  331. endoreg_db/serializers/prediction.py +15 -15
  332. endoreg_db/serializers/report_file.py +7 -7
  333. endoreg_db/serializers/video.py +27 -27
  334. endoreg_db/tests.py +3 -3
  335. endoreg_db/utils/cropping.py +28 -28
  336. endoreg_db/utils/dataloader.py +92 -185
  337. endoreg_db/utils/file_operations.py +30 -30
  338. endoreg_db/utils/hashs.py +33 -33
  339. endoreg_db/utils/legacy_ocr.py +201 -201
  340. endoreg_db/utils/ocr.py +197 -197
  341. endoreg_db/utils/uuid.py +4 -4
  342. endoreg_db/utils/video_metadata.py +87 -87
  343. endoreg_db/views.py +3 -3
  344. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.6.dist-info}/LICENSE +674 -674
  345. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.6.dist-info}/METADATA +2 -2
  346. endoreg_db-0.3.6.dist-info/RECORD +357 -0
  347. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.6.dist-info}/WHEEL +1 -1
  348. endoreg_db/models/persons/patient.py +0 -58
  349. endoreg_db/models.py +0 -3
  350. endoreg_db-0.3.4.dist-info/RECORD +0 -185
@@ -0,0 +1,224 @@
1
+ from .rule import Rule
2
+ import random
3
+ from django.core.exceptions import ValidationError
4
+
5
+ class RuleApplicator:
6
+ """
7
+ A class to apply different types of rules to a Django model instance based on the Rule configuration.
8
+ """
9
+
10
+ def get_rule_by_name(self, rule_name):
11
+ """
12
+ A helper method to fetch a rule by name. This can be further customized.
13
+ """
14
+ # get rule by name which is natural key
15
+ rule = Rule.objects.get_by_natural_key(rule_name)
16
+ return rule
17
+
18
+
19
+ def apply(self, obj, rule):
20
+ """
21
+ Applies a specified rule to an object based on the rule type and attributes.
22
+
23
+ Parameters:
24
+ obj (Django model instance): The object to which the rule is applied.
25
+ rule (Rule): The rule instance containing the rule_type and attribute details.
26
+ """
27
+ rule_type_method = self.get_rule_type_method(rule.rule_type.name)
28
+ if rule_type_method:
29
+ rule_type_method(obj, rule)
30
+
31
+ else:
32
+ raise ValueError(f"Unsupported rule type: {rule.rule_type.name}")
33
+
34
+ def apply_rule_by_name(self, obj, rule_name):
35
+ """
36
+ A helper method to apply a rule and get a value. This can be further customized.
37
+ """
38
+ rule = self.get_rule_by_name(rule_name)
39
+ self.apply(obj, rule)
40
+
41
+ def apply_rules_by_name(self, obj, rule_names):
42
+ """
43
+ A helper method to apply multiple rules and get values. This can be further customized.
44
+ """
45
+ rules = [self.get_rule_by_name(rule_name) for rule_name in rule_names]
46
+ for rule in rules:
47
+ self.apply(obj, rule)
48
+
49
+
50
+ def get_rule_type_method(self, rule_type_name):
51
+ """
52
+ Maps rule type name to the corresponding method.
53
+ """
54
+ return getattr(self, f"handle_{rule_type_name}", None)
55
+
56
+ def parse_attribute_path(self, obj, attribute_key):
57
+ """
58
+ Parses the attribute path and applies the value to the correct attribute of a nested object.
59
+ """
60
+ parts = attribute_key.split('.')
61
+ model_name = parts[0]
62
+ if model_name.lower() != obj.__class__.__name__.lower():
63
+ raise ValidationError(f"Model type mismatch: expected {model_name}, got {obj.__class__.__name__}")
64
+
65
+ # Navigate through the nested attributes
66
+ target = obj
67
+ for part in parts[1:-1]:
68
+ target = getattr(target, part)
69
+
70
+ return target, parts[-1]
71
+
72
+ def set_attribute_value(self, obj, rule):
73
+ """
74
+ Generic method to set attribute value considering nested paths.
75
+ """
76
+ target, attribute = self.parse_attribute_path(obj, rule.attribute_key)
77
+ setattr(target, attribute, rule.attribute_dict['value'])
78
+ target.save()
79
+
80
+ #####
81
+
82
+ def handle_case_attribute_set_value(self, obj, rule):
83
+ """
84
+ Sets a specific attribute to a given value.
85
+ """
86
+ self.set_attribute_value(obj, rule.attribute_key, rule.attribute_dict["value"])
87
+
88
+ def handle_case_attribute_set_value_range_uniform(self, obj, rule):
89
+ """
90
+ Sets an attribute to a value within a specified range, selected uniformly.
91
+ """
92
+ if not hasattr(rule, 'attribute_dtype') or rule.attribute_dtype.name not in ['numeric', 'ordered_categorical']:
93
+ raise ValidationError("Attribute dtype must be numeric or ordered_categorical")
94
+ min_val = rule.attribute_dict["value_min"]
95
+ max_val = rule.attribute_dict["value_max"]
96
+ value = random.uniform(min_val, max_val)
97
+ self.set_attribute_value(obj, rule.attribute_key, value)
98
+
99
+ def handle_case_attribute_set_value_range_norm_dist(self, obj, rule):
100
+ """
101
+ Sets an attribute to a value within a specified range, based on a normal distribution.
102
+ """
103
+ if rule.attribute_dtype.name in ['float', "integer"]:
104
+ raise ValidationError("Attribute dtype must be float or integer")
105
+ mean = rule.attribute_dict["value_mean"]
106
+ std_dev = rule.attribute_dict["value_sd"]
107
+ value = random.normalvariate(mean, std_dev)
108
+ self.set_attribute_value(obj, rule.attribute_key, value)
109
+
110
+
111
+ def handle_case_attribute_set_from_list_uniform(self, obj, rule):
112
+ """
113
+ Selects an attribute value uniformly from a list of choices.
114
+ """
115
+ choices = rule.attribute_dict["value_choices"]
116
+ value = random.choice(choices)
117
+ self.set_attribute_value(obj, rule.attribute_key, value)
118
+
119
+ def handle_case_attribute_set_from_prop_tuple_list(self, obj, rule):
120
+ """
121
+ Selects an attribute value based on a list of value-probability tuples.
122
+ """
123
+ prop_list = rule.attribute_dict["value_prop_tuple_list"]
124
+ total = sum(prop for _, prop in prop_list)
125
+ pick = random.uniform(0, total)
126
+ current = 0
127
+ for value, prop in prop_list:
128
+ current += prop
129
+ if current > pick:
130
+ self.set_attribute_value(obj, rule.attribute_key, value)
131
+ break
132
+
133
+
134
+ #####
135
+
136
+ def handle_case_add_patient(self, obj, rule):
137
+ """Function to add a patient to a case. If the patient already exists, raise an error. Requires the following
138
+ rules in the rule_dict:
139
+ - gender_rule
140
+ - dob_rule
141
+ - event_rules
142
+ - disease_rules
143
+ """
144
+ from endoreg_db.models import Patient, PatientEvent, PatientDisease, Case
145
+
146
+ # Check if the
147
+ obj:Case = obj
148
+ if obj.patient:
149
+ raise ValueError("Patient already exists in the case")
150
+
151
+ patient = Patient()
152
+ self.apply_rule_by_name(patient, rule.attribute_dict["patient_gender_rule"])
153
+ self.apply_rule_by_name(patient, rule.attribute_dict["patient_dob_rule"])
154
+ self.apply_rules_by_name(patient, rule.attribute_dict["patient_event_rules"])
155
+ self.apply_rules_by_name(patient, rule.attribute_dict["patient_disease_rules"])
156
+
157
+ def handle_case_add_polyp(self, obj, rule):
158
+ """
159
+ Adds a polyp to the case, processing various polyp characteristics. Requires Rules for each attribute:
160
+ - polyp_location_organ_rule (single rule)
161
+ - polyp_location_organ_part_rule (single rule)
162
+ - polyp_morphology_classification_shape_choices_rule (list of rules)
163
+ - polyp_morphology_classification_chromo_choices_rule (list of rules)
164
+ - polyp_intervention_type_rule (single rule)
165
+ - polyp_intervention_instrument_rule (single rule)
166
+ - polyp_size_mm_rule (single rule)
167
+
168
+ """
169
+ # Example: create and add a polyp instance based on the rules
170
+ from endoreg_db.models import Polyp # Ensure you have a Polyp model and adjust the import
171
+ from endoreg_db.models import Location
172
+ from endoreg_db.models import EndoscopicIntervention
173
+ from endoreg_db.models import PolypMorphology
174
+
175
+ assert obj.examination.type != None, "Examination type is required"
176
+
177
+ location = Location()
178
+ location.organ = self.apply_rule_by_name(location, rule.attribute_dict["polyp_location_organ_rule"])
179
+ location.organ_part = self.apply_rule_by_name(location, rule.attribute_dict["polyp_location_organ_part_rule"])
180
+ location.save()
181
+
182
+ morphology = PolypMorphology()
183
+ # M2M to ClassificationChoice (linked to Classification which has name as natural key)
184
+ morphology.shape_classification_choices = self.apply_rules_by_name(morphology, rule.attribute_dict["polyp_morphology_classification_shape_choices_rules"])
185
+ # M2M to ClassificationChoice (linked to Classification which has name as natural key)
186
+ morphology.chromo_classification_choices = self.apply_rules_by_name(morphology, rule.attribute_dict["polyp_morphology_classification_chromo_choices_rules"])
187
+ morphology.save()
188
+
189
+ intervention = EndoscopicIntervention()
190
+ intervention.type = self.apply_rule_by_name(intervention, rule.attribute_dict["polyp_intervention_type_rule"])
191
+ intervention.instrument = self.apply_rule_by_name(intervention, rule.attribute_dict["polyp_intervention_instrument_rule"])
192
+ intervention.save()
193
+
194
+ polyp = Polyp()
195
+ polyp.size_mm = self.apply_rule_by_name(polyp, rule.attribute_dict["polyp_size_mm_rule"])
196
+ polyp.location = location
197
+ polyp.morphology = morphology
198
+ polyp.intervention = intervention
199
+
200
+ polyp.save()
201
+
202
+ obj.polyps.add(polyp)
203
+ obj.save()
204
+
205
+
206
+ # def handle_case_add_esophageal_varices(self, obj, rule):
207
+ # """
208
+ # Handles adding esophageal varices to a case based on the rule.
209
+ # """
210
+ # # Similar to the polyp case, create and add esophageal varices based on the attributes
211
+ # from endoreg_db.models import EsophagealVarices # Ensure this model exists
212
+ # varices = EsophagealVarices()
213
+ # varices.origin = self.apply_rule_by_name(obj, rule.attribute_dict["esophageal_varices_origin_rule"])
214
+ # varices.classification = self.apply_rule_by_name(obj, rule.attribute_dict["esophageal_varices_classification_rule"])
215
+ # varices.location_extent = self.apply_rule_by_name(obj, rule.attribute_dict["esophageal_varices_location_extent_rule"])
216
+ # varices.save()
217
+ # # Assuming a relationship setup
218
+ # obj.esophageal_varices.add(varices)
219
+ # obj.save()
220
+
221
+
222
+
223
+
224
+
@@ -0,0 +1,19 @@
1
+ from django.db import models
2
+
3
+
4
+ class RuleAttributeDtypeManager(models.Manager):
5
+ def get_by_natural_key(self, name):
6
+ return self.get(name=name)
7
+
8
+ class RuleAttributeDType(models.Model):
9
+ name = models.CharField(max_length=255, unique=True)
10
+ name_de = models.CharField(max_length=255, blank=True, null=True)
11
+ name_en = models.CharField(max_length=255, blank=True, null=True)
12
+
13
+ objects = RuleAttributeDtypeManager()
14
+
15
+ def natural_key(self):
16
+ return (self.name,)
17
+
18
+ def __str__(self):
19
+ return self.name
@@ -0,0 +1,22 @@
1
+ from django.db import models
2
+
3
+ class RuleTypeManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class RuleType(models.Model):
8
+ name = models.CharField(max_length=255, unique=True)
9
+ name_de = models.CharField(max_length=255, blank=True, null=True)
10
+ name_en = models.CharField(max_length=255, blank=True, null=True)
11
+
12
+ objects = RuleTypeManager()
13
+
14
+ def natural_key(self):
15
+ return (self.name,)
16
+
17
+ def __str__(self):
18
+ return self.name
19
+
20
+ class Meta:
21
+ verbose_name = 'Rule Type'
22
+ verbose_name_plural = 'Rule Types'
@@ -0,0 +1,19 @@
1
+ from django.db import models
2
+
3
+ class RulesetManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class Ruleset(models.Model):
8
+ name = models.CharField(max_length=255, unique=True)
9
+ name_de = models.CharField(max_length=255, blank=True, null=True)
10
+ name_en = models.CharField(max_length=255, blank=True, null=True)
11
+ rules = models.ManyToManyField('Rule')
12
+
13
+ objects = RulesetManager()
14
+
15
+ def natural_key(self):
16
+ return (self.name,)
17
+
18
+ def __str__(self):
19
+ return self.name
endoreg_db/models/unit.py CHANGED
@@ -1,20 +1,22 @@
1
- from django.db import models
2
-
3
- class UnitManager(models.Manager):
4
- def get_by_natural_key(self, name):
5
- return self.get(name=name)
6
-
7
- class Unit(models.Model):
8
- objects = UnitManager()
9
-
10
- name = models.CharField(max_length=100) # e.g. "Centimeter"
11
- name_de = models.CharField(max_length=100, blank=True, null=True) # e.g. "Zentimeter"
12
- name_en = models.CharField(max_length=100, blank=True, null=True) # e.g. "Centimeter"
13
- description = models.CharField(max_length=100, blank=True, null=True) # e.g. "centimeters", "millimeters", "inches"
14
- abbreviation = models.CharField(max_length=10, blank=True, null=True) # e.g. "cm", "mm", "in"
15
-
16
- def __str__(self):
17
- return self.abbreviation
18
-
19
- def natural_key(self):
1
+ from django.db import models
2
+
3
+ class UnitManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class Unit(models.Model):
8
+ objects = UnitManager()
9
+
10
+ name = models.CharField(max_length=100) # e.g. "Centimeter"
11
+ name_de = models.CharField(max_length=100, blank=True, null=True) # e.g. "Zentimeter"
12
+ name_en = models.CharField(max_length=100, blank=True, null=True) # e.g. "Centimeter"
13
+ description = models.CharField(max_length=100, blank=True, null=True) # e.g. "centimeters", "milimeters", "inches"
14
+ abbreviation = models.CharField(max_length=25, blank=True, null=True) # e.g. "cm", "mm", "in"
15
+
16
+ def __str__(self):
17
+ if self.abbreviation:
18
+ return self.abbreviation
19
+ return self.name
20
+
21
+ def natural_key(self):
20
22
  return (self.name,)
@@ -1,5 +1,5 @@
1
- from .annotations import (
2
- generate_legacy_dataset_output
3
- )
4
-
1
+ from .annotations import (
2
+ generate_legacy_dataset_output
3
+ )
4
+
5
5
  from .get import *
@@ -1,3 +1,3 @@
1
- from .legacy import (
2
- get_legacy_annotations_for_labelset, generate_legacy_dataset_output
1
+ from .legacy import (
2
+ get_legacy_annotations_for_labelset, generate_legacy_dataset_output
3
3
  )
@@ -1,159 +1,159 @@
1
- from ...models import LabelSet, ImageClassificationAnnotation
2
- from django.db.models import Q, F
3
- from django.db import models
4
- from icecream import ic
5
- from tqdm import tqdm
6
- from collections import defaultdict
7
-
8
- # def get_legacy_annotations_for_labelset(labelset_name, version=None):
9
- # """
10
- # Retrieve annotations for a given label set for training.
11
-
12
- # Args:
13
- # - labelset_name (str): The name of the label set.
14
- # - version (int, optional): The version of the label set. If not specified, the latest version is fetched.
15
-
16
- # Returns:
17
- # - list[dict]: A list of dictionaries. Each dictionary represents an image and its annotations.
18
- # Format: [{"frame": <frame_object>, "annotations": [{"label": <label_name>, "value": <value>}, ...]}, ...]
19
-
20
- # Example:
21
- # annotations_for_training = get_annotations_for_labelset("YourLabelSetName", version=2)
22
-
23
- # """
24
-
25
- # # Fetch the label set based on the name and optionally the version
26
- # if version:
27
- # labelset = LabelSet.objects.get(name=labelset_name, version=version)
28
- # else:
29
- # labelset = LabelSet.objects.filter(name=labelset_name).order_by('-version').first()
30
- # if not labelset:
31
- # raise ValueError(f"No label set found with the name: {labelset_name}")
32
-
33
- # # Retrieve all labels in the label set
34
- # labels_in_set = labelset.labels.all()
35
-
36
- # # Get the most recent annotations for each frame/label combination
37
- # annotations = ImageClassificationAnnotation.objects.filter(label__in=labels_in_set)
38
- # annotations = annotations.annotate(
39
- # latest_annotation=models.Window(
40
- # expression=models.functions.RowNumber(),
41
- # partition_by=[F('legacy_image'), F('label')],
42
- # order_by=F('date_modified').desc()
43
- # )
44
- # ).filter(latest_annotation=1)
45
-
46
- # # Organize the annotations by image/frame
47
- # organized_annotations = []
48
-
49
- # for annotation in tqdm(annotations):
50
- # # ic(annotation)
51
- # # Check if the frame is already in the organized list
52
- # existing_entry = next((entry for entry in organized_annotations if entry['legacy_image'] == annotation.legacy_frame), None)
53
-
54
- # if existing_entry:
55
- # # Add this annotation to the existing frame's annotations
56
- # existing_entry['annotations'].append({
57
- # "label": annotation.label.name,
58
- # "value": annotation.value
59
- # })
60
- # else:
61
- # # Create a new entry for this frame
62
- # organized_annotations.append({
63
- # "legacy_image": annotation.legacy_image,
64
- # "annotations": [{
65
- # "label": annotation.label.name,
66
- # "value": annotation.value
67
- # }]
68
- # })
69
-
70
- # return organized_annotations
71
-
72
-
73
-
74
- def get_legacy_annotations_for_labelset(labelset_name, version=None):
75
- """
76
- ... [rest of your docstring]
77
- """
78
-
79
- # Fetch the label set based on the name and optionally the version
80
- if version:
81
- labelset = LabelSet.objects.get(name=labelset_name, version=version)
82
- else:
83
- labelset = LabelSet.objects.filter(name=labelset_name).order_by('-version').first()
84
- if not labelset:
85
- raise ValueError(f"No label set found with the name: {labelset_name}")
86
-
87
- # Retrieve all labels in the label set
88
- labels_in_set = labelset.labels.all()
89
-
90
- # Get the most recent annotations for each frame/label combination
91
- annotations = (ImageClassificationAnnotation.objects
92
- .filter(label__in=labels_in_set)
93
- .select_related('legacy_image', 'label') # Reduce number of queries
94
- .annotate(
95
- latest_annotation=models.Window(
96
- expression=models.functions.RowNumber(),
97
- partition_by=[F('legacy_image'), F('label')],
98
- order_by=F('date_modified').desc()
99
- )
100
- ).filter(latest_annotation=1))
101
-
102
- # Organize the annotations by image/frame using a defaultdict
103
- organized_annotations_dict = defaultdict(lambda: {
104
- "legacy_image": None,
105
- "annotations": []
106
- })
107
-
108
- for annotation in tqdm(annotations):
109
- organized_entry = organized_annotations_dict[annotation.legacy_image.id]
110
- organized_entry["legacy_image"] = annotation.legacy_image
111
- organized_entry["annotations"].append({
112
- "label": annotation.label.name,
113
- "value": annotation.value
114
- })
115
-
116
- # Convert organized_annotations_dict to a list
117
- organized_annotations = list(organized_annotations_dict.values())
118
-
119
- return organized_annotations
120
-
121
- def generate_legacy_dataset_output(labelset_name, version=None):
122
- """
123
- Generate an output suitable for creating PyTorch datasets.
124
-
125
- Args:
126
- - labelset_name (str): The name of the label set.
127
- - version (int, optional): The version of the label set. If not specified, the latest version is fetched.
128
-
129
- Returns:
130
- - list[dict]: A list of dictionaries, where each dictionary contains the file path and the labels.
131
- Format: [{"path": <file_path>, "labels": [<label_1_value>, <label_2_value>, ...]}, ...]
132
- - labelset[LabelSet]: The label set that was used to generate the output.
133
- """
134
-
135
- # First, retrieve the organized annotations using the previously defined function
136
- organized_annotations = get_legacy_annotations_for_labelset(labelset_name, version)
137
-
138
- # Fetch all labels from the labelset for consistent ordering
139
- labelset = LabelSet.objects.get(name=labelset_name, version=version)
140
- all_labels = labelset.get_labels_in_order()
141
-
142
- dataset_output = []
143
-
144
- for entry in organized_annotations:
145
- # Prepare a dictionary for each frame
146
- frame_data = {
147
- "path": entry['legacy_image'].image.path, # Assuming 'image' field stores the file path
148
- "labels": [-1] * len(all_labels) # Initialize with -1 for all labels
149
- }
150
-
151
- # Update the labels based on the annotations
152
- for annotation in entry['annotations']:
153
- index = next((i for i, label in enumerate(all_labels) if label.name == annotation['label']), None)
154
- if index is not None:
155
- frame_data['labels'][index] = int(annotation['value'])
156
-
157
- dataset_output.append(frame_data)
158
-
159
- return dataset_output, labelset
1
+ from ...models import LabelSet, ImageClassificationAnnotation
2
+ from django.db.models import Q, F
3
+ from django.db import models
4
+ from icecream import ic
5
+ from tqdm import tqdm
6
+ from collections import defaultdict
7
+
8
+ # def get_legacy_annotations_for_labelset(labelset_name, version=None):
9
+ # """
10
+ # Retrieve annotations for a given label set for training.
11
+
12
+ # Args:
13
+ # - labelset_name (str): The name of the label set.
14
+ # - version (int, optional): The version of the label set. If not specified, the latest version is fetched.
15
+
16
+ # Returns:
17
+ # - list[dict]: A list of dictionaries. Each dictionary represents an image and its annotations.
18
+ # Format: [{"frame": <frame_object>, "annotations": [{"label": <label_name>, "value": <value>}, ...]}, ...]
19
+
20
+ # Example:
21
+ # annotations_for_training = get_annotations_for_labelset("YourLabelSetName", version=2)
22
+
23
+ # """
24
+
25
+ # # Fetch the label set based on the name and optionally the version
26
+ # if version:
27
+ # labelset = LabelSet.objects.get(name=labelset_name, version=version)
28
+ # else:
29
+ # labelset = LabelSet.objects.filter(name=labelset_name).order_by('-version').first()
30
+ # if not labelset:
31
+ # raise ValueError(f"No label set found with the name: {labelset_name}")
32
+
33
+ # # Retrieve all labels in the label set
34
+ # labels_in_set = labelset.labels.all()
35
+
36
+ # # Get the most recent annotations for each frame/label combination
37
+ # annotations = ImageClassificationAnnotation.objects.filter(label__in=labels_in_set)
38
+ # annotations = annotations.annotate(
39
+ # latest_annotation=models.Window(
40
+ # expression=models.functions.RowNumber(),
41
+ # partition_by=[F('legacy_image'), F('label')],
42
+ # order_by=F('date_modified').desc()
43
+ # )
44
+ # ).filter(latest_annotation=1)
45
+
46
+ # # Organize the annotations by image/frame
47
+ # organized_annotations = []
48
+
49
+ # for annotation in tqdm(annotations):
50
+ # # ic(annotation)
51
+ # # Check if the frame is already in the organized list
52
+ # existing_entry = next((entry for entry in organized_annotations if entry['legacy_image'] == annotation.legacy_frame), None)
53
+
54
+ # if existing_entry:
55
+ # # Add this annotation to the existing frame's annotations
56
+ # existing_entry['annotations'].append({
57
+ # "label": annotation.label.name,
58
+ # "value": annotation.value
59
+ # })
60
+ # else:
61
+ # # Create a new entry for this frame
62
+ # organized_annotations.append({
63
+ # "legacy_image": annotation.legacy_image,
64
+ # "annotations": [{
65
+ # "label": annotation.label.name,
66
+ # "value": annotation.value
67
+ # }]
68
+ # })
69
+
70
+ # return organized_annotations
71
+
72
+
73
+
74
+ def get_legacy_annotations_for_labelset(labelset_name, version=None):
75
+ """
76
+ ... [rest of your docstring]
77
+ """
78
+
79
+ # Fetch the label set based on the name and optionally the version
80
+ if version:
81
+ labelset = LabelSet.objects.get(name=labelset_name, version=version)
82
+ else:
83
+ labelset = LabelSet.objects.filter(name=labelset_name).order_by('-version').first()
84
+ if not labelset:
85
+ raise ValueError(f"No label set found with the name: {labelset_name}")
86
+
87
+ # Retrieve all labels in the label set
88
+ labels_in_set = labelset.labels.all()
89
+
90
+ # Get the most recent annotations for each frame/label combination
91
+ annotations = (ImageClassificationAnnotation.objects
92
+ .filter(label__in=labels_in_set)
93
+ .select_related('legacy_image', 'label') # Reduce number of queries
94
+ .annotate(
95
+ latest_annotation=models.Window(
96
+ expression=models.functions.RowNumber(),
97
+ partition_by=[F('legacy_image'), F('label')],
98
+ order_by=F('date_modified').desc()
99
+ )
100
+ ).filter(latest_annotation=1))
101
+
102
+ # Organize the annotations by image/frame using a defaultdict
103
+ organized_annotations_dict = defaultdict(lambda: {
104
+ "legacy_image": None,
105
+ "annotations": []
106
+ })
107
+
108
+ for annotation in tqdm(annotations):
109
+ organized_entry = organized_annotations_dict[annotation.legacy_image.id]
110
+ organized_entry["legacy_image"] = annotation.legacy_image
111
+ organized_entry["annotations"].append({
112
+ "label": annotation.label.name,
113
+ "value": annotation.value
114
+ })
115
+
116
+ # Convert organized_annotations_dict to a list
117
+ organized_annotations = list(organized_annotations_dict.values())
118
+
119
+ return organized_annotations
120
+
121
+ def generate_legacy_dataset_output(labelset_name, version=None):
122
+ """
123
+ Generate an output suitable for creating PyTorch datasets.
124
+
125
+ Args:
126
+ - labelset_name (str): The name of the label set.
127
+ - version (int, optional): The version of the label set. If not specified, the latest version is fetched.
128
+
129
+ Returns:
130
+ - list[dict]: A list of dictionaries, where each dictionary contains the file path and the labels.
131
+ Format: [{"path": <file_path>, "labels": [<label_1_value>, <label_2_value>, ...]}, ...]
132
+ - labelset[LabelSet]: The label set that was used to generate the output.
133
+ """
134
+
135
+ # First, retrieve the organized annotations using the previously defined function
136
+ organized_annotations = get_legacy_annotations_for_labelset(labelset_name, version)
137
+
138
+ # Fetch all labels from the labelset for consistent ordering
139
+ labelset = LabelSet.objects.get(name=labelset_name, version=version)
140
+ all_labels = labelset.get_labels_in_order()
141
+
142
+ dataset_output = []
143
+
144
+ for entry in organized_annotations:
145
+ # Prepare a dictionary for each frame
146
+ frame_data = {
147
+ "path": entry['legacy_image'].image.path, # Assuming 'image' field stores the file path
148
+ "labels": [-1] * len(all_labels) # Initialize with -1 for all labels
149
+ }
150
+
151
+ # Update the labels based on the annotations
152
+ for annotation in entry['annotations']:
153
+ index = next((i for i, label in enumerate(all_labels) if label.name == annotation['label']), None)
154
+ if index is not None:
155
+ frame_data['labels'][index] = int(annotation['value'])
156
+
157
+ dataset_output.append(frame_data)
158
+
159
+ return dataset_output, labelset