Alwrity version 0.5.4

This commit is contained in:
ajaysi
2025-08-11 10:54:50 +05:30
parent 13ca78f653
commit 39b96c44da
44 changed files with 10448 additions and 2119 deletions

View File

@@ -0,0 +1,8 @@
"""
Content Strategy API Module
Modular API endpoints for content strategy functionality.
"""
from .routes import router
__all__ = ["router"]

View File

@@ -0,0 +1,13 @@
"""
Strategy Endpoints Module
CRUD, analytics, utility, streaming, autofill, and AI generation endpoints for content strategies.
"""
from .strategy_crud import router as crud_router
from .analytics_endpoints import router as analytics_router
from .utility_endpoints import router as utility_router
from .streaming_endpoints import router as streaming_router
from .autofill_endpoints import router as autofill_router
from .ai_generation_endpoints import router as ai_generation_router
__all__ = ["crud_router", "analytics_router", "utility_router", "streaming_router", "autofill_router", "ai_generation_router"]

View File

@@ -0,0 +1,995 @@
"""
AI Generation Endpoints
Handles AI-powered strategy generation endpoints.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from loguru import logger
from datetime import datetime
from fastapi.responses import StreamingResponse
import json
# Import database
from services.database import get_db_session
# Import services
from ....services.content_strategy.ai_generation import AIStrategyGenerator, StrategyGenerationConfig
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["AI Strategy Generation"])
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
@router.post("/generate-comprehensive-strategy")
async def generate_comprehensive_strategy(
user_id: int,
strategy_name: Optional[str] = None,
config: Optional[Dict[str, Any]] = None,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Generate a comprehensive AI-powered content strategy."""
try:
logger.info(f"🚀 Generating comprehensive AI strategy for user: {user_id}")
# Get user context and onboarding data
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# Get onboarding data for context
onboarding_data = await enhanced_service._get_onboarding_data(user_id)
# Build context for AI generation
context = {
"onboarding_data": onboarding_data,
"user_id": user_id,
"generation_config": config or {}
}
# Create strategy generation config
generation_config = StrategyGenerationConfig(
include_competitive_analysis=config.get("include_competitive_analysis", True) if config else True,
include_content_calendar=config.get("include_content_calendar", True) if config else True,
include_performance_predictions=config.get("include_performance_predictions", True) if config else True,
include_implementation_roadmap=config.get("include_implementation_roadmap", True) if config else True,
include_risk_assessment=config.get("include_risk_assessment", True) if config else True,
max_content_pieces=config.get("max_content_pieces", 50) if config else 50,
timeline_months=config.get("timeline_months", 12) if config else 12
)
# Initialize AI strategy generator
strategy_generator = AIStrategyGenerator(generation_config)
# Generate comprehensive strategy
comprehensive_strategy = await strategy_generator.generate_comprehensive_strategy(
user_id=user_id,
context=context,
strategy_name=strategy_name
)
logger.info(f"✅ Comprehensive AI strategy generated successfully for user: {user_id}")
return ResponseBuilder.create_success_response(
message="Comprehensive AI strategy generated successfully",
data=comprehensive_strategy
)
except RuntimeError as e:
logger.error(f"❌ AI service error generating comprehensive strategy: {str(e)}")
raise HTTPException(
status_code=503,
detail=f"AI service temporarily unavailable: {str(e)}"
)
except Exception as e:
logger.error(f"❌ Error generating comprehensive strategy: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "generate_comprehensive_strategy")
@router.post("/generate-strategy-component")
async def generate_strategy_component(
user_id: int,
component_type: str,
base_strategy: Optional[Dict[str, Any]] = None,
context: Optional[Dict[str, Any]] = None,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Generate a specific strategy component using AI."""
try:
logger.info(f"🚀 Generating strategy component '{component_type}' for user: {user_id}")
# Validate component type
valid_components = [
"strategic_insights",
"competitive_analysis",
"content_calendar",
"performance_predictions",
"implementation_roadmap",
"risk_assessment"
]
if component_type not in valid_components:
raise HTTPException(
status_code=400,
detail=f"Invalid component type. Must be one of: {valid_components}"
)
# Get context if not provided
if not context:
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
onboarding_data = await enhanced_service._get_onboarding_data(user_id)
context = {"onboarding_data": onboarding_data, "user_id": user_id}
# Get base strategy if not provided
if not base_strategy:
# Generate base strategy using autofill
from ....services.content_strategy.autofill.ai_structured_autofill import AIStructuredAutofillService
autofill_service = AIStructuredAutofillService()
autofill_result = await autofill_service.generate_autofill_fields(user_id, context)
base_strategy = autofill_result.get("fields", {})
# Initialize AI strategy generator
strategy_generator = AIStrategyGenerator()
# Generate specific component
if component_type == "strategic_insights":
component = await strategy_generator._generate_strategic_insights(base_strategy, context)
elif component_type == "competitive_analysis":
component = await strategy_generator._generate_competitive_analysis(base_strategy, context)
elif component_type == "content_calendar":
component = await strategy_generator._generate_content_calendar(base_strategy, context)
elif component_type == "performance_predictions":
component = await strategy_generator._generate_performance_predictions(base_strategy, context)
elif component_type == "implementation_roadmap":
component = await strategy_generator._generate_implementation_roadmap(base_strategy, context)
elif component_type == "risk_assessment":
component = await strategy_generator._generate_risk_assessment(base_strategy, context)
logger.info(f"✅ Strategy component '{component_type}' generated successfully for user: {user_id}")
return ResponseBuilder.create_success_response(
message=f"Strategy component '{component_type}' generated successfully",
data={
"component_type": component_type,
"component_data": component,
"generated_at": datetime.utcnow().isoformat(),
"user_id": user_id
}
)
except RuntimeError as e:
logger.error(f"❌ AI service error generating strategy component: {str(e)}")
raise HTTPException(
status_code=503,
detail=f"AI service temporarily unavailable for {component_type}: {str(e)}"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Error generating strategy component: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "generate_strategy_component")
@router.get("/strategy-generation-status")
async def get_strategy_generation_status(
user_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get the status of strategy generation for a user."""
try:
logger.info(f"Getting strategy generation status for user: {user_id}")
# Get user's strategies
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, None, db)
# Analyze generation status
strategies = strategies_data.get("strategies", [])
status_data = {
"user_id": user_id,
"total_strategies": len(strategies),
"ai_generated_strategies": len([s for s in strategies if s.get("ai_generated", False)]),
"last_generation": None,
"generation_stats": {
"comprehensive_strategies": 0,
"partial_strategies": 0,
"manual_strategies": 0
}
}
if strategies:
# Find most recent AI-generated strategy
ai_strategies = [s for s in strategies if s.get("ai_generated", False)]
if ai_strategies:
latest_ai = max(ai_strategies, key=lambda x: x.get("created_at", ""))
status_data["last_generation"] = latest_ai.get("created_at")
# Categorize strategies
for strategy in strategies:
if strategy.get("ai_generated", False):
if strategy.get("comprehensive", False):
status_data["generation_stats"]["comprehensive_strategies"] += 1
else:
status_data["generation_stats"]["partial_strategies"] += 1
else:
status_data["generation_stats"]["manual_strategies"] += 1
logger.info(f"✅ Strategy generation status retrieved for user: {user_id}")
return ResponseBuilder.create_success_response(
message="Strategy generation status retrieved successfully",
data=status_data
)
except Exception as e:
logger.error(f"❌ Error getting strategy generation status: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "get_strategy_generation_status")
@router.post("/optimize-existing-strategy")
async def optimize_existing_strategy(
strategy_id: int,
optimization_type: str = "comprehensive",
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Optimize an existing strategy using AI."""
try:
logger.info(f"🚀 Optimizing existing strategy {strategy_id} with type: {optimization_type}")
# Get existing strategy
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
strategies_data = await enhanced_service.get_enhanced_strategies(strategy_id=strategy_id, db=db)
if strategies_data.get("status") == "not_found" or not strategies_data.get("strategies"):
raise HTTPException(
status_code=404,
detail=f"Strategy with ID {strategy_id} not found"
)
existing_strategy = strategies_data["strategies"][0]
user_id = existing_strategy.get("user_id")
# Get user context
onboarding_data = await enhanced_service._get_onboarding_data(user_id)
context = {"onboarding_data": onboarding_data, "user_id": user_id}
# Initialize AI strategy generator
strategy_generator = AIStrategyGenerator()
# Generate optimization based on type
if optimization_type == "comprehensive":
# Generate comprehensive optimization
optimized_strategy = await strategy_generator.generate_comprehensive_strategy(
user_id=user_id,
context=context,
strategy_name=f"Optimized: {existing_strategy.get('name', 'Strategy')}"
)
else:
# Generate specific component optimization
component = await strategy_generator._generate_strategic_insights(existing_strategy, context)
optimized_strategy = {
"optimization_type": optimization_type,
"original_strategy": existing_strategy,
"optimization_data": component,
"optimized_at": datetime.utcnow().isoformat()
}
logger.info(f"✅ Strategy {strategy_id} optimized successfully")
return ResponseBuilder.create_success_response(
message="Strategy optimized successfully",
data=optimized_strategy
)
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Error optimizing strategy: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "optimize_existing_strategy")
@router.get("/generate-comprehensive-strategy/stream")
async def generate_comprehensive_strategy_stream(
user_id: int,
strategy_name: Optional[str] = None,
config: Optional[Dict[str, Any]] = None,
db: Session = Depends(get_db)
):
"""Generate comprehensive AI strategy with Server-Sent Events for progress updates."""
try:
logger.info(f"🚀 Starting streaming AI strategy generation for user: {user_id}")
async def generate_strategy_stream():
try:
# Step 1: Get user context with educational content
yield f"data: {json.dumps({
'step': 1,
'message': 'Getting user context...',
'progress': 10,
'educational_content': {
'title': '🔍 Analyzing Your Data',
'description': 'We\'re gathering all your onboarding information to create a personalized strategy.',
'details': [
'📊 Website analysis data',
'🎯 Research preferences',
'🔑 API configurations',
'📈 Historical performance metrics'
],
'insight': 'Your data helps us understand your business context, target audience, and competitive landscape.',
'ai_prompt_preview': 'Analyzing user onboarding data to extract business context, audience insights, and competitive positioning...'
}
})}\n\n"
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
onboarding_data = await enhanced_service._get_onboarding_data(user_id)
context = {
"onboarding_data": onboarding_data,
"user_id": user_id,
"generation_config": config or {}
}
# Step 2: Generate base strategy fields
yield f"data: {json.dumps({
'step': 2,
'message': 'Generating base strategy fields...',
'progress': 20,
'educational_content': {
'title': '🏗️ Building Foundation',
'description': 'Creating the core strategy framework based on your business objectives.',
'details': [
'🎯 Business objectives mapping',
'📊 Target metrics definition',
'💰 Budget allocation strategy',
'⏰ Timeline planning'
],
'insight': 'A solid foundation ensures your content strategy aligns with business goals and resources.',
'ai_prompt_preview': 'Generating strategic foundation: business objectives, target metrics, budget allocation, and timeline planning...'
}
})}\n\n"
# Initialize AI strategy generator
from ....services.content_strategy.ai_generation import AIStrategyGenerator
strategy_generator = AIStrategyGenerator()
# Step 3: Generate strategic insights with real-time educational content
yield f"data: {json.dumps({
'step': 3,
'message': 'Generating strategic insights...',
'progress': 30,
'educational_content': {
'title': '🧠 Strategic Intelligence Analysis',
'description': 'AI is analyzing your market position and identifying strategic opportunities.',
'details': [
'🎯 Market positioning analysis',
'💡 Opportunity identification',
'📈 Growth potential assessment',
'🎪 Competitive advantage mapping'
],
'insight': 'Strategic insights help you understand where you stand in the market and how to differentiate.',
'ai_prompt_preview': 'Analyzing market position, identifying strategic opportunities, assessing growth potential, and mapping competitive advantages...',
'estimated_time': '15-20 seconds'
}
})}\n\n"
try:
# Create a custom AI service manager that emits educational content to SSE
from services.ai_service_manager import AIServiceManager, AIServiceType
class SSEAIServiceManager(AIServiceManager):
def __init__(self, sse_yield_func):
super().__init__()
self.sse_yield = sse_yield_func
async def _emit_educational_content(self, service_type: AIServiceType, status: str, error_message: str = None, processing_time: float = None):
"""Override to emit educational content to SSE stream."""
try:
educational_content = self._get_educational_content(service_type, status, error_message, processing_time)
# Emit to SSE stream
yield_data = {
'type': 'educational_content',
'service_type': service_type.value,
'status': status,
'educational_content': educational_content
}
if processing_time:
yield_data['processing_time'] = processing_time
if error_message:
yield_data['error_message'] = error_message
await self.sse_yield(f"data: {json.dumps(yield_data)}\n\n")
logger.info(f"📚 Emitted educational content for {service_type.value}: {status}")
except Exception as e:
logger.error(f"Error emitting educational content to SSE: {e}")
# Use the SSE-enabled AI service manager
sse_ai_manager = SSEAIServiceManager(lambda data: generate_strategy_stream().__anext__())
# Generate strategic insights with educational content
strategic_insights = await strategy_generator._generate_strategic_insights({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 3,
'message': 'Strategic insights generated successfully',
'progress': 35,
'success': True,
'educational_content': {
'title': '✅ Strategic Insights Complete',
'description': 'Successfully identified key strategic opportunities and market positioning.',
'achievement': f'Generated {len(strategic_insights.get("insights", []))} strategic insights',
'next_step': 'Moving to competitive analysis...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 3,
'message': f'Strategic insights generation failed: {str(e)}',
'progress': 35,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Strategic Insights Issue',
'description': 'We encountered an issue with strategic analysis, but continuing with other components.',
'fallback': 'Will use industry best practices for strategic positioning.'
}
})}\n\n"
strategic_insights = {}
# Step 4: Generate competitive analysis with educational content
yield f"data: {json.dumps({
'step': 4,
'message': 'Generating competitive analysis...',
'progress': 40,
'educational_content': {
'title': '🔍 Competitive Intelligence Analysis',
'description': 'AI is analyzing your competitors to identify gaps and opportunities.',
'details': [
'🏢 Competitor content strategies',
'📊 Market gap analysis',
'🎯 Differentiation opportunities',
'📈 Industry trend analysis'
],
'insight': 'Understanding your competitors helps you find unique angles and underserved market segments.',
'ai_prompt_preview': 'Analyzing competitor content strategies, identifying market gaps, finding differentiation opportunities, and assessing industry trends...',
'estimated_time': '20-25 seconds'
}
})}\n\n"
try:
competitive_analysis = await strategy_generator._generate_competitive_analysis({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 4,
'message': 'Competitive analysis generated successfully',
'progress': 45,
'success': True,
'educational_content': {
'title': '✅ Competitive Analysis Complete',
'description': 'Successfully analyzed competitive landscape and identified market opportunities.',
'achievement': f'Analyzed {len(competitive_analysis.get("competitors", []))} competitors',
'next_step': 'Moving to content calendar generation...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 4,
'message': f'Competitive analysis generation failed: {str(e)}',
'progress': 45,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Competitive Analysis Issue',
'description': 'We encountered an issue with competitive analysis, but continuing with other components.',
'fallback': 'Will use industry best practices for competitive positioning.'
}
})}\n\n"
competitive_analysis = {}
# Step 5: Generate content calendar with educational content
yield f"data: {json.dumps({
'step': 5,
'message': 'Generating content calendar...',
'progress': 50,
'educational_content': {
'title': '📅 Content Calendar Creation',
'description': 'AI is building a comprehensive content schedule optimized for your audience.',
'details': [
'📝 Content piece generation',
'📅 Optimal publishing schedule',
'🎯 Audience engagement timing',
'🔄 Content repurposing strategy'
],
'insight': 'A well-planned content calendar ensures consistent engagement and maximizes content ROI.',
'ai_prompt_preview': 'Generating content pieces, optimizing publishing schedule, determining audience engagement timing, and planning content repurposing...',
'estimated_time': '25-30 seconds'
}
})}\n\n"
try:
content_calendar = await strategy_generator._generate_content_calendar({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 5,
'message': 'Content calendar generated successfully',
'progress': 55,
'success': True,
'educational_content': {
'title': '✅ Content Calendar Complete',
'description': 'Successfully created comprehensive content schedule.',
'achievement': f'Generated {len(content_calendar.get("content_pieces", []))} content pieces',
'next_step': 'Moving to performance predictions...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 5,
'message': f'Content calendar generation failed: {str(e)}',
'progress': 55,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Content Calendar Issue',
'description': 'We encountered an issue with content calendar generation, but continuing with other components.',
'fallback': 'Will use industry best practices for content scheduling.'
}
})}\n\n"
content_calendar = {}
# Step 6: Generate performance predictions with educational content
yield f"data: {json.dumps({
'step': 6,
'message': 'Generating performance predictions...',
'progress': 60,
'educational_content': {
'title': '📊 Performance Forecasting',
'description': 'AI is predicting content performance and ROI based on industry data.',
'details': [
'📈 Traffic growth projections',
'💰 ROI predictions',
'🎯 Conversion rate estimates',
'📊 Engagement metrics forecasting'
],
'insight': 'Performance predictions help you set realistic expectations and optimize resource allocation.',
'ai_prompt_preview': 'Analyzing industry benchmarks, predicting traffic growth, estimating ROI, forecasting conversion rates, and projecting engagement metrics...',
'estimated_time': '15-20 seconds'
}
})}\n\n"
try:
performance_predictions = await strategy_generator._generate_performance_predictions({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 6,
'message': 'Performance predictions generated successfully',
'progress': 65,
'success': True,
'educational_content': {
'title': '✅ Performance Predictions Complete',
'description': 'Successfully predicted content performance and ROI.',
'achievement': f'Predicted {performance_predictions.get("estimated_roi", "15-25%")} ROI',
'next_step': 'Moving to implementation roadmap...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 6,
'message': f'Performance predictions generation failed: {str(e)}',
'progress': 65,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Performance Predictions Issue',
'description': 'We encountered an issue with performance predictions, but continuing with other components.',
'fallback': 'Will use industry benchmarks for performance estimates.'
}
})}\n\n"
performance_predictions = {}
# Step 7: Generate implementation roadmap with educational content
yield f"data: {json.dumps({
'step': 7,
'message': 'Generating implementation roadmap...',
'progress': 70,
'educational_content': {
'title': '🗺️ Implementation Roadmap',
'description': 'AI is creating a detailed implementation plan for your content strategy.',
'details': [
'📋 Task breakdown and timeline',
'👥 Resource allocation planning',
'🎯 Milestone definition',
'📊 Success metric tracking'
],
'insight': 'A clear implementation roadmap ensures successful strategy execution and measurable results.',
'ai_prompt_preview': 'Creating implementation roadmap: task breakdown, resource allocation, milestone planning, and success metric definition...',
'estimated_time': '15-20 seconds'
}
})}\n\n"
try:
implementation_roadmap = await strategy_generator._generate_implementation_roadmap({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 7,
'message': 'Implementation roadmap generated successfully',
'progress': 75,
'success': True,
'educational_content': {
'title': '✅ Implementation Roadmap Complete',
'description': 'Successfully created detailed implementation plan.',
'achievement': f'Planned {implementation_roadmap.get("total_duration", "12 months")} implementation timeline',
'next_step': 'Moving to risk assessment...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 7,
'message': f'Implementation roadmap generation failed: {str(e)}',
'progress': 75,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Implementation Roadmap Issue',
'description': 'We encountered an issue with implementation roadmap generation, but continuing with other components.',
'fallback': 'Will use industry best practices for implementation planning.'
}
})}\n\n"
implementation_roadmap = {}
# Step 8: Generate risk assessment with educational content
yield f"data: {json.dumps({
'step': 8,
'message': 'Generating risk assessment...',
'progress': 80,
'educational_content': {
'title': '⚠️ Risk Assessment',
'description': 'AI is identifying potential risks and mitigation strategies for your content strategy.',
'details': [
'🔍 Risk identification and analysis',
'📊 Risk probability assessment',
'🛡️ Mitigation strategy development',
'📈 Risk monitoring framework'
],
'insight': 'Proactive risk assessment helps you prepare for challenges and maintain strategy effectiveness.',
'ai_prompt_preview': 'Assessing risks: identifying potential challenges, analyzing probability and impact, developing mitigation strategies, and creating monitoring framework...',
'estimated_time': '10-15 seconds'
}
})}\n\n"
try:
risk_assessment = await strategy_generator._generate_risk_assessment({}, context, sse_ai_manager)
yield f"data: {json.dumps({
'step': 8,
'message': 'Risk assessment generated successfully',
'progress': 85,
'success': True,
'educational_content': {
'title': '✅ Risk Assessment Complete',
'description': 'Successfully identified risks and mitigation strategies.',
'achievement': f'Assessed {risk_assessment.get("overall_risk_level", "Medium")} risk level',
'next_step': 'Finalizing comprehensive strategy...'
}
})}\n\n"
except Exception as e:
yield f"data: {json.dumps({
'step': 8,
'message': f'Risk assessment generation failed: {str(e)}',
'progress': 85,
'success': False,
'error': str(e),
'educational_content': {
'title': '⚠️ Risk Assessment Issue',
'description': 'We encountered an issue with risk assessment, but continuing with strategy finalization.',
'fallback': 'Will use industry best practices for risk management.'
}
})}\n\n"
risk_assessment = {}
# Step 9: Compile comprehensive strategy
yield f"data: {json.dumps({
'step': 9,
'message': 'Compiling comprehensive strategy...',
'progress': 90,
'educational_content': {
'title': '📋 Strategy Compilation',
'description': 'AI is compiling all components into a comprehensive content strategy.',
'details': [
'🔗 Component integration',
'📊 Data synthesis',
'📝 Strategy documentation',
'✅ Quality validation'
],
'insight': 'A comprehensive strategy integrates all components into a cohesive, actionable plan.',
'ai_prompt_preview': 'Compiling comprehensive strategy: integrating all components, synthesizing data, documenting strategy, and validating quality...',
'estimated_time': '5-10 seconds'
}
})}\n\n"
# Compile the comprehensive strategy
comprehensive_strategy = {
"strategic_insights": strategic_insights,
"competitive_analysis": competitive_analysis,
"content_calendar": content_calendar,
"performance_predictions": performance_predictions,
"implementation_roadmap": implementation_roadmap,
"risk_assessment": risk_assessment,
"metadata": {
"ai_generated": True,
"comprehensive": True,
"generation_timestamp": datetime.utcnow().isoformat(),
"user_id": user_id,
"strategy_name": strategy_name or "Enhanced Content Strategy"
}
}
# Step 10: Complete with educational content
yield f"data: {json.dumps({
'step': 10,
'message': 'Strategy generation completed successfully!',
'progress': 100,
'success': True,
'strategy': comprehensive_strategy,
'educational_content': {
'title': '🎉 Strategy Generation Complete!',
'description': 'Your comprehensive AI-powered content strategy is ready!',
'summary': {
'total_components': 6,
'successful_components': sum([
1 if strategic_insights else 0,
1 if competitive_analysis else 0,
1 if content_calendar else 0,
1 if performance_predictions else 0,
1 if implementation_roadmap else 0,
1 if risk_assessment else 0
]),
'total_content_pieces': len(content_calendar.get("content_pieces", [])),
'estimated_roi': performance_predictions.get("estimated_roi", "15-25%"),
'implementation_timeline': implementation_roadmap.get("total_duration", "12 months"),
'risk_level': risk_assessment.get("overall_risk_level", "Medium")
},
'key_achievements': [
'🧠 Strategic insights generated',
'🔍 Competitive analysis completed',
'📅 Content calendar created',
'📊 Performance predictions calculated',
'🗺️ Implementation roadmap planned',
'⚠️ Risk assessment conducted'
],
'next_steps': [
'Review your comprehensive strategy',
'Customize specific components as needed',
'Share with your team for feedback',
'Begin implementation following the roadmap'
],
'ai_insights': 'Your strategy leverages advanced AI analysis of your business context, competitive landscape, and industry best practices to create a data-driven content approach.',
'personalization_note': 'This strategy is uniquely tailored to your business based on your onboarding data, ensuring relevance and effectiveness.'
}
})}\n\n"
except Exception as e:
logger.error(f"❌ Error in streaming strategy generation: {str(e)}")
yield f"data: {json.dumps({'error': f'Strategy generation failed: {str(e)}', 'progress': 0, 'success': False})}\n\n"
return StreamingResponse(
generate_strategy_stream(),
media_type="text/plain",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Cache-Control"
}
)
except Exception as e:
logger.error(f"❌ Error starting streaming strategy generation: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to start streaming strategy generation: {str(e)}"
)
@router.get("/ai-generation-education")
async def get_ai_generation_education() -> Dict[str, Any]:
"""Get educational content about the AI generation process."""
try:
logger.info("📚 Providing AI generation educational content")
educational_content = {
"title": "🤖 AI-Powered Strategy Generation",
"subtitle": "Understanding How We Create Your Content Strategy",
"overview": {
"description": "Our AI system analyzes your business data and generates a comprehensive content strategy using advanced machine learning and industry best practices.",
"total_time": "2-3 minutes",
"components": 6,
"ai_model": "Google Gemini Pro",
"personalization_level": "High"
},
"process_steps": [
{
"step": 1,
"title": "🔍 Data Analysis",
"description": "Analyzing your onboarding data to understand your business context",
"duration": "5-10 seconds",
"details": [
"Website analysis data processing",
"Research preferences analysis",
"API configuration review",
"Historical performance assessment"
],
"ai_prompt_example": "Analyze user onboarding data to extract business context, audience insights, and competitive positioning..."
},
{
"step": 2,
"title": "🏗️ Foundation Building",
"description": "Creating the core strategy framework based on your objectives",
"duration": "5-10 seconds",
"details": [
"Business objectives mapping",
"Target metrics definition",
"Budget allocation strategy",
"Timeline planning"
],
"ai_prompt_example": "Generate strategic foundation: business objectives, target metrics, budget allocation, and timeline planning..."
},
{
"step": 3,
"title": "🧠 Strategic Intelligence",
"description": "AI analyzes your market position and identifies opportunities",
"duration": "15-20 seconds",
"details": [
"Market positioning analysis",
"Opportunity identification",
"Growth potential assessment",
"Competitive advantage mapping"
],
"ai_prompt_example": "Analyze market position, identify strategic opportunities, assess growth potential, and map competitive advantages..."
},
{
"step": 4,
"title": "🔍 Competitive Intelligence",
"description": "Analyzing competitors to identify gaps and opportunities",
"duration": "20-25 seconds",
"details": [
"Competitor content strategies",
"Market gap analysis",
"Differentiation opportunities",
"Industry trend analysis"
],
"ai_prompt_example": "Analyze competitor content strategies, identify market gaps, find differentiation opportunities, and assess industry trends..."
},
{
"step": 5,
"title": "📅 Content Calendar Creation",
"description": "Building a comprehensive content schedule optimized for your audience",
"duration": "25-30 seconds",
"details": [
"Content piece generation",
"Optimal publishing schedule",
"Audience engagement timing",
"Content repurposing strategy"
],
"ai_prompt_example": "Generate content pieces, optimize publishing schedule, determine audience engagement timing, and plan content repurposing..."
},
{
"step": 6,
"title": "📊 Performance Forecasting",
"description": "Predicting content performance and ROI based on industry data",
"duration": "15-20 seconds",
"details": [
"Traffic growth projections",
"ROI predictions",
"Conversion rate estimates",
"Engagement metrics forecasting"
],
"ai_prompt_example": "Analyze industry benchmarks, predict traffic growth, estimate ROI, forecast conversion rates, and project engagement metrics..."
},
{
"step": 7,
"title": "🗺️ Implementation Roadmap",
"description": "Creating a step-by-step plan to execute your strategy",
"duration": "15-20 seconds",
"details": [
"Phase-by-phase breakdown",
"Timeline with milestones",
"Resource allocation",
"Success checkpoints"
],
"ai_prompt_example": "Create phase-by-phase breakdown, establish timeline with milestones, allocate resources, and set success checkpoints..."
},
{
"step": 8,
"title": "⚠️ Risk Assessment",
"description": "Identifying potential challenges and creating mitigation strategies",
"duration": "10-15 seconds",
"details": [
"Risk identification",
"Risk probability analysis",
"Mitigation strategies",
"Contingency planning"
],
"ai_prompt_example": "Identify potential risks, analyze risk probabilities, develop mitigation strategies, and create contingency plans..."
}
],
"ai_technology": {
"model": "Google Gemini Pro",
"capabilities": [
"Advanced natural language processing",
"Context-aware analysis",
"Industry knowledge integration",
"Personalized recommendations"
],
"data_sources": [
"Your onboarding data",
"Industry benchmarks",
"Best practices database",
"Market research insights"
]
},
"personalization_features": {
"data_points_used": [
"Business objectives and goals",
"Target audience demographics",
"Industry and market context",
"Competitive landscape",
"Content preferences and style",
"Budget and resource constraints"
],
"customization_level": "High",
"adaptation_factors": [
"Industry-specific insights",
"Audience behavior patterns",
"Competitive positioning",
"Resource availability"
]
},
"quality_assurance": {
"validation_steps": [
"Data completeness check",
"Strategy coherence validation",
"Industry alignment verification",
"Implementation feasibility assessment"
],
"fallback_mechanisms": [
"Industry best practices",
"Standard templates",
"Benchmark data",
"Expert recommendations"
]
},
"tips_for_users": [
"💡 The more detailed your onboarding data, the more personalized your strategy will be",
"📊 Review and customize the generated strategy to match your specific needs",
"🔄 Use the strategy as a starting point and iterate based on performance",
"📈 Monitor results and adjust the strategy as your business evolves",
"👥 Share the strategy with your team for feedback and buy-in"
],
"technical_details": {
"processing_time": "2-3 minutes total",
"ai_calls": "8 specialized AI analyses",
"data_processing": "Real-time onboarding data integration",
"output_format": "Structured JSON with comprehensive strategy components",
"scalability": "Handles multiple concurrent generations"
}
}
return ResponseBuilder.create_success_response(
message="AI generation educational content retrieved successfully",
data=educational_content
)
except Exception as e:
logger.error(f"❌ Error getting AI generation education: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "get_ai_generation_education")

View File

@@ -0,0 +1,333 @@
"""
Analytics Endpoints
Handles analytics and AI analysis endpoints for enhanced content strategies.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from loguru import logger
from datetime import datetime
# Import database
from services.database import get_db_session
# Import services
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
# Import models
from models.enhanced_strategy_models import EnhancedContentStrategy, EnhancedAIAnalysisResult
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["Strategy Analytics"])
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
@router.get("/{strategy_id}/analytics")
async def get_enhanced_strategy_analytics(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get analytics data for an enhanced strategy."""
try:
logger.info(f"Getting analytics for strategy: {strategy_id}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Calculate completion statistics
strategy.calculate_completion_percentage()
# Get AI analysis results
ai_analyses = db.query(EnhancedAIAnalysisResult).filter(
EnhancedAIAnalysisResult.strategy_id == strategy_id
).order_by(EnhancedAIAnalysisResult.created_at.desc()).all()
analytics_data = {
"strategy_id": strategy_id,
"completion_percentage": strategy.completion_percentage,
"total_fields": 30,
"completed_fields": len([f for f in strategy.get_field_values() if f is not None and f != ""]),
"ai_analyses_count": len(ai_analyses),
"last_ai_analysis": ai_analyses[0].to_dict() if ai_analyses else None,
"created_at": strategy.created_at.isoformat() if strategy.created_at else None,
"updated_at": strategy.updated_at.isoformat() if strategy.updated_at else None
}
logger.info(f"Retrieved analytics for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['analytics_retrieved'],
data=analytics_data
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting strategy analytics: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_analytics")
@router.get("/{strategy_id}/ai-analyses")
async def get_enhanced_strategy_ai_analysis(
strategy_id: int,
limit: int = Query(10, description="Number of AI analysis results to return"),
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get AI analysis results for an enhanced strategy."""
try:
logger.info(f"Getting AI analyses for strategy: {strategy_id}, limit: {limit}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Get AI analysis results
ai_analyses = db.query(EnhancedAIAnalysisResult).filter(
EnhancedAIAnalysisResult.strategy_id == strategy_id
).order_by(EnhancedAIAnalysisResult.created_at.desc()).limit(limit).all()
analyses_data = [analysis.to_dict() for analysis in ai_analyses]
logger.info(f"Retrieved {len(analyses_data)} AI analyses for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['ai_analyses_retrieved'],
data={
"strategy_id": strategy_id,
"analyses": analyses_data,
"total_count": len(analyses_data)
}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting AI analyses: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_ai_analysis")
@router.get("/{strategy_id}/completion")
async def get_enhanced_strategy_completion_stats(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get completion statistics for an enhanced strategy."""
try:
logger.info(f"Getting completion stats for strategy: {strategy_id}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Calculate completion statistics
strategy.calculate_completion_percentage()
# Get field values and categorize them
field_values = strategy.get_field_values()
completed_fields = []
incomplete_fields = []
for field_name, value in field_values.items():
if value is not None and value != "":
completed_fields.append(field_name)
else:
incomplete_fields.append(field_name)
completion_stats = {
"strategy_id": strategy_id,
"completion_percentage": strategy.completion_percentage,
"total_fields": 30,
"completed_fields_count": len(completed_fields),
"incomplete_fields_count": len(incomplete_fields),
"completed_fields": completed_fields,
"incomplete_fields": incomplete_fields,
"last_updated": strategy.updated_at.isoformat() if strategy.updated_at else None
}
logger.info(f"Retrieved completion stats for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['completion_stats_retrieved'],
data=completion_stats
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting completion stats: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_completion_stats")
@router.get("/{strategy_id}/onboarding-integration")
async def get_enhanced_strategy_onboarding_integration(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get onboarding integration data for an enhanced strategy."""
try:
logger.info(f"Getting onboarding integration for strategy: {strategy_id}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Get onboarding integration data
onboarding_data = strategy.onboarding_data_used if hasattr(strategy, 'onboarding_data_used') else {}
integration_data = {
"strategy_id": strategy_id,
"onboarding_integration": onboarding_data,
"has_onboarding_data": bool(onboarding_data),
"auto_populated_fields": onboarding_data.get('auto_populated_fields', {}),
"data_sources": onboarding_data.get('data_sources', []),
"integration_id": onboarding_data.get('integration_id')
}
logger.info(f"Retrieved onboarding integration for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['onboarding_integration_retrieved'],
data=integration_data
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting onboarding integration: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_onboarding_integration")
@router.post("/{strategy_id}/ai-recommendations")
async def generate_enhanced_ai_recommendations(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Generate AI recommendations for an enhanced strategy."""
try:
logger.info(f"Generating AI recommendations for strategy: {strategy_id}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Generate AI recommendations
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# This would call the AI service to generate recommendations
# For now, we'll return a placeholder
recommendations = {
"strategy_id": strategy_id,
"recommendations": [
{
"type": "content_optimization",
"title": "Optimize Content Strategy",
"description": "Based on your current strategy, consider focusing on pillar content and topic clusters.",
"priority": "high",
"estimated_impact": "Increase organic traffic by 25%"
}
],
"generated_at": datetime.utcnow().isoformat()
}
logger.info(f"Generated AI recommendations for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['ai_recommendations_generated'],
data=recommendations
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error generating AI recommendations: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "generate_enhanced_ai_recommendations")
@router.post("/{strategy_id}/ai-analysis/regenerate")
async def regenerate_enhanced_strategy_ai_analysis(
strategy_id: int,
analysis_type: str,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Regenerate AI analysis for an enhanced strategy."""
try:
logger.info(f"Regenerating AI analysis for strategy: {strategy_id}, type: {analysis_type}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Regenerate AI analysis
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# This would call the AI service to regenerate analysis
# For now, we'll return a placeholder
analysis_result = {
"strategy_id": strategy_id,
"analysis_type": analysis_type,
"status": "regenerated",
"regenerated_at": datetime.utcnow().isoformat(),
"result": {
"insights": ["New insight 1", "New insight 2"],
"recommendations": ["New recommendation 1", "New recommendation 2"]
}
}
logger.info(f"Regenerated AI analysis for strategy: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['ai_analysis_regenerated'],
data=analysis_result
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error regenerating AI analysis: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "regenerate_enhanced_strategy_ai_analysis")

View File

@@ -0,0 +1,199 @@
"""
Autofill Endpoints
Handles autofill endpoints for enhanced content strategies.
CRITICAL PROTECTION ZONE - These endpoints are essential for autofill functionality.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from loguru import logger
import json
import asyncio
from datetime import datetime
# Import database
from services.database import get_db_session
# Import services
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
from ....services.content_strategy.autofill.ai_refresh import AutoFillRefreshService
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["Strategy Autofill"])
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
async def stream_data(data_generator):
"""Helper function to stream data as Server-Sent Events"""
async for chunk in data_generator:
if isinstance(chunk, dict):
yield f"data: {json.dumps(chunk)}\n\n"
else:
yield f"data: {json.dumps({'message': str(chunk)})}\n\n"
await asyncio.sleep(0.1) # Small delay to prevent overwhelming
@router.post("/{strategy_id}/autofill/accept")
async def accept_autofill_inputs(
strategy_id: int,
payload: Dict[str, Any],
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Persist end-user accepted auto-fill inputs and associate with the strategy."""
try:
logger.info(f"🚀 Accepting autofill inputs for strategy: {strategy_id}")
user_id = int(payload.get('user_id') or 1)
accepted_fields = payload.get('accepted_fields') or {}
# Optional transparency bundles
sources = payload.get('sources') or {}
input_data_points = payload.get('input_data_points') or {}
quality_scores = payload.get('quality_scores') or {}
confidence_levels = payload.get('confidence_levels') or {}
data_freshness = payload.get('data_freshness') or {}
if not accepted_fields:
raise HTTPException(status_code=400, detail="accepted_fields is required")
db_service = EnhancedStrategyDBService(db)
record = await db_service.save_autofill_insights(
strategy_id=strategy_id,
user_id=user_id,
payload={
'accepted_fields': accepted_fields,
'sources': sources,
'input_data_points': input_data_points,
'quality_scores': quality_scores,
'confidence_levels': confidence_levels,
'data_freshness': data_freshness,
}
)
if not record:
raise HTTPException(status_code=500, detail="Failed to persist autofill insights")
return ResponseBuilder.create_success_response(
message="Accepted autofill inputs persisted successfully",
data={
'id': record.id,
'strategy_id': record.strategy_id,
'user_id': record.user_id,
'created_at': record.created_at.isoformat() if getattr(record, 'created_at', None) else None
}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Error accepting autofill inputs: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "accept_autofill_inputs")
@router.get("/autofill/refresh/stream")
async def stream_autofill_refresh(
user_id: Optional[int] = Query(None, description="User ID to build auto-fill for"),
use_ai: bool = Query(True, description="Use AI augmentation during refresh"),
ai_only: bool = Query(False, description="AI-first refresh: return AI overrides when available"),
db: Session = Depends(get_db)
):
"""SSE endpoint to stream steps while generating a fresh auto-fill payload (no DB writes)."""
async def refresh_generator():
try:
actual_user_id = user_id or 1
start_time = datetime.utcnow()
logger.info(f"🚀 Starting auto-fill refresh stream for user: {actual_user_id}")
yield {"type": "status", "phase": "init", "message": "Starting…", "progress": 5}
refresh_service = AutoFillRefreshService(db)
# Phase: Collect onboarding context
yield {"type": "progress", "phase": "context", "message": "Collecting context…", "progress": 15}
# We deliberately do not emit DB-derived values; context is used inside the service
# Phase: Build prompt
yield {"type": "progress", "phase": "prompt", "message": "Preparing prompt…", "progress": 30}
# Phase: AI call - run in background and heartbeat until completion
yield {"type": "progress", "phase": "ai", "message": "Calling AI…", "progress": 45}
import asyncio
ai_task = asyncio.create_task(
refresh_service.build_fresh_payload(actual_user_id, use_ai=use_ai, ai_only=ai_only)
)
# Heartbeat loop while AI is running
heartbeat_progress = 50
while not ai_task.done():
elapsed = (datetime.utcnow() - start_time).total_seconds()
heartbeat_progress = min(heartbeat_progress + 3, 85)
yield {"type": "progress", "phase": "ai_running", "message": f"AI running… {int(elapsed)}s", "progress": heartbeat_progress}
await asyncio.sleep(2)
# Retrieve result or error
final_payload = await ai_task
# Phase: Validate & map
yield {"type": "progress", "phase": "validate", "message": "Validating…", "progress": 92}
# Phase: Transparency
yield {"type": "progress", "phase": "finalize", "message": "Finalizing…", "progress": 96}
total_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000)
meta = final_payload.get('meta') or {}
meta.update({
'sse_total_ms': total_ms,
'sse_started_at': start_time.isoformat()
})
final_payload['meta'] = meta
yield {"type": "result", "status": "success", "data": final_payload, "progress": 100}
logger.info(f"✅ Auto-fill refresh stream completed for user: {actual_user_id} in {total_ms} ms")
except Exception as e:
logger.error(f"❌ Error in auto-fill refresh stream: {str(e)}")
yield {"type": "error", "message": str(e), "timestamp": datetime.utcnow().isoformat()}
return StreamingResponse(
stream_data(refresh_generator()),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Credentials": "true"
}
)
@router.post("/autofill/refresh")
async def refresh_autofill(
user_id: Optional[int] = Query(None, description="User ID to build auto-fill for"),
use_ai: bool = Query(True, description="Use AI augmentation during refresh"),
ai_only: bool = Query(False, description="AI-first refresh: return AI overrides when available"),
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Non-stream endpoint to return a fresh auto-fill payload (no DB writes)."""
try:
actual_user_id = user_id or 1
started = datetime.utcnow()
refresh_service = AutoFillRefreshService(db)
payload = await refresh_service.build_fresh_payload(actual_user_id, use_ai=use_ai, ai_only=ai_only)
total_ms = int((datetime.utcnow() - started).total_seconds() * 1000)
meta = payload.get('meta') or {}
meta.update({'http_total_ms': total_ms, 'http_started_at': started.isoformat()})
payload['meta'] = meta
return ResponseBuilder.create_success_response(
message="Fresh auto-fill payload generated successfully",
data=payload
)
except Exception as e:
logger.error(f"❌ Error generating fresh auto-fill payload: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "refresh_autofill")

View File

@@ -0,0 +1,278 @@
"""
Strategy CRUD Endpoints
Handles CRUD operations for enhanced content strategies.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from loguru import logger
import json
from datetime import datetime
# Import database
from services.database import get_db_session
# Import services
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
# Import models
from models.enhanced_strategy_models import EnhancedContentStrategy
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["Strategy CRUD"])
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
@router.post("/create")
async def create_enhanced_strategy(
strategy_data: Dict[str, Any],
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Create a new enhanced content strategy."""
try:
logger.info(f"Creating enhanced strategy: {strategy_data.get('name', 'Unknown')}")
# Validate required fields
required_fields = ['user_id', 'name']
for field in required_fields:
if field not in strategy_data or not strategy_data[field]:
raise HTTPException(
status_code=400,
detail=f"Missing required field: {field}"
)
# Parse and validate data types
def parse_float(value: Any) -> Optional[float]:
if value is None or value == "":
return None
try:
return float(value)
except (ValueError, TypeError):
return None
def parse_int(value: Any) -> Optional[int]:
if value is None or value == "":
return None
try:
return int(value)
except (ValueError, TypeError):
return None
def parse_json(value: Any) -> Optional[Any]:
if value is None or value == "":
return None
if isinstance(value, str):
try:
return json.loads(value)
except json.JSONDecodeError:
return value
return value
def parse_array(value: Any) -> Optional[list]:
if value is None or value == "":
return []
if isinstance(value, str):
try:
parsed = json.loads(value)
return parsed if isinstance(parsed, list) else [parsed]
except json.JSONDecodeError:
return [value]
elif isinstance(value, list):
return value
else:
return [value]
# Parse numeric fields
numeric_fields = ['content_budget', 'team_size', 'market_share', 'ab_testing_capabilities']
for field in numeric_fields:
if field in strategy_data:
strategy_data[field] = parse_float(strategy_data[field])
# Parse array fields
array_fields = ['content_preferences', 'consumption_patterns', 'audience_pain_points',
'buying_journey', 'seasonal_trends', 'engagement_metrics', 'top_competitors',
'competitor_content_strategies', 'market_gaps', 'industry_trends',
'emerging_trends', 'preferred_formats', 'content_mix', 'content_frequency',
'optimal_timing', 'quality_metrics', 'editorial_guidelines', 'brand_voice',
'traffic_sources', 'conversion_rates', 'content_roi_targets', 'target_audience',
'content_pillars']
for field in array_fields:
if field in strategy_data:
strategy_data[field] = parse_array(strategy_data[field])
# Parse JSON fields
json_fields = ['business_objectives', 'target_metrics', 'performance_metrics',
'competitive_position', 'ai_recommendations']
for field in json_fields:
if field in strategy_data:
strategy_data[field] = parse_json(strategy_data[field])
# Create strategy
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
result = await enhanced_service.create_enhanced_strategy(strategy_data, db)
logger.info(f"Enhanced strategy created successfully: {result.get('strategy_id')}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['strategy_created'],
data=result
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error creating enhanced strategy: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "create_enhanced_strategy")
@router.get("/")
async def get_enhanced_strategies(
user_id: Optional[int] = Query(None, description="User ID to filter strategies"),
strategy_id: Optional[int] = Query(None, description="Specific strategy ID"),
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get enhanced content strategies."""
try:
logger.info(f"Getting enhanced strategies for user: {user_id}, strategy: {strategy_id}")
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, strategy_id, db)
logger.info(f"Retrieved {strategies_data.get('total_count', 0)} strategies")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['strategies_retrieved'],
data=strategies_data
)
except Exception as e:
logger.error(f"Error getting enhanced strategies: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategies")
@router.get("/{strategy_id}")
async def get_enhanced_strategy_by_id(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get a specific enhanced strategy by ID."""
try:
logger.info(f"Getting enhanced strategy by ID: {strategy_id}")
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
strategies_data = await enhanced_service.get_enhanced_strategies(strategy_id=strategy_id, db=db)
if strategies_data.get("status") == "not_found" or not strategies_data.get("strategies"):
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
strategy = strategies_data["strategies"][0]
logger.info(f"Retrieved strategy: {strategy.get('name')}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['strategy_retrieved'],
data=strategy
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting enhanced strategy by ID: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_by_id")
@router.put("/{strategy_id}")
async def update_enhanced_strategy(
strategy_id: int,
update_data: Dict[str, Any],
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Update an enhanced strategy."""
try:
logger.info(f"Updating enhanced strategy: {strategy_id}")
# Check if strategy exists
existing_strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not existing_strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Update strategy fields
for field, value in update_data.items():
if hasattr(existing_strategy, field):
setattr(existing_strategy, field, value)
existing_strategy.updated_at = datetime.utcnow()
# Save to database
db.commit()
db.refresh(existing_strategy)
logger.info(f"Enhanced strategy updated successfully: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['strategy_updated'],
data=existing_strategy.to_dict()
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error updating enhanced strategy: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "update_enhanced_strategy")
@router.delete("/{strategy_id}")
async def delete_enhanced_strategy(
strategy_id: int,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Delete an enhanced strategy."""
try:
logger.info(f"Deleting enhanced strategy: {strategy_id}")
# Check if strategy exists
strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if not strategy:
raise HTTPException(
status_code=404,
detail=f"Enhanced strategy with ID {strategy_id} not found"
)
# Delete strategy
db.delete(strategy)
db.commit()
logger.info(f"Enhanced strategy deleted successfully: {strategy_id}")
return ResponseBuilder.success_response(
message=SUCCESS_MESSAGES['strategy_deleted'],
data={"strategy_id": strategy_id}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error deleting enhanced strategy: {str(e)}")
return ContentPlanningErrorHandler.handle_general_error(e, "delete_enhanced_strategy")

View File

@@ -0,0 +1,357 @@
"""
Streaming Endpoints
Handles streaming endpoints for enhanced content strategies.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from loguru import logger
import json
import asyncio
from datetime import datetime
from collections import defaultdict
import time
# Import database
from services.database import get_db_session
# Import services
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["Strategy Streaming"])
# Cache for streaming endpoints (5 minutes cache)
streaming_cache = defaultdict(dict)
CACHE_DURATION = 300 # 5 minutes
def get_cached_data(cache_key: str) -> Optional[Dict[str, Any]]:
"""Get cached data if it exists and is not expired."""
if cache_key in streaming_cache:
cached_data = streaming_cache[cache_key]
if time.time() - cached_data.get("timestamp", 0) < CACHE_DURATION:
return cached_data.get("data")
return None
def set_cached_data(cache_key: str, data: Dict[str, Any]):
"""Set cached data with timestamp."""
streaming_cache[cache_key] = {
"data": data,
"timestamp": time.time()
}
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
async def stream_data(data_generator):
"""Helper function to stream data as Server-Sent Events"""
async for chunk in data_generator:
if isinstance(chunk, dict):
yield f"data: {json.dumps(chunk)}\n\n"
else:
yield f"data: {json.dumps({'message': str(chunk)})}\n\n"
await asyncio.sleep(0.1) # Small delay to prevent overwhelming
@router.get("/stream/strategies")
async def stream_enhanced_strategies(
user_id: Optional[int] = Query(None, description="User ID to filter strategies"),
strategy_id: Optional[int] = Query(None, description="Specific strategy ID"),
db: Session = Depends(get_db)
):
"""Stream enhanced strategies with real-time updates."""
async def strategy_generator():
try:
logger.info(f"🚀 Starting strategy stream for user: {user_id}, strategy: {strategy_id}")
# Send initial status
yield {"type": "status", "message": "Starting strategy retrieval...", "timestamp": datetime.utcnow().isoformat()}
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# Send progress update
yield {"type": "progress", "message": "Querying database...", "progress": 25}
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, strategy_id, db)
# Send progress update
yield {"type": "progress", "message": "Processing strategies...", "progress": 50}
if strategies_data.get("status") == "not_found":
yield {"type": "result", "status": "not_found", "data": strategies_data}
return
# Send progress update
yield {"type": "progress", "message": "Finalizing data...", "progress": 75}
# Send final result
yield {"type": "result", "status": "success", "data": strategies_data, "progress": 100}
logger.info(f"✅ Strategy stream completed for user: {user_id}")
except Exception as e:
logger.error(f"❌ Error in strategy stream: {str(e)}")
yield {"type": "error", "message": str(e), "timestamp": datetime.utcnow().isoformat()}
return StreamingResponse(
stream_data(strategy_generator()),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Credentials": "true"
}
)
@router.get("/stream/strategic-intelligence")
async def stream_strategic_intelligence(
user_id: Optional[int] = Query(None, description="User ID"),
db: Session = Depends(get_db)
):
"""Stream strategic intelligence data with real-time updates."""
async def intelligence_generator():
try:
logger.info(f"🚀 Starting strategic intelligence stream for user: {user_id}")
# Check cache first
cache_key = f"strategic_intelligence_{user_id}"
cached_data = get_cached_data(cache_key)
if cached_data:
logger.info(f"✅ Returning cached strategic intelligence data for user: {user_id}")
yield {"type": "result", "status": "success", "data": cached_data, "progress": 100}
return
# Send initial status
yield {"type": "status", "message": "Loading strategic intelligence...", "timestamp": datetime.utcnow().isoformat()}
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# Send progress update
yield {"type": "progress", "message": "Retrieving strategies...", "progress": 20}
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, None, db)
# Send progress update
yield {"type": "progress", "message": "Analyzing market positioning...", "progress": 40}
if strategies_data.get("status") == "not_found":
yield {"type": "error", "status": "not_ready", "message": "No strategies found. Complete onboarding and create a strategy before generating intelligence.", "progress": 100}
return
# Extract strategic intelligence from first strategy
strategy = strategies_data.get("strategies", [{}])[0]
# Parse ai_recommendations if it's a JSON string
ai_recommendations = {}
if strategy.get("ai_recommendations"):
try:
if isinstance(strategy["ai_recommendations"], str):
ai_recommendations = json.loads(strategy["ai_recommendations"])
else:
ai_recommendations = strategy["ai_recommendations"]
except (json.JSONDecodeError, TypeError):
ai_recommendations = {}
# Send progress update
yield {"type": "progress", "message": "Processing intelligence data...", "progress": 60}
strategic_intelligence = {
"market_positioning": {
"current_position": strategy.get("competitive_position", "Challenger"),
"target_position": "Market Leader",
"differentiation_factors": [
"AI-powered content optimization",
"Data-driven strategy development",
"Personalized user experience"
]
},
"competitive_analysis": {
"top_competitors": strategy.get("top_competitors", [])[:3] or [
"Competitor A", "Competitor B", "Competitor C"
],
"competitive_advantages": [
"Advanced AI capabilities",
"Comprehensive data integration",
"User-centric design"
],
"market_gaps": strategy.get("market_gaps", []) or [
"AI-driven content personalization",
"Real-time performance optimization",
"Predictive analytics"
]
},
"ai_insights": ai_recommendations.get("strategic_insights", []) or [
"Focus on pillar content strategy",
"Implement topic clustering",
"Optimize for voice search"
],
"opportunities": [
{
"area": "Content Personalization",
"potential_impact": "High",
"implementation_timeline": "3-6 months",
"estimated_roi": "25-40%"
},
{
"area": "AI-Powered Optimization",
"potential_impact": "Medium",
"implementation_timeline": "6-12 months",
"estimated_roi": "15-30%"
}
]
}
# Cache the strategic intelligence data
set_cached_data(cache_key, strategic_intelligence)
# Send progress update
yield {"type": "progress", "message": "Finalizing strategic intelligence...", "progress": 80}
# Send final result
yield {"type": "result", "status": "success", "data": strategic_intelligence, "progress": 100}
logger.info(f"✅ Strategic intelligence stream completed for user: {user_id}")
except Exception as e:
logger.error(f"❌ Error in strategic intelligence stream: {str(e)}")
yield {"type": "error", "message": str(e), "timestamp": datetime.utcnow().isoformat()}
return StreamingResponse(
stream_data(intelligence_generator()),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Credentials": "true"
}
)
@router.get("/stream/keyword-research")
async def stream_keyword_research(
user_id: Optional[int] = Query(None, description="User ID"),
db: Session = Depends(get_db)
):
"""Stream keyword research data with real-time updates."""
async def keyword_generator():
try:
logger.info(f"🚀 Starting keyword research stream for user: {user_id}")
# Check cache first
cache_key = f"keyword_research_{user_id}"
cached_data = get_cached_data(cache_key)
if cached_data:
logger.info(f"✅ Returning cached keyword research data for user: {user_id}")
yield {"type": "result", "status": "success", "data": cached_data, "progress": 100}
return
# Send initial status
yield {"type": "status", "message": "Loading keyword research...", "timestamp": datetime.utcnow().isoformat()}
# Import gap analysis service
from ....services.gap_analysis_service import GapAnalysisService
# Send progress update
yield {"type": "progress", "message": "Retrieving gap analyses...", "progress": 20}
gap_service = GapAnalysisService()
gap_analyses = await gap_service.get_gap_analyses(user_id)
# Send progress update
yield {"type": "progress", "message": "Analyzing keyword opportunities...", "progress": 40}
# Handle case where gap_analyses is 0, None, or empty
if not gap_analyses or gap_analyses == 0 or len(gap_analyses) == 0:
yield {"type": "error", "status": "not_ready", "message": "No keyword research data available. Connect data sources or run analysis first.", "progress": 100}
return
# Extract keyword data from first gap analysis
gap_analysis = gap_analyses[0] if isinstance(gap_analyses, list) else gap_analyses
# Parse analysis_results if it's a JSON string
analysis_results = {}
if gap_analysis.get("analysis_results"):
try:
if isinstance(gap_analysis["analysis_results"], str):
analysis_results = json.loads(gap_analysis["analysis_results"])
else:
analysis_results = gap_analysis["analysis_results"]
except (json.JSONDecodeError, TypeError):
analysis_results = {}
# Send progress update
yield {"type": "progress", "message": "Processing keyword data...", "progress": 60}
keyword_data = {
"trend_analysis": {
"high_volume_keywords": analysis_results.get("opportunities", [])[:3] or [
{"keyword": "AI marketing automation", "volume": "10K-100K", "difficulty": "Medium"},
{"keyword": "content strategy 2024", "volume": "1K-10K", "difficulty": "Low"},
{"keyword": "digital marketing trends", "volume": "10K-100K", "difficulty": "High"}
],
"trending_keywords": [
{"keyword": "AI content generation", "growth": "+45%", "opportunity": "High"},
{"keyword": "voice search optimization", "growth": "+32%", "opportunity": "Medium"},
{"keyword": "video marketing strategy", "growth": "+28%", "opportunity": "High"}
]
},
"intent_analysis": {
"informational": ["how to", "what is", "guide to"],
"navigational": ["company name", "brand name", "website"],
"transactional": ["buy", "purchase", "download", "sign up"]
},
"opportunities": analysis_results.get("opportunities", []) or [
{"keyword": "AI content tools", "search_volume": "5K-10K", "competition": "Low", "cpc": "$2.50"},
{"keyword": "content marketing ROI", "search_volume": "1K-5K", "competition": "Medium", "cpc": "$4.20"},
{"keyword": "social media strategy", "search_volume": "10K-50K", "competition": "High", "cpc": "$3.80"}
]
}
# Cache the keyword data
set_cached_data(cache_key, keyword_data)
# Send progress update
yield {"type": "progress", "message": "Finalizing keyword research...", "progress": 80}
# Send final result
yield {"type": "result", "status": "success", "data": keyword_data, "progress": 100}
logger.info(f"✅ Keyword research stream completed for user: {user_id}")
except Exception as e:
logger.error(f"❌ Error in keyword research stream: {str(e)}")
yield {"type": "error", "message": str(e), "timestamp": datetime.utcnow().isoformat()}
return StreamingResponse(
stream_data(keyword_generator()),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Credentials": "true"
}
)

View File

@@ -0,0 +1,237 @@
"""
Utility Endpoints
Handles utility endpoints for enhanced content strategies.
"""
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from loguru import logger
# Import database
from services.database import get_db_session
# Import services
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
router = APIRouter(tags=["Strategy Utilities"])
# Helper function to get database session
def get_db():
db = get_db_session()
try:
yield db
finally:
db.close()
@router.get("/onboarding-data")
async def get_onboarding_data(
user_id: Optional[int] = Query(None, description="User ID to get onboarding data for"),
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get onboarding data for enhanced strategy auto-population."""
try:
logger.info(f"🚀 Getting onboarding data for user: {user_id}")
db_service = EnhancedStrategyDBService(db)
enhanced_service = EnhancedStrategyService(db_service)
# Ensure we have a valid user_id
actual_user_id = user_id or 1
onboarding_data = await enhanced_service._get_onboarding_data(actual_user_id)
logger.info(f"✅ Onboarding data retrieved successfully for user: {actual_user_id}")
return ResponseBuilder.create_success_response(
message="Onboarding data retrieved successfully",
data=onboarding_data
)
except Exception as e:
logger.error(f"❌ Error getting onboarding data: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "get_onboarding_data")
@router.get("/tooltips")
async def get_enhanced_strategy_tooltips() -> Dict[str, Any]:
"""Get tooltip data for enhanced strategy fields."""
try:
logger.info("🚀 Getting enhanced strategy tooltips")
# Mock tooltip data - in real implementation, this would come from a database
tooltip_data = {
"business_objectives": {
"title": "Business Objectives",
"description": "Define your primary and secondary business goals that content will support.",
"examples": ["Increase brand awareness by 25%", "Generate 100 qualified leads per month"],
"best_practices": ["Be specific and measurable", "Align with overall business strategy"]
},
"target_metrics": {
"title": "Target Metrics",
"description": "Specify the KPIs that will measure content strategy success.",
"examples": ["Traffic growth: 30%", "Engagement rate: 5%", "Conversion rate: 2%"],
"best_practices": ["Set realistic targets", "Track both leading and lagging indicators"]
},
"content_budget": {
"title": "Content Budget",
"description": "Define your allocated budget for content creation and distribution.",
"examples": ["$10,000 per month", "15% of marketing budget"],
"best_practices": ["Include both creation and distribution costs", "Plan for seasonal variations"]
},
"team_size": {
"title": "Team Size",
"description": "Number of team members dedicated to content creation and management.",
"examples": ["3 content creators", "1 content manager", "2 designers"],
"best_practices": ["Consider skill sets and workload", "Plan for growth"]
},
"implementation_timeline": {
"title": "Implementation Timeline",
"description": "Timeline for implementing your content strategy.",
"examples": ["3 months for setup", "6 months for full implementation"],
"best_practices": ["Set realistic milestones", "Allow for iteration"]
},
"market_share": {
"title": "Market Share",
"description": "Your current market share and target market share.",
"examples": ["Current: 5%", "Target: 15%"],
"best_practices": ["Use reliable data sources", "Set achievable targets"]
},
"competitive_position": {
"title": "Competitive Position",
"description": "Your position relative to competitors in the market.",
"examples": ["Market leader", "Challenger", "Niche player"],
"best_practices": ["Be honest about your position", "Identify opportunities"]
},
"performance_metrics": {
"title": "Performance Metrics",
"description": "Key metrics to track content performance.",
"examples": ["Organic traffic", "Engagement rate", "Conversion rate"],
"best_practices": ["Focus on actionable metrics", "Set up proper tracking"]
}
}
logger.info("✅ Enhanced strategy tooltips retrieved successfully")
return ResponseBuilder.create_success_response(
message="Enhanced strategy tooltips retrieved successfully",
data=tooltip_data
)
except Exception as e:
logger.error(f"❌ Error getting enhanced strategy tooltips: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_tooltips")
@router.get("/disclosure-steps")
async def get_enhanced_strategy_disclosure_steps() -> Dict[str, Any]:
"""Get progressive disclosure steps for enhanced strategy."""
try:
logger.info("🚀 Getting enhanced strategy disclosure steps")
# Progressive disclosure steps configuration
disclosure_steps = [
{
"id": "business_context",
"title": "Business Context",
"description": "Define your business objectives and context",
"fields": ["business_objectives", "target_metrics", "content_budget", "team_size", "implementation_timeline", "market_share", "competitive_position", "performance_metrics"],
"is_complete": False,
"is_visible": True,
"dependencies": []
},
{
"id": "audience_intelligence",
"title": "Audience Intelligence",
"description": "Understand your target audience",
"fields": ["content_preferences", "consumption_patterns", "audience_pain_points", "buying_journey", "seasonal_trends", "engagement_metrics"],
"is_complete": False,
"is_visible": False,
"dependencies": ["business_context"]
},
{
"id": "competitive_intelligence",
"title": "Competitive Intelligence",
"description": "Analyze your competitive landscape",
"fields": ["top_competitors", "competitor_content_strategies", "market_gaps", "industry_trends", "emerging_trends"],
"is_complete": False,
"is_visible": False,
"dependencies": ["audience_intelligence"]
},
{
"id": "content_strategy",
"title": "Content Strategy",
"description": "Define your content approach",
"fields": ["preferred_formats", "content_mix", "content_frequency", "optimal_timing", "quality_metrics", "editorial_guidelines", "brand_voice"],
"is_complete": False,
"is_visible": False,
"dependencies": ["competitive_intelligence"]
},
{
"id": "distribution_channels",
"title": "Distribution Channels",
"description": "Plan your content distribution",
"fields": ["traffic_sources", "conversion_rates", "content_roi_targets"],
"is_complete": False,
"is_visible": False,
"dependencies": ["content_strategy"]
},
{
"id": "target_audience",
"title": "Target Audience",
"description": "Define your target audience segments",
"fields": ["target_audience", "content_pillars"],
"is_complete": False,
"is_visible": False,
"dependencies": ["distribution_channels"]
}
]
logger.info("✅ Enhanced strategy disclosure steps retrieved successfully")
return ResponseBuilder.create_success_response(
message="Enhanced strategy disclosure steps retrieved successfully",
data=disclosure_steps
)
except Exception as e:
logger.error(f"❌ Error getting enhanced strategy disclosure steps: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_disclosure_steps")
@router.post("/cache/clear")
async def clear_streaming_cache(
user_id: Optional[int] = Query(None, description="User ID to clear cache for")
):
"""Clear streaming cache for a specific user or all users."""
try:
logger.info(f"🚀 Clearing streaming cache for user: {user_id}")
# Import the cache from the streaming endpoints module
from .streaming_endpoints import streaming_cache
if user_id:
# Clear cache for specific user
cache_keys_to_remove = [
f"strategic_intelligence_{user_id}",
f"keyword_research_{user_id}"
]
for key in cache_keys_to_remove:
if key in streaming_cache:
del streaming_cache[key]
logger.info(f"✅ Cleared cache for key: {key}")
else:
# Clear all cache
streaming_cache.clear()
logger.info("✅ Cleared all streaming cache")
return ResponseBuilder.create_success_response(
message="Streaming cache cleared successfully",
data={"cleared_for_user": user_id}
)
except Exception as e:
logger.error(f"❌ Error clearing streaming cache: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "clear_streaming_cache")

View File

@@ -0,0 +1,7 @@
"""
Strategy Middleware Module
Validation and error handling middleware for content strategies.
"""
# Future middleware modules will be imported here
__all__ = []

View File

@@ -0,0 +1,25 @@
"""
Content Strategy Routes
Main router that includes all content strategy endpoint modules.
"""
from fastapi import APIRouter
# Import endpoint modules
from .endpoints.strategy_crud import router as crud_router
from .endpoints.analytics_endpoints import router as analytics_router
from .endpoints.utility_endpoints import router as utility_router
from .endpoints.streaming_endpoints import router as streaming_router
from .endpoints.autofill_endpoints import router as autofill_router
from .endpoints.ai_generation_endpoints import router as ai_generation_router
# Create main router
router = APIRouter(prefix="/content-strategy", tags=["Content Strategy"])
# Include all endpoint routers
router.include_router(crud_router, prefix="/strategies")
router.include_router(analytics_router, prefix="/strategies")
router.include_router(utility_router, prefix="")
router.include_router(streaming_router, prefix="")
router.include_router(autofill_router, prefix="/strategies")
router.include_router(ai_generation_router, prefix="/ai-generation")

View File

@@ -14,6 +14,9 @@ from .routes import strategies, calendar_events, gap_analysis, ai_analytics, cal
# Import enhanced strategy routes
from .enhanced_strategy_routes import router as enhanced_strategy_router
# Import content strategy routes
from .content_strategy.routes import router as content_strategy_router
# Create main router
router = APIRouter(prefix="/api/content-planning", tags=["content-planning"])
@@ -28,6 +31,9 @@ router.include_router(health_monitoring.router)
# Include enhanced strategy routes with correct prefix
router.include_router(enhanced_strategy_router, prefix="/enhanced-strategies")
# Include content strategy routes
router.include_router(content_strategy_router)
# Add health check endpoint
@router.get("/health")
async def content_planning_health_check():