AI functins complete

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-26 20:55:03 +00:00
parent 94a8aee0e2
commit 9b9352b9d2
4 changed files with 68 additions and 23 deletions

View File

@@ -175,10 +175,18 @@ class GenerateContentFunction(BaseAIFunction):
# JSON response with structured fields # JSON response with structured fields
content_html = parsed.get('content', '') content_html = parsed.get('content', '')
title = parsed.get('title') or task.title title = parsed.get('title') or task.title
meta_title = parsed.get('meta_title') or parsed.get('seo_title') or title
meta_description = parsed.get('meta_description') or parsed.get('seo_description')
primary_keyword = parsed.get('primary_keyword') or parsed.get('focus_keyword')
secondary_keywords = parsed.get('secondary_keywords') or parsed.get('keywords', [])
else: else:
# Plain text response # Plain text response
content_html = str(parsed) content_html = str(parsed)
title = task.title title = task.title
meta_title = title
meta_description = None
primary_keyword = None
secondary_keywords = []
# Calculate word count # Calculate word count
word_count = 0 word_count = 0
@@ -192,6 +200,12 @@ class GenerateContentFunction(BaseAIFunction):
title=title, title=title,
content_html=content_html or '', content_html=content_html or '',
word_count=word_count, word_count=word_count,
# SEO fields
meta_title=meta_title,
meta_description=meta_description,
primary_keyword=primary_keyword,
secondary_keywords=secondary_keywords if isinstance(secondary_keywords, list) else [],
# Structure
cluster=task.cluster, cluster=task.cluster,
content_type=task.content_type, content_type=task.content_type,
content_structure=task.content_structure, content_structure=task.content_structure,

View File

@@ -174,6 +174,13 @@ class Content(SiteSectorBaseModel):
default=0, default=0,
help_text="Actual word count of content (calculated from HTML)" help_text="Actual word count of content (calculated from HTML)"
) )
# SEO fields
meta_title = models.CharField(max_length=255, blank=True, null=True, help_text="SEO meta title")
meta_description = models.TextField(blank=True, null=True, help_text="SEO meta description")
primary_keyword = models.CharField(max_length=255, blank=True, null=True, help_text="Primary SEO keyword")
secondary_keywords = models.JSONField(default=list, blank=True, help_text="Secondary SEO keywords")
cluster = models.ForeignKey( cluster = models.ForeignKey(
'planner.Clusters', 'planner.Clusters',
on_delete=models.SET_NULL, on_delete=models.SET_NULL,

View File

@@ -163,6 +163,10 @@ class ContentSerializer(serializers.ModelSerializer):
'id', 'id',
'title', 'title',
'content_html', 'content_html',
'meta_title',
'meta_description',
'primary_keyword',
'secondary_keywords',
'cluster_id', 'cluster_id',
'cluster_name', 'cluster_name',
'content_type', 'content_type',

View File

@@ -585,8 +585,8 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
]); ]);
const parsedArticle = useMemo( const parsedArticle = useMemo(
() => parseContentHtml(content?.html_content ?? ''), () => parseContentHtml(content?.content_html ?? ''),
[content?.html_content] [content?.content_html]
); );
const shouldShowFeaturedBlock = imagesLoading || Boolean(resolvedFeaturedImage); const shouldShowFeaturedBlock = imagesLoading || Boolean(resolvedFeaturedImage);
@@ -770,6 +770,22 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
SEO & Tags SEO & Tags
</h3> </h3>
<div className="space-y-3"> <div className="space-y-3">
{content.meta_title && (
<div>
<p className="text-xs text-gray-500 dark:text-gray-400">Meta Title</p>
<p className="text-sm font-medium text-gray-900 dark:text-white">
{content.meta_title}
</p>
</div>
)}
{content.meta_description && (
<div>
<p className="text-xs text-gray-500 dark:text-gray-400">Meta Description</p>
<p className="text-sm text-gray-700 dark:text-gray-300">
{content.meta_description}
</p>
</div>
)}
{content.primary_keyword && ( {content.primary_keyword && (
<div> <div>
<p className="text-xs text-gray-500 dark:text-gray-400">Primary Keyword</p> <p className="text-xs text-gray-500 dark:text-gray-400">Primary Keyword</p>
@@ -797,37 +813,41 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
</div> </div>
</div> </div>
{/* Tags and Categories */} {/* Tags and Categories from taxonomy_terms_data */}
{(content.tags && content.tags.length > 0) || (content.categories && content.categories.length > 0) ? ( {content.taxonomy_terms_data && content.taxonomy_terms_data.length > 0 ? (
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700"> <div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<div className="flex flex-wrap gap-4"> <div className="flex flex-wrap gap-4">
{content.tags && content.tags.length > 0 && ( {content.taxonomy_terms_data.filter(term => term.taxonomy_type === 'tag').length > 0 && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<TagIcon className="w-4 h-4 text-gray-400" /> <TagIcon className="w-4 h-4 text-gray-400" />
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{content.tags.map((tag, idx) => ( {content.taxonomy_terms_data
<span .filter(term => term.taxonomy_type === 'tag')
key={idx} .map((tag) => (
className="px-3 py-1 bg-brand-50 dark:bg-brand-900/20 text-brand-700 dark:text-brand-300 rounded-full text-xs font-medium" <span
> key={tag.id}
{tag} className="px-3 py-1 bg-brand-50 dark:bg-brand-900/20 text-brand-700 dark:text-brand-300 rounded-full text-xs font-medium"
</span> >
))} {tag.name}
</span>
))}
</div> </div>
</div> </div>
)} )}
{content.categories && content.categories.length > 0 && ( {content.taxonomy_terms_data.filter(term => term.taxonomy_type === 'category').length > 0 && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-xs text-gray-500 dark:text-gray-400">Categories:</span> <span className="text-xs text-gray-500 dark:text-gray-400">Categories:</span>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{content.categories.map((category, idx) => ( {content.taxonomy_terms_data
<span .filter(term => term.taxonomy_type === 'category')
key={idx} .map((category) => (
className="px-3 py-1 bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300 rounded-full text-xs font-medium" <span
> key={category.id}
{category} className="px-3 py-1 bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300 rounded-full text-xs font-medium"
</span> >
))} {category.name}
</span>
))}
</div> </div>
</div> </div>
)} )}
@@ -878,7 +898,7 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
sections={parsedArticle.sections} sections={parsedArticle.sections}
sectionImages={resolvedInArticleImages} sectionImages={resolvedInArticleImages}
imagesLoading={imagesLoading} imagesLoading={imagesLoading}
rawHtml={content.html_content} rawHtml={content.content_html}
/> />
</div> </div>