Implement Stage 3: Enhance content metadata and validation features
- Added entity metadata fields to the Tasks model, including entity_type, taxonomy, and cluster_role. - Updated CandidateEngine to prioritize content relevance based on cluster mappings. - Introduced metadata completeness scoring in ContentAnalyzer. - Enhanced validation services to check for entity type and mapping completeness. - Updated frontend components to display and validate new metadata fields. - Implemented API endpoints for content validation and metadata persistence. - Migrated existing data to populate new metadata fields for Tasks and Content.
This commit is contained in:
@@ -5,6 +5,7 @@ interface InputProps {
|
||||
type?: "text" | "number" | "email" | "password" | "date" | "time" | string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
value?: string | number;
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
@@ -16,12 +17,15 @@ interface InputProps {
|
||||
success?: boolean;
|
||||
error?: boolean;
|
||||
hint?: string;
|
||||
multiline?: boolean;
|
||||
rows?: number;
|
||||
}
|
||||
|
||||
const Input: FC<InputProps> = ({
|
||||
type = "text",
|
||||
id,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
value,
|
||||
onChange,
|
||||
@@ -33,6 +37,8 @@ const Input: FC<InputProps> = ({
|
||||
success = false,
|
||||
error = false,
|
||||
hint,
|
||||
multiline = false,
|
||||
rows = 3,
|
||||
}) => {
|
||||
let inputClasses = ` h-9 w-full rounded-lg border appearance-none px-3 py-2 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 ${className}`;
|
||||
|
||||
@@ -46,21 +52,44 @@ const Input: FC<InputProps> = ({
|
||||
inputClasses += ` bg-transparent text-gray-800 border-gray-300 focus:border-brand-300 focus:ring-brand-500/20 dark:border-gray-700 dark:text-white/90 dark:focus:border-brand-800`;
|
||||
}
|
||||
|
||||
const inputId = id || name || `input-${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<input
|
||||
type={type}
|
||||
id={id}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
disabled={disabled}
|
||||
className={inputClasses}
|
||||
/>
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="block text-sm font-medium mb-2 text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{multiline ? (
|
||||
<textarea
|
||||
id={inputId}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
value={value as string}
|
||||
onChange={onChange as any}
|
||||
disabled={disabled}
|
||||
rows={rows}
|
||||
className={inputClasses.replace('h-9', '')}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type={type}
|
||||
id={inputId}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
disabled={disabled}
|
||||
className={inputClasses}
|
||||
/>
|
||||
)}
|
||||
|
||||
{hint && (
|
||||
<p
|
||||
|
||||
@@ -6,11 +6,15 @@ interface ScoreData {
|
||||
readability_score: number;
|
||||
engagement_score: number;
|
||||
overall_score: number;
|
||||
metadata_completeness_score?: number; // Stage 3: Metadata completeness
|
||||
word_count?: number;
|
||||
has_meta_title?: boolean;
|
||||
has_meta_description?: boolean;
|
||||
has_primary_keyword?: boolean;
|
||||
internal_links_count?: number;
|
||||
has_cluster_mapping?: boolean; // Stage 3: Cluster mapping
|
||||
has_taxonomy_mapping?: boolean; // Stage 3: Taxonomy mapping
|
||||
has_attributes?: boolean; // Stage 3: Attributes
|
||||
}
|
||||
|
||||
interface OptimizationScoresProps {
|
||||
@@ -53,7 +57,7 @@ export const OptimizationScores: React.FC<OptimizationScoresProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`grid grid-cols-1 md:grid-cols-4 gap-4 ${className}`}>
|
||||
<div className={`grid grid-cols-1 md:grid-cols-5 gap-4 ${className}`}>
|
||||
{/* Overall Score */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
@@ -149,6 +153,51 @@ export const OptimizationScores: React.FC<OptimizationScoresProps> = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Metadata Completeness Score - Stage 3 */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-sm font-medium text-gray-600 dark:text-gray-400">Metadata</span>
|
||||
{before && scores.metadata_completeness_score !== undefined && getChangeIcon(
|
||||
scores.metadata_completeness_score,
|
||||
before.metadata_completeness_score
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className={`text-2xl font-bold ${getScoreColor(scores.metadata_completeness_score || 0)}`}>
|
||||
{(scores.metadata_completeness_score || 0).toFixed(1)}
|
||||
</span>
|
||||
{before && scores.metadata_completeness_score !== undefined && (
|
||||
<span className="text-xs text-gray-500">
|
||||
{getChangeText(scores.metadata_completeness_score, before.metadata_completeness_score)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={`mt-2 h-2 rounded-full ${getScoreBgColor(scores.metadata_completeness_score || 0)}`}>
|
||||
<div
|
||||
className={`h-2 rounded-full ${getScoreColor(scores.metadata_completeness_score || 0).replace('text-', 'bg-')}`}
|
||||
style={{ width: `${scores.metadata_completeness_score || 0}%` }}
|
||||
/>
|
||||
</div>
|
||||
{/* Metadata indicators */}
|
||||
<div className="mt-3 flex flex-wrap gap-2 text-xs">
|
||||
{scores.has_cluster_mapping && (
|
||||
<span className="px-2 py-0.5 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded">
|
||||
Cluster
|
||||
</span>
|
||||
)}
|
||||
{scores.has_taxonomy_mapping && (
|
||||
<span className="px-2 py-0.5 bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded">
|
||||
Taxonomy
|
||||
</span>
|
||||
)}
|
||||
{scores.has_attributes && (
|
||||
<span className="px-2 py-0.5 bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded">
|
||||
Attributes
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user