feat: image generation overhaul (model-aware text, dim clamping, \.30 pricing), event-driven dashboard cache invalidation, SEO insights (AI visibility, GSC, keyword gap), YouTube OAuth/publish, blog writer & content planning improvements, scheduler monitoring updates
This commit is contained in:
@@ -9,51 +9,88 @@ from services.intelligence.agents.core_agent_framework import TaskProposal
|
||||
from services.intelligence.txtai_service import TxtaiIntelligenceService
|
||||
|
||||
class LinkGraphAgent(SIFBaseAgent):
|
||||
"""Agent for internal linking and graph optimization."""
|
||||
|
||||
"""Agent for internal linking and graph optimization using real SIF index data."""
|
||||
|
||||
def __init__(self, intelligence_service: TxtaiIntelligenceService, user_id: str, **kwargs):
|
||||
super().__init__(intelligence_service, user_id, agent_type="link_graph_expert", **kwargs)
|
||||
|
||||
async def analyze_graph(self) -> Dict[str, Any]:
|
||||
"""Analyze the knowledge graph structure of the content."""
|
||||
"""
|
||||
Analyze the knowledge graph structure by searching the SIF index.
|
||||
Returns semantic clusters and content grouping insights.
|
||||
"""
|
||||
if not self.intelligence.is_initialized():
|
||||
return {}
|
||||
|
||||
return {"node_count": 0, "edge_count": 0, "clusters": [], "error": "SIF index not initialized"}
|
||||
|
||||
try:
|
||||
# Construct a graph from semantic relationships
|
||||
graph = await self.intelligence.construct_graph()
|
||||
|
||||
# Identify isolated nodes (orphaned content)
|
||||
orphans = [] # self._find_orphans(graph)
|
||||
|
||||
# Identify central nodes (pillars)
|
||||
hubs = [] # self._find_hubs(graph)
|
||||
|
||||
# Use clustering to identify content groups
|
||||
cluster_indices = await self.intelligence.cluster(min_score=0.5)
|
||||
cluster_count = len(cluster_indices) if cluster_indices else 0
|
||||
|
||||
# Search for content hub candidates
|
||||
hub_results = await self.intelligence.search("pillar core foundation guide overview", limit=10)
|
||||
|
||||
# Search for orphan candidates (specific niche content not linking to pillars)
|
||||
orphan_results = await self.intelligence.search("specific detailed deep dive", limit=10)
|
||||
|
||||
return {
|
||||
"node_count": 0, # graph.number_of_nodes(),
|
||||
"edge_count": 0, # graph.number_of_edges(),
|
||||
"orphaned_content": orphans,
|
||||
"content_hubs": hubs
|
||||
"node_count": len(hub_results) + len(orphan_results),
|
||||
"cluster_count": cluster_count,
|
||||
"content_hubs": [
|
||||
{"id": r.get("id", ""), "title": r.get("text", "")[:100]}
|
||||
for r in hub_results
|
||||
],
|
||||
"orphaned_content": [
|
||||
{"id": r.get("id", ""), "snippet": r.get("text", "")[:100]}
|
||||
for r in orphan_results
|
||||
],
|
||||
"analysis_timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.__class__.__name__}] Graph analysis failed: {e}")
|
||||
return {}
|
||||
return {"node_count": 0, "edge_count": 0, "clusters": [], "error": str(e)}
|
||||
|
||||
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
|
||||
"""Propose internal linking tasks."""
|
||||
"""
|
||||
Propose internal linking tasks based on real SIF cluster and search data.
|
||||
"""
|
||||
proposals = []
|
||||
|
||||
# 1. Internal Link Opportunity
|
||||
proposals.append(TaskProposal(
|
||||
title="Internal Linking Review",
|
||||
description="Add internal links to your new post 'Content Strategy 101'.",
|
||||
pillar_id="create",
|
||||
priority="medium",
|
||||
estimated_time=15,
|
||||
source_agent="LinkGraphAgent",
|
||||
reasoning="Improves SEO and user navigation.",
|
||||
action_type="navigate",
|
||||
action_url="/content-planning-dashboard"
|
||||
))
|
||||
|
||||
cluster_count = 0
|
||||
hub_count = 0
|
||||
|
||||
if self.intelligence.is_initialized():
|
||||
try:
|
||||
cluster_indices = await self.intelligence.cluster(min_score=0.5)
|
||||
cluster_count = len(cluster_indices) if cluster_indices else 0
|
||||
|
||||
hub_results = await self.intelligence.search("pillar guide", limit=5)
|
||||
hub_count = len(hub_results)
|
||||
except Exception as e:
|
||||
logger.debug(f"[LinkGraphAgent] SIF analysis failed: {e}")
|
||||
|
||||
if cluster_count > 0:
|
||||
proposals.append(TaskProposal(
|
||||
title="Strengthen Internal Links",
|
||||
description=f"SIF detected {cluster_count} content clusters that need cross-linking.",
|
||||
pillar_id="distribute",
|
||||
priority="medium",
|
||||
estimated_time=20,
|
||||
source_agent="LinkGraphAgent",
|
||||
reasoning="Connecting content clusters improves SEO and user navigation.",
|
||||
action_type="navigate",
|
||||
action_url="/content-planning-dashboard"
|
||||
))
|
||||
else:
|
||||
proposals.append(TaskProposal(
|
||||
title="Plan Content Clusters",
|
||||
description="No content clusters found. Create pillar pages to build a linked content structure.",
|
||||
pillar_id="distribute",
|
||||
priority="medium",
|
||||
estimated_time=30,
|
||||
source_agent="LinkGraphAgent",
|
||||
reasoning="Structured content clusters drive organic growth.",
|
||||
action_type="navigate",
|
||||
action_url="/content-planning-dashboard"
|
||||
))
|
||||
|
||||
return proposals
|
||||
|
||||
Reference in New Issue
Block a user