Skip to content

Commit fdfc078

Browse files
committed
add aimodel signals to update index
1 parent 1823c30 commit fdfc078

2 files changed

Lines changed: 84 additions & 1 deletion

File tree

api/signals/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# Import signals to register them
2-
from api.signals import dataset_signals, usecase_signals
2+
from api.signals import aimodel_signals, dataset_signals, usecase_signals

api/signals/aimodel_signals.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from typing import Any
2+
3+
import structlog
4+
from django.db.models.signals import post_delete, pre_save
5+
from django.dispatch import receiver
6+
7+
from api.models.AIModel import AIModel
8+
from api.utils.enums import AIModelStatus
9+
from search.documents import AIModelDocument
10+
11+
logger = structlog.get_logger(__name__)
12+
13+
INDEXABLE_STATUSES = {AIModelStatus.ACTIVE, AIModelStatus.APPROVED}
14+
15+
16+
def _should_be_indexed(instance: AIModel) -> bool:
17+
"""Return True when the AI model should exist in Elasticsearch."""
18+
return instance.is_public and instance.is_active and instance.status in INDEXABLE_STATUSES
19+
20+
21+
@receiver(pre_save, sender=AIModel)
22+
def handle_aimodel_visibility(sender: Any, instance: AIModel, **kwargs: Any) -> None:
23+
"""Sync Elasticsearch document whenever publish/visibility fields change."""
24+
if not instance.pk:
25+
# New objects are handled by django-elasticsearch-dsl signal processor
26+
return
27+
28+
try:
29+
original = AIModel.objects.get(pk=instance.pk)
30+
except AIModel.DoesNotExist:
31+
return
32+
33+
was_indexable = _should_be_indexed(original)
34+
is_indexable = _should_be_indexed(instance)
35+
36+
if was_indexable == is_indexable and is_indexable:
37+
# Still indexable, just refresh contents
38+
action = "update"
39+
elif was_indexable and not is_indexable:
40+
action = "delete"
41+
elif not was_indexable and is_indexable:
42+
action = "add"
43+
else:
44+
# Neither was nor is indexable; nothing to do
45+
return
46+
47+
try:
48+
document = AIModelDocument.get(id=instance.id, ignore=404)
49+
if action == "delete":
50+
if document:
51+
document.delete()
52+
logger.info("Removed AI model from Elasticsearch index", model_id=instance.id)
53+
else:
54+
if document:
55+
document.update(instance)
56+
else:
57+
AIModelDocument().update(instance)
58+
logger.info(
59+
"Synced AI model to Elasticsearch index", model_id=instance.id, action=action
60+
)
61+
except Exception as exc: # pragma: no cover - logging only
62+
logger.error(
63+
"Failed to sync AI model search document",
64+
model_id=instance.id,
65+
action=action,
66+
error=str(exc),
67+
)
68+
69+
70+
@receiver(post_delete, sender=AIModel)
71+
def remove_aimodel_document(sender: Any, instance: AIModel, **kwargs: Any) -> None:
72+
"""Ensure Elasticsearch document gets deleted when the model is removed."""
73+
try:
74+
document = AIModelDocument.get(id=instance.id, ignore=404)
75+
if document:
76+
document.delete()
77+
logger.info("Removed deleted AI model from Elasticsearch index", model_id=instance.id)
78+
except Exception as exc: # pragma: no cover - logging only
79+
logger.error(
80+
"Failed to delete AI model search document",
81+
model_id=instance.id,
82+
error=str(exc),
83+
)

0 commit comments

Comments
 (0)