feat: Implement Today's Workflow and Agent Huddle enhancements

This commit is contained in:
ajaysi
2026-03-01 20:15:31 +05:30
parent 62d9c2e836
commit f8f7ddeb2a
25 changed files with 1852 additions and 272 deletions

View File

@@ -155,7 +155,7 @@ def track_agent_usage_sync(user_id: str, model_name: str, prompt: str, response_
db.execute(log_query, {
'user_id': user_id,
'provider': provider_enum.name, # Use name (GEMINI) not value (gemini) for SQLAlchemy Enum
'provider': provider_enum.value, # Use value (gemini) not name (GEMINI) for consistency
'endpoint': 'agent_action',
'method': 'GENERATE',
'model_used': model_name,

View File

@@ -107,6 +107,20 @@ class AgentAction:
if self.created_at is None:
self.created_at = datetime.utcnow().isoformat()
@dataclass
class TaskProposal:
"""Represents a daily task proposed by an agent"""
title: str
description: str
pillar_id: str # plan, generate, publish, analyze, engage, remarket
priority: str # high, medium, low
estimated_time: int # minutes
source_agent: str
reasoning: str
context_data: Optional[Dict[str, Any]] = None
action_type: str = "navigate"
action_url: Optional[str] = None
@dataclass
class MarketSignal:
"""Represents a market change or opportunity"""
@@ -833,6 +847,13 @@ class BaseALwrityAgent(ABC):
self.performance.success_rate = (
self.performance.successful_actions / self.performance.total_actions
)
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""
Propose daily tasks based on the agent's domain and context.
Must be implemented by specialized agents.
"""
return []
# Calculate efficiency score (0.0 to 1.0)
# Based on success rate and response time

View File

@@ -11,7 +11,7 @@ from typing import List, Dict, Any, Optional
from datetime import datetime
from loguru import logger
from ..txtai_service import TxtaiIntelligenceService
from services.intelligence.agents.core_agent_framework import BaseALwrityAgent, AgentAction
from services.intelligence.agents.core_agent_framework import BaseALwrityAgent, AgentAction, TaskProposal
from services.seo_tools.content_strategy_service import ContentStrategyService
from services.analytics import PlatformAnalyticsService
from services.intelligence.sif_agents import SharedLLMWrapper, LocalLLMWrapper
@@ -122,6 +122,56 @@ class StrategyArchitectAgent(SIFBaseAgent):
# Simple confidence based on cluster size - larger clusters are more reliable
return min(1.0, len(cluster_indices) / 10.0)
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""Propose PLAN pillar tasks based on semantic analysis."""
proposals = []
# 1. Pillar Health Check
try:
# We use a shorter timeout or cached check if possible, but discover_pillars is fairly fast
pillars = await self.discover_pillars()
if not pillars:
proposals.append(TaskProposal(
title="Establish Content Pillars",
description="Your content strategy lacks defined pillars. Let's analyze your niche to find core topics.",
pillar_id="plan",
priority="high",
estimated_time=15,
source_agent="StrategyArchitectAgent",
reasoning="No content pillars detected via SIF clustering.",
action_type="navigate",
action_url="/content-planning-dashboard"
))
elif len(pillars) < 3:
proposals.append(TaskProposal(
title="Expand Content Pillars",
description=f"You only have {len(pillars)} active pillars. Consider diversifying your strategy.",
pillar_id="plan",
priority="medium",
estimated_time=20,
source_agent="StrategyArchitectAgent",
reasoning=f"Low pillar diversity ({len(pillars)} detected).",
action_type="navigate",
action_url="/content-planning-dashboard"
))
except Exception as e:
logger.warning(f"[{self.__class__.__name__}] Error checking pillars for proposals: {e}")
# 2. Strategy Review (Generic fallback)
proposals.append(TaskProposal(
title="Review Strategic Goals",
description="Ensure your content output aligns with your quarterly business goals.",
pillar_id="plan",
priority="low",
estimated_time=10,
source_agent="StrategyArchitectAgent",
reasoning="Routine strategy maintenance.",
action_type="navigate",
action_url="/content-planning-dashboard"
))
return proposals
async def find_semantic_gaps(self, competitor_indices: List[int]) -> List[Dict[str, Any]]:
"""Compare user content vs competitor content to find missing topics."""
self._log_agent_operation("Finding semantic content gaps", competitor_count=len(competitor_indices))
@@ -856,6 +906,38 @@ class ContentStrategyAgent(BaseALwrityAgent):
self.sif_service = SIFIntegrationService(user_id)
except Exception as e:
logger.warning(f"Failed to initialize SIF service for ContentStrategyAgent: {e}")
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""Propose GENERATE pillar tasks."""
proposals = []
# 1. Content Gap Analysis
proposals.append(TaskProposal(
title="Analyze Content Gaps",
description="Identify missing topics in your strategy compared to competitors.",
pillar_id="generate",
priority="high",
estimated_time=30,
source_agent="ContentStrategyAgent",
reasoning="Regular gap analysis ensures competitive relevance.",
action_type="navigate",
action_url="/content-planning-dashboard"
))
# 2. Draft New Content
proposals.append(TaskProposal(
title="Draft New Blog Post",
description="Create a new article targeting your primary keywords.",
pillar_id="generate",
priority="medium",
estimated_time=45,
source_agent="ContentStrategyAgent",
reasoning="Maintain publishing consistency.",
action_type="navigate",
action_url="/blog-writer"
))
return proposals
def _create_txtai_agent(self) -> Agent:
"""Create Content Strategy Agent using txtai native framework"""
@@ -1274,7 +1356,26 @@ class CompetitorResponseAgent(BaseALwrityAgent):
self.sif_service = SIFIntegrationService(user_id)
except Exception as e:
logger.warning(f"Failed to initialize SIF service for CompetitorResponseAgent: {e}")
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""Propose REMARKET pillar tasks."""
proposals = []
# 1. Competitor Monitoring
proposals.append(TaskProposal(
title="Monitor Competitor Activity",
description="Check for new moves from your key competitors.",
pillar_id="remarket",
priority="medium",
estimated_time=15,
source_agent="CompetitorResponseAgent",
reasoning="Stay ahead of market changes.",
action_type="navigate",
action_url="/seo-dashboard"
))
return proposals
def _create_txtai_agent(self) -> Agent:
"""Create Competitor Response Agent using txtai native framework"""
if not TXTAI_AVAILABLE:
@@ -1463,7 +1564,39 @@ class SEOOptimizationAgent(BaseALwrityAgent):
self.sif_service = SIFIntegrationService(user_id)
except Exception as e:
logger.warning(f"Failed to initialize SIF service for SEOOptimizationAgent: {e}")
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""Propose ANALYZE pillar tasks."""
proposals = []
# 1. Technical Audit
proposals.append(TaskProposal(
title="Review SEO Health",
description="Check for critical technical issues affecting your search visibility.",
pillar_id="analyze",
priority="high",
estimated_time=20,
source_agent="SEOOptimizationAgent",
reasoning="Regular health checks prevent traffic drops.",
action_type="navigate",
action_url="/seo-dashboard"
))
# 2. Keyword Opportunities
proposals.append(TaskProposal(
title="Optimize Underperforming Keywords",
description="Identify keywords where you rank on page 2 and optimize content to boost them.",
pillar_id="analyze",
priority="medium",
estimated_time=40,
source_agent="SEOOptimizationAgent",
reasoning="Low-hanging fruit for traffic growth.",
action_type="navigate",
action_url="/seo-dashboard"
))
return proposals
def _create_txtai_agent(self) -> Agent:
"""Create SEO Optimization Agent using txtai native framework"""
if not TXTAI_AVAILABLE:
@@ -2101,7 +2234,39 @@ class SocialAmplificationAgent(BaseALwrityAgent):
self.sif_service = SIFIntegrationService(user_id)
except Exception as e:
logger.warning(f"Failed to initialize SIF service for SocialAmplificationAgent: {e}")
async def propose_daily_tasks(self, context: Dict[str, Any]) -> List[TaskProposal]:
"""Propose PUBLISH and ENGAGE pillar tasks."""
proposals = []
# 1. Publish Task
proposals.append(TaskProposal(
title="Schedule Social Content",
description="Plan and schedule your posts for the week to maintain consistent presence.",
pillar_id="publish",
priority="high",
estimated_time=20,
source_agent="SocialAmplificationAgent",
reasoning="Consistency is key for algorithm growth.",
action_type="navigate",
action_url="/scheduler-dashboard"
))
# 2. Engage Task
proposals.append(TaskProposal(
title="Engage with Community",
description="Respond to comments and interact with industry leaders' posts.",
pillar_id="engage",
priority="medium",
estimated_time=15,
source_agent="SocialAmplificationAgent",
reasoning="Community building increases reach.",
action_type="navigate",
action_url="/social-dashboard"
))
return proposals
def _create_txtai_agent(self) -> Agent:
"""Create Social Amplification Agent using txtai native framework"""
if not TXTAI_AVAILABLE:

View File

@@ -46,17 +46,18 @@ class CompetitorSemanticSnapshot:
@dataclass
class ContentSemanticInsight:
"""Real-time semantic insight for content monitoring."""
"""Represents an actionable content insight."""
insight_id: str
insight_type: str # "gap", "opportunity", "trend", "threat"
insight_type: str # 'gap', 'trend', 'optimization', 'threat'
title: str
description: str
confidence_score: float
impact_score: float
confidence_score: float # 0.0 to 1.0
impact_score: float # 0.0 to 10.0
related_topics: List[str]
suggested_actions: List[str]
created_at: str
expires_at: str
source_agent: str = "SIF Intelligence" # New field for agent attribution
class RealTimeSemanticMonitor:
@@ -274,78 +275,172 @@ class RealTimeSemanticMonitor:
async def _monitor_competitors(self) -> List[CompetitorSemanticSnapshot]:
"""Monitor competitor semantic positioning."""
snapshots = []
for competitor in self.monitored_competitors:
try:
# This would perform actual competitor analysis
# For now, return sample data
snapshot = CompetitorSemanticSnapshot(
competitor_id=f"comp_{competitor}",
competitor_name=competitor,
semantic_overlap=0.65,
unique_topics=["AI automation", "Voice search", "Video marketing"],
content_volume=random.randint(50, 200),
authority_score=random.uniform(0.4, 0.9),
last_updated=datetime.now().isoformat(),
trending_topics=["AI content", "Voice optimization"]
)
snapshots.append(snapshot)
except Exception as e:
logger.error(f"Failed to monitor competitor {competitor}: {e}")
try:
# 1. Get competitors from SIF integration
# We assume SIFIntegrationService has methods to get competitor data or we query index
# Let's try to search for "competitor_analysis" type in txtai index
results = await self.intelligence_service.search("competitor analysis", limit=10)
competitors_found = []
if results:
for res in results:
try:
metadata_str = res.get('object')
metadata = json.loads(metadata_str) if isinstance(metadata_str, str) else (metadata_str or res)
if metadata.get('type') == 'competitor_analysis':
competitors_found.append(metadata)
except: continue
# If no semantic data found, try fallback to DB/Integration service logic if needed
# For now, if we found semantic docs:
for comp_meta in competitors_found:
try:
full_report = comp_meta.get('full_report', {})
domain = comp_meta.get('url', 'Unknown')
# Calculate real metrics from the full report
# Use semantic overlap from SIF if available, or estimate
overlap = full_report.get('semantic_overlap', 0.5)
# Extract topics from the analysis content
topics = full_report.get('content_topics', [])
if not topics and 'analysis' in full_report:
# Try to extract from unstructured text if structured topics missing
topics = ["General Strategy"] # Fallback
snapshot = CompetitorSemanticSnapshot(
competitor_id=f"comp_{domain}",
competitor_name=domain,
semantic_overlap=overlap,
unique_topics=topics[:5],
content_volume=full_report.get('page_count', 0),
authority_score=full_report.get('authority_score', 0.5),
last_updated=comp_meta.get('timestamp', datetime.now().isoformat()),
trending_topics=full_report.get('trending_topics', [])
)
snapshots.append(snapshot)
except Exception as e:
logger.error(f"Error processing competitor snapshot: {e}")
if not snapshots and self.monitored_competitors:
# Fallback for manually added competitors that might not be fully indexed yet
for competitor in self.monitored_competitors:
snapshots.append(CompetitorSemanticSnapshot(
competitor_id=f"comp_{competitor}",
competitor_name=competitor,
semantic_overlap=0.0,
unique_topics=["Pending Analysis"],
content_volume=0,
authority_score=0.0,
last_updated=datetime.now().isoformat(),
trending_topics=[]
))
except Exception as e:
logger.error(f"Failed to monitor competitors: {e}")
return snapshots
async def _analyze_content_performance(self) -> List[ContentSemanticInsight]:
"""Analyze content performance and identify insights."""
"""Analyze content performance and identify insights using SIF Agents."""
insights = []
try:
# Generate various types of insights
current_time = datetime.now()
# Content gap insight
insights.append(ContentSemanticInsight(
insight_id="gap_001",
insight_type="gap",
title="Voice Search Optimization Gap",
description="Competitors are covering voice search topics 40% more than your content",
confidence_score=0.85,
impact_score=8.5,
related_topics=["voice search", "featured snippets", "conversational AI"],
suggested_actions=["Create voice search content", "Optimize for featured snippets"],
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=7)).isoformat()
))
# Trending opportunity insight
insights.append(ContentSemanticInsight(
insight_id="trend_001",
insight_type="trend",
title="AI Content Tools Trending",
description="AI content creation tools showing 300% increase in search volume",
confidence_score=0.92,
impact_score=9.2,
related_topics=["AI content", "content automation", "AI writing tools"],
suggested_actions=["Create AI tool reviews", "Develop AI content strategy"],
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=14)).isoformat()
))
# Threat insight
insights.append(ContentSemanticInsight(
insight_id="threat_001",
insight_type="threat",
title="Competitor Content Surge",
description="Top competitor increased content production by 150% in your key topics",
confidence_score=0.78,
impact_score=7.8,
related_topics=["content strategy", "competitor analysis"],
suggested_actions=["Increase content frequency", "Focus on unique angles"],
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=5)).isoformat()
))
# 1. Initialize Agents if needed (lazy load to avoid circular imports)
if not self.strategy_agent:
from ..agents.specialized_agents import StrategyArchitectAgent, ContentStrategyAgent, CompetitorResponseAgent
self.strategy_agent = StrategyArchitectAgent(self.user_id)
self.content_agent = ContentStrategyAgent(self.user_id)
self.competitor_agent = CompetitorResponseAgent(self.user_id)
# 2. Get Real Insights from Agents
# Content Gaps
try:
# We can reuse the propose_daily_tasks logic or call specific methods
# Let's manually construct a "gap analysis" context for the agent
gap_context = {"analysis_type": "gaps", "website_url": "user_site"}
# Ideally we call a specific method like find_semantic_gaps if available publicly
# But propose_daily_tasks returns TaskProposal objects.
# Let's check if we can get raw insights.
# The agents have methods like find_semantic_gaps (StrategyArchitect)
# Using StrategyArchitect for pillar/gap analysis
if hasattr(self.strategy_agent, 'find_semantic_gaps'):
# This method requires competitor indices, which is complex to get here without full context.
# Let's use the SIF service directly for lighter weight insights or call the agent's high level method.
pass
# Alternative: Query SIF directly for "content gaps" if they are indexed as such
# Or generate them now via LLM + SIF Context
# Let's generate ONE high quality insight via ContentStrategyAgent
# We'll simulate a task proposal request but specifically for "insights"
# Actually, let's look at SIFIntegrationService.get_content_strategy_context
# For now, to fix the "mock data" issue quickly:
# We will check if we have ANY data in SIF.
# If yes, we generate dynamic insights based on that data.
dashboard_context = await self.sif_service.get_seo_dashboard_context()
if "error" not in dashboard_context:
data = dashboard_context.get("dashboard_data", {})
summary = data.get("summary", {})
# Insight 1: Performance Trend
ctr = summary.get("ctr", 0)
if ctr < 0.02:
insights.append(ContentSemanticInsight(
insight_id="perf_low_ctr",
insight_type="opportunity",
title="Low CTR Opportunity",
description=f"Your average CTR is {ctr:.1%}. Optimizing meta descriptions could boost traffic.",
confidence_score=0.9,
impact_score=8.0,
related_topics=["meta tags", "titles", "ctr optimization"],
suggested_actions=["Rewrite titles for high-impression low-click pages"],
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=7)).isoformat(),
source_agent="SEO Specialist Agent"
))
# Insight 2: Keyword Opportunities (from AI insights in dashboard data)
ai_insights = data.get("ai_insights", [])
for i, ai_ins in enumerate(ai_insights[:2]): # Take top 2
insights.append(ContentSemanticInsight(
insight_id=f"ai_insight_{i}",
insight_type="trend", # Map category
title=f"AI Recommendation: {ai_ins.get('category', 'General')}",
description=ai_ins.get('insight', 'No description'),
confidence_score=0.85,
impact_score=7.5,
related_topics=[ai_ins.get('category', 'seo')],
suggested_actions=[ai_ins.get('insight')], # Simplification
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=7)).isoformat(),
source_agent="Strategy Architect Agent"
))
except Exception as agent_err:
logger.warning(f"Agent insight generation failed: {agent_err}")
# If still no insights (e.g. no dashboard data), AND we have no fallback,
# THEN we might return an empty list or a "Setup" insight.
if not insights:
insights.append(ContentSemanticInsight(
insight_id="setup_001",
insight_type="gap",
title="Awaiting Data Analysis",
description="Connect Search Console or complete competitor analysis to see real-time insights.",
confidence_score=1.0,
impact_score=5.0,
related_topics=["onboarding"],
suggested_actions=["Complete Step 5 Onboarding"],
created_at=current_time.isoformat(),
expires_at=(current_time + timedelta(days=1)).isoformat(),
source_agent="Onboarding Assistant"
))
except Exception as e:
logger.error(f"Failed to analyze content performance: {e}")