endoreg-db 0.8.4.1__py3-none-any.whl → 0.8.4.3__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.
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +23 -1
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/management/commands/load_ai_model_data.py +17 -15
- endoreg_db/management/commands/setup_endoreg_db.py +135 -51
- endoreg_db/models/medical/hardware/endoscopy_processor.py +10 -1
- endoreg_db/models/metadata/model_meta_logic.py +6 -2
- endoreg_db/services/video_import.py +152 -176
- endoreg_db/utils/setup_config.py +177 -0
- {endoreg_db-0.8.4.1.dist-info → endoreg_db-0.8.4.3.dist-info}/METADATA +1 -1
- {endoreg_db-0.8.4.1.dist-info → endoreg_db-0.8.4.3.dist-info}/RECORD +12 -10
- {endoreg_db-0.8.4.1.dist-info → endoreg_db-0.8.4.3.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.1.dist-info → endoreg_db-0.8.4.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,27 @@
|
|
|
1
|
+
# Model metadata configuration with setup hints
|
|
1
2
|
- model: endoreg_db.model_meta
|
|
2
3
|
fields:
|
|
3
4
|
name: "image_multilabel_classification_colonoscopy_default"
|
|
4
|
-
version: 1
|
|
5
|
+
version: "1"
|
|
6
|
+
model: "image_multilabel_classification_colonoscopy_default"
|
|
5
7
|
labelset: "multilabel_classification_colonoscopy_default"
|
|
8
|
+
activation: "sigmoid"
|
|
9
|
+
mean: "0.485,0.456,0.406" # ImageNet defaults
|
|
10
|
+
std: "0.229,0.224,0.225" # ImageNet defaults
|
|
11
|
+
size_x: 224
|
|
12
|
+
size_y: 224
|
|
13
|
+
axes: "CHW"
|
|
14
|
+
batchsize: 32
|
|
15
|
+
num_workers: 4
|
|
16
|
+
description: "Default colonoscopy image multilabel classification model from YAML"
|
|
17
|
+
# Note: weights field intentionally left empty - will be set by setup command or model meta logic
|
|
18
|
+
|
|
19
|
+
# Setup configuration hints for this model
|
|
20
|
+
setup_config:
|
|
21
|
+
is_primary_model: true # Mark this as the primary model for setup
|
|
22
|
+
weight_filenames: # Specific weight file patterns for this model
|
|
23
|
+
- "colo_segmentation_RegNetX800MF_6.ckpt"
|
|
24
|
+
- "image_multilabel_classification_colonoscopy_default_v1_*.ckpt"
|
|
25
|
+
huggingface_fallback: # HF configuration for this model
|
|
26
|
+
repo_id: "wg-lux/colo_segmentation_RegNetX800MF_base"
|
|
27
|
+
filename: "colo_segmentation_RegNetX800MF_base.ckpt"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# EndoReg DB Setup Configuration
|
|
2
|
+
# This file defines which models should be used for setup and their fallback configurations
|
|
3
|
+
|
|
4
|
+
default_models:
|
|
5
|
+
primary_classification_model: "image_multilabel_classification_colonoscopy_default"
|
|
6
|
+
primary_labelset: "multilabel_classification_colonoscopy_default"
|
|
7
|
+
|
|
8
|
+
# HuggingFace fallback configuration
|
|
9
|
+
huggingface_fallback:
|
|
10
|
+
enabled: true
|
|
11
|
+
repo_id: "wg-lux/colo_segmentation_RegNetX800MF_base"
|
|
12
|
+
filename: "colo_segmentation_RegNetX800MF_base.ckpt"
|
|
13
|
+
labelset_name: "multilabel_classification_colonoscopy_default"
|
|
14
|
+
|
|
15
|
+
# Local weights search patterns
|
|
16
|
+
weights_search_patterns:
|
|
17
|
+
# Primary model weight filename patterns (supports wildcards)
|
|
18
|
+
- "colo_segmentation_RegNetX800MF_*.ckpt"
|
|
19
|
+
- "image_multilabel_classification_colonoscopy_default_*.ckpt"
|
|
20
|
+
- "*_colonoscopy_*.ckpt"
|
|
21
|
+
|
|
22
|
+
# Search directories for local weights (relative to project root)
|
|
23
|
+
weights_search_dirs:
|
|
24
|
+
- "tests/assets"
|
|
25
|
+
- "assets"
|
|
26
|
+
- "data/storage/model_weights"
|
|
27
|
+
- "${STORAGE_DIR}/model_weights" # Environment variable substitution
|
|
28
|
+
|
|
29
|
+
# Auto-generation defaults when creating metadata
|
|
30
|
+
auto_generation_defaults:
|
|
31
|
+
activation: "sigmoid"
|
|
32
|
+
mean: "0.485,0.456,0.406" # ImageNet defaults
|
|
33
|
+
std: "0.229,0.224,0.225" # ImageNet defaults
|
|
34
|
+
size_x: 224
|
|
35
|
+
size_y: 224
|
|
36
|
+
axes: "CHW"
|
|
37
|
+
batchsize: 32
|
|
38
|
+
num_workers: 4
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
from django.core.management.base import BaseCommand
|
|
2
|
+
|
|
3
|
+
from ...data import (
|
|
4
|
+
AI_MODEL_DATA_DIR,
|
|
5
|
+
AI_MODEL_META_DATA_DIR, # Add this import
|
|
6
|
+
MODEL_TYPE_DATA_DIR,
|
|
7
|
+
VIDEO_SEGMENTATION_LABEL_DATA_DIR,
|
|
8
|
+
VIDEO_SEGMENTATION_LABELSET_DATA_DIR,
|
|
9
|
+
)
|
|
2
10
|
from ...models import (
|
|
11
|
+
AiModel,
|
|
12
|
+
ModelMeta, # Add ModelMeta back to imports
|
|
3
13
|
ModelType,
|
|
4
14
|
VideoSegmentationLabel,
|
|
5
15
|
VideoSegmentationLabelSet,
|
|
6
|
-
AiModel,
|
|
7
16
|
)
|
|
8
17
|
from ...utils import load_model_data_from_yaml
|
|
9
|
-
from ...data import (
|
|
10
|
-
MODEL_TYPE_DATA_DIR,
|
|
11
|
-
VIDEO_SEGMENTATION_LABEL_DATA_DIR,
|
|
12
|
-
VIDEO_SEGMENTATION_LABELSET_DATA_DIR,
|
|
13
|
-
AI_MODEL_DATA_DIR,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
18
|
|
|
17
19
|
IMPORT_MODELS = [ # string as model key, serves as key in IMPORT_METADATA
|
|
18
20
|
ModelType.__name__,
|
|
19
|
-
# ModelMeta.__name__,
|
|
20
21
|
VideoSegmentationLabel.__name__,
|
|
21
22
|
VideoSegmentationLabelSet.__name__,
|
|
22
23
|
AiModel.__name__,
|
|
24
|
+
ModelMeta.__name__, # Re-enable ModelMeta loading
|
|
23
25
|
]
|
|
24
26
|
|
|
25
27
|
IMPORT_METADATA = {
|
|
@@ -29,12 +31,12 @@ IMPORT_METADATA = {
|
|
|
29
31
|
"foreign_keys": [], # e.g. ["interventions"]
|
|
30
32
|
"foreign_key_models": [], # e.g. [Intervention]
|
|
31
33
|
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
ModelMeta.__name__: {
|
|
35
|
+
"dir": AI_MODEL_META_DATA_DIR, # e.g. "ai_model_meta"
|
|
36
|
+
"model": ModelMeta, # e.g. ModelMeta
|
|
37
|
+
"foreign_keys": ["labelset", "model"], # Foreign key relationships
|
|
38
|
+
"foreign_key_models": [VideoSegmentationLabelSet, AiModel], # Actual model classes
|
|
39
|
+
},
|
|
38
40
|
VideoSegmentationLabel.__name__: {
|
|
39
41
|
"dir": VIDEO_SEGMENTATION_LABEL_DATA_DIR, # e.g. "interventions"
|
|
40
42
|
"model": VideoSegmentationLabel, # e.g. Intervention
|
|
@@ -3,9 +3,6 @@ Django management command to perform complete setup for EndoReg DB when used as
|
|
|
3
3
|
This command ensures all necessary data and configurations are initialized.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
import os
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
6
|
from django.core.management import call_command
|
|
10
7
|
from django.core.management.base import BaseCommand
|
|
11
8
|
|
|
@@ -17,9 +14,10 @@ class Command(BaseCommand):
|
|
|
17
14
|
Complete setup for EndoReg DB when used as an embedded app.
|
|
18
15
|
This command performs all necessary initialization steps:
|
|
19
16
|
1. Loads base database data
|
|
20
|
-
2. Sets up
|
|
21
|
-
3.
|
|
22
|
-
4.
|
|
17
|
+
2. Sets up caching (if using db cache)
|
|
18
|
+
3. Loads default models from setup configuration file (setup_config.yaml)
|
|
19
|
+
4. Loads models according to fallback chain (Local Files -> HuggingFace -> graceful failure)
|
|
20
|
+
5. Initializes model metadata
|
|
23
21
|
"""
|
|
24
22
|
|
|
25
23
|
def add_arguments(self, parser):
|
|
@@ -33,13 +31,22 @@ class Command(BaseCommand):
|
|
|
33
31
|
action="store_true",
|
|
34
32
|
help="Force recreation of AI model metadata even if it exists",
|
|
35
33
|
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--yaml-only",
|
|
36
|
+
action="store_true",
|
|
37
|
+
help="Only use YAML-defined models, don't auto-generate missing metadata",
|
|
38
|
+
)
|
|
36
39
|
|
|
37
40
|
def handle(self, *args, **options):
|
|
38
41
|
skip_ai = options.get("skip_ai_setup", False)
|
|
39
42
|
force_recreate = options.get("force_recreate", False)
|
|
43
|
+
yaml_only = options.get("yaml_only", False)
|
|
40
44
|
|
|
41
45
|
self.stdout.write(self.style.SUCCESS("🚀 Starting EndoReg DB embedded app setup..."))
|
|
42
46
|
|
|
47
|
+
if yaml_only:
|
|
48
|
+
self.stdout.write(self.style.WARNING("📋 YAML-only mode: Will not auto-generate missing metadata"))
|
|
49
|
+
|
|
43
50
|
# Step 1: Load base database data
|
|
44
51
|
self.stdout.write("\n📊 Step 1: Loading base database data...")
|
|
45
52
|
try:
|
|
@@ -49,7 +56,7 @@ class Command(BaseCommand):
|
|
|
49
56
|
self.stdout.write(self.style.ERROR(f"❌ Failed to load base data: {e}"))
|
|
50
57
|
return
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
# Step 2: Create cache table (only if using database caching)
|
|
53
60
|
self.stdout.write("\n💾 Step 2: Setting up caching...")
|
|
54
61
|
from django.conf import settings
|
|
55
62
|
|
|
@@ -89,10 +96,16 @@ class Command(BaseCommand):
|
|
|
89
96
|
# Step 5: Create model metadata
|
|
90
97
|
self.stdout.write("\n📋 Step 5: Creating AI model metadata...")
|
|
91
98
|
try:
|
|
99
|
+
# Load setup configuration
|
|
100
|
+
from endoreg_db.utils.setup_config import setup_config
|
|
101
|
+
|
|
102
|
+
# Get primary model from configuration
|
|
103
|
+
default_model_name = setup_config.get_primary_model_name()
|
|
104
|
+
primary_labelset = setup_config.get_primary_labelset_name()
|
|
105
|
+
|
|
92
106
|
# Check if model metadata already exists
|
|
93
107
|
from endoreg_db.models import AiModel
|
|
94
108
|
|
|
95
|
-
default_model_name = "image_multilabel_classification_colonoscopy_default"
|
|
96
109
|
ai_model = AiModel.objects.filter(name=default_model_name).first()
|
|
97
110
|
|
|
98
111
|
if not ai_model:
|
|
@@ -103,14 +116,14 @@ class Command(BaseCommand):
|
|
|
103
116
|
if existing_meta and not force_recreate:
|
|
104
117
|
self.stdout.write(self.style.SUCCESS("✅ Model metadata already exists (use --force-recreate to recreate)"))
|
|
105
118
|
else:
|
|
106
|
-
# Try to create model metadata
|
|
119
|
+
# Try to create model metadata using configurable approach
|
|
107
120
|
model_path = self._find_model_weights_file()
|
|
108
121
|
if model_path:
|
|
109
122
|
call_command(
|
|
110
123
|
"create_multilabel_model_meta",
|
|
111
124
|
model_name=default_model_name,
|
|
112
125
|
model_meta_version=1,
|
|
113
|
-
image_classification_labelset_name=
|
|
126
|
+
image_classification_labelset_name=primary_labelset,
|
|
114
127
|
model_path=str(model_path),
|
|
115
128
|
)
|
|
116
129
|
self.stdout.write(self.style.SUCCESS("✅ AI model metadata created successfully"))
|
|
@@ -124,7 +137,7 @@ class Command(BaseCommand):
|
|
|
124
137
|
# Step 5.5: Validate and fix AI model active metadata
|
|
125
138
|
self.stdout.write("\n🔧 Step 5.5: Validating AI model active metadata...")
|
|
126
139
|
try:
|
|
127
|
-
self._validate_and_fix_ai_model_metadata()
|
|
140
|
+
self._validate_and_fix_ai_model_metadata(yaml_only)
|
|
128
141
|
self.stdout.write(self.style.SUCCESS("✅ AI model metadata validation completed"))
|
|
129
142
|
except Exception as e:
|
|
130
143
|
self.stdout.write(self.style.ERROR(f"❌ Failed to validate AI model metadata: {e}"))
|
|
@@ -146,33 +159,37 @@ class Command(BaseCommand):
|
|
|
146
159
|
self.stdout.write("3. Start development server: python manage.py runserver")
|
|
147
160
|
|
|
148
161
|
def _find_model_weights_file(self):
|
|
149
|
-
"""Find the model weights file
|
|
150
|
-
#
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
162
|
+
"""Find the model weights file using configurable search patterns and directories."""
|
|
163
|
+
# Load setup configuration
|
|
164
|
+
from endoreg_db.utils.setup_config import setup_config
|
|
165
|
+
|
|
166
|
+
# First try to find weights using configured patterns
|
|
167
|
+
found_files = setup_config.find_model_weights_files()
|
|
168
|
+
if found_files:
|
|
169
|
+
self.stdout.write(f"Found model weights at: {found_files[0]}")
|
|
170
|
+
return found_files[0]
|
|
171
|
+
|
|
172
|
+
# If no local weights found and HuggingFace fallback is enabled
|
|
173
|
+
hf_config = setup_config.get_huggingface_config()
|
|
174
|
+
if hf_config.get("enabled", True):
|
|
175
|
+
self.stdout.write("📦 No local model weights found — attempting HuggingFace download...")
|
|
176
|
+
try:
|
|
177
|
+
if not ModelMeta.objects.exists():
|
|
178
|
+
ModelMeta.setup_default_from_huggingface(
|
|
179
|
+
hf_config.get("repo_id", "wg-lux/colo_segmentation_RegNetX800MF_base"),
|
|
180
|
+
labelset_name=hf_config.get("labelset_name", "multilabel_classification_colonoscopy_default"),
|
|
181
|
+
)
|
|
182
|
+
self.stdout.write("✅ Default ModelMeta created from HuggingFace.")
|
|
183
|
+
|
|
184
|
+
# Try to find the downloaded weights
|
|
185
|
+
found_files = setup_config.find_model_weights_files()
|
|
186
|
+
if found_files:
|
|
187
|
+
return found_files[0]
|
|
173
188
|
|
|
174
|
-
|
|
189
|
+
except Exception as e:
|
|
190
|
+
self.stdout.write(f"⚠️ HuggingFace download failed: {e}")
|
|
175
191
|
|
|
192
|
+
self.stdout.write("Model weights file not found in configured locations")
|
|
176
193
|
return None
|
|
177
194
|
|
|
178
195
|
def _verify_setup(self):
|
|
@@ -214,16 +231,24 @@ class Command(BaseCommand):
|
|
|
214
231
|
|
|
215
232
|
self.stdout.write("Setup verification passed")
|
|
216
233
|
|
|
217
|
-
def _validate_and_fix_ai_model_metadata(self):
|
|
234
|
+
def _validate_and_fix_ai_model_metadata(self, yaml_only=False):
|
|
218
235
|
"""
|
|
219
236
|
Validate that all AI models have proper active metadata and fix if necessary.
|
|
220
237
|
This addresses the "No model metadata found for this model" error.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
yaml_only (bool): If True, only set active metadata but don't create new metadata
|
|
221
241
|
"""
|
|
222
242
|
from endoreg_db.models import AiModel, LabelSet, ModelMeta
|
|
243
|
+
from endoreg_db.utils.setup_config import setup_config
|
|
223
244
|
|
|
224
245
|
all_models = AiModel.objects.all()
|
|
225
246
|
fixed_count = 0
|
|
226
247
|
|
|
248
|
+
# Get configurable defaults
|
|
249
|
+
defaults = setup_config.get_auto_generation_defaults()
|
|
250
|
+
primary_labelset_name = setup_config.get_primary_labelset_name()
|
|
251
|
+
|
|
227
252
|
for model in all_models:
|
|
228
253
|
self.stdout.write(f"Checking model: {model.name}")
|
|
229
254
|
|
|
@@ -232,28 +257,59 @@ class Command(BaseCommand):
|
|
|
232
257
|
self.stdout.write(f" Metadata versions: {metadata_count}")
|
|
233
258
|
|
|
234
259
|
if metadata_count == 0:
|
|
260
|
+
if yaml_only:
|
|
261
|
+
self.stdout.write(f" ⚠️ YAML-only mode: Skipping auto-generation for {model.name}")
|
|
262
|
+
continue
|
|
263
|
+
|
|
235
264
|
# Create metadata for models that don't have any
|
|
236
265
|
self.stdout.write(f" Creating metadata for {model.name}...")
|
|
237
266
|
|
|
238
|
-
# Use
|
|
239
|
-
labelset =
|
|
240
|
-
|
|
241
|
-
labelset = LabelSet.objects.
|
|
242
|
-
|
|
243
|
-
|
|
267
|
+
# Use configured labelset or create default
|
|
268
|
+
labelset = None
|
|
269
|
+
try:
|
|
270
|
+
labelset = LabelSet.objects.get(name=primary_labelset_name)
|
|
271
|
+
except LabelSet.DoesNotExist:
|
|
272
|
+
labelset = LabelSet.objects.first()
|
|
273
|
+
if not labelset:
|
|
274
|
+
labelset = LabelSet.objects.create(name="default_colonoscopy_labels", description="Default colonoscopy classification labels")
|
|
275
|
+
|
|
276
|
+
# Create basic metadata WITH weights if available
|
|
277
|
+
weights_file = self._find_model_weights_file()
|
|
278
|
+
weights_path = ""
|
|
279
|
+
if weights_file:
|
|
280
|
+
# If we have weights, set up the relative path
|
|
281
|
+
from pathlib import Path
|
|
282
|
+
|
|
283
|
+
from endoreg_db.utils.paths import STORAGE_DIR
|
|
284
|
+
|
|
285
|
+
try:
|
|
286
|
+
weights_path = str(Path(weights_file).relative_to(STORAGE_DIR))
|
|
287
|
+
except ValueError:
|
|
288
|
+
# If file is not in storage dir, copy it there
|
|
289
|
+
import shutil
|
|
290
|
+
|
|
291
|
+
weights_dir = STORAGE_DIR / "model_weights"
|
|
292
|
+
weights_dir.mkdir(parents=True, exist_ok=True)
|
|
293
|
+
dest_path = weights_dir / Path(weights_file).name
|
|
294
|
+
shutil.copy2(weights_file, dest_path)
|
|
295
|
+
weights_path = str(dest_path.relative_to(STORAGE_DIR))
|
|
296
|
+
self.stdout.write(f" Copied weights to: {dest_path}")
|
|
297
|
+
|
|
298
|
+
# Create basic metadata using configurable defaults
|
|
244
299
|
meta = ModelMeta.objects.create(
|
|
245
300
|
name=model.name,
|
|
246
301
|
version="1.0",
|
|
247
302
|
model=model,
|
|
248
303
|
labelset=labelset,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
304
|
+
weights=weights_path, # Set weights if available
|
|
305
|
+
activation=defaults.get("activation", "sigmoid"),
|
|
306
|
+
mean=defaults.get("mean", "0.485,0.456,0.406"),
|
|
307
|
+
std=defaults.get("std", "0.229,0.224,0.225"),
|
|
308
|
+
size_x=defaults.get("size_x", 224),
|
|
309
|
+
size_y=defaults.get("size_y", 224),
|
|
310
|
+
axes=defaults.get("axes", "CHW"),
|
|
311
|
+
batchsize=defaults.get("batchsize", 32),
|
|
312
|
+
num_workers=defaults.get("num_workers", 4),
|
|
257
313
|
description=f"Auto-generated metadata for {model.name}",
|
|
258
314
|
)
|
|
259
315
|
|
|
@@ -267,6 +323,34 @@ class Command(BaseCommand):
|
|
|
267
323
|
first_meta = model.metadata_versions.first()
|
|
268
324
|
if first_meta:
|
|
269
325
|
self.stdout.write(f" Setting active metadata for {model.name}...")
|
|
326
|
+
|
|
327
|
+
# Check if the metadata has weights - if not, try to assign them
|
|
328
|
+
if not first_meta.weights:
|
|
329
|
+
self.stdout.write(" Metadata exists but no weights assigned, attempting to add weights...")
|
|
330
|
+
weights_file = self._find_model_weights_file()
|
|
331
|
+
if weights_file:
|
|
332
|
+
from pathlib import Path
|
|
333
|
+
|
|
334
|
+
from endoreg_db.utils.paths import STORAGE_DIR
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
weights_path = str(Path(weights_file).relative_to(STORAGE_DIR))
|
|
338
|
+
except ValueError:
|
|
339
|
+
# Copy weights to storage if not already there
|
|
340
|
+
import shutil
|
|
341
|
+
|
|
342
|
+
weights_dir = STORAGE_DIR / "model_weights"
|
|
343
|
+
weights_dir.mkdir(parents=True, exist_ok=True)
|
|
344
|
+
dest_path = weights_dir / Path(weights_file).name
|
|
345
|
+
shutil.copy2(weights_file, dest_path)
|
|
346
|
+
weights_path = str(dest_path.relative_to(STORAGE_DIR))
|
|
347
|
+
self.stdout.write(f" Copied weights to: {dest_path}")
|
|
348
|
+
|
|
349
|
+
# Assign the relative path to the FileField
|
|
350
|
+
first_meta.weights.name = weights_path
|
|
351
|
+
first_meta.save(update_fields=["weights"])
|
|
352
|
+
self.stdout.write(f" Added weights to existing metadata: {weights_path}")
|
|
353
|
+
|
|
270
354
|
model.active_meta = first_meta
|
|
271
355
|
model.save()
|
|
272
356
|
fixed_count += 1
|
|
@@ -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[
|
|
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
|
+
}
|
|
@@ -139,8 +139,8 @@ def create_from_file_logic(
|
|
|
139
139
|
# --- Optionally update AiModel's active_meta ---
|
|
140
140
|
# You might want to add logic here to automatically set the newly created/updated
|
|
141
141
|
# meta as the active one for the AiModel, e.g.:
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
ai_model.active_meta = model_meta
|
|
143
|
+
ai_model.save()
|
|
144
144
|
|
|
145
145
|
return model_meta
|
|
146
146
|
|
|
@@ -308,6 +308,10 @@ def setup_default_from_huggingface_logic(cls, model_id: str, labelset_name: str
|
|
|
308
308
|
|
|
309
309
|
ai_model, _ = AiModel.objects.get_or_create(name=meta["name"])
|
|
310
310
|
labelset = LabelSet.objects.first() if not labelset_name else LabelSet.objects.get(name=labelset_name)
|
|
311
|
+
model_meta = ModelMeta.objects.filter(name=meta["name"], model=ai_model).first()
|
|
312
|
+
if model_meta:
|
|
313
|
+
logger.info(f"ModelMeta {meta['name']} for model {ai_model.name} already exists. Skipping creation.")
|
|
314
|
+
return model_meta
|
|
311
315
|
|
|
312
316
|
return create_from_file_logic(
|
|
313
317
|
cls,
|