Implement Stage 3: Enhance content metadata and validation features
- Added entity metadata fields to the Tasks model, including entity_type, taxonomy, and cluster_role. - Updated CandidateEngine to prioritize content relevance based on cluster mappings. - Introduced metadata completeness scoring in ContentAnalyzer. - Enhanced validation services to check for entity type and mapping completeness. - Updated frontend components to display and validate new metadata fields. - Implemented API endpoints for content validation and metadata persistence. - Migrated existing data to populate new metadata fields for Tasks and Content.
This commit is contained in:
@@ -218,6 +218,91 @@ class SiteBlueprintViewSet(SiteSectorModelViewSet):
|
||||
except Exception as e:
|
||||
return error_response(str(e), status.HTTP_400_BAD_REQUEST, request)
|
||||
|
||||
@action(detail=True, methods=['get'], url_path='progress', url_name='progress')
|
||||
def progress(self, request, pk=None):
|
||||
"""
|
||||
Stage 3: Get cluster-level completion + validation status for site.
|
||||
|
||||
GET /api/v1/site-builder/blueprints/{id}/progress/
|
||||
Returns progress summary with cluster coverage, validation flags.
|
||||
"""
|
||||
blueprint = self.get_object()
|
||||
from igny8_core.business.content.models import (
|
||||
Tasks,
|
||||
Content,
|
||||
ContentClusterMap,
|
||||
ContentTaxonomyMap,
|
||||
)
|
||||
from igny8_core.business.planning.models import Clusters
|
||||
from django.db.models import Count, Q
|
||||
|
||||
# Get clusters attached to blueprint
|
||||
blueprint_clusters = blueprint.cluster_links.all()
|
||||
cluster_ids = list(blueprint_clusters.values_list('cluster_id', flat=True))
|
||||
|
||||
# Get tasks and content for this blueprint's site
|
||||
tasks = Tasks.objects.filter(site=blueprint.site)
|
||||
content = Content.objects.filter(site=blueprint.site)
|
||||
|
||||
# Cluster coverage analysis
|
||||
cluster_progress = []
|
||||
for cluster_link in blueprint_clusters:
|
||||
cluster = cluster_link.cluster
|
||||
cluster_tasks = tasks.filter(cluster=cluster)
|
||||
cluster_content_ids = ContentClusterMap.objects.filter(
|
||||
cluster=cluster
|
||||
).values_list('content_id', flat=True).distinct()
|
||||
cluster_content = content.filter(id__in=cluster_content_ids)
|
||||
|
||||
# Count by role
|
||||
hub_count = cluster_tasks.filter(cluster_role='hub').count()
|
||||
supporting_count = cluster_tasks.filter(cluster_role='supporting').count()
|
||||
attribute_count = cluster_tasks.filter(cluster_role='attribute').count()
|
||||
|
||||
cluster_progress.append({
|
||||
'cluster_id': cluster.id,
|
||||
'cluster_name': cluster.name,
|
||||
'role': cluster_link.role,
|
||||
'coverage_status': cluster_link.coverage_status,
|
||||
'tasks_count': cluster_tasks.count(),
|
||||
'content_count': cluster_content.count(),
|
||||
'hub_pages': hub_count,
|
||||
'supporting_pages': supporting_count,
|
||||
'attribute_pages': attribute_count,
|
||||
'is_complete': cluster_link.coverage_status == 'complete',
|
||||
})
|
||||
|
||||
# Overall stats
|
||||
total_tasks = tasks.count()
|
||||
total_content = content.count()
|
||||
tasks_with_cluster = tasks.filter(cluster__isnull=False).count()
|
||||
content_with_cluster_map = ContentClusterMap.objects.filter(
|
||||
content__site=blueprint.site
|
||||
).values('content').distinct().count()
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
'blueprint_id': blueprint.id,
|
||||
'blueprint_name': blueprint.name,
|
||||
'overall_progress': {
|
||||
'total_tasks': total_tasks,
|
||||
'total_content': total_content,
|
||||
'tasks_with_cluster': tasks_with_cluster,
|
||||
'content_with_cluster_mapping': content_with_cluster_map,
|
||||
'completion_percentage': (
|
||||
(content_with_cluster_map / total_content * 100) if total_content > 0 else 0
|
||||
),
|
||||
},
|
||||
'cluster_progress': cluster_progress,
|
||||
'validation_flags': {
|
||||
'has_clusters': blueprint_clusters.exists(),
|
||||
'has_taxonomies': blueprint.taxonomies.exists(),
|
||||
'has_pages': blueprint.pages.exists(),
|
||||
}
|
||||
},
|
||||
request=request
|
||||
)
|
||||
|
||||
@action(detail=True, methods=['get'], url_path='workflow/context')
|
||||
def workflow_context(self, request, pk=None):
|
||||
"""Return aggregated wizard context (steps, clusters, taxonomies, coverage)."""
|
||||
|
||||
Reference in New Issue
Block a user