Recovered state: integrated TrendSurferAgent, restored frontend/backend files, and cleaned up recovery scripts

This commit is contained in:
ajaysi
2026-02-08 13:56:57 +05:30
parent 1db10ccd0f
commit e404a86502
333 changed files with 42223 additions and 10875 deletions

View File

@@ -0,0 +1,165 @@
"""
Trend Surfer Agent
Agent for identifying and capitalizing on emerging market trends.
"""
import traceback
from typing import List, Dict, Any, Optional
from loguru import logger
from services.intelligence.agents.specialized_agents import SIFBaseAgent
from services.intelligence.agents.market_signal_detector import MarketSignalDetector, MarketSignal, UrgencyLevel, SignalType
from services.intelligence.txtai_service import TxtaiIntelligenceService
from services.research.trends.google_trends_service import GoogleTrendsService
class TrendSurferAgent(SIFBaseAgent):
"""
Agent for identifying and capitalizing on emerging market trends.
"Surfs" the trends detected by MarketSignalDetector to propose timely content.
"""
def __init__(self, intelligence_service: TxtaiIntelligenceService, user_id: str):
super().__init__(intelligence_service)
self.user_id = user_id
self.signal_detector = MarketSignalDetector(user_id)
self.trends_service = GoogleTrendsService()
async def surf_trends(self) -> List[Dict[str, Any]]:
"""
Identify high-potential trends and suggest content angles.
Integrates real-time Google Trends data with MarketSignalDetector signals.
"""
self._log_agent_operation("Surfing market trends")
try:
# 1. Get real-time trending searches from Google Trends
realtime_trends = await self.trends_service.get_trending_searches(user_id=self.user_id)
logger.info(f"[{self.__class__.__name__}] Found {len(realtime_trends)} real-time trends")
# 2. Detect internal market signals (competitors, SERP, etc.)
signals = await self.signal_detector.detect_market_signals()
# 3. Analyze real-time trends and convert to signals if actionable
trend_signals = await self._analyze_realtime_trends(realtime_trends)
signals.extend(trend_signals)
if not signals:
logger.info(f"[{self.__class__.__name__}] No active market signals found")
return []
# Filter for actionable trends (High/Critical urgency or High impact)
actionable_trends = [
s for s in signals
if s.urgency_level.value in ['high', 'critical'] or s.impact_score > 0.7
]
logger.info(f"[{self.__class__.__name__}] Found {len(actionable_trends)} actionable trends")
opportunities = []
for trend in actionable_trends:
opp = await self._analyze_opportunity(trend)
if opp:
opportunities.append(opp)
return opportunities
except Exception as e:
logger.error(f"[{self.__class__.__name__}] Trend surfing failed: {e}")
logger.error(f"[{self.__class__.__name__}] Full traceback: {traceback.format_exc()}")
return []
async def _analyze_realtime_trends(self, trends: List[str]) -> List[MarketSignal]:
"""
Analyze raw trend keywords and convert actionable ones to MarketSignals.
Uses pytrends (via GoogleTrendsService) to validate interest.
"""
signals = []
# Limit to top 5 for detailed analysis to avoid rate limits
top_trends = trends[:5]
for trend_kw in top_trends:
try:
# Get detailed data for the keyword
trend_data = await self.trends_service.analyze_trends(
keywords=[trend_kw],
timeframe="now 7-d", # Last 7 days to see immediate trajectory
geo="US" # Default to US for now, could be user-configured
)
# Check if rising
interest_over_time = trend_data.get("interest_over_time", [])
if not interest_over_time:
continue
# Simple logic: is the last point higher than the average?
values = [float(point.get(trend_kw, 0)) for point in interest_over_time if trend_kw in point]
if not values:
continue
avg_interest = sum(values) / len(values)
last_interest = values[-1]
# Calculate impact/urgency
impact_score = min(last_interest / 100.0, 1.0) # Normalized
urgency = UrgencyLevel.MEDIUM
if last_interest > 80:
urgency = UrgencyLevel.CRITICAL
elif last_interest > 50:
urgency = UrgencyLevel.HIGH
# Create Signal
signal = MarketSignal(
signal_id=f"trend_{trend_kw.replace(' ', '_')}_{int(values[-1])}",
signal_type=SignalType.SOCIAL_TREND, # Using SOCIAL_TREND as proxy for general search trend
source="google_trends",
description=f"Surging interest in '{trend_kw}'",
impact_score=impact_score,
urgency_level=urgency,
confidence_score=0.9,
related_topics=[t.get("topic_title", "") for t in trend_data.get("related_topics", {}).get("top", [])[:3]],
suggested_actions=["Create timely content", "Update social media"],
metadata=trend_data
)
signals.append(signal)
except Exception as e:
logger.warning(f"[{self.__class__.__name__}] Failed to analyze trend '{trend_kw}': {e}")
continue
return signals
async def _analyze_opportunity(self, trend: MarketSignal) -> Optional[Dict[str, Any]]:
"""
Analyze a specific trend signal to generate a content opportunity.
"""
try:
# Use semantic search to find if we already have content covering this
query = f"{trend.description} {' '.join(trend.related_topics)}"
existing_content = await self.intelligence.search(query, limit=3)
coverage_score = 0.0
if existing_content:
# If top result has high score, we might already cover it
coverage_score = existing_content[0].get('score', 0.0)
# If already well-covered, might skip or suggest update
if coverage_score > 0.8:
recommendation = "Update existing content"
else:
recommendation = "Create new content"
return {
"trend_id": trend.signal_id,
"topic": trend.description,
"source": trend.source,
"urgency": trend.urgency_level.value,
"impact_score": trend.impact_score,
"current_coverage": coverage_score,
"recommendation": recommendation,
"suggested_angle": f"Leverage {trend.source} trend on {trend.related_topics[0] if trend.related_topics else 'topic'}",
"detected_at": trend.detected_at
}
except Exception as e:
logger.warning(f"[{self.__class__.__name__}] Failed to analyze opportunity for signal {trend.signal_id}: {e}")
return None