112
This commit is contained in:
@@ -8,6 +8,7 @@ from typing import Dict, List, Any
|
||||
from django.db import transaction
|
||||
from igny8_core.ai.base import BaseAIFunction
|
||||
from igny8_core.modules.writer.models import Tasks, Content
|
||||
from igny8_core.business.content.models import ContentTaxonomy
|
||||
from igny8_core.ai.ai_core import AICore
|
||||
from igny8_core.ai.validators import validate_tasks_exist
|
||||
from igny8_core.ai.prompts import PromptRegistry
|
||||
@@ -183,6 +184,7 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
# Extract tags and categories from AI response
|
||||
tags_from_response = parsed.get('tags', [])
|
||||
categories_from_response = parsed.get('categories', [])
|
||||
logger.info(f"Extracted from AI response - Tags: {tags_from_response}, Categories: {categories_from_response}")
|
||||
else:
|
||||
# Plain text response
|
||||
content_html = str(parsed)
|
||||
@@ -224,9 +226,13 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
sector=task.sector,
|
||||
)
|
||||
|
||||
logger.info(f"Created content record ID: {content_record.id}")
|
||||
logger.info(f"Processing {len(tags_from_response) if tags_from_response else 0} tags and {len(categories_from_response) if categories_from_response else 0} categories")
|
||||
|
||||
# Link taxonomy terms from task if available
|
||||
if task.taxonomy_term:
|
||||
content_record.taxonomy_terms.add(task.taxonomy_term)
|
||||
logger.info(f"Added task taxonomy term: {task.taxonomy_term.name}")
|
||||
|
||||
# Process tags from AI response
|
||||
if tags_from_response and isinstance(tags_from_response, list):
|
||||
@@ -237,7 +243,7 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
if tag_name:
|
||||
try:
|
||||
# Get or create tag taxonomy term
|
||||
tag_obj, _ = ContentTaxonomy.objects.get_or_create(
|
||||
tag_obj, created = ContentTaxonomy.objects.get_or_create(
|
||||
site=task.site,
|
||||
name=tag_name,
|
||||
taxonomy_type='tag',
|
||||
@@ -245,11 +251,17 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
'slug': slugify(tag_name),
|
||||
'sector': task.sector,
|
||||
'account': task.account,
|
||||
'description': '', # Required by database
|
||||
'external_taxonomy': '', # Required by database
|
||||
'sync_status': '', # Required by database
|
||||
'count': 0, # Required by database
|
||||
'metadata': {}, # Required by database
|
||||
}
|
||||
)
|
||||
content_record.taxonomy_terms.add(tag_obj)
|
||||
logger.info(f"{'Created' if created else 'Found'} and linked tag: {tag_name} (ID: {tag_obj.id})")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to add tag '{tag_name}': {e}")
|
||||
logger.error(f"Failed to add tag '{tag_name}': {e}", exc_info=True)
|
||||
|
||||
# Process categories from AI response
|
||||
if categories_from_response and isinstance(categories_from_response, list):
|
||||
@@ -260,7 +272,7 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
if category_name:
|
||||
try:
|
||||
# Get or create category taxonomy term
|
||||
category_obj, _ = ContentTaxonomy.objects.get_or_create(
|
||||
category_obj, created = ContentTaxonomy.objects.get_or_create(
|
||||
site=task.site,
|
||||
name=category_name,
|
||||
taxonomy_type='category',
|
||||
@@ -268,11 +280,17 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
'slug': slugify(category_name),
|
||||
'sector': task.sector,
|
||||
'account': task.account,
|
||||
'description': '', # Required by database
|
||||
'external_taxonomy': '', # Required by database
|
||||
'sync_status': '', # Required by database
|
||||
'count': 0, # Required by database
|
||||
'metadata': {}, # Required by database
|
||||
}
|
||||
)
|
||||
content_record.taxonomy_terms.add(category_obj)
|
||||
logger.info(f"{'Created' if created else 'Found'} and linked category: {category_name} (ID: {category_obj.id})")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to add category '{category_name}': {e}")
|
||||
logger.error(f"Failed to add category '{category_name}': {e}", exc_info=True)
|
||||
|
||||
# STAGE 3: Update task status to completed
|
||||
task.status = 'completed'
|
||||
|
||||
@@ -297,8 +297,8 @@ class ContentTaxonomy(SiteSectorBaseModel):
|
||||
external_taxonomy = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text="WordPress taxonomy slug (category, post_tag, product_cat, pa_*) - null for cluster taxonomies"
|
||||
default='',
|
||||
help_text="WordPress taxonomy slug (category, post_tag, product_cat, pa_*) - empty for cluster taxonomies"
|
||||
)
|
||||
external_id = models.IntegerField(
|
||||
null=True,
|
||||
@@ -306,6 +306,26 @@ class ContentTaxonomy(SiteSectorBaseModel):
|
||||
db_index=True,
|
||||
help_text="WordPress term_id - null for cluster taxonomies"
|
||||
)
|
||||
description = models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
help_text="Taxonomy term description"
|
||||
)
|
||||
sync_status = models.CharField(
|
||||
max_length=50,
|
||||
blank=True,
|
||||
default='',
|
||||
help_text="Synchronization status with external platforms"
|
||||
)
|
||||
count = models.IntegerField(
|
||||
default=0,
|
||||
help_text="Number of times this term is used"
|
||||
)
|
||||
metadata = models.JSONField(
|
||||
default=dict,
|
||||
blank=True,
|
||||
help_text="Additional metadata for the taxonomy term"
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@@ -86,11 +86,12 @@ class ImagesAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
|
||||
@admin.register(Content)
|
||||
class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
list_display = ['title', 'content_type', 'content_structure', 'site', 'sector', 'source', 'status', 'created_at']
|
||||
list_display = ['title', 'content_type', 'content_structure', 'site', 'sector', 'source', 'status', 'get_taxonomy_count', 'created_at']
|
||||
list_filter = ['content_type', 'content_structure', 'source', 'status', 'site', 'sector', 'created_at']
|
||||
search_fields = ['title', 'content_html', 'external_url']
|
||||
ordering = ['-created_at']
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
readonly_fields = ['created_at', 'updated_at', 'word_count']
|
||||
filter_horizontal = ['taxonomy_terms'] # Add many-to-many widget for taxonomy terms
|
||||
|
||||
fieldsets = (
|
||||
('Basic Info', {
|
||||
@@ -99,8 +100,16 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
('Content Classification', {
|
||||
'fields': ('content_type', 'content_structure', 'source')
|
||||
}),
|
||||
('Taxonomy Terms (Tags & Categories)', {
|
||||
'fields': ('taxonomy_terms',),
|
||||
'description': 'Select tags and categories for this content'
|
||||
}),
|
||||
('Content', {
|
||||
'fields': ('content_html',)
|
||||
'fields': ('content_html', 'word_count')
|
||||
}),
|
||||
('SEO', {
|
||||
'fields': ('meta_title', 'meta_description', 'primary_keyword', 'secondary_keywords'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('WordPress Sync', {
|
||||
'fields': ('external_id', 'external_url'),
|
||||
@@ -112,6 +121,11 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
}),
|
||||
)
|
||||
|
||||
def get_taxonomy_count(self, obj):
|
||||
"""Display count of associated taxonomy terms"""
|
||||
return obj.taxonomy_terms.count()
|
||||
get_taxonomy_count.short_description = 'Taxonomy Count'
|
||||
|
||||
def get_site_display(self, obj):
|
||||
"""Safely get site name"""
|
||||
try:
|
||||
|
||||
@@ -154,6 +154,8 @@ class ContentSerializer(serializers.ModelSerializer):
|
||||
cluster_name = serializers.SerializerMethodField()
|
||||
sector_name = serializers.SerializerMethodField()
|
||||
taxonomy_terms_data = serializers.SerializerMethodField()
|
||||
tags = serializers.SerializerMethodField()
|
||||
categories = serializers.SerializerMethodField()
|
||||
has_image_prompts = serializers.SerializerMethodField()
|
||||
image_status = serializers.SerializerMethodField()
|
||||
has_generated_images = serializers.SerializerMethodField()
|
||||
@@ -175,6 +177,8 @@ class ContentSerializer(serializers.ModelSerializer):
|
||||
'content_type',
|
||||
'content_structure',
|
||||
'taxonomy_terms_data',
|
||||
'tags',
|
||||
'categories',
|
||||
'external_id',
|
||||
'external_url',
|
||||
'source',
|
||||
@@ -246,6 +250,20 @@ class ContentSerializer(serializers.ModelSerializer):
|
||||
for term in obj.taxonomy_terms.all()
|
||||
]
|
||||
|
||||
def get_tags(self, obj):
|
||||
"""Get only tags (taxonomy_type='tag')"""
|
||||
return [
|
||||
term.name
|
||||
for term in obj.taxonomy_terms.filter(taxonomy_type='tag')
|
||||
]
|
||||
|
||||
def get_categories(self, obj):
|
||||
"""Get only categories (taxonomy_type='category')"""
|
||||
return [
|
||||
term.name
|
||||
for term in obj.taxonomy_terms.filter(taxonomy_type='category')
|
||||
]
|
||||
|
||||
def get_has_image_prompts(self, obj):
|
||||
"""Check if content has any image prompts (images with prompts)"""
|
||||
return obj.images.filter(prompt__isnull=False).exclude(prompt='').exists()
|
||||
|
||||
Reference in New Issue
Block a user