Implement Stage 3: Enhance content generation and metadata features

- Updated AI prompts to include metadata context, cluster roles, and product attributes for improved content generation.
- Enhanced GenerateContentFunction to incorporate taxonomy and keyword objects for richer context.
- Introduced new metadata fields in frontend components for better content organization and filtering.
- Added cluster match, taxonomy match, and relevance score to LinkResults for improved link management.
- Implemented metadata completeness scoring and recommended actions in AnalysisPreview for better content optimization.
- Updated API services to support new metadata structures and site progress tracking.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-19 20:07:05 +00:00
parent bae9ea47d8
commit 746a51715f
14 changed files with 892 additions and 23 deletions

View File

@@ -156,6 +156,58 @@ export const createIdeasPageConfig = (
width: '200px',
render: (_value: string, row: ContentIdea) => row.keyword_cluster_name || '-',
},
// Stage 3: Metadata columns
{
key: 'site_entity_type',
label: 'Entity Type',
sortable: true,
sortField: 'site_entity_type',
width: '120px',
defaultVisible: true,
render: (value: string, row: ContentIdea) => {
const entityType = value || (row as any).site_entity_type;
if (!entityType) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const typeLabels: Record<string, string> = {
'blog_post': 'Blog Post',
'article': 'Article',
'product': 'Product',
'service': 'Service',
'taxonomy': 'Taxonomy',
'page': 'Page',
};
return (
<Badge color="info" size="sm" variant="light">
{typeLabels[entityType] || entityType}
</Badge>
);
},
},
{
key: 'cluster_role',
label: 'Role',
sortable: true,
sortField: 'cluster_role',
width: '100px',
defaultVisible: false,
render: (value: string, row: ContentIdea) => {
const role = value || (row as any).cluster_role;
if (!role) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const roleColors: Record<string, 'primary' | 'success' | 'warning'> = {
'hub': 'primary',
'supporting': 'success',
'attribute': 'warning',
};
return (
<Badge color={roleColors[role] || 'primary'} size="sm" variant="light">
{role.charAt(0).toUpperCase() + role.slice(1)}
</Badge>
);
},
},
{
...statusColumn,
sortable: true,
@@ -242,6 +294,21 @@ export const createIdeasPageConfig = (
{ value: 'tutorial', label: 'Tutorial' },
],
},
// Stage 3: Entity type filter
{
key: 'site_entity_type',
label: 'Entity Type',
type: 'select',
options: [
{ value: '', label: 'All Entity Types' },
{ value: 'blog_post', label: 'Blog Post' },
{ value: 'article', label: 'Article' },
{ value: 'product', label: 'Product' },
{ value: 'service', label: 'Service' },
{ value: 'taxonomy', label: 'Taxonomy' },
{ value: 'page', label: 'Page' },
],
},
{
key: 'keyword_cluster_id',
label: 'Cluster',

View File

@@ -107,7 +107,7 @@ export const createTasksPageConfig = (
toggleContentLabel: 'Idea & Content Outline',
render: (value: string, row: Task) => {
const isSiteBuilder = value?.startsWith('[Site Builder]');
const displayTitle = isSiteBuilder ? value.replace('[Site Builder] ', '') : value;
const displayTitle = isSiteBuilder && value ? value.replace('[Site Builder] ', '') : (value || 'Untitled');
return (
<div className="flex items-center gap-2">
@@ -140,6 +140,76 @@ export const createTasksPageConfig = (
width: '200px',
render: (_value: string, row: Task) => row.cluster_name || '-',
},
// Stage 3: Metadata columns
{
key: 'entity_type',
label: 'Entity Type',
sortable: true,
sortField: 'entity_type',
width: '120px',
defaultVisible: true,
render: (value: string, row: Task) => {
const entityType = value || row.entity_type;
if (!entityType) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const typeLabels: Record<string, string> = {
'blog_post': 'Blog Post',
'article': 'Article',
'product': 'Product',
'service': 'Service',
'taxonomy': 'Taxonomy',
'page': 'Page',
};
return (
<Badge color="info" size="sm" variant="light">
{typeLabels[entityType] || entityType}
</Badge>
);
},
},
{
key: 'cluster_role',
label: 'Role',
sortable: true,
sortField: 'cluster_role',
width: '100px',
defaultVisible: false,
render: (value: string, row: Task) => {
const role = value || row.cluster_role;
if (!role) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const roleColors: Record<string, 'primary' | 'success' | 'warning'> = {
'hub': 'primary',
'supporting': 'success',
'attribute': 'warning',
};
return (
<Badge color={roleColors[role] || 'primary'} size="sm" variant="light">
{role.charAt(0).toUpperCase() + role.slice(1)}
</Badge>
);
},
},
{
key: 'taxonomy_name',
label: 'Taxonomy',
sortable: false,
width: '150px',
defaultVisible: false,
render: (_value: string, row: Task) => {
const taxonomyName = row.taxonomy_name;
if (!taxonomyName) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
return (
<Badge color="purple" size="sm" variant="light">
{taxonomyName}
</Badge>
);
},
},
{
key: 'content_structure',
label: 'Structure',
@@ -339,6 +409,21 @@ export const createTasksPageConfig = (
})(),
dynamicOptions: 'clusters',
},
// Stage 3: Entity type filter
{
key: 'entity_type',
label: 'Entity Type',
type: 'select',
options: [
{ value: '', label: 'All Entity Types' },
{ value: 'blog_post', label: 'Blog Post' },
{ value: 'article', label: 'Article' },
{ value: 'product', label: 'Product' },
{ value: 'service', label: 'Service' },
{ value: 'taxonomy', label: 'Taxonomy' },
{ value: 'page', label: 'Page' },
],
},
],
formFields: (clusters: Array<{ id: number; name: string }>) => [
{