endoreg-db 0.8.4.0__py3-none-any.whl → 0.8.4.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.
- endoreg_db/management/commands/setup_endoreg_db.py +91 -7
- endoreg_db/management/commands/validate_ai_models.py +124 -0
- endoreg_db/models/metadata/model_meta_logic.py +109 -43
- {endoreg_db-0.8.4.0.dist-info → endoreg_db-0.8.4.1.dist-info}/METADATA +1 -1
- {endoreg_db-0.8.4.0.dist-info → endoreg_db-0.8.4.1.dist-info}/RECORD +7 -6
- {endoreg_db-0.8.4.0.dist-info → endoreg_db-0.8.4.1.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.0.dist-info → endoreg_db-0.8.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,8 +8,10 @@ from pathlib import Path
|
|
|
8
8
|
|
|
9
9
|
from django.core.management import call_command
|
|
10
10
|
from django.core.management.base import BaseCommand
|
|
11
|
+
|
|
11
12
|
from endoreg_db.models import ModelMeta
|
|
12
13
|
|
|
14
|
+
|
|
13
15
|
class Command(BaseCommand):
|
|
14
16
|
help = """
|
|
15
17
|
Complete setup for EndoReg DB when used as an embedded app.
|
|
@@ -119,6 +121,15 @@ class Command(BaseCommand):
|
|
|
119
121
|
self.stdout.write(self.style.ERROR(f"❌ Failed to create AI model metadata: {e}"))
|
|
120
122
|
return
|
|
121
123
|
|
|
124
|
+
# Step 5.5: Validate and fix AI model active metadata
|
|
125
|
+
self.stdout.write("\n🔧 Step 5.5: Validating AI model active metadata...")
|
|
126
|
+
try:
|
|
127
|
+
self._validate_and_fix_ai_model_metadata()
|
|
128
|
+
self.stdout.write(self.style.SUCCESS("✅ AI model metadata validation completed"))
|
|
129
|
+
except Exception as e:
|
|
130
|
+
self.stdout.write(self.style.ERROR(f"❌ Failed to validate AI model metadata: {e}"))
|
|
131
|
+
return
|
|
132
|
+
|
|
122
133
|
# Step 6: Verification
|
|
123
134
|
self.stdout.write("\n🔍 Step 6: Verifying setup...")
|
|
124
135
|
try:
|
|
@@ -137,12 +148,11 @@ class Command(BaseCommand):
|
|
|
137
148
|
def _find_model_weights_file(self):
|
|
138
149
|
"""Find the model weights file in various possible locations."""
|
|
139
150
|
# Check common locations for model weights
|
|
140
|
-
|
|
151
|
+
|
|
141
152
|
if not ModelMeta.objects.exists():
|
|
142
153
|
print("📦 No model metadata found — creating from Hugging Face...")
|
|
143
154
|
ModelMeta.setup_default_from_huggingface(
|
|
144
|
-
"wg-lux/colo_segmentation_RegNetX800MF_base",
|
|
145
|
-
labelset_name="multilabel_classification_colonoscopy_default"
|
|
155
|
+
"wg-lux/colo_segmentation_RegNetX800MF_base", labelset_name="multilabel_classification_colonoscopy_default"
|
|
146
156
|
)
|
|
147
157
|
print("✅ Default ModelMeta created.")
|
|
148
158
|
possible_paths = [
|
|
@@ -162,10 +172,8 @@ class Command(BaseCommand):
|
|
|
162
172
|
return path
|
|
163
173
|
|
|
164
174
|
self.stdout.write("Model weights file not found in standard locations")
|
|
165
|
-
|
|
166
|
-
return None
|
|
167
|
-
|
|
168
175
|
|
|
176
|
+
return None
|
|
169
177
|
|
|
170
178
|
def _verify_setup(self):
|
|
171
179
|
"""Verify that the setup was successful."""
|
|
@@ -205,5 +213,81 @@ class Command(BaseCommand):
|
|
|
205
213
|
self.stdout.write(f"Found {meta_count} model metadata record(s)")
|
|
206
214
|
|
|
207
215
|
self.stdout.write("Setup verification passed")
|
|
208
|
-
|
|
209
216
|
|
|
217
|
+
def _validate_and_fix_ai_model_metadata(self):
|
|
218
|
+
"""
|
|
219
|
+
Validate that all AI models have proper active metadata and fix if necessary.
|
|
220
|
+
This addresses the "No model metadata found for this model" error.
|
|
221
|
+
"""
|
|
222
|
+
from endoreg_db.models import AiModel, LabelSet, ModelMeta
|
|
223
|
+
|
|
224
|
+
all_models = AiModel.objects.all()
|
|
225
|
+
fixed_count = 0
|
|
226
|
+
|
|
227
|
+
for model in all_models:
|
|
228
|
+
self.stdout.write(f"Checking model: {model.name}")
|
|
229
|
+
|
|
230
|
+
# Check if model has metadata versions
|
|
231
|
+
metadata_count = model.metadata_versions.count()
|
|
232
|
+
self.stdout.write(f" Metadata versions: {metadata_count}")
|
|
233
|
+
|
|
234
|
+
if metadata_count == 0:
|
|
235
|
+
# Create metadata for models that don't have any
|
|
236
|
+
self.stdout.write(f" Creating metadata for {model.name}...")
|
|
237
|
+
|
|
238
|
+
# Use existing labelset or create default
|
|
239
|
+
labelset = LabelSet.objects.first()
|
|
240
|
+
if not labelset:
|
|
241
|
+
labelset = LabelSet.objects.create(name="default_colonoscopy_labels", description="Default colonoscopy classification labels")
|
|
242
|
+
|
|
243
|
+
# Create basic metadata
|
|
244
|
+
meta = ModelMeta.objects.create(
|
|
245
|
+
name=model.name,
|
|
246
|
+
version="1.0",
|
|
247
|
+
model=model,
|
|
248
|
+
labelset=labelset,
|
|
249
|
+
activation="sigmoid" if "classification" in model.name else "sigmoid",
|
|
250
|
+
mean="0.485,0.456,0.406", # ImageNet defaults
|
|
251
|
+
std="0.229,0.224,0.225", # ImageNet defaults
|
|
252
|
+
size_x=224,
|
|
253
|
+
size_y=224,
|
|
254
|
+
axes="CHW",
|
|
255
|
+
batchsize=32,
|
|
256
|
+
num_workers=4,
|
|
257
|
+
description=f"Auto-generated metadata for {model.name}",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
model.active_meta = meta
|
|
261
|
+
model.save()
|
|
262
|
+
fixed_count += 1
|
|
263
|
+
self.stdout.write(f" ✅ Created and set metadata for {model.name}")
|
|
264
|
+
|
|
265
|
+
elif not model.active_meta:
|
|
266
|
+
# Model has metadata but no active meta set
|
|
267
|
+
first_meta = model.metadata_versions.first()
|
|
268
|
+
if first_meta:
|
|
269
|
+
self.stdout.write(f" Setting active metadata for {model.name}...")
|
|
270
|
+
model.active_meta = first_meta
|
|
271
|
+
model.save()
|
|
272
|
+
fixed_count += 1
|
|
273
|
+
self.stdout.write(f" ✅ Set active metadata: {first_meta.name} v{first_meta.version}")
|
|
274
|
+
else:
|
|
275
|
+
self.stdout.write(f" ⚠️ No metadata versions available for {model.name}")
|
|
276
|
+
|
|
277
|
+
else:
|
|
278
|
+
self.stdout.write(f" ✅ Model {model.name} has active metadata: {model.active_meta}")
|
|
279
|
+
|
|
280
|
+
# Verify all models can get latest version
|
|
281
|
+
self.stdout.write("\nTesting model metadata access...")
|
|
282
|
+
for model in all_models:
|
|
283
|
+
try:
|
|
284
|
+
latest = model.get_latest_version()
|
|
285
|
+
self.stdout.write(f" ✅ {model.name}: {latest}")
|
|
286
|
+
except Exception as e:
|
|
287
|
+
self.stdout.write(f" ❌ {model.name}: {e}")
|
|
288
|
+
raise Exception(f"Model {model.name} still has metadata issues: {e}")
|
|
289
|
+
|
|
290
|
+
if fixed_count > 0:
|
|
291
|
+
self.stdout.write(f"Fixed metadata for {fixed_count} model(s)")
|
|
292
|
+
else:
|
|
293
|
+
self.stdout.write("All models already had proper metadata")
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django management command to validate and fix AI model metadata issues.
|
|
3
|
+
This command addresses the "No model metadata found for this model" error.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from django.core.management.base import BaseCommand
|
|
7
|
+
|
|
8
|
+
from endoreg_db.models.metadata.model_meta_logic import validate_and_fix_ai_model_metadata_logic
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Command(BaseCommand):
|
|
12
|
+
help = """
|
|
13
|
+
Validate and fix AI model metadata to prevent processing errors.
|
|
14
|
+
|
|
15
|
+
This command:
|
|
16
|
+
- Checks all AI models for proper metadata configuration
|
|
17
|
+
- Creates missing metadata with sensible defaults
|
|
18
|
+
- Sets active metadata for models that don't have it
|
|
19
|
+
- Validates that all models can access their latest versions
|
|
20
|
+
|
|
21
|
+
Use this command to fix "No model metadata found for this model" errors.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def add_arguments(self, parser):
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--dry-run",
|
|
27
|
+
action="store_true",
|
|
28
|
+
help="Show what would be fixed without making changes",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--force",
|
|
32
|
+
action="store_true",
|
|
33
|
+
help="Force recreation of existing metadata",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def handle(self, *args, **options):
|
|
37
|
+
dry_run = options.get("dry_run", False)
|
|
38
|
+
force = options.get("force", False)
|
|
39
|
+
|
|
40
|
+
self.stdout.write(self.style.SUCCESS("🔍 Validating AI model metadata..."))
|
|
41
|
+
|
|
42
|
+
if dry_run:
|
|
43
|
+
self.stdout.write(self.style.WARNING("🧪 DRY RUN MODE - No changes will be made"))
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
if dry_run:
|
|
47
|
+
# In dry run, we just check and report issues
|
|
48
|
+
summary = self._check_ai_models_dry_run()
|
|
49
|
+
else:
|
|
50
|
+
# Actually fix the issues
|
|
51
|
+
summary = validate_and_fix_ai_model_metadata_logic()
|
|
52
|
+
|
|
53
|
+
# Report results
|
|
54
|
+
self._report_summary(summary)
|
|
55
|
+
|
|
56
|
+
if summary["errors"]:
|
|
57
|
+
self.stdout.write(self.style.ERROR("❌ Validation completed with errors"))
|
|
58
|
+
for error in summary["errors"]:
|
|
59
|
+
self.stdout.write(self.style.ERROR(f" - {error}"))
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
self.stdout.write(self.style.SUCCESS("✅ AI model metadata validation completed successfully"))
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
self.stdout.write(self.style.ERROR(f"❌ Validation failed: {e}"))
|
|
66
|
+
raise
|
|
67
|
+
|
|
68
|
+
def _check_ai_models_dry_run(self):
|
|
69
|
+
"""Check AI models without making changes."""
|
|
70
|
+
from endoreg_db.models import AiModel
|
|
71
|
+
|
|
72
|
+
summary = {"models_checked": 0, "models_fixed": 0, "metadata_created": 0, "active_meta_set": 0, "errors": []}
|
|
73
|
+
|
|
74
|
+
all_models = AiModel.objects.all()
|
|
75
|
+
summary["models_checked"] = all_models.count()
|
|
76
|
+
|
|
77
|
+
for model in all_models:
|
|
78
|
+
self.stdout.write(f"Checking model: {model.name}")
|
|
79
|
+
|
|
80
|
+
metadata_count = model.metadata_versions.count()
|
|
81
|
+
self.stdout.write(f" Metadata versions: {metadata_count}")
|
|
82
|
+
|
|
83
|
+
if metadata_count == 0:
|
|
84
|
+
self.stdout.write(f" 🔧 Would create metadata for {model.name}")
|
|
85
|
+
summary["models_fixed"] += 1
|
|
86
|
+
summary["metadata_created"] += 1
|
|
87
|
+
|
|
88
|
+
elif not model.active_meta:
|
|
89
|
+
self.stdout.write(f" 🔧 Would set active metadata for {model.name}")
|
|
90
|
+
summary["models_fixed"] += 1
|
|
91
|
+
summary["active_meta_set"] += 1
|
|
92
|
+
|
|
93
|
+
else:
|
|
94
|
+
self.stdout.write(f" ✅ Model {model.name} has valid active metadata")
|
|
95
|
+
|
|
96
|
+
# Test metadata access
|
|
97
|
+
try:
|
|
98
|
+
latest = model.get_latest_version()
|
|
99
|
+
self.stdout.write(f" ✅ Can access latest version: {latest}")
|
|
100
|
+
except Exception as e:
|
|
101
|
+
error_msg = f"Model {model.name} metadata test failed: {e}"
|
|
102
|
+
self.stdout.write(self.style.ERROR(f" ❌ {error_msg}"))
|
|
103
|
+
summary["errors"].append(error_msg)
|
|
104
|
+
|
|
105
|
+
return summary
|
|
106
|
+
|
|
107
|
+
def _report_summary(self, summary):
|
|
108
|
+
"""Report the validation summary."""
|
|
109
|
+
self.stdout.write("\n📊 Validation Summary:")
|
|
110
|
+
self.stdout.write(f" Models checked: {summary['models_checked']}")
|
|
111
|
+
|
|
112
|
+
if summary["models_fixed"] > 0:
|
|
113
|
+
self.stdout.write(f" Models fixed: {summary['models_fixed']}")
|
|
114
|
+
|
|
115
|
+
if summary["metadata_created"] > 0:
|
|
116
|
+
self.stdout.write(f" Metadata created: {summary['metadata_created']}")
|
|
117
|
+
|
|
118
|
+
if summary["active_meta_set"] > 0:
|
|
119
|
+
self.stdout.write(f" Active metadata set: {summary['active_meta_set']}")
|
|
120
|
+
|
|
121
|
+
if summary["errors"]:
|
|
122
|
+
self.stdout.write(f" Errors encountered: {len(summary['errors'])}")
|
|
123
|
+
else:
|
|
124
|
+
self.stdout.write(" No errors found")
|
|
@@ -18,18 +18,14 @@ if TYPE_CHECKING:
|
|
|
18
18
|
from .model_meta import ModelMeta # Import ModelMeta for type hinting
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def get_latest_version_number_logic(
|
|
22
|
-
cls: Type["ModelMeta"], meta_name: str, model_name: str
|
|
23
|
-
) -> int:
|
|
21
|
+
def get_latest_version_number_logic(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> int:
|
|
24
22
|
"""
|
|
25
23
|
Finds the highest numerical version for a given meta_name and model_name.
|
|
26
24
|
Iterates through all versions, attempts to parse them as integers,
|
|
27
25
|
and returns the maximum integer found. If no numeric versions are found,
|
|
28
26
|
returns 0.
|
|
29
27
|
"""
|
|
30
|
-
versions_qs = cls.objects.filter(
|
|
31
|
-
name=meta_name, model__name=model_name
|
|
32
|
-
).values_list("version", flat=True)
|
|
28
|
+
versions_qs = cls.objects.filter(name=meta_name, model__name=model_name).values_list("version", flat=True)
|
|
33
29
|
|
|
34
30
|
max_v = 0
|
|
35
31
|
found_numeric_version = False
|
|
@@ -84,24 +80,17 @@ def create_from_file_logic(
|
|
|
84
80
|
|
|
85
81
|
if requested_version:
|
|
86
82
|
target_version = str(requested_version)
|
|
87
|
-
existing = cls.objects.filter(
|
|
88
|
-
name=meta_name, model=ai_model, version=target_version
|
|
89
|
-
).first()
|
|
83
|
+
existing = cls.objects.filter(name=meta_name, model=ai_model, version=target_version).first()
|
|
90
84
|
if existing and not bump_if_exists:
|
|
91
85
|
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."
|
|
86
|
+
f"ModelMeta '{meta_name}' version '{target_version}' for model '{model_name}' already exists. Use bump_if_exists=True to increment."
|
|
94
87
|
)
|
|
95
88
|
elif existing and bump_if_exists:
|
|
96
89
|
target_version = str(latest_version_num + 1)
|
|
97
|
-
logger.info(
|
|
98
|
-
f"Bumping version for {meta_name}/{model_name} to {target_version}"
|
|
99
|
-
)
|
|
90
|
+
logger.info(f"Bumping version for {meta_name}/{model_name} to {target_version}")
|
|
100
91
|
else:
|
|
101
92
|
target_version = str(latest_version_num + 1)
|
|
102
|
-
logger.info(
|
|
103
|
-
f"Setting next version for {meta_name}/{model_name} to {target_version}"
|
|
104
|
-
)
|
|
93
|
+
logger.info(f"Setting next version for {meta_name}/{model_name} to {target_version}")
|
|
105
94
|
|
|
106
95
|
# --- Prepare Weights File ---
|
|
107
96
|
source_weights_path = Path(weights_file).resolve()
|
|
@@ -111,10 +100,7 @@ def create_from_file_logic(
|
|
|
111
100
|
# Construct destination path within MEDIA_ROOT/WEIGHTS_DIR
|
|
112
101
|
weights_filename = source_weights_path.name
|
|
113
102
|
# 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
|
-
)
|
|
103
|
+
relative_dest_path = Path(WEIGHTS_DIR.relative_to(STORAGE_DIR)) / f"{meta_name}_v{target_version}_{weights_filename}"
|
|
118
104
|
# Full path for shutil.copy
|
|
119
105
|
full_dest_path = STORAGE_DIR / relative_dest_path
|
|
120
106
|
|
|
@@ -233,22 +219,14 @@ def get_model_meta_by_name_version_logic(
|
|
|
233
219
|
try:
|
|
234
220
|
return cls.objects.get(name=meta_name, model=ai_model, version=version)
|
|
235
221
|
except Exception as exc:
|
|
236
|
-
raise cls.DoesNotExist(
|
|
237
|
-
f"ModelMeta '{meta_name}' version '{version}' for model '{model_name}' not found."
|
|
238
|
-
) from exc
|
|
222
|
+
raise cls.DoesNotExist(f"ModelMeta '{meta_name}' version '{version}' for model '{model_name}' not found.") from exc
|
|
239
223
|
else:
|
|
240
224
|
# Get latest version
|
|
241
|
-
latest = (
|
|
242
|
-
cls.objects.filter(name=meta_name, model=ai_model)
|
|
243
|
-
.order_by("-date_created")
|
|
244
|
-
.first()
|
|
245
|
-
)
|
|
225
|
+
latest = cls.objects.filter(name=meta_name, model=ai_model).order_by("-date_created").first()
|
|
246
226
|
if latest:
|
|
247
227
|
return latest
|
|
248
228
|
else:
|
|
249
|
-
raise cls.DoesNotExist(
|
|
250
|
-
f"No ModelMeta found for '{meta_name}' and model '{model_name}'."
|
|
251
|
-
)
|
|
229
|
+
raise cls.DoesNotExist(f"No ModelMeta found for '{meta_name}' and model '{model_name}'.")
|
|
252
230
|
|
|
253
231
|
|
|
254
232
|
import re
|
|
@@ -266,9 +244,7 @@ def infer_default_model_meta_from_hf(model_id: str) -> dict[str, Any]:
|
|
|
266
244
|
"""
|
|
267
245
|
|
|
268
246
|
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
|
-
)
|
|
247
|
+
logger.info(f"Could not retrieve model info for {model_id}, using ColoReg segmentation defaults.")
|
|
272
248
|
return {
|
|
273
249
|
"name": "wg-lux/colo_segmentation_RegNetX800MF_base",
|
|
274
250
|
"activation": "sigmoid",
|
|
@@ -317,9 +293,7 @@ def infer_default_model_meta_from_hf(model_id: str) -> dict[str, Any]:
|
|
|
317
293
|
}
|
|
318
294
|
|
|
319
295
|
|
|
320
|
-
def setup_default_from_huggingface_logic(
|
|
321
|
-
cls, model_id: str, labelset_name: str | None = None
|
|
322
|
-
):
|
|
296
|
+
def setup_default_from_huggingface_logic(cls, model_id: str, labelset_name: str | None = None):
|
|
323
297
|
"""
|
|
324
298
|
Downloads model weights from Hugging Face and auto-fills ModelMeta fields.
|
|
325
299
|
"""
|
|
@@ -333,11 +307,7 @@ def setup_default_from_huggingface_logic(
|
|
|
333
307
|
)
|
|
334
308
|
|
|
335
309
|
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
|
-
)
|
|
310
|
+
labelset = LabelSet.objects.first() if not labelset_name else LabelSet.objects.get(name=labelset_name)
|
|
341
311
|
|
|
342
312
|
return create_from_file_logic(
|
|
343
313
|
cls,
|
|
@@ -352,3 +322,99 @@ def setup_default_from_huggingface_logic(
|
|
|
352
322
|
size_y=meta["size_y"],
|
|
353
323
|
description=meta["description"],
|
|
354
324
|
)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def validate_and_fix_ai_model_metadata_logic():
|
|
328
|
+
"""
|
|
329
|
+
Validates that all AI models have proper active metadata and fixes any issues.
|
|
330
|
+
This prevents the "No model metadata found for this model" error.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
dict: Summary of fixes applied
|
|
334
|
+
"""
|
|
335
|
+
from ..administration.ai.ai_model import AiModel
|
|
336
|
+
from ..label.label_set import LabelSet
|
|
337
|
+
|
|
338
|
+
summary = {"models_checked": 0, "models_fixed": 0, "metadata_created": 0, "active_meta_set": 0, "errors": []}
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
all_models = AiModel.objects.all()
|
|
342
|
+
summary["models_checked"] = all_models.count()
|
|
343
|
+
|
|
344
|
+
for model in all_models:
|
|
345
|
+
logger.info(f"Validating model: {model.name}")
|
|
346
|
+
|
|
347
|
+
# Check if model has metadata versions
|
|
348
|
+
metadata_count = model.metadata_versions.count()
|
|
349
|
+
|
|
350
|
+
if metadata_count == 0:
|
|
351
|
+
# Create metadata for models that don't have any
|
|
352
|
+
logger.info(f"Creating metadata for {model.name}")
|
|
353
|
+
|
|
354
|
+
# Use existing labelset or create default
|
|
355
|
+
labelset = LabelSet.objects.first()
|
|
356
|
+
if not labelset:
|
|
357
|
+
labelset = LabelSet.objects.create(name="default_colonoscopy_labels", description="Default colonoscopy classification labels")
|
|
358
|
+
|
|
359
|
+
# Import here to avoid circular imports
|
|
360
|
+
from .model_meta import ModelMeta
|
|
361
|
+
|
|
362
|
+
# Create basic metadata
|
|
363
|
+
meta = ModelMeta.objects.create(
|
|
364
|
+
name=model.name,
|
|
365
|
+
version="1.0",
|
|
366
|
+
model=model,
|
|
367
|
+
labelset=labelset,
|
|
368
|
+
activation="sigmoid" if "classification" in model.name else "sigmoid",
|
|
369
|
+
mean="0.485,0.456,0.406", # ImageNet defaults
|
|
370
|
+
std="0.229,0.224,0.225", # ImageNet defaults
|
|
371
|
+
size_x=224,
|
|
372
|
+
size_y=224,
|
|
373
|
+
axes="CHW",
|
|
374
|
+
batchsize=32,
|
|
375
|
+
num_workers=4,
|
|
376
|
+
description=f"Auto-generated metadata for {model.name}",
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
model.active_meta = meta
|
|
380
|
+
model.save()
|
|
381
|
+
summary["models_fixed"] += 1
|
|
382
|
+
summary["metadata_created"] += 1
|
|
383
|
+
logger.info(f"Created and set metadata for {model.name}")
|
|
384
|
+
|
|
385
|
+
elif not model.active_meta:
|
|
386
|
+
# Model has metadata but no active meta set
|
|
387
|
+
first_meta = model.metadata_versions.first()
|
|
388
|
+
if first_meta:
|
|
389
|
+
logger.info(f"Setting active metadata for {model.name}")
|
|
390
|
+
model.active_meta = first_meta
|
|
391
|
+
model.save()
|
|
392
|
+
summary["models_fixed"] += 1
|
|
393
|
+
summary["active_meta_set"] += 1
|
|
394
|
+
logger.info(f"Set active metadata: {first_meta.name} v{first_meta.version}")
|
|
395
|
+
else:
|
|
396
|
+
error_msg = f"No metadata versions available for {model.name}"
|
|
397
|
+
logger.warning(error_msg)
|
|
398
|
+
summary["errors"].append(error_msg)
|
|
399
|
+
|
|
400
|
+
else:
|
|
401
|
+
logger.info(f"Model {model.name} has valid active metadata: {model.active_meta}")
|
|
402
|
+
|
|
403
|
+
# Verify all models can get latest version
|
|
404
|
+
logger.info("Testing model metadata access...")
|
|
405
|
+
for model in all_models:
|
|
406
|
+
try:
|
|
407
|
+
latest = model.get_latest_version()
|
|
408
|
+
logger.info(f"✅ {model.name}: {latest}")
|
|
409
|
+
except Exception as e:
|
|
410
|
+
error_msg = f"Model {model.name} metadata test failed: {e}"
|
|
411
|
+
logger.error(error_msg)
|
|
412
|
+
summary["errors"].append(error_msg)
|
|
413
|
+
|
|
414
|
+
return summary
|
|
415
|
+
|
|
416
|
+
except Exception as e:
|
|
417
|
+
error_msg = f"Validation failed: {e}"
|
|
418
|
+
logger.error(error_msg)
|
|
419
|
+
summary["errors"].append(error_msg)
|
|
420
|
+
return summary
|
|
@@ -290,10 +290,11 @@ endoreg_db/management/commands/load_unit_data.py,sha256=tcux-iL-ByT2ApgmHEkLllZS
|
|
|
290
290
|
endoreg_db/management/commands/load_user_groups.py,sha256=D7SK2FvZEHoE4TIXNGCjDw5_12MH9bpGZvoS7eEv0Os,1031
|
|
291
291
|
endoreg_db/management/commands/register_ai_model.py,sha256=KixTfuQR6TUfRmzB5GOos16BFOz7NL4TzLzBkgtPPgE,2510
|
|
292
292
|
endoreg_db/management/commands/reset_celery_schedule.py,sha256=U-m_FNRTw6LAwJoT9RUE4qrhmQXm7AyFToPcHYyJpIE,386
|
|
293
|
-
endoreg_db/management/commands/setup_endoreg_db.py,sha256=
|
|
293
|
+
endoreg_db/management/commands/setup_endoreg_db.py,sha256=v9QgbxAONChZNqm-TVPQGj7AEjZdSA01zC7gImkJEkY,12989
|
|
294
294
|
endoreg_db/management/commands/start_filewatcher.py,sha256=3jESBqRiYPa9f35--zd70qQaYnyT0tzRO_b_HJuyteQ,4093
|
|
295
295
|
endoreg_db/management/commands/storage_management.py,sha256=NpToX59ndwTFNmnSoeppmiPdMvpjSHH7mAdIe4SvUoI,22396
|
|
296
296
|
endoreg_db/management/commands/summarize_db_content.py,sha256=pOIz3qbY4Ktmh0zV_DKFx971VD0pPx027gCD7a47EL0,10766
|
|
297
|
+
endoreg_db/management/commands/validate_ai_models.py,sha256=Z7Ga-PndTFVG8GnkYbS58h8ofiyhnxZDcyP5Qqpl1c8,4684
|
|
297
298
|
endoreg_db/management/commands/validate_video.py,sha256=cns_kNgztyp6XTeXuDeLEet8vAATkpxZwJuSWuQ5Olk,11302
|
|
298
299
|
endoreg_db/management/commands/validate_video_files.py,sha256=0lvA0Z8BKiibjyqc4ueI646IIc5bKI3sIOxiiF5_bTk,6509
|
|
299
300
|
endoreg_db/management/commands/video_validation.py,sha256=xnAoCPB44dmnRbn6FqUjqRXQ-ZhDPNX1T5kCpAU8sgc,771
|
|
@@ -464,7 +465,7 @@ endoreg_db/models/medical/risk/risk_type.py,sha256=kEugcaWSTEWH_Vxq4dcF80Iv1L4_K
|
|
|
464
465
|
endoreg_db/models/metadata/__init__.py,sha256=8I6oLj3YTmeaPGJpL0AWG5gLwp38QzrEggxSkTisv7c,474
|
|
465
466
|
endoreg_db/models/metadata/frame_ocr_result.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
466
467
|
endoreg_db/models/metadata/model_meta.py,sha256=F_r-PTLeNi4J-4EaGCQkGIguhdl7Bwba7_i56ZAjc-4,7589
|
|
467
|
-
endoreg_db/models/metadata/model_meta_logic.py,sha256=
|
|
468
|
+
endoreg_db/models/metadata/model_meta_logic.py,sha256=R2VqcmJb3LmMMM37RMBWpRmfD_GVP3FsmgpAXAoyQPs,15810
|
|
468
469
|
endoreg_db/models/metadata/pdf_meta.py,sha256=BTmpSgqxmPKi0apcNjyrZAS4AFKCPXVdBd6VBeyyv6E,3174
|
|
469
470
|
endoreg_db/models/metadata/sensitive_meta.py,sha256=ekLHrW-b5uYcjfkRd0EW5ncx5ef8Bu-K6msDkpWCAbk,13034
|
|
470
471
|
endoreg_db/models/metadata/sensitive_meta_logic.py,sha256=by3eCW8CgglK1SHiDOepHhTOGaugswxJhkH0BZp7-gs,33909
|
|
@@ -786,7 +787,7 @@ endoreg_db/views/video/video_meta.py,sha256=C1wBMTtQb_yzEUrhFGAy2UHEWMk_CbU75WXX
|
|
|
786
787
|
endoreg_db/views/video/video_processing_history.py,sha256=mhFuS8RG5GV8E-lTtuD0qrq-bIpnUFp8vy9aERfC-J8,770
|
|
787
788
|
endoreg_db/views/video/video_remove_frames.py,sha256=2FmvNrSPM0fUXiBxINN6vBUUDCqDlBkNcGR3WsLDgKo,1696
|
|
788
789
|
endoreg_db/views/video/video_stream.py,sha256=kLyuf0ORTmsLeYUQkTQ6iRYqlIQozWhMMR3Lhfe_trk,12148
|
|
789
|
-
endoreg_db-0.8.4.
|
|
790
|
-
endoreg_db-0.8.4.
|
|
791
|
-
endoreg_db-0.8.4.
|
|
792
|
-
endoreg_db-0.8.4.
|
|
790
|
+
endoreg_db-0.8.4.1.dist-info/METADATA,sha256=TmIf-CR3u-Mx2h06sKN1XHpfDx8vh5R3hbrsDZDgJPw,14758
|
|
791
|
+
endoreg_db-0.8.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
792
|
+
endoreg_db-0.8.4.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
793
|
+
endoreg_db-0.8.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|