endoreg-db 0.8.3.3__py3-none-any.whl → 0.8.6.5__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 (41) hide show
  1. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +23 -1
  2. endoreg_db/data/setup_config.yaml +38 -0
  3. endoreg_db/management/commands/create_model_meta_from_huggingface.py +1 -2
  4. endoreg_db/management/commands/load_ai_model_data.py +18 -15
  5. endoreg_db/management/commands/setup_endoreg_db.py +218 -33
  6. endoreg_db/models/media/pdf/raw_pdf.py +241 -97
  7. endoreg_db/models/media/video/pipe_1.py +30 -33
  8. endoreg_db/models/media/video/video_file.py +300 -187
  9. endoreg_db/models/medical/hardware/endoscopy_processor.py +10 -1
  10. endoreg_db/models/metadata/model_meta_logic.py +34 -45
  11. endoreg_db/models/metadata/sensitive_meta_logic.py +555 -150
  12. endoreg_db/serializers/__init__.py +26 -55
  13. endoreg_db/serializers/misc/__init__.py +1 -1
  14. endoreg_db/serializers/misc/file_overview.py +65 -35
  15. endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
  16. endoreg_db/serializers/video_examination.py +198 -0
  17. endoreg_db/services/lookup_service.py +228 -58
  18. endoreg_db/services/lookup_store.py +174 -30
  19. endoreg_db/services/pdf_import.py +585 -282
  20. endoreg_db/services/video_import.py +493 -240
  21. endoreg_db/urls/__init__.py +36 -23
  22. endoreg_db/urls/label_video_segments.py +2 -0
  23. endoreg_db/urls/media.py +103 -66
  24. endoreg_db/utils/setup_config.py +177 -0
  25. endoreg_db/views/__init__.py +5 -3
  26. endoreg_db/views/media/pdf_media.py +3 -1
  27. endoreg_db/views/media/video_media.py +1 -1
  28. endoreg_db/views/media/video_segments.py +187 -259
  29. endoreg_db/views/pdf/__init__.py +5 -8
  30. endoreg_db/views/pdf/pdf_stream.py +186 -0
  31. endoreg_db/views/pdf/reimport.py +110 -94
  32. endoreg_db/views/requirement/lookup.py +171 -287
  33. endoreg_db/views/video/__init__.py +0 -2
  34. endoreg_db/views/video/video_examination_viewset.py +202 -289
  35. {endoreg_db-0.8.3.3.dist-info → endoreg_db-0.8.6.5.dist-info}/METADATA +1 -2
  36. {endoreg_db-0.8.3.3.dist-info → endoreg_db-0.8.6.5.dist-info}/RECORD +38 -37
  37. endoreg_db/views/pdf/pdf_media.py +0 -239
  38. endoreg_db/views/pdf/pdf_stream_views.py +0 -127
  39. endoreg_db/views/video/video_media.py +0 -158
  40. {endoreg_db-0.8.3.3.dist-info → endoreg_db-0.8.6.5.dist-info}/WHEEL +0 -0
  41. {endoreg_db-0.8.3.3.dist-info → endoreg_db-0.8.6.5.dist-info}/licenses/LICENSE +0 -0
@@ -160,7 +160,7 @@ class EndoscopyProcessor(models.Model):
160
160
  "height": self.endoscope_sn_height,
161
161
  }
162
162
 
163
- def get_rois(self) -> dict[ str, dict[str, int | None] | None]:
163
+ def get_rois(self) -> dict[str, dict[str, int | None] | None]:
164
164
  return {
165
165
  "endoscope_image": self.get_roi_endoscope_image(),
166
166
  "examination_date": self.get_roi_examination_date(),
@@ -171,3 +171,12 @@ class EndoscopyProcessor(models.Model):
171
171
  "endoscope_type": self.get_roi_endoscope_type(),
172
172
  "endoscope_sn": self.get_roi_endoscopy_sn(),
173
173
  }
174
+
175
+ def get_sensitive_rois(self) -> dict[str, dict[str, int | None] | None]:
176
+ return {
177
+ "examination_date": self.get_roi_examination_date(),
178
+ "examination_time": self.get_roi_examination_time(),
179
+ "patient_first_name": self.get_roi_patient_first_name(),
180
+ "patient_last_name": self.get_roi_patient_last_name(),
181
+ "patient_dob": self.get_roi_patient_dob(),
182
+ }
@@ -3,6 +3,7 @@ from logging import getLogger
3
3
  from pathlib import Path
4
4
  from typing import TYPE_CHECKING, Any, Optional, Type
5
5
 
6
+ from django.core.files import File
6
7
  from django.db import transaction
7
8
  from huggingface_hub import hf_hub_download
8
9
 
@@ -18,18 +19,21 @@ if TYPE_CHECKING:
18
19
  from .model_meta import ModelMeta # Import ModelMeta for type hinting
19
20
 
20
21
 
21
- def get_latest_version_number_logic(
22
- cls: Type["ModelMeta"], meta_name: str, model_name: str
23
- ) -> int:
22
+ def _get_model_meta_class():
23
+ """Lazy import to avoid circular imports"""
24
+ from .model_meta import ModelMeta
25
+
26
+ return ModelMeta
27
+
28
+
29
+ def get_latest_version_number_logic(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> int:
24
30
  """
25
31
  Finds the highest numerical version for a given meta_name and model_name.
26
32
  Iterates through all versions, attempts to parse them as integers,
27
33
  and returns the maximum integer found. If no numeric versions are found,
28
34
  returns 0.
29
35
  """
30
- versions_qs = cls.objects.filter(
31
- name=meta_name, model__name=model_name
32
- ).values_list("version", flat=True)
36
+ versions_qs = cls.objects.filter(name=meta_name, model__name=model_name).values_list("version", flat=True)
33
37
 
34
38
  max_v = 0
35
39
  found_numeric_version = False
@@ -84,24 +88,17 @@ def create_from_file_logic(
84
88
 
85
89
  if requested_version:
86
90
  target_version = str(requested_version)
87
- existing = cls.objects.filter(
88
- name=meta_name, model=ai_model, version=target_version
89
- ).first()
91
+ existing = cls.objects.filter(name=meta_name, model=ai_model, version=target_version).first()
90
92
  if existing and not bump_if_exists:
91
93
  raise ValueError(
92
- f"ModelMeta '{meta_name}' version '{target_version}' for model '{model_name}' "
93
- f"already exists. Use bump_if_exists=True to increment."
94
+ f"ModelMeta '{meta_name}' version '{target_version}' for model '{model_name}' already exists. Use bump_if_exists=True to increment."
94
95
  )
95
96
  elif existing and bump_if_exists:
96
97
  target_version = str(latest_version_num + 1)
97
- logger.info(
98
- f"Bumping version for {meta_name}/{model_name} to {target_version}"
99
- )
98
+ logger.info(f"Bumping version for {meta_name}/{model_name} to {target_version}")
100
99
  else:
101
100
  target_version = str(latest_version_num + 1)
102
- logger.info(
103
- f"Setting next version for {meta_name}/{model_name} to {target_version}"
104
- )
101
+ logger.info(f"Setting next version for {meta_name}/{model_name} to {target_version}")
105
102
 
106
103
  # --- Prepare Weights File ---
107
104
  source_weights_path = Path(weights_file).resolve()
@@ -111,10 +108,7 @@ def create_from_file_logic(
111
108
  # Construct destination path within MEDIA_ROOT/WEIGHTS_DIR
112
109
  weights_filename = source_weights_path.name
113
110
  # Relative path for the FileField upload_to
114
- relative_dest_path = (
115
- Path(WEIGHTS_DIR.relative_to(STORAGE_DIR))
116
- / f"{meta_name}_v{target_version}_{weights_filename}"
117
- )
111
+ relative_dest_path = Path(WEIGHTS_DIR.relative_to(STORAGE_DIR)) / f"{meta_name}_v{target_version}_{weights_filename}"
118
112
  # Full path for shutil.copy
119
113
  full_dest_path = STORAGE_DIR / relative_dest_path
120
114
 
@@ -153,8 +147,8 @@ def create_from_file_logic(
153
147
  # --- Optionally update AiModel's active_meta ---
154
148
  # You might want to add logic here to automatically set the newly created/updated
155
149
  # meta as the active one for the AiModel, e.g.:
156
- # ai_model.active_meta = model_meta
157
- # ai_model.save()
150
+ ai_model.active_meta = model_meta
151
+ ai_model.save()
158
152
 
159
153
  return model_meta
160
154
 
@@ -233,22 +227,14 @@ def get_model_meta_by_name_version_logic(
233
227
  try:
234
228
  return cls.objects.get(name=meta_name, model=ai_model, version=version)
235
229
  except Exception as exc:
236
- raise cls.DoesNotExist(
237
- f"ModelMeta '{meta_name}' version '{version}' for model '{model_name}' not found."
238
- ) from exc
230
+ raise cls.DoesNotExist(f"ModelMeta '{meta_name}' version '{version}' for model '{model_name}' not found.") from exc
239
231
  else:
240
232
  # Get latest version
241
- latest = (
242
- cls.objects.filter(name=meta_name, model=ai_model)
243
- .order_by("-date_created")
244
- .first()
245
- )
233
+ latest = cls.objects.filter(name=meta_name, model=ai_model).order_by("-date_created").first()
246
234
  if latest:
247
235
  return latest
248
236
  else:
249
- raise cls.DoesNotExist(
250
- f"No ModelMeta found for '{meta_name}' and model '{model_name}'."
251
- )
237
+ raise cls.DoesNotExist(f"No ModelMeta found for '{meta_name}' and model '{model_name}'.")
252
238
 
253
239
 
254
240
  import re
@@ -266,9 +252,7 @@ def infer_default_model_meta_from_hf(model_id: str) -> dict[str, Any]:
266
252
  """
267
253
 
268
254
  if not (info := model_info(model_id)):
269
- logger.info(
270
- f"Could not retrieve model info for {model_id}, using ColoReg segmentation defaults."
271
- )
255
+ logger.info(f"Could not retrieve model info for {model_id}, using ColoReg segmentation defaults.")
272
256
  return {
273
257
  "name": "wg-lux/colo_segmentation_RegNetX800MF_base",
274
258
  "activation": "sigmoid",
@@ -317,9 +301,7 @@ def infer_default_model_meta_from_hf(model_id: str) -> dict[str, Any]:
317
301
  }
318
302
 
319
303
 
320
- def setup_default_from_huggingface_logic(
321
- cls, model_id: str, labelset_name: str | None = None
322
- ):
304
+ def setup_default_from_huggingface_logic(cls, model_id: str, labelset_name: str | None = None):
323
305
  """
324
306
  Downloads model weights from Hugging Face and auto-fills ModelMeta fields.
325
307
  """
@@ -333,11 +315,18 @@ def setup_default_from_huggingface_logic(
333
315
  )
334
316
 
335
317
  ai_model, _ = AiModel.objects.get_or_create(name=meta["name"])
336
- labelset = (
337
- LabelSet.objects.first()
338
- if not labelset_name
339
- else LabelSet.objects.get(name=labelset_name)
340
- )
318
+ if not labelset_name:
319
+ labelset = LabelSet.objects.first()
320
+ if not labelset:
321
+ raise ValueError("No labelset found and no labelset_name provided")
322
+ else:
323
+ labelset = LabelSet.objects.get(name=labelset_name)
324
+
325
+ ModelMeta = _get_model_meta_class()
326
+ model_meta = ModelMeta.objects.filter(name=meta["name"], model=ai_model).first()
327
+ if model_meta:
328
+ logger.info(f"ModelMeta {meta['name']} for model {ai_model.name} already exists. Skipping creation.")
329
+ return model_meta
341
330
 
342
331
  return create_from_file_logic(
343
332
  cls,