Add Linker and Optimizer modules with API integration and frontend components
- Added Linker and Optimizer apps to `INSTALLED_APPS` in `settings.py`. - Configured API endpoints for Linker and Optimizer in `urls.py`. - Implemented `OptimizeContentFunction` for content optimization in the AI module. - Created prompts for content optimization and site structure generation. - Updated `OptimizerService` to utilize the new AI function for content optimization. - Developed frontend components including dashboards and content lists for Linker and Optimizer. - Integrated new routes and sidebar navigation for Linker and Optimizer in the frontend. - Enhanced content management with source and sync status filters in the Writer module. - Comprehensive test coverage added for new features and components.
This commit is contained in:
116
frontend/src/components/optimizer/ScoreComparison.tsx
Normal file
116
frontend/src/components/optimizer/ScoreComparison.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import React from 'react';
|
||||
import { OptimizationScores } from './OptimizationScores';
|
||||
|
||||
interface ScoreData {
|
||||
seo_score: number;
|
||||
readability_score: number;
|
||||
engagement_score: number;
|
||||
overall_score: number;
|
||||
}
|
||||
|
||||
interface ScoreComparisonProps {
|
||||
before: ScoreData;
|
||||
after: ScoreData;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ScoreComparison: React.FC<ScoreComparisonProps> = ({
|
||||
before,
|
||||
after,
|
||||
className = '',
|
||||
}) => {
|
||||
const calculateImprovement = (before: number, after: number) => {
|
||||
const diff = after - before;
|
||||
const percent = before > 0 ? ((diff / before) * 100).toFixed(1) : '0.0';
|
||||
return { diff, percent };
|
||||
};
|
||||
|
||||
const overallImprovement = calculateImprovement(before.overall_score, after.overall_score);
|
||||
|
||||
return (
|
||||
<div className={`space-y-6 ${className}`}>
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Score Comparison</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400">Overall Improvement:</span>
|
||||
<span
|
||||
className={`text-lg font-bold ${
|
||||
overallImprovement.diff > 0
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: overallImprovement.diff < 0
|
||||
? 'text-red-600 dark:text-red-400'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
}`}
|
||||
>
|
||||
{overallImprovement.diff > 0 ? '+' : ''}
|
||||
{overallImprovement.diff.toFixed(1)} ({overallImprovement.percent}%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Before Scores */}
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">Before</h4>
|
||||
<OptimizationScores scores={before} />
|
||||
</div>
|
||||
|
||||
{/* After Scores */}
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">After</h4>
|
||||
<OptimizationScores scores={after} before={before} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Detailed Breakdown */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4">Detailed Breakdown</h4>
|
||||
<div className="space-y-3">
|
||||
{[
|
||||
{ label: 'SEO Score', before: before.seo_score, after: after.seo_score },
|
||||
{ label: 'Readability Score', before: before.readability_score, after: after.readability_score },
|
||||
{ label: 'Engagement Score', before: before.engagement_score, after: after.engagement_score },
|
||||
{ label: 'Overall Score', before: before.overall_score, after: after.overall_score },
|
||||
].map(({ label, before: beforeScore, after: afterScore }) => {
|
||||
const improvement = calculateImprovement(beforeScore, afterScore);
|
||||
return (
|
||||
<div key={label} className="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-700">
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400">{label}</span>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-sm text-gray-500">{beforeScore.toFixed(1)}</span>
|
||||
<span className="text-gray-400">→</span>
|
||||
<span
|
||||
className={`text-sm font-medium ${
|
||||
improvement.diff > 0
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: improvement.diff < 0
|
||||
? 'text-red-600 dark:text-red-400'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
}`}
|
||||
>
|
||||
{afterScore.toFixed(1)}
|
||||
</span>
|
||||
<span
|
||||
className={`text-xs ${
|
||||
improvement.diff > 0
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: improvement.diff < 0
|
||||
? 'text-red-600 dark:text-red-400'
|
||||
: 'text-gray-500'
|
||||
}`}
|
||||
>
|
||||
({improvement.diff > 0 ? '+' : ''}
|
||||
{improvement.diff.toFixed(1)})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user