ALwrity Version 0.5.0 (Fastapi + React )
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
"""
|
||||
Calendar Generation Service for Content Planning API
|
||||
Extracted business logic from the calendar generation route for better separation of concerns.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from datetime import datetime
|
||||
from loguru import logger
|
||||
from sqlalchemy.orm import Session
|
||||
import time
|
||||
|
||||
# Import database service
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
|
||||
# Import calendar generator service
|
||||
from services.calendar_generator_service import CalendarGeneratorService
|
||||
|
||||
# Import validation service
|
||||
from services.validation import check_all_api_keys
|
||||
|
||||
# Import utilities
|
||||
from ..utils.error_handlers import ContentPlanningErrorHandler
|
||||
from ..utils.response_builders import ResponseBuilder
|
||||
from ..utils.constants import ERROR_MESSAGES, SUCCESS_MESSAGES
|
||||
|
||||
class CalendarGenerationService:
|
||||
"""Service class for calendar generation operations."""
|
||||
|
||||
def __init__(self):
|
||||
self.calendar_generator_service = CalendarGeneratorService()
|
||||
|
||||
async def generate_comprehensive_calendar(self, user_id: int, strategy_id: Optional[int] = None,
|
||||
calendar_type: str = "monthly", industry: Optional[str] = None,
|
||||
business_size: str = "sme") -> Dict[str, Any]:
|
||||
"""Generate a comprehensive AI-powered content calendar using database insights."""
|
||||
try:
|
||||
logger.info(f"🎯 Generating comprehensive calendar for user {user_id}")
|
||||
start_time = time.time()
|
||||
|
||||
# Generate calendar using advanced AI-powered method
|
||||
calendar_data = await self.calendar_generator_service.generate_ai_powered_calendar(
|
||||
user_id=user_id,
|
||||
strategy_id=strategy_id,
|
||||
calendar_type=calendar_type,
|
||||
industry=industry,
|
||||
business_size=business_size
|
||||
)
|
||||
|
||||
processing_time = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Calendar generated successfully in {processing_time:.2f}s")
|
||||
return calendar_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error generating comprehensive calendar: {str(e)}")
|
||||
logger.error(f"Exception type: {type(e)}")
|
||||
import traceback
|
||||
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "generate_comprehensive_calendar")
|
||||
|
||||
async def optimize_content_for_platform(self, user_id: int, title: str, description: str,
|
||||
content_type: str, target_platform: str, event_id: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""Optimize content for specific platforms using database insights."""
|
||||
try:
|
||||
logger.info(f"🔧 Starting content optimization for user {user_id}")
|
||||
|
||||
# Validate API keys - temporarily disabled for testing
|
||||
# from services.api_key_manager import APIKeyManager
|
||||
# api_manager = APIKeyManager()
|
||||
# api_key_status = check_all_api_keys(api_manager)
|
||||
# if not api_key_status.get("all_valid", False):
|
||||
# raise Exception("AI services are not properly configured")
|
||||
|
||||
# Get user data for optimization
|
||||
user_data = await self.calendar_generator_service._get_comprehensive_user_data(
|
||||
user_id,
|
||||
None # No strategy_id for content optimization
|
||||
)
|
||||
|
||||
# Create optimization request for AI
|
||||
optimization_prompt = f"""
|
||||
Optimize the following content for {target_platform}:
|
||||
|
||||
Original Content:
|
||||
- Title: {title}
|
||||
- Description: {description}
|
||||
- Content Type: {content_type}
|
||||
- Platform: {target_platform}
|
||||
|
||||
User Context:
|
||||
- Industry: {user_data.get('industry', 'technology')}
|
||||
- Target Audience: {user_data.get('target_audience', {})}
|
||||
- Performance Data: {user_data.get('performance_data', {})}
|
||||
- Gap Analysis: {user_data.get('gap_analysis', {})}
|
||||
|
||||
Provide comprehensive optimization including:
|
||||
1. Platform-specific adaptations
|
||||
2. Visual recommendations
|
||||
3. Hashtag suggestions
|
||||
4. Keyword optimization
|
||||
5. Tone adjustments
|
||||
6. Length optimization
|
||||
7. Performance predictions
|
||||
"""
|
||||
|
||||
# Generate optimization using AI
|
||||
optimization_result = await self.calendar_generator_service.ai_engine.generate_content_recommendations(
|
||||
analysis_data={
|
||||
"original_content": {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"content_type": content_type,
|
||||
"target_platform": target_platform
|
||||
},
|
||||
"user_context": {
|
||||
"industry": user_data.get('industry', 'technology'),
|
||||
"target_audience": user_data.get('target_audience', {}),
|
||||
"performance_data": user_data.get('performance_data', {}),
|
||||
"gap_analysis": user_data.get('gap_analysis', {})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Prepare response
|
||||
response_data = {
|
||||
"user_id": user_id,
|
||||
"event_id": event_id,
|
||||
"original_content": {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"content_type": content_type,
|
||||
"target_platform": target_platform
|
||||
},
|
||||
"optimized_content": {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"content_type": content_type,
|
||||
"target_platform": target_platform
|
||||
},
|
||||
"platform_adaptations": [rec.get('description', '') for rec in optimization_result[:3]],
|
||||
"visual_recommendations": ["Use engaging visuals", "Include relevant images", "Optimize for mobile"],
|
||||
"hashtag_suggestions": ["#content", "#marketing", "#digital"],
|
||||
"keyword_optimization": {"primary": "content", "secondary": ["marketing", "digital"]},
|
||||
"tone_adjustments": {"tone": "professional", "style": "informative"},
|
||||
"length_optimization": {"optimal_length": "150-300 words", "format": "paragraphs"},
|
||||
"performance_prediction": {"engagement_rate": 0.05, "reach": 1000},
|
||||
"optimization_score": 0.8,
|
||||
"created_at": datetime.utcnow()
|
||||
}
|
||||
|
||||
logger.info(f"✅ Content optimization completed for user {user_id}")
|
||||
return response_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error optimizing content: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "optimize_content_for_platform")
|
||||
|
||||
async def predict_content_performance(self, user_id: int, content_type: str, platform: str,
|
||||
content_data: Dict[str, Any], strategy_id: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""Predict content performance using database insights."""
|
||||
try:
|
||||
logger.info(f"📊 Starting performance prediction for user {user_id}")
|
||||
|
||||
# Get user data for prediction
|
||||
user_data = await self.calendar_generator_service._get_comprehensive_user_data(
|
||||
user_id,
|
||||
strategy_id
|
||||
)
|
||||
|
||||
# Generate performance prediction
|
||||
prediction_prompt = f"""
|
||||
Predict performance for the following content:
|
||||
|
||||
Content Data:
|
||||
- Content Type: {content_type}
|
||||
- Platform: {platform}
|
||||
- Content Data: {content_data}
|
||||
|
||||
User Context:
|
||||
- Industry: {user_data.get('industry', 'technology')}
|
||||
- Performance Data: {user_data.get('performance_data', {})}
|
||||
- Gap Analysis: {user_data.get('gap_analysis', {})}
|
||||
- Audience Insights: {user_data.get('onboarding_data', {}).get('target_audience', {})}
|
||||
|
||||
Provide performance predictions including:
|
||||
1. Engagement rate
|
||||
2. Reach estimates
|
||||
3. Conversion predictions
|
||||
4. ROI estimates
|
||||
5. Confidence score
|
||||
6. Recommendations
|
||||
"""
|
||||
|
||||
# Generate prediction using AI
|
||||
prediction_result = await self.calendar_generator_service.ai_engine.generate_structured_response(
|
||||
prompt=prediction_prompt,
|
||||
schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"predicted_engagement_rate": {"type": "number"},
|
||||
"predicted_reach": {"type": "integer"},
|
||||
"predicted_conversions": {"type": "integer"},
|
||||
"predicted_roi": {"type": "number"},
|
||||
"confidence_score": {"type": "number"},
|
||||
"recommendations": {"type": "array", "items": {"type": "string"}}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Prepare response
|
||||
response_data = {
|
||||
"user_id": user_id,
|
||||
"strategy_id": strategy_id,
|
||||
"content_type": content_type,
|
||||
"platform": platform,
|
||||
"predicted_engagement_rate": prediction_result.get("predicted_engagement_rate", 0.05),
|
||||
"predicted_reach": prediction_result.get("predicted_reach", 1000),
|
||||
"predicted_conversions": prediction_result.get("predicted_conversions", 10),
|
||||
"predicted_roi": prediction_result.get("predicted_roi", 2.5),
|
||||
"confidence_score": prediction_result.get("confidence_score", 0.75),
|
||||
"recommendations": prediction_result.get("recommendations", []),
|
||||
"created_at": datetime.utcnow()
|
||||
}
|
||||
|
||||
logger.info(f"✅ Performance prediction completed for user {user_id}")
|
||||
return response_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error predicting content performance: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "predict_content_performance")
|
||||
|
||||
async def repurpose_content_across_platforms(self, user_id: int, original_content: Dict[str, Any],
|
||||
target_platforms: List[str], strategy_id: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""Repurpose content across different platforms using database insights."""
|
||||
try:
|
||||
logger.info(f"🔄 Starting content repurposing for user {user_id}")
|
||||
|
||||
# Get user data for repurposing
|
||||
user_data = await self.calendar_generator_service._get_comprehensive_user_data(
|
||||
user_id,
|
||||
strategy_id
|
||||
)
|
||||
|
||||
# Generate repurposing suggestions
|
||||
repurposing_prompt = f"""
|
||||
Repurpose the following content for multiple platforms:
|
||||
|
||||
Original Content:
|
||||
{original_content}
|
||||
|
||||
Target Platforms:
|
||||
{target_platforms}
|
||||
|
||||
User Context:
|
||||
- Gap Analysis: {user_data.get('gap_analysis', {})}
|
||||
- Strategy Data: {user_data.get('strategy_data', {})}
|
||||
- Recommendations: {user_data.get('recommendations_data', [])}
|
||||
|
||||
Provide repurposing suggestions including:
|
||||
1. Platform-specific adaptations
|
||||
2. Content transformations
|
||||
3. Implementation tips
|
||||
4. Gap addressing opportunities
|
||||
"""
|
||||
|
||||
# Generate repurposing suggestions using AI
|
||||
repurposing_result = await self.calendar_generator_service.ai_engine.generate_structured_response(
|
||||
prompt=repurposing_prompt,
|
||||
schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_adaptations": {"type": "array", "items": {"type": "object"}},
|
||||
"transformations": {"type": "array", "items": {"type": "object"}},
|
||||
"implementation_tips": {"type": "array", "items": {"type": "string"}},
|
||||
"gap_addresses": {"type": "array", "items": {"type": "string"}}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Prepare response
|
||||
response_data = {
|
||||
"user_id": user_id,
|
||||
"strategy_id": strategy_id,
|
||||
"original_content": original_content,
|
||||
"platform_adaptations": repurposing_result.get("platform_adaptations", []),
|
||||
"transformations": repurposing_result.get("transformations", []),
|
||||
"implementation_tips": repurposing_result.get("implementation_tips", []),
|
||||
"gap_addresses": repurposing_result.get("gap_addresses", []),
|
||||
"created_at": datetime.utcnow()
|
||||
}
|
||||
|
||||
logger.info(f"✅ Content repurposing completed for user {user_id}")
|
||||
return response_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error repurposing content: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "repurpose_content_across_platforms")
|
||||
|
||||
async def get_trending_topics(self, user_id: int, industry: str, limit: int = 10) -> Dict[str, Any]:
|
||||
"""Get trending topics relevant to the user's industry and content gaps."""
|
||||
try:
|
||||
logger.info(f"📈 Getting trending topics for user {user_id} in {industry}")
|
||||
|
||||
# Get user data for trending topics
|
||||
user_data = await self.calendar_generator_service._get_comprehensive_user_data(user_id, None)
|
||||
|
||||
# Get trending topics with database insights
|
||||
trending_topics = await self.calendar_generator_service._get_trending_topics_from_db(industry, user_data)
|
||||
|
||||
# Limit results
|
||||
limited_topics = trending_topics[:limit]
|
||||
|
||||
# Calculate relevance scores
|
||||
gap_relevance_scores = {}
|
||||
audience_alignment_scores = {}
|
||||
|
||||
for topic in limited_topics:
|
||||
topic_key = topic.get("keyword", "")
|
||||
gap_relevance_scores[topic_key] = self.calendar_generator_service._assess_gap_relevance(topic, user_data.get("gap_analysis", {}))
|
||||
audience_alignment_scores[topic_key] = self.calendar_generator_service._assess_audience_alignment(topic, user_data.get("onboarding_data", {}))
|
||||
|
||||
# Prepare response
|
||||
response_data = {
|
||||
"user_id": user_id,
|
||||
"industry": industry,
|
||||
"trending_topics": limited_topics,
|
||||
"gap_relevance_scores": gap_relevance_scores,
|
||||
"audience_alignment_scores": audience_alignment_scores,
|
||||
"created_at": datetime.utcnow()
|
||||
}
|
||||
|
||||
logger.info(f"✅ Trending topics retrieved for user {user_id}")
|
||||
return response_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error getting trending topics: {str(e)}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "get_trending_topics")
|
||||
|
||||
async def get_comprehensive_user_data(self, user_id: int) -> Dict[str, Any]:
|
||||
"""Get comprehensive user data for calendar generation."""
|
||||
try:
|
||||
logger.info(f"Getting comprehensive user data for user_id: {user_id}")
|
||||
|
||||
# Get comprehensive data using the calendar generator service
|
||||
logger.info("Calling calendar generator service...")
|
||||
comprehensive_data = await self.calendar_generator_service._get_comprehensive_user_data(user_id, None)
|
||||
logger.info(f"Calendar generator service returned: {type(comprehensive_data)}")
|
||||
|
||||
logger.info(f"Successfully retrieved comprehensive user data for user_id: {user_id}")
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"data": comprehensive_data,
|
||||
"message": "Comprehensive user data retrieved successfully",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting comprehensive user data for user_id {user_id}: {str(e)}")
|
||||
logger.error(f"Exception type: {type(e)}")
|
||||
import traceback
|
||||
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
raise ContentPlanningErrorHandler.handle_general_error(e, "get_comprehensive_user_data")
|
||||
|
||||
async def health_check(self) -> Dict[str, Any]:
|
||||
"""Health check for calendar generation services."""
|
||||
try:
|
||||
logger.info("🏥 Performing calendar generation health check")
|
||||
|
||||
# Check AI services
|
||||
from services.api_key_manager import APIKeyManager
|
||||
api_manager = APIKeyManager()
|
||||
api_key_status = check_all_api_keys(api_manager)
|
||||
|
||||
# Check database connectivity
|
||||
db_status = "healthy"
|
||||
try:
|
||||
# Test database connection - only if calendar generator service is properly initialized
|
||||
if hasattr(self.calendar_generator_service, 'content_planning_db_service') and self.calendar_generator_service.content_planning_db_service is not None:
|
||||
await self.calendar_generator_service.content_planning_db_service.get_user_content_gap_analyses(1)
|
||||
else:
|
||||
db_status = "not_initialized"
|
||||
except Exception as e:
|
||||
db_status = f"error: {str(e)}"
|
||||
|
||||
health_status = {
|
||||
"service": "calendar_generation",
|
||||
"status": "healthy" if api_key_status.get("all_valid", False) and db_status == "healthy" else "unhealthy",
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"components": {
|
||||
"ai_services": "healthy" if api_key_status.get("all_valid", False) else "unhealthy",
|
||||
"database": db_status,
|
||||
"calendar_generator": "healthy"
|
||||
},
|
||||
"api_keys": api_key_status
|
||||
}
|
||||
|
||||
logger.info("✅ Calendar generation health check completed")
|
||||
return health_status
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Calendar generation health check failed: {str(e)}")
|
||||
return {
|
||||
"service": "calendar_generation",
|
||||
"status": "unhealthy",
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"error": str(e)
|
||||
}
|
||||
Reference in New Issue
Block a user