remaining stage 1

This commit is contained in:
alorig
2025-11-19 20:53:29 +05:00
parent b5cc262f04
commit 4ca85ae0e5
4 changed files with 86 additions and 32 deletions

View File

@@ -52,12 +52,26 @@ class ClusteringService:
# Delegate to AI task # Delegate to AI task
from igny8_core.ai.tasks import run_ai_task from igny8_core.ai.tasks import run_ai_task
from django.conf import settings
payload = { payload = {
'ids': keyword_ids, 'ids': keyword_ids,
'sector_id': sector_id 'sector_id': sector_id
} }
# Stage 1: When USE_SITE_BUILDER_REFACTOR is enabled, payload can include
# taxonomy hints and dimension metadata for enhanced clustering.
# TODO (Stage 2/3): Enhance clustering to collect and use:
# - Taxonomy hints from SiteBlueprintTaxonomy
# - Dimension metadata (context_type, dimension_meta) for clusters
# - Attribute values from Keywords.attribute_values
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
logger.info(
f"Clustering with refactor enabled: {len(keyword_ids)} keywords, "
f"sector_id={sector_id}, account_id={account.id}"
)
# Future: Add taxonomy hints and dimension metadata to payload
try: try:
if hasattr(run_ai_task, 'delay'): if hasattr(run_ai_task, 'delay'):
# Celery available - queue async # Celery available - queue async

View File

@@ -1,4 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from django.conf import settings
from .models import Keywords, Clusters, ContentIdeas from .models import Keywords, Clusters, ContentIdeas
from igny8_core.auth.models import SeedKeyword from igny8_core.auth.models import SeedKeyword
@@ -28,14 +29,6 @@ class KeywordSerializer(serializers.ModelSerializer):
sector_name = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField()
site_id = serializers.IntegerField(write_only=True, required=False) site_id = serializers.IntegerField(write_only=True, required=False)
sector_id = serializers.IntegerField(write_only=True, required=False) sector_id = serializers.IntegerField(write_only=True, required=False)
attribute_values = serializers.ListField(
child=serializers.CharField(),
required=False,
allow_empty=True,
default=list,
help_text="Optional attribute metadata (e.g., product specs, service modifiers)",
)
class Meta: class Meta:
model = Keywords model = Keywords
@@ -53,7 +46,6 @@ class KeywordSerializer(serializers.ModelSerializer):
'cluster_name', 'cluster_name',
'sector_name', 'sector_name',
'status', 'status',
'attribute_values',
'created_at', 'created_at',
'updated_at', 'updated_at',
'site_id', 'site_id',
@@ -62,6 +54,12 @@ class KeywordSerializer(serializers.ModelSerializer):
] ]
read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keyword', 'volume', 'difficulty', 'intent'] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keyword', 'volume', 'difficulty', 'intent']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only include Stage 1 fields when feature flag is enabled
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
self.fields['attribute_values'] = serializers.JSONField(read_only=True)
def validate(self, attrs): def validate(self, attrs):
"""Validate that seed_keyword_id is provided for create operations""" """Validate that seed_keyword_id is provided for create operations"""
# For create operations, seed_keyword_id is required # For create operations, seed_keyword_id is required
@@ -123,8 +121,6 @@ class ClusterSerializer(serializers.ModelSerializer):
sector_name = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField()
site_id = serializers.IntegerField(write_only=True, required=False) site_id = serializers.IntegerField(write_only=True, required=False)
sector_id = serializers.IntegerField(write_only=True, required=False) sector_id = serializers.IntegerField(write_only=True, required=False)
context_type_display = serializers.SerializerMethodField()
class Meta: class Meta:
model = Clusters model = Clusters
@@ -136,9 +132,6 @@ class ClusterSerializer(serializers.ModelSerializer):
'volume', 'volume',
'mapped_pages', 'mapped_pages',
'status', 'status',
'context_type',
'context_type_display',
'dimension_meta',
'sector_name', 'sector_name',
'created_at', 'created_at',
'updated_at', 'updated_at',
@@ -148,6 +141,14 @@ class ClusterSerializer(serializers.ModelSerializer):
] ]
read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keywords_count', 'volume', 'mapped_pages'] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keywords_count', 'volume', 'mapped_pages']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only include Stage 1 fields when feature flag is enabled
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
self.fields['context_type'] = serializers.CharField(read_only=True)
self.fields['context_type_display'] = serializers.SerializerMethodField()
self.fields['dimension_meta'] = serializers.JSONField(read_only=True)
def get_sector_name(self, obj): def get_sector_name(self, obj):
"""Get sector name from Sector model""" """Get sector name from Sector model"""
if obj.sector_id: if obj.sector_id:
@@ -160,7 +161,10 @@ class ClusterSerializer(serializers.ModelSerializer):
return None return None
def get_context_type_display(self, obj): def get_context_type_display(self, obj):
return obj.get_context_type_display() """Get context type display name (only when feature flag enabled)"""
if hasattr(obj, 'get_context_type_display'):
return obj.get_context_type_display()
return None
def validate_name(self, value): def validate_name(self, value):
"""Ensure cluster name is unique within account""" """Ensure cluster name is unique within account"""
@@ -172,7 +176,6 @@ class ContentIdeasSerializer(serializers.ModelSerializer):
"""Serializer for ContentIdeas model""" """Serializer for ContentIdeas model"""
keyword_cluster_name = serializers.SerializerMethodField() keyword_cluster_name = serializers.SerializerMethodField()
sector_name = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField()
taxonomy_name = serializers.SerializerMethodField()
site_id = serializers.IntegerField(write_only=True, required=False) site_id = serializers.IntegerField(write_only=True, required=False)
sector_id = serializers.IntegerField(write_only=True, required=False) sector_id = serializers.IntegerField(write_only=True, required=False)
@@ -187,13 +190,9 @@ class ContentIdeasSerializer(serializers.ModelSerializer):
'target_keywords', 'target_keywords',
'keyword_cluster_id', 'keyword_cluster_id',
'keyword_cluster_name', 'keyword_cluster_name',
'taxonomy_id',
'taxonomy_name',
'sector_name', 'sector_name',
'status', 'status',
'estimated_word_count', 'estimated_word_count',
'site_entity_type',
'cluster_role',
'created_at', 'created_at',
'updated_at', 'updated_at',
'site_id', 'site_id',
@@ -202,6 +201,15 @@ class ContentIdeasSerializer(serializers.ModelSerializer):
] ]
read_only_fields = ['id', 'created_at', 'updated_at', 'account_id'] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only include Stage 1 fields when feature flag is enabled
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
self.fields['taxonomy_id'] = serializers.IntegerField(read_only=True, allow_null=True)
self.fields['taxonomy_name'] = serializers.SerializerMethodField()
self.fields['site_entity_type'] = serializers.CharField(read_only=True)
self.fields['cluster_role'] = serializers.CharField(read_only=True)
def get_keyword_cluster_name(self, obj): def get_keyword_cluster_name(self, obj):
"""Get cluster name from Clusters model""" """Get cluster name from Clusters model"""
if obj.keyword_cluster_id: if obj.keyword_cluster_id:

View File

@@ -2,6 +2,28 @@ from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
def backfill_metadata_mappings_stub(apps, schema_editor):
"""
Stage 1: Placeholder for Stage 3 metadata backfill.
This function will be extended in Stage 3 to backfill:
- ContentClusterMap records from existing Content/Task -> Cluster relationships
- ContentTaxonomyMap records from existing taxonomy associations
- ContentAttributeMap records from existing attribute data
For now, this is a no-op to establish the migration hook.
"""
# Stage 1: No-op - tables created, ready for Stage 3 backfill
pass
def reverse_backfill_metadata_mappings_stub(apps, schema_editor):
"""
Reverse operation for metadata backfill (no-op for Stage 1).
"""
pass
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@@ -117,5 +139,10 @@ class Migration(migrations.Migration):
model_name='contentattributemap', model_name='contentattributemap',
index=models.Index(fields=['task', 'name'], name='writer_con_task__name_fa4a4e_idx'), index=models.Index(fields=['task', 'name'], name='writer_con_task__name_fa4a4e_idx'),
), ),
# Stage 1: Data migration stub for Stage 3 backfill
migrations.RunPython(
backfill_metadata_mappings_stub,
reverse_backfill_metadata_mappings_stub,
),
] ]

View File

@@ -1,6 +1,7 @@
from rest_framework import serializers from rest_framework import serializers
from django.db import models from django.db import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from .models import Tasks, Images, Content from .models import Tasks, Images, Content
from igny8_core.business.planning.models import Clusters, ContentIdeas from igny8_core.business.planning.models import Clusters, ContentIdeas
from igny8_core.business.content.models import ( from igny8_core.business.content.models import (
@@ -22,9 +23,6 @@ class TasksSerializer(serializers.ModelSerializer):
content_secondary_keywords = serializers.SerializerMethodField() content_secondary_keywords = serializers.SerializerMethodField()
content_tags = serializers.SerializerMethodField() content_tags = serializers.SerializerMethodField()
content_categories = serializers.SerializerMethodField() content_categories = serializers.SerializerMethodField()
cluster_mappings = serializers.SerializerMethodField()
taxonomy_mappings = serializers.SerializerMethodField()
attribute_mappings = serializers.SerializerMethodField()
class Meta: class Meta:
model = Tasks model = Tasks
@@ -50,9 +48,6 @@ class TasksSerializer(serializers.ModelSerializer):
'content_secondary_keywords', 'content_secondary_keywords',
'content_tags', 'content_tags',
'content_categories', 'content_categories',
'cluster_mappings',
'taxonomy_mappings',
'attribute_mappings',
'assigned_post_id', 'assigned_post_id',
'post_url', 'post_url',
'created_at', 'created_at',
@@ -63,6 +58,14 @@ class TasksSerializer(serializers.ModelSerializer):
] ]
read_only_fields = ['id', 'created_at', 'updated_at', 'account_id'] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only include Stage 1 fields when feature flag is enabled
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
self.fields['cluster_mappings'] = serializers.SerializerMethodField()
self.fields['taxonomy_mappings'] = serializers.SerializerMethodField()
self.fields['attribute_mappings'] = serializers.SerializerMethodField()
def get_cluster_name(self, obj): def get_cluster_name(self, obj):
"""Get cluster name from Clusters model""" """Get cluster name from Clusters model"""
if obj.cluster_id: if obj.cluster_id:
@@ -246,9 +249,6 @@ class ContentSerializer(serializers.ModelSerializer):
sector_name = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField()
has_image_prompts = serializers.SerializerMethodField() has_image_prompts = serializers.SerializerMethodField()
has_generated_images = serializers.SerializerMethodField() has_generated_images = serializers.SerializerMethodField()
cluster_mappings = serializers.SerializerMethodField()
taxonomy_mappings = serializers.SerializerMethodField()
attribute_mappings = serializers.SerializerMethodField()
class Meta: class Meta:
model = Content model = Content
@@ -277,12 +277,17 @@ class ContentSerializer(serializers.ModelSerializer):
'entity_type', 'entity_type',
'json_blocks', 'json_blocks',
'structure_data', 'structure_data',
'cluster_mappings',
'taxonomy_mappings',
'attribute_mappings',
] ]
read_only_fields = ['id', 'generated_at', 'updated_at', 'account_id'] read_only_fields = ['id', 'generated_at', 'updated_at', 'account_id']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only include Stage 1 fields when feature flag is enabled
if getattr(settings, 'USE_SITE_BUILDER_REFACTOR', False):
self.fields['cluster_mappings'] = serializers.SerializerMethodField()
self.fields['taxonomy_mappings'] = serializers.SerializerMethodField()
self.fields['attribute_mappings'] = serializers.SerializerMethodField()
def get_task_title(self, obj): def get_task_title(self, obj):
"""Get task title""" """Get task title"""
if obj.task_id: if obj.task_id: