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

@@ -17,7 +17,8 @@ import PageMeta from '../../components/common/PageMeta';
import { Card } from '../../components/ui/card';
import Button from '../../components/ui/button/Button';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { fetchAPI } from '../../services/api';
import { fetchAPI, fetchSiteBlueprints } from '../../services/api';
import SiteProgressWidget from '../../components/sites/SiteProgressWidget';
interface Site {
id: number;
@@ -51,6 +52,7 @@ export default function SiteDashboard() {
const toast = useToast();
const [site, setSite] = useState<Site | null>(null);
const [stats, setStats] = useState<SiteStats | null>(null);
const [blueprints, setBlueprints] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
@@ -62,9 +64,10 @@ export default function SiteDashboard() {
const loadSiteData = async () => {
try {
setLoading(true);
const [siteData, statsData] = await Promise.all([
const [siteData, statsData, blueprintsData] = await Promise.all([
fetchAPI(`/v1/auth/sites/${siteId}/`),
fetchSiteStats(),
fetchSiteBlueprints({ site_id: Number(siteId) }),
]);
if (siteData) {
@@ -74,6 +77,10 @@ export default function SiteDashboard() {
if (statsData) {
setStats(statsData);
}
if (blueprintsData && blueprintsData.results) {
setBlueprints(blueprintsData.results);
}
} catch (error: any) {
toast.error(`Failed to load site data: ${error.message}`);
} finally {
@@ -207,6 +214,19 @@ export default function SiteDashboard() {
</div>
</div>
{/* Stage 3: Site Progress Widget */}
{blueprints.length > 0 && (
<div className="mb-6">
{blueprints.map((blueprint) => (
<SiteProgressWidget
key={blueprint.id}
blueprintId={blueprint.id}
siteId={Number(siteId)}
/>
))}
</div>
)}
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
{statCards.map((stat, index) => (

View File

@@ -32,6 +32,13 @@ interface Content {
sector: number;
word_count?: number;
metadata?: Record<string, any>;
// Stage 3: Metadata fields
entity_type?: string | null;
cluster_name?: string | null;
cluster_id?: number | null;
taxonomy_name?: string | null;
taxonomy_id?: number | null;
cluster_role?: string | null;
}
export default function PostEditor() {
@@ -269,6 +276,10 @@ export default function PostEditor() {
<div className="p-6">
<PageMeta title={content.id ? 'Edit Post' : 'New Post'} />
<div className="flex gap-6">
{/* Main Content Area */}
<div className="flex-1">
<div className="mb-6 flex justify-between items-center">
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
@@ -289,10 +300,11 @@ export default function PostEditor() {
<Button
variant="primary"
onClick={handleSave}
disabled={saving}
disabled={saving || (content.status === 'publish' && validationResult && !validationResult.is_valid)}
title={content.status === 'publish' && validationResult && !validationResult.is_valid ? 'Please fix validation errors before publishing' : undefined}
>
<SaveIcon className="w-4 h-4 mr-2" />
{saving ? 'Saving...' : 'Save Post'}
{saving ? 'Saving...' : content.status === 'publish' ? 'Publish' : 'Save Post'}
</Button>
</div>
</div>
@@ -717,6 +729,103 @@ export default function PostEditor() {
</Card>
)}
</div>
</div>
{/* Stage 3: Sidebar with Metadata Summary */}
{content.id && (
<div className="w-80 flex-shrink-0">
<Card className="p-4 sticky top-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
Content Metadata
</h3>
<div className="space-y-4">
{/* Entity Type */}
{content.entity_type && (
<div>
<div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
Entity Type
</div>
<div className="text-sm text-gray-900 dark:text-white">
{content.entity_type ? content.entity_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase()) : '-'}
</div>
</div>
)}
{/* Cluster */}
{content.cluster_name && (
<div>
<div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
Cluster
</div>
<div className="text-sm text-gray-900 dark:text-white">
{content.cluster_name}
{content.cluster_role && (
<span className="ml-2 text-xs text-gray-500 dark:text-gray-400">
({content.cluster_role})
</span>
)}
</div>
</div>
)}
{/* Taxonomy */}
{content.taxonomy_name && (
<div>
<div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
Taxonomy
</div>
<div className="text-sm text-gray-900 dark:text-white">
{content.taxonomy_name}
</div>
</div>
)}
{/* Validation Status */}
{validationResult && (
<div>
<div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
Validation Status
</div>
<div className={`text-sm font-medium ${
validationResult.is_valid
? 'text-green-600 dark:text-green-400'
: 'text-red-600 dark:text-red-400'
}`}>
{validationResult.is_valid ? '✓ Valid' : `${validationResult.validation_errors.length} error(s)`}
</div>
</div>
)}
{/* Quick Links */}
<div className="pt-4 border-t border-gray-200 dark:border-gray-700">
<div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">
Quick Actions
</div>
<div className="space-y-1">
{content.cluster_id && (
<button
onClick={() => navigate(`/planner/clusters/${content.cluster_id}`)}
className="text-xs text-blue-600 dark:text-blue-400 hover:underline w-full text-left"
>
View Cluster
</button>
)}
{content.taxonomy_id && (
<button
onClick={() => navigate(`/sites/builder?taxonomy=${content.taxonomy_id}`)}
className="text-xs text-blue-600 dark:text-blue-400 hover:underline w-full text-left"
>
View Taxonomy
</button>
)}
</div>
</div>
</div>
</Card>
</div>
)}
</div>
</div>
);
}