AI functins complete
This commit is contained in:
@@ -175,10 +175,18 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
# JSON response with structured fields
|
||||
content_html = parsed.get('content', '')
|
||||
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:
|
||||
# Plain text response
|
||||
content_html = str(parsed)
|
||||
title = task.title
|
||||
meta_title = title
|
||||
meta_description = None
|
||||
primary_keyword = None
|
||||
secondary_keywords = []
|
||||
|
||||
# Calculate word count
|
||||
word_count = 0
|
||||
@@ -192,6 +200,12 @@ class GenerateContentFunction(BaseAIFunction):
|
||||
title=title,
|
||||
content_html=content_html or '',
|
||||
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,
|
||||
content_type=task.content_type,
|
||||
content_structure=task.content_structure,
|
||||
|
||||
@@ -174,6 +174,13 @@ class Content(SiteSectorBaseModel):
|
||||
default=0,
|
||||
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(
|
||||
'planner.Clusters',
|
||||
on_delete=models.SET_NULL,
|
||||
|
||||
@@ -163,6 +163,10 @@ class ContentSerializer(serializers.ModelSerializer):
|
||||
'id',
|
||||
'title',
|
||||
'content_html',
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
'primary_keyword',
|
||||
'secondary_keywords',
|
||||
'cluster_id',
|
||||
'cluster_name',
|
||||
'content_type',
|
||||
|
||||
@@ -585,8 +585,8 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
]);
|
||||
|
||||
const parsedArticle = useMemo(
|
||||
() => parseContentHtml(content?.html_content ?? ''),
|
||||
[content?.html_content]
|
||||
() => parseContentHtml(content?.content_html ?? ''),
|
||||
[content?.content_html]
|
||||
);
|
||||
|
||||
const shouldShowFeaturedBlock = imagesLoading || Boolean(resolvedFeaturedImage);
|
||||
@@ -770,6 +770,22 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
SEO & Tags
|
||||
</h3>
|
||||
<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 && (
|
||||
<div>
|
||||
<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>
|
||||
|
||||
{/* Tags and Categories */}
|
||||
{(content.tags && content.tags.length > 0) || (content.categories && content.categories.length > 0) ? (
|
||||
{/* Tags and Categories from taxonomy_terms_data */}
|
||||
{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="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">
|
||||
<TagIcon className="w-4 h-4 text-gray-400" />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{content.tags.map((tag, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
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"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
{content.taxonomy_terms_data
|
||||
.filter(term => term.taxonomy_type === 'tag')
|
||||
.map((tag) => (
|
||||
<span
|
||||
key={tag.id}
|
||||
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"
|
||||
>
|
||||
{tag.name}
|
||||
</span>
|
||||
))}
|
||||
</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">
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400">Categories:</span>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{content.categories.map((category, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
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"
|
||||
>
|
||||
{category}
|
||||
</span>
|
||||
))}
|
||||
{content.taxonomy_terms_data
|
||||
.filter(term => term.taxonomy_type === 'category')
|
||||
.map((category) => (
|
||||
<span
|
||||
key={category.id}
|
||||
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"
|
||||
>
|
||||
{category.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -878,7 +898,7 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
sections={parsedArticle.sections}
|
||||
sectionImages={resolvedInArticleImages}
|
||||
imagesLoading={imagesLoading}
|
||||
rawHtml={content.html_content}
|
||||
rawHtml={content.content_html}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user