163 lines
5.7 KiB
Python
163 lines
5.7 KiB
Python
from datetime import datetime, timedelta
|
|
from typing import Dict, List, Any, Optional
|
|
import logging
|
|
import sys
|
|
import json
|
|
import os
|
|
from lib.database.models import ContentItem, ContentType, Platform, get_engine, get_session, init_db
|
|
from ..integrations.seo_tools import SEOToolsIntegration
|
|
from ..integrations.gap_analyzer import GapAnalyzerIntegration
|
|
from ..utils.date_utils import calculate_publish_dates
|
|
from ..utils.error_handling import handle_calendar_error
|
|
|
|
logging.basicConfig(
|
|
level=logging.DEBUG,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.StreamHandler(sys.stdout),
|
|
logging.FileHandler('content_calendar_debug.log', mode='a')
|
|
]
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
engine = get_engine()
|
|
init_db(engine)
|
|
session = get_session(engine)
|
|
|
|
class CalendarManager:
|
|
"""
|
|
Main calendar management system that coordinates content planning,
|
|
scheduling, and optimization.
|
|
"""
|
|
def __init__(self):
|
|
self.logger = logging.getLogger('content_calendar.manager')
|
|
self.logger.info("Initializing CalendarManager")
|
|
self.seo_tools = SEOToolsIntegration()
|
|
self.gap_analyzer = GapAnalyzerIntegration()
|
|
self.logger.info("CalendarManager initialized successfully")
|
|
|
|
@handle_calendar_error
|
|
def create_calendar(
|
|
self,
|
|
start_date: datetime,
|
|
duration: str, # 'weekly', 'monthly', 'quarterly'
|
|
platforms: List[str],
|
|
website_url: str
|
|
) -> List[ContentItem]:
|
|
self.logger.info(f"Creating new calendar for {website_url}")
|
|
self.logger.debug(f"Parameters: start_date={start_date}, duration={duration}, platforms={platforms}")
|
|
try:
|
|
gap_analysis = self.gap_analyzer.analyze_gaps(website_url)
|
|
topics = self._generate_topics(gap_analysis, platforms)
|
|
schedule = calculate_publish_dates(
|
|
topics=topics,
|
|
start_date=start_date,
|
|
duration=duration
|
|
)
|
|
# Add to DB
|
|
for topic in schedule:
|
|
session.add(topic)
|
|
session.commit()
|
|
self.logger.info("Calendar created and content scheduled in DB successfully")
|
|
return schedule
|
|
except Exception as e:
|
|
self.logger.error(f"Error creating calendar: {str(e)}", exc_info=True)
|
|
raise
|
|
|
|
def _generate_topics(
|
|
self,
|
|
gap_analysis: Dict[str, Any],
|
|
platforms: List[str]
|
|
) -> List[ContentItem]:
|
|
topics = []
|
|
for gap in gap_analysis['gaps']:
|
|
topic = self._generate_topic_from_gap(gap, platforms)
|
|
optimized_topic = self._optimize_topic(topic)
|
|
topics.append(optimized_topic)
|
|
return topics
|
|
|
|
def _generate_topic_from_gap(
|
|
self,
|
|
gap: Dict[str, Any],
|
|
platforms: List[str]
|
|
) -> ContentItem:
|
|
topic_data = {
|
|
'title': self._generate_title(gap),
|
|
'description': self._generate_description(gap),
|
|
'keywords': gap.get('keywords', []),
|
|
'platforms': platforms,
|
|
'content_type': self._determine_content_type(gap, platforms),
|
|
'publish_date': datetime.now(),
|
|
'status': 'Draft',
|
|
'author': None,
|
|
'tags': [],
|
|
'notes': None,
|
|
'seo_data': {}
|
|
}
|
|
return ContentItem(**topic_data)
|
|
|
|
def _optimize_topic(self, topic: ContentItem) -> ContentItem:
|
|
topic.title = self.seo_tools.optimize_title(topic.title)
|
|
topic.seo_data['meta_description'] = self.seo_tools.generate_meta_description(topic.description)
|
|
topic.seo_data['structured_data'] = self.seo_tools.generate_structured_data(topic.content_type)
|
|
return topic
|
|
|
|
def get_all_content(self) -> List[ContentItem]:
|
|
return session.query(ContentItem).all()
|
|
|
|
def remove_content(self, content_id):
|
|
content = session.query(ContentItem).get(content_id)
|
|
if content:
|
|
session.delete(content)
|
|
session.commit()
|
|
|
|
def update_content(self, content_id, **kwargs):
|
|
content = session.query(ContentItem).get(content_id)
|
|
if content:
|
|
for key, value in kwargs.items():
|
|
setattr(content, key, value)
|
|
session.commit()
|
|
|
|
def get_calendar(self) -> Optional[List[ContentItem]]:
|
|
"""
|
|
Get the current calendar.
|
|
"""
|
|
self.logger.debug("Getting current calendar")
|
|
return self.get_all_content()
|
|
|
|
def update_calendar(self, calendar: List[ContentItem]) -> None:
|
|
"""
|
|
Update the current calendar.
|
|
"""
|
|
self.get_all_content()
|
|
for content in calendar:
|
|
session.add(content)
|
|
session.commit()
|
|
|
|
def export_calendar(self) -> Optional[Dict[str, Any]]:
|
|
"""Export the current calendar."""
|
|
self.logger.info("Exporting calendar")
|
|
calendar = self.get_calendar()
|
|
if not calendar:
|
|
self.logger.warning("No calendar to export")
|
|
return None
|
|
|
|
try:
|
|
calendar_data = [content.to_dict() for content in calendar]
|
|
self.logger.info("Calendar exported successfully")
|
|
return calendar_data
|
|
except Exception as e:
|
|
self.logger.error(f"Error exporting calendar: {str(e)}", exc_info=True)
|
|
return None
|
|
|
|
def save_calendar_to_json(self):
|
|
calendar = self.get_calendar()
|
|
if calendar:
|
|
with open("calendar_data.json", "w") as f:
|
|
json.dump(calendar, f, indent=2, default=str)
|
|
|
|
def load_calendar_from_json(self):
|
|
if os.path.exists("calendar_data.json"):
|
|
with open("calendar_data.json", "r") as f:
|
|
data = json.load(f)
|
|
self.update_calendar(data) |