Base code

This commit is contained in:
Kunthawat Greethong
2026-01-08 22:39:53 +07:00
parent 697115c61a
commit c35fa52117
2169 changed files with 626670 additions and 0 deletions

View File

@@ -0,0 +1,383 @@
import logging
from typing import Dict, Any, Optional, List
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
from models.monitoring_models import (
StrategyMonitoringPlan,
MonitoringTask,
TaskExecutionLog,
StrategyPerformanceMetrics,
StrategyActivationStatus
)
from models.enhanced_strategy_models import EnhancedContentStrategy
from services.database import get_db_session
logger = logging.getLogger(__name__)
class StrategyService:
"""Service for managing content strategies and their activation status"""
def __init__(self, db_session: Optional[Session] = None):
self.db_session = db_session or get_db_session()
async def get_strategy_by_id(self, strategy_id: int) -> Optional[Dict[str, Any]]:
"""Get strategy by ID with all related data"""
try:
if self.db_session:
# Query the actual database
strategy = self.db_session.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.id == strategy_id
).first()
if strategy:
return strategy.to_dict()
# Fallback to mock data if no database or strategy not found
strategy_data = {
'id': strategy_id,
'name': f'Content Strategy {strategy_id}',
'industry': 'Technology',
'business_goals': ['Increase brand awareness', 'Generate leads', 'Improve engagement'],
'content_pillars': ['Educational Content', 'Thought Leadership', 'Case Studies'],
'target_audience': {
'demographics': 'B2B professionals',
'age_range': '25-45',
'interests': ['technology', 'business', 'innovation']
},
'strategic_insights': {
'market_positioning': 'Innovation leader in tech solutions',
'content_opportunities': ['AI trends', 'Digital transformation', 'Industry insights'],
'growth_potential': 'High growth potential in emerging markets'
},
'competitive_analysis': {
'competitors': ['Competitor A', 'Competitor B', 'Competitor C'],
'market_gaps': ['AI implementation guidance', 'ROI measurement tools'],
'opportunities': ['Thought leadership in AI', 'Educational content series']
},
'performance_predictions': {
'estimated_roi': '25-35%',
'traffic_growth': '40% increase in 6 months',
'engagement_metrics': '15% improvement in engagement rate'
},
'implementation_roadmap': {
'phases': ['Foundation', 'Growth', 'Optimization', 'Scale'],
'timeline': '12 months',
'milestones': ['Month 3: Content foundation', 'Month 6: Growth phase', 'Month 9: Optimization']
},
'risk_assessment': {
'risks': ['Market competition', 'Resource constraints', 'Technology changes'],
'overall_risk_level': 'Medium',
'mitigation_strategies': ['Continuous monitoring', 'Agile adaptation', 'Resource planning']
}
}
logger.info(f"Retrieved strategy {strategy_id}")
return strategy_data
except Exception as e:
logger.error(f"Error retrieving strategy {strategy_id}: {e}")
return None
async def activate_strategy(self, strategy_id: int, user_id: int = 1) -> bool:
"""Activate a strategy and set up monitoring"""
try:
# Check if strategy exists
strategy = await self.get_strategy_by_id(strategy_id)
if not strategy:
logger.error(f"Strategy {strategy_id} not found")
return False
# Check if already activated
if self.db_session:
existing_activation = self.db_session.query(StrategyActivationStatus).filter(
and_(
StrategyActivationStatus.strategy_id == strategy_id,
StrategyActivationStatus.user_id == user_id,
StrategyActivationStatus.status == 'active'
)
).first()
if existing_activation:
logger.info(f"Strategy {strategy_id} is already active")
return True
# Create activation status record
activation_status = StrategyActivationStatus(
strategy_id=strategy_id,
user_id=user_id,
activation_date=datetime.utcnow(),
status='active',
performance_score=0.0
)
if self.db_session:
self.db_session.add(activation_status)
self.db_session.commit()
logger.info(f"Strategy {strategy_id} activated successfully")
else:
logger.info(f"Strategy {strategy_id} activated (no database session)")
return True
except Exception as e:
logger.error(f"Error activating strategy {strategy_id}: {e}")
if self.db_session:
self.db_session.rollback()
return False
async def save_monitoring_plan(self, strategy_id: int, plan_data: Dict[str, Any]) -> bool:
"""Save monitoring plan to database"""
try:
# Check if monitoring plan already exists
if self.db_session:
existing_plan = self.db_session.query(StrategyMonitoringPlan).filter(
StrategyMonitoringPlan.strategy_id == strategy_id
).first()
if existing_plan:
# Update existing plan
existing_plan.plan_data = plan_data
existing_plan.updated_at = datetime.utcnow()
else:
# Create new monitoring plan
monitoring_plan = StrategyMonitoringPlan(
strategy_id=strategy_id,
plan_data=plan_data
)
self.db_session.add(monitoring_plan)
# Clear existing tasks and create new ones
self.db_session.query(MonitoringTask).filter(
MonitoringTask.strategy_id == strategy_id
).delete()
# Create individual monitoring tasks
for component in plan_data.get('components', []):
for task in component.get('tasks', []):
monitoring_task = MonitoringTask(
strategy_id=strategy_id,
component_name=component['name'],
task_title=task['title'],
task_description=task['description'],
assignee=task['assignee'],
frequency=task['frequency'],
metric=task['metric'],
measurement_method=task['measurementMethod'],
success_criteria=task['successCriteria'],
alert_threshold=task['alertThreshold'],
status='pending'
)
self.db_session.add(monitoring_task)
self.db_session.commit()
logger.info(f"Monitoring plan saved for strategy {strategy_id}")
else:
logger.info(f"Monitoring plan prepared for strategy {strategy_id} (no database session)")
return True
except Exception as e:
logger.error(f"Error saving monitoring plan for strategy {strategy_id}: {e}")
if self.db_session:
self.db_session.rollback()
return False
async def get_monitoring_plan(self, strategy_id: int) -> Optional[Dict[str, Any]]:
"""Get monitoring plan for a strategy"""
try:
if self.db_session:
monitoring_plan = self.db_session.query(StrategyMonitoringPlan).filter(
StrategyMonitoringPlan.strategy_id == strategy_id
).first()
if monitoring_plan:
return monitoring_plan.plan_data
# Also check activation status
activation_status = self.db_session.query(StrategyActivationStatus).filter(
StrategyActivationStatus.strategy_id == strategy_id
).first()
if activation_status:
return {
'strategy_id': strategy_id,
'status': activation_status.status,
'activation_date': activation_status.activation_date.isoformat(),
'message': 'Strategy is active but no monitoring plan found'
}
# Fallback to mock data
return {
'strategy_id': strategy_id,
'status': 'active',
'message': 'Monitoring plan retrieved successfully'
}
except Exception as e:
logger.error(f"Error getting monitoring plan for strategy {strategy_id}: {e}")
return None
async def update_strategy_status(self, strategy_id: int, status: str, user_id: int = 1) -> bool:
"""Update strategy activation status"""
try:
if self.db_session:
activation_status = self.db_session.query(StrategyActivationStatus).filter(
and_(
StrategyActivationStatus.strategy_id == strategy_id,
StrategyActivationStatus.user_id == user_id
)
).first()
if activation_status:
activation_status.status = status
activation_status.last_updated = datetime.utcnow()
self.db_session.commit()
logger.info(f"Strategy {strategy_id} status updated to {status}")
return True
else:
logger.warning(f"No activation status found for strategy {strategy_id}")
return False
else:
logger.info(f"Strategy {strategy_id} status would be updated to {status} (no database session)")
return True
except Exception as e:
logger.error(f"Error updating strategy status for {strategy_id}: {e}")
if self.db_session:
self.db_session.rollback()
return False
async def get_active_strategies(self, user_id: int = 1) -> List[Dict[str, Any]]:
"""Get all active strategies for a user"""
try:
if self.db_session:
active_strategies = self.db_session.query(StrategyActivationStatus).filter(
and_(
StrategyActivationStatus.user_id == user_id,
StrategyActivationStatus.status == 'active'
)
).all()
return [
{
'strategy_id': strategy.strategy_id,
'activation_date': strategy.activation_date,
'performance_score': strategy.performance_score,
'last_updated': strategy.last_updated
}
for strategy in active_strategies
]
else:
# Return mock data
return [
{
'strategy_id': 1,
'activation_date': datetime.utcnow(),
'performance_score': 0.0,
'last_updated': datetime.utcnow()
}
]
except Exception as e:
logger.error(f"Error getting active strategies for user {user_id}: {e}")
return []
async def save_performance_metrics(self, strategy_id: int, metrics: Dict[str, Any], user_id: int = 1) -> bool:
"""Save performance metrics for a strategy"""
try:
performance_metrics = StrategyPerformanceMetrics(
strategy_id=strategy_id,
user_id=user_id,
metric_date=datetime.utcnow(),
traffic_growth_percentage=metrics.get('traffic_growth_percentage'),
engagement_rate_percentage=metrics.get('engagement_rate_percentage'),
conversion_rate_percentage=metrics.get('conversion_rate_percentage'),
roi_ratio=metrics.get('roi_ratio'),
strategy_adoption_rate=metrics.get('strategy_adoption_rate'),
content_quality_score=metrics.get('content_quality_score'),
competitive_position_rank=metrics.get('competitive_position_rank'),
audience_growth_percentage=metrics.get('audience_growth_percentage'),
data_source=metrics.get('data_source', 'manual'),
confidence_score=metrics.get('confidence_score', 0.8)
)
if self.db_session:
self.db_session.add(performance_metrics)
self.db_session.commit()
logger.info(f"Performance metrics saved for strategy {strategy_id}")
else:
logger.info(f"Performance metrics prepared for strategy {strategy_id} (no database session)")
return True
except Exception as e:
logger.error(f"Error saving performance metrics for strategy {strategy_id}: {e}")
if self.db_session:
self.db_session.rollback()
return False
async def get_strategy_performance_history(self, strategy_id: int, days: int = 30) -> List[Dict[str, Any]]:
"""Get performance history for a strategy"""
try:
if self.db_session:
from datetime import timedelta
cutoff_date = datetime.utcnow() - timedelta(days=days)
metrics = self.db_session.query(StrategyPerformanceMetrics).filter(
and_(
StrategyPerformanceMetrics.strategy_id == strategy_id,
StrategyPerformanceMetrics.metric_date >= cutoff_date
)
).order_by(StrategyPerformanceMetrics.metric_date.desc()).all()
return [
{
'date': metric.metric_date.isoformat(),
'traffic_growth': metric.traffic_growth_percentage,
'engagement_rate': metric.engagement_rate_percentage,
'conversion_rate': metric.conversion_rate_percentage,
'roi': metric.roi_ratio,
'strategy_adoption': metric.strategy_adoption_rate,
'content_quality': metric.content_quality_score,
'competitive_position': metric.competitive_position_rank,
'audience_growth': metric.audience_growth_percentage
}
for metric in metrics
]
else:
return []
except Exception as e:
logger.error(f"Error getting performance history for strategy {strategy_id}: {e}")
return []
async def deactivate_strategy(self, strategy_id: int, user_id: int = 1) -> bool:
"""Deactivate a strategy"""
try:
return await self.update_strategy_status(strategy_id, 'inactive', user_id)
except Exception as e:
logger.error(f"Error deactivating strategy {strategy_id}: {e}")
return False
async def pause_strategy(self, strategy_id: int, user_id: int = 1) -> bool:
"""Pause a strategy"""
try:
return await self.update_strategy_status(strategy_id, 'paused', user_id)
except Exception as e:
logger.error(f"Error pausing strategy {strategy_id}: {e}")
return False
async def resume_strategy(self, strategy_id: int, user_id: int = 1) -> bool:
"""Resume a paused strategy"""
try:
return await self.update_strategy_status(strategy_id, 'active', user_id)
except Exception as e:
logger.error(f"Error resuming strategy {strategy_id}: {e}")
return False
def __del__(self):
"""Cleanup database session"""
if self.db_session:
self.db_session.close()