chore: bulk commit of local changes across blog writer, SEO dashboard, scheduler, docs-site, and frontend

This commit is contained in:
ajaysi
2026-06-05 12:40:04 +05:30
parent b894bc0abb
commit e54aaa7a3e
74 changed files with 5667 additions and 996 deletions

View File

@@ -137,6 +137,15 @@ class KeywordCurator:
lines.append(f"### Competitive advantage signal (must weave into narrative): {content_gap[0]}")
lines.append(" → This is your primary differentiation hook. Surface it prominently in the unique value section.")
lines.append("")
lines.append("### SUGGESTED SECTION → KEYWORD MAPPING")
lines.append("Map each outline section's keyword focus according to its narrative role:")
lines.append("- Hook / Introduction → lead with primary and trending keywords for timeliness & relevance")
lines.append("- Problem / Pain Point → anchor on secondary and long-tail keywords (informational intent)")
lines.append("- Solution / How-To → weave in primary and secondary keywords for solution-oriented search")
lines.append("- Comparison / Analysis → embed semantic keywords to prevent topical drift into tangents")
lines.append("- Case Studies / Evidence → surface content gap keywords as differentiation proof points")
lines.append("- Future / Trends → leverage trending and content gap keywords for forward-looking authority")
lines.append("")
lines.append("GUIDELINE: Treat these as the primary keyword anchors. You may include closely related")
lines.append("intent-matching variations where natural, but avoid inserting every raw research keyword.")
@@ -176,7 +185,11 @@ class KeywordCurator:
slot_key: Optional[str] = None,
) -> List[str]:
"""
Pick up to N items from a keyword list.
Pick up to N items from a keyword list with diversity sampling.
When the raw list is significantly larger than the limit, selects
evenly-spaced entries to capture semantic diversity rather than
just the first N entries.
Args:
data: The raw keyword_analysis dict.
@@ -184,11 +197,24 @@ class KeywordCurator:
slot_key: The internal slot name for looking up the limit.
Falls back to source_key if not provided.
Returns:
Sliced list of at most N strings.
List of at most N strings with diversity sampling.
"""
limit_key = slot_key or source_key
limit = self.SLOTS.get(limit_key, 5)
raw: Any = data.get(source_key, [])
if not isinstance(raw, list):
return []
return raw[:limit]
if len(raw) <= limit:
return raw
if len(raw) <= limit * 2:
return raw[:limit]
indices = set()
if limit >= 2:
indices.add(0)
indices.add(len(raw) - 1)
step = (len(raw) - 1) / max(limit - 1, 1)
for i in range(1, limit - 1):
indices.add(int(round(i * step)))
else:
indices.add(0)
return [raw[i] for i in sorted(indices) if i < len(raw)][:limit]