AI Analysis and Content Strategy fixes. Enhanced Strategy Routes refactoring.
This commit is contained in:
@@ -726,9 +726,10 @@ async def get_latest_generated_strategy(
|
||||
# Fallback: Check in-memory task status
|
||||
if not hasattr(generate_comprehensive_strategy_polling, '_task_status'):
|
||||
logger.warning("⚠️ No task status storage found")
|
||||
return ResponseBuilder.create_not_found_response(
|
||||
return ResponseBuilder.create_success_response(
|
||||
data={"user_id": user_id, "strategy": None},
|
||||
message="No strategy generation tasks found",
|
||||
data={"user_id": user_id, "strategy": None}
|
||||
status_code=200
|
||||
)
|
||||
|
||||
# Debug: Log all task statuses
|
||||
@@ -768,9 +769,10 @@ async def get_latest_generated_strategy(
|
||||
)
|
||||
else:
|
||||
logger.info(f"⚠️ No completed strategies found for user: {user_id}")
|
||||
return ResponseBuilder.create_not_found_response(
|
||||
return ResponseBuilder.create_success_response(
|
||||
data={"user_id": user_id, "strategy": None},
|
||||
message="No completed strategy generation found",
|
||||
data={"user_id": user_id, "strategy": None}
|
||||
status_code=200
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@@ -39,51 +39,34 @@ async def get_enhanced_strategy_analytics(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get analytics data for an enhanced strategy."""
|
||||
"""Get comprehensive analytics for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Getting analytics for strategy: {strategy_id}")
|
||||
logger.info(f"🚀 Getting analytics for enhanced strategy: {strategy_id}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
# Get strategy with analytics
|
||||
strategies_with_analytics = await db_service.get_enhanced_strategies_with_analytics(
|
||||
strategy_id=strategy_id
|
||||
)
|
||||
|
||||
# Calculate completion statistics
|
||||
strategy.calculate_completion_percentage()
|
||||
if not strategies_with_analytics:
|
||||
raise ContentPlanningErrorHandler.handle_not_found_error("Enhanced strategy", strategy_id)
|
||||
|
||||
# Get AI analysis results
|
||||
ai_analyses = db.query(EnhancedAIAnalysisResult).filter(
|
||||
EnhancedAIAnalysisResult.strategy_id == strategy_id
|
||||
).order_by(EnhancedAIAnalysisResult.created_at.desc()).all()
|
||||
strategy_analytics = strategies_with_analytics[0]
|
||||
|
||||
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"✅ Enhanced strategy analytics retrieved successfully: {strategy_id}")
|
||||
|
||||
logger.info(f"Retrieved analytics for strategy: {strategy_id}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['analytics_retrieved'],
|
||||
data=analytics_data
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy analytics retrieved successfully",
|
||||
data=strategy_analytics
|
||||
)
|
||||
|
||||
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")
|
||||
logger.error(f"❌ Error getting enhanced strategy analytics: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_analytics")
|
||||
|
||||
@router.get("/{strategy_id}/ai-analyses")
|
||||
async def get_enhanced_strategy_ai_analysis(
|
||||
@@ -91,43 +74,36 @@ async def get_enhanced_strategy_ai_analysis(
|
||||
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."""
|
||||
"""Get AI analysis history for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Getting AI analyses for strategy: {strategy_id}, limit: {limit}")
|
||||
logger.info(f"🚀 Getting AI analysis for enhanced strategy: {strategy_id}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
|
||||
# Verify strategy exists
|
||||
strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
raise ContentPlanningErrorHandler.handle_not_found_error("Enhanced strategy", strategy_id)
|
||||
|
||||
# Get AI analysis results
|
||||
ai_analyses = db.query(EnhancedAIAnalysisResult).filter(
|
||||
EnhancedAIAnalysisResult.strategy_id == strategy_id
|
||||
).order_by(EnhancedAIAnalysisResult.created_at.desc()).limit(limit).all()
|
||||
# Get AI analysis history
|
||||
ai_analysis_history = await db_service.get_ai_analysis_history(strategy_id, limit)
|
||||
|
||||
analyses_data = [analysis.to_dict() for analysis in ai_analyses]
|
||||
logger.info(f"✅ AI analysis history retrieved successfully: {strategy_id}")
|
||||
|
||||
logger.info(f"Retrieved {len(analyses_data)} AI analyses for strategy: {strategy_id}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['ai_analyses_retrieved'],
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy AI analysis retrieved successfully",
|
||||
data={
|
||||
"strategy_id": strategy_id,
|
||||
"analyses": analyses_data,
|
||||
"total_count": len(analyses_data)
|
||||
"ai_analysis_history": ai_analysis_history,
|
||||
"total_analyses": len(ai_analysis_history)
|
||||
}
|
||||
)
|
||||
|
||||
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")
|
||||
logger.error(f"❌ Error getting enhanced strategy AI analysis: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_ai_analysis")
|
||||
|
||||
@router.get("/{strategy_id}/completion")
|
||||
async def get_enhanced_strategy_completion_stats(
|
||||
@@ -136,99 +112,67 @@ async def get_enhanced_strategy_completion_stats(
|
||||
) -> Dict[str, Any]:
|
||||
"""Get completion statistics for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Getting completion stats for strategy: {strategy_id}")
|
||||
logger.info(f"🚀 Getting completion stats for enhanced strategy: {strategy_id}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
|
||||
# Get strategy
|
||||
strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
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)
|
||||
raise ContentPlanningErrorHandler.handle_not_found_error("Enhanced strategy", strategy_id)
|
||||
|
||||
# Calculate completion stats
|
||||
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,
|
||||
"total_fields": 30, # 30+ strategic inputs
|
||||
"filled_fields": len([f for f in strategy.__dict__.keys() if getattr(strategy, f) is not None]),
|
||||
"missing_fields": 30 - len([f for f in strategy.__dict__.keys() if getattr(strategy, f) is not None]),
|
||||
"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'],
|
||||
logger.info(f"✅ Completion stats retrieved successfully: {strategy_id}")
|
||||
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy completion stats retrieved successfully",
|
||||
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")
|
||||
logger.error(f"❌ Error getting enhanced strategy completion stats: {str(e)}")
|
||||
raise 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."""
|
||||
"""Get onboarding data integration for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Getting onboarding integration for strategy: {strategy_id}")
|
||||
logger.info(f"🚀 Getting onboarding integration for enhanced strategy: {strategy_id}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
onboarding_integration = await db_service.get_onboarding_integration(strategy_id)
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
if not onboarding_integration:
|
||||
return ResponseBuilder.create_success_response(
|
||||
data={"strategy_id": strategy_id, "onboarding_integration": None},
|
||||
message="No onboarding integration found for this strategy",
|
||||
status_code=200
|
||||
)
|
||||
|
||||
# Get onboarding integration data
|
||||
onboarding_data = strategy.onboarding_data_used if hasattr(strategy, 'onboarding_data_used') else {}
|
||||
logger.info(f"✅ Onboarding integration retrieved successfully: {strategy_id}")
|
||||
|
||||
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
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy onboarding integration retrieved successfully",
|
||||
data=onboarding_integration
|
||||
)
|
||||
|
||||
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")
|
||||
logger.error(f"❌ Error getting onboarding integration: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "get_enhanced_strategy_onboarding_integration")
|
||||
|
||||
@router.post("/{strategy_id}/ai-recommendations")
|
||||
async def generate_enhanced_ai_recommendations(
|
||||
@@ -237,50 +181,36 @@ async def generate_enhanced_ai_recommendations(
|
||||
) -> Dict[str, Any]:
|
||||
"""Generate AI recommendations for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Generating AI recommendations for strategy: {strategy_id}")
|
||||
logger.info(f"🚀 Generating AI recommendations for enhanced strategy: {strategy_id}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
# Get strategy
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
raise ContentPlanningErrorHandler.handle_not_found_error("Enhanced strategy", strategy_id)
|
||||
|
||||
# Generate AI recommendations
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
enhanced_service = EnhancedStrategyService(db_service)
|
||||
# Pass user_id for subscription checks
|
||||
user_id = str(strategy.user_id) if hasattr(strategy, 'user_id') else None
|
||||
await enhanced_service._generate_comprehensive_ai_recommendations(strategy, db, user_id=user_id)
|
||||
|
||||
# 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()
|
||||
}
|
||||
# Get updated strategy data
|
||||
updated_strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
|
||||
logger.info(f"Generated AI recommendations for strategy: {strategy_id}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['ai_recommendations_generated'],
|
||||
data=recommendations
|
||||
logger.info(f"✅ AI recommendations generated successfully: {strategy_id}")
|
||||
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy AI recommendations generated successfully",
|
||||
data=updated_strategy.to_dict()
|
||||
)
|
||||
|
||||
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")
|
||||
logger.error(f"❌ Error generating AI recommendations: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "generate_enhanced_ai_recommendations")
|
||||
|
||||
@router.post("/{strategy_id}/ai-analysis/regenerate")
|
||||
async def regenerate_enhanced_strategy_ai_analysis(
|
||||
@@ -290,44 +220,33 @@ async def regenerate_enhanced_strategy_ai_analysis(
|
||||
) -> Dict[str, Any]:
|
||||
"""Regenerate AI analysis for an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Regenerating AI analysis for strategy: {strategy_id}, type: {analysis_type}")
|
||||
logger.info(f"🚀 Regenerating AI analysis for enhanced strategy: {strategy_id}, type: {analysis_type}")
|
||||
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
# Get strategy
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
raise ContentPlanningErrorHandler.handle_not_found_error("Enhanced strategy", strategy_id)
|
||||
|
||||
# Regenerate AI analysis
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
enhanced_service = EnhancedStrategyService(db_service)
|
||||
# Pass user_id for subscription checks
|
||||
user_id = str(strategy.user_id) if hasattr(strategy, 'user_id') else None
|
||||
await enhanced_service._generate_specialized_recommendations(strategy, analysis_type, db, user_id=user_id)
|
||||
|
||||
# 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"]
|
||||
}
|
||||
}
|
||||
# Get updated strategy data
|
||||
updated_strategy = await db_service.get_enhanced_strategy(strategy_id)
|
||||
|
||||
logger.info(f"Regenerated AI analysis for strategy: {strategy_id}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['ai_analysis_regenerated'],
|
||||
data=analysis_result
|
||||
logger.info(f"✅ AI analysis regenerated successfully: {strategy_id}")
|
||||
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Enhanced strategy AI analysis regenerated successfully",
|
||||
data=updated_strategy.to_dict()
|
||||
)
|
||||
|
||||
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")
|
||||
logger.error(f"❌ Error regenerating AI analysis: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "regenerate_enhanced_strategy_ai_analysis")
|
||||
@@ -13,6 +13,9 @@ from datetime import datetime
|
||||
# Import database
|
||||
from services.database import get_db_session
|
||||
|
||||
# Import authentication middleware
|
||||
from middleware.auth_middleware import get_current_user
|
||||
|
||||
# Import services
|
||||
from ....services.enhanced_strategy_service import EnhancedStrategyService
|
||||
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
|
||||
@@ -24,6 +27,7 @@ from models.enhanced_strategy_models import EnhancedContentStrategy
|
||||
from ....utils.error_handlers import ContentPlanningErrorHandler
|
||||
from ....utils.response_builders import ResponseBuilder
|
||||
from ....utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
|
||||
from ....utils.data_parsers import parse_strategy_data
|
||||
|
||||
router = APIRouter(tags=["Strategy CRUD"])
|
||||
|
||||
@@ -38,14 +42,26 @@ def get_db():
|
||||
@router.post("/create")
|
||||
async def create_enhanced_strategy(
|
||||
strategy_data: Dict[str, Any],
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
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')}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
logger.info(f"Creating enhanced strategy: {strategy_data.get('name', 'Unknown')} for user: {clerk_user_id}")
|
||||
|
||||
# Override user_id from request body with authenticated user_id (security)
|
||||
strategy_data['user_id'] = clerk_user_id
|
||||
|
||||
# Validate required fields
|
||||
required_fields = ['user_id', 'name']
|
||||
required_fields = ['name']
|
||||
for field in required_fields:
|
||||
if field not in strategy_data or not strategy_data[field]:
|
||||
raise HTTPException(
|
||||
@@ -53,85 +69,33 @@ async def create_enhanced_strategy(
|
||||
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
|
||||
# Parse and validate strategy data using shared utilities
|
||||
cleaned_data, warnings = parse_strategy_data(strategy_data)
|
||||
|
||||
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])
|
||||
# Log warnings if any
|
||||
if warnings:
|
||||
logger.warning(f"ℹ️ Strategy create warnings: {warnings}")
|
||||
|
||||
# Create strategy
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
enhanced_service = EnhancedStrategyService(db_service)
|
||||
|
||||
result = await enhanced_service.create_enhanced_strategy(strategy_data, db)
|
||||
# Pass authenticated user_id for AI calls with subscription checks
|
||||
result = await enhanced_service.create_enhanced_strategy(cleaned_data, db)
|
||||
|
||||
logger.info(f"Enhanced strategy created successfully: {result.get('strategy_id')}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['strategy_created'],
|
||||
data=result
|
||||
logger.info(f"Enhanced strategy created successfully: {result.get('strategy_id') if isinstance(result, dict) else getattr(result, 'id', None)}")
|
||||
|
||||
response = ResponseBuilder.create_success_response(
|
||||
data=result,
|
||||
message=SUCCESS_MESSAGES['strategy_created']
|
||||
)
|
||||
|
||||
# Include warnings if any
|
||||
if warnings:
|
||||
response['warnings'] = warnings
|
||||
|
||||
return response
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
@@ -140,23 +104,36 @@ async def create_enhanced_strategy(
|
||||
|
||||
@router.get("/")
|
||||
async def get_enhanced_strategies(
|
||||
user_id: Optional[int] = Query(None, description="User ID to filter strategies"),
|
||||
user_id: Optional[int] = Query(None, description="User ID to filter strategies (deprecated - use authenticated user)"),
|
||||
strategy_id: Optional[int] = Query(None, description="Specific strategy ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
# Use authenticated user_id (override query parameter for security)
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
|
||||
logger.info(f"Getting enhanced strategies for authenticated user: {authenticated_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)
|
||||
# Use authenticated user_id to ensure users can only see their own strategies
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(authenticated_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
|
||||
return ResponseBuilder.create_success_response(
|
||||
data=strategies_data,
|
||||
message=SUCCESS_MESSAGES['strategies_retrieved']
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@@ -166,29 +143,47 @@ async def get_enhanced_strategies(
|
||||
@router.get("/{strategy_id}")
|
||||
async def get_enhanced_strategy_by_id(
|
||||
strategy_id: int,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
|
||||
logger.info(f"Getting enhanced strategy by ID: {strategy_id} for authenticated user: {authenticated_user_id}")
|
||||
|
||||
db_service = EnhancedStrategyDBService(db)
|
||||
enhanced_service = EnhancedStrategyService(db_service)
|
||||
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(strategy_id=strategy_id, db=db)
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(user_id=authenticated_user_id, 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"
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found or you don't have access to it"
|
||||
)
|
||||
|
||||
strategy = strategies_data["strategies"][0]
|
||||
|
||||
# Verify ownership
|
||||
if strategy.get('user_id') != authenticated_user_id:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="You don't have permission to access this strategy"
|
||||
)
|
||||
|
||||
logger.info(f"Retrieved strategy: {strategy.get('name')}")
|
||||
return ResponseBuilder.success_response(
|
||||
message=SUCCESS_MESSAGES['strategy_retrieved'],
|
||||
data=strategy
|
||||
return ResponseBuilder.create_success_response(
|
||||
data=strategy,
|
||||
message=SUCCESS_MESSAGES['strategy_retrieved']
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
@@ -201,13 +196,24 @@ async def get_enhanced_strategy_by_id(
|
||||
async def update_enhanced_strategy(
|
||||
strategy_id: int,
|
||||
update_data: Dict[str, Any],
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
) -> Dict[str, Any]:
|
||||
"""Update an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Updating enhanced strategy: {strategy_id}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
# Check if strategy exists
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
|
||||
logger.info(f"Updating enhanced strategy: {strategy_id} for authenticated user: {authenticated_user_id}")
|
||||
|
||||
# Check if strategy exists and verify ownership
|
||||
existing_strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
@@ -218,6 +224,13 @@ async def update_enhanced_strategy(
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Verify ownership
|
||||
if existing_strategy.user_id != authenticated_user_id:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="You don't have permission to update this strategy"
|
||||
)
|
||||
|
||||
# Update strategy fields
|
||||
for field, value in update_data.items():
|
||||
if hasattr(existing_strategy, field):
|
||||
@@ -230,9 +243,9 @@ async def update_enhanced_strategy(
|
||||
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()
|
||||
return ResponseBuilder.create_success_response(
|
||||
data=existing_strategy.to_dict(),
|
||||
message=SUCCESS_MESSAGES['strategy_updated']
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
@@ -244,13 +257,24 @@ async def update_enhanced_strategy(
|
||||
@router.delete("/{strategy_id}")
|
||||
async def delete_enhanced_strategy(
|
||||
strategy_id: int,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
) -> Dict[str, Any]:
|
||||
"""Delete an enhanced strategy."""
|
||||
try:
|
||||
logger.info(f"Deleting enhanced strategy: {strategy_id}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
# Check if strategy exists
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
|
||||
logger.info(f"Deleting enhanced strategy: {strategy_id} for authenticated user: {authenticated_user_id}")
|
||||
|
||||
# Check if strategy exists and verify ownership
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
@@ -261,14 +285,21 @@ async def delete_enhanced_strategy(
|
||||
detail=f"Enhanced strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Verify ownership
|
||||
if strategy.user_id != authenticated_user_id:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="You don't have permission to delete this strategy"
|
||||
)
|
||||
|
||||
# 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}
|
||||
return ResponseBuilder.create_success_response(
|
||||
data={"strategy_id": strategy_id},
|
||||
message=SUCCESS_MESSAGES['strategy_deleted']
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
|
||||
@@ -6,6 +6,7 @@ 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 starlette.requests import Request
|
||||
from sqlalchemy.orm import Session
|
||||
from loguru import logger
|
||||
import json
|
||||
@@ -17,6 +18,9 @@ import time
|
||||
# Import database
|
||||
from services.database import get_db_session
|
||||
|
||||
# Import authentication middleware
|
||||
from middleware.auth_middleware import get_current_user, get_current_user_with_query_token
|
||||
|
||||
# Import services
|
||||
from ....services.enhanced_strategy_service import EnhancedStrategyService
|
||||
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
|
||||
@@ -66,15 +70,26 @@ async def stream_data(data_generator):
|
||||
|
||||
@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"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID in authentication token", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
if not authenticated_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID format", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
logger.info(f"🚀 Starting strategy stream for authenticated user: {authenticated_user_id}, strategy: {strategy_id}")
|
||||
|
||||
# Send initial status
|
||||
yield {"type": "status", "message": "Starting strategy retrieval...", "timestamp": datetime.utcnow().isoformat()}
|
||||
@@ -85,7 +100,8 @@ async def stream_enhanced_strategies(
|
||||
# Send progress update
|
||||
yield {"type": "progress", "message": "Querying database...", "progress": 25}
|
||||
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, strategy_id, db)
|
||||
# Use authenticated user_id to ensure users can only see their own strategies
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(authenticated_user_id, strategy_id, db)
|
||||
|
||||
# Send progress update
|
||||
yield {"type": "progress", "message": "Processing strategies...", "progress": 50}
|
||||
@@ -100,7 +116,7 @@ async def stream_enhanced_strategies(
|
||||
# Send final result
|
||||
yield {"type": "result", "status": "success", "data": strategies_data, "progress": 100}
|
||||
|
||||
logger.info(f"✅ Strategy stream completed for user: {user_id}")
|
||||
logger.info(f"✅ Strategy stream completed for user: {authenticated_user_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in strategy stream: {str(e)}")
|
||||
@@ -121,20 +137,32 @@ async def stream_enhanced_strategies(
|
||||
|
||||
@router.get("/stream/strategic-intelligence")
|
||||
async def stream_strategic_intelligence(
|
||||
user_id: Optional[int] = Query(None, description="User ID"),
|
||||
request: Request,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_with_query_token),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID in authentication token", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
if not authenticated_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID format", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
logger.info(f"🚀 Starting strategic intelligence stream for authenticated user: {authenticated_user_id}")
|
||||
|
||||
# Check cache first
|
||||
cache_key = f"strategic_intelligence_{user_id}"
|
||||
cache_key = f"strategic_intelligence_{authenticated_user_id}"
|
||||
cached_data = get_cached_data(cache_key)
|
||||
if cached_data:
|
||||
logger.info(f"✅ Returning cached strategic intelligence data for user: {user_id}")
|
||||
logger.info(f"✅ Returning cached strategic intelligence data for user: {authenticated_user_id}")
|
||||
yield {"type": "result", "status": "success", "data": cached_data, "progress": 100}
|
||||
return
|
||||
|
||||
@@ -147,7 +175,8 @@ async def stream_strategic_intelligence(
|
||||
# Send progress update
|
||||
yield {"type": "progress", "message": "Retrieving strategies...", "progress": 20}
|
||||
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(user_id, None, db)
|
||||
# Use authenticated user_id to ensure users can only see their own strategies
|
||||
strategies_data = await enhanced_service.get_enhanced_strategies(authenticated_user_id, None, db)
|
||||
|
||||
# Send progress update
|
||||
yield {"type": "progress", "message": "Analyzing market positioning...", "progress": 40}
|
||||
@@ -228,7 +257,7 @@ async def stream_strategic_intelligence(
|
||||
# Send final result
|
||||
yield {"type": "result", "status": "success", "data": strategic_intelligence, "progress": 100}
|
||||
|
||||
logger.info(f"✅ Strategic intelligence stream completed for user: {user_id}")
|
||||
logger.info(f"✅ Strategic intelligence stream completed for user: {authenticated_user_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in strategic intelligence stream: {str(e)}")
|
||||
@@ -249,20 +278,32 @@ async def stream_strategic_intelligence(
|
||||
|
||||
@router.get("/stream/keyword-research")
|
||||
async def stream_keyword_research(
|
||||
user_id: Optional[int] = Query(None, description="User ID"),
|
||||
request: Request,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_with_query_token),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID in authentication token", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
if not authenticated_user_id:
|
||||
yield {"type": "error", "message": "Invalid user ID format", "timestamp": datetime.utcnow().isoformat()}
|
||||
return
|
||||
|
||||
logger.info(f"🚀 Starting keyword research stream for authenticated user: {authenticated_user_id}")
|
||||
|
||||
# Check cache first
|
||||
cache_key = f"keyword_research_{user_id}"
|
||||
cache_key = f"keyword_research_{authenticated_user_id}"
|
||||
cached_data = get_cached_data(cache_key)
|
||||
if cached_data:
|
||||
logger.info(f"✅ Returning cached keyword research data for user: {user_id}")
|
||||
logger.info(f"✅ Returning cached keyword research data for user: {authenticated_user_id}")
|
||||
yield {"type": "result", "status": "success", "data": cached_data, "progress": 100}
|
||||
return
|
||||
|
||||
@@ -276,7 +317,8 @@ async def stream_keyword_research(
|
||||
yield {"type": "progress", "message": "Retrieving gap analyses...", "progress": 20}
|
||||
|
||||
gap_service = GapAnalysisService()
|
||||
gap_analyses = await gap_service.get_gap_analyses(user_id)
|
||||
# Use authenticated user_id to ensure users can only see their own data
|
||||
gap_analyses = await gap_service.get_gap_analyses(authenticated_user_id)
|
||||
|
||||
# Send progress update
|
||||
yield {"type": "progress", "message": "Analyzing keyword opportunities...", "progress": 40}
|
||||
@@ -337,7 +379,7 @@ async def stream_keyword_research(
|
||||
# Send final result
|
||||
yield {"type": "result", "status": "success", "data": keyword_data, "progress": 100}
|
||||
|
||||
logger.info(f"✅ Keyword research stream completed for user: {user_id}")
|
||||
logger.info(f"✅ Keyword research stream completed for user: {authenticated_user_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in keyword research stream: {str(e)}")
|
||||
|
||||
@@ -15,6 +15,9 @@ from services.database import get_db_session
|
||||
from ....services.enhanced_strategy_service import EnhancedStrategyService
|
||||
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
|
||||
|
||||
# Import authentication
|
||||
from middleware.auth_middleware import get_current_user
|
||||
|
||||
# Import utilities
|
||||
from ....utils.error_handlers import ContentPlanningErrorHandler
|
||||
from ....utils.response_builders import ResponseBuilder
|
||||
@@ -32,36 +35,60 @@ def get_db():
|
||||
|
||||
@router.get("/onboarding-data")
|
||||
async def get_onboarding_data(
|
||||
user_id: Optional[int] = Query(None, description="User ID to get onboarding data for"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user),
|
||||
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}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
if not authenticated_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID format in authentication token"
|
||||
)
|
||||
|
||||
logger.info(f"🚀 Getting onboarding data for authenticated user: {authenticated_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)
|
||||
onboarding_data = await enhanced_service._get_onboarding_data(authenticated_user_id)
|
||||
|
||||
logger.info(f"✅ Onboarding data retrieved successfully for user: {actual_user_id}")
|
||||
logger.info(f"✅ Onboarding data retrieved successfully for user: {authenticated_user_id}")
|
||||
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Onboarding data retrieved successfully",
|
||||
data=onboarding_data
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
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]:
|
||||
async def get_enhanced_strategy_tooltips(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get tooltip data for enhanced strategy fields."""
|
||||
try:
|
||||
logger.info("🚀 Getting enhanced strategy tooltips")
|
||||
# Verify authentication (user_id not needed for static data, but auth is required)
|
||||
if not current_user or not current_user.get('id'):
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Authentication required"
|
||||
)
|
||||
|
||||
logger.info(f"🚀 Getting enhanced strategy tooltips for authenticated user: {current_user.get('id')}")
|
||||
|
||||
# Mock tooltip data - in real implementation, this would come from a database
|
||||
tooltip_data = {
|
||||
@@ -122,15 +149,26 @@ async def get_enhanced_strategy_tooltips() -> Dict[str, Any]:
|
||||
data=tooltip_data
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
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]:
|
||||
async def get_enhanced_strategy_disclosure_steps(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get progressive disclosure steps for enhanced strategy."""
|
||||
try:
|
||||
logger.info("🚀 Getting enhanced strategy disclosure steps")
|
||||
# Verify authentication (user_id not needed for static data, but auth is required)
|
||||
if not current_user or not current_user.get('id'):
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Authentication required"
|
||||
)
|
||||
|
||||
logger.info(f"🚀 Getting enhanced strategy disclosure steps for authenticated user: {current_user.get('id')}")
|
||||
|
||||
# Progressive disclosure steps configuration
|
||||
disclosure_steps = [
|
||||
@@ -197,41 +235,55 @@ async def get_enhanced_strategy_disclosure_steps() -> Dict[str, Any]:
|
||||
data=disclosure_steps
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
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")
|
||||
current_user: Dict[str, Any] = Depends(get_current_user)
|
||||
):
|
||||
"""Clear streaming cache for a specific user or all users."""
|
||||
"""Clear streaming cache for the authenticated user."""
|
||||
try:
|
||||
logger.info(f"🚀 Clearing streaming cache for user: {user_id}")
|
||||
# Extract authenticated user_id from Clerk
|
||||
clerk_user_id = str(current_user.get('id', ''))
|
||||
if not clerk_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID in authentication token"
|
||||
)
|
||||
|
||||
authenticated_user_id = int(clerk_user_id) if clerk_user_id.isdigit() else None
|
||||
if not authenticated_user_id:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid user ID format in authentication token"
|
||||
)
|
||||
|
||||
logger.info(f"🚀 Clearing streaming cache for authenticated user: {authenticated_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")
|
||||
# Clear cache for authenticated user only (security: users can only clear their own cache)
|
||||
cache_keys_to_remove = [
|
||||
f"strategic_intelligence_{authenticated_user_id}",
|
||||
f"keyword_research_{authenticated_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}")
|
||||
|
||||
return ResponseBuilder.create_success_response(
|
||||
message="Streaming cache cleared successfully",
|
||||
data={"cleared_for_user": user_id}
|
||||
data={"cleared_for_user": authenticated_user_id}
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error clearing streaming cache: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "clear_streaming_cache")
|
||||
@@ -14,12 +14,19 @@ 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"])
|
||||
# Using /enhanced-strategies prefix for backward compatibility with frontend
|
||||
router = APIRouter(prefix="/enhanced-strategies", tags=["Content Strategy"])
|
||||
|
||||
# Include all endpoint routers
|
||||
router.include_router(crud_router, prefix="/strategies")
|
||||
# CRUD endpoints directly under /enhanced-strategies (backward compatibility)
|
||||
router.include_router(crud_router, prefix="")
|
||||
# Analytics endpoints under /enhanced-strategies/strategies/{id}/...
|
||||
router.include_router(analytics_router, prefix="/strategies")
|
||||
# Utility endpoints directly under /enhanced-strategies
|
||||
router.include_router(utility_router, prefix="")
|
||||
# Streaming endpoints directly under /enhanced-strategies
|
||||
router.include_router(streaming_router, prefix="")
|
||||
# Autofill endpoints under /enhanced-strategies/strategies/{id}/...
|
||||
router.include_router(autofill_router, prefix="/strategies")
|
||||
# AI generation endpoints under /enhanced-strategies/ai-generation
|
||||
router.include_router(ai_generation_router, prefix="/ai-generation")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,10 +11,7 @@ from loguru import logger
|
||||
# Import route modules
|
||||
from .routes import strategies, calendar_events, gap_analysis, ai_analytics, calendar_generation, health_monitoring, monitoring
|
||||
|
||||
# Import enhanced strategy routes
|
||||
from .enhanced_strategy_routes import router as enhanced_strategy_router
|
||||
|
||||
# Import content strategy routes
|
||||
# Import content strategy routes (modular endpoints)
|
||||
from .content_strategy.routes import router as content_strategy_router
|
||||
|
||||
# Import quality analysis routes
|
||||
@@ -35,10 +32,7 @@ router.include_router(calendar_generation.router)
|
||||
router.include_router(health_monitoring.router)
|
||||
router.include_router(monitoring.router)
|
||||
|
||||
# Include enhanced strategy routes with correct prefix
|
||||
router.include_router(enhanced_strategy_router, prefix="/enhanced-strategies")
|
||||
|
||||
# Include content strategy routes
|
||||
# Include content strategy routes (modular endpoints)
|
||||
router.include_router(content_strategy_router)
|
||||
|
||||
# Include quality analysis routes
|
||||
|
||||
@@ -62,18 +62,24 @@ async def get_cache_statistics(db = None) -> Dict[str, Any]:
|
||||
|
||||
@router.get("/health")
|
||||
async def get_system_health() -> Dict[str, Any]:
|
||||
"""Get overall system health status."""
|
||||
"""Get overall system health status.
|
||||
|
||||
Optimized to fail fast - cache stats are optional and won't block the response.
|
||||
"""
|
||||
try:
|
||||
# Get lightweight API stats
|
||||
# Get lightweight API stats (this is the critical path)
|
||||
api_stats = await get_lightweight_stats()
|
||||
|
||||
# Get cache stats if available
|
||||
# Get cache stats if available (non-blocking - don't fail if unavailable)
|
||||
cache_stats = {}
|
||||
try:
|
||||
db = next(get_db())
|
||||
cache_service = ComprehensiveUserDataCacheService(db)
|
||||
cache_stats = cache_service.get_cache_stats()
|
||||
except:
|
||||
db.close()
|
||||
except Exception as cache_err:
|
||||
# Cache stats are optional - log at debug level, don't fail
|
||||
logger.debug(f"Cache stats unavailable: {cache_err}")
|
||||
cache_stats = {"error": "Cache service unavailable"}
|
||||
|
||||
# Determine overall health
|
||||
@@ -97,7 +103,7 @@ async def get_system_health() -> Dict[str, Any]:
|
||||
"message": f"System health: {system_health}"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting system health: {str(e)}")
|
||||
logger.error(f"Error getting system health: {str(e)}", exc_info=True)
|
||||
return {
|
||||
"status": "error",
|
||||
"data": {
|
||||
|
||||
Reference in New Issue
Block a user